X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=snaps%2Fopenstack%2Ftests%2Fcreate_stack_tests.py;h=a320aa018696838ed0615ae4879e90d0868fe00d;hb=e6ec3766be49d69a44ca1e1348bbf5e6ed692c84;hp=d56c967a9df05af12a62b2cd64c5fa03c9f06f32;hpb=a759ebf00044dd6031fbeed6f7d31099dbdfbba5;p=snaps.git diff --git a/snaps/openstack/tests/create_stack_tests.py b/snaps/openstack/tests/create_stack_tests.py index d56c967..a320aa0 100644 --- a/snaps/openstack/tests/create_stack_tests.py +++ b/snaps/openstack/tests/create_stack_tests.py @@ -12,12 +12,18 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +import os import time import pkg_resources from heatclient.exc import HTTPBadRequest + +import snaps from snaps import file_utils -from snaps.openstack.create_flavor import OpenStackFlavor, FlavorSettings +from snaps.config.flavor import FlavorConfig +from snaps.config.image import ImageConfig +from snaps.config.stack import StackConfigError, StackConfig +from snaps.openstack.create_flavor import OpenStackFlavor from snaps.openstack.create_image import OpenStackImage try: @@ -30,10 +36,12 @@ import unittest import uuid from snaps.openstack import create_stack -from snaps.openstack.create_stack import StackSettings, StackSettingsError -from snaps.openstack.tests import openstack_tests +from snaps.openstack.create_stack import ( + StackSettings, StackCreationError, StackError, OpenStackHeatStack) +from snaps.openstack.tests import openstack_tests, create_instance_tests from snaps.openstack.tests.os_source_file_test import OSIntegrationTestCase -from snaps.openstack.utils import heat_utils +from snaps.openstack.utils import ( + heat_utils, neutron_utils, nova_utils, keystone_utils) __author__ = 'spisarski' @@ -46,19 +54,19 @@ class StackSettingsUnitTests(unittest.TestCase): """ def test_no_params(self): - with self.assertRaises(StackSettingsError): + with self.assertRaises(StackConfigError): StackSettings() def test_empty_config(self): - with self.assertRaises(StackSettingsError): + with self.assertRaises(StackConfigError): StackSettings(**dict()) def test_name_only(self): - with self.assertRaises(StackSettingsError): + with self.assertRaises(StackConfigError): StackSettings(name='foo') def test_config_with_name_only(self): - with self.assertRaises(StackSettingsError): + with self.assertRaises(StackConfigError): StackSettings(**{'name': 'foo'}) def test_config_minimum_template(self): @@ -67,7 +75,7 @@ class StackSettingsUnitTests(unittest.TestCase): self.assertEqual('foo', settings.template) self.assertIsNone(settings.template_path) self.assertIsNone(settings.env_values) - self.assertEqual(create_stack.STACK_COMPLETE_TIMEOUT, + self.assertEqual(snaps.config.stack.STACK_COMPLETE_TIMEOUT, settings.stack_create_timeout) def test_config_minimum_template_path(self): @@ -76,7 +84,7 @@ class StackSettingsUnitTests(unittest.TestCase): self.assertIsNone(settings.template) self.assertEqual('foo', settings.template_path) self.assertIsNone(settings.env_values) - self.assertEqual(create_stack.STACK_COMPLETE_TIMEOUT, + self.assertEqual(snaps.config.stack.STACK_COMPLETE_TIMEOUT, settings.stack_create_timeout) def test_minimum_template(self): @@ -85,7 +93,7 @@ class StackSettingsUnitTests(unittest.TestCase): self.assertEqual('foo', settings.template) self.assertIsNone(settings.template_path) self.assertIsNone(settings.env_values) - self.assertEqual(create_stack.STACK_COMPLETE_TIMEOUT, + self.assertEqual(snaps.config.stack.STACK_COMPLETE_TIMEOUT, settings.stack_create_timeout) def test_minimum_template_path(self): @@ -94,7 +102,7 @@ class StackSettingsUnitTests(unittest.TestCase): self.assertEqual('foo', settings.template_path) self.assertIsNone(settings.template) self.assertIsNone(settings.env_values) - self.assertEqual(create_stack.STACK_COMPLETE_TIMEOUT, + self.assertEqual(snaps.config.stack.STACK_COMPLETE_TIMEOUT, settings.stack_create_timeout) def test_all(self): @@ -122,40 +130,43 @@ class StackSettingsUnitTests(unittest.TestCase): class CreateStackSuccessTests(OSIntegrationTestCase): """ - Test for the CreateStack class defined in create_stack.py + Tests for the OpenStackHeatStack class defined in create_stack.py """ def setUp(self): - """ - Instantiates the CreateStack object that is responsible for downloading - and creating an OS stack file within OpenStack - """ - super(self.__class__, self).__start__() + self.user_roles = ['heat_stack_owner'] - self.guid = str(uuid.uuid4()) + super(self.__class__, self).__start__() - self.heat_creds = self.admin_os_creds - self.heat_creds.project_name = self.admin_os_creds.project_name + self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4()) - self.heat_cli = heat_utils.heat_client(self.heat_creds) + self.heat_cli = heat_utils.heat_client(self.os_creds, self.os_session) self.stack_creator = None self.image_creator = OpenStackImage( - self.heat_creds, openstack_tests.cirros_image_settings( - name=self.__class__.__name__ + '-' + str(self.guid) + '-image', + self.os_creds, openstack_tests.cirros_image_settings( + name=self.guid + '-image', image_metadata=self.image_metadata)) self.image_creator.create() # Create Flavor + flavor_config = openstack_tests.get_flavor_config( + name=self.guid + '-flavor-name', ram=256, disk=10, + vcpus=1, metadata=self.flavor_metadata) self.flavor_creator = OpenStackFlavor( - self.admin_os_creds, - FlavorSettings(name=self.guid + '-flavor-name', ram=128, disk=10, - vcpus=1)) + self.admin_os_creds, flavor_config) self.flavor_creator.create() + self.network_name = self.guid + '-net' + self.subnet_name = self.guid + '-subnet' + self.vm_inst_name = self.guid + '-inst' + self.env_values = { 'image_name': self.image_creator.image_settings.name, - 'flavor_name': self.flavor_creator.flavor_settings.name} + 'flavor_name': self.flavor_creator.flavor_settings.name, + 'net_name': self.network_name, + 'subnet_name': self.subnet_name, + 'inst_name': self.vm_inst_name} self.heat_tmplt_path = pkg_resources.resource_filename( 'snaps.openstack.tests.heat', 'test_heat_template.yaml') @@ -191,12 +202,12 @@ class CreateStackSuccessTests(OSIntegrationTestCase): # Create Stack # Set the default stack settings, then set any custom parameters sent # from the app - stack_settings = StackSettings( + stack_settings = StackConfig( name=self.__class__.__name__ + '-' + str(self.guid) + '-stack', template_path=self.heat_tmplt_path, env_values=self.env_values) - self.stack_creator = create_stack.OpenStackHeatStack(self.heat_creds, - stack_settings) + self.stack_creator = OpenStackHeatStack( + self.os_creds, stack_settings) created_stack = self.stack_creator.create() self.assertIsNotNone(created_stack) @@ -205,8 +216,30 @@ class CreateStackSuccessTests(OSIntegrationTestCase): self.assertIsNotNone(retrieved_stack) self.assertEqual(created_stack.name, retrieved_stack.name) self.assertEqual(created_stack.id, retrieved_stack.id) - self.assertIsNotNone(self.stack_creator.get_outputs()) - self.assertEquals(0, len(self.stack_creator.get_outputs())) + self.assertEqual(0, len(self.stack_creator.get_outputs())) + + derived_creator = create_stack.generate_creator( + self.os_creds, retrieved_stack, + [self.image_creator.image_settings]) + derived_stack = derived_creator.get_stack() + self.assertEqual(retrieved_stack, derived_stack) + + def test_create_stack_short_timeout(self): + """ + Tests the creation of an OpenStack stack from Heat template file. + """ + # Create Stack + # Set the default stack settings, then set any custom parameters sent + # from the app + stack_settings = StackConfig( + name=self.__class__.__name__ + '-' + str(self.guid) + '-stack', + template_path=self.heat_tmplt_path, + env_values=self.env_values, stack_create_timeout=0) + + self.stack_creator = OpenStackHeatStack( + self.os_creds, stack_settings) + with self.assertRaises(StackCreationError): + self.stack_creator.create() def test_create_stack_template_dict(self): """ @@ -217,12 +250,12 @@ class CreateStackSuccessTests(OSIntegrationTestCase): # from the app template_dict = heat_utils.parse_heat_template_str( file_utils.read_file(self.heat_tmplt_path)) - stack_settings = StackSettings( + stack_settings = StackConfig( name=self.__class__.__name__ + '-' + str(self.guid) + '-stack', template=template_dict, env_values=self.env_values) - self.stack_creator = create_stack.OpenStackHeatStack(self.heat_creds, - stack_settings) + self.stack_creator = OpenStackHeatStack( + self.os_creds, stack_settings) created_stack = self.stack_creator.create() self.assertIsNotNone(created_stack) @@ -231,8 +264,7 @@ class CreateStackSuccessTests(OSIntegrationTestCase): self.assertIsNotNone(retrieved_stack) self.assertEqual(created_stack.name, retrieved_stack.name) self.assertEqual(created_stack.id, retrieved_stack.id) - self.assertIsNotNone(self.stack_creator.get_outputs()) - self.assertEquals(0, len(self.stack_creator.get_outputs())) + self.assertEqual(0, len(self.stack_creator.get_outputs())) def test_create_delete_stack(self): """ @@ -242,12 +274,12 @@ class CreateStackSuccessTests(OSIntegrationTestCase): # Create Stack template_dict = heat_utils.parse_heat_template_str( file_utils.read_file(self.heat_tmplt_path)) - stack_settings = StackSettings( + stack_settings = StackConfig( name=self.__class__.__name__ + '-' + str(self.guid) + '-stack', template=template_dict, env_values=self.env_values) - self.stack_creator = create_stack.OpenStackHeatStack(self.heat_creds, - stack_settings) + self.stack_creator = OpenStackHeatStack( + self.os_creds, stack_settings) created_stack = self.stack_creator.create() self.assertIsNotNone(created_stack) @@ -256,9 +288,8 @@ class CreateStackSuccessTests(OSIntegrationTestCase): self.assertIsNotNone(retrieved_stack) self.assertEqual(created_stack.name, retrieved_stack.name) self.assertEqual(created_stack.id, retrieved_stack.id) - self.assertIsNotNone(self.stack_creator.get_outputs()) - self.assertEquals(0, len(self.stack_creator.get_outputs())) - self.assertEqual(create_stack.STATUS_CREATE_COMPLETE, + self.assertEqual(0, len(self.stack_creator.get_outputs())) + self.assertEqual(snaps.config.stack.STATUS_CREATE_COMPLETE, self.stack_creator.get_status()) # Delete Stack manually @@ -269,7 +300,7 @@ class CreateStackSuccessTests(OSIntegrationTestCase): while time.time() < end_time: status = heat_utils.get_stack_status(self.heat_cli, retrieved_stack.id) - if status == create_stack.STATUS_DELETE_COMPLETE: + if status == snaps.config.stack.STATUS_DELETE_COMPLETE: deleted = True break @@ -287,12 +318,12 @@ class CreateStackSuccessTests(OSIntegrationTestCase): # Create Stack template_dict = heat_utils.parse_heat_template_str( file_utils.read_file(self.heat_tmplt_path)) - stack_settings = StackSettings( + stack_settings = StackConfig( name=self.__class__.__name__ + '-' + str(self.guid) + '-stack', template=template_dict, env_values=self.env_values) - self.stack_creator = create_stack.OpenStackHeatStack(self.heat_creds, - stack_settings) + self.stack_creator = OpenStackHeatStack( + self.os_creds, stack_settings) created_stack1 = self.stack_creator.create() retrieved_stack = heat_utils.get_stack_by_id(self.heat_cli, @@ -300,26 +331,746 @@ class CreateStackSuccessTests(OSIntegrationTestCase): self.assertIsNotNone(retrieved_stack) self.assertEqual(created_stack1.name, retrieved_stack.name) self.assertEqual(created_stack1.id, retrieved_stack.id) - self.assertIsNotNone(self.stack_creator.get_outputs()) self.assertEqual(0, len(self.stack_creator.get_outputs())) # Should be retrieving the instance data - stack_creator2 = create_stack.OpenStackHeatStack(self.heat_creds, - stack_settings) + stack_creator2 = OpenStackHeatStack(self.os_creds, stack_settings) stack2 = stack_creator2.create() self.assertEqual(created_stack1.id, stack2.id) + def test_retrieve_network_creators(self): + """ + Tests the creation of an OpenStack stack from Heat template file and + the retrieval of the network creator. + """ + stack_settings = StackConfig( + name=self.__class__.__name__ + '-' + str(self.guid) + '-stack', + template_path=self.heat_tmplt_path, + env_values=self.env_values) + self.stack_creator = OpenStackHeatStack( + self.os_creds, stack_settings) + created_stack = self.stack_creator.create() + self.assertIsNotNone(created_stack) + + net_creators = self.stack_creator.get_network_creators() + self.assertIsNotNone(net_creators) + self.assertEqual(1, len(net_creators)) + self.assertEqual(self.network_name, net_creators[0].get_network().name) -class CreateStackNegativeTests(OSIntegrationTestCase): + # Need to use 'admin' creds as heat creates objects under it's own + # project/tenant + neutron = neutron_utils.neutron_client( + self.os_creds, self.os_session) + keystone = keystone_utils.keystone_client( + self.os_creds, self.os_session) + net_by_name = neutron_utils.get_network( + neutron, keystone, network_name=net_creators[0].get_network().name) + self.assertEqual(net_creators[0].get_network(), net_by_name) + self.assertIsNotNone(neutron_utils.get_network_by_id( + neutron, net_creators[0].get_network().id)) + + self.assertEqual(1, len(net_creators[0].get_network().subnets)) + subnet = net_creators[0].get_network().subnets[0] + subnet_by_name = neutron_utils.get_subnet( + neutron, net_creators[0].get_network(), subnet_name=subnet.name) + self.assertEqual(subnet, subnet_by_name) + + subnet_by_id = neutron_utils.get_subnet_by_id(neutron, subnet.id) + self.assertIsNotNone(subnet_by_id) + self.assertEqual(subnet_by_name, subnet_by_id) + + def test_retrieve_vm_inst_creators(self): + """ + Tests the creation of an OpenStack stack from Heat template file and + the retrieval of the network creator. + """ + stack_settings = StackConfig( + name=self.__class__.__name__ + '-' + str(self.guid) + '-stack', + template_path=self.heat_tmplt_path, + env_values=self.env_values) + self.stack_creator = OpenStackHeatStack( + self.os_creds, stack_settings) + created_stack = self.stack_creator.create() + self.assertIsNotNone(created_stack) + + vm_inst_creators = self.stack_creator.get_vm_inst_creators() + self.assertIsNotNone(vm_inst_creators) + self.assertEqual(1, len(vm_inst_creators)) + self.assertEqual(self.vm_inst_name, + vm_inst_creators[0].get_vm_inst().name) + + nova = nova_utils.nova_client(self.os_creds, self.os_session) + neutron = neutron_utils.neutron_client(self.os_creds, self.os_session) + keystone = keystone_utils.keystone_client(self.os_creds, self.os_session) + vm_inst_by_name = nova_utils.get_server( + nova, neutron, keystone, + server_name=vm_inst_creators[0].get_vm_inst().name) + + self.assertEqual(vm_inst_creators[0].get_vm_inst(), vm_inst_by_name) + self.assertIsNotNone(nova_utils.get_server_object_by_id( + nova, neutron, keystone, vm_inst_creators[0].get_vm_inst().id)) + + +class CreateStackFloatingIpTests(OSIntegrationTestCase): + """ + Tests to ensure that floating IPs can be accessed via an + OpenStackVmInstance object obtained from the OpenStackHeatStack instance + """ + + def setUp(self): + self.user_roles = ['heat_stack_owner', 'admin'] + + super(self.__class__, self).__start__() + + self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4()) + + self.heat_cli = heat_utils.heat_client(self.os_creds, self.os_session) + self.stack_creator = None + + self.image_creator = OpenStackImage( + self.os_creds, openstack_tests.cirros_image_settings( + name=self.guid + '-image', + image_metadata=self.image_metadata)) + self.image_creator.create() + + self.network_name = self.guid + '-net' + self.subnet_name = self.guid + '-subnet' + self.flavor1_name = self.guid + '-flavor1' + self.flavor2_name = self.guid + '-flavor2' + self.sec_grp_name = self.guid + '-sec_grp' + self.vm_inst1_name = self.guid + '-inst1' + self.vm_inst2_name = self.guid + '-inst2' + self.keypair_name = self.guid + '-kp' + + self.env_values = { + 'image1_name': self.image_creator.image_settings.name, + 'image2_name': self.image_creator.image_settings.name, + 'flavor1_name': self.flavor1_name, + 'flavor2_name': self.flavor2_name, + 'net_name': self.network_name, + 'subnet_name': self.subnet_name, + 'inst1_name': self.vm_inst1_name, + 'inst2_name': self.vm_inst2_name, + 'keypair_name': self.keypair_name, + 'external_net_name': self.ext_net_name, + 'security_group_name': self.sec_grp_name} + + self.heat_tmplt_path = pkg_resources.resource_filename( + 'snaps.openstack.tests.heat', 'floating_ip_heat_template.yaml') + + self.vm_inst_creators = list() + + def tearDown(self): + """ + Cleans the stack and downloaded stack file + """ + if self.stack_creator: + try: + self.stack_creator.clean() + except: + pass + + if self.image_creator: + try: + self.image_creator.clean() + except: + pass + + for vm_inst_creator in self.vm_inst_creators: + try: + keypair_settings = vm_inst_creator.keypair_settings + if keypair_settings and keypair_settings.private_filepath: + expanded_path = os.path.expanduser( + keypair_settings.private_filepath) + os.chmod(expanded_path, 0o755) + os.remove(expanded_path) + except: + pass + + super(self.__class__, self).__clean__() + + def test_connect_via_ssh_heat_vm(self): + """ + Tests the creation of an OpenStack stack from Heat template file and + the retrieval of two VM instance creators and attempt to connect via + SSH to the first one with a floating IP. + """ + stack_settings = StackConfig( + name=self.__class__.__name__ + '-' + str(self.guid) + '-stack', + template_path=self.heat_tmplt_path, + env_values=self.env_values) + self.stack_creator = OpenStackHeatStack( + self.os_creds, stack_settings, + [self.image_creator.image_settings]) + created_stack = self.stack_creator.create() + self.assertIsNotNone(created_stack) + + self.vm_inst_creators = self.stack_creator.get_vm_inst_creators( + heat_keypair_option='private_key') + self.assertIsNotNone(self.vm_inst_creators) + self.assertEqual(2, len(self.vm_inst_creators)) + + for vm_inst_creator in self.vm_inst_creators: + if vm_inst_creator.get_vm_inst().name == self.vm_inst1_name: + self.assertTrue( + create_instance_tests.validate_ssh_client(vm_inst_creator)) + else: + vm_settings = vm_inst_creator.instance_settings + self.assertEqual(0, len(vm_settings.floating_ip_settings)) + + def test_connect_via_ssh_heat_vm_derived(self): + """ + Tests the the retrieval of two VM instance creators from a derived + OpenStackHeatStack object and attempt to connect via + SSH to the first one with a floating IP. + """ + stack_settings = StackConfig( + name=self.__class__.__name__ + '-' + str(self.guid) + '-stack', + template_path=self.heat_tmplt_path, + env_values=self.env_values) + self.stack_creator = OpenStackHeatStack( + self.os_creds, stack_settings, + [self.image_creator.image_settings]) + created_stack = self.stack_creator.create() + self.assertIsNotNone(created_stack) + + derived_stack = create_stack.generate_creator( + self.os_creds, created_stack, + [self.image_creator.image_settings]) + + self.vm_inst_creators = derived_stack.get_vm_inst_creators( + heat_keypair_option='private_key') + self.assertIsNotNone(self.vm_inst_creators) + self.assertEqual(2, len(self.vm_inst_creators)) + + for vm_inst_creator in self.vm_inst_creators: + if vm_inst_creator.get_vm_inst().name == self.vm_inst1_name: + self.assertTrue( + create_instance_tests.validate_ssh_client(vm_inst_creator)) + else: + vm_settings = vm_inst_creator.instance_settings + self.assertEqual(0, len(vm_settings.floating_ip_settings)) + + +class CreateStackNestedResourceTests(OSIntegrationTestCase): """ - Negative test cases for the CreateStack class + Tests to ensure that nested heat templates work """ def setUp(self): + self.user_roles = ['heat_stack_owner'] + super(self.__class__, self).__start__() - self.heat_creds = self.admin_os_creds - self.heat_creds.project_name = self.admin_os_creds.project_name + self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4()) + + self.heat_cli = heat_utils.heat_client(self.os_creds, self.os_session) + self.stack_creator = None + + self.image_creator = OpenStackImage( + self.os_creds, openstack_tests.cirros_image_settings( + name="{}-{}".format(self.guid, 'image'), + image_metadata=self.image_metadata)) + self.image_creator.create() + + flavor_config = openstack_tests.get_flavor_config( + name="{}-{}".format(self.guid, 'flavor-name'), ram=256, disk=10, + vcpus=1, metadata=self.flavor_metadata) + self.flavor_creator = OpenStackFlavor( + self.admin_os_creds, flavor_config) + self.flavor_creator.create() + + env_values = { + 'network_name': self.guid + '-network', + 'public_network': self.ext_net_name, + 'agent_image': self.image_creator.image_settings.name, + 'agent_flavor': self.flavor_creator.flavor_settings.name, + 'key_name': self.guid + '-key', + } + + heat_tmplt_path = pkg_resources.resource_filename( + 'snaps.openstack.tests.heat', 'agent-group.yaml') + heat_resource_path = pkg_resources.resource_filename( + 'snaps.openstack.tests.heat', 'agent.yaml') + + stack_settings = StackConfig( + name="{}-{}".format( + self.__class__.__name__, str(self.guid) + '-stack'), + template_path=heat_tmplt_path, + resource_files=[heat_resource_path], + env_values=env_values) + + self.stack_creator = OpenStackHeatStack( + self.os_creds, stack_settings, + [self.image_creator.image_settings]) + + self.vm_inst_creators = list() + + def tearDown(self): + """ + Cleans the stack and downloaded stack file + """ + if self.stack_creator: + try: + self.stack_creator.clean() + except: + pass + + if self.image_creator: + try: + self.image_creator.clean() + except: + pass + + if self.flavor_creator: + try: + self.flavor_creator.clean() + except: + pass + + for vm_inst_creator in self.vm_inst_creators: + try: + keypair_settings = vm_inst_creator.keypair_settings + if keypair_settings and keypair_settings.private_filepath: + expanded_path = os.path.expanduser( + keypair_settings.private_filepath) + os.chmod(expanded_path, 0o755) + os.remove(expanded_path) + except: + pass + + super(self.__class__, self).__clean__() + + def test_nested(self): + """ + Tests the creation of an OpenStack stack from Heat template file and + the retrieval of two VM instance creators and attempt to connect via + SSH to the first one with a floating IP. + """ + created_stack = self.stack_creator.create() + self.assertIsNotNone(created_stack) + + self.vm_inst_creators = self.stack_creator.get_vm_inst_creators( + heat_keypair_option='private_key') + self.assertIsNotNone(self.vm_inst_creators) + self.assertEqual(1, len(self.vm_inst_creators)) + + for vm_inst_creator in self.vm_inst_creators: + self.assertTrue( + create_instance_tests.validate_ssh_client(vm_inst_creator)) + + +class CreateStackRouterTests(OSIntegrationTestCase): + """ + Tests for the CreateStack class defined in create_stack.py where the + target is a Network, Subnet, and Router + """ + + def setUp(self): + """ + Instantiates the CreateStack object that is responsible for downloading + and creating an OS stack file within OpenStack + """ + self.user_roles = ['heat_stack_owner'] + + super(self.__class__, self).__start__() + + self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4()) + + self.heat_cli = heat_utils.heat_client(self.os_creds, self.os_session) + self.neutron = neutron_utils.neutron_client( + self.os_creds, self.os_session) + self.stack_creator = None + + self.net_name = self.guid + '-net' + self.subnet_name = self.guid + '-subnet' + self.router_name = self.guid + '-router' + + self.env_values = { + 'net_name': self.net_name, + 'subnet_name': self.subnet_name, + 'router_name': self.router_name, + 'external_net_name': self.ext_net_name} + + self.heat_tmplt_path = pkg_resources.resource_filename( + 'snaps.openstack.tests.heat', 'router_heat_template.yaml') + + stack_settings = StackConfig( + name=self.__class__.__name__ + '-' + str(self.guid) + '-stack', + template_path=self.heat_tmplt_path, + env_values=self.env_values) + self.stack_creator = OpenStackHeatStack( + self.os_creds, stack_settings) + self.created_stack = self.stack_creator.create() + self.assertIsNotNone(self.created_stack) + + def tearDown(self): + """ + Cleans the stack and downloaded stack file + """ + if self.stack_creator: + try: + self.stack_creator.clean() + except: + pass + + super(self.__class__, self).__clean__() + + def test_retrieve_router_creator(self): + """ + Tests the creation of an OpenStack stack from Heat template file and + the retrieval of an OpenStackRouter creator/state machine instance + """ + router_creators = self.stack_creator.get_router_creators() + self.assertEqual(1, len(router_creators)) + + creator = router_creators[0] + self.assertEqual(self.router_name, creator.router_settings.name) + + router = creator.get_router() + + ext_net = neutron_utils.get_network( + self.neutron, self.keystone, network_name=self.ext_net_name) + self.assertEqual(ext_net.id, router.external_network_id) + + +class CreateStackVolumeTests(OSIntegrationTestCase): + """ + Tests to ensure that floating IPs can be accessed via an + OpenStackVolume object obtained from the OpenStackHeatStack instance + """ + + def setUp(self): + + self.user_roles = ['heat_stack_owner', 'admin'] + + super(self.__class__, self).__start__() + + self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4()) + + self.heat_cli = heat_utils.heat_client(self.os_creds, self.os_session) + self.stack_creator = None + + self.volume_name = self.guid + '-volume' + self.volume_type_name = self.guid + '-volume-type' + + self.env_values = { + 'volume_name': self.volume_name, + 'volume_type_name': self.volume_type_name} + + self.heat_tmplt_path = pkg_resources.resource_filename( + 'snaps.openstack.tests.heat', 'volume_heat_template.yaml') + + stack_settings = StackConfig( + name=self.__class__.__name__ + '-' + str(self.guid) + '-stack', + template_path=self.heat_tmplt_path, + env_values=self.env_values) + self.stack_creator = OpenStackHeatStack( + self.os_creds, stack_settings) + self.created_stack = self.stack_creator.create() + self.assertIsNotNone(self.created_stack) + + def tearDown(self): + """ + Cleans the stack and downloaded stack file + """ + if self.stack_creator: + try: + self.stack_creator.clean() + except: + pass + + super(self.__class__, self).__clean__() + + def test_retrieve_volume_creator(self): + """ + Tests the creation of an OpenStack stack from Heat template file and + the retrieval of an OpenStackVolume creator/state machine instance + """ + volume_creators = self.stack_creator.get_volume_creators() + self.assertEqual(1, len(volume_creators)) + + creator = volume_creators[0] + self.assertEqual(self.volume_name, creator.volume_settings.name) + self.assertEqual(self.volume_name, creator.get_volume().name) + self.assertEqual(self.volume_type_name, + creator.volume_settings.type_name) + self.assertEqual(self.volume_type_name, creator.get_volume().type) + self.assertEqual(1, creator.volume_settings.size) + self.assertEqual(1, creator.get_volume().size) + + def test_retrieve_volume_type_creator(self): + """ + Tests the creation of an OpenStack stack from Heat template file and + the retrieval of an OpenStackVolume creator/state machine instance + """ + volume_type_creators = self.stack_creator.get_volume_type_creators() + self.assertEqual(1, len(volume_type_creators)) + + creator = volume_type_creators[0] + self.assertIsNotNone(creator) + + volume_type = creator.get_volume_type() + self.assertIsNotNone(volume_type) + + self.assertEqual(self.volume_type_name, volume_type.name) + self.assertTrue(volume_type.public) + self.assertIsNone(volume_type.qos_spec) + + # TODO - Add encryption back and find out why it broke in Pike + # encryption = volume_type.encryption + # self.assertIsNotNone(encryption) + # self.assertIsNone(encryption.cipher) + # self.assertEqual('front-end', encryption.control_location) + # self.assertIsNone(encryption.key_size) + # self.assertEqual(u'nova.volume.encryptors.luks.LuksEncryptor', + # encryption.provider) + # self.assertEqual(volume_type.id, encryption.volume_type_id) + + +class CreateStackFlavorTests(OSIntegrationTestCase): + """ + Tests to ensure that floating IPs can be accessed via an + OpenStackFlavor object obtained from the OpenStackHeatStack instance + """ + + def setUp(self): + + self.user_roles = ['heat_stack_owner', 'admin'] + + super(self.__class__, self).__start__() + + self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4()) + + self.heat_cli = heat_utils.heat_client(self.os_creds, self.os_session) + self.stack_creator = None + + self.heat_tmplt_path = pkg_resources.resource_filename( + 'snaps.openstack.tests.heat', 'flavor_heat_template.yaml') + + stack_settings = StackConfig( + name=self.guid + '-stack', + template_path=self.heat_tmplt_path) + self.stack_creator = OpenStackHeatStack( + self.os_creds, stack_settings) + self.created_stack = self.stack_creator.create() + self.assertIsNotNone(self.created_stack) + + def tearDown(self): + """ + Cleans the stack and downloaded stack file + """ + if self.stack_creator: + try: + self.stack_creator.clean() + except: + pass + + super(self.__class__, self).__clean__() + + def test_retrieve_flavor_creator(self): + """ + Tests the creation of an OpenStack stack from Heat template file and + the retrieval of an OpenStackVolume creator/state machine instance + """ + flavor_creators = self.stack_creator.get_flavor_creators() + self.assertEqual(1, len(flavor_creators)) + + creator = flavor_creators[0] + self.assertTrue(creator.get_flavor().name.startswith(self.guid)) + self.assertEqual(1024, creator.get_flavor().ram) + self.assertEqual(200, creator.get_flavor().disk) + self.assertEqual(8, creator.get_flavor().vcpus) + self.assertEqual(0, creator.get_flavor().ephemeral) + self.assertIsNone(creator.get_flavor().swap) + self.assertEqual(1.0, creator.get_flavor().rxtx_factor) + self.assertTrue(creator.get_flavor().is_public) + + +class CreateStackKeypairTests(OSIntegrationTestCase): + """ + Tests to ensure that floating IPs can be accessed via an + OpenStackKeypair object obtained from the OpenStackHeatStack instance + """ + + def setUp(self): + + self.user_roles = ['heat_stack_owner'] + + super(self.__class__, self).__start__() + + self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4()) + + self.heat_cli = heat_utils.heat_client(self.os_creds, self.os_session) + self.nova = nova_utils.nova_client(self.os_creds, self.os_session) + self.stack_creator = None + + self.keypair_name = self.guid + '-kp' + + self.env_values = { + 'keypair_name': self.keypair_name} + + self.heat_tmplt_path = pkg_resources.resource_filename( + 'snaps.openstack.tests.heat', 'keypair_heat_template.yaml') + + stack_settings = StackConfig( + name=self.__class__.__name__ + '-' + str(self.guid) + '-stack', + template_path=self.heat_tmplt_path, + env_values=self.env_values) + self.stack_creator = OpenStackHeatStack( + self.os_creds, stack_settings) + self.created_stack = self.stack_creator.create() + self.assertIsNotNone(self.created_stack) + + self.keypair_creators = list() + + def tearDown(self): + """ + Cleans the stack and downloaded stack file + """ + if self.stack_creator: + try: + self.stack_creator.clean() + except: + pass + for keypair_creator in self.keypair_creators: + try: + keypair_creator.clean() + except: + pass + + super(self.__class__, self).__clean__() + + def test_retrieve_keypair_creator(self): + """ + Tests the creation of an OpenStack stack from Heat template file and + the retrieval of an OpenStackKeypair creator/state machine instance + """ + self.kp_creators = self.stack_creator.get_keypair_creators( + 'private_key') + self.assertEqual(1, len(self.kp_creators)) + + self.keypair_creator = self.kp_creators[0] + + self.assertEqual(self.keypair_name, + self.keypair_creator.get_keypair().name) + self.assertIsNotNone( + self.keypair_creator.keypair_settings.private_filepath) + + private_file_contents = file_utils.read_file( + self.keypair_creator.keypair_settings.private_filepath) + self.assertTrue(private_file_contents.startswith( + '-----BEGIN RSA PRIVATE KEY-----')) + + keypair = nova_utils.get_keypair_by_id( + self.nova, self.keypair_creator.get_keypair().id) + self.assertIsNotNone(keypair) + self.assertEqual(self.keypair_creator.get_keypair(), keypair) + + +class CreateStackSecurityGroupTests(OSIntegrationTestCase): + """ + Tests for the OpenStackHeatStack class to ensure it returns an + OpenStackSecurityGroup object + """ + + def setUp(self): + """ + Instantiates the CreateStack object that is responsible for downloading + and creating an OS stack file within OpenStack + """ + self.user_roles = ['heat_stack_owner'] + + super(self.__class__, self).__start__() + + self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4()) + + self.heat_cli = heat_utils.heat_client(self.os_creds, self.os_session) + self.nova = nova_utils.nova_client(self.os_creds, self.os_session) + self.stack_creator = None + + self.security_group_name = self.guid + '-sec-grp' + + self.env_values = { + 'security_group_name': self.security_group_name} + + self.heat_tmplt_path = pkg_resources.resource_filename( + 'snaps.openstack.tests.heat', 'security_group_heat_template.yaml') + + stack_settings = StackConfig( + name=self.__class__.__name__ + '-' + str(self.guid) + '-stack', + template_path=self.heat_tmplt_path, + env_values=self.env_values) + self.stack_creator = OpenStackHeatStack( + self.os_creds, stack_settings) + self.created_stack = self.stack_creator.create() + self.assertIsNotNone(self.created_stack) + + def tearDown(self): + """ + Cleans the stack and downloaded stack file + """ + if self.stack_creator: + try: + self.stack_creator.clean() + except: + pass + + super(self.__class__, self).__clean__() + + def test_retrieve_security_group_creator(self): + """ + Tests the creation of an OpenStack stack from Heat template file and + the retrieval of an OpenStackSecurityGroup creator/state machine + instance + """ + sec_grp_creators = self.stack_creator.get_security_group_creators() + self.assertEqual(1, len(sec_grp_creators)) + + creator = sec_grp_creators[0] + sec_grp = creator.get_security_group() + + self.assertEqual(self.security_group_name, sec_grp.name) + self.assertEqual('Test description', sec_grp.description) + self.assertEqual(2, len(sec_grp.rules)) + + has_ssh_rule = False + has_icmp_rule = False + + for rule in sec_grp.rules: + if (rule.security_group_id == sec_grp.id + and rule.direction == 'egress' + and rule.ethertype == 'IPv4' + and rule.port_range_min == 22 + and rule.port_range_max == 22 + and rule.protocol == 'tcp' + and rule.remote_group_id is None + and rule.remote_ip_prefix == '0.0.0.0/0'): + has_ssh_rule = True + if (rule.security_group_id == sec_grp.id + and rule.direction == 'ingress' + and rule.ethertype == 'IPv4' + and rule.port_range_min is None + and rule.port_range_max is None + and rule.protocol == 'icmp' + and rule.remote_group_id is None + and rule.remote_ip_prefix == '0.0.0.0/0'): + has_icmp_rule = True + + self.assertTrue(has_ssh_rule) + self.assertTrue(has_icmp_rule) + + +class CreateStackNegativeTests(OSIntegrationTestCase): + """ + Negative test cases for the OpenStackHeatStack class with poor + configuration + """ + + def setUp(self): + self.user_roles = ['heat_stack_owner'] + + super(self.__class__, self).__start__() self.stack_name = self.__class__.__name__ + '-' + str(uuid.uuid4()) self.stack_creator = None @@ -329,16 +1080,17 @@ class CreateStackNegativeTests(OSIntegrationTestCase): def tearDown(self): if self.stack_creator: self.stack_creator.clean() + super(self.__class__, self).__clean__() def test_missing_dependencies(self): """ Expect an StackCreationError when the stack file does not exist """ - stack_settings = StackSettings(name=self.stack_name, - template_path=self.heat_tmplt_path) - self.stack_creator = create_stack.OpenStackHeatStack(self.heat_creds, - stack_settings) + stack_settings = StackConfig(name=self.stack_name, + template_path=self.heat_tmplt_path) + self.stack_creator = OpenStackHeatStack( + self.os_creds, stack_settings) with self.assertRaises(HTTPBadRequest): self.stack_creator.create() @@ -346,9 +1098,117 @@ class CreateStackNegativeTests(OSIntegrationTestCase): """ Expect an StackCreationError when the stack file does not exist """ - stack_settings = StackSettings(name=self.stack_name, - template_path='foo') - self.stack_creator = create_stack.OpenStackHeatStack(self.heat_creds, - stack_settings) + stack_settings = StackConfig( + name=self.stack_name, template_path='foo') + self.stack_creator = OpenStackHeatStack( + self.os_creds, stack_settings) with self.assertRaises(IOError): self.stack_creator.create() + + +class CreateStackFailureTests(OSIntegrationTestCase): + """ + Tests for the OpenStackHeatStack class defined in create_stack.py for + when failures occur. Failures are being triggered by allocating 1 million + CPUs. + """ + + def setUp(self): + self.user_roles = ['heat_stack_owner'] + + super(self.__class__, self).__start__() + + self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4()) + + self.heat_cli = heat_utils.heat_client(self.os_creds, self.os_session) + self.stack_creator = None + + self.tmp_file = file_utils.save_string_to_file( + ' ', str(uuid.uuid4()) + '-bad-image') + self.image_creator = OpenStackImage( + self.os_creds, ImageConfig( + name=self.guid + 'image', image_file=self.tmp_file.name, + image_user='foo', img_format='qcow2')) + self.image_creator.create() + + # Create Flavor + self.flavor_creator = OpenStackFlavor( + self.admin_os_creds, + FlavorConfig( + name=self.guid + '-flavor-name', ram=256, disk=10, + vcpus=1000000)) + self.flavor_creator.create() + + self.network_name = self.guid + '-net' + self.subnet_name = self.guid + '-subnet' + self.vm_inst_name = self.guid + '-inst' + + self.env_values = { + 'image_name': self.image_creator.image_settings.name, + 'flavor_name': self.flavor_creator.flavor_settings.name, + 'net_name': self.network_name, + 'subnet_name': self.subnet_name, + 'inst_name': self.vm_inst_name} + + self.heat_tmplt_path = pkg_resources.resource_filename( + 'snaps.openstack.tests.heat', 'test_heat_template.yaml') + + def tearDown(self): + """ + Cleans the stack and downloaded stack file + """ + if self.stack_creator: + try: + self.stack_creator.clean() + except: + pass + + if self.image_creator: + try: + self.image_creator.clean() + except: + pass + + if self.flavor_creator: + try: + self.flavor_creator.clean() + except: + pass + + if self.tmp_file: + try: + os.remove(self.tmp_file.name) + except: + pass + + super(self.__class__, self).__clean__() + + def test_stack_failure(self): + """ + Tests the creation of an OpenStack stack from Heat template file that + should always fail due to too many CPU cores + """ + # Create Stack + # Set the default stack settings, then set any custom parameters sent + # from the app + stack_settings = StackConfig( + name=self.__class__.__name__ + '-' + str(self.guid) + '-stack', + template_path=self.heat_tmplt_path, + env_values=self.env_values) + self.stack_creator = OpenStackHeatStack( + self.os_creds, stack_settings) + + with self.assertRaises(StackError): + try: + self.stack_creator.create() + except StackError: + resources = heat_utils.get_resources( + self.heat_cli, self.stack_creator.get_stack().id) + + found = False + for resource in resources: + if (resource.status == + snaps.config.stack.STATUS_CREATE_COMPLETE): + found = True + self.assertTrue(found) + raise