diff --git a/api/src/com/cloud/network/Network.java b/api/src/com/cloud/network/Network.java index efed5cd4f8b..e584e8de925 100644 --- a/api/src/com/cloud/network/Network.java +++ b/api/src/com/cloud/network/Network.java @@ -138,6 +138,7 @@ public interface Network extends ControlledEntity, StateObject, I // NiciraNvp is not an "External" provider, otherwise we get in trouble with NetworkServiceImpl.providersConfiguredForExternalNetworking public static final Provider NiciraNvp = new Provider("NiciraNvp", false); public static final Provider MidokuraMidonet = new Provider("MidokuraMidonet", true); + public static final Provider VPCNetscaler = new Provider("VPCNetscaler", true); private String name; private boolean isExternal; diff --git a/api/src/com/cloud/network/vpc/VpcService.java b/api/src/com/cloud/network/vpc/VpcService.java index 79ad75c0f13..9bf1beea5f0 100644 --- a/api/src/com/cloud/network/vpc/VpcService.java +++ b/api/src/com/cloud/network/vpc/VpcService.java @@ -41,7 +41,7 @@ public interface VpcService { public VpcOffering getVpcOffering(long vpcOfferingId); - public VpcOffering createVpcOffering(String name, String displayText, List supportedServices); + public VpcOffering createVpcOffering(String name, String displayText, List supportedServices, Map> serviceProviders); public Vpc getVpc(long vpcId); diff --git a/api/src/org/apache/cloudstack/api/ServerApiException.java b/api/src/org/apache/cloudstack/api/ServerApiException.java index 682e5b7e774..4b0fae58548 100644 --- a/api/src/org/apache/cloudstack/api/ServerApiException.java +++ b/api/src/org/apache/cloudstack/api/ServerApiException.java @@ -43,7 +43,7 @@ public class ServerApiException extends CloudRuntimeException { super(description, cause); _errorCode = errorCode; _description = description; - if (cause instanceof CloudRuntimeException || cause instanceof CloudException ) { + if (cause instanceof CloudRuntimeException) { CloudRuntimeException rt = (CloudRuntimeException) cause; ArrayList idList = rt.getIdProxyList(); if (idList != null) { @@ -52,6 +52,15 @@ public class ServerApiException extends CloudRuntimeException { } } setCSErrorCode(rt.getCSErrorCode()); + } else if (cause instanceof CloudException) { + CloudException rt = (CloudException) cause; + ArrayList idList = rt.getIdProxyList(); + if (idList != null) { + for (int i = 0; i < idList.size(); i++) { + addProxyObject(idList.get(i)); + } + } + setCSErrorCode(rt.getCSErrorCode()); } } diff --git a/api/src/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmd.java b/api/src/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmd.java index f08cb16b23d..3c7956b7d7e 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmd.java @@ -16,7 +16,7 @@ // under the License. package org.apache.cloudstack.api.command.admin.vpc; -import java.util.List; +import java.util.*; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; @@ -52,6 +52,10 @@ public class CreateVPCOfferingCmd extends BaseAsyncCreateCmd{ description="services supported by the vpc offering") private List supportedServices; + @Parameter(name = ApiConstants.SERVICE_PROVIDER_LIST, type = CommandType.MAP, description = "provider to service mapping. " + + "If not specified, the provider for the service will be mapped to the default provider on the physical network") + private Map serviceProviderList; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -68,10 +72,33 @@ public class CreateVPCOfferingCmd extends BaseAsyncCreateCmd{ return supportedServices; } + public Map> getServiceProviders() { + Map> serviceProviderMap = null; + if (serviceProviderList != null && !serviceProviderList.isEmpty()) { + serviceProviderMap = new HashMap>(); + Collection servicesCollection = serviceProviderList.values(); + Iterator iter = servicesCollection.iterator(); + while (iter.hasNext()) { + HashMap services = (HashMap) iter.next(); + String service = services.get("service"); + String provider = services.get("provider"); + List providerList = null; + if (serviceProviderMap.containsKey(service)) { + providerList = serviceProviderMap.get(service); + } else { + providerList = new ArrayList(); + } + providerList.add(provider); + serviceProviderMap.put(service, providerList); + } + } + + return serviceProviderMap; + } @Override public void create() throws ResourceAllocationException { - VpcOffering vpcOff = _vpcService.createVpcOffering(getVpcOfferingName(), getDisplayText(), getSupportedServices()); + VpcOffering vpcOff = _vpcService.createVpcOffering(getVpcOfferingName(), getDisplayText(), getSupportedServices(), getServiceProviders()); if (vpcOff != null) { this.setEntityId(vpcOff.getId()); this.setEntityUuid(vpcOff.getUuid()); diff --git a/debian/control b/debian/control index 380b2e4a78d..e9697ea5e26 100644 --- a/debian/control +++ b/debian/control @@ -48,7 +48,7 @@ Description: CloudStack server library Package: cloud-scripts Replaces: cloud-agent-scripts Architecture: any -Depends: openjdk-6-jre, python, bash, bzip2, gzip, unzip, nfs-common, openssh-client +Depends: openjdk-6-jre, python, bash, bzip2, gzip, unzip, nfs-common, openssh-client, lsb-release Description: CloudStack scripts This package contains a number of scripts needed for the CloudStack Agent and Management Server. Both the CloudStack Agent and Management server depend on this package diff --git a/developer/pom.xml b/developer/pom.xml index daaa6e3bc60..ff47b143093 100644 --- a/developer/pom.xml +++ b/developer/pom.xml @@ -27,16 +27,15 @@ 5.1.21 runtime - - org.apache.cloudstack - cloud-plugin-hypervisor-simulator - ${project.version} - compile - + + org.apache.cloudstack + cloud-plugin-hypervisor-simulator + ${project.version} + compile + install - target/db @@ -133,11 +132,6 @@ cloud-server ${project.version} - - org.apache.cloudstack - cloud-server - ${project.version} - @@ -149,15 +143,13 @@ - true + false true org.apache.cloudstack cloud-server - com.cloud.upgrade.DatabaseCreator - test ${project.parent.basedir}/utils/conf/db.properties @@ -178,7 +170,7 @@ ${basedir}/target/db/cloudbridge_offering_alter.sql ${basedir}/developer-prefill.sql - + com.cloud.upgrade.DatabaseUpgradeChecker --database=cloud,usage,awsapi --rootpassword=${db.root.password} @@ -191,6 +183,10 @@ catalina.home ${project.parent.basedir}/utils + + paths.script + ${basedir}/target/db + diff --git a/packaging/centos63/cloud.spec b/packaging/centos63/cloud.spec index 1267f47c8f3..72022d6f5ad 100644 --- a/packaging/centos63/cloud.spec +++ b/packaging/centos63/cloud.spec @@ -78,7 +78,7 @@ Requires: mkisofs Requires: MySQL-python Requires: python-paramiko Requires: ipmitool -Requires: %{name}-common = 4.1.0 +Requires: %{name}-common = %{_ver} Obsoletes: cloud-client < 4.1.0 Obsoletes: cloud-client-ui < 4.1.0 Obsoletes: cloud-daemonize < 4.1.0 diff --git a/python/lib/cloudutils/utilities.py b/python/lib/cloudutils/utilities.py index c9d1e339f72..739a48385a0 100755 --- a/python/lib/cloudutils/utilities.py +++ b/python/lib/cloudutils/utilities.py @@ -122,7 +122,14 @@ class Distribution: if kernel.find("2.6.32") != -1: self.release = "10.04" self.arch = bash("uname -m").getStdout() - + elif os.path.exists("/usr/bin/lsb_release"): + o = bash("/usr/bin/lsb_release -i") + distributor = o.getStdout().split(":\t")[1] + if "Debian" in distributor: + # This obviously needs a rewrite at some point + self.distro = "Ubuntu" + else: + raise UnknownSystemException(distributor) else: raise UnknownSystemException diff --git a/scripts/vm/hypervisor/xenserver/xenheartbeat.sh b/scripts/vm/hypervisor/xenserver/xenheartbeat.sh index 9cf2afe87f6..5edacf7e39a 100755 --- a/scripts/vm/hypervisor/xenserver/xenheartbeat.sh +++ b/scripts/vm/hypervisor/xenserver/xenheartbeat.sh @@ -6,9 +6,9 @@ # 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 @@ -17,9 +17,9 @@ # under the License. #set -x - + usage() { - printf "Usage: %s [uuid of this host] [interval in seconds]\n" $(basename $0) >&2 + printf "Usage: %s [uuid of this host] [timeout in seconds] [interval in seconds]\n" $(basename $0) >&2 } @@ -33,10 +33,24 @@ if [ -z $2 ]; then exit 3 fi +if [ ! -z $3 ]; then + interval=$3 +else + interval=10 +fi + +if [ $interval -gt $2 ]; then + usage + exit 3 +fi + file=/opt/xensource/bin/heartbeat -while true -do - sleep $2 +maxtries=$(($2 / $interval)) +tries=1 + +while [ $tries -le $maxtries ] +do + sleep $interval if [ ! -f $file ] then @@ -51,13 +65,17 @@ do hb=$dir/hb-$1 date +%s | dd of=$hb count=100 bs=1 2>/dev/null if [ $? -ne 0 ]; then - /usr/bin/logger -t heartbeat "Problem with $hb" - reboot -f + /usr/bin/logger -t heartbeat "Potential problem with $hb: not reachable since $(($tries * $interval)) seconds" + tries=$(($tries + 1)) + else + tries=1 fi else + /usr/bin/logger -t heartbeat "Heartbeat dir not found for $dir" sed -i /${dir##/*/}/d $file fi done + # for nfs dirs=$(cat $file | grep sr-mount) for dir in $dirs @@ -67,13 +85,17 @@ do hb=$dir/hb-$1 date +%s | dd of=$hb count=100 bs=1 2>/dev/null if [ $? -ne 0 ]; then - /usr/bin/logger -t heartbeat "Problem with $hb" - reboot -f + /usr/bin/logger -t heartbeat "Potential problem with $hb: not reachable since $(($tries * $interval)) seconds" + tries=$(($tries + 1)) + else + tries=1 fi else + /usr/bin/logger -t heartbeat "Heartbeat mount not found for $dir" sed -i /${dir##/*/}/d $file fi done - done +/usr/bin/logger -t heartbeat "Problem with $hb: not reachable for $2 seconds, rebooting system!" +reboot -f diff --git a/server/src/com/cloud/configuration/Config.java b/server/src/com/cloud/configuration/Config.java index 8c77715c0cf..1cea9aad933 100755 --- a/server/src/com/cloud/configuration/Config.java +++ b/server/src/com/cloud/configuration/Config.java @@ -232,6 +232,7 @@ public enum Config { EnableEC2API("Advanced", ManagementServer.class, Boolean.class, "enable.ec2.api", "false", "enable EC2 API on CloudStack", null), EnableS3API("Advanced", ManagementServer.class, Boolean.class, "enable.s3.api", "false", "enable Amazon S3 API on CloudStack", null), RecreateSystemVmEnabled("Advanced", ManagementServer.class, Boolean.class, "recreate.systemvm.enabled", "false", "If true, will recreate system vm root disk whenever starting system vm", "true,false"), + SetVmInternalNameUsingDisplayName("Advanced", ManagementServer.class, Boolean.class, "vm.instancename.flag", "false", "If true, will append guest VM's display Name (if set) to its internal instance name", "true,false"), IncorrectLoginAttemptsAllowed("Advanced", ManagementServer.class, Integer.class, "incorrect.login.attempts.allowed", "5", "Incorrect login attempts allowed before the user is disabled", null), // Ovm OvmPublicNetwork("Hidden", ManagementServer.class, String.class, "ovm.public.network.device", null, "Specify the public bridge on host for public network", null), diff --git a/server/src/com/cloud/network/element/VpcVirtualRouterElement.java b/server/src/com/cloud/network/element/VpcVirtualRouterElement.java index 27b1a2a7a9a..aa8f10d9c2a 100644 --- a/server/src/com/cloud/network/element/VpcVirtualRouterElement.java +++ b/server/src/com/cloud/network/element/VpcVirtualRouterElement.java @@ -446,7 +446,7 @@ public class VpcVirtualRouterElement extends VirtualRouterElement implements Vpc Long vpcId = ip.getVpcId(); Vpc vpc = _vpcMgr.getVpc(vpcId); - if (!_vpcMgr.vpcProviderEnabledInZone(vpc.getZoneId())) { + if (!_vpcMgr.vpcProviderEnabledInZone(vpc.getZoneId(), Provider.VPCVirtualRouter.getName())) { throw new ResourceUnavailableException("VPC provider is not enabled in zone " + vpc.getZoneId(), DataCenter.class, vpc.getZoneId()); } @@ -474,7 +474,7 @@ public class VpcVirtualRouterElement extends VirtualRouterElement implements Vpc Long vpcId = ip.getVpcId(); Vpc vpc = _vpcMgr.getVpc(vpcId); - if (!_vpcMgr.vpcProviderEnabledInZone(vpc.getZoneId())) { + if (!_vpcMgr.vpcProviderEnabledInZone(vpc.getZoneId(), Provider.VPCVirtualRouter.getName())) { throw new ResourceUnavailableException("VPC provider is not enabled in zone " + vpc.getZoneId(), DataCenter.class, vpc.getZoneId()); } diff --git a/server/src/com/cloud/network/vpc/VpcManager.java b/server/src/com/cloud/network/vpc/VpcManager.java index 8d49aa1615c..714330dd5aa 100644 --- a/server/src/com/cloud/network/vpc/VpcManager.java +++ b/server/src/com/cloud/network/vpc/VpcManager.java @@ -71,9 +71,10 @@ public interface VpcManager extends VpcService{ /** * @param zoneId + * @param provider * @return */ - boolean vpcProviderEnabledInZone(long zoneId); + boolean vpcProviderEnabledInZone(long zoneId, String provider); /** * @param vpcId diff --git a/server/src/com/cloud/network/vpc/VpcManagerImpl.java b/server/src/com/cloud/network/vpc/VpcManagerImpl.java index 60e2a3845d4..c9c13c97199 100644 --- a/server/src/com/cloud/network/vpc/VpcManagerImpl.java +++ b/server/src/com/cloud/network/vpc/VpcManagerImpl.java @@ -31,6 +31,7 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.network.element.StaticNatServiceProvider; import org.apache.cloudstack.api.command.user.vpc.ListStaticRoutesCmd; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -84,6 +85,7 @@ import com.cloud.network.vpc.dao.VpcDao; import com.cloud.network.vpc.dao.VpcGatewayDao; import com.cloud.network.vpc.dao.VpcOfferingDao; import com.cloud.network.vpc.dao.VpcOfferingServiceMapDao; +import com.cloud.network.vpc.dao.VpcServiceMapDao; import com.cloud.network.vpn.Site2SiteVpnManager; import com.cloud.offering.NetworkOffering; import com.cloud.offerings.NetworkOfferingServiceMapVO; @@ -173,10 +175,11 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager{ VlanDao _vlanDao = null; @Inject ResourceLimitService _resourceLimitMgr; - + @Inject + VpcServiceMapDao _vpcSrvcDao; private final ScheduledExecutorService _executor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("VpcChecker")); - private VpcProvider vpcElement = null; + private List vpcElements = null; private final List nonSupportedServices = Arrays.asList(Service.SecurityGroup, Service.Firewall); int _cleanupInterval; @@ -255,7 +258,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager{ @Override @ActionEvent(eventType = EventTypes.EVENT_VPC_OFFERING_CREATE, eventDescription = "creating vpc offering", create=true) - public VpcOffering createVpcOffering(String name, String displayText, List supportedServices) { + public VpcOffering createVpcOffering(String name, String displayText, List supportedServices, Map> serviceProviders) { Map> svcProviderMap = new HashMap>(); Set defaultProviders = new HashSet(); defaultProviders.add(Provider.VPCVirtualRouter); @@ -291,7 +294,34 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager{ } svcProviderMap.put(Service.Gateway, defaultProviders); - + + if (serviceProviders != null) { + for (String serviceStr : serviceProviders.keySet()) { + Network.Service service = Network.Service.getService(serviceStr); + if (svcProviderMap.containsKey(service)) { + Set providers = new HashSet(); + // don't allow to specify more than 1 provider per service + if (serviceProviders.get(serviceStr) != null && serviceProviders.get(serviceStr).size() > 1) { + throw new InvalidParameterValueException("In the current release only one provider can be " + + "specified for the service"); + } + for (String prvNameStr : serviceProviders.get(serviceStr)) { + // check if provider is supported + Network.Provider provider = Network.Provider.getProvider(prvNameStr); + if (provider == null) { + throw new InvalidParameterValueException("Invalid service provider: " + prvNameStr); + } + + providers.add(provider); + } + svcProviderMap.put(service, providers); + } else { + throw new InvalidParameterValueException("Service " + serviceStr + " is not enabled for the network " + + "offering, can't add a provider to it"); + } + } + } + VpcOffering offering = createVpcOffering(name, displayText, svcProviderMap, false, null); UserContext.current().setEventDetails(" Id: " + offering.getId() + " Name: " + name); @@ -556,11 +586,11 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager{ } @Override - public boolean vpcProviderEnabledInZone(long zoneId) + public boolean vpcProviderEnabledInZone(long zoneId, String provider) { //the provider has to be enabled at least in one network in the zone for (PhysicalNetwork pNtwk : _pNtwkDao.listByZone(zoneId)) { - if (_ntwkModel.isProviderEnabledInPhysicalNetwork(pNtwk.getId(), Provider.VPCVirtualRouter.getName())) { + if (_ntwkModel.isProviderEnabledInPhysicalNetwork(pNtwk.getId(), provider)) { return true; } } @@ -573,11 +603,6 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager{ protected Vpc createVpc(long zoneId, long vpcOffId, Account vpcOwner, String vpcName, String displayText, String cidr, String networkDomain) { - if (!vpcProviderEnabledInZone(zoneId)) { - throw new InvalidParameterValueException("Provider " + Provider.VPCVirtualRouter.getName() + - " should be enabled in at least one physical network of the zone specified"); - } - //Validate CIDR if (!NetUtils.isValidCIDR(cidr)) { throw new InvalidParameterValueException("Invalid CIDR specified " + cidr); @@ -601,7 +626,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager{ txn.start(); VpcVO vpc = new VpcVO (zoneId, vpcName, displayText, vpcOwner.getId(), vpcOwner.getDomainId(), vpcOffId, cidr, networkDomain); - vpc = _vpcDao.persist(vpc); + vpc = _vpcDao.persist(vpc, finalizeServicesAndProvidersForVpc(zoneId, vpcOffId)); _resourceLimitMgr.incrementResourceCount(vpcOwner.getId(), ResourceType.vpc); txn.commit(); @@ -609,7 +634,44 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager{ return vpc; } - + + private Map finalizeServicesAndProvidersForVpc(long zoneId, long offeringId) { + Map svcProviders = new HashMap(); + Map> providerSvcs = new HashMap>(); + List servicesMap = _vpcOffSvcMapDao.listByVpcOffId(offeringId); + + for (VpcOfferingServiceMapVO serviceMap : servicesMap) { + if (svcProviders.containsKey(serviceMap.getService())) { + // FIXME - right now we pick up the first provider from the list, need to add more logic based on + // provider load, etc + continue; + } + + String service = serviceMap.getService(); + String provider = serviceMap.getProvider(); + + if (provider == null) { + // Default to VPCVirtualRouter + provider = Provider.VPCVirtualRouter.getName(); + } + + + if (!vpcProviderEnabledInZone(zoneId, provider)) { + throw new InvalidParameterValueException("Provider " + provider + + " should be enabled in at least one physical network of the zone specified"); + } + + svcProviders.put(service, provider); + List l = providerSvcs.get(provider); + if (l == null) { + providerSvcs.put(provider, l = new ArrayList()); + } + l.add(service); + } + + return svcProviders; + } + @Override @ActionEvent(eventType = EventTypes.EVENT_VPC_DELETE, eventDescription = "deleting VPC") public boolean deleteVpc(long vpcId) throws ConcurrentOperationException, ResourceUnavailableException { @@ -903,13 +965,19 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager{ protected boolean startVpc(Vpc vpc, DeployDestination dest, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException { //deploy provider - if (getVpcElement().implementVpc(vpc, dest, context)) { - s_logger.debug("Vpc " + vpc + " has started succesfully"); - return true; - } else { - s_logger.warn("Vpc " + vpc + " failed to start"); - return false; + boolean success = true; + List providersToImplement = getVpcProviders(vpc.getId()); + for (VpcProvider element: getVpcElements()){ + if(providersToImplement.contains(element.getProvider())){ + if (element.implementVpc(vpc, dest, context)) { + s_logger.debug("Vpc " + vpc + " has started succesfully"); + } else { + s_logger.warn("Vpc " + vpc + " failed to start"); + success = false; + } + } } + return success; } @Override @@ -928,15 +996,22 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager{ //shutdown provider s_logger.debug("Shutting down vpc " + vpc); - ReservationContext context = new ReservationContextImpl(null, null, _accountMgr.getActiveUser(ctx.getCallerUserId()), caller); - boolean success = getVpcElement().shutdownVpc(vpc, context); - //TODO - shutdown all vpc resources here (ACLs, gateways, etc) - if (success) { - s_logger.debug("Vpc " + vpc + " has been shutdown succesfully"); - } else { - s_logger.warn("Vpc " + vpc + " failed to shutdown"); + + boolean success = true; + List providersToImplement = getVpcProviders(vpc.getId()); + ReservationContext context = new ReservationContextImpl(null, null, _accountMgr.getActiveUser(ctx.getCallerUserId()), caller); + for (VpcProvider element: getVpcElements()){ + if(providersToImplement.contains(element.getProvider())){ + if (element.shutdownVpc(vpc, context)) { + s_logger.debug("Vpc " + vpc + " has been shutdown succesfully"); + } else { + s_logger.warn("Vpc " + vpc + " failed to shutdown"); + success = false; + } + } } + return success; } @@ -1085,16 +1160,18 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager{ } - protected VpcProvider getVpcElement() { - if (vpcElement == null) { - vpcElement = ((VpcProvider)_ntwkModel.getElementImplementingProvider(Provider.VPCVirtualRouter.getName())); + protected List getVpcElements() { + if (vpcElements == null) { + vpcElements = new ArrayList(); + vpcElements.add((VpcProvider)_ntwkModel.getElementImplementingProvider(Provider.VPCVirtualRouter.getName())); + vpcElements.add((VpcProvider)_ntwkModel.getElementImplementingProvider(Provider.VPCNetscaler.getName())); } - if (vpcElement == null) { - throw new CloudRuntimeException("Failed to initialize vpc element"); + if (vpcElements == null) { + throw new CloudRuntimeException("Failed to initialize vpc elements"); } - - return vpcElement; + + return vpcElements; } @Override @@ -1268,10 +1345,14 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager{ public PrivateGateway applyVpcPrivateGateway(long gatewayId, boolean destroyOnFailure) throws ConcurrentOperationException, ResourceUnavailableException { VpcGatewayVO vo = _vpcGatewayDao.findById(gatewayId); - boolean success = false; + boolean success = true; try { PrivateGateway gateway = getVpcPrivateGateway(gatewayId); - success = getVpcElement().createPrivateGateway(gateway); + for (VpcProvider provider: getVpcElements()){ + if(!provider.createPrivateGateway(gateway)){ + success = false; + } + } if (success) { s_logger.debug("Private gateway " + gateway + " was applied succesfully on the backend"); if (vo.getState() != VpcGateway.State.Ready) { @@ -1327,11 +1408,13 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager{ //1) delete the gateway on the backend PrivateGateway gateway = getVpcPrivateGateway(gatewayId); - if (getVpcElement().deletePrivateGateway(gateway)) { - s_logger.debug("Private gateway " + gateway + " was applied succesfully on the backend"); - } else { - s_logger.warn("Private gateway " + gateway + " failed to apply on the backend"); - return false; + for (VpcProvider provider: getVpcElements()){ + if (provider.deletePrivateGateway(gateway)) { + s_logger.debug("Private gateway " + gateway + " was applied succesfully on the backend"); + } else { + s_logger.warn("Private gateway " + gateway + " failed to apply on the backend"); + return false; + } } //2) Delete private gateway from the DB @@ -1499,11 +1582,19 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager{ Vpc vpc = getVpc(routes.get(0).getVpcId()); s_logger.debug("Applying static routes for vpc " + vpc); - if (getVpcElement().applyStaticRoutes(vpc, routes)) { - s_logger.debug("Applied static routes for vpc " + vpc); - } else { - s_logger.warn("Failed to apply static routes for vpc " + vpc); - return false; + String staticNatProvider = _vpcSrvcDao.getProviderForServiceInVpc(vpc.getId(), Service.StaticNat); + + for (VpcProvider provider: getVpcElements()){ + if (!(provider instanceof StaticNatServiceProvider && provider.getName().equalsIgnoreCase(staticNatProvider))) { + continue; + } + + if (provider.applyStaticRoutes(vpc, routes)) { + s_logger.debug("Applied static routes for vpc " + vpc); + } else { + s_logger.warn("Failed to apply static routes for vpc " + vpc); + return false; + } } return true; @@ -1958,4 +2049,16 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager{ hTypes.add(HypervisorType.KVM); return hTypes; } + + private List getVpcProviders(long vpcId) { + List providerNames = _vpcSrvcDao.getDistinctProviders(vpcId); + Map providers = new HashMap(); + for (String providerName : providerNames) { + if(!providers.containsKey(providerName)){ + providers.put(providerName, Network.Provider.getProvider(providerName)); + } + } + + return new ArrayList(providers.values()); + } } diff --git a/server/src/com/cloud/network/vpc/VpcServiceMapVO.java b/server/src/com/cloud/network/vpc/VpcServiceMapVO.java new file mode 100644 index 00000000000..6f229096404 --- /dev/null +++ b/server/src/com/cloud/network/vpc/VpcServiceMapVO.java @@ -0,0 +1,90 @@ +// 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 java.util.Date; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +import com.cloud.network.Network.Provider; +import com.cloud.network.Network.Service; +import com.cloud.utils.db.GenericDao; + +@Entity +@Table(name="vpc_service_map") +public class VpcServiceMapVO { + @Id + @GeneratedValue(strategy=GenerationType.IDENTITY) + @Column(name="id") + long id; + + @Column(name="vpc_id") + long vpcId; + + @Column(name="service") + String service; + + @Column(name="provider") + String provider; + + @Column(name=GenericDao.CREATED_COLUMN) + Date created; + + public long getId() { + return id; + } + + public long getVpcId() { + return vpcId; + } + + public String getService() { + return service; + } + + public String getProvider() { + return provider; + } + + public Date getCreated() { + return created; + } + + public VpcServiceMapVO() { + } + + public VpcServiceMapVO(long vpcId, Service service, Provider provider) { + this.vpcId = vpcId; + this.service = service.getName(); + this.provider = provider.getName(); + } + + public String toString() { + StringBuilder buf = new StringBuilder("[VPC Service["); + return buf.append(vpcId).append("-").append(service).append("-").append(provider).append("]").toString(); + } +} + + + + + diff --git a/server/src/com/cloud/network/vpc/dao/VpcDao.java b/server/src/com/cloud/network/vpc/dao/VpcDao.java index 80e5e15f9c0..5a33217c028 100644 --- a/server/src/com/cloud/network/vpc/dao/VpcDao.java +++ b/server/src/com/cloud/network/vpc/dao/VpcDao.java @@ -17,6 +17,7 @@ package com.cloud.network.vpc.dao; import java.util.List; +import java.util.Map; import com.cloud.network.vpc.Vpc; import com.cloud.network.vpc.VpcVO; @@ -39,4 +40,8 @@ public interface VpcDao extends GenericDao{ long countByAccountId(long accountId); + VpcVO persist(VpcVO vpc, Map serviceProviderMap); + + void persistVpcServiceProviders(long vpcId, + Map serviceProviderMap); } diff --git a/server/src/com/cloud/network/vpc/dao/VpcDaoImpl.java b/server/src/com/cloud/network/vpc/dao/VpcDaoImpl.java index a9b5e182b60..5fdf27972a2 100644 --- a/server/src/com/cloud/network/vpc/dao/VpcDaoImpl.java +++ b/server/src/com/cloud/network/vpc/dao/VpcDaoImpl.java @@ -17,10 +17,13 @@ package com.cloud.network.vpc.dao; import java.util.List; +import java.util.Map; import javax.ejb.Local; import javax.inject.Inject; +import com.cloud.network.Network; +import com.cloud.network.vpc.VpcServiceMapVO; import org.springframework.stereotype.Component; import com.cloud.network.vpc.Vpc; @@ -45,6 +48,7 @@ public class VpcDaoImpl extends GenericDaoBase implements VpcDao{ final SearchBuilder AllFieldsSearch; final GenericSearchBuilder CountByAccountId; @Inject ResourceTagsDaoImpl _tagsDao; + @Inject VpcServiceMapDaoImpl _vpcSvcMap; protected VpcDaoImpl() { super(); @@ -120,5 +124,28 @@ public class VpcDaoImpl extends GenericDaoBase implements VpcDao{ List results = customSearch(sc, null); return results.get(0); } + + @Override + @DB + public VpcVO persist(VpcVO vpc, Map serviceProviderMap) { + Transaction txn = Transaction.currentTxn(); + txn.start(); + VpcVO newVpc = super.persist(vpc); + persistVpcServiceProviders(vpc.getId(), serviceProviderMap); + txn.commit(); + return newVpc; + } + + @Override + @DB + public void persistVpcServiceProviders(long vpcId, Map serviceProviderMap) { + Transaction txn = Transaction.currentTxn(); + txn.start(); + for (String service : serviceProviderMap.keySet()) { + VpcServiceMapVO serviceMap = new VpcServiceMapVO(vpcId, Network.Service.getService(service), Network.Provider.getProvider(serviceProviderMap.get(service))); + _vpcSvcMap.persist(serviceMap); + } + txn.commit(); + } } diff --git a/server/src/com/cloud/network/vpc/dao/VpcServiceMapDao.java b/server/src/com/cloud/network/vpc/dao/VpcServiceMapDao.java new file mode 100644 index 00000000000..8c4537ede4e --- /dev/null +++ b/server/src/com/cloud/network/vpc/dao/VpcServiceMapDao.java @@ -0,0 +1,40 @@ +// 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.dao; + +import java.util.List; + +import com.cloud.network.Network.Provider; +import com.cloud.network.Network.Service; +import com.cloud.network.dao.NetworkServiceMapVO; +import com.cloud.network.vpc.VpcServiceMapVO; +import com.cloud.utils.db.GenericDao; + +/** + * VpcServiceMapDao deals with searches and operations done on the + * vpc_service_map table. + * + */ +public interface VpcServiceMapDao extends GenericDao{ + boolean areServicesSupportedInVpc(long vpcId, Service... services); + boolean canProviderSupportServiceInVpc(long vpcId, Service service, Provider provider); + List getServicesInVpc(long vpcId); + String getProviderForServiceInVpc(long vpcId, Service service); + void deleteByVpcId(long vpcId); + List getDistinctProviders(long vpcId); + String isProviderForVpc(long vpcId, Provider provider); +} \ No newline at end of file diff --git a/server/src/com/cloud/network/vpc/dao/VpcServiceMapDaoImpl.java b/server/src/com/cloud/network/vpc/dao/VpcServiceMapDaoImpl.java new file mode 100644 index 00000000000..a992181f864 --- /dev/null +++ b/server/src/com/cloud/network/vpc/dao/VpcServiceMapDaoImpl.java @@ -0,0 +1,115 @@ +// 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.dao; + +import java.util.List; + +import javax.ejb.Local; + +import com.cloud.exception.UnsupportedServiceException; +import com.cloud.network.Network.Provider; +import com.cloud.network.Network.Service; +import com.cloud.network.dao.NetworkServiceMapVO; +import com.cloud.network.vpc.VpcServiceMapVO; +import com.cloud.utils.db.DB; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.GenericSearchBuilder; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import org.springframework.stereotype.Component; + +@Component +@Local(value=VpcServiceMapDao.class) @DB(txn=false) +public class VpcServiceMapDaoImpl extends GenericDaoBase implements VpcServiceMapDao { + final SearchBuilder AllFieldsSearch; + final SearchBuilder MultipleServicesSearch; + final GenericSearchBuilder DistinctProvidersSearch; + + protected VpcServiceMapDaoImpl(){ + super(); + AllFieldsSearch = createSearchBuilder(); + AllFieldsSearch.and("vpcId", AllFieldsSearch.entity().getVpcId(), SearchCriteria.Op.EQ); + AllFieldsSearch.and("service", AllFieldsSearch.entity().getService(), SearchCriteria.Op.EQ); + AllFieldsSearch.and("provider", AllFieldsSearch.entity().getProvider(), SearchCriteria.Op.EQ); + AllFieldsSearch.done(); + + MultipleServicesSearch = createSearchBuilder(); + MultipleServicesSearch.and("vpcId", MultipleServicesSearch.entity().getVpcId(), SearchCriteria.Op.EQ); + MultipleServicesSearch.and("service", MultipleServicesSearch.entity().getService(), SearchCriteria.Op.IN); + MultipleServicesSearch.and("provider", MultipleServicesSearch.entity().getProvider(), SearchCriteria.Op.EQ); + MultipleServicesSearch.done(); + + DistinctProvidersSearch = createSearchBuilder(String.class); + DistinctProvidersSearch.and("vpcId", DistinctProvidersSearch.entity().getVpcId(), SearchCriteria.Op.EQ); + DistinctProvidersSearch.and("provider", DistinctProvidersSearch.entity().getProvider(), SearchCriteria.Op.EQ); + DistinctProvidersSearch.selectField(DistinctProvidersSearch.entity().getProvider()); + DistinctProvidersSearch.done(); + } + + @Override + public boolean areServicesSupportedInVpc(long vpcId, Service... services) { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean canProviderSupportServiceInVpc(long vpcId, Service service, + Provider provider) { + // TODO Auto-generated method stub + return false; + } + + @Override + public List getServicesInVpc(long vpcId) { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getProviderForServiceInVpc(long vpcId, Service service) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("vpcId", vpcId); + sc.setParameters("service", service.getName()); + VpcServiceMapVO ntwkSvc = findOneBy(sc); + if (ntwkSvc == null) { + throw new UnsupportedServiceException("Service " + service.getName() + " is not supported in the vpc id=" + vpcId); + } + + return ntwkSvc.getProvider(); + } + + @Override + public void deleteByVpcId(long vpcId) { + // TODO Auto-generated method stub + + } + + @Override + public List getDistinctProviders(long vpcId) { + SearchCriteria sc = DistinctProvidersSearch.create(); + sc.setParameters("vpcId", vpcId); + List results = customSearch(sc, null); + return results; + } + + @Override + public String isProviderForVpc(long vpcId, Provider provider) { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/server/src/com/cloud/storage/dao/VMTemplateHostDaoImpl.java b/server/src/com/cloud/storage/dao/VMTemplateHostDaoImpl.java index 4d19bfc0074..7f35eabfaa7 100755 --- a/server/src/com/cloud/storage/dao/VMTemplateHostDaoImpl.java +++ b/server/src/com/cloud/storage/dao/VMTemplateHostDaoImpl.java @@ -258,7 +258,6 @@ public class VMTemplateHostDaoImpl extends GenericDaoBase userVmUsingIso = _userVmDao.listByIsoId(tInfo.getId()); + //check if there is any Vm using this ISO. + if (userVmUsingIso == null || userVmUsingIso.isEmpty()) { + DeleteTemplateCommand dtCommand = new DeleteTemplateCommand(ssHost.getStorageUrl(), tInfo.getInstallPath()); + try { + _agentMgr.sendToSecStorage(ssHost, dtCommand, null); + } catch (AgentUnavailableException e) { + String err = "Failed to delete " + tInfo.getTemplateName() + " on secondary storage " + sserverId + " which isn't in the database"; + s_logger.error(err); + return; + } - String description = "Deleted template " + tInfo.getTemplateName() + " on secondary storage " + sserverId + " since it isn't in the database"; - s_logger.info(description); + String description = "Deleted template " + tInfo.getTemplateName() + " on secondary storage " + sserverId + " since it isn't in the database"; + s_logger.info(description); + } } } diff --git a/server/src/com/cloud/template/HyervisorTemplateAdapter.java b/server/src/com/cloud/template/HyervisorTemplateAdapter.java index c1177f4a060..ad41af51506 100755 --- a/server/src/com/cloud/template/HyervisorTemplateAdapter.java +++ b/server/src/com/cloud/template/HyervisorTemplateAdapter.java @@ -63,6 +63,8 @@ import com.cloud.storage.secondary.SecondaryStorageVmManager; import com.cloud.user.Account; import com.cloud.utils.db.DB; import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.vm.UserVmVO; + import org.apache.cloudstack.api.command.user.iso.DeleteIsoCmd; import org.apache.cloudstack.api.command.user.iso.RegisterIsoCmd; import org.apache.cloudstack.api.command.user.template.DeleteTemplateCmd; @@ -86,7 +88,6 @@ public class HyervisorTemplateAdapter extends TemplateAdapterBase implements Tem @Inject ImageDataFactory imageFactory; @Inject TemplateManager templateMgr; - @Override public String getName() { return TemplateAdapterType.Hypervisor.getName(); @@ -248,17 +249,21 @@ public class HyervisorTemplateAdapter extends TemplateAdapterBase implements Tem templateHostVO.setDestroyed(true); _tmpltHostDao.update(templateHostVO.getId(), templateHostVO); String installPath = templateHostVO.getInstallPath(); - if (installPath != null) { - Answer answer = _agentMgr.sendToSecStorage(secondaryStorageHost, new DeleteTemplateCommand(secondaryStorageHost.getStorageUrl(), installPath)); + List userVmUsingIso = _userVmDao.listByIsoId(templateId); + //check if there is any VM using this ISO. + if (userVmUsingIso == null || userVmUsingIso.isEmpty()) { + if (installPath != null) { + Answer answer = _agentMgr.sendToSecStorage(secondaryStorageHost, new DeleteTemplateCommand(secondaryStorageHost.getStorageUrl(), installPath)); - if (answer == null || !answer.getResult()) { - s_logger.debug("Failed to delete " + templateHostVO + " due to " + ((answer == null) ? "answer is null" : answer.getDetails())); + if (answer == null || !answer.getResult()) { + s_logger.debug("Failed to delete " + templateHostVO + " due to " + ((answer == null) ? "answer is null" : answer.getDetails())); + } else { + _tmpltHostDao.remove(templateHostVO.getId()); + s_logger.debug("Deleted template at: " + installPath); + } } else { _tmpltHostDao.remove(templateHostVO.getId()); - s_logger.debug("Deleted template at: " + installPath); } - } else { - _tmpltHostDao.remove(templateHostVO.getId()); } VMTemplateZoneVO templateZone = _tmpltZoneDao.findByZoneTemplate(sZoneId, templateId); diff --git a/server/src/com/cloud/template/TemplateAdapterBase.java b/server/src/com/cloud/template/TemplateAdapterBase.java index 247ce636cf2..1b114250621 100755 --- a/server/src/com/cloud/template/TemplateAdapterBase.java +++ b/server/src/com/cloud/template/TemplateAdapterBase.java @@ -63,6 +63,7 @@ import com.cloud.utils.EnumUtils; import com.cloud.utils.component.AdapterBase; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.UserVmVO; +import com.cloud.vm.dao.UserVmDao; public abstract class TemplateAdapterBase extends AdapterBase implements TemplateAdapter { private final static Logger s_logger = Logger.getLogger(TemplateAdapterBase.class); @@ -77,6 +78,7 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat protected @Inject VMTemplateZoneDao _tmpltZoneDao; protected @Inject UsageEventDao _usageEventDao; protected @Inject HostDao _hostDao; + protected @Inject UserVmDao _userVmDao; protected @Inject ResourceLimitService _resourceLimitMgr; protected @Inject DataStoreManager storeMgr; @Inject TemplateManager templateMgr; diff --git a/server/src/com/cloud/template/TemplateManagerImpl.java b/server/src/com/cloud/template/TemplateManagerImpl.java index 101c3d9c714..29659d3deee 100755 --- a/server/src/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/com/cloud/template/TemplateManagerImpl.java @@ -1227,32 +1227,37 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, } @Override - public boolean templateIsDeleteable(VMTemplateHostVO templateHostRef) { - VMTemplateVO template = _tmpltDao.findByIdIncludingRemoved(templateHostRef.getTemplateId()); - long templateId = template.getId(); - HostVO secondaryStorageHost = _hostDao.findById(templateHostRef.getHostId()); - long zoneId = secondaryStorageHost.getDataCenterId(); - DataCenterVO zone = _dcDao.findById(zoneId); - - // Check if there are VMs running in the template host ref's zone that use the template - List nonExpungedVms = _vmInstanceDao.listNonExpungedByZoneAndTemplate(zoneId, templateId); - - if (!nonExpungedVms.isEmpty()) { - s_logger.debug("Template " + template.getName() + " in zone " + zone.getName() + " is not deleteable because there are non-expunged VMs deployed from this template."); - return false; - } - - // Check if there are any snapshots for the template in the template host ref's zone - List volumes = _volumeDao.findByTemplateAndZone(templateId, zoneId); - for (VolumeVO volume : volumes) { - List snapshots = _snapshotDao.listByVolumeIdVersion(volume.getId(), "2.1"); - if (!snapshots.isEmpty()) { - s_logger.debug("Template " + template.getName() + " in zone " + zone.getName() + " is not deleteable because there are 2.1 snapshots using this template."); - return false; - } - } - - return true; + public boolean templateIsDeleteable(VMTemplateHostVO templateHostRef) { + VMTemplateVO template = _tmpltDao.findByIdIncludingRemoved(templateHostRef.getTemplateId()); + long templateId = template.getId(); + HostVO secondaryStorageHost = _hostDao.findById(templateHostRef.getHostId()); + long zoneId = secondaryStorageHost.getDataCenterId(); + DataCenterVO zone = _dcDao.findById(zoneId); + + // Check if there are VMs running in the template host ref's zone that use the template + List nonExpungedVms = _vmInstanceDao.listNonExpungedByZoneAndTemplate(zoneId, templateId); + + if (!nonExpungedVms.isEmpty()) { + s_logger.debug("Template " + template.getName() + " in zone " + zone.getName() + " is not deleteable because there are non-expunged VMs deployed from this template."); + return false; + } + List userVmUsingIso = _userVmDao.listByIsoId(templateId); + //check if there is any VM using this ISO. + if (!userVmUsingIso.isEmpty()) { + s_logger.debug("ISO " + template.getName() + " in zone " + zone.getName() + " is not deleteable because it is attached to " + userVmUsingIso.size() + " VMs"); + return false; + } + // Check if there are any snapshots for the template in the template host ref's zone + List volumes = _volumeDao.findByTemplateAndZone(templateId, zoneId); + for (VolumeVO volume : volumes) { + List snapshots = _snapshotDao.listByVolumeIdVersion(volume.getId(), "2.1"); + if (!snapshots.isEmpty()) { + s_logger.debug("Template " + template.getName() + " in zone " + zone.getName() + " is not deleteable because there are 2.1 snapshots using this template."); + return false; + } + } + + return true; } @Override diff --git a/server/src/com/cloud/upgrade/dao/Upgrade410to420.java b/server/src/com/cloud/upgrade/dao/Upgrade410to420.java index a0592579a43..9000e15f7aa 100644 --- a/server/src/com/cloud/upgrade/dao/Upgrade410to420.java +++ b/server/src/com/cloud/upgrade/dao/Upgrade410to420.java @@ -59,6 +59,20 @@ public class Upgrade410to420 implements DbUpgrade { @Override public void performDataMigration(Connection conn) { + PreparedStatement sql = null; + try { + sql = conn.prepareStatement("update vm_template set image_data_store_id = 1 where type = 'SYSTEM' or type = 'BUILTIN'"); + sql.executeUpdate(); + } catch (SQLException e) { + throw new CloudRuntimeException("Failed to upgrade vm template data store uuid: " + e.toString()); + } finally { + if (sql != null) { + try { + sql.close(); + } catch (SQLException e) { + } + } + } } @Override diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index cf9eb274712..6cb3f1a70af 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -60,16 +60,16 @@ import com.cloud.agent.AgentManager.OnError; import com.cloud.agent.api.Answer; import com.cloud.agent.api.GetVmStatsAnswer; import com.cloud.agent.api.GetVmStatsCommand; +import com.cloud.agent.api.PlugNicAnswer; +import com.cloud.agent.api.PlugNicCommand; import com.cloud.agent.api.StartAnswer; import com.cloud.agent.api.StopAnswer; +import com.cloud.agent.api.UnPlugNicAnswer; +import com.cloud.agent.api.UnPlugNicCommand; import com.cloud.agent.api.VmStatsEntry; import com.cloud.agent.api.to.NicTO; import com.cloud.agent.api.to.VirtualMachineTO; import com.cloud.agent.api.to.VolumeTO; -import com.cloud.agent.api.PlugNicAnswer; -import com.cloud.agent.api.PlugNicCommand; -import com.cloud.agent.api.UnPlugNicAnswer; -import com.cloud.agent.api.UnPlugNicCommand; import com.cloud.agent.manager.Commands; import com.cloud.alert.AlertManager; import com.cloud.api.query.dao.UserVmJoinDao; @@ -115,11 +115,14 @@ import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.hypervisor.dao.HypervisorCapabilitiesDao; -import com.cloud.network.*; +import com.cloud.network.Network; import com.cloud.network.Network.IpAddresses; import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; +import com.cloud.network.NetworkManager; +import com.cloud.network.NetworkModel; import com.cloud.network.Networks.TrafficType; +import com.cloud.network.PhysicalNetwork; import com.cloud.network.dao.FirewallRulesDao; import com.cloud.network.dao.IPAddressDao; import com.cloud.network.dao.IPAddressVO; @@ -244,6 +247,7 @@ import java.util.*; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; + import com.cloud.vm.dao.InstanceGroupDao; import com.cloud.vm.dao.InstanceGroupVMMapDao; import com.cloud.vm.dao.NicDao; @@ -252,7 +256,6 @@ import com.cloud.vm.dao.UserVmDetailsDao; import com.cloud.vm.dao.VMInstanceDao; import com.cloud.vm.snapshot.VMSnapshot; import com.cloud.vm.snapshot.VMSnapshotManager; -//import com.cloud.vm.snapshot.VMSnapshotVO; import com.cloud.vm.snapshot.dao.VMSnapshotDao; @Local(value = { UserVmManager.class, UserVmService.class }) @@ -408,10 +411,12 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use protected String _name; protected String _instance; protected String _zone; + protected boolean _instanceNameFlag; @Inject ConfigurationDao _configDao; private int _createprivatetemplatefromvolumewait; private int _createprivatetemplatefromsnapshotwait; + private final int MAX_VM_NAME_LEN = 80; @Inject protected OrchestrationService _orchSrvc; @@ -1219,6 +1224,15 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use VirtualMachine.State.getStateMachine().registerListener( new UserVmStateListener(_usageEventDao, _networkDao, _nicDao)); + value = _configDao.getValue(Config.SetVmInternalNameUsingDisplayName.key()); + if(value == null) { + _instanceNameFlag = false; + } + else + { + _instanceNameFlag = Boolean.parseBoolean(value); + } + s_logger.info("User VM Manager is configured."); return true; @@ -2114,6 +2128,14 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId, diskSize, networkList, null, group, userData, sshKeyPair, hypervisor, caller, requestedIps, defaultIps, keyboard); } + + public void checkNameForRFCCompliance(String name) { + if (!NetUtils.verifyDomainNameLabel(name, true)) { + throw new InvalidParameterValueException("Invalid name. Vm name can contain ASCII letters 'a' through 'z', the digits '0' through '9', " + + "and the hyphen ('-'), must be between 1 and 63 characters long, and can't start or end with \"-\" and can't start with digit"); + } + } + @DB @ActionEvent(eventType = EventTypes.EVENT_VM_CREATE, eventDescription = "deploying Vm", create = true) protected UserVm createVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, String hostName, String displayName, Account owner, Long diskOfferingId, Long diskSize, List networkList, List securityGroupIdList, String group, String userData, String sshKeyPair, HypervisorType hypervisor, Account caller, Map requestedIps, IpAddresses defaultIps, String keyboard) @@ -2300,8 +2322,23 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use long id = _vmDao.getNextInSequence(Long.class, "id"); - String instanceName = VirtualMachineName.getVmName(id, owner.getId(), - _instance); + String instanceName; + if (_instanceNameFlag && displayName != null) { + // Check if the displayName conforms to RFC standards. + checkNameForRFCCompliance(displayName); + instanceName = VirtualMachineName.getVmName(id, owner.getId(), displayName); + if (instanceName.length() > MAX_VM_NAME_LEN) { + throw new InvalidParameterValueException("Specified display name " + displayName + " causes VM name to exceed 80 characters in length"); + } + // Search whether there is already an instance with the same instance name + // that is not in the destroyed or expunging state. + VMInstanceVO vm = _vmInstanceDao.findVMByInstanceName(instanceName); + if (vm != null && vm.getState() != VirtualMachine.State.Expunging) { + throw new InvalidParameterValueException("There already exists a VM by the display name supplied"); + } + } else { + instanceName = VirtualMachineName.getVmName(id, owner.getId(), _instance); + } String uuidName = UUID.randomUUID().toString(); @@ -2309,12 +2346,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use if (hostName == null) { hostName = uuidName; } else { - // 1) check is hostName is RFC complient - if (!NetUtils.verifyDomainNameLabel(hostName, true)) { - throw new InvalidParameterValueException( - "Invalid name. Vm name can contain ASCII letters 'a' through 'z', the digits '0' through '9', " - + "and the hyphen ('-'), must be between 1 and 63 characters long, and can't start or end with \"-\" and can't start with digit"); - } + //1) check is hostName is RFC compliant + checkNameForRFCCompliance(hostName); // 2) hostName has to be unique in the network domain Map> ntwkDomains = new HashMap>(); for (NetworkVO network : networkList) { diff --git a/server/src/com/cloud/vm/dao/UserVmDao.java b/server/src/com/cloud/vm/dao/UserVmDao.java index 9fbcde377dd..81d13cda2ed 100755 --- a/server/src/com/cloud/vm/dao/UserVmDao.java +++ b/server/src/com/cloud/vm/dao/UserVmDao.java @@ -70,5 +70,7 @@ public interface UserVmDao extends GenericDao { public Long countAllocatedVMsForAccount(long accountId); Hashtable listVmDetails(Hashtable userVmData); + + List listByIsoId(Long isoId); } diff --git a/server/src/com/cloud/vm/dao/UserVmDaoImpl.java b/server/src/com/cloud/vm/dao/UserVmDaoImpl.java index f2fc10bbaa4..02604fe767b 100755 --- a/server/src/com/cloud/vm/dao/UserVmDaoImpl.java +++ b/server/src/com/cloud/vm/dao/UserVmDaoImpl.java @@ -72,10 +72,11 @@ public class UserVmDaoImpl extends GenericDaoBase implements Use protected SearchBuilder DestroySearch; protected SearchBuilder AccountDataCenterVirtualSearch; protected GenericSearchBuilder CountByAccountPod; - protected GenericSearchBuilder CountByAccount; - protected GenericSearchBuilder PodsHavingVmsForAccount; - - protected SearchBuilder UserVmSearch; + protected GenericSearchBuilder CountByAccount; + protected GenericSearchBuilder PodsHavingVmsForAccount; + + protected SearchBuilder UserVmSearch; + protected SearchBuilder UserVmByIsoSearch; protected Attribute _updateTimeAttr; // ResourceTagsDaoImpl _tagsDao = ComponentLocator.inject(ResourceTagsDaoImpl.class); @Inject ResourceTagsDaoImpl _tagsDao; @@ -194,7 +195,10 @@ public class UserVmDaoImpl extends GenericDaoBase implements Use AccountDataCenterVirtualSearch.and("dc", AccountDataCenterVirtualSearch.entity().getDataCenterId(), SearchCriteria.Op.EQ); AccountDataCenterVirtualSearch.join("nicSearch", nicSearch, AccountDataCenterVirtualSearch.entity().getId(), nicSearch.entity().getInstanceId(), JoinBuilder.JoinType.INNER); AccountDataCenterVirtualSearch.done(); - + + UserVmByIsoSearch = createSearchBuilder(); + UserVmByIsoSearch.and("isoId", UserVmByIsoSearch.entity().getIsoId(), SearchCriteria.Op.EQ); + UserVmByIsoSearch.done(); _updateTimeAttr = _allAttributes.get("updateTime"); assert _updateTimeAttr != null : "Couldn't get this updateTime attribute"; @@ -248,13 +252,20 @@ public class UserVmDaoImpl extends GenericDaoBase implements Use public List listByHostId(Long id) { SearchCriteria sc = HostSearch.create(); sc.setParameters("host", id); - - return listBy(sc); - } - - @Override - public List listUpByHostId(Long hostId) { - SearchCriteria sc = HostUpSearch.create(); + + return listBy(sc); + } + + @Override + public List listByIsoId(Long isoId) { + SearchCriteria sc = UserVmByIsoSearch.create(); + sc.setParameters("isoId", isoId); + return listBy(sc); + } + + @Override + public List listUpByHostId(Long hostId) { + SearchCriteria sc = HostUpSearch.create(); sc.setParameters("host", hostId); sc.setParameters("states", new Object[] {State.Destroyed, State.Stopped, State.Expunging}); return listBy(sc); diff --git a/server/src/com/cloud/vm/dao/VMInstanceDao.java b/server/src/com/cloud/vm/dao/VMInstanceDao.java index d34b25726dc..c604027abde 100644 --- a/server/src/com/cloud/vm/dao/VMInstanceDao.java +++ b/server/src/com/cloud/vm/dao/VMInstanceDao.java @@ -26,7 +26,6 @@ import com.cloud.utils.fsm.StateDao; import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.State; -import com.cloud.vm.VirtualMachine.Type; /* @@ -75,6 +74,8 @@ public interface VMInstanceDao extends GenericDao, StateDao< VMInstanceVO findByIdTypes(long id, VirtualMachine.Type... types); + VMInstanceVO findVMByInstanceName(String name); + void updateProxyId(long id, Long proxyId, Date time); List listByHostIdTypes(long hostid, VirtualMachine.Type... types); diff --git a/server/src/com/cloud/vm/dao/VMInstanceDaoImpl.java b/server/src/com/cloud/vm/dao/VMInstanceDaoImpl.java index 531c79447b7..7198b7c24e0 100644 --- a/server/src/com/cloud/vm/dao/VMInstanceDaoImpl.java +++ b/server/src/com/cloud/vm/dao/VMInstanceDaoImpl.java @@ -35,12 +35,9 @@ import org.springframework.stereotype.Component; import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; -import com.cloud.host.dao.HostDaoImpl; import com.cloud.server.ResourceTag.TaggedResourceType; import com.cloud.tags.dao.ResourceTagDao; -import com.cloud.tags.dao.ResourceTagsDaoImpl; import com.cloud.utils.Pair; - import com.cloud.utils.db.Attribute; import com.cloud.utils.db.DB; import com.cloud.utils.db.GenericDaoBase; @@ -80,6 +77,7 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem protected SearchBuilder HostIdTypesSearch; protected SearchBuilder HostIdUpTypesSearch; protected SearchBuilder HostUpSearch; + protected SearchBuilder InstanceNameSearch; protected GenericSearchBuilder CountVirtualRoutersByAccount; protected GenericSearchBuilder CountRunningByHost; protected GenericSearchBuilder CountRunningByAccount; @@ -188,6 +186,10 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem HostUpSearch.and("states", HostUpSearch.entity().getState(), Op.IN); HostUpSearch.done(); + InstanceNameSearch = createSearchBuilder(); + InstanceNameSearch.and("instanceName", InstanceNameSearch.entity().getInstanceName(), Op.EQ); + InstanceNameSearch.done(); + CountVirtualRoutersByAccount = createSearchBuilder(Long.class); CountVirtualRoutersByAccount.select(null, Func.COUNT, null); CountVirtualRoutersByAccount.and("account", CountVirtualRoutersByAccount.entity().getAccountId(), SearchCriteria.Op.EQ); @@ -340,6 +342,12 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem return findOneIncludingRemovedBy(sc); } + @Override + public VMInstanceVO findVMByInstanceName(String name) { + SearchCriteria sc = InstanceNameSearch.create(); + sc.setParameters("instanceName", name); + return findOneBy(sc); + } @Override public void updateProxyId(long id, Long proxyId, Date time) { diff --git a/server/test/com/cloud/vpc/MockVpcManagerImpl.java b/server/test/com/cloud/vpc/MockVpcManagerImpl.java index b0a89ee88bc..e6c65200ded 100644 --- a/server/test/com/cloud/vpc/MockVpcManagerImpl.java +++ b/server/test/com/cloud/vpc/MockVpcManagerImpl.java @@ -72,12 +72,8 @@ public class MockVpcManagerImpl extends ManagerBase implements VpcManager { return null; } - /* (non-Javadoc) - * @see com.cloud.network.vpc.VpcService#createVpcOffering(java.lang.String, java.lang.String, java.util.List) - */ @Override - public VpcOffering createVpcOffering(String name, String displayText, List supportedServices) { - // TODO Auto-generated method stub + public VpcOffering createVpcOffering(String name, String displayText, List supportedServices, Map> serviceProviders) { return null; } @@ -357,12 +353,8 @@ public class MockVpcManagerImpl extends ManagerBase implements VpcManager { return null; } - /* (non-Javadoc) - * @see com.cloud.network.vpc.VpcManager#vpcProviderEnabledInZone(long) - */ @Override - public boolean vpcProviderEnabledInZone(long zoneId) { - // TODO Auto-generated method stub + public boolean vpcProviderEnabledInZone(long zoneId, String provider) { return false; } diff --git a/server/test/com/cloud/vpc/dao/MockVpcDaoImpl.java b/server/test/com/cloud/vpc/dao/MockVpcDaoImpl.java index 99bdb58e4f7..562d67dc207 100644 --- a/server/test/com/cloud/vpc/dao/MockVpcDaoImpl.java +++ b/server/test/com/cloud/vpc/dao/MockVpcDaoImpl.java @@ -18,6 +18,7 @@ package com.cloud.vpc.dao; import java.lang.reflect.Field; import java.util.List; +import java.util.Map; import javax.ejb.Local; @@ -83,7 +84,17 @@ public class MockVpcDaoImpl extends GenericDaoBase implements VpcDa // TODO Auto-generated method stub return 0; } - + + @Override + public VpcVO persist(VpcVO vpc, Map serviceProviderMap) { + return null; + } + + @Override + public void persistVpcServiceProviders(long vpcId, Map serviceProviderMap) { + return; + } + @Override public VpcVO findById(Long id) { VpcVO vo = null; diff --git a/setup/db/db/schema-410to420.sql b/setup/db/db/schema-410to420.sql index 4637b6df951..be8e7f543a0 100644 --- a/setup/db/db/schema-410to420.sql +++ b/setup/db/db/schema-410to420.sql @@ -26,6 +26,7 @@ UPDATE `cloud`.`hypervisor_capabilities` SET `max_hosts_per_cluster`=32 WHERE `h INSERT IGNORE INTO `cloud`.`hypervisor_capabilities`(hypervisor_type, hypervisor_version, max_guests_limit, security_group_enabled, max_hosts_per_cluster) VALUES ('VMware', '5.1', 128, 0, 32); DELETE FROM `cloud`.`configuration` where name='vmware.percluster.host.max'; INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'AgentManager', 'xen.nics.max', '7', 'Maximum allowed nics for Vms created on Xen'); + alter table template_host_ref add state varchar(255); alter table template_host_ref add update_count bigint unsigned; alter table template_host_ref add updated datetime; @@ -83,5 +84,19 @@ ALTER TABLE `cloud`.`service_offering` ADD COLUMN `is_volatile` tinyint(1) unsig ALTER TABLE `cloud`.`networks` ADD COLUMN `network_cidr` VARCHAR(18) COMMENT 'The network cidr for the isolated guest network which uses IP Reservation facility.For networks not using IP reservation, network_cidr is always null.'; ALTER TABLE `cloud`.`networks` CHANGE `cidr` `cidr` varchar(18) COMMENT 'CloudStack managed vms get IP address from cidr.In general this cidr also serves as the network CIDR. But in case IP reservation feature is being used by a Guest network, networkcidr is the Effective network CIDR for that network'; + +CREATE TABLE `vpc_service_map` ( + `id` bigint unsigned NOT NULL auto_increment, + `vpc_id` bigint unsigned NOT NULL COMMENT 'vpc_id', + `service` varchar(255) NOT NULL COMMENT 'service', + `provider` varchar(255) COMMENT 'service provider', + `created` datetime COMMENT 'date created', + PRIMARY KEY (`id`), + CONSTRAINT `fk_vpc_service_map__vpc_id` FOREIGN KEY(`vpc_id`) REFERENCES `vpc`(`id`) ON DELETE CASCADE, + UNIQUE (`vpc_id`, `service`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + + SET foreign_key_checks = 1; +INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', 'vm.instancename.flag', 'false', 'Append guest VM display Name (if set) to the internal name of the VM'); diff --git a/test/integration/smoke/test_vm_life_cycle.py b/test/integration/smoke/test_vm_life_cycle.py index 3596ca244ba..8d65c00c896 100644 --- a/test/integration/smoke/test_vm_life_cycle.py +++ b/test/integration/smoke/test_vm_life_cycle.py @@ -854,9 +854,6 @@ class TestVMLifeCycle(cloudstackTestCase): ) expunge_delay = int(config[0].value) - if expunge_delay < 600: - expunge_delay = 600 - # Wait for some time more than expunge.delay time.sleep(expunge_delay * 2) #VM should be destroyed unless expunge thread hasn't run @@ -866,9 +863,6 @@ class TestVMLifeCycle(cloudstackTestCase): name='expunge.interval' ) expunge_cycle = int(config[0].value) - if expunge_cycle < 600: - expunge_cycle = 600 - wait_time = expunge_cycle * 2 while wait_time >= 0: list_vm_response = list_virtual_machines( diff --git a/utils/src/com/cloud/utils/script/Script.java b/utils/src/com/cloud/utils/script/Script.java index 1e5aab45408..cb258449e43 100755 --- a/utils/src/com/cloud/utils/script/Script.java +++ b/utils/src/com/cloud/utils/script/Script.java @@ -449,6 +449,12 @@ public class Script implements Callable { } } + + file = new File(System.getProperty("paths.script") + File.separator + path + File.separator + script); + if (file.exists()) { + return file.getAbsolutePath(); + } + s_logger.warn("Unable to find script " + script); return null; }