diff --git a/agent/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-agent.in b/agent/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-agent.in index 60e1e045b24..704ef6b05b4 100755 --- a/agent/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-agent.in +++ b/agent/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-agent.in @@ -26,7 +26,7 @@ # set environment variables -SHORTNAME="$0" +SHORTNAME="basename $0" PIDFILE=@PIDDIR@/"$SHORTNAME".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@AGENTLOG@ diff --git a/agent/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-agent.in b/agent/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-agent.in index 60e1e045b24..704ef6b05b4 100755 --- a/agent/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-agent.in +++ b/agent/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-agent.in @@ -26,7 +26,7 @@ # set environment variables -SHORTNAME="$0" +SHORTNAME="basename $0" PIDFILE=@PIDDIR@/"$SHORTNAME".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@AGENTLOG@ diff --git a/agent/distro/opensuse/sles/SYSCONFDIR/init.d/cloud-agent.in b/agent/distro/opensuse/sles/SYSCONFDIR/init.d/cloud-agent.in index 2422268f416..e684888b86e 100644 --- a/agent/distro/opensuse/sles/SYSCONFDIR/init.d/cloud-agent.in +++ b/agent/distro/opensuse/sles/SYSCONFDIR/init.d/cloud-agent.in @@ -33,7 +33,7 @@ # set environment variables -SHORTNAME="$0" +SHORTNAME="basename $0" PIDFILE=@PIDDIR@/"$SHORTNAME".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@AGENTLOG@ diff --git a/agent/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-agent.in b/agent/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-agent.in index 60e1e045b24..704ef6b05b4 100644 --- a/agent/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-agent.in +++ b/agent/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-agent.in @@ -26,7 +26,7 @@ # set environment variables -SHORTNAME="$0" +SHORTNAME="basename $0" PIDFILE=@PIDDIR@/"$SHORTNAME".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@AGENTLOG@ diff --git a/agent/distro/sles/SYSCONFDIR/init.d/cloud-agent.in b/agent/distro/sles/SYSCONFDIR/init.d/cloud-agent.in index 2422268f416..e684888b86e 100644 --- a/agent/distro/sles/SYSCONFDIR/init.d/cloud-agent.in +++ b/agent/distro/sles/SYSCONFDIR/init.d/cloud-agent.in @@ -33,7 +33,7 @@ # set environment variables -SHORTNAME="$0" +SHORTNAME="basename $0" PIDFILE=@PIDDIR@/"$SHORTNAME".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@AGENTLOG@ diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java index ec54ea14521..7994adab82e 100755 --- a/api/src/com/cloud/event/EventTypes.java +++ b/api/src/com/cloud/event/EventTypes.java @@ -493,10 +493,13 @@ public class EventTypes { entityEventDetails.put(EVENT_VM_REBOOT, VirtualMachine.class.getName()); entityEventDetails.put(EVENT_VM_UPDATE, VirtualMachine.class.getName()); entityEventDetails.put(EVENT_VM_UPGRADE, VirtualMachine.class.getName()); + entityEventDetails.put(EVENT_VM_DYNAMIC_SCALE, VirtualMachine.class.getName()); entityEventDetails.put(EVENT_VM_RESETPASSWORD, VirtualMachine.class.getName()); + entityEventDetails.put(EVENT_VM_RESETSSHKEY, VirtualMachine.class.getName()); entityEventDetails.put(EVENT_VM_MIGRATE, VirtualMachine.class.getName()); entityEventDetails.put(EVENT_VM_MOVE, VirtualMachine.class.getName()); entityEventDetails.put(EVENT_VM_RESTORE, VirtualMachine.class.getName()); + entityEventDetails.put(EVENT_VM_EXPUNGE, VirtualMachine.class.getName()); entityEventDetails.put(EVENT_ROUTER_CREATE, VirtualRouter.class.getName()); entityEventDetails.put(EVENT_ROUTER_DESTROY, VirtualRouter.class.getName()); @@ -544,9 +547,11 @@ public class EventTypes { entityEventDetails.put(EVENT_LB_CERT_REMOVE, LoadBalancer.class.getName()); // Account events + entityEventDetails.put(EVENT_ACCOUNT_ENABLE, Account.class.getName()); entityEventDetails.put(EVENT_ACCOUNT_DISABLE, Account.class.getName()); entityEventDetails.put(EVENT_ACCOUNT_CREATE, Account.class.getName()); entityEventDetails.put(EVENT_ACCOUNT_DELETE, Account.class.getName()); + entityEventDetails.put(EVENT_ACCOUNT_UPDATE, Account.class.getName()); entityEventDetails.put(EVENT_ACCOUNT_MARK_DEFAULT_ZONE, Account.class.getName()); // UserVO Events diff --git a/api/src/com/cloud/network/VpcVirtualNetworkApplianceService.java b/api/src/com/cloud/network/VpcVirtualNetworkApplianceService.java index eee62ceea76..382c460725d 100644 --- a/api/src/com/cloud/network/VpcVirtualNetworkApplianceService.java +++ b/api/src/com/cloud/network/VpcVirtualNetworkApplianceService.java @@ -16,10 +16,13 @@ // under the License. package com.cloud.network; +import java.util.Map; + import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.router.VirtualRouter; +import com.cloud.vm.VirtualMachineProfile; public interface VpcVirtualNetworkApplianceService extends VirtualNetworkApplianceService { @@ -27,13 +30,14 @@ public interface VpcVirtualNetworkApplianceService extends VirtualNetworkApplian * @param router * @param network * @param isRedundant + * @param params TODO * @return * @throws ConcurrentOperationException * @throws ResourceUnavailableException * @throws InsufficientCapacityException */ - boolean addVpcRouterToGuestNetwork(VirtualRouter router, Network network, boolean isRedundant) throws ConcurrentOperationException, ResourceUnavailableException, - InsufficientCapacityException; + boolean addVpcRouterToGuestNetwork(VirtualRouter router, Network network, boolean isRedundant, Map params) + throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException; /** * @param router diff --git a/core/src/com/cloud/info/ConsoleProxyInfo.java b/core/src/com/cloud/info/ConsoleProxyInfo.java index 9a94474efda..0e57b7551fc 100644 --- a/core/src/com/cloud/info/ConsoleProxyInfo.java +++ b/core/src/com/cloud/info/ConsoleProxyInfo.java @@ -32,16 +32,17 @@ public class ConsoleProxyInfo { this.sslEnabled = sslEnabled; if (sslEnabled) { - StringBuffer sb = new StringBuffer(proxyIpAddress); - for (int i = 0; i < sb.length(); i++) - if (sb.charAt(i) == '.') - sb.setCharAt(i, '-'); - if (consoleProxyUrlDomain != null && consoleProxyUrlDomain.length() > 0) { - sb.append("."); + StringBuffer sb = new StringBuffer(); + if (consoleProxyUrlDomain.startsWith("*")) { + sb.append(proxyIpAddress); + for (int i = 0; i < proxyIpAddress.length(); i++) + if (sb.charAt(i) == '.') + sb.setCharAt(i, '-'); + sb.append(consoleProxyUrlDomain.substring(1));//skip the * + } else { + //LB address sb.append(consoleProxyUrlDomain); - } else - sb.append(".realhostip.com"); - + } proxyAddress = sb.toString(); proxyPort = port; this.proxyUrlPort = proxyUrlPort; diff --git a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/CloudOrchestrator.java b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/CloudOrchestrator.java index 7969e43cdc5..fc1b85c0802 100755 --- a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/CloudOrchestrator.java +++ b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/CloudOrchestrator.java @@ -188,7 +188,7 @@ public class CloudOrchestrator implements OrchestrationService { rootDiskOfferingInfo.setDiskOffering(offering); rootDiskOfferingInfo.setSize(rootDiskSize); - if (offering.isCustomizedIops()) { + if (offering.isCustomizedIops() != null && offering.isCustomizedIops()) { Map userVmDetails = _userVmDetailsDao.listDetailsKeyPairs(vm.getId()); if (userVmDetails != null) { diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java index 166b523e387..4e6ab6ba300 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java @@ -777,12 +777,21 @@ public class TemplateServiceImpl implements TemplateService { String scheme = "http"; boolean _sslCopy = false; String sslCfg = _configDao.getValue(Config.SecStorageEncryptCopy.toString()); + String _ssvmUrlDomain = _configDao.getValue("secstorage.ssl.cert.domain"); if (sslCfg != null) { _sslCopy = Boolean.parseBoolean(sslCfg); } + if(_sslCopy && (_ssvmUrlDomain == null || _ssvmUrlDomain.isEmpty())){ + s_logger.warn("Empty secondary storage url domain, ignoring SSL"); + _sslCopy = false; + } if (_sslCopy) { - hostname = ipAddress.replace(".", "-"); - hostname = hostname + ".realhostip.com"; + if(_ssvmUrlDomain.startsWith("*")) { + hostname = ipAddress.replace(".", "-"); + hostname = hostname + _ssvmUrlDomain.substring(1); + } else { + hostname = _ssvmUrlDomain; + } scheme = "https"; } return scheme + "://" + hostname + "/copy/SecStorage/" + dir + "/" + path; diff --git a/packaging/centos63/cloud-agent.rc b/packaging/centos63/cloud-agent.rc index 40c358e36b6..af1c624eda2 100755 --- a/packaging/centos63/cloud-agent.rc +++ b/packaging/centos63/cloud-agent.rc @@ -26,7 +26,7 @@ # set environment variables -SHORTNAME="$0" +SHORTNAME="basename $0" PIDFILE=/var/run/"$SHORTNAME".pid LOCKFILE=/var/lock/subsys/"$SHORTNAME" LOGDIR=/var/log/cloudstack/agent diff --git a/packaging/centos63/cloud-ipallocator.rc b/packaging/centos63/cloud-ipallocator.rc index 9a24d8dfc8a..9d1adb43506 100755 --- a/packaging/centos63/cloud-ipallocator.rc +++ b/packaging/centos63/cloud-ipallocator.rc @@ -25,7 +25,7 @@ # set environment variables -SHORTNAME="$0" +SHORTNAME="basename $0" PIDFILE=/var/run/"$SHORTNAME".pid LOCKFILE=/var/lock/subsys/"$SHORTNAME" LOGFILE=/var/log/cloudstack/ipallocator/ipallocator.log diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/XenServerGuru.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/XenServerGuru.java index 529e26125f3..059e6e4139a 100644 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/XenServerGuru.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/XenServerGuru.java @@ -34,7 +34,6 @@ import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.storage.GuestOSVO; -import com.cloud.storage.Volume; import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.GuestOSDao; import com.cloud.storage.dao.VolumeDao; @@ -103,30 +102,30 @@ public class XenServerGuru extends HypervisorGuruBase implements HypervisorGuru List volumes = _volumeDao.findByInstance(vm.getId()); + // it's OK in this case to send a detach command to the host for a root volume as this + // will simply lead to the SR that supports the root volume being removed if (volumes != null) { for (VolumeVO volume : volumes) { - if (volume.getVolumeType() == Volume.Type.DATADISK) { - StoragePoolVO storagePool = _storagePoolDao.findById(volume.getPoolId()); + StoragePoolVO storagePool = _storagePoolDao.findById(volume.getPoolId()); - // storagePool should be null if we are expunging a volume that was never - // attached to a VM that was started (the "trick" for storagePool to be null - // is that none of the VMs this volume may have been attached to were ever started, - // so the volume was never assigned to a storage pool) - if (storagePool != null && storagePool.isManaged()) { - DataTO volTO = _volFactory.getVolume(volume.getId()).getTO(); - DiskTO disk = new DiskTO(volTO, volume.getDeviceId(), volume.getPath(), volume.getVolumeType()); + // storagePool should be null if we are expunging a volume that was never + // attached to a VM that was started (the "trick" for storagePool to be null + // is that none of the VMs this volume may have been attached to were ever started, + // so the volume was never assigned to a storage pool) + if (storagePool != null && storagePool.isManaged()) { + DataTO volTO = _volFactory.getVolume(volume.getId()).getTO(); + DiskTO disk = new DiskTO(volTO, volume.getDeviceId(), volume.getPath(), volume.getVolumeType()); - DettachCommand cmd = new DettachCommand(disk, vm.getInstanceName()); + DettachCommand cmd = new DettachCommand(disk, vm.getInstanceName()); - cmd.setManaged(true); + cmd.setManaged(true); - cmd.setStorageHost(storagePool.getHostAddress()); - cmd.setStoragePort(storagePool.getPort()); + cmd.setStorageHost(storagePool.getHostAddress()); + cmd.setStoragePort(storagePool.getPort()); - cmd.set_iScsiName(volume.get_iScsiName()); + cmd.set_iScsiName(volume.get_iScsiName()); - commands.add(cmd); - } + commands.add(cmd); } } } diff --git a/plugins/storage/image/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackImageStoreDriverImpl.java b/plugins/storage/image/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackImageStoreDriverImpl.java index d6e1a01b49c..c2e26d52f65 100644 --- a/plugins/storage/image/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackImageStoreDriverImpl.java +++ b/plugins/storage/image/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackImageStoreDriverImpl.java @@ -93,12 +93,16 @@ public class CloudStackImageStoreDriverImpl extends BaseImageStoreDriverImpl { if (sslCfg != null) { _sslCopy = Boolean.parseBoolean(sslCfg); } + if(_sslCopy && (_ssvmUrlDomain == null || _ssvmUrlDomain.isEmpty())){ + s_logger.warn("Empty secondary storage url domain, ignoring SSL"); + _sslCopy = false; + } if (_sslCopy) { - hostname = ipAddress.replace(".", "-"); - if (_ssvmUrlDomain != null && _ssvmUrlDomain.length() > 0) { - hostname = hostname + "." + _ssvmUrlDomain; + if(_ssvmUrlDomain.startsWith("*")) { + hostname = ipAddress.replace(".", "-"); + hostname = hostname + _ssvmUrlDomain.substring(1); } else { - hostname = hostname + ".realhostip.com"; + hostname = _ssvmUrlDomain; } scheme = "https"; } diff --git a/python/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in b/python/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in index b6720f5b639..ae8d2157541 100755 --- a/python/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in +++ b/python/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in @@ -25,7 +25,7 @@ # set environment variables -SHORTNAME="$0" +SHORTNAME="basename $0" PIDFILE=@PIDDIR@/"$SHORTNAME".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@IPALOCATORLOG@ diff --git a/python/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in b/python/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in index aa7e8cf8820..49fd9b6f237 100755 --- a/python/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in +++ b/python/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in @@ -25,7 +25,7 @@ # set environment variables -SHORTNAME="$0" +SHORTNAME="basename $0" PIDFILE=@PIDDIR@/"$SHORTNAME".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@AGENTLOG@ diff --git a/python/distro/opensuse/SYSCONFDIR/init.d/cloud-ipallocator.in b/python/distro/opensuse/SYSCONFDIR/init.d/cloud-ipallocator.in index 7aa456df51c..901d5845f39 100755 --- a/python/distro/opensuse/SYSCONFDIR/init.d/cloud-ipallocator.in +++ b/python/distro/opensuse/SYSCONFDIR/init.d/cloud-ipallocator.in @@ -32,7 +32,7 @@ # set environment variables -SHORTNAME="$0" +SHORTNAME="basename $0" PIDFILE=@PIDDIR@/"$SHORTNAME".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@AGENTLOG@ diff --git a/python/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in b/python/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in index aa7e8cf8820..49fd9b6f237 100644 --- a/python/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in +++ b/python/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in @@ -25,7 +25,7 @@ # set environment variables -SHORTNAME="$0" +SHORTNAME="basename $0" PIDFILE=@PIDDIR@/"$SHORTNAME".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@AGENTLOG@ diff --git a/python/distro/sles/SYSCONFDIR/init.d/cloud-ipallocator.in b/python/distro/sles/SYSCONFDIR/init.d/cloud-ipallocator.in index 7aa456df51c..901d5845f39 100755 --- a/python/distro/sles/SYSCONFDIR/init.d/cloud-ipallocator.in +++ b/python/distro/sles/SYSCONFDIR/init.d/cloud-ipallocator.in @@ -32,7 +32,7 @@ # set environment variables -SHORTNAME="$0" +SHORTNAME="basename $0" PIDFILE=@PIDDIR@/"$SHORTNAME".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@AGENTLOG@ diff --git a/python/distro/ubuntu/SYSCONFDIR/init.d/cloud-ipallocator.in b/python/distro/ubuntu/SYSCONFDIR/init.d/cloud-ipallocator.in index ec84962b669..5ec6da07f23 100755 --- a/python/distro/ubuntu/SYSCONFDIR/init.d/cloud-ipallocator.in +++ b/python/distro/ubuntu/SYSCONFDIR/init.d/cloud-ipallocator.in @@ -26,7 +26,7 @@ # set environment variables -SHORTNAME="$0" +SHORTNAME="basename $0" PIDFILE=@PIDDIR@/"$SHORTNAME".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@AGENTLOG@ diff --git a/server/src/com/cloud/api/ApiDispatcher.java b/server/src/com/cloud/api/ApiDispatcher.java index 5d4b4d3368c..8f980d99038 100755 --- a/server/src/com/cloud/api/ApiDispatcher.java +++ b/server/src/com/cloud/api/ApiDispatcher.java @@ -21,6 +21,7 @@ import java.util.Map; import javax.annotation.PostConstruct; import javax.inject.Inject; +import com.cloud.event.EventTypes; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseAsyncCmd; import org.apache.cloudstack.api.BaseAsyncCreateCmd; @@ -82,8 +83,14 @@ public class ApiDispatcher { final BaseAsyncCmd asyncCmd = (BaseAsyncCmd)cmd; final String startEventId = params.get(ApiConstants.CTX_START_EVENT_ID); + String uuid = params.get("uuid"); ctx.setStartEventId(Long.valueOf(startEventId)); + // Fow now use the key from EventTypes.java rather than getInstanceType bcz the later doesn't refer to the interfaces + if(EventTypes.getEntityForEvent(asyncCmd.getEventType()) != null){ + ctx.putContextParameter(EventTypes.getEntityForEvent(asyncCmd.getEventType()), uuid); + } + // Synchronise job on the object if needed if (asyncCmd.getJob() != null && asyncCmd.getSyncObjId() != null && asyncCmd.getSyncObjType() != null) { Long queueSizeLimit = null; diff --git a/server/src/com/cloud/api/ApiServer.java b/server/src/com/cloud/api/ApiServer.java index a9b1130eed1..7ad7c106952 100755 --- a/server/src/com/cloud/api/ApiServer.java +++ b/server/src/com/cloud/api/ApiServer.java @@ -53,6 +53,7 @@ import javax.naming.ConfigurationException; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; +import com.cloud.event.EventTypes; import org.apache.cloudstack.acl.APIChecker; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; @@ -517,6 +518,8 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer objectUuid = createCmd.getEntityUuid(); params.put("id", objectId.toString()); } else { + // Extract the uuid before params are processed and id reflects internal db id + objectUuid = params.get("id"); dispatchChainFactory.getStandardDispatchChain().dispatch(new DispatchTask(cmdObj, params)); } @@ -528,10 +531,16 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer if (caller != null) { params.put("ctxAccountId", String.valueOf(caller.getId())); } + if(objectUuid != null){ + params.put("uuid", objectUuid); + } long startEventId = ctx.getStartEventId(); asyncCmd.setStartEventId(startEventId); + if(EventTypes.getEntityForEvent(asyncCmd.getEventType()) != null){ + ctx.putContextParameter(EventTypes.getEntityForEvent(asyncCmd.getEventType()), objectUuid); + } // save the scheduled event final Long eventId = ActionEventUtils.onScheduledActionEvent((callerUserId == null) ? User.UID_SYSTEM : callerUserId, asyncCmd.getEntityOwnerId(), asyncCmd.getEventType(), @@ -577,7 +586,7 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer !(cmdObj instanceof ListVolumesCmd) && !(cmdObj instanceof ListUsersCmd) && !(cmdObj instanceof ListAccountsCmd) && !(cmdObj instanceof ListStoragePoolsCmd) && !(cmdObj instanceof ListDiskOfferingsCmd) && !(cmdObj instanceof ListServiceOfferingsCmd) && !(cmdObj instanceof ListZonesByCmd)) { - buildAsyncListResponse((BaseListCmd)cmdObj, caller); + buildAsyncListResponse((BaseListCmd) cmdObj, caller); } SerializationContext.current().setUuidTranslation(true); diff --git a/server/src/com/cloud/api/dispatch/ParamGenericValidationWorker.java b/server/src/com/cloud/api/dispatch/ParamGenericValidationWorker.java index 0c829e8db07..f456468948b 100644 --- a/server/src/com/cloud/api/dispatch/ParamGenericValidationWorker.java +++ b/server/src/com/cloud/api/dispatch/ParamGenericValidationWorker.java @@ -37,9 +37,9 @@ import org.apache.log4j.Logger; */ public class ParamGenericValidationWorker implements DispatchWorker { - protected static Logger s_logger = Logger.getLogger(ParamGenericValidationWorker.class.getName()); + static Logger s_logger = Logger.getLogger(ParamGenericValidationWorker.class.getName()); - protected static List defaultParamNames = new ArrayList(); + protected static final List defaultParamNames = new ArrayList(); static { defaultParamNames.add(ApiConstants.CTX_START_EVENT_ID); diff --git a/server/src/com/cloud/configuration/Config.java b/server/src/com/cloud/configuration/Config.java index 98e5d3424a2..f2fe68a78a9 100755 --- a/server/src/com/cloud/configuration/Config.java +++ b/server/src/com/cloud/configuration/Config.java @@ -439,7 +439,7 @@ public enum Config { "Console proxy command port that is used to communicate with management server", null), ConsoleProxyRestart("Console Proxy", AgentManager.class, Boolean.class, "consoleproxy.restart", "true", "Console proxy restart flag, defaulted to true", null), - ConsoleProxyUrlDomain("Console Proxy", AgentManager.class, String.class, "consoleproxy.url.domain", "realhostip.com", "Console proxy url domain", null), + ConsoleProxyUrlDomain("Console Proxy", AgentManager.class, String.class, "consoleproxy.url.domain", "", "Console proxy url domain", null), ConsoleProxyLoadscanInterval( "Console Proxy", AgentManager.class, @@ -782,7 +782,7 @@ public enum Config { ManagementServer.class, String.class, "secstorage.ssl.cert.domain", - "realhostip.com", + "", "SSL certificate used to encrypt copy traffic between zones", null), SecStorageCapacityStandby( diff --git a/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java b/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java index 3e4c57e6852..05120963961 100755 --- a/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java +++ b/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java @@ -233,6 +233,7 @@ public class ConsoleProxyManagerImpl extends ManagerBase implements ConsoleProxy private int _proxySessionTimeoutValue = DEFAULT_PROXY_SESSION_TIMEOUT; private boolean _sslEnabled = true; + private String _consoleProxyUrlDomain; // global load picture at zone basis private SystemVmLoadScanner _loadScanner; @@ -384,9 +385,9 @@ public class ConsoleProxyManagerImpl extends ManagerBase implements ConsoleProxy assert (ksVo != null); if (_staticPublicIp == null) { - return new ConsoleProxyInfo(proxy.isSslEnabled(), proxy.getPublicIpAddress(), _consoleProxyPort, proxy.getPort(), ksVo.getDomainSuffix()); + return new ConsoleProxyInfo(proxy.isSslEnabled(), proxy.getPublicIpAddress(), _consoleProxyPort, proxy.getPort(), _consoleProxyUrlDomain); } else { - return new ConsoleProxyInfo(proxy.isSslEnabled(), _staticPublicIp, _consoleProxyPort, _staticPort, ksVo.getDomainSuffix()); + return new ConsoleProxyInfo(proxy.isSslEnabled(), _staticPublicIp, _consoleProxyPort, _staticPort, _consoleProxyUrlDomain); } } @@ -1191,6 +1192,12 @@ public class ConsoleProxyManagerImpl extends ManagerBase implements ConsoleProxy _sslEnabled = true; } + _consoleProxyUrlDomain = configs.get(Config.ConsoleProxyUrlDomain.key()); + if( _sslEnabled && (_consoleProxyUrlDomain == null || _consoleProxyUrlDomain.isEmpty())) { + s_logger.warn("Empty console proxy domain, explicitly disabling SSL"); + _sslEnabled = false; + } + value = configs.get(Config.ConsoleProxyCapacityScanInterval.key()); _capacityScanInterval = NumbersUtil.parseLong(value, DEFAULT_CAPACITY_SCAN_INTERVAL); diff --git a/server/src/com/cloud/event/ActionEventUtils.java b/server/src/com/cloud/event/ActionEventUtils.java index 9724d99e5e6..59546708bce 100755 --- a/server/src/com/cloud/event/ActionEventUtils.java +++ b/server/src/com/cloud/event/ActionEventUtils.java @@ -25,7 +25,6 @@ import java.util.Map; import javax.annotation.PostConstruct; import javax.inject.Inject; -import com.cloud.vm.VirtualMachine; import org.apache.log4j.Logger; import org.springframework.beans.factory.NoSuchBeanDefinitionException; @@ -186,13 +185,19 @@ public class ActionEventUtils { // get the entity details for which ActionEvent is generated String entityType = null; String entityUuid = null; + CallContext context = CallContext.current(); Class entityKey = getEntityKey(eventType); if (entityKey != null) { - CallContext context = CallContext.current(); + //FIXME - Remove this entityUuid = (String)context.getContextParameter(entityKey); if (entityUuid != null) entityType = entityKey.getName(); + }else if (EventTypes.getEntityForEvent(eventType) != null){ + entityType = EventTypes.getEntityForEvent(eventType); + if (entityType != null){ + entityUuid = (String)context.getContextParameter(entityType); + } } org.apache.cloudstack.framework.events.Event event = @@ -240,6 +245,7 @@ public class ActionEventUtils { private static Class getEntityKey(String eventType) { + // FIXME - Remove this if (eventType.startsWith("DOMAIN.")) { return Domain.class; @@ -251,8 +257,6 @@ public class ActionEventUtils { else if (eventType.startsWith("USER.")) { return User.class; - }else if (eventType.startsWith("VM.")){ - return VirtualMachine.class; } return null; diff --git a/server/src/com/cloud/network/IpAddressManagerImpl.java b/server/src/com/cloud/network/IpAddressManagerImpl.java index 8903d1d1137..15d1458fb59 100644 --- a/server/src/com/cloud/network/IpAddressManagerImpl.java +++ b/server/src/com/cloud/network/IpAddressManagerImpl.java @@ -693,7 +693,7 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage errorMessage.append(", vlanId id=" + Arrays.toString(dedicatedVlanDbIds.toArray())); } else if (nonDedicatedVlanDbIds != null && !nonDedicatedVlanDbIds.isEmpty()) { sc.setParameters("vlanId", nonDedicatedVlanDbIds.toArray()); - errorMessage.append(", vlanId id=" + nonDedicatedVlanDbIds.toArray()); + errorMessage.append(", vlanId id=" + Arrays.toString(nonDedicatedVlanDbIds.toArray())); } else { if (podId != null) { InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException("Insufficient address capacity", Pod.class, podId); @@ -733,7 +733,7 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage if (useSystemIps && nonDedicatedVlanDbIds != null && !nonDedicatedVlanDbIds.isEmpty()) { fetchFromDedicatedRange = false; sc.setParameters("vlanId", nonDedicatedVlanDbIds.toArray()); - errorMessage.append(", vlanId id=" + nonDedicatedVlanDbIds.toArray()); + errorMessage.append(", vlanId id=" + Arrays.toString(nonDedicatedVlanDbIds.toArray())); addrs = _ipAddressDao.lockRows(sc, filter, true); } } diff --git a/server/src/com/cloud/network/NetworkModelImpl.java b/server/src/com/cloud/network/NetworkModelImpl.java index 9212a89b838..7b4b2bebdb2 100755 --- a/server/src/com/cloud/network/NetworkModelImpl.java +++ b/server/src/com/cloud/network/NetworkModelImpl.java @@ -1533,28 +1533,34 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel { @Override public void checkNetworkPermissions(Account owner, Network network) { + // dahn 20140310: I was thinking of making this an assert but + // as we hardly ever test with asserts I think + // we better make sure at runtime. + if (network == null) { + throw new CloudRuntimeException("cannot check permissions on (Network) "); + } // Perform account permission check if (network.getGuestType() != Network.GuestType.Shared || (network.getGuestType() == Network.GuestType.Shared && network.getAclType() == ACLType.Account)) { AccountVO networkOwner = _accountDao.findById(network.getAccountId()); if (networkOwner == null) - throw new PermissionDeniedException("Unable to use network with id= " + ((network != null) ? ((NetworkVO)network).getUuid() : "") + + throw new PermissionDeniedException("Unable to use network with id= " + ((NetworkVO)network).getUuid() + ", network does not have an owner"); if (owner.getType() != Account.ACCOUNT_TYPE_PROJECT && networkOwner.getType() == Account.ACCOUNT_TYPE_PROJECT) { if (!_projectAccountDao.canAccessProjectAccount(owner.getAccountId(), network.getAccountId())) { - throw new PermissionDeniedException("Unable to use network with id= " + ((network != null) ? ((NetworkVO)network).getUuid() : "") + + throw new PermissionDeniedException("Unable to use network with id= " + ((NetworkVO)network).getUuid() + ", permission denied"); } } else { List networkMap = _networksDao.listBy(owner.getId(), network.getId()); if (networkMap == null || networkMap.isEmpty()) { - throw new PermissionDeniedException("Unable to use network with id= " + ((network != null) ? ((NetworkVO)network).getUuid() : "") + + throw new PermissionDeniedException("Unable to use network with id= " + ((NetworkVO)network).getUuid() + ", permission denied"); } } } else { if (!isNetworkAvailableInDomain(network.getId(), owner.getDomainId())) { - throw new PermissionDeniedException("Shared network id=" + ((network != null) ? ((NetworkVO)network).getUuid() : "") + " is not available in domain id=" + + throw new PermissionDeniedException("Shared network id=" + ((NetworkVO)network).getUuid() + " is not available in domain id=" + owner.getDomainId()); } } diff --git a/server/src/com/cloud/network/element/VpcVirtualRouterElement.java b/server/src/com/cloud/network/element/VpcVirtualRouterElement.java index 5695a2c9fcd..b433fe4532f 100644 --- a/server/src/com/cloud/network/element/VpcVirtualRouterElement.java +++ b/server/src/com/cloud/network/element/VpcVirtualRouterElement.java @@ -36,6 +36,7 @@ import com.cloud.network.Network; import com.cloud.network.Network.Capability; import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; +import com.cloud.network.Network.State; import com.cloud.network.NetworkModel; import com.cloud.network.PublicIpAddress; import com.cloud.network.RemoteAccessVpn; @@ -179,7 +180,11 @@ public class VpcVirtualRouterElement extends VirtualRouterElement implements Vpc DomainRouterVO router = routers.get(0); //Add router to guest network if needed if (!_networkMgr.isVmPartOfNetwork(router.getId(), network.getId())) { - if (!_vpcRouterMgr.addVpcRouterToGuestNetwork(router, network, false)) { + Map paramsForRouter = new HashMap(1); + if (network.getState() == State.Setup) { + paramsForRouter.put(VirtualMachineProfile.Param.ReProgramGuestNetworks, true); + } + if (!_vpcRouterMgr.addVpcRouterToGuestNetwork(router, network, false, paramsForRouter)) { throw new CloudRuntimeException("Failed to add VPC router " + router + " to guest network " + network); } else { s_logger.debug("Successfully added VPC router " + router + " to guest network " + network); @@ -220,7 +225,12 @@ public class VpcVirtualRouterElement extends VirtualRouterElement implements Vpc DomainRouterVO router = routers.get(0); //Add router to guest network if needed if (!_networkMgr.isVmPartOfNetwork(router.getId(), network.getId())) { - if (!_vpcRouterMgr.addVpcRouterToGuestNetwork(router, network, false)) { + Map paramsForRouter = new HashMap(1); + // need to reprogram guest network if it comes in a setup state + if (network.getState() == State.Setup) { + paramsForRouter.put(VirtualMachineProfile.Param.ReProgramGuestNetworks, true); + } + if (!_vpcRouterMgr.addVpcRouterToGuestNetwork(router, network, false, paramsForRouter)) { throw new CloudRuntimeException("Failed to add VPC router " + router + " to guest network " + network); } else { s_logger.debug("Successfully added VPC router " + router + " to guest network " + network); diff --git a/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java index bed30df8d2a..f7fdd08aee0 100644 --- a/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java @@ -36,6 +36,7 @@ import org.springframework.stereotype.Component; import com.cloud.agent.api.Answer; import com.cloud.agent.api.Command; +import com.cloud.agent.api.Command.OnError; import com.cloud.agent.api.NetworkUsageCommand; import com.cloud.agent.api.PlugNicCommand; import com.cloud.agent.api.SetupGuestNetworkCommand; @@ -246,9 +247,8 @@ public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplian } @Override - public boolean addVpcRouterToGuestNetwork(VirtualRouter router, Network network, boolean isRedundant) throws ConcurrentOperationException, - ResourceUnavailableException, InsufficientCapacityException { - + public boolean addVpcRouterToGuestNetwork(VirtualRouter router, Network network, boolean isRedundant, Map params) + throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException { if (network.getTrafficType() != TrafficType.Guest) { s_logger.warn("Network " + network + " is not of type " + TrafficType.Guest); return false; @@ -257,16 +257,23 @@ public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplian //Add router to the Guest network boolean result = true; try { + + // 1) add nic to the router _routerDao.addRouterToGuestNetwork(router, network); NicProfile guestNic = _itMgr.addVmToNetwork(router, network, null); - //setup guest network + //2) setup guest network if (guestNic != null) { result = setupVpcGuestNetwork(network, router, true, guestNic); } else { s_logger.warn("Failed to add router " + router + " to guest network " + network); result = false; } + //3) apply networking rules + if (result && params.get(Param.ReProgramGuestNetworks) != null + && (Boolean) params.get(Param.ReProgramGuestNetworks) == true) { + sendNetworkRulesToRouter(router.getId(), network.getId()); + } } catch (Exception ex) { s_logger.warn("Failed to add router " + router + " to network " + network + " due to ", ex); result = false; @@ -885,6 +892,25 @@ public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplian } } + + protected boolean sendNetworkRulesToRouter(long routerId, long networkId) + throws ResourceUnavailableException { + DomainRouterVO router = _routerDao.findById(routerId); + Commands cmds = new Commands(OnError.Continue); + + VirtualRouterProvider vrProvider = _vrProviderDao.findById(router.getElementId()); + if (vrProvider == null) { + throw new CloudRuntimeException("Cannot find related virtual router provider of router: " + router.getHostName()); + } + Provider provider = Network.Provider.getProvider(vrProvider.getType().toString()); + if (provider == null) { + throw new CloudRuntimeException("Cannot find related provider of virtual router provider: " + vrProvider.getType().toString()); + } + + finalizeNetworkRulesForNetwork(cmds, router, provider, networkId); + return sendCommandsToRouter(router, cmds); + } + @Override public boolean setupPrivateGateway(PrivateGateway gateway, VirtualRouter router) throws ConcurrentOperationException, ResourceUnavailableException { boolean result = true; diff --git a/server/src/com/cloud/network/vpc/VpcManagerImpl.java b/server/src/com/cloud/network/vpc/VpcManagerImpl.java index 403b95e3a1b..762cc6f3993 100644 --- a/server/src/com/cloud/network/vpc/VpcManagerImpl.java +++ b/server/src/com/cloud/network/vpc/VpcManagerImpl.java @@ -424,14 +424,14 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis List map = _vpcOffSvcMapDao.listByVpcOffId(vpcOffId); for (VpcOfferingServiceMapVO instance : map) { - String service = instance.getService(); + Service service = Service.getService(instance.getService()); Set providers; providers = serviceProviderMap.get(service); if (providers == null) { providers = new HashSet(); } providers.add(Provider.getProvider(instance.getProvider())); - serviceProviderMap.put(Service.getService(service), providers); + serviceProviderMap.put(service, providers); } return serviceProviderMap; diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index ca5ba6f73cc..f9972597b7f 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -3002,7 +3002,6 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir long vmId = cmd.getEntityId(); Long hostId = cmd.getHostId(); UserVmVO vm = _vmDao.findById(vmId); - CallContext.current().putContextParameter(VirtualMachine.class, vm.getUuid()); Pair> vmParamPair = null; try { diff --git a/server/test/com/cloud/network/vpc/VpcManagerImplTest.java b/server/test/com/cloud/network/vpc/VpcManagerImplTest.java new file mode 100644 index 00000000000..3918a374034 --- /dev/null +++ b/server/test/com/cloud/network/vpc/VpcManagerImplTest.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package com.cloud.network.vpc; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +import com.cloud.network.Network.Provider; +import com.cloud.network.Network.Service; +import com.cloud.network.vpc.dao.VpcOfferingServiceMapDao; + +public class VpcManagerImplTest { + + @Mock + VpcOfferingServiceMapDao vpcOffSvcMapDao; + VpcManagerImpl manager; + + @Before + public void setup() + { + MockitoAnnotations.initMocks(this); + manager = new VpcManagerImpl(); + manager._vpcOffSvcMapDao = vpcOffSvcMapDao; + } + @Test + public void getVpcOffSvcProvidersMapForEmptyServiceTest() { + long vpcOffId = 1L; + List list = new ArrayList(); + list.add(Mockito.mock(VpcOfferingServiceMapVO.class)); + when(manager._vpcOffSvcMapDao.listByVpcOffId(vpcOffId)).thenReturn(list); + + Map> map = manager.getVpcOffSvcProvidersMap(vpcOffId); + + assertNotNull(map); + assertEquals(map.size(),1); + } + +} diff --git a/server/test/com/cloud/vpc/MockVpcVirtualNetworkApplianceManager.java b/server/test/com/cloud/vpc/MockVpcVirtualNetworkApplianceManager.java index 4802cfff93b..e0c599deeb4 100644 --- a/server/test/com/cloud/vpc/MockVpcVirtualNetworkApplianceManager.java +++ b/server/test/com/cloud/vpc/MockVpcVirtualNetworkApplianceManager.java @@ -23,10 +23,9 @@ import java.util.Map; import javax.ejb.Local; import javax.naming.ConfigurationException; -import org.springframework.stereotype.Component; - import org.apache.cloudstack.api.command.admin.router.UpgradeRouterCmd; import org.apache.cloudstack.api.command.admin.router.UpgradeRouterTemplateCmd; +import org.springframework.stereotype.Component; import com.cloud.deploy.DeployDestination; import com.cloud.exception.ConcurrentOperationException; @@ -313,8 +312,8 @@ public class MockVpcVirtualNetworkApplianceManager extends ManagerBase implement * @see com.cloud.network.VpcVirtualNetworkApplianceService#addVpcRouterToGuestNetwork(com.cloud.network.router.VirtualRouter, com.cloud.network.Network, boolean) */ @Override - public boolean addVpcRouterToGuestNetwork(VirtualRouter router, Network network, boolean isRedundant) throws ConcurrentOperationException, - ResourceUnavailableException, InsufficientCapacityException { + public boolean addVpcRouterToGuestNetwork(VirtualRouter router, Network network, boolean isRedundant, Map params) + throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException { // TODO Auto-generated method stub return false; } diff --git a/services/secondary-storage/controller/src/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java b/services/secondary-storage/controller/src/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java index dd0c26774d2..f8edefa39a1 100755 --- a/services/secondary-storage/controller/src/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java +++ b/services/secondary-storage/controller/src/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java @@ -807,6 +807,13 @@ public class SecondaryStorageManagerImpl extends ManagerBase implements Secondar _useSSlCopy = true; } + //default to HTTP in case of missing domain + String ssvmUrlDomain = _configDao.getValue("secstorage.ssl.cert.domain"); + if(_useSSlCopy && (ssvmUrlDomain == null || ssvmUrlDomain.isEmpty())){ + s_logger.warn("Empty secondary storage url domain, explicitly disabling SSL"); + _useSSlCopy = false; + } + _allowedInternalSites = _configDao.getValue("secstorage.allowed.internal.sites"); String value = configs.get("secstorage.capacityscan.interval"); diff --git a/setup/db/db/schema-421to430.sql b/setup/db/db/schema-421to430.sql index b49fd965fb7..3f2ad023d26 100644 --- a/setup/db/db/schema-421to430.sql +++ b/setup/db/db/schema-421to430.sql @@ -110,6 +110,10 @@ CREATE TABLE `cloud`.`async_job_join_map` ( INDEX `i_async_job_join_map__expiration`(`expiration`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +#realhostip changes, before changing table and adding default value +UPDATE `cloud`.`configuration` SET value = CONCAT("*.",(SELECT `temptable`.`value` FROM (SELECT * FROM `cloud`.`configuration` WHERE `name`="consoleproxy.url.domain") AS `temptable` WHERE `temptable`.`name`="consoleproxy.url.domain")) WHERE `name`="consoleproxy.url.domain"; +UPDATE `cloud`.`configuration` SET `value` = CONCAT("*.",(SELECT `temptable`.`value` FROM (SELECT * FROM `cloud`.`configuration` WHERE `name`="secstorage.ssl.cert.domain") AS `temptable` WHERE `temptable`.`name`="secstorage.ssl.cert.domain")) WHERE `name`="secstorage.ssl.cert.domain"; + ALTER TABLE `cloud`.`configuration` ADD COLUMN `default_value` VARCHAR(4095) COMMENT 'Default value for a configuration parameter'; ALTER TABLE `cloud`.`configuration` ADD COLUMN `updated` datetime COMMENT 'Time this was updated by the server. null means this row is obsolete.'; ALTER TABLE `cloud`.`configuration` ADD COLUMN `scope` VARCHAR(255) DEFAULT NULL COMMENT 'Can this parameter be scoped'; diff --git a/systemvm/conf/consoleproxy.properties b/systemvm/conf/consoleproxy.properties index bb452f5823c..a3cddbcab96 100644 --- a/systemvm/conf/consoleproxy.properties +++ b/systemvm/conf/consoleproxy.properties @@ -16,7 +16,7 @@ # under the License. consoleproxy.tcpListenPort=0 -consoleproxy.httpListenPort=8088 +consoleproxy.httpListenPort=80 consoleproxy.httpCmdListenPort=8001 consoleproxy.jarDir=./applet/ consoleproxy.viewerLinger=180 diff --git a/systemvm/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in b/systemvm/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in index 76ee681dbe9..e43f6413c67 100644 --- a/systemvm/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in +++ b/systemvm/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in @@ -26,7 +26,7 @@ # set environment variables -SHORTNAME="$0" +SHORTNAME="basename $0" PIDFILE=@PIDDIR@/"$SHORTNAME".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@CPLOG@ diff --git a/systemvm/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in b/systemvm/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in index 76ee681dbe9..e43f6413c67 100644 --- a/systemvm/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in +++ b/systemvm/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in @@ -26,7 +26,7 @@ # set environment variables -SHORTNAME="$0" +SHORTNAME="basename $0" PIDFILE=@PIDDIR@/"$SHORTNAME".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@CPLOG@ diff --git a/systemvm/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in b/systemvm/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in index 76ee681dbe9..e43f6413c67 100644 --- a/systemvm/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in +++ b/systemvm/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in @@ -26,7 +26,7 @@ # set environment variables -SHORTNAME="$0" +SHORTNAME="basename $0" PIDFILE=@PIDDIR@/"$SHORTNAME".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@CPLOG@ diff --git a/systemvm/distro/ubuntu/SYSCONFDIR/init.d/cloud-console-proxy.in b/systemvm/distro/ubuntu/SYSCONFDIR/init.d/cloud-console-proxy.in index c83f00aa76d..87a653e920b 100755 --- a/systemvm/distro/ubuntu/SYSCONFDIR/init.d/cloud-console-proxy.in +++ b/systemvm/distro/ubuntu/SYSCONFDIR/init.d/cloud-console-proxy.in @@ -27,7 +27,7 @@ # set environment variables -SHORTNAME="$0" +SHORTNAME="basename $0" PIDFILE=@PIDDIR@/"$SHORTNAME".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@CPLOG@ diff --git a/test/integration/component/test_cpu_domain_limits.py b/test/integration/component/test_cpu_domain_limits.py index c427e4fcf41..1247a799c89 100644 --- a/test/integration/component/test_cpu_domain_limits.py +++ b/test/integration/component/test_cpu_domain_limits.py @@ -30,10 +30,11 @@ from marvin.integration.lib.base import ( from marvin.integration.lib.common import (get_domain, get_zone, get_template, - find_suitable_host, + findSuitableHostForMigration, get_resource_type ) from marvin.integration.lib.utils import cleanup_resources +from marvin.codes import ERROR_NO_HOST_FOR_MIGRATION class Services: """Test resource limit services @@ -329,7 +330,9 @@ class TestDomainCPULimitsUpdateResources(cloudstackTestCase): self.assertEqual(resource_count, expected_resource_count, "Initial resource count should match with the expected resource count") - host = find_suitable_host(self.apiclient, vm) + host = findSuitableHostForMigration(self.apiclient, vm.id) + if host is None: + self.skipTest(ERROR_NO_HOST_FOR_MIGRATION) self.debug("Migrating instance: %s to host: %s" % (vm.name, host.name)) try: @@ -477,7 +480,9 @@ class TestDomainCPULimitsUpdateResources(cloudstackTestCase): self.assertEqual(resource_count_after_delete, expected_resource_count, "Resource count should match with the expected count") - host = find_suitable_host(self.apiclient, vm_2) + host = findSuitableHostForMigration(self.apiclient, vm_2.id) + if host is None: + self.skipTest(ERROR_NO_HOST_FOR_MIGRATION) self.debug("Migrating instance: %s to host: %s" % (vm_2.name, host.name)) try: diff --git a/test/integration/component/test_cpu_limits.py b/test/integration/component/test_cpu_limits.py index bdf2869c7c1..f043773e7b1 100644 --- a/test/integration/component/test_cpu_limits.py +++ b/test/integration/component/test_cpu_limits.py @@ -30,10 +30,11 @@ from marvin.integration.lib.base import ( from marvin.integration.lib.common import (get_domain, get_zone, get_template, - find_suitable_host, + findSuitableHostForMigration, get_resource_type ) from marvin.integration.lib.utils import cleanup_resources +from marvin.codes import ERROR_NO_HOST_FOR_MIGRATION class Services: @@ -251,7 +252,9 @@ class TestCPULimits(cloudstackTestCase): self.assertEqual(resource_count, expected_resource_count, "Resource count should match with the expected resource count") - host = find_suitable_host(self.apiclient, self.vm) + host = findSuitableHostForMigration(self.apiclient, self.vm.id) + if host is None: + self.skipTest(ERROR_NO_HOST_FOR_MIGRATION) self.debug("Migrating instance: %s to host: %s" % (self.vm.name, host.name)) try: self.vm.migrate(self.apiclient, host.id) @@ -570,7 +573,9 @@ class TestDomainCPULimitsConfiguration(cloudstackTestCase): self.assertEqual(resource_count, expected_resource_count, "Initial resource count should with the expected resource count") - host = find_suitable_host(self.apiclient, vm) + host = findSuitableHostForMigration(self.apiclient, vm.id) + if host is None: + self.skipTest(ERROR_NO_HOST_FOR_MIGRATION) self.debug("Migrating instance: %s to host: %s" % (vm.name, host.name)) try: @@ -725,7 +730,9 @@ class TestDomainCPULimitsConfiguration(cloudstackTestCase): self.assertEqual(resource_count_after_delete, expected_resource_count, "Resource count should be less than before after deleting the instance") - host = find_suitable_host(self.apiclient, vm_2) + host = findSuitableHostForMigration(self.apiclient, vm_2.id) + if host is None: + self.skipTest(ERROR_NO_HOST_FOR_MIGRATION) self.debug("Migrating instance: %s to host: %s" % (vm_2.name, host.name)) try: diff --git a/test/integration/component/test_cpu_project_limits.py b/test/integration/component/test_cpu_project_limits.py index a8a1b3c3b24..ed7cd88248a 100644 --- a/test/integration/component/test_cpu_project_limits.py +++ b/test/integration/component/test_cpu_project_limits.py @@ -30,10 +30,11 @@ from marvin.integration.lib.base import ( from marvin.integration.lib.common import (get_domain, get_zone, get_template, - find_suitable_host, + findSuitableHostForMigration, get_resource_type ) from marvin.integration.lib.utils import cleanup_resources +from marvin.codes import ERROR_NO_HOST_FOR_MIGRATION class Services: """Test resource limit services @@ -291,7 +292,9 @@ class TestProjectsCPULimits(cloudstackTestCase): self.assertEqual(resource_count, expected_resource_count, "Resource count should match with the expected resource count") - host = find_suitable_host(self.apiclient, self.vm) + host = findSuitableHostForMigration(self.apiclient, self.vm.id) + if host is None: + self.skipTest(ERROR_NO_HOST_FOR_MIGRATION) self.debug("Migrating instance: %s to host: %s" % (self.vm.name, host.name)) try: diff --git a/test/integration/component/test_dynamic_compute_offering.py b/test/integration/component/test_dynamic_compute_offering.py new file mode 100644 index 00000000000..75cf0d658f4 --- /dev/null +++ b/test/integration/component/test_dynamic_compute_offering.py @@ -0,0 +1,409 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +""" Tests for Dynamic Compute Offering Feature + + Test Plan: https://cwiki.apache.org/confluence/display/CLOUDSTACK/Dynamic+ComputeOffering + + Issue Link: https://issues.apache.org/jira/browse/CLOUDSTACK-6147 + + Feature Specifications: https://cwiki.apache.org/confluence/display/CLOUDSTACK/Dynamic+Compute+Offering+FS +""" +from marvin.cloudstackTestCase import cloudstackTestCase +from marvin.integration.lib.utils import (cleanup_resources, + validateList) +from marvin.integration.lib.base import (ServiceOffering, + VirtualMachine, + Account) +from marvin.integration.lib.common import (get_domain, + get_zone, + get_template, + verifyComputeOfferingCreation) + +from nose.plugins.attrib import attr +from marvin.codes import PASS, ADMIN_ACCOUNT, USER_ACCOUNT +from ddt import ddt, data + +@ddt +class TestDynamicServiceOffering(cloudstackTestCase): + """Test Dynamic Service Offerings + """ + + @classmethod + def setUpClass(cls): + cloudstackTestClient = super(TestDynamicServiceOffering,cls).getClsTestClient() + cls.api_client = cloudstackTestClient.getApiClient() + + # Fill services from the external config file + cls.services = cloudstackTestClient.getConfigParser().parsedDict + + # Get Zone, Domain and templates + cls.domain = get_domain(cls.api_client, cls.services) + cls.zone = get_zone(cls.api_client, cls.services) + cls.mode = str(cls.zone.networktype).lower() + cls.template = get_template( + cls.api_client, + cls.zone.id, + cls.services["ostype"] + ) + cls.services["virtual_machine"]["zoneid"] = cls.zone.id + cls.services["virtual_machine"]["template"] = cls.template.id + cls._cleanup = [] + return + + @classmethod + def tearDownClass(cls): + try: + # Cleanup resources used + cleanup_resources(cls.api_client, cls._cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + def setUp(self): + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + self.cleanup_co = [] + self.cleanup = [] + return + + def tearDown(self): + try: + # Clean up compute offerings + cleanup_resources(self.apiclient, self.cleanup) + + # Clean up compute offerings + cleanup_resources(self.apiclient, self.cleanup_co) + + self.cleanup_co[:] = [] + self.cleanup[:] = [] + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + @attr(tags=["basic","advanced"]) + def test_create_normal_compute_offering(self): + """ Create normal compute offering with non zero values for cpu, + cpu number and memory""" + + # Steps: + # 1. Create normal compute offering with non zero values for cpu number, + # cpu speed, memory + + # Validations: + # 1. Compute offering should be created + + self.services["service_offering"]["cpunumber"] = 2 + self.services["service_offering"]["cpuspeed"] = 256 + self.services["service_offering"]["memory"] = 128 + + serviceOffering = ServiceOffering.create(self.api_client, + self.services["service_offering"] + ) + self.assertEqual(verifyComputeOfferingCreation(self.apiclient, serviceOffering.id), + PASS, "Compute Offering verification failed") + + self.cleanup_co.append(serviceOffering) + return + + @attr(tags=["basic","advanced"]) + def test_create_dynamic_compute_offering(self): + """ Create dynamic compute offering with cpunumber, cpuspeed and memory + not specified""" + + # Steps: + # 1. Create dynamic compute offering with values for cpu number, + # cpu speed, memory not specified + + # Validations: + # 1. Compute offering should be created + + self.services["service_offering"]["cpunumber"] = "" + self.services["service_offering"]["cpuspeed"] = "" + self.services["service_offering"]["memory"] = "" + + serviceOffering = ServiceOffering.create(self.api_client, + self.services["service_offering"] + ) + self.assertEqual(verifyComputeOfferingCreation(self.apiclient, serviceOffering.id), + PASS, "Compute Offering verification failed") + + self.cleanup_co.append(serviceOffering) + return + + @attr(tags=["basic","advanced"]) + def test_create_dynamic_compute_offering_no_cpunumber(self): + """ Create dynamic compute offering with only cpunumber unspecified""" + + # Validations: + # 1. Compute Offering creation should fail + + self.services["service_offering"]["cpunumber"] = "" + self.services["service_offering"]["cpuspeed"] = 256 + self.services["service_offering"]["memory"] = 128 + + try: + serviceOffering = ServiceOffering.create(self.api_client, + self.services["service_offering"] + ) + self.cleanup_co.append(serviceOffering) + self.fail("Compute Offering creation succeded, it should have failed") + except Exception: + self.debug("Compute Offering Creation failed as expected") + return + + @attr(tags=["basic","advanced"]) + def test_create_dynamic_compute_offering_no_cpuspeed(self): + """ Create dynamic compute offering with only cpuspeed unspecified""" + + # Validations: + # 1. Compute offering creation should fail + + self.services["service_offering"]["cpunumber"] = 2 + self.services["service_offering"]["cpuspeed"] = "" + self.services["service_offering"]["memory"] = 128 + + try: + serviceOffering = ServiceOffering.create(self.api_client, + self.services["service_offering"] + ) + self.cleanup_co.append(serviceOffering) + self.fail("Compute Offering creation succeded, it should have failed") + except Exception: + self.debug("Compute Offering Creation failed as expected") + return + + @attr(tags=["basic","advanced"]) + def test_create_dynamic_compute_offering_no_memory(self): + """ Create dynamic compute offering with only memory unspecified""" + + # Validations: + # 1. Compute offering creation should fail + + self.services["service_offering"]["cpunumber"] = 2 + self.services["service_offering"]["cpuspeed"] = 256 + self.services["service_offering"]["memory"] = "" + + try: + serviceOffering = ServiceOffering.create(self.api_client, + self.services["service_offering"] + ) + self.cleanup_co.append(serviceOffering) + self.fail("Compute Offering creation succeded, it should have failed") + except Exception: + self.debug("Compute Offering Creation failed as expected") + return + + @data(ADMIN_ACCOUNT, USER_ACCOUNT) + @attr(tags=["basic","advanced"]) + def test_deploy_virtual_machines_static_offering(self, value): + """Test deploy VM with static offering""" + + # Steps: + # 1. Create admin/user account and create its user api client + # 2. Create a static compute offering + # 3. Deploy a VM with account api client and static service offering + # 4. Repeat step 3 but also pass custom values for cpu number, cpu speed and memory + # while deploying VM + + # Validations: + # 1. Step 3 should succeed + # 2. Step 4 should fail + + isadmin=True + if value == USER_ACCOUNT: + isadmin=False + + # Create Account + self.account = Account.create(self.apiclient,self.services["account"],domainid=self.domain.id, admin=isadmin) + apiclient = self.testClient.createUserApiClient( + UserName=self.account.name, + DomainName=self.account.domain) + self.cleanup.append(self.account) + + # Create service offering + self.services["service_offering"]["cpunumber"] = 2 + self.services["service_offering"]["cpuspeed"] = 256 + self.services["service_offering"]["memory"] = 128 + + serviceOffering = ServiceOffering.create(self.apiclient, + self.services["service_offering"]) + + self.cleanup_co.append(serviceOffering) + + # Deploy VM with static service offering + try: + VirtualMachine.create(apiclient,self.services["virtual_machine"], + serviceofferingid=serviceOffering.id, + accountid=self.account.name,domainid=self.account.domainid) + except Exception as e: + self.fail("vm creation failed: %s" % e) + + # Deploy VM with static service offering, also with custom values + try: + VirtualMachine.create(apiclient,self.services["virtual_machine"], + serviceofferingid=serviceOffering.id, + customcpunumber=4, + customcpuspeed=512, + custommemory=256, + accountid=self.account.name,domainid=self.account.domainid) + self.fail("VM creation should have failed, it succeeded") + except Exception as e: + self.debug("vm creation failed as expected: %s" % e) + return + + @data(ADMIN_ACCOUNT, USER_ACCOUNT) + @attr(tags=["basic","advanced"]) + def test_deploy_virtual_machines_dynamic_offering(self, value): + """Test deploy VM with dynamic compute offering""" + + # Steps: + # 1. Create admin/user account and create its user api client + # 2. Create a dynamic service offering + # 3. Deploy a VM with account api client and dynamic service offering + # without providing custom values for cpu number, cpu speed and memory + # 4. Deploy a VM with account api client and dynamic service offering providing + # custom values for cpu number, cpu speed and memory + # 5. Deploy a VM with account api client and dynamic service offering providing + # custom values only for cpu number + + # Validations: + # 1. Step 3 should fail + # 2. Step 4 should succeed + # 3. Step 5 should fail + + isadmin=True + if value == USER_ACCOUNT: + isadmin=False + + # Create Account and its api client + self.account = Account.create(self.apiclient,self.services["account"],domainid=self.domain.id, admin=isadmin) + apiclient = self.testClient.createUserApiClient( + UserName=self.account.name, + DomainName=self.account.domain) + self.cleanup.append(self.account) + + # Create dynamic service offering + self.services["service_offering"]["cpunumber"] = "" + self.services["service_offering"]["cpuspeed"] = "" + self.services["service_offering"]["memory"] = "" + + serviceOffering = ServiceOffering.create(self.apiclient, + self.services["service_offering"]) + + self.cleanup_co.append(serviceOffering) + + # Deploy VM with dynamic compute offering without providing custom values for + # cpu number, cpu speed and memory + try: + VirtualMachine.create(apiclient,self.services["virtual_machine"], + serviceofferingid=serviceOffering.id, + accountid=self.account.name,domainid=self.account.domainid) + self.fail("VM creation succeded, it should have failed") + except Exception as e: + self.debug("vm creation failed as expected with error: %s" % e) + + # Deploy VM with dynamic compute offering providing custom values for + # cpu number, cpu speed and memory + try: + VirtualMachine.create(apiclient,self.services["virtual_machine"], + serviceofferingid=serviceOffering.id, + customcpunumber=2, + customcpuspeed=256, + custommemory=128, + accountid=self.account.name,domainid=self.account.domainid) + except Exception as e: + self.fail("vm creation failed: %s" % e) + + # Deploy VM with dynamic compute offering providing custom values for only + # cpu number + try: + VirtualMachine.create(apiclient,self.services["virtual_machine"], + serviceofferingid=serviceOffering.id, + customcpunumber=2, + accountid=self.account.name,domainid=self.account.domainid) + self.fail("VM deployment should have failed, it succeded") + except Exception as e: + self.debug("vm creation failed as expected: %s" % e) + return + + @data(ADMIN_ACCOUNT, USER_ACCOUNT) + @attr(tags=["basic","advanced"]) + def test_check_vm_stats(self, value): + """Deploy VM with dynamic service offering and check VM stats""" + + # Steps: + # 1. Create admin/user account and create its user api client + # 2. Create a dynamic service offering + # 3. Deploy a VM with account api client and dynamic service offering + # providing custom values for cpu number, cpu speed and memory + # 4. List the VM and verify the dynamic parameters are same as passed + + isadmin=True + if value == USER_ACCOUNT: + isadmin=False + + # Create Account and api client + self.account = Account.create(self.apiclient,self.services["account"],domainid=self.domain.id, admin=isadmin) + apiclient = self.testClient.createUserApiClient( + UserName=self.account.name, + DomainName=self.account.domain) + self.cleanup.append(self.account) + + # Create dynamic compute offering + self.services["service_offering"]["cpunumber"] = "" + self.services["service_offering"]["cpuspeed"] = "" + self.services["service_offering"]["memory"] = "" + + serviceOffering = ServiceOffering.create(self.apiclient, + self.services["service_offering"]) + + self.cleanup_co.append(serviceOffering) + + # Custom values + customcpunumber = 2 + customcpuspeed = 256 + custommemory = 128 + + # Deploy VM with dynamic service offering and the custom values + try: + virtualMachine = VirtualMachine.create(apiclient,self.services["virtual_machine"], + serviceofferingid=serviceOffering.id, + customcpunumber=customcpunumber, + customcpuspeed=customcpuspeed, + custommemory=custommemory, + accountid=self.account.name,domainid=self.account.domainid) + except Exception as e: + self.fail("vm creation failed: %s" % e) + + vmlist = VirtualMachine.list(self.apiclient, id=virtualMachine.id) + self.assertEqual(validateList(vmlist)[0], PASS, "vm list validation failed") + vm = vmlist[0] + + # Verify the custom values + self.assertEqual(str(vm.cpunumber), str(customcpunumber), "vm cpu number %s\ + not matching with provided custom cpu number %s" % \ + (vm.cpunumber, customcpunumber)) + + self.assertEqual(str(vm.cpuspeed), str(customcpuspeed), "vm cpu speed %s\ + not matching with provided custom cpu speed %s" % \ + (vm.cpuspeed, customcpuspeed)) + + self.assertEqual(str(vm.memory), str(custommemory), "vm memory %s\ + not matching with provided custom memory %s" % \ + (vm.memory, custommemory)) + return diff --git a/test/integration/component/test_memory_limits.py b/test/integration/component/test_memory_limits.py index 7921e4be9ed..231307f693e 100644 --- a/test/integration/component/test_memory_limits.py +++ b/test/integration/component/test_memory_limits.py @@ -30,10 +30,11 @@ from marvin.integration.lib.common import (get_domain, get_zone, get_template, wait_for_cleanup, - find_suitable_host, + findSuitableHostForMigration, get_resource_type ) from marvin.integration.lib.utils import cleanup_resources +from marvin.codes import ERROR_NO_HOST_FOR_MIGRATION class Services: """Test memory resource limit services @@ -248,7 +249,9 @@ class TestMemoryLimits(cloudstackTestCase): self.assertEqual(resource_count, expected_resource_count, "Resource count should match with the expected resource count") - host = find_suitable_host(self.apiclient, self.vm) + host = findSuitableHostForMigration(self.apiclient, self.vm.id) + if host is None: + self.skipTest(ERROR_NO_HOST_FOR_MIGRATION) self.debug("Migrating instance: %s to host: %s" % (self.vm.name, host.name)) try: self.vm.migrate(self.apiclient, host.id) @@ -587,7 +590,9 @@ class TestDomainMemoryLimitsConfiguration(cloudstackTestCase): self.assertEqual(resource_count, expected_resource_count, "Initial resource count should with the expected resource count") - host = find_suitable_host(self.apiclient, vm) + host = findSuitableHostForMigration(self.apiclient, vm.id) + if host is None: + self.skipTest(ERROR_NO_HOST_FOR_MIGRATION) self.debug("Migrating instance: %s to host: %s" % (vm.name, host.name)) try: @@ -743,7 +748,9 @@ class TestDomainMemoryLimitsConfiguration(cloudstackTestCase): self.assertEqual(resource_count_after_delete, expected_resource_count, "Resource count should match with the expected resource count") - host = find_suitable_host(self.apiclient, vm_2) + host = findSuitableHostForMigration(self.apiclient, vm_2.id) + if host is None: + self.skipTest(ERROR_NO_HOST_FOR_MIGRATION) self.debug("Migrating instance: %s to host: %s" % (vm_2.name, host.name)) try: diff --git a/test/integration/component/test_mm_domain_limits.py b/test/integration/component/test_mm_domain_limits.py index 68660c13cf5..a2b7395cd13 100644 --- a/test/integration/component/test_mm_domain_limits.py +++ b/test/integration/component/test_mm_domain_limits.py @@ -30,11 +30,12 @@ from marvin.integration.lib.common import (get_domain, get_zone, get_template, wait_for_cleanup, - find_suitable_host, + findSuitableHostForMigration, get_resource_type, update_resource_count ) from marvin.integration.lib.utils import cleanup_resources +from marvin.codes import ERROR_NO_HOST_FOR_MIGRATION class Services: """Test memory resource limit services @@ -388,7 +389,9 @@ class TestDomainMemoryLimits(cloudstackTestCase): self.assertEqual(resource_count, expected_resource_count, "Resource count should match with the expected resource count") - host = find_suitable_host(self.apiclient, vm) + host = findSuitableHostForMigration(self.apiclient, vm.id) + if host is None: + self.skipTest(ERROR_NO_HOST_FOR_MIGRATION) self.debug("Migrating instance: %s to host: %s" % (vm.name, host.name)) try: diff --git a/test/integration/component/test_mm_project_limits.py b/test/integration/component/test_mm_project_limits.py index c314011090c..29a3b549729 100644 --- a/test/integration/component/test_mm_project_limits.py +++ b/test/integration/component/test_mm_project_limits.py @@ -30,10 +30,11 @@ from marvin.integration.lib.common import (get_domain, get_zone, get_template, wait_for_cleanup, - find_suitable_host, + findSuitableHostForMigration, get_resource_type ) from marvin.integration.lib.utils import cleanup_resources +from marvin.codes import ERROR_NO_HOST_FOR_MIGRATION class Services: """Test memory resource limit services @@ -291,7 +292,9 @@ class TestProjectsMemoryLimits(cloudstackTestCase): resource_count = project_list[0].memorytotal self.debug(resource_count) - host = find_suitable_host(self.apiclient, self.vm) + host = findSuitableHostForMigration(self.apiclient, self.vm.id) + if host is None: + self.skipTest(ERROR_NO_HOST_FOR_MIGRATION) self.debug("Migrating instance: %s to host: %s" % (self.vm.name, host.name)) try: diff --git a/test/integration/component/test_routers.py b/test/integration/component/test_routers.py index f8359f0e2c5..ced3f525ca2 100644 --- a/test/integration/component/test_routers.py +++ b/test/integration/component/test_routers.py @@ -1254,21 +1254,10 @@ class TestRouterStopCreateFW(cloudstackTestCase): str(self.services["fw_rule"]["endport"]), "Check end port of firewall rule" ) - hosts = list_hosts( - self.apiclient, - id=router.hostid, - ) - self.assertEqual( - isinstance(hosts, list), - True, - "Check for list hosts response return valid data" - ) - host = hosts[0] - host.user, host.passwd = get_host_credentials(self.config, host.ipaddress) - # For DNS and DHCP check 'dnsmasq' process status - if self.apiclient.hypervisor.lower() == 'vmware': - result = get_process_status( + if (self.apiclient.hypervisor.lower() == 'vmware' + or self.apiclient.hypervisor.lower() == 'hyperv'): + result = get_process_status( self.apiclient.connection.mgtSvr, 22, self.apiclient.connection.user, @@ -1278,6 +1267,17 @@ class TestRouterStopCreateFW(cloudstackTestCase): hypervisor=self.apiclient.hypervisor ) else: + hosts = list_hosts( + self.apiclient, + id=router.hostid, + ) + self.assertEqual( + isinstance(hosts, list), + True, + "Check for list hosts response return valid data" + ) + host = hosts[0] + host.user, host.passwd = get_host_credentials(self.config, host.ipaddress) try: result = get_process_status( host.ipaddress, diff --git a/test/integration/component/test_vpc_vm_life_cycle.py b/test/integration/component/test_vpc_vm_life_cycle.py index 01373ac5a73..e40067ea86d 100644 --- a/test/integration/component/test_vpc_vm_life_cycle.py +++ b/test/integration/component/test_vpc_vm_life_cycle.py @@ -41,9 +41,10 @@ from marvin.integration.lib.common import (get_domain, get_free_vlan, wait_for_cleanup, list_virtual_machines, - list_hosts) + list_hosts, + findSuitableHostForMigration) -from marvin.codes import PASS +from marvin.codes import PASS, ERROR_NO_HOST_FOR_MIGRATION import time @@ -715,35 +716,13 @@ class TestVMLifeCycleVPC(cloudstackTestCase): # works as expected. # 3. Make sure that we are able to access google.com from this user Vm - vm_list = VirtualMachine.list(self.apiclient, id=self.vm_1.id) - self.assertEqual(validateList(vm_list)[0], PASS, "vm list validation failed, vm list is %s" % vm_list) - - vm_hostid = vm_list[0].hostid - - self.debug("Checking if the host is available for migration?") - hosts = Host.list( - self.apiclient, - zoneid=self.zone.id, - type='Routing' - ) - - self.assertEqual( - isinstance(hosts, list), - True, - "List hosts should return a valid list" - ) - if len(hosts) < 2: - raise unittest.SkipTest( - "No host available for migration. Test requires atleast 2 hosts") - - # Remove the host of current VM from the hosts list - hosts[:] = [host for host in hosts if host.id != vm_hostid] - - host = hosts[0] - self.debug("Validating if the network rules work properly or not?") self.validate_network_rules() + host = findSuitableHostForMigration(self.apiclient, self.vm_1.id) + if host is None: + self.skipTest(ERROR_NO_HOST_FOR_MIGRATION) + self.debug("Migrating VM-ID: %s to Host: %s" % ( self.vm_1.id, host.id @@ -1506,30 +1485,13 @@ class TestVMLifeCycleSharedNwVPC(cloudstackTestCase): # works as expected. # 3. Make sure that we are able to access google.com from this user Vm - self.debug("Checking if the host is available for migration?") - hosts = Host.list( - self.apiclient, - zoneid=self.zone.id, - type='Routing' - ) - - self.assertEqual( - isinstance(hosts, list), - True, - "List hosts should return a valid list" - ) - if len(hosts) < 2: - raise unittest.SkipTest( - "No host available for migration. Test requires atleast 2 hosts") - - # Remove the host of current VM from the hosts list - hosts[:] = [host for host in hosts if host.id != self.vm_1.hostid] - - host = hosts[0] - self.debug("Validating if network rules are coonfigured properly?") self.validate_network_rules() + host = findSuitableHostForMigration(self.apiclient, self.vm_1.id) + if host is None: + self.skipTest(ERROR_NO_HOST_FOR_MIGRATION) + self.debug("Migrating VM-ID: %s to Host: %s" % ( self.vm_1.id, host.id @@ -2559,30 +2521,13 @@ class TestVMLifeCycleStoppedVPCVR(cloudstackTestCase): # works as expected. # 3. Make sure that we are able to access google.com from this user Vm - self.debug("Checking if the host is available for migration?") - hosts = Host.list( - self.apiclient, - zoneid=self.zone.id, - type='Routing' - ) - - self.assertEqual( - isinstance(hosts, list), - True, - "List hosts should return a valid list" - ) - if len(hosts) < 2: - raise unittest.SkipTest( - "No host available for migration. Test requires atleast 2 hosts") - - # Remove the host of current VM from the hosts list - hosts[:] = [host for host in hosts if host.id != self.vm_1.hostid] - - host = hosts[0] - self.debug("Validating if the network rules work properly or not?") self.validate_network_rules() + host = findSuitableHostForMigration(self.apiclient, self.vm_1.id) + if host is None: + self.skipTest(ERROR_NO_HOST_FOR_MIGRATION) + self.debug("Migrating VM-ID: %s on Host: %s to Host: %s" % ( self.vm_1.id, self.vm_1.hostid, @@ -3459,28 +3404,13 @@ class TestVMLifeCycleDiffHosts(cloudstackTestCase): # works as expected. # 3. Make sure that we are able to access google.com from this user Vm - self.debug("Checking if the host is available for migration?") - hosts = Host.listForMigration( - self.apiclient, - virtualmachineid=self.vm_1.id, - ) - self.debug("Hosts vm can be migrated to are : %s" %(hosts)) - self.assertEqual( - isinstance(hosts, list), - True, - "List hosts should return a valid list" - ) - # Remove the host of current VM from the hosts list - hosts[:] = [host for host in hosts if host.id != self.vm_1.hostid] - if len(hosts) <= 0: - self.skipTest( - "No host available for migration. Test requires atleast 2 hosts tagged with host1") - - host = hosts[0] - self.debug("Validating if the network rules work properly or not?") self.validate_network_rules() + host = findSuitableHostForMigration(self.apiclient, self.vm_1.id) + if host is None: + self.skipTest(ERROR_NO_HOST_FOR_MIGRATION) + self.debug("Migrating VM-ID: %s to Host: %s" % ( self.vm_1.id, host.id diff --git a/tools/marvin/marvin/codes.py b/tools/marvin/marvin/codes.py index 3882f0d59b8..e4a0f6a789a 100644 --- a/tools/marvin/marvin/codes.py +++ b/tools/marvin/marvin/codes.py @@ -51,3 +51,4 @@ BASIC_ZONE = "basic" ISOLATED_NETWORK = "ISOLATED" SHARED_NETWORK = "SHARED" VPC_NETWORK = "VPC" +ERROR_NO_HOST_FOR_MIGRATION = "Could not find suitable host for migration, please ensure setup has required no. of hosts" diff --git a/tools/marvin/marvin/integration/lib/base.py b/tools/marvin/marvin/integration/lib/base.py index 0a7ad9404a6..7449d8c9d11 100755 --- a/tools/marvin/marvin/integration/lib/base.py +++ b/tools/marvin/marvin/integration/lib/base.py @@ -324,7 +324,8 @@ class VirtualMachine: domainid=None, zoneid=None, networkids=None, serviceofferingid=None, securitygroupids=None, projectid=None, startvm=None, diskofferingid=None, affinitygroupnames=None, affinitygroupids=None, group=None, - hostid=None, keypair=None, ipaddress=None, mode='default', method='GET'): + hostid=None, keypair=None, ipaddress=None, mode='default', method='GET', + customcpunumber=None, customcpuspeed=None, custommemory=None): """Create the instance""" cmd = deployVirtualMachine.deployVirtualMachineCmd() @@ -412,6 +413,17 @@ class VirtualMachine: if "userdata" in services: cmd.userdata = base64.urlsafe_b64encode(services["userdata"]) + cmd.details = [{"cpuNumber": "","cpuSpeed":"","memory":""}] + + if customcpunumber: + cmd.details[0]["cpuNumber"] = customcpunumber + + if customcpuspeed: + cmd.details[0]["cpuSpeed"] = customcpuspeed + + if custommemory: + cmd.details[0]["memory"] = custommemory + if group: cmd.group = group @@ -636,6 +648,21 @@ class VirtualMachine: return apiclient.updateVMAffinityGroup(cmd) + def scale(self, apiclient, serviceOfferingId, + customcpunumber=None, customcpuspeed=None, custommemory=None): + """Change service offering of the instance""" + cmd = scaleVirtualMachine.scaleVirtualMachineCmd() + cmd.id = self.id + cmd.serviceofferingid = serviceOfferingId + cmd.details = [{"cpuNumber": "","cpuSpeed":"","memory":""}] + if customcpunumber: + cmd.details[0]["cpuNumber"] = customcpunumber + if customcpuspeed: + cmd.details[0]["cpuSpeed"] = customcpuspeed + if custommemory: + cmd.details[0]["memory"] = custommemory + return apiclient.scaleVirtualMachine(cmd) + class Volume: """Manage Volume Life cycle diff --git a/tools/marvin/marvin/integration/lib/common.py b/tools/marvin/marvin/integration/lib/common.py index b2da3ffef24..3b292bf920f 100644 --- a/tools/marvin/marvin/integration/lib/common.py +++ b/tools/marvin/marvin/integration/lib/common.py @@ -712,18 +712,23 @@ def update_resource_count(apiclient, domainid, accountid=None, ) return -def find_suitable_host(apiclient, vm): - """Returns a suitable host for VM migration""" +def findSuitableHostForMigration(apiclient, vmid): + """Returns a suitable host for VM migration""" + suitableHost = None + try: + hosts = Host.listForMigration(apiclient, virtualmachineid=vmid, + ) + except Exception as e: + raise Exception("Exception while getting hosts list suitable for migration: %s" % e) - hosts = Host.list(apiclient, - virtualmachineid=vm.id, - listall=True) + suitablehosts = [] + if isinstance(hosts, list) and len(hosts) > 0: + suitablehosts = [host for host in hosts if (str(host.resourcestate).lower() == "enabled"\ + and str(host.state).lower() == "up")] + if len(suitablehosts)>0: + suitableHost = suitablehosts[0] - if isinstance(hosts, list): - assert len(hosts) > 0, "List host should return valid response" - else: - raise Exception("Exception: List host should return valid response") - return hosts[0] + return suitableHost def get_resource_type(resource_id): """Returns resource type""" @@ -980,3 +985,17 @@ def verifyNetworkState(apiclient, networkid, state): assert validateList(networks)[0] == PASS, "Networks list validation failed, list is %s" % networks assert str(networks[0].state).lower() == state, "network state should be %s, it is %s" % (state, networks[0].state) return + +def verifyComputeOfferingCreation(apiclient, computeofferingid): + """List Compute offerings by ID and verify that the offering exists""" + + cmd = listServiceOfferings.listServiceOfferingsCmd() + cmd.id = computeofferingid + serviceOfferings = None + try: + serviceOfferings = apiclient.listServiceOfferings(cmd) + except Exception as e: + return FAIL + if not (isinstance(serviceOfferings, list) and len(serviceOfferings) > 0): + return FAIL + return PASS diff --git a/tools/marvin/marvin/integration/lib/utils.py b/tools/marvin/marvin/integration/lib/utils.py index e870158cfb5..709fddebe78 100644 --- a/tools/marvin/marvin/integration/lib/utils.py +++ b/tools/marvin/marvin/integration/lib/utils.py @@ -191,7 +191,8 @@ def get_process_status(hostip, port, username, password, linklocalip, process, h #SSH to the machine ssh = SshClient(hostip, port, username, password) - if str(hypervisor).lower() == 'vmware': + if (str(hypervisor).lower() == 'vmware' + or str(hypervisor).lower() == 'hyperv'): ssh_command = "ssh -i /var/cloudstack/management/.ssh/id_rsa -ostricthostkeychecking=no " else: ssh_command = "ssh -i ~/.ssh/id_rsa.cloud -ostricthostkeychecking=no " diff --git a/ui/css/cloudstack3.css b/ui/css/cloudstack3.css index 11c1c7ee95c..2b88e033662 100644 --- a/ui/css/cloudstack3.css +++ b/ui/css/cloudstack3.css @@ -3080,7 +3080,7 @@ div.toolbar div.button.refresh span { div.toolbar div.button.add span, .detail-group .button.add span.icon { - padding: 0px 0 0px 18px; + padding: 0px 0 3px 18px; background: url(../images/icons.png) no-repeat -626px -209px; /*+placement:shift 0px 0px;*/ position: relative;