Refactoring of RouterSettings to extend RouterConfig
[snaps.git] / snaps / openstack / tests / create_instance_tests.py
index 19173d2..bc664fe 100644 (file)
@@ -21,21 +21,27 @@ import uuid
 
 import os
 from neutronclient.common.exceptions import InvalidIpForSubnetClient
+from novaclient.exceptions import BadRequest
 
 from snaps import file_utils
+from snaps.config.router import RouterConfig
+from snaps.config.keypair import KeypairConfig
 from snaps.openstack import create_network, create_router
-from snaps.openstack.create_flavor import OpenStackFlavor, FlavorSettings
-from snaps.openstack.create_image import OpenStackImage, ImageSettings
+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,
     VmInstanceSettingsError, FloatingIpSettingsError)
-from snaps.openstack.create_keypairs import OpenStackKeypair, KeypairSettings
+from snaps.openstack.create_keypairs import OpenStackKeypair
 from snaps.openstack.create_network import (
-    OpenStackNetwork, PortSettings, NetworkSettings)
-from snaps.openstack.create_router import OpenStackRouter, RouterSettings
+    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)
@@ -93,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')
@@ -110,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))
@@ -142,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')
@@ -153,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))
@@ -171,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):
@@ -210,11 +220,22 @@ class FloatingIpSettingsUnitTests(unittest.TestCase):
         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)
@@ -225,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)
@@ -236,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)
@@ -247,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)
@@ -301,8 +325,8 @@ class SimpleHealthCheck(OSIntegrationTestCase):
             # Create Flavor
             self.flavor_creator = OpenStackFlavor(
                 self.admin_os_creds,
-                FlavorSettings(name=guid + '-flavor-name', ram=256, 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()
@@ -408,8 +432,8 @@ class CreateInstanceSimpleTests(OSIntegrationTestCase):
             # Create Flavor
             self.flavor_creator = OpenStackFlavor(
                 self.admin_os_creds,
-                FlavorSettings(name=guid + '-flavor-name', ram=256, 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
@@ -546,12 +570,12 @@ class CreateInstanceSingleNetworkTests(OSIntegrationTestCase):
             # Create Flavor
             self.flavor_creator = OpenStackFlavor(
                 self.admin_os_creds,
-                FlavorSettings(name=guid + '-flavor-name', ram=256, 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))
@@ -595,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()
@@ -668,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):
         """
@@ -687,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)])
@@ -704,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))
 
@@ -723,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)])
@@ -742,9 +760,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))
 
@@ -761,6 +777,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)])
@@ -780,9 +797,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))
 
@@ -794,6 +809,230 @@ class CreateInstanceSingleNetworkTests(OSIntegrationTestCase):
         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):
     """
     Test for the CreateInstance class with a single NIC/Port where mac and IP
@@ -839,8 +1078,8 @@ class CreateInstancePortManipulationTests(OSIntegrationTestCase):
             # Create Flavor
             self.flavor_creator = OpenStackFlavor(
                 self.admin_os_creds,
-                FlavorSettings(name=guid + '-flavor-name', ram=256, 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()
@@ -1132,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
@@ -1298,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))
@@ -1349,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()
@@ -1423,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)])
@@ -1434,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))
@@ -1442,10 +1676,6 @@ 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))
 
@@ -1503,9 +1733,9 @@ class InstanceSecurityGroupTests(OSIntegrationTestCase):
             # Create Flavor
             self.flavor_creator = OpenStackFlavor(
                 self.admin_os_creds,
-                FlavorSettings(name=self.guid + '-flavor-name', ram=256,
-                               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(
@@ -1837,8 +2067,8 @@ class CreateInstanceFromThreePartImage(OSIntegrationTestCase):
             # Create Flavor
             self.flavor_creator = OpenStackFlavor(
                 self.admin_os_creds,
-                FlavorSettings(name=guid + '-flavor-name', ram=256, 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
@@ -1958,7 +2188,7 @@ class CreateInstanceMockOfflineTests(OSComponentTestCase):
             # Create Flavor
             self.flavor_creator = OpenStackFlavor(
                 self.os_creds,
-                FlavorSettings(
+                FlavorConfig(
                     name=self.guid + '-flavor-name', ram=256, disk=10,
                     vcpus=1))
             self.flavor_creator.create()
@@ -2090,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)
@@ -2385,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)
@@ -2491,8 +2721,8 @@ class CreateInstanceTwoNetTests(OSIntegrationTestCase):
                     network_name=self.net_config_2.name,
                     project_name=self.os_creds.project_name)]
 
-            router_settings = RouterSettings(name=self.guid + '-pub-router',
-                                             port_settings=port_settings)
+            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()
@@ -2500,9 +2730,9 @@ class CreateInstanceTwoNetTests(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()
 
             sec_grp_name = self.guid + '-sec-grp'
@@ -2633,6 +2863,180 @@ class CreateInstanceTwoNetTests(OSIntegrationTestCase):
         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