From ea95ac180838e38e7dbcb8aeeddaa22a594ed0a1 Mon Sep 17 00:00:00 2001 From: Kelven Yang Date: Thu, 31 Mar 2011 17:13:26 -0700 Subject: [PATCH] bug 8713 : finalize the implementation of supporting system vm pooling --- .../com/cloud/agent/api/StartupCommand.java | 4 + api/src/com/cloud/host/Host.java | 1 + .../resource/NfsSecondaryStorageResource.java | 20 +++- core/src/com/cloud/vm/SecondaryStorageVm.java | 3 +- .../com/cloud/vm/SecondaryStorageVmVO.java | 23 ++++- .../cloud/agent/manager/AgentManagerImpl.java | 33 ++++--- .../src/com/cloud/configuration/Config.java | 6 +- .../consoleproxy/ConsoleProxyManagerImpl.java | 12 +-- server/src/com/cloud/host/dao/HostDao.java | 4 +- .../src/com/cloud/host/dao/HostDaoImpl.java | 13 ++- .../storage/download/DownloadMonitorImpl.java | 4 +- .../SecondaryStorageManagerImpl.java | 63 +++++++----- .../secondary/SecondaryStorageVmManager.java | 11 ++- .../storage/upload/UploadMonitorImpl.java | 5 +- .../com/cloud/vm/SystemVmLoadScanHandler.java | 7 +- .../src/com/cloud/vm/SystemVmLoadScanner.java | 9 +- .../cloud/vm/dao/SecondaryStorageVmDao.java | 18 ++-- .../vm/dao/SecondaryStorageVmDaoImpl.java | 99 ++++++++++++++++--- setup/db/create-schema.sql | 4 +- 19 files changed, 244 insertions(+), 95 deletions(-) diff --git a/api/src/com/cloud/agent/api/StartupCommand.java b/api/src/com/cloud/agent/api/StartupCommand.java index 4c23d5851cf..c55102734b3 100755 --- a/api/src/com/cloud/agent/api/StartupCommand.java +++ b/api/src/com/cloud/agent/api/StartupCommand.java @@ -63,6 +63,10 @@ public class StartupCommand extends Command { return type; } + public void setHostType(Host.Type type) { + this.type = type; + } + public String getIqn() { return iqn; } diff --git a/api/src/com/cloud/host/Host.java b/api/src/com/cloud/host/Host.java index db85aae47d0..2ae9b501a95 100755 --- a/api/src/com/cloud/host/Host.java +++ b/api/src/com/cloud/host/Host.java @@ -30,6 +30,7 @@ public interface Host { Storage(false), Routing(false), SecondaryStorage(false), + SecondaryStorageCmdExecutor(false), ConsoleProxy(true), ExternalFirewall(false), ExternalLoadBalancer(false), diff --git a/core/src/com/cloud/storage/resource/NfsSecondaryStorageResource.java b/core/src/com/cloud/storage/resource/NfsSecondaryStorageResource.java index 3b5e5728ad5..7cb6778357b 100755 --- a/core/src/com/cloud/storage/resource/NfsSecondaryStorageResource.java +++ b/core/src/com/cloud/storage/resource/NfsSecondaryStorageResource.java @@ -69,6 +69,7 @@ import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.NetUtils; import com.cloud.utils.net.NfsUtils; import com.cloud.utils.script.Script; +import com.cloud.vm.SecondaryStorageVm; public class NfsSecondaryStorageResource extends ServerResourceBase implements ServerResource { private static final Logger s_logger = Logger.getLogger(NfsSecondaryStorageResource.class); @@ -82,6 +83,7 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S String _guid; String _nfsPath; String _mountParent; + String _role; Map _params; StorageLayer _storage; boolean _inSystemVM = false; @@ -183,8 +185,6 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S return null; } - - private Answer execute(SecStorageFirewallCfgCommand cmd) { if (!_inSystemVM){ return new Answer(cmd, true, null); @@ -294,7 +294,10 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S @Override public Type getType() { - return Host.Type.SecondaryStorage; + if(SecondaryStorageVm.Role.templateProcessor.toString().equals(_role)) + return Host.Type.SecondaryStorage; + + return Host.Type.SecondaryStorageCmdExecutor; } @Override @@ -353,6 +356,11 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S s_logger.info("_configIpFirewallScr found in " + _configIpFirewallScr); } + _role = (String)params.get("role"); + if(_role == null) + _role = SecondaryStorageVm.Role.templateProcessor.toString(); + s_logger.info("Secondary storage runs in role " + _role); + _guid = (String)params.get("guid"); if (_guid == null) { throw new ConfigurationException("Unable to find the guid"); @@ -636,6 +644,7 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S final StartupStorageCommand cmd = new StartupStorageCommand(_parent, StoragePoolType.NetworkFilesystem, getTotalSize(), new HashMap()); + cmd.setHostType(getType()); cmd.setResourceType(Storage.StorageResourceType.SECONDARY_STORAGE); cmd.setIqn(null); @@ -646,7 +655,10 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S cmd.setName(_guid); cmd.setVersion(NfsSecondaryStorageResource.class.getPackage().getImplementationVersion()); /* gather TemplateInfo in second storage */ - final Map tInfo = _dlMgr.gatherTemplateInfo(); + + Map tInfo = new HashMap(); + if(SecondaryStorageVm.Role.templateProcessor.toString().equals(_role)) + tInfo = _dlMgr.gatherTemplateInfo(); cmd.setTemplateInfo(tInfo); cmd.getHostDetails().put("mount.parent", _mountParent); cmd.getHostDetails().put("mount.path", _nfsPath); diff --git a/core/src/com/cloud/vm/SecondaryStorageVm.java b/core/src/com/cloud/vm/SecondaryStorageVm.java index b43a3160788..94924f1170f 100644 --- a/core/src/com/cloud/vm/SecondaryStorageVm.java +++ b/core/src/com/cloud/vm/SecondaryStorageVm.java @@ -21,6 +21,7 @@ package com.cloud.vm; * Secondary Storage VM is a system VM instance that is used * to interface the management server to secondary storage */ -public interface SecondaryStorageVm extends SystemVm { +public interface SecondaryStorageVm extends SystemVm { + enum Role { templateProcessor, commandExecutor } } diff --git a/core/src/com/cloud/vm/SecondaryStorageVmVO.java b/core/src/com/cloud/vm/SecondaryStorageVmVO.java index d407ab3ad12..4617c244bd1 100644 --- a/core/src/com/cloud/vm/SecondaryStorageVmVO.java +++ b/core/src/com/cloud/vm/SecondaryStorageVmVO.java @@ -22,6 +22,8 @@ import java.util.Date; import javax.persistence.Column; import javax.persistence.DiscriminatorValue; import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; import javax.persistence.PrimaryKeyJoinColumn; import javax.persistence.Table; import javax.persistence.Temporal; @@ -52,17 +54,20 @@ public class SecondaryStorageVmVO extends VMInstanceVO implements SecondaryStora private String guid; @Column(name="nfs_share", nullable=false) - private String nfsShare; + private String nfsShare; + + @Column(name="role", nullable=false) + @Enumerated(value=EnumType.STRING) + private Role role; @Temporal(TemporalType.TIMESTAMP) @Column(name="last_update", updatable=true, nullable=true) private Date lastUpdateTime; - - public SecondaryStorageVmVO(long id, long serviceOfferingId, String name, long templateId, HypervisorType hypervisorType, long guestOSId, long dataCenterId, - long domainId, long accountId) { + long domainId, long accountId, Role role) { super(id, serviceOfferingId, name, name, Type.SecondaryStorageVm, templateId, hypervisorType, guestOSId, domainId, accountId, true); + this.role = role; } protected SecondaryStorageVmVO() { @@ -119,5 +124,13 @@ public class SecondaryStorageVmVO extends VMInstanceVO implements SecondaryStora public String getNfsShare() { return nfsShare; - } + } + + public Role getRole() { + return this.role; + } + + public void setRole(Role role) { + this.role = role; + } } diff --git a/server/src/com/cloud/agent/manager/AgentManagerImpl.java b/server/src/com/cloud/agent/manager/AgentManagerImpl.java index 04522a9ec7e..da4df79991d 100755 --- a/server/src/com/cloud/agent/manager/AgentManagerImpl.java +++ b/server/src/com/cloud/agent/manager/AgentManagerImpl.java @@ -2488,23 +2488,26 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, Host.Type type = null; if (startup instanceof StartupStorageCommand) { - StartupStorageCommand ssCmd = ((StartupStorageCommand) startup); - if (ssCmd.getResourceType() == Storage.StorageResourceType.SECONDARY_STORAGE) { - type = Host.Type.SecondaryStorage; - if (resource != null - && resource instanceof DummySecondaryStorageResource) { - resource = null; - } + if(ssCmd.getHostType() == Host.Type.SecondaryStorageCmdExecutor) { + type = ssCmd.getHostType(); } else { - type = Host.Type.Storage; - } - final Map hostDetails = ssCmd.getHostDetails(); - if (hostDetails != null) { - if (details != null) { - details.putAll(hostDetails); + if (ssCmd.getResourceType() == Storage.StorageResourceType.SECONDARY_STORAGE) { + type = Host.Type.SecondaryStorage; + if (resource != null + && resource instanceof DummySecondaryStorageResource) { + resource = null; + } } else { - details = hostDetails; + type = Host.Type.Storage; + } + final Map hostDetails = ssCmd.getHostDetails(); + if (hostDetails != null) { + if (details != null) { + details.putAll(hostDetails); + } else { + details = hostDetails; + } } } } else if (startup instanceof StartupRoutingCommand) { @@ -2530,7 +2533,7 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, type = Host.Type.PxeServer; } else if (startup instanceof StartupExternalDhcpCommand) { type = Host.Type.ExternalDhcp; - }else { + } else { assert false : "Did someone add a new Startup command?"; } diff --git a/server/src/com/cloud/configuration/Config.java b/server/src/com/cloud/configuration/Config.java index 974e3321c5e..3e5be400da7 100755 --- a/server/src/com/cloud/configuration/Config.java +++ b/server/src/com/cloud/configuration/Config.java @@ -152,7 +152,11 @@ public enum Config { MaxTemplateAndIsoSize("Advanced", ManagementServer.class, Long.class, "max.template.iso.size", "50", "The maximum size for a downloaded template or ISO (in GB).", null), SecStorageAllowedInternalDownloadSites("Advanced", ManagementServer.class, String.class, "secstorage.allowed.internal.sites", null, "Comma separated list of cidrs internal to the datacenter that can host template download servers", null), SecStorageEncryptCopy("Advanced", ManagementServer.class, Boolean.class, "secstorage.encrypt.copy", "false", "Use SSL method used to encrypt copy traffic between zones", "true,false"), - SecStorageSecureCopyCert("Advanced", ManagementServer.class, String.class, "secstorage.ssl.cert.domain", "realhostip.com", "SSL certificate used to encrypt copy traffic between zones", null), + SecStorageSecureCopyCert("Advanced", ManagementServer.class, String.class, "secstorage.ssl.cert.domain", "realhostip.com", "SSL certificate used to encrypt copy traffic between zones", null), + SecStorageCapacityStandby("Advanced", AgentManager.class, Integer.class, "secstorage.capacity.standby", "10", "The minimal number of command execution sessions that system is able to serve immediately(standby capacity)", null), + SecStorageSessionMax("Advanced", AgentManager.class, Integer.class, "secstorage.session.max", "50", "The max number of command execution sessions that a SSVM can handle", null), + SecStorageCmdExecutionTimeMax("Advanced", AgentManager.class, Integer.class, "secstorage.cmd.execution.time.max", "30", "The max command execution time in minute", null), + DirectAttachNetworkEnabled("Advanced", ManagementServer.class, Boolean.class, "direct.attach.network.externalIpAllocator.enabled", "false", "Direct-attach VMs using external DHCP server", "true,false"), DirectAttachNetworkExternalAPIURL("Advanced", ManagementServer.class, String.class, "direct.attach.network.externalIpAllocator.url", null, "Direct-attach VMs using external DHCP server (API url)", null), CheckPodCIDRs("Advanced", ManagementServer.class, String.class, "check.pod.cidrs", "true", "If true, different pods must belong to different CIDR subnets.", "true,false"), diff --git a/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java b/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java index 911bac09eb2..d7b7807fe37 100644 --- a/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java +++ b/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java @@ -1478,12 +1478,12 @@ public class ConsoleProxyManagerImpl implements ConsoleProxyManager, ConsoleProx } @Override - public AfterScanAction scanPool(Long pool) { + public Pair scanPool(Long pool) { long dataCenterId = pool.longValue(); ConsoleProxyLoadInfo proxyInfo = this._zoneProxyCountMap.get(dataCenterId); if(proxyInfo == null) - return AfterScanAction.nop; + return new Pair(AfterScanAction.nop, null); ConsoleProxyLoadInfo vmInfo = this._zoneVmCountMap.get(dataCenterId); if(vmInfo == null) @@ -1493,20 +1493,20 @@ public class ConsoleProxyManagerImpl implements ConsoleProxyManager, ConsoleProx if(s_logger.isDebugEnabled()) s_logger.debug("Expand console proxy standby capacity for zone " + proxyInfo.getName()); - return AfterScanAction.expand; + return new Pair(AfterScanAction.expand, null); } - return AfterScanAction.nop; + return new Pair(AfterScanAction.nop, null); } @Override - public void expandPool(Long pool) { + public void expandPool(Long pool, Object actionArgs) { long dataCenterId = pool.longValue(); allocCapacity(dataCenterId); } @Override - public void shrinkPool(Long pool) { + public void shrinkPool(Long pool, Object actionArgs) { } @Override diff --git a/server/src/com/cloud/host/dao/HostDao.java b/server/src/com/cloud/host/dao/HostDao.java index 7018f1e58c4..3cc6f9990c5 100644 --- a/server/src/com/cloud/host/dao/HostDao.java +++ b/server/src/com/cloud/host/dao/HostDao.java @@ -95,7 +95,9 @@ public interface HostDao extends GenericDao { * @param macAddress * @return HostVO or null if not found. */ - public HostVO findByGuid(String macAddress); + public HostVO findByGuid(String macAddress); + + public HostVO findByName(String name); /** diff --git a/server/src/com/cloud/host/dao/HostDaoImpl.java b/server/src/com/cloud/host/dao/HostDaoImpl.java index 3320ed537f9..77d14abe832 100644 --- a/server/src/com/cloud/host/dao/HostDaoImpl.java +++ b/server/src/com/cloud/host/dao/HostDaoImpl.java @@ -75,7 +75,8 @@ public class HostDaoImpl extends GenericDaoBase implements HostDao protected final SearchBuilder PodSearch; protected final SearchBuilder TypeSearch; protected final SearchBuilder StatusSearch; - protected final SearchBuilder NameLikeSearch; + protected final SearchBuilder NameLikeSearch; + protected final SearchBuilder NameSearch; protected final SearchBuilder SequenceSearch; protected final SearchBuilder DirectlyConnectedSearch; protected final SearchBuilder UnmanagedDirectConnectSearch; @@ -183,6 +184,10 @@ public class HostDaoImpl extends GenericDaoBase implements HostDao NameLikeSearch = createSearchBuilder(); NameLikeSearch.and("name", NameLikeSearch.entity().getName(), SearchCriteria.Op.LIKE); NameLikeSearch.done(); + + NameSearch = createSearchBuilder(); + NameSearch.and("name", NameSearch.entity().getName(), SearchCriteria.Op.EQ); + NameSearch.done(); SequenceSearch = createSearchBuilder(); SequenceSearch.and("id", SequenceSearch.entity().getId(), SearchCriteria.Op.EQ); @@ -513,6 +518,12 @@ public class HostDaoImpl extends GenericDaoBase implements HostDao public HostVO findByGuid(String guid) { SearchCriteria sc = GuidSearch.create("guid", guid); return findOneBy(sc); + } + + @Override + public HostVO findByName(String name) { + SearchCriteria sc = NameSearch.create("name", name); + return findOneBy(sc); } @Override diff --git a/server/src/com/cloud/storage/download/DownloadMonitorImpl.java b/server/src/com/cloud/storage/download/DownloadMonitorImpl.java index 8e3a20afcf4..959f0f89b19 100755 --- a/server/src/com/cloud/storage/download/DownloadMonitorImpl.java +++ b/server/src/com/cloud/storage/download/DownloadMonitorImpl.java @@ -44,7 +44,6 @@ import com.cloud.dc.dao.ClusterDao; import com.cloud.dc.dao.DataCenterDao; import com.cloud.event.EventTypes; import com.cloud.event.UsageEventVO; -import com.cloud.event.dao.EventDao; import com.cloud.event.dao.UsageEventDao; import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.StorageUnavailableException; @@ -68,6 +67,7 @@ import com.cloud.storage.template.TemplateInfo; import com.cloud.user.Account; import com.cloud.utils.component.Inject; import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.vm.SecondaryStorageVm; import com.cloud.vm.SecondaryStorageVmVO; import com.cloud.vm.VirtualMachine.State; import com.cloud.vm.dao.SecondaryStorageVmDao; @@ -238,7 +238,7 @@ public class DownloadMonitorImpl implements DownloadMonitor { } private String generateCopyUrl(HostVO sourceServer, VMTemplateHostVO srcTmpltHost) { - List ssVms = _secStorageVmDao.getSecStorageVmListInStates(sourceServer.getDataCenterId(), State.Running); + List ssVms = _secStorageVmDao.getSecStorageVmListInStates(SecondaryStorageVm.Role.templateProcessor, sourceServer.getDataCenterId(), State.Running); if (ssVms.size() > 0) { SecondaryStorageVmVO ssVm = ssVms.get(0); if (ssVm.getPublicIpAddress() == null) { diff --git a/server/src/com/cloud/storage/secondary/SecondaryStorageManagerImpl.java b/server/src/com/cloud/storage/secondary/SecondaryStorageManagerImpl.java index 349830354e4..22bb4f769a2 100644 --- a/server/src/com/cloud/storage/secondary/SecondaryStorageManagerImpl.java +++ b/server/src/com/cloud/storage/secondary/SecondaryStorageManagerImpl.java @@ -31,6 +31,7 @@ import org.apache.log4j.Logger; import com.cloud.agent.AgentManager; import com.cloud.agent.api.Answer; +import com.cloud.agent.api.Command; import com.cloud.agent.api.RebootCommand; import com.cloud.agent.api.SecStorageFirewallCfgCommand; import com.cloud.agent.api.SecStorageSetupCommand; @@ -89,6 +90,7 @@ import com.cloud.utils.net.NfsUtils; import com.cloud.vm.Nic; import com.cloud.vm.NicProfile; import com.cloud.vm.ReservationContext; +import com.cloud.vm.SecondaryStorageVm; import com.cloud.vm.SecondaryStorageVmVO; import com.cloud.vm.SystemVmLoadScanHandler; import com.cloud.vm.SystemVmLoadScanner; @@ -138,7 +140,7 @@ public class SecondaryStorageManagerImpl implements SecondaryStorageVmManager, V private Adapters _ssVmAllocators; @Inject - private SecondaryStorageVmDao _secStorageVmDao; + protected SecondaryStorageVmDao _secStorageVmDao; @Inject private DataCenterDao _dcDao; @Inject @@ -164,7 +166,7 @@ public class SecondaryStorageManagerImpl implements SecondaryStorageVmManager, V private ServiceOfferingVO _serviceOffering; @Inject - private ConfigurationDao _configDao; + protected ConfigurationDao _configDao; @Inject private ServiceOfferingDao _offeringDao; @Inject @@ -225,7 +227,7 @@ public class SecondaryStorageManagerImpl implements SecondaryStorageVmManager, V @Override public boolean generateSetupCommand(Long zoneId) { - List zoneSsvms = _secStorageVmDao.listByZoneId(zoneId); + List zoneSsvms = _secStorageVmDao.listByZoneId(SecondaryStorageVm.Role.templateProcessor, zoneId); if (zoneSsvms.size() == 0) { return true; } @@ -275,8 +277,13 @@ public class SecondaryStorageManagerImpl implements SecondaryStorageVmManager, V } } + @Override + public Pair assignSecStorageVm(long zoneId, Command cmd) { + return null; + } + private boolean generateFirewallConfigurationForZone(Long zoneId) { - List zoneSsvms = _secStorageVmDao.listByZoneId(zoneId); + List zoneSsvms = _secStorageVmDao.listByZoneId(SecondaryStorageVm.Role.templateProcessor, zoneId); if (zoneSsvms.size() == 0) { return true; } @@ -291,7 +298,7 @@ public class SecondaryStorageManagerImpl implements SecondaryStorageVmManager, V s_logger.warn("No storage hosts found in zone " + zoneId + " , skip programming firewall rules"); return true; } - List alreadyRunning = _secStorageVmDao.getSecStorageVmListInStates(State.Running, State.Migrating, State.Starting); + List alreadyRunning = _secStorageVmDao.getSecStorageVmListInStates(SecondaryStorageVm.Role.templateProcessor, State.Running, State.Migrating, State.Starting); String copyPort = Integer.toString(TemplateConstants.DEFAULT_TMPLT_COPY_PORT); SecStorageFirewallCfgCommand cpc = new SecStorageFirewallCfgCommand(); @@ -321,13 +328,13 @@ public class SecondaryStorageManagerImpl implements SecondaryStorageVmManager, V } - public SecondaryStorageVmVO startNew(long dataCenterId) { + public SecondaryStorageVmVO startNew(long dataCenterId, SecondaryStorageVm.Role role) { if (s_logger.isDebugEnabled()) { s_logger.debug("Assign secondary storage vm from a newly started instance for request from data center : " + dataCenterId); } - Map context = createSecStorageVmInstance(dataCenterId); + Map context = createSecStorageVmInstance(dataCenterId, role); long secStorageVmId = (Long) context.get("secStorageVmId"); if (secStorageVmId == 0) { @@ -360,7 +367,7 @@ public class SecondaryStorageManagerImpl implements SecondaryStorageVmManager, V return null; } - protected Map createSecStorageVmInstance(long dataCenterId) { + protected Map createSecStorageVmInstance(long dataCenterId, SecondaryStorageVm.Role role) { HostVO secHost = _hostDao.findSecondaryStorageHost(dataCenterId); if (secHost == null) { String msg = "No secondary storage available in zone " + dataCenterId + ", cannot create secondary storage vm"; @@ -406,7 +413,7 @@ public class SecondaryStorageManagerImpl implements SecondaryStorageVmManager, V } SecondaryStorageVmVO secStorageVm = new SecondaryStorageVmVO(id, _serviceOffering.getId(), name, template.getId(), - template.getHypervisorType(), template.getGuestOSId(), dataCenterId, systemAcct.getDomainId(), systemAcct.getId()); + template.getHypervisorType(), template.getGuestOSId(), dataCenterId, systemAcct.getDomainId(), systemAcct.getId(), role); try { secStorageVm = _itMgr.allocate(secStorageVm, template, _serviceOffering, networks, plan, null, systemAcct); } catch (InsufficientCapacityException e) { @@ -434,7 +441,7 @@ public class SecondaryStorageManagerImpl implements SecondaryStorageVmManager, V return null; } - public SecondaryStorageVmVO assignSecStorageVmFromRunningPool(long dataCenterId) { + public SecondaryStorageVmVO assignSecStorageVmFromRunningPool(long dataCenterId, SecondaryStorageVm.Role role) { if (s_logger.isTraceEnabled()) { s_logger.trace("Assign secondary storage vm from running pool for request from data center : " + dataCenterId); @@ -442,7 +449,7 @@ public class SecondaryStorageManagerImpl implements SecondaryStorageVmManager, V SecondaryStorageVmAllocator allocator = getCurrentAllocator(); assert (allocator != null); - List runningList = _secStorageVmDao.getSecStorageVmListInStates(dataCenterId, State.Running); + List runningList = _secStorageVmDao.getSecStorageVmListInStates(role, dataCenterId, State.Running); if (runningList != null && runningList.size() > 0) { if (s_logger.isTraceEnabled()) { s_logger.trace("Running secondary storage vm pool size : " + runningList.size()); @@ -462,8 +469,8 @@ public class SecondaryStorageManagerImpl implements SecondaryStorageVmManager, V return null; } - public SecondaryStorageVmVO assignSecStorageVmFromStoppedPool(long dataCenterId) { - List l = _secStorageVmDao.getSecStorageVmListInStates(dataCenterId, State.Starting, State.Stopped, State.Migrating); + public SecondaryStorageVmVO assignSecStorageVmFromStoppedPool(long dataCenterId, SecondaryStorageVm.Role role) { + List l = _secStorageVmDao.getSecStorageVmListInStates(role, dataCenterId, State.Starting, State.Stopped, State.Migrating); if (l != null && l.size() > 0) { return l.get(0); } @@ -471,13 +478,13 @@ public class SecondaryStorageManagerImpl implements SecondaryStorageVmManager, V return null; } - private void allocCapacity(long dataCenterId) { + private void allocCapacity(long dataCenterId, SecondaryStorageVm.Role role) { if (s_logger.isTraceEnabled()) { s_logger.trace("Allocate secondary storage vm standby capacity for data center : " + dataCenterId); } boolean secStorageVmFromStoppedPool = false; - SecondaryStorageVmVO secStorageVm = assignSecStorageVmFromStoppedPool(dataCenterId); + SecondaryStorageVmVO secStorageVm = assignSecStorageVmFromStoppedPool(dataCenterId, role); if (secStorageVm == null) { if (s_logger.isInfoEnabled()) { s_logger.info("No stopped secondary storage vm is available, need to allocate a new secondary storage vm"); @@ -485,7 +492,7 @@ public class SecondaryStorageManagerImpl implements SecondaryStorageVmManager, V if (_allocLock.lock(ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_SYNC)) { try { - secStorageVm = startNew(dataCenterId); + secStorageVm = startNew(dataCenterId, role); } finally { _allocLock.unlock(); } @@ -853,7 +860,12 @@ public class SecondaryStorageManagerImpl implements SecondaryStorageVmManager, V buf.append(" zone=").append(dest.getDataCenter().getId()); buf.append(" pod=").append(dest.getPod().getId()); - buf.append(" guid=").append(secHost.getGuid()); + + if(profile.getVirtualMachine().getRole() == SecondaryStorageVm.Role.templateProcessor) + buf.append(" guid=").append(secHost.getGuid()); + else + buf.append(" guid=").append(profile.getVirtualMachine().getName()); + String nfsMountPoint = null; try { nfsMountPoint = NfsUtils.url2Mount(secHost.getStorageUrl()); @@ -870,6 +882,7 @@ public class SecondaryStorageManagerImpl implements SecondaryStorageVmManager, V buf.append(" resource=com.cloud.storage.resource.NfsSecondaryStorageResource"); buf.append(" instance=SecStorage"); buf.append(" sslcopy=").append(Boolean.toString(_useSSlCopy)); + buf.append(" role=").append(profile.getVirtualMachine().getRole().toString()); boolean externalDhcp = false; String externalDhcpStr = _configDao.getValue("direct.attach.network.externalIpAllocator.enabled"); @@ -1030,34 +1043,34 @@ public class SecondaryStorageManagerImpl implements SecondaryStorageVmManager, V } @Override - public AfterScanAction scanPool(Long pool) { + public Pair scanPool(Long pool) { long dataCenterId = pool.longValue(); - List alreadyRunning = _secStorageVmDao.getSecStorageVmListInStates(dataCenterId, State.Running, + List alreadyRunning = _secStorageVmDao.getSecStorageVmListInStates(SecondaryStorageVm.Role.templateProcessor, dataCenterId, State.Running, State.Migrating, State.Starting); - List stopped = _secStorageVmDao.getSecStorageVmListInStates(dataCenterId, State.Stopped, + List stopped = _secStorageVmDao.getSecStorageVmListInStates(SecondaryStorageVm.Role.templateProcessor, dataCenterId, State.Stopped, State.Stopping); if (alreadyRunning.size() == 0) { if (stopped.size() == 0) { s_logger.info("No secondary storage vms found in datacenter id=" + dataCenterId + ", starting a new one"); - return AfterScanAction.expand; + return new Pair(AfterScanAction.expand, SecondaryStorageVm.Role.templateProcessor); } else { s_logger.warn("Stopped secondary storage vms found in datacenter id=" + dataCenterId + ", not restarting them automatically"); } } - return AfterScanAction.nop; + return new Pair(AfterScanAction.nop, SecondaryStorageVm.Role.templateProcessor); } @Override - public void expandPool(Long pool) { + public void expandPool(Long pool, Object actionArgs) { long dataCenterId = pool.longValue(); - allocCapacity(dataCenterId); + allocCapacity(dataCenterId, (SecondaryStorageVm.Role)actionArgs); } @Override - public void shrinkPool(Long pool) { + public void shrinkPool(Long pool, Object actionArgs) { } @Override diff --git a/server/src/com/cloud/storage/secondary/SecondaryStorageVmManager.java b/server/src/com/cloud/storage/secondary/SecondaryStorageVmManager.java index aa9c0ff69bb..abb9b6946c7 100644 --- a/server/src/com/cloud/storage/secondary/SecondaryStorageVmManager.java +++ b/server/src/com/cloud/storage/secondary/SecondaryStorageVmManager.java @@ -17,7 +17,10 @@ */ package com.cloud.storage.secondary; +import com.cloud.agent.api.Command; import com.cloud.agent.api.StartupCommand; +import com.cloud.host.HostVO; +import com.cloud.utils.Pair; import com.cloud.utils.component.Manager; import com.cloud.vm.SecondaryStorageVmVO; @@ -25,6 +28,9 @@ public interface SecondaryStorageVmManager extends Manager { public static final int DEFAULT_SS_VM_RAMSIZE = 256; // 256M public static final int DEFAULT_SS_VM_CPUMHZ = 500; // 500 MHz + + public static final int DEFAULT_SS_VM_CAPACITY = 50; // max command execution session per SSVM + public static final int DEFAULT_STANDBY_CAPACITY = 10; // standy capacity to reserve per zone public static final String ALERT_SUBJECT = "secondarystoragevm-alert"; @@ -34,6 +40,7 @@ public interface SecondaryStorageVmManager extends Manager { public boolean destroySecStorageVm(long ssVmVmId); public void onAgentConnect(Long dcId, StartupCommand cmd); public boolean generateFirewallConfiguration(Long agentId); - public boolean generateSetupCommand(Long zoneId); - + public boolean generateSetupCommand(Long zoneId); + + public Pair assignSecStorageVm(long zoneId, Command cmd); } diff --git a/server/src/com/cloud/storage/upload/UploadMonitorImpl.java b/server/src/com/cloud/storage/upload/UploadMonitorImpl.java index b02aec8bf33..214fe68099b 100755 --- a/server/src/com/cloud/storage/upload/UploadMonitorImpl.java +++ b/server/src/com/cloud/storage/upload/UploadMonitorImpl.java @@ -47,6 +47,7 @@ import com.cloud.utils.component.Inject; import com.cloud.utils.concurrency.NamedThreadFactory; import com.cloud.utils.db.GlobalLock; import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.vm.SecondaryStorageVm; import com.cloud.vm.SecondaryStorageVmVO; import com.cloud.vm.VirtualMachine.State; import com.cloud.vm.dao.SecondaryStorageVmDao; @@ -210,7 +211,7 @@ public class UploadMonitorImpl implements UploadMonitor { } //Construct actual URL locally now that the symlink exists at SSVM - List ssVms = _secStorageVmDao.getSecStorageVmListInStates(dataCenterId, State.Running); + List ssVms = _secStorageVmDao.getSecStorageVmListInStates(SecondaryStorageVm.Role.templateProcessor, dataCenterId, State.Running); if (ssVms.size() > 0) { SecondaryStorageVmVO ssVm = ssVms.get(0); if (ssVm.getPublicIpAddress() == null) { @@ -259,7 +260,7 @@ public class UploadMonitorImpl implements UploadMonitor { uploadJob.setLastUpdated(new Date()); _uploadDao.update(uploadJob.getId(), uploadJob); - List ssVms = _secStorageVmDao.getSecStorageVmListInStates(dataCenterId, State.Running); + List ssVms = _secStorageVmDao.getSecStorageVmListInStates(SecondaryStorageVm.Role.templateProcessor, dataCenterId, State.Running); if (ssVms.size() == 0){ errorString = "Couldnt find a running SSVM in the zone" + dataCenterId+ ". Couldnt create the extraction URL."; throw new CloudRuntimeException(errorString); diff --git a/server/src/com/cloud/vm/SystemVmLoadScanHandler.java b/server/src/com/cloud/vm/SystemVmLoadScanHandler.java index ced7e9e6ddb..0b7be848d0c 100644 --- a/server/src/com/cloud/vm/SystemVmLoadScanHandler.java +++ b/server/src/com/cloud/vm/SystemVmLoadScanHandler.java @@ -1,5 +1,6 @@ package com.cloud.vm; +import com.cloud.utils.Pair; import com.cloud.vm.SystemVmLoadScanner.AfterScanAction; public interface SystemVmLoadScanHandler { @@ -9,9 +10,9 @@ public interface SystemVmLoadScanHandler { T[] getScannablePools(); boolean isPoolReadyForScan(T pool); - AfterScanAction scanPool(T pool); - void expandPool(T pool); - void shrinkPool(T pool); + Pair scanPool(T pool); + void expandPool(T pool, Object actionArgs); + void shrinkPool(T pool, Object actionArgs); void onScanEnd(); } diff --git a/server/src/com/cloud/vm/SystemVmLoadScanner.java b/server/src/com/cloud/vm/SystemVmLoadScanner.java index d37fb67d1b7..26742bdb43c 100644 --- a/server/src/com/cloud/vm/SystemVmLoadScanner.java +++ b/server/src/com/cloud/vm/SystemVmLoadScanner.java @@ -7,6 +7,7 @@ import java.util.concurrent.TimeUnit; import org.apache.log4j.Logger; import com.cloud.maid.StackMaid; +import com.cloud.utils.Pair; import com.cloud.utils.concurrency.NamedThreadFactory; import com.cloud.utils.db.GlobalLock; import com.cloud.utils.db.Transaction; @@ -86,16 +87,18 @@ public class SystemVmLoadScanner { T[] pools = _scanHandler.getScannablePools(); for(T p : pools) { if(_scanHandler.isPoolReadyForScan(p)) { - switch(_scanHandler.scanPool(p)) { + Pair actionInfo = _scanHandler.scanPool(p); + + switch(actionInfo.first()) { case nop: break; case expand: - _scanHandler.expandPool(p); + _scanHandler.expandPool(p, actionInfo.second()); break; case shrink: - _scanHandler.shrinkPool(p); + _scanHandler.shrinkPool(p, actionInfo.second()); break; } } diff --git a/server/src/com/cloud/vm/dao/SecondaryStorageVmDao.java b/server/src/com/cloud/vm/dao/SecondaryStorageVmDao.java index 1bd3c69938b..352afbffd83 100644 --- a/server/src/com/cloud/vm/dao/SecondaryStorageVmDao.java +++ b/server/src/com/cloud/vm/dao/SecondaryStorageVmDao.java @@ -20,21 +20,23 @@ package com.cloud.vm.dao; import java.util.List; import com.cloud.utils.db.GenericDao; +import com.cloud.vm.SecondaryStorageVm; import com.cloud.vm.SecondaryStorageVmVO; import com.cloud.vm.VirtualMachine.State; public interface SecondaryStorageVmDao extends GenericDao { - public List getSecStorageVmListInStates(long dataCenterId, State... states); - public List getSecStorageVmListInStates(State... states); + public List getSecStorageVmListInStates(SecondaryStorageVm.Role role, long dataCenterId, State... states); + public List getSecStorageVmListInStates(SecondaryStorageVm.Role role, State... states); - public List listByHostId(long hostId); - public List listByLastHostId(long hostId); + public List listByHostId(SecondaryStorageVm.Role role, long hostId); + public List listByLastHostId(SecondaryStorageVm.Role role, long hostId); - public List listUpByHostId(long hostId); + public List listUpByHostId(SecondaryStorageVm.Role role, long hostId); - public List listByZoneId(long zoneId); + public List listByZoneId(SecondaryStorageVm.Role role, long zoneId); - - public List getRunningSecStorageVmListByMsid(long msid); + public List getRunningSecStorageVmListByMsid(SecondaryStorageVm.Role role, long msid); + + public List listRunningSecStorageOrderByLoad(SecondaryStorageVm.Role role, long zoneId); } diff --git a/server/src/com/cloud/vm/dao/SecondaryStorageVmDaoImpl.java b/server/src/com/cloud/vm/dao/SecondaryStorageVmDaoImpl.java index 6f6c35c2b87..6414bedd508 100644 --- a/server/src/com/cloud/vm/dao/SecondaryStorageVmDaoImpl.java +++ b/server/src/com/cloud/vm/dao/SecondaryStorageVmDaoImpl.java @@ -33,6 +33,7 @@ import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.Transaction; import com.cloud.utils.db.UpdateBuilder; +import com.cloud.vm.SecondaryStorageVm; import com.cloud.vm.SecondaryStorageVmVO; import com.cloud.vm.VirtualMachine.State; @@ -54,28 +55,34 @@ public class SecondaryStorageVmDaoImpl extends GenericDaoBase getSecStorageVmListInStates(long dataCenterId, State... states) { + public List getSecStorageVmListInStates(SecondaryStorageVm.Role role, long dataCenterId, State... states) { SearchCriteria sc = DataCenterStatusSearch.create(); sc.setParameters("states", (Object[])states); - sc.setParameters("dc", dataCenterId); + sc.setParameters("dc", dataCenterId); + if(role != null) + sc.setParameters("role", role); return listBy(sc); } @Override - public List getSecStorageVmListInStates(State... states) { + public List getSecStorageVmListInStates(SecondaryStorageVm.Role role, State... states) { SearchCriteria sc = StateSearch.create(); - sc.setParameters("states", (Object[])states); + sc.setParameters("states", (Object[])states); + if(role != null) + sc.setParameters("role", role); + return listBy(sc); } @Override - public List listByHostId(long hostId) { + public List listByHostId(SecondaryStorageVm.Role role, long hostId) { SearchCriteria sc = HostSearch.create(); sc.setParameters("host", hostId); + if(role != null) + sc.setParameters("role", role); return listBy(sc); } @Override - public List listUpByHostId(long hostId) { + public List listUpByHostId(SecondaryStorageVm.Role role, long hostId) { SearchCriteria sc = HostUpSearch.create(); sc.setParameters("host", hostId); sc.setParameters("states", new Object[] {State.Destroyed, State.Stopped, State.Expunging}); + if(role != null) + sc.setParameters("role", role); return listBy(sc); } @Override - public List getRunningSecStorageVmListByMsid(long msid) { + public List getRunningSecStorageVmListByMsid(SecondaryStorageVm.Role role, long msid) { List l = new ArrayList(); Transaction txn = Transaction.currentTxn();; PreparedStatement pstmt = null; - try { - pstmt = txn.prepareAutoCloseStatement( - "SELECT s.id FROM secondary_storage_vm s, vm_instance v, host h " + - "WHERE s.id=v.id AND v.state='Running' AND v.host_id=h.id AND h.mgmt_server_id=?"); + try { + String sql; + if(role == null) + sql = "SELECT s.id FROM secondary_storage_vm s, vm_instance v, host h " + + "WHERE s.id=v.id AND v.state='Running' AND v.host_id=h.id AND h.mgmt_server_id=?"; + else + sql = "SELECT s.id FROM secondary_storage_vm s, vm_instance v, host h " + + "WHERE s.id=v.id AND v.state='Running' AND s.role=? AND v.host_id=h.id AND h.mgmt_server_id=?"; + + pstmt = txn.prepareAutoCloseStatement(sql); + + if(role == null) { + pstmt.setLong(1, msid); + } else { + pstmt.setString(1, role.toString()); + pstmt.setLong(2, msid); + } - pstmt.setLong(1, msid); ResultSet rs = pstmt.executeQuery(); while(rs.next()) { l.add(rs.getLong(1)); @@ -159,17 +188,57 @@ public class SecondaryStorageVmDaoImpl extends GenericDaoBase listByZoneId(long zoneId) { + public List listByZoneId(SecondaryStorageVm.Role role, long zoneId) { SearchCriteria sc = ZoneSearch.create(); sc.setParameters("zone", zoneId); + if(role != null) + sc.setParameters("role", role); return listBy(sc); } @Override - public List listByLastHostId(long hostId) { + public List listByLastHostId(SecondaryStorageVm.Role role, long hostId) { SearchCriteria sc = LastHostSearch.create(); sc.setParameters("lastHost", hostId); sc.setParameters("state", State.Stopped); + if(role != null) + sc.setParameters("role", role); + return listBy(sc); - } + } + + @Override + public List listRunningSecStorageOrderByLoad(SecondaryStorageVm.Role role, long zoneId) { + + List l = new ArrayList(); + Transaction txn = Transaction.currentTxn();; + PreparedStatement pstmt = null; + try { + String sql; + if(role == null) + sql = "SELECT s.id, count(l.id) as count FROM secondary_storage_vm s, vm_instance v, cmd_exec_log l " + + "WHERE s.id=v.id AND v.state='Running' AND v.data_center_id=? AND v.id=l.instance_id GROUP BY s.id ORDER BY count"; + else + sql = "SELECT s.id, count(l.id) as count FROM secondary_storage_vm s, vm_instance v, cmd_exec_log l " + + "WHERE s.id=v.id AND v.state='Running' AND v.data_center_id=? AND s.role=? AND v.id=l.instance_id GROUP BY s.id ORDER BY count"; + + pstmt = txn.prepareAutoCloseStatement(sql); + + if(role == null) { + pstmt.setLong(1, zoneId); + } else { + pstmt.setLong(1, zoneId); + pstmt.setString(2, role.toString()); + } + + ResultSet rs = pstmt.executeQuery(); + while(rs.next()) { + l.add(rs.getLong(1)); + } + } catch (SQLException e) { + s_logger.error("Unexpected exception ", e); + } + + return l; + } } diff --git a/setup/db/create-schema.sql b/setup/db/create-schema.sql index 28586a57510..4e74076a9df 100755 --- a/setup/db/create-schema.sql +++ b/setup/db/create-schema.sql @@ -951,6 +951,7 @@ CREATE TABLE `cloud`.`secondary_storage_vm` ( `guid` varchar(255) COMMENT 'copied from guid of secondary storage host', `nfs_share` varchar(255) COMMENT 'server and path exported by the nfs server ', `last_update` DATETIME NULL COMMENT 'Last session update time', + `role` varchar(64) NOT NULL DEFAULT 'templateProcessor' COMMENT 'work role of secondary storage host(templateProcessor | commandExecutor)', PRIMARY KEY (`id`), CONSTRAINT `fk_secondary_storage_vm__id` FOREIGN KEY `fk_secondary_storage_vm__id`(`id`) REFERENCES `vm_instance`(`id`) ON DELETE CASCADE ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; @@ -1483,8 +1484,9 @@ CREATE TABLE `cloud`.`domain_network_ref` ( CREATE TABLE `cloud`.`cmd_exec_log` ( `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `host_id` bigint unsigned NOT NULL COMMENT 'host id of the system VM agent that command is sent to', `instance_id` bigint unsigned NOT NULL COMMENT 'instance id of the system VM that command is executed on', - `command_name` bigint unsigned NOT NULL COMMENT 'command name', + `command_name` varchar(255) NOT NULL COMMENT 'command name', `created` datetime NOT NULL COMMENT 'date created', PRIMARY KEY (`id`), CONSTRAINT `fk_cmd_exec_log_ref__inst_id` FOREIGN KEY (`instance_id`) REFERENCES `vm_instance`(`id`) ON DELETE CASCADE