diff --git a/api/src/com/cloud/network/NetworkService.java b/api/src/com/cloud/network/NetworkService.java index 489bc6cebf0..250121e452b 100755 --- a/api/src/com/cloud/network/NetworkService.java +++ b/api/src/com/cloud/network/NetworkService.java @@ -64,7 +64,7 @@ public interface NetworkService { Pair, Integer> searchForNetworks(ListNetworksCmd cmd); - boolean deleteNetwork(long networkId); + boolean deleteNetwork(long networkId, boolean forced); boolean restartNetwork(RestartNetworkCmd cmd, boolean cleanup) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException; diff --git a/api/src/org/apache/cloudstack/api/command/user/network/DeleteNetworkCmd.java b/api/src/org/apache/cloudstack/api/command/user/network/DeleteNetworkCmd.java index a48e01b0d36..808051ecdef 100644 --- a/api/src/org/apache/cloudstack/api/command/user/network/DeleteNetworkCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/network/DeleteNetworkCmd.java @@ -45,6 +45,10 @@ public class DeleteNetworkCmd extends BaseAsyncCmd { @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = NetworkResponse.class, required = true, description = "the ID of the network") private Long id; + @Parameter(name = ApiConstants.FORCED, type = CommandType.BOOLEAN, required = false, description = "Force delete a network." + + " Network will be marked as 'Destroy' even when commands to shutdown and cleanup to the backend fails.") + private Boolean forced; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -53,6 +57,10 @@ public class DeleteNetworkCmd extends BaseAsyncCmd { return id; } + public boolean isForced() { + return (forced != null) ? forced : false; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// @@ -65,7 +73,7 @@ public class DeleteNetworkCmd extends BaseAsyncCmd { @Override public void execute() { CallContext.current().setEventDetails("Network Id: " + id); - boolean result = _networkService.deleteNetwork(id); + boolean result = _networkService.deleteNetwork(id, isForced()); if (result) { SuccessResponse response = new SuccessResponse(getCommandName()); this.setResponseObject(response); diff --git a/awsapi/pom.xml b/awsapi/pom.xml index 3c2bbe16399..f0312309b98 100644 --- a/awsapi/pom.xml +++ b/awsapi/pom.xml @@ -418,49 +418,6 @@ - diff --git a/client/pom.xml b/client/pom.xml index abbc25dbcbf..5215e0cd90e 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -562,36 +562,6 @@ - - - - - org.eclipse.m2e - lifecycle-mapping - 1.0.0 - - - - - - org.apache.maven.plugins - maven-antrun-plugin - [1.7,) - - run - - - - - - - - - - - - diff --git a/engine/api/src/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java b/engine/api/src/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java index c036c99b63d..a50c184a5e0 100755 --- a/engine/api/src/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java +++ b/engine/api/src/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java @@ -125,7 +125,7 @@ public interface NetworkOrchestrationService { boolean shutdownNetwork(long networkId, ReservationContext context, boolean cleanupElements); - boolean destroyNetwork(long networkId, ReservationContext context); + boolean destroyNetwork(long networkId, ReservationContext context, boolean forced); Network createGuestNetwork(long networkOfferingId, String name, String displayText, String gateway, String cidr, String vlanId, String networkDomain, Account owner, Long domainId, PhysicalNetwork physicalNetwork, long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, String ip6Gateway, String ip6Cidr, diff --git a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java index 7bf784110e3..85fa530e820 100755 --- a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java +++ b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java @@ -2068,7 +2068,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra @Override @DB - public boolean destroyNetwork(long networkId, final ReservationContext context) { + public boolean destroyNetwork(long networkId, final ReservationContext context, boolean forced) { final Account callerAccount = context.getAccount(); NetworkVO network = _networksDao.findById(networkId); @@ -2111,7 +2111,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra // get updated state for the network network = _networksDao.findById(networkId); - if (network.getState() != Network.State.Allocated && network.getState() != Network.State.Setup) { + if (network.getState() != Network.State.Allocated && network.getState() != Network.State.Setup && !forced) { s_logger.debug("Network is not not in the correct state to be destroyed: " + network.getState()); return false; } diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareContextFactory.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareContextFactory.java index cdd0c29c9fe..11163e90d6f 100755 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareContextFactory.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareContextFactory.java @@ -89,7 +89,7 @@ public class VmwareContextFactory { } else { // Validate current context and verify if vCenter session timeout value of the context matches the timeout value set by Admin if (!context.validate() || (context.getVimClient().getVcenterSessionTimeout() != s_vmwareMgr.getVcenterSessionTimeout())) { - s_logger.info("Validation of the context faild. dispose and create a new one"); + s_logger.info("Validation of the context failed, dispose and create a new one"); context.close(); context = create(vCenterAddress, vCenterUserName, vCenterPassword); } diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java index 4aa6f27991a..8b252763e78 100755 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -6896,10 +6896,16 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa @Override public VmwareContext getServiceContext(Command cmd) { - if (s_serviceContext.get() != null) - return s_serviceContext.get(); - VmwareContext context = null; + if(s_serviceContext.get() != null) { + context = s_serviceContext.get(); + if (context.validate()) { + return context; + } else { + s_logger.info("Validation of the context failed, dispose and use a new one"); + invalidateServiceContext(context); + } + } try { context = VmwareContextFactory.getContext(_vCenterAddress, _username, _password); s_serviceContext.set(context); diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java index c91d7b6f2cd..7e08aeceac9 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java @@ -214,18 +214,23 @@ public class VmwareSecondaryStorageResourceHandler implements SecondaryStorageRe _resource.ensureOutgoingRuleForAddress(vCenterAddress); VmwareContext context = currentContext.get(); - if (context == null) { + if (context != null) { + if(!context.validate()) { + invalidateServiceContext(context); + context = null; + } else { + context.registerStockObject("serviceconsole", cmd.getContextParam("serviceconsole")); + context.registerStockObject("manageportgroup", cmd.getContextParam("manageportgroup")); + context.registerStockObject("noderuninfo", cmd.getContextParam("noderuninfo")); + } + } + if(context == null) { s_logger.info("Open new VmwareContext. vCenter: " + vCenterAddress + ", user: " + username + ", password: " + - StringUtils.getMaskedPasswordForDisplay(password)); + StringUtils.getMaskedPasswordForDisplay(password)); VmwareSecondaryStorageContextFactory.setVcenterSessionTimeout(vCenterSessionTimeout); context = VmwareSecondaryStorageContextFactory.getContext(vCenterAddress, username, password); } - if (context != null) { - context.registerStockObject("serviceconsole", cmd.getContextParam("serviceconsole")); - context.registerStockObject("manageportgroup", cmd.getContextParam("manageportgroup")); - context.registerStockObject("noderuninfo", cmd.getContextParam("noderuninfo")); - } currentContext.set(context); return context; } catch (Exception e) { diff --git a/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/NetworkProviderTest.java b/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/NetworkProviderTest.java index fff4e5a1395..6996a287302 100644 --- a/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/NetworkProviderTest.java +++ b/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/NetworkProviderTest.java @@ -179,7 +179,7 @@ public class NetworkProviderTest extends TestCase { List list = _networkService.getIsolatedNetworksOwnedByAccountInZone(zone.getId(), system); for (Network net : list) { s_logger.debug("Delete network " + net.getName()); - _networkService.deleteNetwork(net.getId()); + _networkService.deleteNetwork(net.getId(), false); } } diff --git a/plugins/user-authenticators/ldap/pom.xml b/plugins/user-authenticators/ldap/pom.xml index dc4e1725029..46eec81b946 100644 --- a/plugins/user-authenticators/ldap/pom.xml +++ b/plugins/user-authenticators/ldap/pom.xml @@ -90,39 +90,6 @@ - - - - org.eclipse.m2e - lifecycle-mapping - 1.0.0 - - - - - - - org.codehaus.gmaven - - - gmaven-plugin - - [1.3,) - - compile - testCompile - - - - - - - - - - - - diff --git a/pom.xml b/pom.xml index 3f65bdd05ad..c661d31da6e 100644 --- a/pom.xml +++ b/pom.xml @@ -560,6 +560,33 @@ + + + com.mycila.maven-license-plugin + maven-license-plugin + [1.9.0,) + + format + + + + + + + + + org.codehaus.gmaven + gmaven-plugin + [1.3,) + + compile + testCompile + + + + + + diff --git a/server/src/com/cloud/api/ApiServer.java b/server/src/com/cloud/api/ApiServer.java index 03361a4a999..3fb3495f7ae 100755 --- a/server/src/com/cloud/api/ApiServer.java +++ b/server/src/com/cloud/api/ApiServer.java @@ -760,7 +760,11 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer @Override public Long fetchDomainId(String domainUUID) { - return _domainMgr.getDomain(domainUUID).getId(); + Domain domain = _domainMgr.getDomain(domainUUID); + if (domain != null) + return domain.getId(); + else + return null; } @Override diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java index fb6f3fd451a..056190f1c4a 100755 --- a/server/src/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/com/cloud/network/NetworkServiceImpl.java @@ -1762,7 +1762,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { @Override @ActionEvent(eventType = EventTypes.EVENT_NETWORK_DELETE, eventDescription = "deleting network", async = true) - public boolean deleteNetwork(long networkId) { + public boolean deleteNetwork(long networkId, boolean forced) { Account caller = CallContext.current().getCallingAccount(); @@ -1788,10 +1788,14 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { // Perform permission check _accountMgr.checkAccess(caller, null, true, network); + if (forced && !_accountMgr.isRootAdmin(caller.getType())) { + throw new InvalidParameterValueException("Delete network with 'forced' option can only be called by root admins"); + } + User callerUser = _accountMgr.getActiveUser(CallContext.current().getCallingUserId()); ReservationContext context = new ReservationContextImpl(null, null, callerUser, owner); - return _networkMgr.destroyNetwork(networkId, context); + return _networkMgr.destroyNetwork(networkId, context, forced); } @Override diff --git a/server/src/com/cloud/network/vpc/VpcManagerImpl.java b/server/src/com/cloud/network/vpc/VpcManagerImpl.java index 30751895e51..2face90a7a4 100644 --- a/server/src/com/cloud/network/vpc/VpcManagerImpl.java +++ b/server/src/com/cloud/network/vpc/VpcManagerImpl.java @@ -1565,7 +1565,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis User callerUser = _accountMgr.getActiveUser(CallContext.current().getCallingUserId()); Account owner = _accountMgr.getAccount(Account.ACCOUNT_ID_SYSTEM); ReservationContext context = new ReservationContextImpl(null, null, callerUser, owner); - _ntwkMgr.destroyNetwork(networkId, context); + _ntwkMgr.destroyNetwork(networkId, context, false); s_logger.debug("Deleted private network id=" + networkId); } diff --git a/server/src/com/cloud/user/AccountManagerImpl.java b/server/src/com/cloud/user/AccountManagerImpl.java index 20a6242cfd6..52045897619 100755 --- a/server/src/com/cloud/user/AccountManagerImpl.java +++ b/server/src/com/cloud/user/AccountManagerImpl.java @@ -679,7 +679,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M ReservationContext context = new ReservationContextImpl(null, null, getActiveUser(callerUserId), caller); - if (!_networkMgr.destroyNetwork(network.getId(), context)) { + if (!_networkMgr.destroyNetwork(network.getId(), context, false)) { s_logger.warn("Unable to destroy network " + network + " as a part of account id=" + accountId + " cleanup."); accountCleanupNeeded = true; networksDeleted = false; diff --git a/server/src/com/cloud/user/DomainManagerImpl.java b/server/src/com/cloud/user/DomainManagerImpl.java index 89a918ee68e..b2a478ef096 100644 --- a/server/src/com/cloud/user/DomainManagerImpl.java +++ b/server/src/com/cloud/user/DomainManagerImpl.java @@ -395,8 +395,7 @@ public class DomainManagerImpl extends ManagerBase implements DomainManager, Dom ReservationContext context = new ReservationContextImpl(null, null, _accountMgr.getActiveUser(ctx.getCallingUserId()), ctx.getCallingAccount()); for (Long networkId : networkIds) { s_logger.debug("Deleting network id=" + networkId + " as a part of domain id=" + domainId + " cleanup"); - - if (!_networkMgr.destroyNetwork(networkId, context)) { + if (!_networkMgr.destroyNetwork(networkId, context, false)) { s_logger.warn("Unable to destroy network id=" + networkId + " as a part of domain id=" + domainId + " cleanup."); networksDeleted = false; } else { diff --git a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java index be305dee0f4..846e2f58d8e 100644 --- a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java +++ b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java @@ -203,7 +203,7 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkOrches * @see com.cloud.network.NetworkService#deleteNetwork(long) */ @Override - public boolean deleteNetwork(long networkId) { + public boolean deleteNetwork(long networkId, boolean forced) { // TODO Auto-generated method stub return false; } @@ -597,7 +597,7 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkOrches * @see com.cloud.network.NetworkManager#destroyNetwork(long, com.cloud.vm.ReservationContext) */ @Override - public boolean destroyNetwork(long networkId, ReservationContext context) { + public boolean destroyNetwork(long networkId, ReservationContext context, boolean forced) { // TODO Auto-generated method stub return false; } diff --git a/test/integration/component/test_advancedsg_networks.py b/test/integration/component/test_advancedsg_networks.py index 7f3a39021a9..207659f1efd 100644 --- a/test/integration/component/test_advancedsg_networks.py +++ b/test/integration/component/test_advancedsg_networks.py @@ -28,7 +28,8 @@ from marvin.integration.lib.base import (Zone, Domain, VpcOffering, VPC, - SecurityGroup) + SecurityGroup, + Host) from marvin.integration.lib.common import (get_domain, get_zone, @@ -41,10 +42,12 @@ from marvin.integration.lib.utils import (cleanup_resources, random_gen, validateList) from marvin.cloudstackAPI import (authorizeSecurityGroupIngress, - revokeSecurityGroupIngress) + revokeSecurityGroupIngress, + deleteSecurityGroup) from nose.plugins.attrib import attr from marvin.codes import PASS import time +import sys import random class TestCreateZoneSG(cloudstackTestCase): @@ -532,11 +535,11 @@ class TestNetworksInAdvancedSG(cloudstackTestCase): # Steps, # 1. create a Domain and subdomain # 2. Create one shared Network in parent domain with SG and set subdomain access True - # 3. Deploy a VM in subdomain using the shared network + # 3. Deploy a VM in subdomain using the shared network # Validations, # 1. shared network should be created successfully - # 2. Shared network should be able to be accessed within subdomain (VM should be deployed) + # 2. Shared network should be able to be accessed within subdomain (VM should be deployed) #Create Domain self.debug("Creating parent domain") @@ -851,6 +854,53 @@ class TestNetworksInAdvancedSG(cloudstackTestCase): return + @attr(tags = ["advancedsg"]) + def test_29_deleteSharedNwSG_ZoneWide_InUse(self): + """ Test delete Zone wide shared network with SG which is in use""" + + # Steps, + # 1. create zone wide shared network + # 2. Deploy vm in the shared network + # 3. Try to delete the shared network while its still in use + + # Validations, + # 1. shared network deletion should fail + + physical_network, vlan = get_free_vlan(self.api_client, self.zone.id) + + #create network using the shared network offering created + self.services["shared_network_sg"]["acltype"] = "domain" + self.services["shared_network_sg"]["vlan"] = vlan + self.services["shared_network_sg"]["networkofferingid"] = self.shared_network_offering_sg.id + self.services["shared_network_sg"]["physicalnetworkid"] = physical_network.id + + self.setSharedNetworkParams("shared_network_sg") + + self.debug("Creating shared network in zone: %s" % self.zone.id) + shared_network_sg = Network.create(self.api_client,self.services["shared_network_sg"], + networkofferingid=self.shared_network_offering_sg.id, + zoneid=self.zone.id) + + self.debug("Created shared network: %s" % shared_network_sg.id) + + self.debug("Deploying vm in the shared network: %s" % shared_network_sg.id) + + vm = VirtualMachine.create(self.api_client,self.services["virtual_machine"], + networkids=[shared_network_sg.id,],serviceofferingid=self.service_offering.id) + self.debug("Created vm %s" % vm.id) + + self.debug("Trying to delete shared network: %s" % shared_network_sg.id) + + try: + shared_network_sg.delete(self.api_client) + self.fail("Exception not raised while deleting network") + except Exception as e: + self.debug("Network deletion failed with exception: %s" % e) + + self.cleanup_networks.append(shared_network_sg) + self.cleanup_vms.append(vm) + return + @attr(tags = ["advancedsg"]) def test_12_deleteSharedNwSGAccountSpecific_NotInUse(self): """ Test delete Account specific shared network creation with SG which is not in use""" @@ -937,6 +987,43 @@ class TestNetworksInAdvancedSG(cloudstackTestCase): return + @attr(tags = ["advancedsg"]) + def test_30_deleteSharedNwSG_ZoneWide_NotInUse(self): + """ Test delete zone wide shared network with SG which is not in use""" + + # Steps, + # 1. create a zone wide shared network with SG + # 2. Try to delete the shared network + + # Validations, + # 1. shared network deletion should succeed + + physical_network, vlan = get_free_vlan(self.api_client, self.zone.id) + + #create network using the shared network offering created + self.services["shared_network_sg"]["acltype"] = "domain" + self.services["shared_network_sg"]["vlan"] = vlan + self.services["shared_network_sg"]["networkofferingid"] = self.shared_network_offering_sg.id + self.services["shared_network_sg"]["physicalnetworkid"] = physical_network.id + + self.setSharedNetworkParams("shared_network_sg") + + self.debug("Creating shared network in zone: %s" % self.zone.id) + shared_network_sg = Network.create(self.api_client,self.services["shared_network_sg"], + networkofferingid=self.shared_network_offering_sg.id, + zoneid=self.zone.id) + + self.debug("Created shared network: %s" % shared_network_sg.id) + + self.debug("Trying to delete shared network: %s" % shared_network_sg.id) + + try: + shared_network_sg.delete(self.api_client) + except Exception as e: + self.fail("Network deletion failed with exception: %s" % e) + + return + @attr(tags = ["advancedsg"]) def test__14_createSharedNwWithSG_withoutParams(self): """ Test create shared network with SG without specifying necessary parameters""" @@ -1126,7 +1213,7 @@ class TestNetworksInAdvancedSG_VmOperations(cloudstackTestCase): exceptions.append(e) if len(exceptions) > 0: - self.faill("There were exceptions during cleanup: %s" % exceptions) + self.fail("There were exceptions during cleanup: %s" % exceptions) return @@ -1145,6 +1232,29 @@ class TestNetworksInAdvancedSG_VmOperations(cloudstackTestCase): return + def setVmState(self, vm, state): + """ set VM state and verify if it is reflected correctly + Currently takes 2 states - running and stopped""" + + if state=="running": + vm.start(self.api_client) + elif state=="stopped": + vm.stop(self.api_client) + else: + self.fail("Invalid state passed") + retriesCount = 5 + while True: + vm_list = list_virtual_machines(self.api_client, id=vm.id) + self.assertEqual(validateList(vm_list)[0], PASS, "vm list validation failed, vm list is %s" % vm_list) + if vm_list[0].state.lower() == state: + break + if retriesCount == 0: + self.fail("Failed to set VM state as %s" % state) + retriesCount -= 1 + time.sleep(10) + + return + @attr(tags = ["advancedsg"]) def test__16_AccountSpecificNwAccess(self): """ Test account specific network access of users""" @@ -1152,7 +1262,7 @@ class TestNetworksInAdvancedSG_VmOperations(cloudstackTestCase): # Steps, # 1. create multiple accounts/users and their account specific SG enabled shared networks # 2. Deploy VM in the account specific network with user of that account - # 3. Try to deploy VM in one account specific network from other account user + # 3. Try to deploy VM in one account specific network from other account user # Validations, # 1. VM deployment should be allowed for the users of the same account only for their account @@ -1511,6 +1621,467 @@ class TestNetworksInAdvancedSG_VmOperations(cloudstackTestCase): return + @attr(tags = ["advancedsg"]) + def test_24_DeployVM_Multiple_Shared_Networks(self): + """ Test deploy VM in multiple zone wide shared networks""" + + # Steps, + # 1. Create multiple zone wide shared networks + # 2. Try to deploy VM using all these networks + + # Validations, + # 1. VM deployment should fail saying "error 431 Only support one zone wide network per VM if security group enabled" + + self.services["shared_network_sg"]["acltype"] = "domain" + self.services["shared_network_sg"]["networkofferingid"] = self.shared_network_offering_sg.id + + physical_network, vlan = get_free_vlan(self.api_client, self.zone.id) + + #create network using the shared network offering created + self.services["shared_network_sg"]["vlan"] = vlan + self.services["shared_network_sg"]["physicalnetworkid"] = physical_network.id + + self.setSharedNetworkParams("shared_network_sg") + + shared_network_1 = Network.create(self.api_client,self.services["shared_network_sg"], + networkofferingid=self.shared_network_offering_sg.id,zoneid=self.zone.id) + self.cleanup_networks.append(shared_network_1) + self.debug("Created shared network: %s" % shared_network_1.id) + + self.services["shared_network_sg"]["vlan"] = get_free_vlan(self.api_client, self.zone.id)[1] + self.setSharedNetworkParams("shared_network_sg") + + shared_network_2 = Network.create(self.api_client,self.services["shared_network_sg"], + networkofferingid=self.shared_network_offering_sg.id,zoneid=self.zone.id) + self.cleanup_networks.append(shared_network_2) + self.debug("Created shared network: %s" % shared_network_2.id) + + try: + self.debug("Creating virtual machine in zone wide shared networks %s and %s, this should fail" % + (shared_network_1.id, shared_network_2.id)) + vm = VirtualMachine.create(self.api_client,self.services["virtual_machine"], + templateid=self.template.id, networkids=[shared_network_1.id, shared_network_2.id], + serviceofferingid=self.service_offering.id) + self.cleanup_vms.append(vm) + self.fail("Vm creation should have failed, it succeded, created vm %s" % vm.id) + except Exception as e: + self.debug("VM creation failed as expected with exception: %s" % e) + + return + + @attr(tags = ["advancedsg"]) + def test_25_Deploy_Multiple_VM_Different_Shared_Networks_Same_SG(self): + """ Test deploy Multiple VMs in different shared networks but same security group""" + + # Steps, + # 1. Create multiple zone wide shared networks + # 2. Create a custom security group + # 3. Deploy Multiple VMs in different shared networks but using the same custom + # security group + + # Validations, + # 1. VM deployments should succeed + + self.services["shared_network_sg"]["acltype"] = "domain" + self.services["shared_network_sg"]["networkofferingid"] = self.shared_network_offering_sg.id + + physical_network, vlan = get_free_vlan(self.api_client, self.zone.id) + + #create network using the shared network offering created + self.services["shared_network_sg"]["vlan"] = vlan + self.services["shared_network_sg"]["physicalnetworkid"] = physical_network.id + + self.setSharedNetworkParams("shared_network_sg") + + shared_network_1 = Network.create(self.api_client,self.services["shared_network_sg"], + networkofferingid=self.shared_network_offering_sg.id,zoneid=self.zone.id) + self.cleanup_networks.append(shared_network_1) + self.debug("Created shared network: %s" % shared_network_1.id) + + self.services["shared_network_sg"]["vlan"] = get_free_vlan(self.api_client, self.zone.id)[1] + self.setSharedNetworkParams("shared_network_sg") + + shared_network_2 = Network.create(self.api_client,self.services["shared_network_sg"], + networkofferingid=self.shared_network_offering_sg.id,zoneid=self.zone.id) + self.cleanup_networks.append(shared_network_2) + self.debug("Created shared network: %s" % shared_network_2.id) + + self.services["security_group"]["name"] = "Custom_sec_grp_" + random_gen() + sec_grp_1 = SecurityGroup.create(self.api_client,self.services["security_group"]) + self.debug("Created security groups: %s" % sec_grp_1.id) + self.cleanup_secGrps.append(sec_grp_1) + + self.debug("Creating virtual machine in shared network %s and security group %s" % + (shared_network_1.id, sec_grp_1.id)) + vm_1 = VirtualMachine.create(self.api_client,self.services["virtual_machine"], + templateid=self.template.id, networkids=[shared_network_1.id], + serviceofferingid=self.service_offering.id, + securitygroupids=[sec_grp_1.id]) + self.cleanup_vms.append(vm_1) + + self.debug("Creating virtual machine in shared network %s and security group %s" % + (shared_network_2.id, sec_grp_1.id)) + vm_2 = VirtualMachine.create(self.api_client,self.services["virtual_machine"], + templateid=self.template.id, networkids=[shared_network_2.id], + serviceofferingid=self.service_offering.id, + securitygroupids=[sec_grp_1.id]) + self.cleanup_vms.append(vm_2) + + vm_list = list_virtual_machines(self.api_client, listall=True) + + self.assertEqual(validateList(vm_list)[0], PASS, "vm list validation failed, vm list is %s" % vm_list) + + vm_ids = [vm.id for vm in vm_list] + self.assertTrue(vm_1.id in vm_ids, "vm %s not present in vm list %s" % (vm_1.id, vm_ids)) + self.assertTrue(vm_1.id in vm_ids, "vm %s not present in vm list %s" % (vm_2.id, vm_ids)) + + return + + @attr(tags = ["advancedsg"]) + def test_26_Destroy_Deploy_VM_NoFreeIPs(self): + """ Test destroy VM in zone wide shared nw when IPs are full and then try to deploy vm""" + + # Steps, + # 1. Create zone wide shared network in SG enabled zone. + # 2. Exhaust the free IPs in the network by deploying VM. + # 3. Destroy VM when IPs are full and then again try to deploy VM + + # Validations, + # 1. VM should be deployed as one IP gets available + + self.services["shared_network_sg"]["acltype"] = "domain" + self.services["shared_network_sg"]["networkofferingid"] = self.shared_network_offering_sg.id + + physical_network, vlan = get_free_vlan(self.api_client, self.zone.id) + + #create network using the shared network offering created + self.services["shared_network_sg"]["vlan"] = vlan + self.services["shared_network_sg"]["physicalnetworkid"] = physical_network.id + + self.setSharedNetworkParams("shared_network_sg", range=2) + + shared_network = Network.create(self.api_client,self.services["shared_network_sg"], + networkofferingid=self.shared_network_offering_sg.id,zoneid=self.zone.id) + self.cleanup_networks.append(shared_network) + + # Deploying 1 VM will exhaust the IP range because we are passing range as 2, and one of the IPs + # already gets consumed by the virtual router of the shared network + + self.debug("Creating virtual machine shared network %s" % shared_network.id) + vm_1 = VirtualMachine.create(self.api_client,self.services["virtual_machine"], + templateid=self.template.id,networkids=[shared_network.id,], + serviceofferingid=self.service_offering.id) + try: + self.debug("Trying to create virtual machine when all the IPs are consumed") + vm = VirtualMachine.create(self.api_client,self.services["virtual_machine"], + templateid=self.template.id,networkids=[shared_network.id,], + serviceofferingid=self.service_offering.id) + self.cleanup_vms.append(vm) + self.fail("Vm creation succeded, should have failed") + except Exception as e: + self.debug("VM creation failed as expected with exception: %s" % e) + + # Now delete VM to free IP in shared network + vm_1.delete(self.api_client) + # Wait for VMs to expunge + wait_for_cleanup(self.api_client, ["expunge.delay", "expunge.interval"]) + + # As IP is free now, VM deployment in the shared network should be successful + + try: + self.debug("Trying to create virtual machine when all the IPs are consumed") + vm_2 = VirtualMachine.create(self.api_client,self.services["virtual_machine"], + templateid=self.template.id,networkids=[shared_network.id,], + serviceofferingid=self.service_offering.id) + self.cleanup_vms.append(vm_2) + self.debug("Deployed VM %s in the shared network %s" % (vm_2.id, shared_network.id)) + except Exception as e: + self.fail("VM creation failed with exception: %s" % e) + + return + + @data("stopStart","reboot") + @attr(tags = ["advancedsg"]) + def test_27_start_stop_vm(self, value): + """ Test start and stop vm""" + + # Steps, + # 1. Create a security group and authorize ingress rule (port 22-80) for this security group + # 2. Create a user account and deploy VMs in this account and security group + # 3. Try to access VM through SSH + # 4. Start and stop/ Reboot VM + # 5. Again try to access the VM through SSH + + # Validations, + # 1. Both the times, SSH should be successful + + #Create user account + user_account = Account.create(self.api_client,self.services["account"],domainid=self.domain.id) + self.debug("Created user account : %s" % user_account.name) + self.cleanup_accounts.append(user_account) + + ingress_rule_ids = [] + + # Create custom security group + self.services["security_group"]["name"] = "Custom_sec_grp_" + random_gen() + custom_sec_grp = SecurityGroup.create(self.api_client,self.services["security_group"], account=user_account.name, domainid=self.domain.id) + self.debug("Created security groups: %s" % custom_sec_grp.id) + self.cleanup_secGrps.append(custom_sec_grp) + + # Authorize Security group to for allowing SSH to VM + ingress_rule = custom_sec_grp.authorize(self.api_client,self.services["ingress_rule"]) + ingress_rule_ids.append(ingress_rule["ingressrule"][0].ruleid) + self.debug("Authorized ingress rule for security group: %s" % custom_sec_grp.id) + + # Create virtual machine without passing any security group id + vm = VirtualMachine.create(self.api_client,self.services["virtual_machine"], + templateid=self.template.id,accountid=user_account.name, + domainid=self.domain.id,serviceofferingid=self.service_offering.id, + securitygroupids = [custom_sec_grp.id,]) + self.debug("Created VM : %s" % vm.id) + self.cleanup_vms.append(vm) + + # Should be able to SSH VM + try: + self.debug("SSH into VM: %s" % vm.nic[0].ipaddress) + vm.get_ssh_client(ipaddress=vm.nic[0].ipaddress) + + self.debug("SSH to VM successful, proceeding for %s operation" % value) + + if value == "stopStart": + self.setVmState(vm, "stopped") + self.setVmState(vm, "running") + elif value == "reboot": + vm.reboot(self.api_client) + + self.debug("SSH into VM: %s" % vm.nic[0].ipaddress) + vm.get_ssh_client(ipaddress=vm.nic[0].ipaddress) + + except Exception as e: + self.fail("SSH Access failed for %s: %s, failed at line %s" % \ + (vm.nic[0].ipaddress, e, sys.exc_info()[2].tb_lineno) + ) + finally: + cmd = revokeSecurityGroupIngress.revokeSecurityGroupIngressCmd() + for rule_id in ingress_rule_ids: + cmd.id = rule_id + self.api_client.revokeSecurityGroupIngress(cmd) + + return + + @data("recover","expunge") + @attr(tags = ["advancedsg"]) + def test_28_destroy_recover_expunge_vm(self, value): + """ Test start and stop vm""" + + # Steps, + # 1. Create a security group and authorize ingress rule (port 22-80) for this security group + # 2. Create a user account and deploy VMs in this account and security group + # 3. Try to access VM through SSH + # 4. Destroy and recover VM (Or Expunge) + # 5. Again try to access the VM through SSH + + # Validations, + # 1. In destroy/recover case Both the times, SSH should be successful + # 2. In expunge case, SSH should not be suceessful after vm gets expunged + + #Create user account + user_account = Account.create(self.api_client,self.services["account"],domainid=self.domain.id) + self.debug("Created user account : %s" % user_account.name) + self.cleanup_accounts.append(user_account) + + ingress_rule_ids = [] + + # Create custom security group + self.services["security_group"]["name"] = "Custom_sec_grp_" + random_gen() + custom_sec_grp = SecurityGroup.create(self.api_client,self.services["security_group"], account=user_account.name, domainid=self.domain.id) + self.debug("Created security groups: %s" % custom_sec_grp.id) + self.cleanup_secGrps.append(custom_sec_grp) + + # Authorize Security group to for allowing SSH to VM + ingress_rule = custom_sec_grp.authorize(self.api_client,self.services["ingress_rule"]) + ingress_rule_ids.append(ingress_rule["ingressrule"][0].ruleid) + self.debug("Authorized ingress rule for security group: %s" % custom_sec_grp.id) + + # Create virtual machine without passing any security group id + vm = VirtualMachine.create(self.api_client,self.services["virtual_machine"], + templateid=self.template.id,accountid=user_account.name, + domainid=self.domain.id,serviceofferingid=self.service_offering.id, + securitygroupids = [custom_sec_grp.id,]) + self.debug("Created VM : %s" % vm.id) + + # Should be able to SSH VM + try: + self.debug("SSH into VM: %s" % vm.nic[0].ipaddress) + vm.get_ssh_client(ipaddress=vm.nic[0].ipaddress) + self.debug("SSH to VM successful, proceeding for %s operation" % value) + vm.delete(self.api_client) + if value == "recover": + vm.recover(self.api_client) + vm.start(self.api_client) + retriesCount = 5 + while True: + vm_list = VirtualMachine.list(self.api_client, id=vm.id) + self.assertEqual(validateList(vm_list)[0], PASS , "vm list validation failed, vm list is %s" % vm_list) + if str(vm_list[0].state).lower() == "running": + break + if retriesCount == 0: + self.fail("Failed to start vm: %s" % vm.id) + retriesCount -= 1 + time.sleep(10) + self.debug("SSH into VM: %s" % vm.nic[0].ipaddress) + vm.get_ssh_client(ipaddress=vm.nic[0].ipaddress) + self.debug("SSH successful") + self.cleanup_vms.append(vm) + elif value == "expunge": + #wait till vm gets expunged + wait_for_cleanup(self.api_client, ["expunge.delay", "expunge.interval"]) + try: + vm_list = VirtualMachine.list(self.api_client, id=vm.id) + self.fail("vm listing should fail, instead got vm list: %s" % vm_list) + except Exception as e: + self.debug("Vm listing failed as expected with exception: %s" % e) + + try: + self.debug("SSH into VM: %s, this should fail" % vm.nic[0].ipaddress) + vm.get_ssh_client(ipaddress=vm.nic[0].ipaddress) + self.fail("SSH should have failed, instead it succeeded") + except Exception as e: + self.debug("SSH failed as expected with exception: %s" % e) + except Exception as e: + self.fail("SSH Access failed for %s: %s, failed at line %s" % \ + (vm.nic[0].ipaddress, e, sys.exc_info()[2].tb_lineno) + ) + finally: + cmd = revokeSecurityGroupIngress.revokeSecurityGroupIngressCmd() + for rule_id in ingress_rule_ids: + cmd.id = rule_id + self.api_client.revokeSecurityGroupIngress(cmd) + + return + + @attr(tags = ["advancedsg"]) + def test_31_Deploy_VM_multiple_shared_networks_sg(self): + """ Test deploy VM in multiple SG enabled shared networks""" + + # Steps, + # 1. Create multiple SG enabled shared networks + # 3. Try to deploy VM in all of these networks + + # Validations, + # 1. VM deployment should fail saying "Only support one network per VM if security group enabled" + + self.services["shared_network_sg"]["acltype"] = "domain" + self.services["shared_network_sg"]["networkofferingid"] = self.shared_network_offering_sg.id + + physical_network, vlan = get_free_vlan(self.api_client, self.zone.id) + + #create network using the shared network offering created + self.services["shared_network_sg"]["vlan"] = vlan + self.services["shared_network_sg"]["physicalnetworkid"] = physical_network.id + + self.setSharedNetworkParams("shared_network_sg") + + shared_network_1 = Network.create(self.api_client,self.services["shared_network_sg"], + networkofferingid=self.shared_network_offering_sg.id,zoneid=self.zone.id) + self.cleanup_networks.append(shared_network_1) + self.debug("Created shared network: %s" % shared_network_1.id) + + self.services["shared_network_sg"]["vlan"] = get_free_vlan(self.api_client, self.zone.id)[1] + self.setSharedNetworkParams("shared_network_sg") + + shared_network_2 = Network.create(self.api_client,self.services["shared_network_sg"], + networkofferingid=self.shared_network_offering_sg.id,zoneid=self.zone.id) + self.cleanup_networks.append(shared_network_2) + self.debug("Created shared network: %s" % shared_network_2.id) + + try: + self.debug("Creating virtual machine in shared networks %s and %s, this should fail" % + (shared_network_1.id, shared_network_2.id)) + vm = VirtualMachine.create(self.api_client,self.services["virtual_machine"], + templateid=self.template.id, networkids=[shared_network_1.id, shared_network_2.id], + serviceofferingid=self.service_offering.id) + self.cleanup_vms.append(vm) + self.fail("Vm deployment should have failed, instead deployed vm %s" % vm.id) + except Exception as e: + self.debug("VM deployment failed as expected with exception: %s" % e) + + return + + @unittest.skip("Testing pending on multihost setup") + @data("account","domain","zone") + @attr(tags = ["advancedsg"]) + def test_33_VM_Migrate_SharedNwSG(self, value): + """ Test migration of VM deployed in Account specific shared network""" + + # Steps, + # 1. create a user account + # 2. Create one shared Network (scope=Account/domain/zone) + # 3. Deploy one VM in above shared network + # 4. Migrate VM to another host + + # Validations, + # 1. VM migration should be successful + + #Create admin account + + hosts = Host.list(self.api_client, zoneid=self.zone.id) + self.assertEqual(validateList(hosts)[0], PASS, "hosts list validation failed, list is %s" % hosts) + if len(hosts) < 2: + self.skipTest("This test requires at least two hosts present in the zone") + domain = self.domain + account = None + self.services["shared_network_sg"]["acltype"] = "domain" + if value == "domain": + domain = Domain.create(self.api_client, services=self.services["domain"], + parentdomainid=self.domain.id) + self.cleanup_domains.append(domain) + elif value == "account": + account = Account.create(self.api_client,self.services["account"],admin=True, + domainid=self.domain.id) + self.cleanup_accounts.append(account) + self.services["shared_network_sg"]["acltype"] = "account" + + physical_network, vlan = get_free_vlan(self.api_client, self.zone.id) + #create network using the shared network offering created + self.services["shared_network_sg"]["vlan"] = vlan + self.services["shared_network_sg"]["networkofferingid"] = self.shared_network_offering_sg.id + self.services["shared_network_sg"]["physicalnetworkid"] = physical_network.id + + self.setSharedNetworkParams("shared_network_sg") + + shared_network_sg = Network.create(self.api_client, self.services["shared_network_sg"], + accountid=account.name if account else None, + domainid=domain.id, + networkofferingid=self.shared_network_offering_sg.id, + zoneid=self.zone.id) + + if value == "domain" or value == "zone": + self.cleanup_networks.append(shared_network_sg) + + self.debug("Created %s wide shared network %s" % (value,shared_network_sg.id)) + + virtual_machine = VirtualMachine.create(self.api_client,self.services["virtual_machine"], + accountid=account.name if account else None, + domainid=domain.id, + networkids=[shared_network_sg.id], + serviceofferingid=self.service_offering.id + ) + self.cleanup_vms.append(virtual_machine) + hosts_to_migrate = [host for host in hosts if host.id != virtual_machine.hostid] + self.assertTrue(len(hosts_to_migrate) > 1, "At least one suitable host should be present to migrate VM") + + try: + self.debug("trying to migrate virtual machine from host %s to host %s" % (virtual_machine.hostid, hosts_to_migrate[0].id)) + virtual_machine.migrate(self.api_client, hosts_to_migrate[0].id) + except Exception as e: + self.fail("VM migration failed with exception %s" % e) + + vm_list = list_virtual_machines(self.api_client, id=virtual_machine.id) + self.assertEqual(validateList(vm_list)[0], PASS, "vm list validation failed, vm list is %s" % vm_list) + self.assertEqual(vm_list[0].hostid, hosts_to_migrate[0].id, "VM host id does not reflect the migration") + return + class TestSecurityGroups_BasicSanity(cloudstackTestCase): @classmethod @@ -1754,8 +2325,8 @@ class TestSecurityGroups_BasicSanity(cloudstackTestCase): return @attr(tags = ["advancedsg"]) - def test_22_DeployVM_WithoutSG(self): - """ Test deploy VM without passing any security group id""" + def test_22_DeployVM_With_Custom_SG(self): + """ Test deploy VM by passing custom security group id""" # Steps, # 1. List security groups and authorize ingress rule for the default security group @@ -1936,5 +2507,795 @@ class TestSecurityGroups_BasicSanity(cloudstackTestCase): 1, "Ping to outside world from VM should be successful" ) + return + + @attr(tags = ["advancedsg"]) + def test_32_delete_default_security_group(self): + """ Test Delete the default security group when No VMs are deployed""" + + # Steps, + # 1. create an account + # 2. List the security groups belonging to the account + # 3. Delete the default security group + # Validations, + # 1. Default security group of the account should not get deleted + + #Create admin account + account = Account.create(self.api_client, self.services["account"], admin=True, + domainid=self.domain.id) + + self.cleanup_accounts.append(account) + + self.debug("Admin type account created: %s" % account.name) + + securitygroups = SecurityGroup.list(self.api_client, account=account.name, domainid=self.domain.id) + self.assertEqual(validateList(securitygroups)[0], PASS, "security groups list validation failed, list is %s" % securitygroups) + + defaultSecGroup = securitygroups[0] + cmd = deleteSecurityGroup.deleteSecurityGroupCmd() + cmd.id = defaultSecGroup.id + + try: + self.debug("Deleting default security group %s in account %s" % (defaultSecGroup.id, account.id)) + self.api_client.deleteSecurityGroup(cmd) + self.fail("Default security group of the account got deleted") + except Exception as e: + self.debug("Deleting the default security group failed as expected with exception: %s" % e) + return + +@ddt +class TestSharedNetworkOperations(cloudstackTestCase): + + @classmethod + def setUpClass(cls): + cloudstackTestClient = super(TestSharedNetworkOperations,cls).getClsTestClient() + cls.api_client = cloudstackTestClient.getApiClient() + + 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.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.service_offering = ServiceOffering.create(cls.api_client,cls.services["service_offering"]) + + cls.services["shared_network_offering_sg"]["specifyVlan"] = "True" + cls.services["shared_network_offering_sg"]["specifyIpRanges"] = "True" + #Create Network Offering + cls.shared_network_offering_sg = NetworkOffering.create(cls.api_client,cls.services["shared_network_offering_sg"],conservemode=False) + + #Update network offering state from disabled to enabled. + NetworkOffering.update(cls.shared_network_offering_sg,cls.api_client,state="enabled") + + cls._cleanup = [ + cls.service_offering, + cls.shared_network_offering_sg + ] + return + + @classmethod + def tearDownClass(cls): + try: + #Update network offering state from enabled to disabled. + cls.shared_network_offering_sg.update(cls.api_client,state="disabled") + #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.api_client = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + self.cleanup = [] + self.cleanup_networks = [] + self.cleanup_accounts = [] + self.cleanup_domains = [] + self.cleanup_projects = [] + self.cleanup_vms = [] + self.cleanup_secGrps = [] + return + + def tearDown(self): + exceptions = [] + try: + #Clean up, terminate the created network offerings + cleanup_resources(self.api_client, self.cleanup) + except Exception as e: + self.debug("Warning: Exception during cleanup : %s" % e) + exceptions.append(e) + + #below components is not a part of cleanup because to mandate the order and to cleanup network + try: + for vm in self.cleanup_vms: + vm.delete(self.api_client) + except Exception as e: + self.debug("Warning: Exception during virtual machines cleanup : %s" % e) + exceptions.append(e) + + # Wait for VMs to expunge + wait_for_cleanup(self.api_client, ["expunge.delay", "expunge.interval"]) + + try: + for sec_grp in self.cleanup_secGrps: + sec_grp.delete(self.api_client) + except Exception as e: + self.debug("Warning : Exception during security groups cleanup: %s" % e) + exceptions.append(e) + + try: + for project in self.cleanup_projects: + project.delete(self.api_client) + except Exception as e: + self.debug("Warning: Exception during project cleanup : %s" % e) + exceptions.append(e) + + try: + for account in self.cleanup_accounts: + account.delete(self.api_client) + except Exception as e: + self.debug("Warning: Exception during account cleanup : %s" % e) + exceptions.append(e) + + #Wait till all resources created are cleaned up completely and then attempt to delete Network + time.sleep(self.services["sleep"]) + + try: + for network in self.cleanup_networks: + network.delete(self.api_client) + except Exception as e: + self.debug("Warning: Exception during network cleanup : %s" % e) + exceptions.append(e) + + try: + for domain in self.cleanup_domains: + domain.delete(self.api_client) + except Exception as e: + self.debug("Warning: Exception during domain cleanup : %s" % e) + exceptions.append(e) + + if len(exceptions) > 0: + self.fail("There were exceptions during cleanup: %s" % exceptions) return + + def setSharedNetworkParams(self, network, range=20): + + # @range: range decides the endip. Pass the range as "x" if you want the difference between the startip + # and endip as "x" + # Set the subnet number of shared networks randomly prior to execution + # of each test case to avoid overlapping of ip addresses + shared_network_subnet_number = random.randrange(1,254) + + self.services[network]["gateway"] = "172.16."+str(shared_network_subnet_number)+".1" + self.services[network]["startip"] = "172.16."+str(shared_network_subnet_number)+".2" + self.services[network]["endip"] = "172.16."+str(shared_network_subnet_number)+"."+str(range+1) + self.services[network]["netmask"] = "255.255.255.0" + + return + + @data("account","domain","zone") + @attr(tags = ["advancedsg"]) + def test_34_restart_shared_network_sg(self, value): + """ Test restart account/domain/zone wide shared network""" + + # Steps, + # 1. Create account/domain/zone wide shared Network + # 2. Restart shared network + + # Validations, + # 1. Network restart should be successful + + domain = self.domain + account = None + self.services["shared_network_sg"]["acltype"] = "domain" + if value == "domain": + domain = Domain.create(self.api_client, services=self.services["domain"], + parentdomainid=self.domain.id) + self.cleanup_domains.append(domain) + elif value == "account": + account = Account.create(self.api_client,self.services["account"],admin=True, + domainid=self.domain.id) + self.cleanup_accounts.append(account) + self.services["shared_network_sg"]["acltype"] = "account" + + physical_network, vlan = get_free_vlan(self.api_client, self.zone.id) + #create network using the shared network offering created + self.services["shared_network_sg"]["vlan"] = vlan + self.services["shared_network_sg"]["networkofferingid"] = self.shared_network_offering_sg.id + self.services["shared_network_sg"]["physicalnetworkid"] = physical_network.id + + self.setSharedNetworkParams("shared_network_sg") + + shared_network_sg = Network.create(self.api_client, self.services["shared_network_sg"], + accountid=account.name if account else None, + domainid=domain.id, + networkofferingid=self.shared_network_offering_sg.id, + zoneid=self.zone.id) + if value == "domain" or value == "zone": + self.cleanup_networks.append(shared_network_sg) + + self.debug("Created %s wide shared network %s" % (value,shared_network_sg.id)) + + try: + self.debug("Restarting shared network: %s" % shared_network_sg) + shared_network_sg.restart(self.api_client) + except Exception as e: + self.fail("Exception while restarting the shared network: %s" % e) + return + + @unittest.skip("Testing pending on multihost setup") + @data("account","domain","zone") + @attr(tags = ["advancedsg"]) + def test_35_Enable_Host_Maintenance(self, value): + """ Test security group rules of VM after putting host in maintenance mode""" + + # Steps, + # 1. Deploy vm in account/domain/zone wide shared network + # 2. Put the host of VM in maintenance mode + # 3. Verify the security group associated with the VM + # 4. Cancel the maintenance mode of the host + # 5. Again verify the security group of the VM + + # Validations, + # 1. Security group should remain the same throughout all the operations + + #Create admin account + + hosts = Host.list(self.api_client, zoneid=self.zone.id) + self.assertEqual(validateList(hosts)[0], PASS, "hosts list validation failed, list is %s" % hosts) + if len(hosts) < 2: + self.skipTest("This test requires at least two hosts present in the zone") + domain = self.domain + account = None + self.services["shared_network_sg"]["acltype"] = "domain" + if value == "domain": + domain = Domain.create(self.api_client, services=self.services["domain"], + parentdomainid=self.domain.id) + self.cleanup_domains.append(domain) + elif value == "account": + account = Account.create(self.api_client,self.services["account"],admin=True, + domainid=self.domain.id) + self.cleanup_accounts.append(account) + self.services["shared_network_sg"]["acltype"] = "account" + + physical_network, vlan = get_free_vlan(self.api_client, self.zone.id) + #create network using the shared network offering created + self.services["shared_network_sg"]["vlan"] = vlan + self.services["shared_network_sg"]["networkofferingid"] = self.shared_network_offering_sg.id + self.services["shared_network_sg"]["physicalnetworkid"] = physical_network.id + + self.setSharedNetworkParams("shared_network_sg") + + shared_network_sg = Network.create(self.api_client, self.services["shared_network_sg"], + accountid=account.name if account else None, + domainid=domain.id, + networkofferingid=self.shared_network_offering_sg.id, + zoneid=self.zone.id) + + if value == "domain" or value == "zone": + self.cleanup_networks.append(shared_network_sg) + + self.debug("Created %s wide shared network %s" % (value,shared_network_sg.id)) + + virtual_machine = VirtualMachine.create(self.api_client,self.services["virtual_machine"], + accountid=account.name if account else None, + domainid=domain.id, + networkids=[shared_network_sg.id], + serviceofferingid=self.service_offering.id + ) + self.cleanup_vms.append(virtual_machine) + hostid = virtual_machine.hostid + + securitygroupid = virtual_machine.securitygroup[0].id + + # Put host in maintenance mode + Host.enableMaintenance(self.api_client, id=hostid) + + vm_list = list_virtual_machines(self.api_client, id=virtual_machine.id) + self.assertEqual(validateList(vm_list)[0], PASS, "vm list validation failed, vm list is: %s" % vm_list) + self.assertEqual(vm_list[0].securitygroup[0].id, securitygroupid, "Security group id should remain same, before\ + it was %s and after putting host in maintenance mode, it is %s" % (securitygroupid, vm_list[0].securitygroup[0].id)) + + # Cancel host maintenance + Host.cancelMaintenance(self.api_client, id=hostid) + vm_list = list_virtual_machines(self.api_client, id=virtual_machine.id) + self.assertEqual(validateList(vm_list)[0], PASS, "vm list validation failed, vm list is: %s" % vm_list) + self.assertEqual(vm_list[0].securitygroup[0].id, securitygroupid, "Security group id should remain same, before\ + it was %s and after putting host in maintenance mode, it is %s" % (securitygroupid, vm_list[0].securitygroup[0].id)) + + return + +@ddt +class TestAccountBasedIngressRules(cloudstackTestCase): + + @classmethod + def setUpClass(cls): + cloudstackTestClient = super(TestAccountBasedIngressRules,cls).getClsTestClient() + cls.api_client = cloudstackTestClient.getApiClient() + + 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.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.service_offering = ServiceOffering.create(cls.api_client,cls.services["service_offering"]) + + cls.services["shared_network_offering_sg"]["specifyVlan"] = "True" + cls.services["shared_network_offering_sg"]["specifyIpRanges"] = "True" + #Create Network Offering + cls.shared_network_offering_sg = NetworkOffering.create(cls.api_client,cls.services["shared_network_offering_sg"],conservemode=False) + + #Update network offering state from disabled to enabled. + NetworkOffering.update(cls.shared_network_offering_sg,cls.api_client,state="enabled") + + cls._cleanup = [ + cls.service_offering, + cls.shared_network_offering_sg + ] + return + + @classmethod + def tearDownClass(cls): + try: + #Update network offering state from enabled to disabled. + cls.shared_network_offering_sg.update(cls.api_client,state="disabled") + #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.api_client = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + self.cleanup = [] + self.cleanup_networks = [] + self.cleanup_accounts = [] + self.cleanup_domains = [] + self.cleanup_projects = [] + self.cleanup_vms = [] + self.cleanup_secGrps = [] + + #Create account 1 + self.account_1 = Account.create(self.api_client, self.services["account"],domainid=self.domain.id) + self.cleanup_accounts.append(self.account_1) + self.debug("Created account 1: %s" % self.account_1.name) + + #Create account 2 + self.account_2 = Account.create(self.api_client, self.services["account"],domainid=self.domain.id) + self.cleanup_accounts.append(self.account_2) + self.debug("Created account 2: %s" % self.account_2.name) + + self.debug("Deploying virtual machine in account 1: %s" % self.account_1.name) + self.virtual_machine_1 = VirtualMachine.create(self.api_client,self.services["virtual_machine"],accountid=self.account_1.name, + domainid=self.account_1.domainid,serviceofferingid=self.service_offering.id) + self.cleanup_vms.append(self.virtual_machine_1) + self.debug("Deployed vm: %s" % self.virtual_machine_1.id) + + self.debug("Deploying virtual machine in account 2: %s" % self.account_2.name) + self.virtual_machine_2 = VirtualMachine.create(self.api_client,self.services["virtual_machine"],accountid=self.account_2.name, + domainid=self.account_2.domainid,serviceofferingid=self.service_offering.id) + self.cleanup_vms.append(self.virtual_machine_2) + self.debug("Deployed vm: %s" % self.virtual_machine_2.id) + + # Getting default security group of account 1 + securitygroups_account_1 = SecurityGroup.list(self.api_client, account=self.account_1.name, domainid=self.account_1.domainid) + + self.assertEqual(validateList(securitygroups_account_1)[0], PASS, "securitygroups list validation\ + failed, securitygroups list is %s" % securitygroups_account_1) + self.sec_grp_1 = securitygroups_account_1[0] + + # Getting default security group of account 2 + securitygroups_account_2 = SecurityGroup.list(self.api_client, account=self.account_2.name, domainid=self.account_2.domainid) + + self.assertEqual(validateList(securitygroups_account_2)[0], PASS, "securitygroups list validation\ + failed, securitygroups list is %s" % securitygroups_account_2) + self.sec_grp_2 = securitygroups_account_2[0] + return + + def tearDown(self): + exceptions = [] + try: + #Clean up, terminate the created network offerings + cleanup_resources(self.api_client, self.cleanup) + except Exception as e: + self.debug("Warning: Exception during cleanup : %s" % e) + exceptions.append(e) + + #below components is not a part of cleanup because to mandate the order and to cleanup network + try: + for vm in self.cleanup_vms: + vm.delete(self.api_client) + except Exception as e: + self.debug("Warning: Exception during virtual machines cleanup : %s" % e) + exceptions.append(e) + + # Wait for VMs to expunge + wait_for_cleanup(self.api_client, ["expunge.delay", "expunge.interval"]) + + try: + for sec_grp in self.cleanup_secGrps: + sec_grp.delete(self.api_client) + except Exception as e: + self.debug("Warning : Exception during security groups cleanup: %s" % e) + exceptions.append(e) + + try: + for project in self.cleanup_projects: + project.delete(self.api_client) + except Exception as e: + self.debug("Warning: Exception during project cleanup : %s" % e) + exceptions.append(e) + + try: + for account in self.cleanup_accounts: + account.delete(self.api_client) + except Exception as e: + self.debug("Warning: Exception during account cleanup : %s" % e) + exceptions.append(e) + + #Wait till all resources created are cleaned up completely and then attempt to delete Network + time.sleep(self.services["sleep"]) + + try: + for network in self.cleanup_networks: + network.delete(self.api_client) + except Exception as e: + self.debug("Warning: Exception during network cleanup : %s" % e) + exceptions.append(e) + + try: + for domain in self.cleanup_domains: + domain.delete(self.api_client) + except Exception as e: + self.debug("Warning: Exception during domain cleanup : %s" % e) + exceptions.append(e) + + if len(exceptions) > 0: + self.fail("There were exceptions during cleanup: %s" % exceptions) + + return + + def setSharedNetworkParams(self, network, range=20): + + # @range: range decides the endip. Pass the range as "x" if you want the difference between the startip + # and endip as "x" + # Set the subnet number of shared networks randomly prior to execution + # of each test case to avoid overlapping of ip addresses + shared_network_subnet_number = random.randrange(1,254) + + self.services[network]["gateway"] = "172.16."+str(shared_network_subnet_number)+".1" + self.services[network]["startip"] = "172.16."+str(shared_network_subnet_number)+".2" + self.services[network]["endip"] = "172.16."+str(shared_network_subnet_number)+"."+str(range+1) + self.services[network]["netmask"] = "255.255.255.0" + + return + + @data("accessByIp","accessByName") + @attr(tags = ["advancedsg"]) + def test_36_ssh_vm_other_sg(self, value): + """ Test access VM in other security group from vm in one security group""" + + # Steps, + # 1. create two accounts, this will create two default security groups of the accounts + # 2. Deploy VM in both the accounts + # 3. Add ingress rule for the security group 2 + # 4. Access vm in security group 2 from vm in security group 1 + # Validations, + # 1. Vm should be accessible from the other security group because ingress rule has been created + + #Create account 1 + + # Authorize ingress rule for the security groups + cmd = authorizeSecurityGroupIngress.authorizeSecurityGroupIngressCmd() + cmd.protocol = 'TCP' + cmd.startport = 22 + cmd.endport = 80 + cmd.cidrlist = ['0.0.0.0/0'] + cmd.securitygroupid = self.sec_grp_1.id + self.api_client.authorizeSecurityGroupIngress(cmd) + + cmd.securitygroupid = self.sec_grp_2.id + cmd.cidrlist = [] + # Authorize to only account not CIDR + cmd.usersecuritygrouplist = [{'account':str(self.account_1.name),'group': str(self.sec_grp_1.name)}] + self.api_client.authorizeSecurityGroupIngress(cmd) + + self.debug("Getting SSH client of virtual machine 1: %s" % self.virtual_machine_1.id) + sshClient = self.virtual_machine_1.get_ssh_client(ipaddress=self.virtual_machine_1.nic[0].ipaddress) + try: + if value == "accessByIp": + self.debug("SSHing into vm_2 %s from vm_1 %s" % (self.virtual_machine_2.nic[0].ipaddress,self.virtual_machine_1.nic[0].ipaddress)) + command = "ssh -t -t root@%s" % self.virtual_machine_2.nic[0].ipaddress + elif value == "accessByName": + self.debug("SSHing into vm_2 %s from vm_1 %s" % (self.virtual_machine_2.name,self.virtual_machine_1.name)) + command = "ssh -t -t root@%s" % self.virtual_machine_2.name + else: + self.fail("Invalid value passed to the test case") + self.debug("command: --> %s" % command) + res = sshClient.execute(command) + self.debug("SSH result: %s" % str(res)) + + except Exception as e: + self.fail("SSH Access failed for %s: %s" % \ + (self.virtual_machine_1.nic[0].ipaddress, e) + ) + result = str(res) + self.assertNotEqual( + result.count("No route to host"), + 1, + "SSH should be successful" + ) + return + + @attr(tags = ["advancedsg"]) + def test_37_ping_vm_other_sg(self): + """ Test access VM in other security group from vm in one security group""" + + # Steps, + # 1. create two accounts, this will create two default security groups of the accounts + # 2. Deploy VM in both the accounts + # 3. Add ingress rule for TCMP protocol the security group 2 allowing traffic from sec group 1 + # 4. Ping vm in security group 2 from vm in security group 1 + # Validations, + # 1. Vm should be pinged from the other security group because ingress rule for TCMP has been created + + #Create account 1 + + # Authorize ingress rule for the security groups + cmd = authorizeSecurityGroupIngress.authorizeSecurityGroupIngressCmd() + cmd.protocol = 'TCP' + cmd.startport = 22 + cmd.endport = 80 + cmd.cidrlist = '0.0.0.0/0' + cmd.securitygroupid = self.sec_grp_1.id + self.api_client.authorizeSecurityGroupIngress(cmd) + + cmd.protocol = 'ICMP' + cmd.icmptype = "-1" + cmd.icmpcode = "-1" + cmd.cidrlist = [] + # Authorize to only account not CIDR + cmd.usersecuritygrouplist = [{'account':str(self.account_1.name),'group': str(self.sec_grp_1.name)}] + cmd.securitygroupid = self.sec_grp_2.id + self.api_client.authorizeSecurityGroupIngress(cmd) + + self.debug("Getting SSH client of virtual machine 1: %s" % self.virtual_machine_1.id) + sshClient = self.virtual_machine_1.get_ssh_client(ipaddress=self.virtual_machine_1.nic[0].ipaddress) + try: + self.debug("SSHing into vm_2 %s from vm_1 %s" % (self.virtual_machine_2.nic[0].ipaddress,self.virtual_machine_1.nic[0].ipaddress)) + command = "ping -c 1 %s" % self.virtual_machine_2.nic[0].ipaddress + self.debug("command: --> %s" % command) + res = sshClient.execute(command) + self.debug("SSH result: %s" % str(res)) + + except Exception as e: + self.fail("SSH Access failed for %s: %s" % \ + (self.virtual_machine_1.nic[0].ipaddress, e) + ) + result = str(res) + self.assertEqual( + result.count("1 received"), + 1, + "Ping to outside world from VM should be successful" + ) + return + + @data("accessByIp","accessByName") + @attr(tags = ["advancedsg"]) + def test_38_ssh_vm_other_sg_new_vm(self, value): + """ Test access VM in other security group from a new vm in one security group""" + + # Steps, + # 1. create two accounts, this will create two default security groups of the accounts + # 2. Deploy VM in both the accounts + # 3. Add ingress rule for the security group 2 allowing traffic from sec group 1 + # 4. Add new VMs in sec grp 1 and sec grp 2 + # 4. Access new vm in security group 2 from new vm in security group 1 + # Validations, + # 1. Vm should be accessible from the other security group because ingress rule has been created + + # Authorize ingress rule for the security groups + cmd = authorizeSecurityGroupIngress.authorizeSecurityGroupIngressCmd() + cmd.protocol = 'TCP' + cmd.startport = 22 + cmd.endport = 80 + cmd.cidrlist = '0.0.0.0/0' + cmd.securitygroupid = self.sec_grp_1.id + self.api_client.authorizeSecurityGroupIngress(cmd) + + cmd.securitygroupid = self.sec_grp_2.id + cmd.cidrlist = [] + # Authorize to only account not CIDR + cmd.usersecuritygrouplist = [{'account':str(self.account_1.name),'group': str(self.sec_grp_1.name)}] + self.api_client.authorizeSecurityGroupIngress(cmd) + + self.debug("Deploying virtual machine in account 1: %s" % self.account_1.name) + self.virtual_machine_3 = VirtualMachine.create(self.api_client,self.services["virtual_machine"],accountid=self.account_1.name, + domainid=self.account_1.domainid,serviceofferingid=self.service_offering.id) + self.cleanup_vms.append(self.virtual_machine_3) + self.debug("Deployed vm: %s" % self.virtual_machine_3.id) + + self.debug("Deploying virtual machine in account 2: %s" % self.account_2.name) + self.virtual_machine_4 = VirtualMachine.create(self.api_client,self.services["virtual_machine"],accountid=self.account_2.name, + domainid=self.account_2.domainid,serviceofferingid=self.service_offering.id) + self.cleanup_vms.append(self.virtual_machine_4) + self.debug("Deployed vm: %s" % self.virtual_machine_4.id) + + self.debug("Getting SSH client of virtual machine 1: %s" % self.virtual_machine_3.id) + sshClient = self.virtual_machine_3.get_ssh_client(ipaddress=self.virtual_machine_3.nic[0].ipaddress) + try: + if value == "accessByIp": + self.debug("SSHing into vm_4 %s from vm_3 %s" % (self.virtual_machine_4.nic[0].ipaddress,self.virtual_machine_3.nic[0].ipaddress)) + command = "ssh -t -t root@%s" % self.virtual_machine_4.nic[0].ipaddress + elif value == "accessByName": + self.debug("SSHing into vm_2 %s from vm_1 %s" % (self.virtual_machine_4.name,self.virtual_machine_3.name)) + command = "ssh -t -t root@%s" % self.virtual_machine_4.name + else: + self.fail("Invalid value passed to the test case") + self.debug("command: --> %s" % command) + res = sshClient.execute(command) + self.debug("SSH result: %s" % str(res)) + + except Exception as e: + self.fail("SSH Access failed for %s: %s" % \ + (self.virtual_machine_3.nic[0].ipaddress, e) + ) + result = str(res) + self.assertNotEqual( + result.count("No route to host"), + 1, + "SSH should be successful" + ) + return + + @data("accessByIp","accessByName") + @attr(tags = ["advancedsg"]) + def test_39_ssh_vm_other_sg_from_multiple_sg_vm(self, value): + """ Test access VM in other security group from vm belonging to multiple security groups""" + + # Steps, + # 1. create two accounts, this will create two default security groups of the accounts + # 2. Deploy VM in both the accounts + # 3. Add ingress rule for the security group 2 allowing traffic from sec group 1 + # 4. Create additional security group and deploy vm in 2 security groups + # 4. Access vm in security group 2 from vm in two security groups + # Validations, + # 1. Vm should be accessible from the other security group because ingress rule has been created + + # Authorize ingress rule for the security groups + cmd = authorizeSecurityGroupIngress.authorizeSecurityGroupIngressCmd() + cmd.protocol = 'TCP' + cmd.startport = 22 + cmd.endport = 80 + cmd.cidrlist = '0.0.0.0/0' + cmd.securitygroupid = self.sec_grp_1.id + self.api_client.authorizeSecurityGroupIngress(cmd) + + cmd.securitygroupid = self.sec_grp_2.id + cmd.cidrlist = [] + # Authorize to only account not CIDR + cmd.usersecuritygrouplist = [{'account':str(self.account_1.name),'group': str(self.sec_grp_1.name)}] + self.api_client.authorizeSecurityGroupIngress(cmd) + + self.sec_grp_3 = SecurityGroup.create(self.api_client, self.services["security_group"], account=self.account_1.name, + domainid=self.account_1.domainid) + self.sec_grp_3.authorize(self.api_client,self.services["ingress_rule"]) + + self.debug("Deploying virtual machine in account 1: %s, with sec groups %s and %s" % + (self.account_1.name,self.sec_grp_1.id, self.sec_grp_3.id)) + + self.virtual_machine_3 = VirtualMachine.create(self.api_client,self.services["virtual_machine"],accountid=self.account_1.name, + domainid=self.account_1.domainid,serviceofferingid=self.service_offering.id, + securitygroupids = [self.sec_grp_1.id, self.sec_grp_3.id]) + self.cleanup_vms.append(self.virtual_machine_3) + self.debug("Deployed vm: %s" % self.virtual_machine_3.id) + + self.debug("Getting SSH client of virtual machine 1: %s" % self.virtual_machine_3.id) + sshClient = self.virtual_machine_3.get_ssh_client(ipaddress=self.virtual_machine_3.nic[0].ipaddress) + try: + if value == "accessByIp": + self.debug("SSHing into vm_2 %s from vm_3 %s" % (self.virtual_machine_2.nic[0].ipaddress,self.virtual_machine_3.nic[0].ipaddress)) + command = "ssh -t -t root@%s" % self.virtual_machine_2.nic[0].ipaddress + elif value == "accessByName": + self.debug("SSHing into vm_2 %s from vm_3 %s" % (self.virtual_machine_2.name,self.virtual_machine_3.name)) + command = "ssh -t -t root@%s" % self.virtual_machine_2.name + else: + self.fail("Invalid value passed to the test case") + self.debug("command: --> %s" % command) + res = sshClient.execute(command) + self.debug("SSH result: %s" % str(res)) + + except Exception as e: + self.fail("SSH Access failed for %s: %s" % \ + (self.virtual_machine_3.nic[0].ipaddress, e) + ) + result = str(res) + self.assertNotEqual( + result.count("No route to host"), + 1, + "SSH should be successful" + ) + return + + @attr(tags = ["advancedsg"]) + def test_40_ssh_vm_other_sg_reboot(self): + """ Test access VM in other security group from vm in one security group before and after reboot""" + + # Steps, + # 1. create two accounts, this will create two default security groups of the accounts + # 2. Deploy VM in both the accounts + # 3. Add ingress rule for the security group 2 allowing traffic from sec group 1 + # 4. Access vm in security group 2 from vm in security group 1 + # 5. Reboot the vm in security group 1 and again access vm in sec grp 2 from it + # Validations, + # 1. Vm should be accessible from the other security group because ingress rule has been created + + #Create account 1 + + # Authorize ingress rule for the security groups + cmd = authorizeSecurityGroupIngress.authorizeSecurityGroupIngressCmd() + cmd.protocol = 'TCP' + cmd.startport = 22 + cmd.endport = 80 + cmd.cidrlist = '0.0.0.0/0' + cmd.securitygroupid = self.sec_grp_1.id + self.api_client.authorizeSecurityGroupIngress(cmd) + + cmd.securitygroupid = self.sec_grp_2.id + cmd.cidrlist = [] + # Authorize to only account not CIDR + cmd.usersecuritygrouplist = [{'account':str(self.account_1.name),'group': str(self.sec_grp_1.name)}] + self.api_client.authorizeSecurityGroupIngress(cmd) + + #Get ssh client of vm in account 1 and ssh to vm in account 2 from it + self.debug("Getting SSH client of virtual machine 1: %s" % self.virtual_machine_1.id) + + try: + sshClient = self.virtual_machine_1.get_ssh_client(ipaddress=self.virtual_machine_1.nic[0].ipaddress) + self.debug("SSHing into vm_2 %s from vm_1 %s" % (self.virtual_machine_2.nic[0].ipaddress,self.virtual_machine_1.nic[0].ipaddress)) + command = "ssh -t -t root@%s" % self.virtual_machine_2.nic[0].ipaddress + self.debug("command: --> %s" % command) + res = sshClient.execute(command) + self.debug("SSH result: %s" % str(res)) + except Exception as e: + self.fail("Exception in SSH operation: %s" % e) + result = str(res) + self.assertNotEqual( + result.count("No route to host"), + 1, + "SSH should be successful" + ) + + self.debug("Rebooting virtual machine %s" % self.virtual_machine_1.id) + self.virtual_machine_1.reboot(self.api_client) + + # Repeat the same procedure after reboot + self.debug("Getting SSH client of virtual machine 1: %s" % self.virtual_machine_1.id) + + try: + sshClient = self.virtual_machine_1.get_ssh_client(ipaddress=self.virtual_machine_1.nic[0].ipaddress) + self.debug("SSHing into vm_2 %s from vm_1 %s" % (self.virtual_machine_2.nic[0].ipaddress,self.virtual_machine_1.nic[0].ipaddress)) + command = "ssh -t -t root@%s" % self.virtual_machine_2.nic[0].ipaddress + self.debug("command: --> %s" % command) + res = sshClient.execute(command) + self.debug("SSH result: %s" % str(res)) + except Exception as e: + self.fail("Exception in ssh operation: %s" % e) + result = str(res) + self.assertNotEqual( + result.count("No route to host"), + 1, + "SSH should be successful" + ) + return diff --git a/test/integration/component/test_vpc_vm_life_cycle.py b/test/integration/component/test_vpc_vm_life_cycle.py index 5ce94f24945..01373ac5a73 100644 --- a/test/integration/component/test_vpc_vm_life_cycle.py +++ b/test/integration/component/test_vpc_vm_life_cycle.py @@ -18,13 +18,31 @@ """ Component tests VM life cycle in VPC network functionality """ #Import Local Modules -import marvin from nose.plugins.attrib import attr -from marvin.cloudstackTestCase import * -from marvin.cloudstackAPI import * -from marvin.integration.lib.utils import * -from marvin.integration.lib.base import * -from marvin.integration.lib.common import * +from marvin.cloudstackTestCase import cloudstackTestCase, unittest +from marvin.integration.lib.utils import cleanup_resources, validateList +from marvin.integration.lib.base import (VirtualMachine, + NATRule, + LoadBalancerRule, + StaticNATRule, + PublicIPAddress, + VPC, + VpcOffering, + Network, + NetworkOffering, + NetworkACL, + Router, + Account, + ServiceOffering, + Host) +from marvin.integration.lib.common import (get_domain, + get_zone, + get_template, + get_free_vlan, + wait_for_cleanup, + list_virtual_machines, + list_hosts) + from marvin.codes import PASS import time @@ -644,6 +662,13 @@ class TestVMLifeCycleVPC(cloudstackTestCase): True, "List LB rules shall return a valid list" ) + + #Recover the instances so that they don't get expunged before runing next test case in the suite + try: + self.vm_1.recover(self.apiclient) + self.vm_2.recover(self.apiclient) + except Exception as e: + self.fail("Failed to recover the virtual instances, %s" % e) return @attr(tags=["advanced", "intervlan"]) @@ -690,6 +715,11 @@ 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, @@ -707,7 +737,7 @@ class TestVMLifeCycleVPC(cloudstackTestCase): "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] + hosts[:] = [host for host in hosts if host.id != vm_hostid] host = hosts[0] @@ -847,17 +877,17 @@ class TestVMLifeCycleVPC(cloudstackTestCase): # Check if the network rules still exists after Vm stop self.debug("Checking if NAT rules existed") with self.assertRaises(Exception): - nat_rules = NATRule.list( - self.apiclient, - id=self.nat_rule.id, - listall=True - ) + NATRule.list( + self.apiclient, + id=self.nat_rule.id, + listall=True + ) - lb_rules = LoadBalancerRule.list( - self.apiclient, - id=self.lb_rule.id, - listall=True - ) + LoadBalancerRule.list( + self.apiclient, + id=self.lb_rule.id, + listall=True + ) return class TestVMLifeCycleSharedNwVPC(cloudstackTestCase): @@ -1651,17 +1681,17 @@ class TestVMLifeCycleSharedNwVPC(cloudstackTestCase): # Check if the network rules still exists after Vm expunged self.debug("Checking if NAT rules existed ") with self.assertRaises(Exception): - nat_rules = NATRule.list( - self.apiclient, - id=self.nat_rule.id, - listall=True - ) + NATRule.list( + self.apiclient, + id=self.nat_rule.id, + listall=True + ) - lb_rules = LoadBalancerRule.list( - self.apiclient, - id=self.lb_rule.id, - listall=True - ) + LoadBalancerRule.list( + self.apiclient, + id=self.lb_rule.id, + listall=True + ) return class TestVMLifeCycleBothIsolated(cloudstackTestCase): @@ -2687,17 +2717,17 @@ class TestVMLifeCycleStoppedVPCVR(cloudstackTestCase): # Check if the network rules still exists after Vm expunged self.debug("Checking if NAT rules existed ") with self.assertRaises(Exception): - nat_rules = NATRule.list( - self.apiclient, - id=self.nat_rule.id, - listall=True - ) + NATRule.list( + self.apiclient, + id=self.nat_rule.id, + listall=True + ) - lb_rules = LoadBalancerRule.list( - self.apiclient, - id=self.lb_rule.id, - listall=True - ) + LoadBalancerRule.list( + self.apiclient, + id=self.lb_rule.id, + listall=True + ) return class TestVMLifeCycleDiffHosts(cloudstackTestCase): diff --git a/tools/marvin/marvin/config/config.cfg b/tools/marvin/marvin/config/config.cfg index 5849fe88afd..7840b7c8e14 100644 --- a/tools/marvin/marvin/config/config.cfg +++ b/tools/marvin/marvin/config/config.cfg @@ -43,8 +43,8 @@ "memory": 128 }, "isolated_network_offering": { - "name": "Network offering-DA services", - "displaytext": "Network offering-DA services", + "name": "Isolated Network offering", + "displaytext": "Isolated Network offering", "guestiptype": "Isolated", "supportedservices": "Dhcp,Dns,SourceNat,PortForwarding,Vpn,Firewall,Lb,UserData,StaticNat", "traffictype": "GUEST", @@ -75,8 +75,8 @@ "protocol": "TCP" }, "shared_network": { - "name": "MySharedNetwork - Test", - "displaytext": "MySharedNetwork", + "name": "Test Shared Network", + "displaytext": "Test Shared Network", "vlan" : "", "gateway" :"", "netmask" :"", @@ -86,8 +86,8 @@ "scope":"all" }, "shared_network_offering_sg": { - "name": "MySharedOffering-sg", - "displaytext": "MySharedOffering-sg", + "name": "SharedNwOffering-sg", + "displaytext": "SharedNwOffering-sg", "guestiptype": "Shared", "supportedservices": "Dhcp,Dns,UserData,SecurityGroup", "specifyVlan" : "False", @@ -103,7 +103,7 @@ "shared_network_sg": { "name": "Shared-Network-SG-Test", "displaytext": "Shared-Network_SG-Test", - "networkofferingid":"1", + "networkofferingid":"", "vlan" : "", "gateway" :"", "netmask" :"255.255.255.0", @@ -123,8 +123,8 @@ "cidr": "10.0.0.1/24" }, "shared_network_offering": { - "name": "MySharedOffering", - "displaytext": "MySharedOffering", + "name": "SharedNwOffering", + "displaytext": "SharedNwOffering", "guestiptype": "Shared", "supportedservices": "Dhcp,Dns,UserData", "specifyVlan" : "False", @@ -140,7 +140,7 @@ "ingress_rule": { "protocol": "TCP", "startport": "22", - "endport": "22", + "endport": "80", "cidrlist": "0.0.0.0/0" }, "ostype": "CentOS 5.3 (64-bit)", diff --git a/vmware-base/src/com/cloud/hypervisor/vmware/util/VmwareContext.java b/vmware-base/src/com/cloud/hypervisor/vmware/util/VmwareContext.java index 4c3ff55ae4d..eaa205ebba3 100755 --- a/vmware-base/src/com/cloud/hypervisor/vmware/util/VmwareContext.java +++ b/vmware-base/src/com/cloud/hypervisor/vmware/util/VmwareContext.java @@ -37,6 +37,7 @@ import java.util.Map; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLSession; +import javax.xml.ws.soap.SOAPFaultException; import org.apache.log4j.Logger; @@ -638,16 +639,18 @@ public class VmwareContext { public void close() { clearStockObjects(); try { + s_logger.info("Disconnecting VMware session"); _vimClient.disconnect(); + } catch(SOAPFaultException sfe) { + s_logger.debug("Tried to disconnect a session that is no longer valid"); } catch (Exception e) { s_logger.warn("Unexpected exception: ", e); + } finally { + if (_pool != null) { + _pool.unregisterOutstandingContext(this); + } + unregisterOutstandingContext(); } - - if (_pool != null) { - _pool.unregisterOutstandingContext(this); - } - - unregisterOutstandingContext(); } public static class TrustAllManager implements javax.net.ssl.TrustManager, javax.net.ssl.X509TrustManager {