String vmName = vmSpec.getName();
State state = State.Stopped;
VmwareContext context = getServiceContext();
try {
VmwareManager mgr = context.getStockObject(VmwareManager.CONTEXT_STOCK_NAME);
// mark VM as starting state so that sync() can know not to report stopped too early
synchronized (_vms) {
_vms.put(vmName, State.Starting);
}
VirtualEthernetCardType nicDeviceType = VirtualEthernetCardType.valueOf(vmSpec.getDetails().get(VmDetailConstants.NIC_ADAPTER));
if(s_logger.isDebugEnabled())
s_logger.debug("VM " + vmName + " will be started with NIC device type: " + nicDeviceType);
VmwareHypervisorHost hyperHost = getHyperHost(context);
VolumeTO[] disks = validateDisks(vmSpec.getDisks());
assert (disks.length > 0);
NicTO[] nics = vmSpec.getNics();
HashMap<String, Pair<ManagedObjectReference, DatastoreMO>> dataStoresDetails = inferDatastoreDetailsFromDiskInfo(hyperHost, context, disks);
if ((dataStoresDetails == null) || (dataStoresDetails.isEmpty()) ){
String msg = "Unable to locate datastore details of the volumes to be attached";
s_logger.error(msg);
throw new Exception(msg);
}
VirtualMachineMO vmMo = hyperHost.findVmOnHyperHost(vmName);
if (vmMo != null) {
s_logger.info("VM " + vmName + " already exists, tear down devices for reconfiguration");
if (getVmState(vmMo) != State.Stopped)
vmMo.safePowerOff(_shutdown_waitMs);
vmMo.tearDownDevices(new Class<?>[] { VirtualDisk.class, VirtualEthernetCard.class });
vmMo.ensureScsiDeviceController();
} else {
ManagedObjectReference morDc = hyperHost.getHyperHostDatacenter();
assert (morDc != null);
vmMo = hyperHost.findVmOnPeerHyperHost(vmName);
if (vmMo != null) {
if (s_logger.isInfoEnabled()) {
s_logger.info("Found vm " + vmName + " at other host, relocate to " + hyperHost.getHyperHostName());
}
takeVmFromOtherHyperHost(hyperHost, vmName);
if (getVmState(vmMo) != State.Stopped)
vmMo.safePowerOff(_shutdown_waitMs);
vmMo.tearDownDevices(new Class<?>[] { VirtualDisk.class, VirtualEthernetCard.class });
vmMo.ensureScsiDeviceController();
} else {
int ramMb = (int) (vmSpec.getMinRam() / (1024 * 1024));
Pair<ManagedObjectReference, DatastoreMO> rootDiskDataStoreDetails = null;
for (VolumeTO vol : disks) {
if (vol.getType() == Volume.Type.ROOT) {
rootDiskDataStoreDetails = dataStoresDetails.get(vol.getPoolUuid());
}
}
assert (vmSpec.getSpeed() != null) && (rootDiskDataStoreDetails != null);
if (!hyperHost.createBlankVm(vmName, vmSpec.getCpus(), vmSpec.getSpeed().intValue(),
getReserveCpuMHz(vmSpec.getSpeed().intValue()), vmSpec.getLimitCpuUse(), ramMb, getReserveMemMB(ramMb),
translateGuestOsIdentifier(vmSpec.getArch(), vmSpec.getOs()).toString(), rootDiskDataStoreDetails.first(), false)) {
throw new Exception("Failed to create VM. vmName: " + vmName);
}
}
vmMo = hyperHost.findVmOnHyperHost(vmName);
if (vmMo == null) {
throw new Exception("Failed to find the newly create or relocated VM. vmName: " + vmName);
}
}
int totalChangeDevices = disks.length + nics.length;
VolumeTO volIso = null;
if (vmSpec.getType() != VirtualMachine.Type.User) {
// system VM needs a patch ISO
totalChangeDevices++;
} else {
for (VolumeTO vol : disks) {
if (vol.getType() == Volume.Type.ISO) {
volIso = vol;
break;
}
}
if (volIso == null)
totalChangeDevices++;
}
VirtualMachineConfigSpec vmConfigSpec = new VirtualMachineConfigSpec();
int ramMb = (int) (vmSpec.getMinRam() / (1024 * 1024));
VmwareHelper.setBasicVmConfig(vmConfigSpec, vmSpec.getCpus(), vmSpec.getSpeed().intValue(),
getReserveCpuMHz(vmSpec.getSpeed().intValue()), ramMb, getReserveMemMB(ramMb),
translateGuestOsIdentifier(vmSpec.getArch(), vmSpec.getOs()).toString(), vmSpec.getLimitCpuUse());
VirtualDeviceConfigSpec[] deviceConfigSpecArray = new VirtualDeviceConfigSpec[totalChangeDevices];
int i = 0;
int ideControllerKey = vmMo.getIDEDeviceControllerKey();
int scsiControllerKey = vmMo.getScsiDeviceControllerKey();
int controllerKey;
String datastoreDiskPath;
// prepare systemvm patch ISO
if (vmSpec.getType() != VirtualMachine.Type.User) {
// attach ISO (for patching of system VM)
String secStoreUrl = mgr.getSecondaryStorageStoreUrl(Long.parseLong(_dcId));
if(secStoreUrl == null) {
String msg = "secondary storage for dc " + _dcId + " is not ready yet?";
throw new Exception(msg);
}
mgr.prepareSecondaryStorageStore(secStoreUrl);
ManagedObjectReference morSecDs = prepareSecondaryDatastoreOnHost(secStoreUrl);
if (morSecDs == null) {
String msg = "Failed to prepare secondary storage on host, secondary store url: " + secStoreUrl;
throw new Exception(msg);
}
DatastoreMO secDsMo = new DatastoreMO(hyperHost.getContext(), morSecDs);
deviceConfigSpecArray[i] = new VirtualDeviceConfigSpec();
Pair<VirtualDevice, Boolean> isoInfo = VmwareHelper.prepareIsoDevice(vmMo, String.format("[%s] systemvm/%s", secDsMo.getName(), mgr.getSystemVMIsoFileNameOnDatastore()),
secDsMo.getMor(), true, true, i, i + 1);
deviceConfigSpecArray[i].setDevice(isoInfo.first());
if (isoInfo.second()) {
if(s_logger.isDebugEnabled())
s_logger.debug("Prepare ISO volume at new device " + _gson.toJson(isoInfo.first()));
deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.add);
} else {
if(s_logger.isDebugEnabled())
s_logger.debug("Prepare ISO volume at existing device " + _gson.toJson(isoInfo.first()));
deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.edit);
}
i++;
} else {
// we will always plugin a CDROM device
if (volIso != null && volIso.getPath() != null && !volIso.getPath().isEmpty()) {
Pair<String, ManagedObjectReference> isoDatastoreInfo = getIsoDatastoreInfo(hyperHost, volIso.getPath());
assert (isoDatastoreInfo != null);
assert (isoDatastoreInfo.second() != null);
deviceConfigSpecArray[i] = new VirtualDeviceConfigSpec();
Pair<VirtualDevice, Boolean> isoInfo = VmwareHelper.prepareIsoDevice(vmMo, isoDatastoreInfo.first(), isoDatastoreInfo.second(), true, true, i, i + 1);
deviceConfigSpecArray[i].setDevice(isoInfo.first());
if (isoInfo.second()) {
if(s_logger.isDebugEnabled())
s_logger.debug("Prepare ISO volume at new device " + _gson.toJson(isoInfo.first()));
deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.add);
} else {
if(s_logger.isDebugEnabled())
s_logger.debug("Prepare ISO volume at existing device " + _gson.toJson(isoInfo.first()));
deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.edit);
}
} else {
deviceConfigSpecArray[i] = new VirtualDeviceConfigSpec();
Pair<VirtualDevice, Boolean> isoInfo = VmwareHelper.prepareIsoDevice(vmMo, null, null, true, true, i, i + 1);
deviceConfigSpecArray[i].setDevice(isoInfo.first());
if (isoInfo.second()) {
if(s_logger.isDebugEnabled())
s_logger.debug("Prepare ISO volume at existing device " + _gson.toJson(isoInfo.first()));
deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.add);
} else {
if(s_logger.isDebugEnabled())
s_logger.debug("Prepare ISO volume at existing device " + _gson.toJson(isoInfo.first()));
deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.edit);
}
}
i++;
}
for (VolumeTO vol : sortVolumesByDeviceId(disks)) {
deviceConfigSpecArray[i] = new VirtualDeviceConfigSpec();
if (vol.getType() == Volume.Type.ISO) {
controllerKey = ideControllerKey;
} else {
if(vol.getType() == Volume.Type.ROOT) {
if(vmSpec.getDetails() != null && vmSpec.getDetails().get(VmDetailConstants.ROOK_DISK_CONTROLLER) != null)
{
if(vmSpec.getDetails().get(VmDetailConstants.ROOK_DISK_CONTROLLER).equalsIgnoreCase("scsi"))
controllerKey = scsiControllerKey;
else
controllerKey = ideControllerKey;
} else {
controllerKey = scsiControllerKey;
}
} else {
// DATA volume always use SCSI device
controllerKey = scsiControllerKey;
}
}
if (vol.getType() != Volume.Type.ISO) {
Pair<ManagedObjectReference, DatastoreMO> volumeDsDetails = dataStoresDetails.get(vol.getPoolUuid());
assert (volumeDsDetails != null);
VirtualDevice device;
datastoreDiskPath = String.format("[%s] %s.vmdk", volumeDsDetails.second().getName(), vol.getPath());
String chainInfo = vol.getChainInfo();
if (chainInfo != null && !chainInfo.isEmpty()) {
String[] diskChain = _gson.fromJson(chainInfo, String[].class);
if (diskChain == null || diskChain.length < 1) {
s_logger.warn("Empty previously-saved chain info, fall back to the original");
device = VmwareHelper.prepareDiskDevice(vmMo, controllerKey, new String[] { datastoreDiskPath }, volumeDsDetails.first(), i, i + 1);
} else {
s_logger.info("Attach the disk with stored chain info: " + chainInfo);
for (int j = 0; j < diskChain.length; j++) {
diskChain[j] = String.format("[%s] %s", volumeDsDetails.second().getName(), diskChain[j]);
}
device = VmwareHelper.prepareDiskDevice(vmMo, controllerKey, diskChain, volumeDsDetails.first(), i, i + 1);
}
} else {
device = VmwareHelper.prepareDiskDevice(vmMo, controllerKey, new String[] { datastoreDiskPath }, volumeDsDetails.first(), i, i + 1);
}
deviceConfigSpecArray[i].setDevice(device);
deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.add);
if(s_logger.isDebugEnabled())
s_logger.debug("Prepare volume at new device " + _gson.toJson(device));
i++;
}
}
VirtualDevice nic;
int nicMask = 0;
int nicCount = 0;
for (NicTO nicTo : sortNicsByDeviceId(nics)) {
s_logger.info("Prepare NIC device based on NicTO: " + _gson.toJson(nicTo));
Pair<ManagedObjectReference, String> networkInfo = prepareNetworkFromNicInfo(vmMo.getRunningHost(), nicTo);
if (mgr.getNexusVSwitchGlobalParameter()) {
String dvSwitchUuid;
ManagedObjectReference dcMor = hyperHost.getHyperHostDatacenter();
DatacenterMO dataCenterMo = new DatacenterMO(context, dcMor);
ManagedObjectReference dvsMor = dataCenterMo.getDvSwitchMor(networkInfo.first());
dvSwitchUuid = dataCenterMo.getDvSwitchUuid(dvsMor);