CLOUDSTACK-4659: Add the missing feature back for GC VMware worker VMs

This commit is contained in:
Kelven Yang 2013-09-13 16:26:40 -07:00
parent 2b4e994a4d
commit 5820b071b8
16 changed files with 191 additions and 176 deletions

View File

@ -112,6 +112,7 @@ public class ConsoleProxyResource extends ServerResourceBase implements
} }
private Answer execute(StartConsoleProxyAgentHttpHandlerCommand cmd) { private Answer execute(StartConsoleProxyAgentHttpHandlerCommand cmd) {
s_logger.info("Invoke launchConsoleProxy() in responding to StartConsoleProxyAgentHttpHandlerCommand");
launchConsoleProxy(cmd.getKeystoreBits(), cmd.getKeystorePassword(), cmd.getEncryptorPassword()); launchConsoleProxy(cmd.getKeystoreBits(), cmd.getKeystorePassword(), cmd.getEncryptorPassword());
return new Answer(cmd); return new Answer(cmd);
} }
@ -361,29 +362,31 @@ public class ConsoleProxyResource extends ServerResourceBase implements
try { try {
Class<?> consoleProxyClazz = Class.forName("com.cloud.consoleproxy.ConsoleProxy"); Class<?> consoleProxyClazz = Class.forName("com.cloud.consoleproxy.ConsoleProxy");
try { try {
s_logger.info("Invoke setEncryptorPassword(), ecnryptorPassword: " + encryptorPassword);
Method methodSetup = consoleProxyClazz.getMethod( Method methodSetup = consoleProxyClazz.getMethod(
"setEncryptorPassword", String.class); "setEncryptorPassword", String.class);
methodSetup.invoke(null, encryptorPassword); methodSetup.invoke(null, encryptorPassword);
s_logger.info("Invoke startWithContext()");
Method method = consoleProxyClazz.getMethod( Method method = consoleProxyClazz.getMethod(
"startWithContext", Properties.class, "startWithContext", Properties.class,
Object.class, byte[].class, String.class); Object.class, byte[].class, String.class);
method.invoke(null, _properties, resource, ksBits, method.invoke(null, _properties, resource, ksBits,
ksPassword); ksPassword);
} catch (SecurityException e) { } catch (SecurityException e) {
s_logger.error("Unable to launch console proxy due to SecurityException"); s_logger.error("Unable to launch console proxy due to SecurityException", e);
System.exit(ExitStatus.Error.value()); System.exit(ExitStatus.Error.value());
} catch (NoSuchMethodException e) { } catch (NoSuchMethodException e) {
s_logger.error("Unable to launch console proxy due to NoSuchMethodException"); s_logger.error("Unable to launch console proxy due to NoSuchMethodException", e);
System.exit(ExitStatus.Error.value()); System.exit(ExitStatus.Error.value());
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
s_logger.error("Unable to launch console proxy due to IllegalArgumentException"); s_logger.error("Unable to launch console proxy due to IllegalArgumentException", e);
System.exit(ExitStatus.Error.value()); System.exit(ExitStatus.Error.value());
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
s_logger.error("Unable to launch console proxy due to IllegalAccessException"); s_logger.error("Unable to launch console proxy due to IllegalAccessException", e);
System.exit(ExitStatus.Error.value()); System.exit(ExitStatus.Error.value());
} catch (InvocationTargetException e) { } catch (InvocationTargetException e) {
s_logger.error("Unable to launch console proxy due to InvocationTargetException"); s_logger.error("Unable to launch console proxy due to InvocationTargetException " + e.getTargetException().toString(), e);
System.exit(ExitStatus.Error.value()); System.exit(ExitStatus.Error.value());
} }
} catch (final ClassNotFoundException e) { } catch (final ClassNotFoundException e) {
@ -402,22 +405,22 @@ public class ConsoleProxyResource extends ServerResourceBase implements
Method methodSetup = consoleProxyClazz.getMethod("setEncryptorPassword", String.class); Method methodSetup = consoleProxyClazz.getMethod("setEncryptorPassword", String.class);
methodSetup.invoke(null, encryptorPassword); methodSetup.invoke(null, encryptorPassword);
} catch (SecurityException e) { } catch (SecurityException e) {
s_logger.error("Unable to launch console proxy due to SecurityException"); s_logger.error("Unable to launch console proxy due to SecurityException", e);
System.exit(ExitStatus.Error.value()); System.exit(ExitStatus.Error.value());
} catch (NoSuchMethodException e) { } catch (NoSuchMethodException e) {
s_logger.error("Unable to launch console proxy due to NoSuchMethodException"); s_logger.error("Unable to launch console proxy due to NoSuchMethodException", e);
System.exit(ExitStatus.Error.value()); System.exit(ExitStatus.Error.value());
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
s_logger.error("Unable to launch console proxy due to IllegalArgumentException"); s_logger.error("Unable to launch console proxy due to IllegalArgumentException", e);
System.exit(ExitStatus.Error.value()); System.exit(ExitStatus.Error.value());
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
s_logger.error("Unable to launch console proxy due to IllegalAccessException"); s_logger.error("Unable to launch console proxy due to IllegalAccessException", e);
System.exit(ExitStatus.Error.value()); System.exit(ExitStatus.Error.value());
} catch (InvocationTargetException e) { } catch (InvocationTargetException e) {
s_logger.error("Unable to launch console proxy due to InvocationTargetException"); s_logger.error("Unable to launch console proxy due to InvocationTargetException " + e.getTargetException().toString(), e);
System.exit(ExitStatus.Error.value()); System.exit(ExitStatus.Error.value());
} catch (final ClassNotFoundException e) { } catch (final ClassNotFoundException e) {
s_logger.error("Unable to launch console proxy due to ClassNotFoundException"); s_logger.error("Unable to launch console proxy due to ClassNotFoundException", e);
System.exit(ExitStatus.Error.value()); System.exit(ExitStatus.Error.value());
} }
} }

View File

@ -17,7 +17,7 @@
<groupId>org.apache.cloudstack</groupId> <groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack</artifactId> <artifactId>cloudstack</artifactId>
<version>4.3.0-SNAPSHOT</version> <version>4.3.0-SNAPSHOT</version>
</parent> </parent>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.apache.cloudstack</groupId> <groupId>org.apache.cloudstack</groupId>

View File

@ -55,6 +55,8 @@ public interface ClusterManager extends Manager {
ManagementServerHost getPeer(String peerName); ManagementServerHost getPeer(String peerName);
String getSelfPeerName(); String getSelfPeerName();
long getManagementNodeId();
long getCurrentRunId();
public interface Dispatcher { public interface Dispatcher {
String getName(); String getName();

View File

@ -1076,6 +1076,10 @@ public class ClusterManagerImpl extends ManagerBase implements ClusterManager, C
} }
return true; return true;
} }
public long getManagementNodeId() {
return _msId;
}
public long getCurrentRunId() { public long getCurrentRunId() {
return _runId; return _runId;

View File

@ -54,6 +54,7 @@ import com.cloud.agent.api.to.DataStoreTO;
import com.cloud.agent.api.to.DataTO; import com.cloud.agent.api.to.DataTO;
import com.cloud.agent.api.to.NicTO; import com.cloud.agent.api.to.NicTO;
import com.cloud.agent.api.to.VirtualMachineTO; import com.cloud.agent.api.to.VirtualMachineTO;
import com.cloud.cluster.ClusterManager;
import com.cloud.configuration.Config; import com.cloud.configuration.Config;
import com.cloud.exception.InsufficientAddressCapacityException; import com.cloud.exception.InsufficientAddressCapacityException;
import com.cloud.host.Host; import com.cloud.host.Host;
@ -115,6 +116,7 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru {
PhysicalNetworkDao _physicalNetworkDao; PhysicalNetworkDao _physicalNetworkDao;
@Inject @Inject
PhysicalNetworkTrafficTypeDao _physicalNetworkTrafficTypeDao; PhysicalNetworkTrafficTypeDao _physicalNetworkTrafficTypeDao;
@Inject ClusterManager _clusterMgr;
protected VMwareGuru() { protected VMwareGuru() {
super(); super();
@ -365,6 +367,7 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru {
CommandExecLogVO execLog = new CommandExecLogVO(cmdTarget.first().getId(), cmdTarget.second().getId(), cmd.getClass().getSimpleName(), 1); CommandExecLogVO execLog = new CommandExecLogVO(cmdTarget.first().getId(), cmdTarget.second().getId(), cmd.getClass().getSimpleName(), 1);
_cmdExecLogDao.persist(execLog); _cmdExecLogDao.persist(execLog);
cmd.setContextParam("execid", String.valueOf(execLog.getId())); cmd.setContextParam("execid", String.valueOf(execLog.getId()));
cmd.setContextParam("noderuninfo", String.format("%d-%d", _clusterMgr.getManagementNodeId(), _clusterMgr.getCurrentRunId()));
if(cmd instanceof BackupSnapshotCommand || if(cmd instanceof BackupSnapshotCommand ||
cmd instanceof CreatePrivateTemplateFromVolumeCommand || cmd instanceof CreatePrivateTemplateFromVolumeCommand ||

View File

@ -52,6 +52,7 @@ public interface VmwareManager {
VmwareStorageManager getStorageManager(); VmwareStorageManager getStorageManager();
void gcLeftOverVMs(VmwareContext context); void gcLeftOverVMs(VmwareContext context);
boolean needRecycle(String workerTag);
Pair<Integer, Integer> getAddiionalVncPortRange(); Pair<Integer, Integer> getAddiionalVncPortRange();

View File

@ -59,6 +59,9 @@ import com.cloud.agent.api.Answer;
import com.cloud.agent.api.Command; import com.cloud.agent.api.Command;
import com.cloud.agent.api.StartupCommand; import com.cloud.agent.api.StartupCommand;
import com.cloud.agent.api.StartupRoutingCommand; import com.cloud.agent.api.StartupRoutingCommand;
import com.cloud.cluster.ClusterManager;
import com.cloud.cluster.ManagementServerHost;
import com.cloud.cluster.dao.ManagementServerHostPeerDao;
import com.cloud.configuration.Config; import com.cloud.configuration.Config;
import com.cloud.dc.ClusterDetailsDao; import com.cloud.dc.ClusterDetailsDao;
import com.cloud.dc.ClusterVO; import com.cloud.dc.ClusterVO;
@ -153,6 +156,8 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
@Inject VmwareDatacenterDao _vmwareDcDao; @Inject VmwareDatacenterDao _vmwareDcDao;
@Inject VmwareDatacenterZoneMapDao _vmwareDcZoneMapDao; @Inject VmwareDatacenterZoneMapDao _vmwareDcZoneMapDao;
@Inject LegacyZoneDao _legacyZoneDao; @Inject LegacyZoneDao _legacyZoneDao;
@Inject ManagementServerHostPeerDao _mshostPeerDao;
@Inject ClusterManager _clusterMgr;
String _mountParent; String _mountParent;
StorageLayer _storage; StorageLayer _storage;
@ -166,6 +171,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
String _managemetPortGroupName; String _managemetPortGroupName;
String _defaultSystemVmNicAdapterType = VirtualEthernetCardType.E1000.toString(); String _defaultSystemVmNicAdapterType = VirtualEthernetCardType.E1000.toString();
String _recycleHungWorker = "false"; String _recycleHungWorker = "false";
long _hungWorkerTimeout = 7200000; // 2 hour
int _additionalPortRangeStart; int _additionalPortRangeStart;
int _additionalPortRangeSize; int _additionalPortRangeSize;
int _routerExtraPublicNics = 2; int _routerExtraPublicNics = 2;
@ -284,6 +290,10 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
if(_recycleHungWorker == null || _recycleHungWorker.isEmpty()) { if(_recycleHungWorker == null || _recycleHungWorker.isEmpty()) {
_recycleHungWorker = "false"; _recycleHungWorker = "false";
} }
value = _configDao.getValue(Config.VmwareHungWorkerTimeout.key());
if(value != null)
_hungWorkerTimeout = Long.parseLong(value) * 1000;
_rootDiskController = _configDao.getValue(Config.VmwareRootDiskControllerType.key()); _rootDiskController = _configDao.getValue(Config.VmwareRootDiskControllerType.key());
if(_rootDiskController == null || _rootDiskController.isEmpty()) { if(_rootDiskController == null || _rootDiskController.isEmpty()) {
@ -529,11 +539,50 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
return _storageMgr; return _storageMgr;
} }
@Override @Override
public void gcLeftOverVMs(VmwareContext context) { public void gcLeftOverVMs(VmwareContext context) {
VmwareCleanupMaid.gcLeftOverVMs(context); VmwareCleanupMaid.gcLeftOverVMs(context);
} }
@Override
public boolean needRecycle(String workerTag) {
if(s_logger.isInfoEnabled())
s_logger.info("Check to see if a worker VM with tag " + workerTag + " needs to be recycled");
if(workerTag == null || workerTag.isEmpty()) {
s_logger.error("Invalid worker VM tag " + workerTag);
return false;
}
String tokens[] = workerTag.split("-");
if(tokens.length != 3) {
s_logger.error("Invalid worker VM tag " + workerTag);
return false;
}
long startTick = Long.parseLong(tokens[0]);
long msid = Long.parseLong(tokens[1]);
long runid = Long.parseLong(tokens[2]);
if(_mshostPeerDao.countStateSeenInPeers(msid, runid, ManagementServerHost.State.Down) > 0) {
if(s_logger.isInfoEnabled())
s_logger.info("Worker VM's owner management server node has been detected down from peer nodes, recycle it");
return true;
}
if(msid == _clusterMgr.getManagementNodeId() && runid != _clusterMgr.getCurrentRunId()) {
if(s_logger.isInfoEnabled())
s_logger.info("Worker VM's owner management server has changed runid, recycle it");
return true;
}
if(System.currentTimeMillis() - startTick > _hungWorkerTimeout) {
if(s_logger.isInfoEnabled())
s_logger.info("Worker VM expired, seconds elapsed: " + (System.currentTimeMillis() - startTick) / 1000);
return true;
}
return false;
}
@Override @Override
public void prepareSecondaryStorageStore(String storageUrl) { public void prepareSecondaryStorageStore(String storageUrl) {

View File

@ -315,46 +315,41 @@ public class VmwareStorageManagerImpl implements VmwareStorageManager {
String prevBackupUuid = cmd.getPrevBackupUuid(); String prevBackupUuid = cmd.getPrevBackupUuid();
VirtualMachineMO workerVm=null; VirtualMachineMO workerVm=null;
String workerVMName = null; String workerVMName = null;
String volumePath = cmd.getVolumePath(); String volumePath = cmd.getVolumePath();
ManagedObjectReference morDs = null; ManagedObjectReference morDs = null;
DatastoreMO dsMo=null; DatastoreMO dsMo=null;
// By default assume failure // By default assume failure
String details = null; String details = null;
boolean success = false; boolean success = false;
String snapshotBackupUuid = null; String snapshotBackupUuid = null;
VmwareContext context = hostService.getServiceContext(cmd); VmwareContext context = hostService.getServiceContext(cmd);
VirtualMachineMO vmMo = null; VirtualMachineMO vmMo = null;
try { try {
VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, cmd); VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, cmd);
morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, cmd.getPool().getUuid()); morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, cmd.getPool().getUuid());
try { try {
vmMo = hyperHost.findVmOnHyperHost(cmd.getVmName()); vmMo = hyperHost.findVmOnHyperHost(cmd.getVmName());
if (vmMo == null) { if (vmMo == null) {
if(s_logger.isDebugEnabled()) if(s_logger.isDebugEnabled()) {
s_logger.debug("Unable to find owner VM for BackupSnapshotCommand on host " + hyperHost.getHyperHostName() + ", will try within datacenter"); s_logger.debug("Unable to find owner VM for BackupSnapshotCommand on host " + hyperHost.getHyperHostName() + ", will try within datacenter");
}
vmMo = hyperHost.findVmOnPeerHyperHost(cmd.getVmName()); vmMo = hyperHost.findVmOnPeerHyperHost(cmd.getVmName());
if(vmMo == null) { if(vmMo == null) {
dsMo = new DatastoreMO(hyperHost.getContext(), morDs); dsMo = new DatastoreMO(hyperHost.getContext(), morDs);
workerVMName = hostService.getWorkerName(context, cmd, 0); workerVMName = hostService.getWorkerName(context, cmd, 0);
vmMo = HypervisorHostHelper.createWorkerVM(hyperHost, dsMo, workerVMName);
if (vmMo == null) {
throw new Exception("Failed to find the newly create or relocated VM. vmName: " + workerVMName);
}
workerVm = vmMo;
// attach a volume to dummay wrapper VM for taking snapshot and exporting the VM for backup // attach volume to worker VM
if (!hyperHost.createBlankVm(workerVMName, null, 1, 512, 0, false, 4, 0, VirtualMachineGuestOsIdentifier.OTHER_GUEST.value(), morDs, false)) {
String msg = "Unable to create worker VM to execute BackupSnapshotCommand";
s_logger.error(msg);
throw new Exception(msg);
}
vmMo = hyperHost.findVmOnHyperHost(workerVMName);
if (vmMo == null) {
throw new Exception("Failed to find the newly create or relocated VM. vmName: " + workerVMName);
}
workerVm = vmMo;
// attach volume to worker VM
String datastoreVolumePath = getVolumePathInDatastore(dsMo, volumePath + ".vmdk"); String datastoreVolumePath = getVolumePathInDatastore(dsMo, volumePath + ".vmdk");
vmMo.attachDisk(new String[] { datastoreVolumePath }, morDs); vmMo.attachDisk(new String[] { datastoreVolumePath }, morDs);
} }
@ -1071,28 +1066,8 @@ public class VmwareStorageManagerImpl implements VmwareStorageManager {
if (vmMo == null) { if (vmMo == null) {
// create a dummy worker vm for attaching the volume // create a dummy worker vm for attaching the volume
DatastoreMO dsMo = new DatastoreMO(hyperHost.getContext(), morDs); DatastoreMO dsMo = new DatastoreMO(hyperHost.getContext(), morDs);
//restrict VM name to 32 chars, (else snapshot descriptor file name will be truncated to 32 chars of vm name) workerVm = HypervisorHostHelper.createWorkerVM(hyperHost, dsMo, workerVmName);
VirtualMachineConfigSpec vmConfig = new VirtualMachineConfigSpec();
vmConfig.setName(workerVmName);
vmConfig.setMemoryMB((long) 4);
vmConfig.setNumCPUs(1);
vmConfig.setGuestId(VirtualMachineGuestOsIdentifier.OTHER_GUEST.value());
VirtualMachineFileInfo fileInfo = new VirtualMachineFileInfo();
fileInfo.setVmPathName(String.format("[%s]", dsMo.getName()));
vmConfig.setFiles(fileInfo);
// Scsi controller
VirtualLsiLogicController scsiController = new VirtualLsiLogicController();
scsiController.setSharedBus(VirtualSCSISharing.NO_SHARING);
scsiController.setBusNumber(0);
scsiController.setKey(1);
VirtualDeviceConfigSpec scsiControllerSpec = new VirtualDeviceConfigSpec();
scsiControllerSpec.setDevice(scsiController);
scsiControllerSpec.setOperation(VirtualDeviceConfigSpecOperation.ADD);
vmConfig.getDeviceChange().add(scsiControllerSpec);
hyperHost.createVm(vmConfig);
workerVm = hyperHost.findVmOnHyperHost(workerVmName);
if (workerVm == null) { if (workerVm == null) {
String msg = "Unable to create worker VM to execute CopyVolumeCommand"; String msg = "Unable to create worker VM to execute CopyVolumeCommand";
s_logger.error(msg); s_logger.error(msg);

View File

@ -22,6 +22,7 @@ import javax.inject.Inject;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import com.cloud.cluster.ClusterManager;
import com.cloud.hypervisor.vmware.manager.VmwareManager; import com.cloud.hypervisor.vmware.manager.VmwareManager;
import com.cloud.hypervisor.vmware.util.VmwareClient; import com.cloud.hypervisor.vmware.util.VmwareClient;
import com.cloud.hypervisor.vmware.util.VmwareContext; import com.cloud.hypervisor.vmware.util.VmwareContext;
@ -34,9 +35,11 @@ public class VmwareContextFactory {
private static volatile int s_seq = 1; private static volatile int s_seq = 1;
private static VmwareManager s_vmwareMgr; private static VmwareManager s_vmwareMgr;
private static ClusterManager s_clusterMgr;
private static VmwareContextPool s_pool; private static VmwareContextPool s_pool;
@Inject VmwareManager _vmwareMgr; @Inject VmwareManager _vmwareMgr;
@Inject ClusterManager _clusterMgr;
static { static {
// skip certificate check // skip certificate check
@ -47,6 +50,7 @@ public class VmwareContextFactory {
@PostConstruct @PostConstruct
void init() { void init() {
s_vmwareMgr = _vmwareMgr; s_vmwareMgr = _vmwareMgr;
s_clusterMgr = _clusterMgr;
} }
public static VmwareContext create(String vCenterAddress, String vCenterUserName, String vCenterPassword) throws Exception { public static VmwareContext create(String vCenterAddress, String vCenterUserName, String vCenterPassword) throws Exception {
@ -66,6 +70,7 @@ public class VmwareContextFactory {
context.registerStockObject("serviceconsole", s_vmwareMgr.getServiceConsolePortGroupName()); context.registerStockObject("serviceconsole", s_vmwareMgr.getServiceConsolePortGroupName());
context.registerStockObject("manageportgroup", s_vmwareMgr.getManagementPortGroupName()); context.registerStockObject("manageportgroup", s_vmwareMgr.getManagementPortGroupName());
context.registerStockObject("noderuninfo", String.format("%d-%d", s_clusterMgr.getManagementNodeId(), s_clusterMgr.getCurrentRunId()));
context.setPoolInfo(s_pool, VmwareContextPool.composePoolKey(vCenterAddress, vCenterUserName)); context.setPoolInfo(s_pool, VmwareContextPool.composePoolKey(vCenterAddress, vCenterUserName));
s_pool.registerOutstandingContext(context); s_pool.registerOutstandingContext(context);
@ -83,6 +88,7 @@ public class VmwareContextFactory {
context.registerStockObject("serviceconsole", s_vmwareMgr.getServiceConsolePortGroupName()); context.registerStockObject("serviceconsole", s_vmwareMgr.getServiceConsolePortGroupName());
context.registerStockObject("manageportgroup", s_vmwareMgr.getManagementPortGroupName()); context.registerStockObject("manageportgroup", s_vmwareMgr.getManagementPortGroupName());
context.registerStockObject("noderuninfo", String.format("%d-%d", s_clusterMgr.getManagementNodeId(), s_clusterMgr.getCurrentRunId()));
} }
return context; return context;

View File

@ -29,7 +29,6 @@ import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.Date; import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
@ -284,7 +283,6 @@ import com.cloud.hypervisor.vmware.mo.DatastoreMO;
import com.cloud.hypervisor.vmware.mo.DiskControllerType; import com.cloud.hypervisor.vmware.mo.DiskControllerType;
import com.cloud.hypervisor.vmware.mo.FeatureKeyConstants; import com.cloud.hypervisor.vmware.mo.FeatureKeyConstants;
import com.cloud.hypervisor.vmware.mo.HostDatastoreSystemMO; import com.cloud.hypervisor.vmware.mo.HostDatastoreSystemMO;
import com.cloud.hypervisor.vmware.mo.HostFirewallSystemMO;
import com.cloud.hypervisor.vmware.mo.HostMO; import com.cloud.hypervisor.vmware.mo.HostMO;
import com.cloud.hypervisor.vmware.mo.HostStorageSystemMO; import com.cloud.hypervisor.vmware.mo.HostStorageSystemMO;
import com.cloud.hypervisor.vmware.mo.HypervisorHostHelper; import com.cloud.hypervisor.vmware.mo.HypervisorHostHelper;
@ -322,7 +320,6 @@ import com.cloud.utils.DateUtil;
import com.cloud.utils.NumbersUtil; import com.cloud.utils.NumbersUtil;
import com.cloud.utils.Pair; import com.cloud.utils.Pair;
import com.cloud.utils.StringUtils; import com.cloud.utils.StringUtils;
import com.cloud.utils.component.ComponentContext;
import com.cloud.utils.db.DB; import com.cloud.utils.db.DB;
import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.exception.ExceptionUtil; import com.cloud.utils.exception.ExceptionUtil;
@ -4462,7 +4459,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
if (!dsMo.fileExists(volumeDatastorePath)) { if (!dsMo.fileExists(volumeDatastorePath)) {
String dummyVmName = getWorkerName(context, cmd, 0); String dummyVmName = getWorkerName(context, cmd, 0);
VirtualMachineMO vmMo = prepareVolumeHostDummyVm(hyperHost, dsMo, dummyVmName); VirtualMachineMO vmMo = HypervisorHostHelper.createWorkerVM(hyperHost, dsMo, dummyVmName);
if (vmMo == null) { if (vmMo == null) {
throw new Exception("Unable to create a dummy VM for volume creation"); throw new Exception("Unable to create a dummy VM for volume creation");
@ -5621,7 +5618,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
VirtualMachineMO vmMo = null; VirtualMachineMO vmMo = null;
try { try {
vmMo = prepareVolumeHostDummyVm(hyperHost, dsMo, dummyVmName); vmMo = HypervisorHostHelper.createWorkerVM(hyperHost, dsMo, dummyVmName);
if (vmMo == null) { if (vmMo == null) {
throw new Exception("Unable to create a dummy VM for volume creation"); throw new Exception("Unable to create a dummy VM for volume creation");
} }
@ -5678,7 +5675,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
String volumeDatastorePath = String.format("[%s] %s.vmdk", dsMo.getName(), volumeUuid); String volumeDatastorePath = String.format("[%s] %s.vmdk", dsMo.getName(), volumeUuid);
String dummyVmName = getWorkerName(context, cmd, 0); String dummyVmName = getWorkerName(context, cmd, 0);
try { try {
vmMo = prepareVolumeHostDummyVm(hyperHost, dsMo, dummyVmName); vmMo = HypervisorHostHelper.createWorkerVM(hyperHost, dsMo, dummyVmName);
if (vmMo == null) { if (vmMo == null) {
throw new Exception("Unable to create a dummy VM for volume creation"); throw new Exception("Unable to create a dummy VM for volume creation");
} }
@ -5713,34 +5710,6 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
return (int)(bytes / (1024L * 1024L)); return (int)(bytes / (1024L * 1024L));
} }
protected VirtualMachineMO prepareVolumeHostDummyVm(VmwareHypervisorHost hyperHost, DatastoreMO dsMo, String vmName) throws Exception {
assert (hyperHost != null);
VirtualMachineMO vmMo = null;
VirtualMachineConfigSpec vmConfig = new VirtualMachineConfigSpec();
vmConfig.setName(vmName);
vmConfig.setMemoryMB((long) 4); // vmware request minimum of 4 MB
vmConfig.setNumCPUs(1);
vmConfig.setGuestId(VirtualMachineGuestOsIdentifier.OTHER_GUEST.value());
VirtualMachineFileInfo fileInfo = new VirtualMachineFileInfo();
fileInfo.setVmPathName(String.format("[%s]", dsMo.getName()));
vmConfig.setFiles(fileInfo);
// Scsi controller
VirtualLsiLogicController scsiController = new VirtualLsiLogicController();
scsiController.setSharedBus(VirtualSCSISharing.NO_SHARING);
scsiController.setBusNumber(0);
scsiController.setKey(1);
VirtualDeviceConfigSpec scsiControllerSpec = new VirtualDeviceConfigSpec();
scsiControllerSpec.setDevice(scsiController);
scsiControllerSpec.setOperation(VirtualDeviceConfigSpecOperation.ADD);
vmConfig.getDeviceChange().add(scsiControllerSpec );
hyperHost.createVm(vmConfig);
vmMo = hyperHost.findVmOnHyperHost(vmName);
return vmMo;
}
@Override @Override
public void disconnected() { public void disconnected() {
} }
@ -5767,70 +5736,53 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
if(hyperHost.isHyperHostConnected()) { if(hyperHost.isHyperHostConnected()) {
mgr.gcLeftOverVMs(context); mgr.gcLeftOverVMs(context);
if(_recycleHungWorker) { s_logger.info("Scan hung worker VM to recycle");
s_logger.info("Scan hung worker VM to recycle");
int workerKey = ((HostMO)hyperHost).getCustomFieldKey("VirtualMachine", CustomFieldConstants.CLOUD_WORKER);
int key = ((HostMO)hyperHost).getCustomFieldKey("VirtualMachine", CustomFieldConstants.CLOUD_VM_INTERNAL_NAME); int workerTagKey = ((HostMO)hyperHost).getCustomFieldKey("VirtualMachine", CustomFieldConstants.CLOUD_WORKER_TAG);
if(key == 0) { String workerPropName = String.format("value[%d]", workerKey);
s_logger.warn("Custom field " + CustomFieldConstants.CLOUD_VM_INTERNAL_NAME + " is not registered ?!"); String workerTagPropName = String.format("value[%d]", workerTagKey);
}
String instanceNameCustomField = "value[" + key + "]"; // GC worker that has been running for too long
ObjectContent[] ocs = hyperHost.getVmPropertiesOnHyperHost(
// GC worker that has been running for too long new String[] {"name", "config.template", workerPropName, workerTagPropName,
ObjectContent[] ocs = hyperHost.getVmPropertiesOnHyperHost( });
new String[] {"name", "config.template", "runtime.powerState", "runtime.bootTime", instanceNameCustomField }); if(ocs != null) {
if(ocs != null) { for(ObjectContent oc : ocs) {
for(ObjectContent oc : ocs) { List<DynamicProperty> props = oc.getPropSet();
List<DynamicProperty> props = oc.getPropSet(); if(props != null) {
if(props != null) { boolean template = false;
String vmName = null; boolean isWorker = false;
String internalName = null; String workerTag = null;
boolean template = false;
VirtualMachinePowerState powerState = VirtualMachinePowerState.POWERED_OFF; for(DynamicProperty prop : props) {
GregorianCalendar bootTime = null; if(prop.getName().equals("config.template")) {
template = (Boolean)prop.getVal();
for(DynamicProperty prop : props) { } else if(prop.getName().equals(workerPropName)) {
if (prop.getName().equals("name")) CustomFieldStringValue val = (CustomFieldStringValue)prop.getVal();
vmName = prop.getVal().toString(); if(val != null && val.getValue() != null && val.getValue().equalsIgnoreCase("true"))
else if(prop.getName().startsWith("value[")) { isWorker = true;
if(prop.getVal() != null) }
internalName = ((CustomFieldStringValue)prop.getVal()).getValue(); else if(prop.getName().equals(workerTagPropName)) {
} CustomFieldStringValue val = (CustomFieldStringValue)prop.getVal();
else if(prop.getName().equals("config.template")) workerTag = val.getValue();
template = (Boolean)prop.getVal(); }
else if(prop.getName().equals("runtime.powerState")) }
powerState = (VirtualMachinePowerState)prop.getVal();
else if(prop.getName().equals("runtime.bootTime")) VirtualMachineMO vmMo = new VirtualMachineMO(hyperHost.getContext(), oc.getObj());
bootTime = (GregorianCalendar)prop.getVal(); if(!template && isWorker) {
} boolean recycle = false;
recycle = mgr.needRecycle(workerTag);
VirtualMachineMO vmMo = new VirtualMachineMO(hyperHost.getContext(), oc.getObj());
String name = null; if(recycle) {
if (internalName != null) { s_logger.info("Recycle pending worker VM: " + vmMo.getName());
name = internalName;
} else { vmMo.powerOff();
name = vmName; vmMo.destroy();
} }
}
if(!template && name.matches("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}")) { }
boolean recycle = false; }
// recycle stopped worker VM and VM that has been running for too long (hard-coded 10 hours for now)
if(powerState == VirtualMachinePowerState.POWERED_OFF)
recycle = true;
else if(bootTime != null && (new Date().getTime() - bootTime.getTimeInMillis() > 10*3600*1000))
recycle = true;
if(recycle) {
s_logger.info("Recycle pending worker VM: " + name);
vmMo.powerOff();
vmMo.destroy();
}
}
}
}
}
} }
} else { } else {
s_logger.error("Host is no longer connected."); s_logger.error("Host is no longer connected.");
@ -6613,6 +6565,8 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
cfmMo.ensureCustomFieldDef("VirtualMachine", CustomFieldConstants.CLOUD_UUID); cfmMo.ensureCustomFieldDef("VirtualMachine", CustomFieldConstants.CLOUD_UUID);
cfmMo.ensureCustomFieldDef("VirtualMachine", CustomFieldConstants.CLOUD_NIC_MASK); cfmMo.ensureCustomFieldDef("VirtualMachine", CustomFieldConstants.CLOUD_NIC_MASK);
cfmMo.ensureCustomFieldDef("VirtualMachine", CustomFieldConstants.CLOUD_VM_INTERNAL_NAME); cfmMo.ensureCustomFieldDef("VirtualMachine", CustomFieldConstants.CLOUD_VM_INTERNAL_NAME);
cfmMo.ensureCustomFieldDef("VirtualMachine", CustomFieldConstants.CLOUD_WORKER);
cfmMo.ensureCustomFieldDef("VirtualMachine", CustomFieldConstants.CLOUD_WORKER_TAG);
VmwareHypervisorHost hostMo = this.getHyperHost(context); VmwareHypervisorHost hostMo = this.getHyperHost(context);
_hostName = hostMo.getHyperHostName(); _hostName = hostMo.getHyperHostName();

View File

@ -218,6 +218,7 @@ public class VmwareSecondaryStorageResourceHandler implements SecondaryStorageRe
if (context != null) { if (context != null) {
context.registerStockObject("serviceconsole", cmd.getContextParam("serviceconsole")); context.registerStockObject("serviceconsole", cmd.getContextParam("serviceconsole"));
context.registerStockObject("manageportgroup", cmd.getContextParam("manageportgroup")); context.registerStockObject("manageportgroup", cmd.getContextParam("manageportgroup"));
context.registerStockObject("noderuninfo", cmd.getContextParam("noderuninfo"));
} }
currentContext.set(context); currentContext.set(context);
return context; return context;

View File

@ -178,7 +178,9 @@ public class VmwareStorageProcessor implements StorageProcessor {
} }
if(vmMo.createSnapshot("cloud.template.base", "Base snapshot", false, false)) { if(vmMo.createSnapshot("cloud.template.base", "Base snapshot", false, false)) {
vmMo.setCustomFieldValue(CustomFieldConstants.CLOUD_UUID, templateUuid); // the same template may be deployed with multiple copies at per-datastore per-host basis,
// save the original template name from CloudStack DB as the UUID to associate them.
vmMo.setCustomFieldValue(CustomFieldConstants.CLOUD_UUID, templateName);
vmMo.markAsTemplate(); vmMo.markAsTemplate();
} else { } else {
vmMo.destroy(); vmMo.destroy();

View File

@ -260,6 +260,7 @@ public enum Config {
VmwareRootDiskControllerType("Advanced", ManagementServer.class, String.class, "vmware.root.disk.controller", "ide", "Specify the default disk controller for root volumes, valid values are scsi, ide", null), VmwareRootDiskControllerType("Advanced", ManagementServer.class, String.class, "vmware.root.disk.controller", "ide", "Specify the default disk controller for root volumes, valid values are scsi, ide", null),
VmwareSystemVmNicDeviceType("Advanced", ManagementServer.class, String.class, "vmware.systemvm.nic.device.type", "E1000", "Specify the default network device type for system VMs, valid values are E1000, PCNet32, Vmxnet2, Vmxnet3", null), VmwareSystemVmNicDeviceType("Advanced", ManagementServer.class, String.class, "vmware.systemvm.nic.device.type", "E1000", "Specify the default network device type for system VMs, valid values are E1000, PCNet32, Vmxnet2, Vmxnet3", null),
VmwareRecycleHungWorker("Advanced", ManagementServer.class, Boolean.class, "vmware.recycle.hung.wokervm", "false", "Specify whether or not to recycle hung worker VMs", null), VmwareRecycleHungWorker("Advanced", ManagementServer.class, Boolean.class, "vmware.recycle.hung.wokervm", "false", "Specify whether or not to recycle hung worker VMs", null),
VmwareHungWorkerTimeout("Advanced", ManagementServer.class, Long.class, "vmware.hung.wokervm.timeout", "7200", "Worker VM timeout in seconds", null),
VmwareEnableNestedVirtualization("Advanced", ManagementServer.class, Boolean.class, "vmware.nested.virtualization", "false", "When set to true this will enable nested virtualization when this is supported by the hypervisor", null), VmwareEnableNestedVirtualization("Advanced", ManagementServer.class, Boolean.class, "vmware.nested.virtualization", "false", "When set to true this will enable nested virtualization when this is supported by the hypervisor", null),
// Midonet // Midonet

View File

@ -23,4 +23,6 @@ public interface CustomFieldConstants {
public final static String CLOUD_NIC_MASK = "cloud.nic.mask"; public final static String CLOUD_NIC_MASK = "cloud.nic.mask";
public final static String CLOUD_ZONE = "cloud.zone"; public final static String CLOUD_ZONE = "cloud.zone";
public final static String CLOUD_VM_INTERNAL_NAME = "cloud.vm.internal.name"; public final static String CLOUD_VM_INTERNAL_NAME = "cloud.vm.internal.name";
public final static String CLOUD_WORKER = "cloud.vm.worker";
public final static String CLOUD_WORKER_TAG = "cloud.vm.worker.tag";
} }

View File

@ -1233,8 +1233,24 @@ public class HypervisorHostHelper {
scsiControllerSpec.setOperation(VirtualDeviceConfigSpecOperation.ADD); scsiControllerSpec.setOperation(VirtualDeviceConfigSpecOperation.ADD);
vmConfig.getDeviceChange().add(scsiControllerSpec); vmConfig.getDeviceChange().add(scsiControllerSpec);
hyperHost.createVm(vmConfig); if(hyperHost.createVm(vmConfig)) {
workingVM = hyperHost.findVmOnHyperHost(vmName); // Ugly work-around, it takes time for newly created VM to appear
for(int i = 0; i < 10 && workingVM == null; i++) {
workingVM = hyperHost.findVmOnHyperHost(vmName);
try {
Thread.sleep(1000);
} catch(InterruptedException e) {
}
}
}
if(workingVM != null) {
workingVM.setCustomFieldValue(CustomFieldConstants.CLOUD_WORKER, "true");
String workerTag = String.format("%d-%s", System.currentTimeMillis(),
hyperHost.getContext().getStockObject("noderuninfo"));
workingVM.setCustomFieldValue(CustomFieldConstants.CLOUD_WORKER_TAG, workerTag);
}
return workingVM; return workingVM;
} }

View File

@ -1559,15 +1559,11 @@ public class VirtualMachineMO extends BaseMO {
assert(disks.length >= 1); assert(disks.length >= 1);
HostMO hostMo = getRunningHost(); HostMO hostMo = getRunningHost();
VirtualMachineConfigInfo vmConfigInfo = getConfigInfo();
if(!hostMo.createBlankVm(clonedVmName, null, 1, cpuSpeedMHz, 0, false, memoryMb, 0, vmConfigInfo.getGuestId(), morDs, false)) VirtualMachineMO clonedVmMo = HypervisorHostHelper.createWorkerVM(hostMo, new DatastoreMO(hostMo.getContext(), morDs), clonedVmName);
throw new Exception("Unable to create a blank VM");
VirtualMachineMO clonedVmMo = hostMo.findVmOnHyperHost(clonedVmName);
if(clonedVmMo == null) if(clonedVmMo == null)
throw new Exception("Unable to find just-created blank VM"); throw new Exception("Unable to find just-created blank VM");
boolean bSuccess = false; boolean bSuccess = false;
try { try {
VirtualMachineConfigSpec vmConfigSpec = new VirtualMachineConfigSpec(); VirtualMachineConfigSpec vmConfigSpec = new VirtualMachineConfigSpec();