X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=snaps%2Fopenstack%2Ftests%2Fcreate_instance_tests.py;h=bc664fe206f3a8f2b0fe1b85be9b28f84c35589b;hb=3482f6e28e26025043f61efb90892d886f5909cc;hp=aef8e6e3a0a2bda440855086e07324ce697027f6;hpb=841b5699185442f2cc6f87a776fd707045be5587;p=snaps.git diff --git a/snaps/openstack/tests/create_instance_tests.py b/snaps/openstack/tests/create_instance_tests.py index aef8e6e..bc664fe 100644 --- a/snaps/openstack/tests/create_instance_tests.py +++ b/snaps/openstack/tests/create_instance_tests.py @@ -20,18 +20,28 @@ import unittest import uuid import os +from neutronclient.common.exceptions import InvalidIpForSubnetClient +from novaclient.exceptions import BadRequest from snaps import file_utils -from snaps.openstack.create_flavor import OpenStackFlavor, FlavorSettings -from snaps.openstack.create_image import OpenStackImage, ImageSettings +from snaps.config.router import RouterConfig +from snaps.config.keypair import KeypairConfig +from snaps.openstack import create_network, create_router +from snaps.config.flavor import FlavorConfig +from snaps.openstack.create_flavor import OpenStackFlavor +from snaps.config.image import ImageConfig +from snaps.openstack.create_image import OpenStackImage from snaps.openstack.create_instance import ( - VmInstanceSettings, OpenStackVmInstance, FloatingIpSettings) -from snaps.openstack.create_keypairs import OpenStackKeypair, KeypairSettings -from snaps.openstack.create_network import OpenStackNetwork, PortSettings + VmInstanceSettings, OpenStackVmInstance, FloatingIpSettings, + VmInstanceSettingsError, FloatingIpSettingsError) +from snaps.openstack.create_keypairs import OpenStackKeypair +from snaps.openstack.create_network import ( + OpenStackNetwork, PortSettings, NetworkSettings, SubnetSettings) from snaps.openstack.create_router import OpenStackRouter from snaps.openstack.create_security_group import ( SecurityGroupSettings, OpenStackSecurityGroup, SecurityGroupRuleSettings, Direction, Protocol) +from snaps.openstack.create_volume import OpenStackVolume, VolumeSettings from snaps.openstack.tests import openstack_tests, validation_utils from snaps.openstack.tests.os_source_file_test import ( OSIntegrationTestCase, OSComponentTestCase) @@ -50,27 +60,27 @@ class VmInstanceSettingsUnitTests(unittest.TestCase): """ def test_no_params(self): - with self.assertRaises(Exception): + with self.assertRaises(VmInstanceSettingsError): VmInstanceSettings() def test_empty_config(self): - with self.assertRaises(Exception): + with self.assertRaises(VmInstanceSettingsError): VmInstanceSettings(config=dict()) def test_name_only(self): - with self.assertRaises(Exception): + with self.assertRaises(VmInstanceSettingsError): VmInstanceSettings(name='foo') def test_config_with_name_only(self): - with self.assertRaises(Exception): + with self.assertRaises(VmInstanceSettingsError): VmInstanceSettings(config={'name': 'foo'}) def test_name_flavor_only(self): - with self.assertRaises(Exception): + with self.assertRaises(VmInstanceSettingsError): VmInstanceSettings(name='foo', flavor='bar') def test_config_with_name_flavor_only(self): - with self.assertRaises(Exception): + with self.assertRaises(VmInstanceSettingsError): VmInstanceSettings(config={'name': 'foo', 'flavor': 'bar'}) def test_name_flavor_port_only(self): @@ -89,6 +99,7 @@ class VmInstanceSettingsUnitTests(unittest.TestCase): self.assertEqual(300, settings.vm_delete_timeout) self.assertEqual(180, settings.ssh_connect_timeout) self.assertIsNone(settings.availability_zone) + self.assertIsNone(settings.volume_names) def test_config_with_name_flavor_port_only(self): port_settings = PortSettings(name='foo-port', network_name='bar-net') @@ -106,20 +117,20 @@ class VmInstanceSettingsUnitTests(unittest.TestCase): self.assertEqual(300, settings.vm_delete_timeout) self.assertEqual(180, settings.ssh_connect_timeout) self.assertIsNone(settings.availability_zone) + self.assertIsNone(settings.volume_names) def test_all(self): port_settings = PortSettings(name='foo-port', network_name='bar-net') fip_settings = FloatingIpSettings(name='foo-fip', port_name='bar-port', router_name='foo-bar-router') - settings = VmInstanceSettings(name='foo', flavor='bar', - port_settings=[port_settings], - security_group_names=['sec_grp_1'], - floating_ip_settings=[fip_settings], - sudo_user='joe', vm_boot_timeout=999, - vm_delete_timeout=333, - ssh_connect_timeout=111, - availability_zone='server name') + settings = VmInstanceSettings( + name='foo', flavor='bar', port_settings=[port_settings], + security_group_names=['sec_grp_1'], + floating_ip_settings=[fip_settings], sudo_user='joe', + vm_boot_timeout=999, vm_delete_timeout=333, + ssh_connect_timeout=111, availability_zone='server name', + volume_names=['vol1']) self.assertEqual('foo', settings.name) self.assertEqual('bar', settings.flavor) self.assertEqual(1, len(settings.port_settings)) @@ -138,6 +149,7 @@ class VmInstanceSettingsUnitTests(unittest.TestCase): self.assertEqual(333, settings.vm_delete_timeout) self.assertEqual(111, settings.ssh_connect_timeout) self.assertEqual('server name', settings.availability_zone) + self.assertEqual('vol1', settings.volume_names[0]) def test_config_all(self): port_settings = PortSettings(name='foo-port', network_name='bar-net') @@ -149,7 +161,8 @@ class VmInstanceSettingsUnitTests(unittest.TestCase): 'security_group_names': ['sec_grp_1'], 'floating_ips': [fip_settings], 'sudo_user': 'joe', 'vm_boot_timeout': 999, 'vm_delete_timeout': 333, - 'ssh_connect_timeout': 111, 'availability_zone': 'server name'}) + 'ssh_connect_timeout': 111, 'availability_zone': 'server name', + 'volume_names': ['vol2']}) self.assertEqual('foo', settings.name) self.assertEqual('bar', settings.flavor) self.assertEqual(1, len(settings.port_settings)) @@ -167,6 +180,7 @@ class VmInstanceSettingsUnitTests(unittest.TestCase): self.assertEqual(333, settings.vm_delete_timeout) self.assertEqual(111, settings.ssh_connect_timeout) self.assertEqual('server name', settings.availability_zone) + self.assertEqual('vol2', settings.volume_names[0]) class FloatingIpSettingsUnitTests(unittest.TestCase): @@ -175,42 +189,53 @@ class FloatingIpSettingsUnitTests(unittest.TestCase): """ def test_no_params(self): - with self.assertRaises(Exception): + with self.assertRaises(FloatingIpSettingsError): FloatingIpSettings() def test_empty_config(self): - with self.assertRaises(Exception): + with self.assertRaises(FloatingIpSettingsError): FloatingIpSettings(**dict()) def test_name_only(self): - with self.assertRaises(Exception): + with self.assertRaises(FloatingIpSettingsError): FloatingIpSettings(name='foo') def test_config_with_name_only(self): - with self.assertRaises(Exception): + with self.assertRaises(FloatingIpSettingsError): FloatingIpSettings(**{'name': 'foo'}) def test_name_port_only(self): - with self.assertRaises(Exception): + with self.assertRaises(FloatingIpSettingsError): FloatingIpSettings(name='foo', port_name='bar') def test_config_with_name_port_only(self): - with self.assertRaises(Exception): + with self.assertRaises(FloatingIpSettingsError): FloatingIpSettings(**{'name': 'foo', 'port_name': 'bar'}) def test_name_router_only(self): - with self.assertRaises(Exception): + with self.assertRaises(FloatingIpSettingsError): FloatingIpSettings(name='foo', router_name='bar') def test_config_with_name_router_only(self): - with self.assertRaises(Exception): + with self.assertRaises(FloatingIpSettingsError): FloatingIpSettings(**{'name': 'foo', 'router_name': 'bar'}) - def test_name_port_router_only(self): + def test_name_port_router_name_only(self): settings = FloatingIpSettings(name='foo', port_name='foo-port', router_name='bar-router') self.assertEqual('foo', settings.name) self.assertEqual('foo-port', settings.port_name) + self.assertIsNone(settings.port_id) + self.assertEqual('bar-router', settings.router_name) + self.assertIsNone(settings.subnet_name) + self.assertTrue(settings.provisioning) + + def test_name_port_router_id_only(self): + settings = FloatingIpSettings(name='foo', port_id='foo-port', + router_name='bar-router') + self.assertEqual('foo', settings.name) + self.assertEqual('foo-port', settings.port_id) + self.assertIsNone(settings.port_name) self.assertEqual('bar-router', settings.router_name) self.assertIsNone(settings.subnet_name) self.assertTrue(settings.provisioning) @@ -221,6 +246,7 @@ class FloatingIpSettingsUnitTests(unittest.TestCase): 'router_name': 'bar-router'}) self.assertEqual('foo', settings.name) self.assertEqual('foo-port', settings.port_name) + self.assertIsNone(settings.port_id) self.assertEqual('bar-router', settings.router_name) self.assertIsNone(settings.subnet_name) self.assertTrue(settings.provisioning) @@ -232,6 +258,7 @@ class FloatingIpSettingsUnitTests(unittest.TestCase): provisioning=False) self.assertEqual('foo', settings.name) self.assertEqual('foo-port', settings.port_name) + self.assertIsNone(settings.port_id) self.assertEqual('bar-router', settings.router_name) self.assertEqual('bar-subnet', settings.subnet_name) self.assertFalse(settings.provisioning) @@ -243,6 +270,7 @@ class FloatingIpSettingsUnitTests(unittest.TestCase): 'provisioning': False}) self.assertEqual('foo', settings.name) self.assertEqual('foo-port', settings.port_name) + self.assertIsNone(settings.port_id) self.assertEqual('bar-router', settings.router_name) self.assertEqual('bar-subnet', settings.subnet_name) self.assertFalse(settings.provisioning) @@ -297,8 +325,8 @@ class SimpleHealthCheck(OSIntegrationTestCase): # Create Flavor self.flavor_creator = OpenStackFlavor( self.admin_os_creds, - FlavorSettings(name=guid + '-flavor-name', ram=128, disk=10, - vcpus=1, metadata=self.flavor_metadata)) + FlavorConfig(name=guid + '-flavor-name', ram=256, disk=10, + vcpus=1, metadata=self.flavor_metadata)) self.flavor_creator.create() except Exception as e: self.tearDown() @@ -404,8 +432,8 @@ class CreateInstanceSimpleTests(OSIntegrationTestCase): # Create Flavor self.flavor_creator = OpenStackFlavor( self.admin_os_creds, - FlavorSettings(name=guid + '-flavor-name', ram=128, disk=10, - vcpus=2, metadata=self.flavor_metadata)) + FlavorConfig(name=guid + '-flavor-name', ram=256, disk=10, + vcpus=2, metadata=self.flavor_metadata)) self.flavor_creator.create() # Create Network @@ -473,15 +501,15 @@ class CreateInstanceSimpleTests(OSIntegrationTestCase): self.image_creator.image_settings) vm_inst = self.inst_creator.create() - self.assertEqual(1, len( - nova_utils.get_servers_by_name(self.nova, instance_settings.name))) + self.assertIsNotNone(nova_utils.get_server( + self.nova, vm_inst_settings=instance_settings)) # Delete instance nova_utils.delete_vm_instance(self.nova, vm_inst) self.assertTrue(self.inst_creator.vm_deleted(block=True)) - self.assertEqual(0, len( - nova_utils.get_servers_by_name(self.nova, instance_settings.name))) + self.assertIsNone(nova_utils.get_server( + self.nova, vm_inst_settings=instance_settings)) # Exception should not be thrown self.inst_creator.clean() @@ -542,12 +570,12 @@ class CreateInstanceSingleNetworkTests(OSIntegrationTestCase): # Create Flavor self.flavor_creator = OpenStackFlavor( self.admin_os_creds, - FlavorSettings(name=guid + '-flavor-name', ram=128, disk=10, - vcpus=2, metadata=self.flavor_metadata)) + FlavorConfig(name=guid + '-flavor-name', ram=256, disk=10, + vcpus=2, metadata=self.flavor_metadata)) self.flavor_creator.create() self.keypair_creator = OpenStackKeypair( - self.os_creds, KeypairSettings( + self.os_creds, KeypairConfig( name=self.keypair_name, public_filepath=self.keypair_pub_filepath, private_filepath=self.keypair_priv_filepath)) @@ -591,12 +619,6 @@ class CreateInstanceSingleNetworkTests(OSIntegrationTestCase): 'Unexpected exception cleaning keypair with message - %s', e) - if os.path.isfile(self.keypair_pub_filepath): - os.remove(self.keypair_pub_filepath) - - if os.path.isfile(self.keypair_priv_filepath): - os.remove(self.keypair_priv_filepath) - if self.flavor_creator: try: self.flavor_creator.clean() @@ -664,11 +686,11 @@ class CreateInstanceSingleNetworkTests(OSIntegrationTestCase): self.image_creator.image_settings, keypair_settings=self.keypair_creator.keypair_settings) self.inst_creators.append(inst_creator) - vm_inst = inst_creator.create() + vm_inst = inst_creator.create(block=True) self.assertEqual(ip_1, inst_creator.get_port_ip(self.port_1_name)) self.assertTrue(inst_creator.vm_active(block=True)) - self.assertEqual(vm_inst, inst_creator.get_vm_inst()) + self.assertEqual(vm_inst.id, inst_creator.get_vm_inst().id) def test_ssh_client_fip_before_active(self): """ @@ -683,6 +705,7 @@ class CreateInstanceSingleNetworkTests(OSIntegrationTestCase): name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=[port_settings], + security_group_names=[self.sec_grp_creator.sec_grp_settings.name], floating_ip_settings=[FloatingIpSettings( name=self.floating_ip_name, port_name=self.port_1_name, router_name=self.pub_net_config.router_settings.name)]) @@ -700,9 +723,7 @@ class CreateInstanceSingleNetworkTests(OSIntegrationTestCase): ip = inst_creator.get_port_ip(port_settings.name) self.assertTrue(check_dhcp_lease(inst_creator, ip)) - inst_creator.add_security_group( - self.sec_grp_creator.get_security_group()) - self.assertEqual(vm_inst, inst_creator.get_vm_inst()) + self.assertEqual(vm_inst.id, inst_creator.get_vm_inst().id) self.assertTrue(validate_ssh_client(inst_creator)) @@ -719,6 +740,7 @@ class CreateInstanceSingleNetworkTests(OSIntegrationTestCase): name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=[port_settings], + security_group_names=[self.sec_grp_creator.sec_grp_settings.name], floating_ip_settings=[FloatingIpSettings( name=self.floating_ip_name, port_name=self.port_1_name, router_name=self.pub_net_config.router_settings.name)]) @@ -738,12 +760,278 @@ class CreateInstanceSingleNetworkTests(OSIntegrationTestCase): ip = inst_creator.get_port_ip(port_settings.name) self.assertTrue(check_dhcp_lease(inst_creator, ip)) - inst_creator.add_security_group( - self.sec_grp_creator.get_security_group()) - self.assertEqual(vm_inst, inst_creator.get_vm_inst()) + self.assertEqual(vm_inst.id, inst_creator.get_vm_inst().id) self.assertTrue(validate_ssh_client(inst_creator)) + def test_ssh_client_fip_second_creator(self): + """ + Tests the ability to access a VM via SSH and a floating IP via a + creator that is identical to the original creator. + """ + port_settings = PortSettings( + name=self.port_1_name, + network_name=self.pub_net_config.network_settings.name) + + instance_settings = VmInstanceSettings( + name=self.vm_inst_name, + flavor=self.flavor_creator.flavor_settings.name, + port_settings=[port_settings], + security_group_names=[self.sec_grp_creator.sec_grp_settings.name], + floating_ip_settings=[FloatingIpSettings( + name=self.floating_ip_name, port_name=self.port_1_name, + router_name=self.pub_net_config.router_settings.name)]) + + inst_creator = OpenStackVmInstance( + self.os_creds, instance_settings, + self.image_creator.image_settings, + keypair_settings=self.keypair_creator.keypair_settings) + self.inst_creators.append(inst_creator) + + # block=True will force the create() method to block until the + vm_inst = inst_creator.create(block=True) + self.assertIsNotNone(vm_inst) + + self.assertTrue(inst_creator.vm_active(block=True)) + + ip = inst_creator.get_port_ip(port_settings.name) + self.assertTrue(check_dhcp_lease(inst_creator, ip)) + + self.assertEqual(vm_inst.id, inst_creator.get_vm_inst().id) + + self.assertTrue(validate_ssh_client(inst_creator)) + + inst_creator2 = OpenStackVmInstance( + self.os_creds, instance_settings, + self.image_creator.image_settings, + keypair_settings=self.keypair_creator.keypair_settings) + inst_creator2.create() + self.assertTrue(validate_ssh_client(inst_creator2)) + + +class CreateInstanceIPv6NetworkTests(OSIntegrationTestCase): + """ + Test for the CreateInstance class with a single NIC/Port with Floating IPs + """ + + def setUp(self): + """ + Instantiates the CreateImage object that is responsible for downloading + and creating an OS image file within OpenStack + """ + super(self.__class__, self).__start__() + + self.nova = nova_utils.nova_client(self.os_creds) + self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4()) + self.keypair_priv_filepath = 'tmp/' + self.guid + self.keypair_pub_filepath = self.keypair_priv_filepath + '.pub' + self.keypair_name = self.guid + '-kp' + self.vm_inst_name = self.guid + '-inst' + self.port1_name = self.guid + 'port1' + self.port2_name = self.guid + 'port2' + + # Initialize for tearDown() + self.image_creator = None + self.network_creator = None + self.router_creator = None + self.flavor_creator = None + self.keypair_creator = None + self.sec_grp_creator = None + self.inst_creator = None + + os_image_settings = openstack_tests.cirros_image_settings( + name=self.guid + '-image', image_metadata=self.image_metadata) + try: + self.image_creator = OpenStackImage( + self.os_creds, os_image_settings) + self.image_creator.create() + + self.flavor_creator = OpenStackFlavor( + self.admin_os_creds, + FlavorConfig( + name=self.guid + '-flavor-name', ram=256, disk=10, vcpus=2, + metadata=self.flavor_metadata)) + self.flavor_creator.create() + + self.keypair_creator = OpenStackKeypair( + self.os_creds, KeypairConfig( + name=self.keypair_name, + public_filepath=self.keypair_pub_filepath, + private_filepath=self.keypair_priv_filepath)) + self.keypair_creator.create() + + sec_grp_name = self.guid + '-sec-grp' + rule1 = SecurityGroupRuleSettings(sec_grp_name=sec_grp_name, + direction=Direction.ingress, + protocol=Protocol.icmp) + rule2 = SecurityGroupRuleSettings(sec_grp_name=sec_grp_name, + direction=Direction.ingress, + protocol=Protocol.tcp, + port_range_min=22, + port_range_max=22) + self.sec_grp_creator = OpenStackSecurityGroup( + self.os_creds, + SecurityGroupSettings(name=sec_grp_name, + rule_settings=[rule1, rule2])) + self.sec_grp_creator.create() + except Exception as e: + self.tearDown() + raise e + + def tearDown(self): + """ + Cleans the created object + """ + if self.inst_creator: + try: + self.inst_creator.clean() + except Exception as e: + logger.error( + 'Unexpected exception cleaning VM instance with message ' + '- %s', e) + + if self.keypair_creator: + try: + self.keypair_creator.clean() + except Exception as e: + logger.error( + 'Unexpected exception cleaning keypair with message - %s', + e) + + if self.flavor_creator: + try: + self.flavor_creator.clean() + except Exception as e: + logger.error( + 'Unexpected exception cleaning flavor with message - %s', + e) + + if self.sec_grp_creator: + try: + self.sec_grp_creator.clean() + except Exception as e: + logger.error( + 'Unexpected exception cleaning security group with message' + ' - %s', e) + + if self.router_creator: + try: + self.router_creator.clean() + except Exception as e: + logger.error( + 'Unexpected exception cleaning router with message - %s', + e) + + if self.network_creator: + try: + self.network_creator.clean() + except Exception as e: + logger.error( + 'Unexpected exception cleaning network with message - %s', + e) + + if self.image_creator and not self.image_creator.image_settings.exists: + try: + self.image_creator.clean() + except Exception as e: + logger.error( + 'Unexpected exception cleaning image with message - %s', e) + + super(self.__class__, self).__clean__() + + def test_v4fip_v6overlay(self): + """ + Tests the ability to assign an IPv4 floating IP to an IPv6 overlay + network when the external network does not have an IPv6 subnet. + """ + subnet_settings = SubnetSettings( + name=self.guid + '-subnet', cidr='1:1:0:0:0:0:0:0/64', + ip_version=6) + network_settings = NetworkSettings( + name=self.guid + '-net', subnet_settings=[subnet_settings]) + router_settings = RouterConfig( + name=self.guid + '-router', external_gateway=self.ext_net_name, + internal_subnets=[subnet_settings.name]) + + # Create Network + self.network_creator = OpenStackNetwork( + self.os_creds, network_settings) + self.network_creator.create() + + # Create Router + self.router_creator = OpenStackRouter( + self.os_creds, router_settings) + self.router_creator.create() + + port_settings = PortSettings( + name=self.port1_name, network_name=network_settings.name) + + instance_settings = VmInstanceSettings( + name=self.vm_inst_name, + flavor=self.flavor_creator.flavor_settings.name, + port_settings=[port_settings], + security_group_names=[self.sec_grp_creator.sec_grp_settings.name], + floating_ip_settings=[FloatingIpSettings( + name='fip1', port_name=self.port1_name, + router_name=router_settings.name)]) + + self.inst_creator = OpenStackVmInstance( + self.os_creds, instance_settings, + self.image_creator.image_settings, + keypair_settings=self.keypair_creator.keypair_settings) + + with self.assertRaises(BadRequest): + self.inst_creator.create(block=True) + + def test_fip_v4and6_overlay(self): + """ + Tests the ability to assign an IPv4 floating IP to an IPv6 overlay + network when the external network does not have an IPv6 subnet. + """ + subnet4_settings = SubnetSettings( + name=self.guid + '-subnet4', cidr='10.0.1.0/24', + ip_version=4) + subnet6_settings = SubnetSettings( + name=self.guid + '-subnet6', cidr='1:1:0:0:0:0:0:0/64', + ip_version=6) + network_settings = NetworkSettings( + name=self.guid + '-net', + subnet_settings=[subnet4_settings, subnet6_settings]) + router_settings = RouterConfig( + name=self.guid + '-router', external_gateway=self.ext_net_name, + internal_subnets=[subnet4_settings.name]) + + # Create Network + self.network_creator = OpenStackNetwork( + self.os_creds, network_settings) + self.network_creator.create() + + # Create Router + self.router_creator = OpenStackRouter( + self.os_creds, router_settings) + self.router_creator.create() + + port_settings = PortSettings( + name=self.port1_name, network_name=network_settings.name) + + instance_settings = VmInstanceSettings( + name=self.vm_inst_name, + flavor=self.flavor_creator.flavor_settings.name, + port_settings=[port_settings], + security_group_names=[self.sec_grp_creator.sec_grp_settings.name], + floating_ip_settings=[FloatingIpSettings( + name='fip1', port_name=self.port1_name, + router_name=router_settings.name)]) + + self.inst_creator = OpenStackVmInstance( + self.os_creds, instance_settings, + self.image_creator.image_settings, + keypair_settings=self.keypair_creator.keypair_settings) + + self.inst_creator.create(block=True) + ssh_client = self.inst_creator.ssh_client() + self.assertIsNotNone(ssh_client) + class CreateInstancePortManipulationTests(OSIntegrationTestCase): """ @@ -790,8 +1078,8 @@ class CreateInstancePortManipulationTests(OSIntegrationTestCase): # Create Flavor self.flavor_creator = OpenStackFlavor( self.admin_os_creds, - FlavorSettings(name=guid + '-flavor-name', ram=128, disk=10, - vcpus=2, metadata=self.flavor_metadata)) + FlavorConfig(name=guid + '-flavor-name', ram=256, disk=10, + vcpus=2, metadata=self.flavor_metadata)) self.flavor_creator.create() except Exception as e: self.tearDown() @@ -882,7 +1170,7 @@ class CreateInstancePortManipulationTests(OSIntegrationTestCase): self.os_creds, instance_settings, self.image_creator.image_settings) - with self.assertRaises(Exception): + with self.assertRaises(InvalidIpForSubnetClient): self.inst_creator.create() def test_set_custom_valid_mac(self): @@ -1083,8 +1371,8 @@ class CreateInstanceOnComputeHost(OSIntegrationTestCase): # Create Flavor self.flavor_creator = OpenStackFlavor( self.admin_os_creds, - FlavorSettings(name=guid + '-flavor-name', ram=512, disk=1, - vcpus=1, metadata=self.flavor_metadata)) + FlavorConfig(name=guid + '-flavor-name', ram=512, disk=1, + vcpus=1, metadata=self.flavor_metadata)) self.flavor_creator.create() # Create Image @@ -1139,11 +1427,11 @@ class CreateInstanceOnComputeHost(OSIntegrationTestCase): """ from snaps.openstack.utils import nova_utils nova = nova_utils.nova_client(self.admin_os_creds) - zones = nova_utils.get_nova_availability_zones(nova) + zone_hosts = nova_utils.get_availability_zone_hosts(nova) # Create Instance on each server/zone ctr = 0 - for zone in zones: + for zone in zone_hosts: inst_name = self.vm_inst_name + '-' + zone ctr += 1 port_settings = PortSettings( @@ -1164,7 +1452,7 @@ class CreateInstanceOnComputeHost(OSIntegrationTestCase): # Validate instances to ensure they've been deployed to the correct # server index = 0 - for zone in zones: + for zone in zone_hosts: creator = self.inst_creators[index] self.assertTrue(creator.vm_active(block=True)) info = creator.get_vm_info() @@ -1249,14 +1537,14 @@ class CreateInstancePubPrivNetTests(OSIntegrationTestCase): # Create Flavor self.flavor_creator = OpenStackFlavor( self.admin_os_creds, - FlavorSettings(name=self.guid + '-flavor-name', ram=512, - disk=10, vcpus=2, - metadata=self.flavor_metadata)) + FlavorConfig(name=self.guid + '-flavor-name', ram=512, + disk=10, vcpus=2, + metadata=self.flavor_metadata)) self.flavor_creator.create() # Create Keypair self.keypair_creator = OpenStackKeypair( - self.os_creds, KeypairSettings( + self.os_creds, KeypairConfig( name=self.keypair_name, public_filepath=self.keypair_pub_filepath, private_filepath=self.keypair_priv_filepath)) @@ -1276,9 +1564,9 @@ class CreateInstancePubPrivNetTests(OSIntegrationTestCase): SecurityGroupSettings(name=sec_grp_name, rule_settings=[rule1, rule2])) self.sec_grp_creator.create() - except Exception as e: + except: self.tearDown() - raise Exception(str(e)) + raise def tearDown(self): """ @@ -1300,12 +1588,6 @@ class CreateInstancePubPrivNetTests(OSIntegrationTestCase): 'Unexpected exception cleaning keypair with message - %s', e) - if os.path.isfile(self.keypair_pub_filepath): - os.remove(self.keypair_pub_filepath) - - if os.path.isfile(self.keypair_priv_filepath): - os.remove(self.keypair_priv_filepath) - if self.flavor_creator: try: self.flavor_creator.clean() @@ -1374,6 +1656,7 @@ class CreateInstancePubPrivNetTests(OSIntegrationTestCase): name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=ports_settings, + security_group_names=[self.sec_grp_creator.sec_grp_settings.name], floating_ip_settings=[FloatingIpSettings( name=self.floating_ip_name, port_name=self.port_1_name, router_name=self.pub_net_config.router_settings.name)]) @@ -1385,7 +1668,7 @@ class CreateInstancePubPrivNetTests(OSIntegrationTestCase): vm_inst = self.inst_creator.create(block=True) - self.assertEqual(vm_inst, self.inst_creator.get_vm_inst()) + self.assertEqual(vm_inst.id, self.inst_creator.get_vm_inst().id) # Effectively blocks until VM has been properly activated self.assertTrue(self.inst_creator.vm_active(block=True)) @@ -1393,22 +1676,10 @@ class CreateInstancePubPrivNetTests(OSIntegrationTestCase): ip = self.inst_creator.get_port_ip(ports_settings[0].name) self.assertTrue(check_dhcp_lease(self.inst_creator, ip)) - # Add security group to VM - self.inst_creator.add_security_group( - self.sec_grp_creator.get_security_group()) - # Effectively blocks until VM's ssh port has been opened self.assertTrue(self.inst_creator.vm_ssh_active(block=True)) - # TODO - Refactor config_nics() to return a status that can be - # validated here. - self.inst_creator.config_nics() - - # TODO - *** ADD VALIDATION HERE *** - # TODO - Add validation that both floating IPs work - # TODO - Add tests where only one NIC has a floating IP - # TODO - Add tests where one attempts to place a floating IP on a - # network/router without an external gateway + self.assertEqual(0, self.inst_creator.config_nics()) class InstanceSecurityGroupTests(OSIntegrationTestCase): @@ -1462,9 +1733,9 @@ class InstanceSecurityGroupTests(OSIntegrationTestCase): # Create Flavor self.flavor_creator = OpenStackFlavor( self.admin_os_creds, - FlavorSettings(name=self.guid + '-flavor-name', ram=128, - disk=10, vcpus=2, - metadata=self.flavor_metadata)) + FlavorConfig(name=self.guid + '-flavor-name', ram=256, + disk=10, vcpus=2, + metadata=self.flavor_metadata)) self.flavor_creator.create() self.port_settings = PortSettings( @@ -1723,17 +1994,19 @@ def validate_ssh_client(instance_creator): if ssh_active: ssh_client = instance_creator.ssh_client() if ssh_client: - out = ssh_client.exec_command('pwd')[1] + try: + out = ssh_client.exec_command('pwd')[1] + channel = out.channel + in_buffer = channel.in_buffer + pwd_out = in_buffer.read(1024) + if not pwd_out or len(pwd_out) < 10: + return False + return True + finally: + ssh_client.close() else: return False - channel = out.channel - in_buffer = channel.in_buffer - pwd_out = in_buffer.read(1024) - if not pwd_out or len(pwd_out) < 10: - return False - return True - return False @@ -1794,8 +2067,8 @@ class CreateInstanceFromThreePartImage(OSIntegrationTestCase): # Create Flavor self.flavor_creator = OpenStackFlavor( self.admin_os_creds, - FlavorSettings(name=guid + '-flavor-name', ram=128, disk=10, - vcpus=2, metadata=self.flavor_metadata)) + FlavorConfig(name=guid + '-flavor-name', ram=256, disk=10, + vcpus=2, metadata=self.flavor_metadata)) self.flavor_creator.create() # Create Network @@ -1915,8 +2188,8 @@ class CreateInstanceMockOfflineTests(OSComponentTestCase): # Create Flavor self.flavor_creator = OpenStackFlavor( self.os_creds, - FlavorSettings( - name=self.guid + '-flavor-name', ram=128, disk=10, + FlavorConfig( + name=self.guid + '-flavor-name', ram=256, disk=10, vcpus=1)) self.flavor_creator.create() except Exception as e: @@ -2047,9 +2320,9 @@ class CreateInstanceMockOfflineTests(OSComponentTestCase): image_settings = self.image_creator.image_settings test_image_creator = OpenStackImage( self.os_creds, - ImageSettings(name=image_settings.name, - image_user=image_settings.image_user, - exists=True)) + ImageConfig( + name=image_settings.name, image_user=image_settings.image_user, + exists=True)) test_image_creator.create() self.assertEqual(self.image_creator.get_image().id, test_image_creator.get_image().id) @@ -2079,11 +2352,11 @@ class CreateInstanceMockOfflineTests(OSComponentTestCase): self.image_creator.create() metadata = { - 'cirros': - {'config': - {'name': os_image_settings.name, - 'image_user': os_image_settings.image_user, - 'exists': True}}} + 'cirros': { + 'config': { + 'name': os_image_settings.name, + 'image_user': os_image_settings.image_user, + 'exists': True}}} test_image_settings = openstack_tests.cirros_image_settings( image_metadata=metadata) test_image = OpenStackImage(self.os_creds, test_image_settings) @@ -2114,22 +2387,22 @@ class CreateInstanceMockOfflineTests(OSComponentTestCase): openstack_tests.CIRROS_DEFAULT_RAMDISK_IMAGE_URL, self.tmpDir) metadata = { - 'cirros': - {'config': - {'name': self.image_name, - 'image_user': openstack_tests.CIRROS_USER, - 'image_file': self.image_file.name, - 'format': openstack_tests.DEFAULT_IMAGE_FORMAT, - 'kernel_image_settings': - {'name': self.image_name + '-kernel', - 'image_user': openstack_tests.CIRROS_USER, - 'image_file': kernel_file.name, - 'format': openstack_tests.DEFAULT_IMAGE_FORMAT}, - 'ramdisk_image_settings': - {'name': self.image_name + '-ramdisk', - 'image_user': openstack_tests.CIRROS_USER, - 'image_file': ramdisk_file.name, - 'format': openstack_tests.DEFAULT_IMAGE_FORMAT}}}} + 'cirros': { + 'config': { + 'name': self.image_name, + 'image_user': openstack_tests.CIRROS_USER, + 'image_file': self.image_file.name, + 'format': openstack_tests.DEFAULT_IMAGE_FORMAT, + 'kernel_image_settings': { + 'name': self.image_name + '-kernel', + 'image_user': openstack_tests.CIRROS_USER, + 'image_file': kernel_file.name, + 'format': openstack_tests.DEFAULT_IMAGE_FORMAT}, + 'ramdisk_image_settings': { + 'name': self.image_name + '-ramdisk', + 'image_user': openstack_tests.CIRROS_USER, + 'image_file': ramdisk_file.name, + 'format': openstack_tests.DEFAULT_IMAGE_FORMAT}}}} os_image_settings = openstack_tests.cirros_image_settings( name=self.image_name, image_metadata=metadata) @@ -2342,9 +2615,9 @@ class CreateInstanceMockOfflineTests(OSComponentTestCase): image_settings = self.image_creator.image_settings test_image_creator = OpenStackImage( self.os_creds, - ImageSettings(name=image_settings.name, - image_user=image_settings.image_user, - exists=True)) + ImageConfig( + name=image_settings.name, image_user=image_settings.image_user, + exists=True)) test_image_creator.create() self.assertEqual(self.image_creator.get_image().id, test_image_creator.get_image().id) @@ -2361,6 +2634,409 @@ class CreateInstanceMockOfflineTests(OSComponentTestCase): self.assertTrue(self.inst_creator.vm_active(block=True)) +class CreateInstanceTwoNetTests(OSIntegrationTestCase): + """ + Tests the ability of two VMs to communicate when attached to separate + private networks that are tied together with a router. + """ + + def setUp(self): + """ + Instantiates the CreateImage object that is responsible for downloading + and creating an OS image file within OpenStack + """ + super(self.__class__, self).__start__() + + cidr1 = '10.200.201.0/24' + cidr2 = '10.200.202.0/24' + static_gateway_ip1 = '10.200.201.1' + static_gateway_ip2 = '10.200.202.1' + self.ip1 = '10.200.201.5' + self.ip2 = '10.200.202.5' + + self.nova = nova_utils.nova_client(self.os_creds) + + # Initialize for tearDown() + self.image_creator = None + self.network_creators = list() + self.router_creator = None + self.flavor_creator = None + self.sec_grp_creator = None + self.inst_creators = list() + + self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4()) + self.vm_inst1_name = self.guid + '-inst1' + self.vm_inst2_name = self.guid + '-inst2' + self.port_1_name = self.guid + '-vm1-port' + self.port_2_name = self.guid + '-vm2-port' + self.net_config_1 = NetworkSettings( + name=self.guid + '-net1', + subnet_settings=[ + create_network.SubnetSettings( + cidr=cidr1, name=self.guid + '-subnet1', + gateway_ip=static_gateway_ip1)]) + self.net_config_2 = NetworkSettings( + name=self.guid + '-net2', + subnet_settings=[ + create_network.SubnetSettings( + cidr=cidr2, name=self.guid + '-subnet2', + gateway_ip=static_gateway_ip2)]) + + image_name = self.__class__.__name__ + '-' + str(uuid.uuid4()) + os_image_settings = openstack_tests.cirros_image_settings( + name=image_name, image_metadata=self.image_metadata) + + try: + # Create Image + self.image_creator = OpenStackImage(self.os_creds, + os_image_settings) + self.image_creator.create() + + # First network is public + self.network_creators.append(OpenStackNetwork( + self.os_creds, self.net_config_1)) + # Second network is private + self.network_creators.append(OpenStackNetwork( + self.os_creds, self.net_config_2)) + for network_creator in self.network_creators: + network_creator.create() + + port_settings = [ + create_network.PortSettings( + name=self.guid + '-router-port1', + ip_addrs=[{ + 'subnet_name': + self.net_config_1.subnet_settings[0].name, + 'ip': static_gateway_ip1 + }], + network_name=self.net_config_1.name, + project_name=self.os_creds.project_name), + create_network.PortSettings( + name=self.guid + '-router-port2', + ip_addrs=[{ + 'subnet_name': + self.net_config_2.subnet_settings[0].name, + 'ip': static_gateway_ip2 + }], + network_name=self.net_config_2.name, + project_name=self.os_creds.project_name)] + + router_settings = RouterConfig( + name=self.guid + '-pub-router', port_settings=port_settings) + self.router_creator = create_router.OpenStackRouter( + self.os_creds, router_settings) + self.router_creator.create() + + # Create Flavor + self.flavor_creator = OpenStackFlavor( + self.admin_os_creds, + FlavorConfig(name=self.guid + '-flavor-name', ram=512, + disk=10, vcpus=2, + metadata=self.flavor_metadata)) + self.flavor_creator.create() + + sec_grp_name = self.guid + '-sec-grp' + rule1 = SecurityGroupRuleSettings(sec_grp_name=sec_grp_name, + direction=Direction.ingress, + protocol=Protocol.icmp) + self.sec_grp_creator = OpenStackSecurityGroup( + self.os_creds, + SecurityGroupSettings(name=sec_grp_name, + rule_settings=[rule1])) + self.sec_grp_creator.create() + except: + self.tearDown() + raise + + def tearDown(self): + """ + Cleans the created objects + """ + for inst_creator in self.inst_creators: + try: + inst_creator.clean() + except Exception as e: + logger.error( + 'Unexpected exception cleaning VM instance with message ' + '- %s', e) + + if self.flavor_creator: + try: + self.flavor_creator.clean() + except Exception as e: + logger.error( + 'Unexpected exception cleaning flavor with message - %s', + e) + + if self.router_creator: + try: + self.router_creator.clean() + except Exception as e: + logger.error( + 'Unexpected exception cleaning router with message - %s', + e) + + for network_creator in self.network_creators: + try: + network_creator.clean() + except Exception as e: + logger.error( + 'Unexpected exception cleaning network with message - %s', + e) + + if self.sec_grp_creator: + try: + self.sec_grp_creator.clean() + except Exception as e: + logger.error( + 'Unexpected exception cleaning security group with message' + ' - %s', e) + + if self.image_creator and not self.image_creator.image_settings.exists: + try: + self.image_creator.clean() + except Exception as e: + logger.error( + 'Unexpected exception cleaning image with message - %s', e) + + super(self.__class__, self).__clean__() + + def test_ping_via_router(self): + """ + Tests the creation of two OpenStack instances with one port on + different private networks wit a router in between to ensure that they + can ping + through + """ + # Create ports/NICs for instance + ports_settings = [] + ctr = 1 + for network_creator in self.network_creators: + ports_settings.append(PortSettings( + name=self.guid + '-port-' + str(ctr), + network_name=network_creator.network_settings.name)) + ctr += 1 + + # Configure instances + instance1_settings = VmInstanceSettings( + name=self.vm_inst1_name, + flavor=self.flavor_creator.flavor_settings.name, + userdata=_get_ping_userdata(self.ip2), + port_settings=[PortSettings( + name=self.port_1_name, + ip_addrs=[{ + 'subnet_name': + self.net_config_1.subnet_settings[0].name, + 'ip': self.ip1 + }], + network_name=self.network_creators[0].network_settings.name)]) + instance2_settings = VmInstanceSettings( + name=self.vm_inst2_name, + flavor=self.flavor_creator.flavor_settings.name, + userdata=_get_ping_userdata(self.ip1), + port_settings=[PortSettings( + name=self.port_2_name, + ip_addrs=[{ + 'subnet_name': + self.net_config_2.subnet_settings[0].name, + 'ip': self.ip2 + }], + network_name=self.network_creators[1].network_settings.name)]) + + # Create instances + self.inst_creators.append(OpenStackVmInstance( + self.os_creds, instance1_settings, + self.image_creator.image_settings)) + self.inst_creators.append(OpenStackVmInstance( + self.os_creds, instance2_settings, + self.image_creator.image_settings)) + + for inst_creator in self.inst_creators: + inst_creator.create(block=True) + + # Check for DHCP lease + self.assertTrue(check_dhcp_lease(self.inst_creators[0], self.ip1)) + self.assertTrue(check_dhcp_lease(self.inst_creators[1], self.ip2)) + + # Effectively blocks until VM has been properly activated + self.assertTrue(check_ping(self.inst_creators[0])) + self.assertTrue(check_ping(self.inst_creators[1])) + + +class CreateInstanceVolumeTests(OSIntegrationTestCase): + """ + Simple instance creation with an attached volume + """ + + def setUp(self): + """ + Instantiates the CreateImage object that is responsible for downloading + and creating an OS image file + within OpenStack + """ + super(self.__class__, self).__start__() + + guid = self.__class__.__name__ + '-' + str(uuid.uuid4()) + self.vm_inst_name = guid + '-inst' + self.nova = nova_utils.nova_client(self.os_creds) + os_image_settings = openstack_tests.cirros_image_settings( + name=guid + '-image', image_metadata=self.image_metadata) + + net_config = openstack_tests.get_priv_net_config( + net_name=guid + '-pub-net', subnet_name=guid + '-pub-subnet', + router_name=guid + '-pub-router', external_net=self.ext_net_name) + + self.volume_settings1 = VolumeSettings( + name=self.__class__.__name__ + '-' + str(guid) + '-1') + self.volume_settings2 = VolumeSettings( + name=self.__class__.__name__ + '-' + str(guid) + '-2') + + # Initialize for tearDown() + self.image_creator = None + self.flavor_creator = None + + self.network_creator = None + self.inst_creator = None + self.volume_creator1 = None + self.volume_creator2 = None + + try: + # Create Image + self.image_creator = OpenStackImage(self.os_creds, + os_image_settings) + self.image_creator.create() + + # Create Flavor + self.flavor_creator = OpenStackFlavor( + self.admin_os_creds, + FlavorConfig(name=guid + '-flavor-name', ram=256, disk=1, + vcpus=2, metadata=self.flavor_metadata)) + self.flavor_creator.create() + + # Create Network + self.network_creator = OpenStackNetwork( + self.os_creds, net_config.network_settings) + self.network_creator.create() + + self.port_settings = PortSettings( + name=guid + '-port', + network_name=net_config.network_settings.name) + + self.volume_creator1 = OpenStackVolume( + self.os_creds, self.volume_settings1) + self.volume_creator1.create(block=True) + + self.volume_creator2 = OpenStackVolume( + self.os_creds, self.volume_settings2) + self.volume_creator2.create(block=True) + + except Exception as e: + self.tearDown() + raise e + + def tearDown(self): + """ + Cleans the created object + """ + if self.inst_creator: + try: + self.inst_creator.clean() + except Exception as e: + logger.error( + 'Unexpected exception cleaning VM instance with message ' + '- %s', e) + + if self.flavor_creator: + try: + self.flavor_creator.clean() + except Exception as e: + logger.error( + 'Unexpected exception cleaning flavor with message - %s', + e) + + if self.network_creator: + try: + self.network_creator.clean() + except Exception as e: + logger.error( + 'Unexpected exception cleaning network with message - %s', + e) + + if self.volume_creator2: + try: + self.volume_creator2.clean() + except Exception as e: + logger.error( + 'Unexpected exception cleaning volume with message - %s', + e) + + if self.volume_creator1: + try: + self.volume_creator1.clean() + except Exception as e: + logger.error( + 'Unexpected exception cleaning volume with message - %s', + e) + + if self.image_creator and not self.image_creator.image_settings.exists: + try: + self.image_creator.clean() + except Exception as e: + logger.error( + 'Unexpected exception cleaning image with message - %s', e) + + super(self.__class__, self).__clean__() + + def test_create_instance_with_one_volume(self): + """ + Tests the creation of an OpenStack instance with a single volume. + """ + instance_settings = VmInstanceSettings( + name=self.vm_inst_name, + flavor=self.flavor_creator.flavor_settings.name, + port_settings=[self.port_settings], + volume_names=[self.volume_settings1.name]) + + self.inst_creator = OpenStackVmInstance( + self.os_creds, instance_settings, + self.image_creator.image_settings) + + vm_inst = self.inst_creator.create(block=True) + self.assertIsNotNone(nova_utils.get_server( + self.nova, vm_inst_settings=instance_settings)) + + self.assertIsNotNone(vm_inst) + self.assertEqual(1, len(vm_inst.volume_ids)) + self.assertEqual(self.volume_creator1.get_volume().id, + vm_inst.volume_ids[0]['id']) + + def test_create_instance_with_two_volumes(self): + """ + Tests the creation of an OpenStack instance with a single volume. + """ + instance_settings = VmInstanceSettings( + name=self.vm_inst_name, + flavor=self.flavor_creator.flavor_settings.name, + port_settings=[self.port_settings], + volume_names=[self.volume_settings1.name, + self.volume_settings2.name]) + + self.inst_creator = OpenStackVmInstance( + self.os_creds, instance_settings, + self.image_creator.image_settings) + + vm_inst = self.inst_creator.create(block=True) + self.assertIsNotNone(nova_utils.get_server( + self.nova, vm_inst_settings=instance_settings)) + + self.assertIsNotNone(vm_inst) + self.assertEqual(2, len(vm_inst.volume_ids)) + self.assertEqual(self.volume_creator1.get_volume().id, + vm_inst.volume_ids[0]['id']) + self.assertEqual(self.volume_creator2.get_volume().id, + vm_inst.volume_ids[1]['id']) + + def check_dhcp_lease(inst_creator, ip, timeout=160): """ Returns true if the expected DHCP lease has been acquired @@ -2388,3 +3064,43 @@ def check_dhcp_lease(inst_creator, ip, timeout=160): logger.debug('Full console output -\n' + full_log) return found + + +def _get_ping_userdata(test_ip): + """ + Returns the post VM creation script to be added into the VM's userdata + :param test_ip: the IP value to substitute into the script + :return: the bash script contents + """ + if test_ip: + return ("#!/bin/sh\n\n" + "while true; do\n" + " ping -c 1 %s 2>&1 >/dev/null\n" + " RES=$?\n" + " if [ \"Z$RES\" = \"Z0\" ] ; then\n" + " echo 'vPing OK'\n" + " break\n" + " else\n" + " echo 'vPing KO'\n" + " fi\n" + " sleep 1\n" + "done\n" % test_ip) + return None + + +def check_ping(vm_creator, timeout=160): + """ + Check for VM for ping result + """ + tries = 0 + + while tries < timeout: + time.sleep(1) + p_console = vm_creator.get_console_output() + if "vPing OK" in p_console: + return True + elif "failed to read iid from metadata" in p_console or tries > 5: + return False + tries += 1 + + return False