summaryrefslogtreecommitdiffstats
path: root/snaps/openstack/tests
diff options
context:
space:
mode:
authorspisarski <s.pisarski@cablelabs.com>2017-02-15 09:13:54 -0700
committerspisarski <s.pisarski@cablelabs.com>2017-02-15 09:15:34 -0700
commit57777f3df521553a06cd01a3861b415d2905ceca (patch)
treef3b3be457baec7b5231309989aa3ffa9658cd25d /snaps/openstack/tests
parent73ef791a1cde68e0d8d69cddf63534fbb90f3e2d (diff)
Initial patch with all code from CableLabs repository.
Change-Id: I70a2778718c5e7f21fd14e4ad28c9269d3761cc7 Signed-off-by: spisarski <s.pisarski@cablelabs.com>
Diffstat (limited to 'snaps/openstack/tests')
-rw-r--r--snaps/openstack/tests/__init__.py15
-rw-r--r--snaps/openstack/tests/conf/os_env.yaml.template39
-rw-r--r--snaps/openstack/tests/conf/overcloudrc_test9
-rw-r--r--snaps/openstack/tests/create_flavor_tests.py311
-rw-r--r--snaps/openstack/tests/create_image_tests.py362
-rw-r--r--snaps/openstack/tests/create_instance_tests.py1474
-rw-r--r--snaps/openstack/tests/create_keypairs_tests.py203
-rw-r--r--snaps/openstack/tests/create_network_tests.py533
-rw-r--r--snaps/openstack/tests/create_project_tests.py228
-rw-r--r--snaps/openstack/tests/create_router_tests.py264
-rw-r--r--snaps/openstack/tests/create_security_group_tests.py355
-rw-r--r--snaps/openstack/tests/create_user_tests.py155
-rw-r--r--snaps/openstack/tests/openstack_tests.py144
-rw-r--r--snaps/openstack/tests/os_source_file_test.py131
-rw-r--r--snaps/openstack/tests/validation_utils.py69
15 files changed, 4292 insertions, 0 deletions
diff --git a/snaps/openstack/tests/__init__.py b/snaps/openstack/tests/__init__.py
new file mode 100644
index 0000000..e3e876e
--- /dev/null
+++ b/snaps/openstack/tests/__init__.py
@@ -0,0 +1,15 @@
+# Copyright (c) 2016 Cable Television Laboratories, Inc. ("CableLabs")
+# and others. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+__author__ = 'spisarski'
diff --git a/snaps/openstack/tests/conf/os_env.yaml.template b/snaps/openstack/tests/conf/os_env.yaml.template
new file mode 100644
index 0000000..da6b942
--- /dev/null
+++ b/snaps/openstack/tests/conf/os_env.yaml.template
@@ -0,0 +1,39 @@
+# Keystone v2.0
+#username: admin
+#password: admin
+#os_auth_url: http://<host>:<port>/v2.0/
+#project_name: admin
+#ext_net: <external network name>
+#http_proxy: <host>:<port>
+#ssh_proxy_cmd: '/usr/local/bin/corkscrew <host> <port> %h %p'
+#ssh_proxy_cmd: 'ssh <host> nc %h %p'
+
+# Keystone v2.0
+#username: admin
+#password: admin
+#os_auth_url: http://<host>:<port>/v3
+#project_name: admin
+#identity_api_version: 3
+#ext_net: <external network name>
+
+
+
+#username: admin
+#password: cable123
+#os_auth_url: http://192.168.67.10:5000/v2.0/
+#project_name: admin
+#ext_net: external
+#http_proxy: 10.197.123.27:3128
+#ssh_proxy_cmd: '/usr/local/bin/corkscrew 10.197.123.27 3128 %h %p'
+
+
+
+
+username: admin
+password: admin
+os_auth_url: http://192.168.0.2:5000/v3
+project_name: admin
+identity_api_version: 3
+ext_net: admin_floating_net
+http_proxy: 10.197.123.27:3128
+ssh_proxy_cmd: '/usr/local/bin/corkscrew localhost 3128 %h %p' \ No newline at end of file
diff --git a/snaps/openstack/tests/conf/overcloudrc_test b/snaps/openstack/tests/conf/overcloudrc_test
new file mode 100644
index 0000000..87746d8
--- /dev/null
+++ b/snaps/openstack/tests/conf/overcloudrc_test
@@ -0,0 +1,9 @@
+export NOVA_VERSION=1.1
+export OS_PASSWORD=test_pw
+export OS_AUTH_URL=http://foo:5000/v2.0/
+export OS_USERNAME=admin
+export OS_TENANT_NAME=admin
+export COMPUTE_API_VERSION=1.1
+export OS_NO_CACHE=True
+export OS_CLOUDNAME=undercloud
+export OS_IMAGE_API_VERSION=1 \ No newline at end of file
diff --git a/snaps/openstack/tests/create_flavor_tests.py b/snaps/openstack/tests/create_flavor_tests.py
new file mode 100644
index 0000000..c75bdf6
--- /dev/null
+++ b/snaps/openstack/tests/create_flavor_tests.py
@@ -0,0 +1,311 @@
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+import uuid
+import unittest
+
+from snaps.openstack.create_flavor import FlavorSettings, OpenStackFlavor
+from snaps.openstack.tests.os_source_file_test import OSComponentTestCase
+from snaps.openstack.utils import nova_utils
+
+__author__ = 'spisarski'
+
+
+class FlavorSettingsUnitTests(unittest.TestCase):
+ """
+ Tests the construction of the FlavorSettings class
+ """
+
+ def test_no_params(self):
+ with self.assertRaises(Exception):
+ FlavorSettings()
+
+ def test_empty_config(self):
+ with self.assertRaises(Exception):
+ FlavorSettings(config=dict())
+
+ def test_name_only(self):
+ with self.assertRaises(Exception):
+ FlavorSettings(name='foo')
+
+ def test_config_with_name_only(self):
+ with self.assertRaises(Exception):
+ FlavorSettings(config={'name': 'foo'})
+
+ def test_name_ram_only(self):
+ with self.assertRaises(Exception):
+ FlavorSettings(name='foo', ram=1)
+
+ def test_config_with_name_ram_only(self):
+ with self.assertRaises(Exception):
+ FlavorSettings(config={'name': 'foo', 'ram': 1})
+
+ def test_name_ram_disk_only(self):
+ with self.assertRaises(Exception):
+ FlavorSettings(name='foo', ram=1, disk=1)
+
+ def test_config_with_name_ram_disk_only(self):
+ with self.assertRaises(Exception):
+ FlavorSettings(config={'name': 'foo', 'ram': 1, 'disk': 1})
+
+ def test_ram_string(self):
+ with self.assertRaises(Exception):
+ FlavorSettings(name='foo', ram='bar', disk=2, vcpus=3, ephemeral=4, swap=5, rxtx_factor=6.0,
+ is_public=False)
+
+ def test_config_ram_string(self):
+ with self.assertRaises(Exception):
+ FlavorSettings(config={'name': 'foo', 'ram': 'bar', 'disk': 2, 'vcpus': 3, 'ephemeral': 4, 'swap': 5,
+ 'rxtx_factor': 6.0, 'is_public': False})
+
+ def test_ram_float(self):
+ with self.assertRaises(Exception):
+ FlavorSettings(name='foo', ram=1.5, disk=2, vcpus=3, ephemeral=4, swap=5, rxtx_factor=6.0, is_public=False)
+
+ def test_config_ram_float(self):
+ with self.assertRaises(Exception):
+ FlavorSettings(config={'name': 'foo', 'ram': 1.5, 'disk': 2, 'vcpus': 3, 'ephemeral': 4, 'swap': 5,
+ 'rxtx_factor': 6.0, 'is_public': False})
+
+ def test_disk_string(self):
+ with self.assertRaises(Exception):
+ FlavorSettings(name='foo', ram=1, disk='bar', vcpus=3, ephemeral=4, swap=5, rxtx_factor=6.0,
+ is_public=False)
+
+ def test_config_disk_string(self):
+ with self.assertRaises(Exception):
+ FlavorSettings(config={'name': 'foo', 'ram': 1, 'disk': 'bar', 'vcpus': 3, 'ephemeral': 4, 'swap': 5,
+ 'rxtx_factor': 6.0, 'is_public': False})
+
+ def test_disk_float(self):
+ with self.assertRaises(Exception):
+ FlavorSettings(name='foo', ram=1, disk=2.5, vcpus=3, ephemeral=4, swap=5, rxtx_factor=6.0, is_public=False)
+
+ def test_config_disk_float(self):
+ with self.assertRaises(Exception):
+ FlavorSettings(config={'name': 'foo', 'ram': 1, 'disk': 2.5, 'vcpus': 3, 'ephemeral': 4, 'swap': 5,
+ 'rxtx_factor': 6.0, 'is_public': False})
+
+ def test_vcpus_string(self):
+ with self.assertRaises(Exception):
+ FlavorSettings(name='foo', ram=1, disk=2, vcpus='bar', ephemeral=4, swap=5, rxtx_factor=6.0,
+ is_public=False)
+
+ def test_config_vcpus_string(self):
+ with self.assertRaises(Exception):
+ FlavorSettings(config={'name': 'foo', 'ram': 1, 'disk': 2, 'vcpus': 'bar', 'ephemeral': 4, 'swap': 5,
+ 'rxtx_factor': 6.0, 'is_public': False})
+
+ def test_ephemeral_string(self):
+ with self.assertRaises(Exception):
+ FlavorSettings(name='foo', ram=1, disk=2, vcpus=3, ephemeral='bar', swap=5, rxtx_factor=6.0,
+ is_public=False)
+
+ def test_config_ephemeral_string(self):
+ with self.assertRaises(Exception):
+ FlavorSettings(config={'name': 'foo', 'ram': 1, 'disk': 2, 'vcpus': 3, 'ephemeral': 'bar', 'swap': 5,
+ 'rxtx_factor': 6.0, 'is_public': False})
+
+ def test_ephemeral_float(self):
+ with self.assertRaises(Exception):
+ FlavorSettings(name='foo', ram=1, disk=2, vcpus=3, ephemeral=4.5, swap=5, rxtx_factor=6.0, is_public=False)
+
+ def test_config_ephemeral_float(self):
+ with self.assertRaises(Exception):
+ FlavorSettings(config={'name': 'foo', 'ram': 1, 'disk': 2, 'vcpus': 3, 'ephemeral': 4.5, 'swap': 5,
+ 'rxtx_factor': 6.0, 'is_public': False})
+
+ def test_swap_string(self):
+ with self.assertRaises(Exception):
+ FlavorSettings(name='foo', ram=1, disk=2, vcpus=3, ephemeral=4, swap='bar', rxtx_factor=6.0,
+ is_public=False)
+
+ def test_config_swap_string(self):
+ with self.assertRaises(Exception):
+ FlavorSettings(config={'name': 'foo', 'ram': 1, 'disk': 2, 'vcpus': 3, 'ephemeral': 4, 'swap': 'bar',
+ 'rxtx_factor': 6.0, 'is_public': False})
+
+ def test_swap_float(self):
+ with self.assertRaises(Exception):
+ FlavorSettings(name='foo', ram=1, disk=2, vcpus=3, ephemeral=4, swap=5.5, rxtx_factor=6.0, is_public=False)
+
+ def test_config_swap_float(self):
+ with self.assertRaises(Exception):
+ FlavorSettings(config={'name': 'foo', 'ram': 1, 'disk': 2, 'vcpus': 3, 'ephemeral': 4, 'swap': 5.5,
+ 'rxtx_factor': 6.0, 'is_public': False})
+
+ def test_rxtx_string(self):
+ with self.assertRaises(Exception):
+ FlavorSettings(name='foo', ram=1, disk=2, vcpus=3, ephemeral=4, swap=5, rxtx_factor='bar', is_public=False)
+
+ def test_config_rxtx_string(self):
+ with self.assertRaises(Exception):
+ FlavorSettings(config={'name': 'foo', 'ram': 1, 'disk': 2, 'vcpus': 3, 'ephemeral': 4, 'swap': 5,
+ 'rxtx_factor': 'bar', 'is_public': False})
+
+ def test_is_pub_string(self):
+ with self.assertRaises(Exception):
+ FlavorSettings(name='foo', ram=1, disk=2, vcpus=3, ephemeral=4, swap=5, rxtx_factor=6.0, is_public='bar')
+
+ def test_config_is_pub_string(self):
+ with self.assertRaises(Exception):
+ FlavorSettings(config={'name': 'foo', 'ram': 1, 'disk': 2, 'vcpus': 3, 'ephemeral': 4, 'swap': 5,
+ 'rxtx_factor': 6.0, 'is_public': 'bar'})
+
+ def test_name_ram_disk_vcpus_only(self):
+ settings = FlavorSettings(name='foo', ram=1, disk=2, vcpus=3)
+ self.assertEquals('foo', settings.name)
+ self.assertEquals('auto', settings.flavor_id)
+ self.assertEquals(1, settings.ram)
+ self.assertEquals(2, settings.disk)
+ self.assertEquals(3, settings.vcpus)
+ self.assertEquals(0, settings.ephemeral)
+ self.assertEquals(0, settings.swap)
+ self.assertEquals(1.0, settings.rxtx_factor)
+ self.assertEquals(True, settings.is_public)
+
+ def test_config_with_name_ram_disk_vcpus_only(self):
+ settings = FlavorSettings(config={'name': 'foo', 'ram': 1, 'disk': 2, 'vcpus': 3})
+ self.assertEquals('foo', settings.name)
+ self.assertEquals('auto', settings.flavor_id)
+ self.assertEquals(1, settings.ram)
+ self.assertEquals(2, settings.disk)
+ self.assertEquals(3, settings.vcpus)
+ self.assertEquals(0, settings.ephemeral)
+ self.assertEquals(0, settings.swap)
+ self.assertEquals(1.0, settings.rxtx_factor)
+ self.assertEquals(True, settings.is_public)
+
+ def test_all(self):
+ settings = FlavorSettings(name='foo', flavor_id='bar', ram=1, disk=2, vcpus=3, ephemeral=4, swap=5, rxtx_factor=6.0,
+ is_public=False)
+ self.assertEquals('foo', settings.name)
+ self.assertEquals('bar', settings.flavor_id)
+ self.assertEquals(1, settings.ram)
+ self.assertEquals(2, settings.disk)
+ self.assertEquals(3, settings.vcpus)
+ self.assertEquals(4, settings.ephemeral)
+ self.assertEquals(5, settings.swap)
+ self.assertEquals(6.0, settings.rxtx_factor)
+ self.assertEquals(False, settings.is_public)
+
+ def test_config_all(self):
+ settings = FlavorSettings(config={'name': 'foo', 'flavor_id': 'bar', 'ram': 1, 'disk': 2, 'vcpus': 3, 'ephemeral': 4,
+ 'swap': 5, 'rxtx_factor': 6.0, 'is_public': False})
+ self.assertEquals('foo', settings.name)
+ self.assertEquals('bar', settings.flavor_id)
+ self.assertEquals(1, settings.ram)
+ self.assertEquals(2, settings.disk)
+ self.assertEquals(3, settings.vcpus)
+ self.assertEquals(4, settings.ephemeral)
+ self.assertEquals(5, settings.swap)
+ self.assertEquals(6.0, settings.rxtx_factor)
+ self.assertEquals(False, settings.is_public)
+
+
+class CreateFlavorTests(OSComponentTestCase):
+ """
+ Test for the CreateSecurityGroup class defined in create_security_group.py
+ """
+
+ def setUp(self):
+ """
+ Instantiates the CreateSecurityGroup object that is responsible for downloading and creating an OS image file
+ within OpenStack
+ """
+ guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
+ self.flavor_name = guid + 'name'
+
+ self.nova = nova_utils.nova_client(self.os_creds)
+
+ # Initialize for cleanup
+ self.flavor_creator = None
+
+ def tearDown(self):
+ """
+ Cleans the image and downloaded image file
+ """
+ if self.flavor_creator:
+ self.flavor_creator.clean()
+
+ def test_create_flavor(self):
+ """
+ Tests the creation of an OpenStack flavor.
+ """
+ # Create Flavor
+ flavor_settings = FlavorSettings(name=self.flavor_name, ram=1, disk=1, vcpus=1)
+ self.flavor_creator = OpenStackFlavor(self.os_creds, flavor_settings)
+ flavor = self.flavor_creator.create()
+ self.assertTrue(validate_flavor(flavor_settings, flavor))
+
+ def test_create_flavor_existing(self):
+ """
+ Tests the creation of an OpenStack flavor then starts another creator to ensure it has not been done twice.
+ """
+ # Create Flavor
+ flavor_settings = FlavorSettings(name=self.flavor_name, ram=1, disk=1, vcpus=1)
+ self.flavor_creator = OpenStackFlavor(self.os_creds, flavor_settings)
+ flavor = self.flavor_creator.create()
+ self.assertTrue(validate_flavor(flavor_settings, flavor))
+
+ flavor_creator_2 = OpenStackFlavor(self.os_creds, flavor_settings)
+ flavor2 = flavor_creator_2.create()
+
+ self.assertEquals(flavor.id, flavor2.id)
+
+ def test_create_clean_flavor(self):
+ """
+ Tests the creation and cleanup of an OpenStack flavor.
+ """
+ # Create Flavor
+ flavor_settings = FlavorSettings(name=self.flavor_name, ram=1, disk=1, vcpus=1)
+ self.flavor_creator = OpenStackFlavor(self.os_creds, flavor_settings)
+ flavor = self.flavor_creator.create()
+ self.assertTrue(validate_flavor(flavor_settings, flavor))
+
+ # Clean Flavor
+ self.flavor_creator.clean()
+
+ self.assertIsNone(self.flavor_creator.get_flavor())
+ self.assertIsNone(nova_utils.get_flavor_by_name(self.nova, flavor_settings.name))
+
+ def test_create_delete_flavor(self):
+ """
+ Tests the creation of an OpenStack Security Group, the deletion, then cleanup to ensure clean() does not
+ raise any exceptions.
+ """
+ # Create Flavor
+ flavor_settings = FlavorSettings(name=self.flavor_name, ram=1, disk=1, vcpus=1)
+ self.flavor_creator = OpenStackFlavor(self.os_creds, flavor_settings)
+ flavor = self.flavor_creator.create()
+ self.assertTrue(validate_flavor(flavor_settings, flavor))
+
+ # Delete Flavor
+ nova_utils.delete_flavor(self.nova, flavor)
+ self.assertIsNone(nova_utils.get_flavor_by_name(self.nova, flavor_settings.name))
+
+ # Attempt to cleanup
+ self.flavor_creator.clean()
+
+ self.assertIsNone(self.flavor_creator.get_flavor())
+
+ # TODO - Add more tests to exercise all configuration options
+
+
+def validate_flavor(flavor_settings, flavor):
+ """
+ Validates the flavor_settings against the OpenStack flavor object
+ :param flavor_settings: the settings used to create the flavor
+ :param flavor: the OpenStack flavor object
+ """
+ return flavor is not None \
+ and flavor_settings.name == flavor.name \
+ and flavor_settings.ram == flavor.ram \
+ and flavor_settings.disk == flavor.disk \
+ and flavor_settings.vcpus == flavor.vcpus
diff --git a/snaps/openstack/tests/create_image_tests.py b/snaps/openstack/tests/create_image_tests.py
new file mode 100644
index 0000000..24bf0f2
--- /dev/null
+++ b/snaps/openstack/tests/create_image_tests.py
@@ -0,0 +1,362 @@
+# Copyright (c) 2016 Cable Television Laboratories, Inc. ("CableLabs")
+# and others. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+import os
+import shutil
+import uuid
+import unittest
+
+from snaps import file_utils
+from snaps.openstack.create_image import ImageSettings
+
+import openstack_tests
+from snaps.openstack.utils import glance_utils, nova_utils
+from snaps.openstack import create_image
+from snaps.openstack import os_credentials
+from snaps.openstack.tests.os_source_file_test import OSIntegrationTestCase
+
+__author__ = 'spisarski'
+
+
+class ImageSettingsUnitTests(unittest.TestCase):
+ """
+ Tests the construction of the ImageSettings class
+ """
+
+ def test_no_params(self):
+ with self.assertRaises(Exception):
+ ImageSettings()
+
+ def test_empty_config(self):
+ with self.assertRaises(Exception):
+ ImageSettings(config=dict())
+
+ def test_name_only(self):
+ with self.assertRaises(Exception):
+ ImageSettings(name='foo')
+
+ def test_config_with_name_only(self):
+ with self.assertRaises(Exception):
+ ImageSettings(config={'name': 'foo'})
+
+ def test_name_user_only(self):
+ with self.assertRaises(Exception):
+ ImageSettings(name='foo', image_user='bar')
+
+ def test_config_with_name_user_only(self):
+ with self.assertRaises(Exception):
+ ImageSettings(config={'name': 'foo', 'image_user': 'bar'})
+
+ def test_name_user_format_only(self):
+ with self.assertRaises(Exception):
+ ImageSettings(name='foo', image_user='bar', img_format='qcow2')
+
+ def test_config_with_name_user_format_only(self):
+ with self.assertRaises(Exception):
+ ImageSettings(config={'name': 'foo', 'image_user': 'bar', 'format': 'qcow2'})
+
+ def test_name_user_format_url_file_only(self):
+ with self.assertRaises(Exception):
+ ImageSettings(name='foo', image_user='bar', img_format='qcow2', url='http://foo.com',
+ image_file='/foo/bar.qcow')
+
+ def test_config_with_name_user_format_url_file_only(self):
+ with self.assertRaises(Exception):
+ ImageSettings(config={'name': 'foo', 'image_user': 'bar', 'format': 'qcow2',
+ 'download_url': 'http://foo.com', 'image_file': '/foo/bar.qcow'})
+
+ def test_name_user_format_url_only(self):
+ settings = ImageSettings(name='foo', image_user='bar', img_format='qcow2', url='http://foo.com')
+ self.assertEquals('foo', settings.name)
+ self.assertEquals('bar', settings.image_user)
+ self.assertEquals('qcow2', settings.format)
+ self.assertEquals('http://foo.com', settings.url)
+ self.assertIsNone(settings.image_file)
+ self.assertIsNone(settings.nic_config_pb_loc)
+
+ def test_config_with_name_user_format_url_only(self):
+ settings = ImageSettings(config={'name': 'foo', 'image_user': 'bar', 'format': 'qcow2',
+ 'download_url': 'http://foo.com'})
+ self.assertEquals('foo', settings.name)
+ self.assertEquals('bar', settings.image_user)
+ self.assertEquals('qcow2', settings.format)
+ self.assertEquals('http://foo.com', settings.url)
+ self.assertIsNone(settings.image_file)
+ self.assertIsNone(settings.nic_config_pb_loc)
+
+ def test_name_user_format_file_only(self):
+ settings = ImageSettings(name='foo', image_user='bar', img_format='qcow2', image_file='/foo/bar.qcow')
+ self.assertEquals('foo', settings.name)
+ self.assertEquals('bar', settings.image_user)
+ self.assertEquals('qcow2', settings.format)
+ self.assertIsNone(settings.url)
+ self.assertEquals('/foo/bar.qcow', settings.image_file)
+ self.assertIsNone(settings.nic_config_pb_loc)
+
+ def test_config_with_name_user_format_file_only(self):
+ settings = ImageSettings(config={'name': 'foo', 'image_user': 'bar', 'format': 'qcow2',
+ 'image_file': '/foo/bar.qcow'})
+ self.assertEquals('foo', settings.name)
+ self.assertEquals('bar', settings.image_user)
+ self.assertEquals('qcow2', settings.format)
+ self.assertIsNone(settings.url)
+ self.assertEquals('/foo/bar.qcow', settings.image_file)
+ self.assertIsNone(settings.nic_config_pb_loc)
+
+ def test_all_url(self):
+ settings = ImageSettings(name='foo', image_user='bar', img_format='qcow2', url='http://foo.com',
+ nic_config_pb_loc='/foo/bar')
+ self.assertEquals('foo', settings.name)
+ self.assertEquals('bar', settings.image_user)
+ self.assertEquals('qcow2', settings.format)
+ self.assertEquals('http://foo.com', settings.url)
+ self.assertIsNone(settings.image_file)
+ self.assertEquals('/foo/bar', settings.nic_config_pb_loc)
+
+ def test_config_all_url(self):
+ settings = ImageSettings(config={'name': 'foo', 'image_user': 'bar', 'format': 'qcow2',
+ 'download_url': 'http://foo.com', 'nic_config_pb_loc': '/foo/bar'})
+ self.assertEquals('foo', settings.name)
+ self.assertEquals('bar', settings.image_user)
+ self.assertEquals('qcow2', settings.format)
+ self.assertEquals('http://foo.com', settings.url)
+ self.assertIsNone(settings.image_file)
+ self.assertEquals('/foo/bar', settings.nic_config_pb_loc)
+
+ def test_all_file(self):
+ settings = ImageSettings(name='foo', image_user='bar', img_format='qcow2', image_file='/foo/bar.qcow',
+ nic_config_pb_loc='/foo/bar')
+ self.assertEquals('foo', settings.name)
+ self.assertEquals('bar', settings.image_user)
+ self.assertEquals('qcow2', settings.format)
+ self.assertIsNone(settings.url)
+ self.assertEquals('/foo/bar.qcow', settings.image_file)
+ self.assertEquals('/foo/bar', settings.nic_config_pb_loc)
+
+ def test_config_all_file(self):
+ settings = ImageSettings(config={'name': 'foo', 'image_user': 'bar', 'format': 'qcow2',
+ 'image_file': '/foo/bar.qcow', 'nic_config_pb_loc': '/foo/bar'})
+ self.assertEquals('foo', settings.name)
+ self.assertEquals('bar', settings.image_user)
+ self.assertEquals('qcow2', settings.format)
+ self.assertIsNone(settings.url)
+ self.assertEquals('/foo/bar.qcow', settings.image_file)
+ self.assertEquals('/foo/bar', settings.nic_config_pb_loc)
+
+
+class CreateImageSuccessTests(OSIntegrationTestCase):
+ """
+ Test for the CreateImage class defined in create_image.py
+ """
+
+ 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 = uuid.uuid4()
+ self.image_name = self.__class__.__name__ + '-' + str(guid)
+
+ self.nova = nova_utils.nova_client(self.os_creds)
+ self.glance = glance_utils.glance_client(self.os_creds)
+
+ self.tmp_dir = 'tmp/' + str(guid)
+ if not os.path.exists(self.tmp_dir):
+ os.makedirs(self.tmp_dir)
+
+ def tearDown(self):
+ """
+ Cleans the image and downloaded image file
+ """
+ if self.image_creator:
+ self.image_creator.clean()
+
+ if os.path.exists(self.tmp_dir) and os.path.isdir(self.tmp_dir):
+ shutil.rmtree(self.tmp_dir)
+
+ super(self.__class__, self).__clean__()
+
+ def test_create_image_clean_url(self):
+ """
+ Tests the creation of an OpenStack image from a URL.
+ """
+ # Create Image
+ os_image_settings = openstack_tests.cirros_url_image(name=self.image_name)
+ self.image_creator = create_image.OpenStackImage(self.os_creds, os_image_settings)
+
+ created_image = self.image_creator.create()
+ self.assertIsNotNone(created_image)
+
+ retrieved_image = glance_utils.get_image(self.nova, self.glance, os_image_settings.name)
+ self.assertIsNotNone(retrieved_image)
+
+ self.assertEquals(created_image.name, retrieved_image.name)
+ self.assertEquals(created_image.id, retrieved_image.id)
+
+ def test_create_image_clean_file(self):
+ """
+ Tests the creation of an OpenStack image from a file.
+ """
+ url_image_settings = openstack_tests.cirros_url_image('foo')
+ image_file = file_utils.download(url_image_settings.url, self.tmp_dir)
+ file_image_settings = openstack_tests.file_image_test_settings(name=self.image_name, file_path=image_file.name)
+ self.image_creator = create_image.OpenStackImage(self.os_creds, file_image_settings)
+
+ self.image = self.image_creator.create()
+ self.assertIsNotNone(self.image)
+ self.assertEqual(self.image_name, self.image.name)
+
+ created_image = self.image_creator.create()
+ self.assertIsNotNone(created_image)
+
+ retrieved_image = glance_utils.get_image(self.nova, self.glance, file_image_settings.name)
+ self.assertIsNotNone(retrieved_image)
+
+ self.assertEquals(created_image.name, retrieved_image.name)
+ self.assertEquals(created_image.id, retrieved_image.id)
+
+ def test_create_delete_image(self):
+ """
+ Tests the creation then deletion of an OpenStack image to ensure clean() does not raise an Exception.
+ """
+ # Create Image
+ os_image_settings = openstack_tests.cirros_url_image(name=self.image_name)
+ self.image_creator = create_image.OpenStackImage(self.os_creds, os_image_settings)
+ created_image = self.image_creator.create()
+ self.assertIsNotNone(created_image)
+
+ # Delete Image manually
+ glance_utils.delete_image(self.glance, created_image)
+
+ self.assertIsNone(glance_utils.get_image(self.nova, self.glance, self.image_creator.image_settings.name))
+
+ # Must not throw an exception when attempting to cleanup non-existent image
+ self.image_creator.clean()
+ self.assertIsNone(self.image_creator.get_image())
+
+ def test_create_same_image(self):
+ """
+ Tests the creation of an OpenStack image when the image already exists.
+ """
+ # Create Image
+ os_image_settings = openstack_tests.cirros_url_image(name=self.image_name)
+ self.image_creator = create_image.OpenStackImage(self.os_creds, os_image_settings)
+ image1 = self.image_creator.create()
+ # Should be retrieving the instance data
+ os_image_2 = create_image.OpenStackImage(self.os_creds, os_image_settings)
+ image2 = os_image_2.create()
+ self.assertEquals(image1.id, image2.id)
+
+
+class CreateImageNegativeTests(OSIntegrationTestCase):
+ """
+ Negative test cases for the CreateImage class
+ """
+
+ def setUp(self):
+ super(self.__class__, self).__start__()
+
+ self.image_name = self.__class__.__name__ + '-' + str(uuid.uuid4())
+ self.image_creator = None
+
+ def tearDown(self):
+ if self.image_creator:
+ self.image_creator.clean()
+
+ super(self.__class__, self).__clean__()
+
+ def test_none_image_name(self):
+ """
+ Expect an exception when the image name is None
+ """
+ os_image_settings = openstack_tests.cirros_url_image(name=self.image_name)
+ with self.assertRaises(Exception):
+ self.image_creator = create_image.OpenStackImage(
+ self.os_creds, create_image.ImageSettings(
+ name=None, image_user=os_image_settings.image_user, img_format=os_image_settings.format,
+ url=os_image_settings.url))
+
+ self.fail('Exception should have been thrown prior to this line')
+
+ def test_bad_image_url(self):
+ """
+ Expect an exception when the image download url is bad
+ """
+ os_image_settings = openstack_tests.cirros_url_image(name=self.image_name)
+ self.image_creator = create_image.OpenStackImage(self.os_creds, create_image.ImageSettings(
+ name=os_image_settings.name, image_user=os_image_settings.image_user,
+ img_format=os_image_settings.format, url="http://foo.bar"))
+ with self.assertRaises(Exception):
+ self.image_creator.create()
+
+ def test_bad_image_file(self):
+ """
+ Expect an exception when the image file does not exist
+ """
+ os_image_settings = openstack_tests.cirros_url_image(name=self.image_name)
+ self.image_creator = create_image.OpenStackImage(
+ self.os_creds,
+ create_image.ImageSettings(name=os_image_settings.name, image_user=os_image_settings.image_user,
+ img_format=os_image_settings.format, image_file="/foo/bar.qcow"))
+ with self.assertRaises(Exception):
+ self.image_creator.create()
+
+ def test_none_proj_name(self):
+ """
+ Expect an exception when the project name is None
+ """
+ os_image_settings = openstack_tests.cirros_url_image(name=self.image_name)
+ with self.assertRaises(Exception):
+ self.image_creator = create_image.OpenStackImage(
+ os_credentials.OSCreds(self.os_creds.username, self.os_creds.password, self.os_creds.auth_url, None,
+ proxy_settings=self.os_creds.proxy_settings),
+ os_image_settings)
+ self.image_creator.create()
+
+ def test_none_auth_url(self):
+ """
+ Expect an exception when the project name is None
+ """
+ os_image_settings = openstack_tests.cirros_url_image(name=self.image_name)
+ with self.assertRaises(Exception):
+ self.image_creator = create_image.OpenStackImage(
+ os_credentials.OSCreds(self.os_creds.username, self.os_creds.password, None,
+ self.os_creds.project_name, proxy_settings=self.os_creds.proxy_settings),
+ os_image_settings)
+ self.image_creator.create()
+
+ def test_none_password(self):
+ """
+ Expect an exception when the project name is None
+ """
+ os_image_settings = openstack_tests.cirros_url_image(name=self.image_name)
+ with self.assertRaises(Exception):
+ self.image_creator = create_image.OpenStackImage(
+ os_credentials.OSCreds(self.os_creds.username, None, self.os_creds.os_auth_url,
+ self.os_creds.project_name, proxy_settings=self.os_creds.proxy_settings),
+ os_image_settings)
+
+ def test_none_user(self):
+ """
+ Expect an exception when the project name is None
+ """
+ os_image_settings = openstack_tests.cirros_url_image(name=self.image_name)
+ with self.assertRaises(Exception):
+ self.image_creator = create_image.OpenStackImage(
+ os_credentials.OSCreds(None, self.os_creds.password, self.os_creds.os_auth_url,
+ self.os_creds.project_name,
+ proxy_settings=self.os_creds.proxy_settings),
+ os_image_settings)
diff --git a/snaps/openstack/tests/create_instance_tests.py b/snaps/openstack/tests/create_instance_tests.py
new file mode 100644
index 0000000..756b45f
--- /dev/null
+++ b/snaps/openstack/tests/create_instance_tests.py
@@ -0,0 +1,1474 @@
+# Copyright (c) 2016 Cable Television Laboratories, Inc. ("CableLabs")
+# and others. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+import logging
+import os
+import time
+import unittest
+import uuid
+
+from snaps.openstack.create_instance import VmInstanceSettings, OpenStackVmInstance, FloatingIpSettings
+from snaps.openstack.create_flavor import OpenStackFlavor, FlavorSettings
+from snaps.openstack.create_keypairs import OpenStackKeypair, KeypairSettings
+from snaps.openstack.create_network import OpenStackNetwork, PortSettings
+from snaps.openstack.create_router import OpenStackRouter
+from snaps.openstack.create_image import OpenStackImage
+from snaps.openstack.create_security_group import SecurityGroupSettings, OpenStackSecurityGroup
+from snaps.openstack.tests import openstack_tests, validation_utils
+from snaps.openstack.utils import nova_utils
+from snaps.openstack.tests.os_source_file_test import OSComponentTestCase, OSIntegrationTestCase
+
+__author__ = 'spisarski'
+
+VM_BOOT_TIMEOUT = 600
+
+logger = logging.getLogger('create_instance_tests')
+
+
+class VmInstanceSettingsUnitTests(unittest.TestCase):
+ """
+ Tests the construction of the VmInstanceSettings class
+ """
+
+ def test_no_params(self):
+ with self.assertRaises(Exception):
+ VmInstanceSettings()
+
+ def test_empty_config(self):
+ with self.assertRaises(Exception):
+ VmInstanceSettings(config=dict())
+
+ def test_name_only(self):
+ with self.assertRaises(Exception):
+ VmInstanceSettings(name='foo')
+
+ def test_config_with_name_only(self):
+ with self.assertRaises(Exception):
+ VmInstanceSettings(config={'name': 'foo'})
+
+ def test_name_flavor_only(self):
+ settings = VmInstanceSettings(name='foo', flavor='bar')
+ self.assertEquals('foo', settings.name)
+ self.assertEquals('bar', settings.flavor)
+ self.assertEquals(0, len(settings.port_settings))
+ self.assertEquals(0, len(settings.security_group_names))
+ self.assertEquals(0, len(settings.floating_ip_settings))
+ self.assertIsNone(settings.sudo_user)
+ self.assertEquals(900, settings.vm_boot_timeout)
+ self.assertEquals(300, settings.vm_delete_timeout)
+ self.assertEquals(180, settings.ssh_connect_timeout)
+ self.assertIsNone(settings.availability_zone)
+
+ def test_config_with_name_flavor_only(self):
+ settings = VmInstanceSettings(config={'name': 'foo', 'flavor': 'bar'})
+ self.assertEquals('foo', settings.name)
+ self.assertEquals('bar', settings.flavor)
+ self.assertEquals(0, len(settings.port_settings))
+ self.assertEquals(0, len(settings.security_group_names))
+ self.assertEquals(0, len(settings.floating_ip_settings))
+ self.assertIsNone(settings.sudo_user)
+ self.assertEquals(900, settings.vm_boot_timeout)
+ self.assertEquals(300, settings.vm_delete_timeout)
+ self.assertEquals(180, settings.ssh_connect_timeout)
+ self.assertIsNone(settings.availability_zone)
+
+ 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')
+ self.assertEquals('foo', settings.name)
+ self.assertEquals('bar', settings.flavor)
+ self.assertEquals(1, len(settings.port_settings))
+ self.assertEquals('foo-port', settings.port_settings[0].name)
+ self.assertEquals('bar-net', settings.port_settings[0].network_name)
+ self.assertEquals(1, len(settings.security_group_names))
+ self.assertEquals('sec_grp_1', settings.security_group_names[0])
+ self.assertEquals(1, len(settings.floating_ip_settings))
+ self.assertEquals('foo-fip', settings.floating_ip_settings[0].name)
+ self.assertEquals('bar-port', settings.floating_ip_settings[0].port_name)
+ self.assertEquals('foo-bar-router', settings.floating_ip_settings[0].router_name)
+ self.assertEquals('joe', settings.sudo_user)
+ self.assertEquals(999, settings.vm_boot_timeout)
+ self.assertEquals(333, settings.vm_delete_timeout)
+ self.assertEquals(111, settings.ssh_connect_timeout)
+ self.assertEquals('server name', settings.availability_zone)
+
+ def test_config_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(config={'name': 'foo', 'flavor': 'bar', 'ports': [port_settings],
+ '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'})
+ self.assertEquals('foo', settings.name)
+ self.assertEquals('bar', settings.flavor)
+ self.assertEquals(1, len(settings.port_settings))
+ self.assertEquals('foo-port', settings.port_settings[0].name)
+ self.assertEquals('bar-net', settings.port_settings[0].network_name)
+ self.assertEquals(1, len(settings.security_group_names))
+ self.assertEquals(1, len(settings.floating_ip_settings))
+ self.assertEquals('foo-fip', settings.floating_ip_settings[0].name)
+ self.assertEquals('bar-port', settings.floating_ip_settings[0].port_name)
+ self.assertEquals('foo-bar-router', settings.floating_ip_settings[0].router_name)
+ self.assertEquals('joe', settings.sudo_user)
+ self.assertEquals(999, settings.vm_boot_timeout)
+ self.assertEquals(333, settings.vm_delete_timeout)
+ self.assertEquals(111, settings.ssh_connect_timeout)
+ self.assertEquals('server name', settings.availability_zone)
+
+
+class FloatingIpSettingsUnitTests(unittest.TestCase):
+ """
+ Tests the construction of the FloatingIpSettings class
+ """
+
+ def test_no_params(self):
+ with self.assertRaises(Exception):
+ FloatingIpSettings()
+
+ def test_empty_config(self):
+ with self.assertRaises(Exception):
+ FloatingIpSettings(config=dict())
+
+ def test_name_only(self):
+ with self.assertRaises(Exception):
+ FloatingIpSettings(name='foo')
+
+ def test_config_with_name_only(self):
+ with self.assertRaises(Exception):
+ FloatingIpSettings(config={'name': 'foo'})
+
+ def test_name_port_only(self):
+ with self.assertRaises(Exception):
+ FloatingIpSettings(name='foo', port_name='bar')
+
+ def test_config_with_name_port_only(self):
+ with self.assertRaises(Exception):
+ FloatingIpSettings(config={'name': 'foo', 'port_name': 'bar'})
+
+ def test_name_router_only(self):
+ with self.assertRaises(Exception):
+ FloatingIpSettings(name='foo', router_name='bar')
+
+ def test_config_with_name_router_only(self):
+ with self.assertRaises(Exception):
+ FloatingIpSettings(config={'name': 'foo', 'router_name': 'bar'})
+
+ def test_name_port_router_only(self):
+ settings = FloatingIpSettings(name='foo', port_name='foo-port', router_name='bar-router')
+ self.assertEquals('foo', settings.name)
+ self.assertEquals('foo-port', settings.port_name)
+ self.assertEquals('bar-router', settings.router_name)
+ self.assertIsNone(settings.subnet_name)
+ self.assertTrue(settings.provisioning)
+
+ def test_config_with_name_port_router_only(self):
+ settings = FloatingIpSettings(config={'name': 'foo', 'port_name': 'foo-port', 'router_name': 'bar-router'})
+ self.assertEquals('foo', settings.name)
+ self.assertEquals('foo-port', settings.port_name)
+ self.assertEquals('bar-router', settings.router_name)
+ self.assertIsNone(settings.subnet_name)
+ self.assertTrue(settings.provisioning)
+
+ def test_all(self):
+ settings = FloatingIpSettings(name='foo', port_name='foo-port', router_name='bar-router',
+ subnet_name='bar-subnet', provisioning=False)
+ self.assertEquals('foo', settings.name)
+ self.assertEquals('foo-port', settings.port_name)
+ self.assertEquals('bar-router', settings.router_name)
+ self.assertEquals('bar-subnet', settings.subnet_name)
+ self.assertFalse(settings.provisioning)
+
+ def test_config_all(self):
+ settings = FloatingIpSettings(config={'name': 'foo', 'port_name': 'foo-port', 'router_name': 'bar-router',
+ 'subnet_name': 'bar-subnet', 'provisioning': False})
+ self.assertEquals('foo', settings.name)
+ self.assertEquals('foo-port', settings.port_name)
+ self.assertEquals('bar-router', settings.router_name)
+ self.assertEquals('bar-subnet', settings.subnet_name)
+ self.assertFalse(settings.provisioning)
+
+
+class SimpleHealthCheck(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__()
+
+ guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
+ self.keypair_priv_filepath = 'tmp/' + guid
+ self.keypair_pub_filepath = self.keypair_priv_filepath + '.pub'
+ self.keypair_name = guid + '-kp'
+ self.vm_inst_name = guid + '-inst'
+ self.port_1_name = guid + 'port-1'
+ self.port_2_name = guid + 'port-2'
+ self.floating_ip_name = guid + 'fip1'
+
+ # Initialize for tearDown()
+ self.image_creator = None
+ self.network_creator = None
+ self.flavor_creator = None
+ self.inst_creator = None
+
+ self.priv_net_config = openstack_tests.get_priv_net_config(
+ net_name=guid + '-priv-net', subnet_name=guid + '-priv-subnet')
+ self.port_settings = PortSettings(
+ name=self.port_1_name, network_name=self.priv_net_config.network_settings.name)
+
+ self.os_image_settings = openstack_tests.cirros_url_image(name=guid + '-image')
+
+ try:
+ # Create Image
+ self.image_creator = OpenStackImage(self.os_creds, self.os_image_settings)
+ self.image_creator.create()
+
+ # Create Network
+ self.network_creator = OpenStackNetwork(self.os_creds, self.priv_net_config.network_settings)
+ self.network_creator.create()
+
+ # Create Flavor
+ self.flavor_creator = OpenStackFlavor(
+ self.admin_os_creds,
+ FlavorSettings(name=guid + '-flavor-name', ram=1024, disk=10, vcpus=1))
+ self.flavor_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 - ' + e.message)
+
+ 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()
+ except Exception as e:
+ logger.error('Unexpected exception cleaning flavor with message - ' + e.message)
+
+ if self.network_creator:
+ try:
+ self.network_creator.clean()
+ except Exception as e:
+ logger.error('Unexpected exception cleaning network with message - ' + e.message)
+
+ if self.image_creator:
+ try:
+ self.image_creator.clean()
+ except Exception as e:
+ logger.error('Unexpected exception cleaning image with message - ' + e.message)
+
+ super(self.__class__, self).__clean__()
+
+ def test_check_vm_ip_dhcp(self):
+ """
+ Tests the creation of an OpenStack instance with a single port and ensures that it's assigned IP address is
+ the actual.
+ """
+ instance_settings = VmInstanceSettings(
+ name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=[self.port_settings])
+
+ self.inst_creator = OpenStackVmInstance(self.os_creds, instance_settings, self.image_creator.image_settings)
+ vm = self.inst_creator.create()
+
+ ip = self.inst_creator.get_port_ip(self.port_settings.name)
+ self.assertIsNotNone(ip)
+
+ self.assertTrue(self.inst_creator.vm_active(block=True))
+
+ found = False
+ timeout = 100
+ start_time = time.time()
+ match_value = 'Lease of ' + ip + ' obtained,'
+
+ while timeout > time.time() - start_time:
+ output = vm.get_console_output()
+ if match_value in output:
+ found = True
+ break
+ self.assertTrue(found)
+
+
+class CreateInstanceSimpleTests(OSIntegrationTestCase):
+ """
+ Simple instance creation tests without any other objects
+ """
+ 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)
+ self.os_image_settings = openstack_tests.cirros_url_image(name=guid + '-image')
+
+ # Initialize for tearDown()
+ self.image_creator = None
+ self.flavor_creator = None
+ self.inst_creator = None
+
+ try:
+ # Create Image
+ self.image_creator = OpenStackImage(self.os_creds, self.os_image_settings)
+ self.image_creator.create()
+ # Create Flavor
+ self.flavor_creator = OpenStackFlavor(
+ self.admin_os_creds,
+ FlavorSettings(name=guid + '-flavor-name', ram=2048, disk=10, vcpus=2))
+ self.flavor_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 - ' + e.message)
+
+ if self.flavor_creator:
+ try:
+ self.flavor_creator.clean()
+ except Exception as e:
+ logger.error('Unexpected exception cleaning flavor with message - ' + e.message)
+
+ if self.image_creator:
+ try:
+ self.image_creator.clean()
+ except Exception as e:
+ logger.error('Unexpected exception cleaning image with message - ' + e.message)
+
+ super(self.__class__, self).__clean__()
+
+ def test_create_delete_instance(self):
+ """
+ Tests the creation of an OpenStack instance with a single port with a static IP without a Floating IP.
+ """
+ instance_settings = VmInstanceSettings(name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name)
+
+ self.inst_creator = OpenStackVmInstance(
+ self.os_creds, instance_settings, self.image_creator.image_settings)
+
+ vm_inst = self.inst_creator.create()
+ self.assertEquals(1, len(nova_utils.get_servers_by_name(self.nova, instance_settings.name)))
+
+ # Delete instance
+ nova_utils.delete_vm_instance(self.nova, vm_inst)
+
+ self.assertTrue(self.inst_creator.vm_deleted(block=True))
+ self.assertEquals(0, len(nova_utils.get_servers_by_name(self.nova, instance_settings.name)))
+
+ # Exception should not be thrown
+ self.inst_creator.clean()
+
+
+class CreateInstanceSingleNetworkTests(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__()
+
+ guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
+ self.keypair_priv_filepath = 'tmp/' + guid
+ self.keypair_pub_filepath = self.keypair_priv_filepath + '.pub'
+ self.keypair_name = guid + '-kp'
+ self.vm_inst_name = guid + '-inst'
+ self.port_1_name = guid + 'port-1'
+ self.port_2_name = guid + 'port-2'
+ self.floating_ip_name = guid + 'fip1'
+
+ # Initialize for tearDown()
+ self.image_creator = None
+ self.network_creator = None
+ self.router_creator = None
+ self.flavor_creator = None
+ self.keypair_creator = None
+ self.inst_creators = list()
+
+ self.pub_net_config = openstack_tests.get_pub_net_config(
+ net_name=guid + '-pub-net', subnet_name=guid + '-pub-subnet',
+ router_name=guid + '-pub-router', external_net=self.ext_net_name)
+ self.os_image_settings = openstack_tests.cirros_url_image(name=guid + '-image')
+
+ try:
+ # Create Image
+ self.image_creator = OpenStackImage(self.os_creds, self.os_image_settings)
+ self.image_creator.create()
+
+ # Create Network
+ self.network_creator = OpenStackNetwork(self.os_creds, self.pub_net_config.network_settings)
+ self.network_creator.create()
+
+ # Create Router
+ self.router_creator = OpenStackRouter(self.os_creds, self.pub_net_config.router_settings)
+ self.router_creator.create()
+
+ # Create Flavor
+ self.flavor_creator = OpenStackFlavor(
+ self.admin_os_creds,
+ FlavorSettings(name=guid + '-flavor-name', ram=2048, disk=10, vcpus=2))
+ self.flavor_creator.create()
+
+ self.keypair_creator = OpenStackKeypair(
+ self.os_creds, KeypairSettings(
+ name=self.keypair_name, public_filepath=self.keypair_pub_filepath,
+ private_filepath=self.keypair_priv_filepath))
+ self.keypair_creator.create()
+ except Exception as e:
+ self.tearDown()
+ raise e
+
+ def tearDown(self):
+ """
+ Cleans the created object
+ """
+ for inst_creator in self.inst_creators:
+ try:
+ inst_creator.clean()
+ except Exception as e:
+ logger.error('Unexpected exception cleaning VM instance with message - ' + e.message)
+
+ if self.keypair_creator:
+ try:
+ self.keypair_creator.clean()
+ except Exception as e:
+ logger.error('Unexpected exception cleaning keypair with message - ' + e.message)
+
+ 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()
+ except Exception as e:
+ logger.error('Unexpected exception cleaning flavor with message - ' + e.message)
+
+ if self.router_creator:
+ try:
+ self.router_creator.clean()
+ except Exception as e:
+ logger.error('Unexpected exception cleaning router with message - ' + e.message)
+
+ if self.network_creator:
+ try:
+ self.network_creator.clean()
+ except Exception as e:
+ logger.error('Unexpected exception cleaning network with message - ' + e.message)
+
+ if self.image_creator:
+ try:
+ self.image_creator.clean()
+ except Exception as e:
+ logger.error('Unexpected exception cleaning image with message - ' + e.message)
+
+ super(self.__class__, self).__clean__()
+
+ def test_single_port_static(self):
+ """
+ Tests the creation of an OpenStack instance with a single port with a static IP without a Floating IP.
+ """
+ ip_1 = '10.55.1.100'
+
+ port_settings = PortSettings(
+ name=self.port_1_name, network_name=self.pub_net_config.network_settings.name,
+ ip_addrs=[{'subnet_name': self.pub_net_config.network_settings.subnet_settings[0].name, 'ip': ip_1}])
+
+ instance_settings = VmInstanceSettings(
+ name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=[port_settings],
+ 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)
+ vm_inst = inst_creator.create()
+
+ self.assertEquals(ip_1, inst_creator.get_port_ip(self.port_1_name))
+ self.assertTrue(inst_creator.vm_active(block=True))
+ self.assertEquals(vm_inst, inst_creator.get_vm_inst())
+
+ def test_ssh_client_fip_before_active(self):
+ """
+ Tests the ability to access a VM via SSH and a floating IP when it has been assigned prior to being active.
+ """
+ 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],
+ 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)
+ vm_inst = inst_creator.create()
+ self.assertIsNotNone(vm_inst)
+
+ self.assertTrue(inst_creator.vm_active(block=True))
+ self.assertEquals(vm_inst, inst_creator.get_vm_inst())
+
+ validate_ssh_client(inst_creator)
+
+ def test_ssh_client_fip_after_active(self):
+ """
+ Tests the ability to access a VM via SSH and a floating IP when it has been assigned prior to being active.
+ """
+ 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],
+ 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))
+ self.assertEquals(vm_inst, inst_creator.get_vm_inst())
+
+ validate_ssh_client(inst_creator)
+
+ # TODO - Determine how allowed_address_pairs is supposed to operate before continuing this test
+ # see http://docs.openstack.org/developer/dragonflow/specs/allowed_address_pairs.html for a functional description
+ # def test_allowed_address_port_access(self):
+ # """
+ # Tests to ensure that setting allowed_address_pairs on a port functions as designed
+ # """
+ # port_settings_1 = PortSettings(
+ # name=self.port_1_name + '-1', network_name=self.pub_net_config.network_settings.name)
+ #
+ # instance_settings_1 = VmInstanceSettings(
+ # name=self.vm_inst_name + '-1', flavor=self.flavor_creator.flavor_settings.name, port_settings=[port_settings_1],
+ # floating_ip_settings=[FloatingIpSettings(
+ # name=self.floating_ip_name + '-1', port_name=port_settings_1.name,
+ # router_name=self.pub_net_config.router_settings.name)])
+ #
+ # inst_creator_1 = OpenStackVmInstance(
+ # self.os_creds, instance_settings_1, self.image_creator.image_settings,
+ # keypair_settings=self.keypair_creator.keypair_settings)
+ # self.inst_creators.append(inst_creator_1)
+ #
+ # # block=True will force the create() method to block until the
+ # vm_inst_1 = inst_creator_1.create(block=True)
+ # self.assertIsNotNone(vm_inst_1)
+ #
+ # port_settings_1 = PortSettings(
+ # name=self.port_1_name + '-1', network_name=self.pub_net_config.network_settings.name)
+ #
+ # instance_settings_1 = VmInstanceSettings(
+ # name=self.vm_inst_name + '-1', flavor=self.flavor_creator.flavor_settings.name, port_settings=[port_settings_1],
+ # floating_ip_settings=[FloatingIpSettings(
+ # name=self.floating_ip_name + '-1', port_name=port_settings_1.name,
+ # router_name=self.pub_net_config.router_settings.name)])
+ #
+ # inst_creator_1 = OpenStackVmInstance(
+ # self.os_creds, instance_settings_1, self.image_creator.image_settings,
+ # keypair_settings=self.keypair_creator.keypair_settings)
+ # self.inst_creators.append(inst_creator_1)
+ # inst_creator_1.create(block=True)
+ #
+ # ip = inst_creator_1.get_port_ip(port_settings_1.name,
+ # subnet_name=self.pub_net_config.network_settings.subnet_settings[0].name)
+ # self.assertIsNotNone(ip)
+ # mac_addr = inst_creator_1.get_port_mac(port_settings_1.name)
+ # self.assertIsNotNone(mac_addr)
+ #
+ # allowed_address_pairs = [{'ip_address': ip, 'mac_address': mac_addr}]
+ #
+ # # Create VM that can be accessed by vm_inst_1
+ # port_settings_2 = PortSettings(
+ # name=self.port_1_name + '-2', network_name=self.pub_net_config.network_settings.name,
+ # allowed_address_pairs=allowed_address_pairs)
+ #
+ # instance_settings_2 = VmInstanceSettings(
+ # name=self.vm_inst_name + '-2', flavor=self.flavor_creator.flavor_settings.name,
+ # port_settings=[port_settings_2])
+ #
+ # inst_creator_2 = OpenStackVmInstance(
+ # self.os_creds, instance_settings_2, self.image_creator.image_settings)
+ # self.inst_creators.append(inst_creator_2)
+ # inst_creator_2.create(block=True)
+ #
+ # # Create VM that cannot be accessed by vm_inst_1
+ # ip = '10.55.0.101'
+ # mac_addr = '0a:1b:2c:3d:4e:5f'
+ # invalid_address_pairs = [{'ip_address': ip, 'mac_address': mac_addr}]
+ #
+ # port_settings_3 = PortSettings(
+ # name=self.port_1_name + '-3', network_name=self.pub_net_config.network_settings.name,
+ # allowed_address_pairs=invalid_address_pairs)
+ #
+ # instance_settings_3 = VmInstanceSettings(
+ # name=self.vm_inst_name + '-3', flavor=self.flavor_creator.flavor_settings.name,
+ # port_settings=[port_settings_3])
+ #
+ # inst_creator_3 = OpenStackVmInstance(
+ # self.os_creds, instance_settings_3, self.image_creator.image_settings)
+ # self.inst_creators.append(inst_creator_3)
+ # inst_creator_3.create(block=True)
+ #
+ # print 'foo'
+ # I expected that this feature would block/allow traffic from specific endpoints (VMs). In this case, I would expect
+ # inst_1 to be able to access inst_2 but not inst_3; however, they all can access each other.
+ # TODO - Add validation
+
+
+class CreateInstancePortManipulationTests(OSIntegrationTestCase):
+ """
+ Test for the CreateInstance class with a single NIC/Port where mac and IP values are manually set
+ """
+
+ 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.port_1_name = guid + 'port-1'
+ self.port_2_name = guid + 'port-2'
+ self.floating_ip_name = guid + 'fip1'
+
+ # Initialize for tearDown()
+ self.image_creator = None
+ self.network_creator = None
+ self.flavor_creator = None
+ self.inst_creator = None
+
+ self.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.os_image_settings = openstack_tests.cirros_url_image(name=guid + '-image')
+
+ try:
+ # Create Image
+ self.image_creator = OpenStackImage(self.os_creds, self.os_image_settings)
+ self.image_creator.create()
+
+ # Create Network
+ self.network_creator = OpenStackNetwork(self.os_creds, self.net_config.network_settings)
+ self.network_creator.create()
+
+ # Create Flavor
+ self.flavor_creator = OpenStackFlavor(
+ self.admin_os_creds,
+ FlavorSettings(name=guid + '-flavor-name', ram=2048, disk=10, vcpus=2))
+ self.flavor_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 - ' + e.message)
+
+ if self.flavor_creator:
+ try:
+ self.flavor_creator.clean()
+ except Exception as e:
+ logger.error('Unexpected exception cleaning flavor with message - ' + e.message)
+
+ if self.network_creator:
+ try:
+ self.network_creator.clean()
+ except Exception as e:
+ logger.error('Unexpected exception cleaning network with message - ' + e.message)
+
+ if self.image_creator:
+ try:
+ self.image_creator.clean()
+ except Exception as e:
+ logger.error('Unexpected exception cleaning image with message - ' + e.message)
+
+ super(self.__class__, self).__clean__()
+
+ def test_set_custom_valid_ip_one_subnet(self):
+ """
+ Tests the creation of an OpenStack instance with a single port with a static IP on a network with one subnet.
+ """
+ ip = '10.55.0.101'
+ port_settings = PortSettings(
+ name=self.port_1_name, network_name=self.net_config.network_settings.name,
+ ip_addrs=[{'subnet_name': self.net_config.network_settings.subnet_settings[0].name, 'ip': ip}])
+
+ instance_settings = VmInstanceSettings(
+ name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=[port_settings])
+
+ self.inst_creator = OpenStackVmInstance(self.os_creds, instance_settings, self.image_creator.image_settings)
+ self.inst_creator.create()
+
+ self.assertEquals(ip, self.inst_creator.get_port_ip(
+ self.port_1_name, subnet_name=self.net_config.network_settings.subnet_settings[0].name))
+
+ def test_set_custom_invalid_ip_one_subnet(self):
+ """
+ Tests the creation of an OpenStack instance with a single port with a static IP on a network with one subnet.
+ """
+ ip = '10.66.0.101'
+ port_settings = PortSettings(
+ name=self.port_1_name, network_name=self.net_config.network_settings.name,
+ ip_addrs=[{'subnet_name': self.net_config.network_settings.subnet_settings[0].name, 'ip': ip}])
+
+ instance_settings = VmInstanceSettings(
+ name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=[port_settings])
+
+ self.inst_creator = OpenStackVmInstance(self.os_creds, instance_settings, self.image_creator.image_settings)
+
+ with self.assertRaises(Exception):
+ self.inst_creator.create()
+
+ def test_set_custom_valid_mac(self):
+ """
+ Tests the creation of an OpenStack instance with a single port where the MAC address is assigned.
+ """
+ mac_addr = '0a:1b:2c:3d:4e:5f'
+ port_settings = PortSettings(
+ name=self.port_1_name, network_name=self.net_config.network_settings.name, mac_address=mac_addr)
+
+ instance_settings = VmInstanceSettings(
+ name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=[port_settings])
+
+ self.inst_creator = OpenStackVmInstance(self.os_creds, instance_settings, self.image_creator.image_settings)
+ self.inst_creator.create()
+
+ self.assertEquals(mac_addr, self.inst_creator.get_port_mac(self.port_1_name))
+
+ def test_set_custom_invalid_mac(self):
+ """
+ Tests the creation of an OpenStack instance with a single port where an invalid MAC address value is being
+ assigned. This should raise an Exception
+ """
+ port_settings = PortSettings(
+ name=self.port_1_name, network_name=self.net_config.network_settings.name, mac_address='foo')
+
+ instance_settings = VmInstanceSettings(
+ name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=[port_settings])
+
+ self.inst_creator = OpenStackVmInstance(
+ self.os_creds, instance_settings, self.image_creator.image_settings)
+
+ with self.assertRaises(Exception):
+ self.inst_creator.create()
+
+ def test_set_custom_mac_and_ip(self):
+ """
+ Tests the creation of an OpenStack instance with a single port where the IP and MAC address is assigned.
+ """
+ ip = '10.55.0.101'
+ mac_addr = '0a:1b:2c:3d:4e:5f'
+ port_settings = PortSettings(
+ name=self.port_1_name, network_name=self.net_config.network_settings.name, mac_address=mac_addr,
+ ip_addrs=[{'subnet_name': self.net_config.network_settings.subnet_settings[0].name, 'ip': ip}])
+
+ instance_settings = VmInstanceSettings(
+ name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=[port_settings])
+
+ self.inst_creator = OpenStackVmInstance(self.os_creds, instance_settings, self.image_creator.image_settings)
+ self.inst_creator.create()
+
+ self.assertEquals(ip, self.inst_creator.get_port_ip(
+ self.port_1_name, subnet_name=self.net_config.network_settings.subnet_settings[0].name))
+ self.assertEquals(mac_addr, self.inst_creator.get_port_mac(self.port_1_name))
+
+ def test_set_allowed_address_pairs(self):
+ """
+ Tests the creation of an OpenStack instance with a single port where max_allowed_address_pair is set.
+ """
+ ip = '10.55.0.101'
+ mac_addr = '0a:1b:2c:3d:4e:5f'
+ pair = {'ip_address': ip, 'mac_address': mac_addr}
+ port_settings = PortSettings(
+ name=self.port_1_name, network_name=self.net_config.network_settings.name, allowed_address_pairs=[pair])
+
+ instance_settings = VmInstanceSettings(
+ name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=[port_settings])
+
+ self.inst_creator = OpenStackVmInstance(self.os_creds, instance_settings, self.image_creator.image_settings)
+ self.inst_creator.create()
+
+ port = self.inst_creator.get_port_by_name(port_settings.name)
+ self.assertIsNotNone(port)
+ self.assertIsNotNone(port['port'].get('allowed_address_pairs'))
+ self.assertEquals(1, len(port['port']['allowed_address_pairs']))
+ validation_utils.objects_equivalent(pair, port['port']['allowed_address_pairs'][0])
+
+ def test_set_allowed_address_pairs_bad_mac(self):
+ """
+ Tests the creation of an OpenStack instance with a single port where max_allowed_address_pair is set with an
+ invalid MAC address.
+ """
+ ip = '10.55.0.101'
+ mac_addr = 'foo'
+ pair = {'ip_address': ip, 'mac_address': mac_addr}
+ pairs = set()
+ pairs.add((ip, mac_addr))
+ port_settings = PortSettings(
+ name=self.port_1_name, network_name=self.net_config.network_settings.name, allowed_address_pairs=[pair])
+
+ instance_settings = VmInstanceSettings(
+ name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=[port_settings])
+
+ self.inst_creator = OpenStackVmInstance(self.os_creds, instance_settings, self.image_creator.image_settings)
+ with self.assertRaises(Exception):
+ self.inst_creator.create()
+
+ def test_set_allowed_address_pairs_bad_ip(self):
+ """
+ Tests the creation of an OpenStack instance with a single port where max_allowed_address_pair is set with an
+ invalid MAC address.
+ """
+ ip = 'foo'
+ mac_addr = '0a:1b:2c:3d:4e:5f'
+ pair = {'ip_address': ip, 'mac_address': mac_addr}
+ pairs = set()
+ pairs.add((ip, mac_addr))
+ port_settings = PortSettings(
+ name=self.port_1_name, network_name=self.net_config.network_settings.name, allowed_address_pairs=[pair])
+
+ instance_settings = VmInstanceSettings(
+ name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=[port_settings])
+
+ self.inst_creator = OpenStackVmInstance(self.os_creds, instance_settings, self.image_creator.image_settings)
+ with self.assertRaises(Exception):
+ self.inst_creator.create()
+
+
+class CreateInstanceOnComputeHost(OSComponentTestCase):
+ """
+ Test for the CreateInstance where one VM is deployed to each compute node
+ """
+
+ def setUp(self):
+ """
+ Instantiates the CreateImage object that is responsible for downloading and creating an OS image file
+ within OpenStack
+ """
+ guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
+ self.vm_inst_name = guid + '-inst'
+ self.port_base_name = guid + 'port'
+
+ # Initialize for tearDown()
+ self.image_creator = None
+ self.flavor_creator = None
+ self.network_creator = None
+ self.inst_creators = list()
+
+ self.priv_net_config = openstack_tests.get_priv_net_config(
+ net_name=guid + '-priv-net', subnet_name=guid + '-priv-subnet')
+
+ self.os_image_settings = openstack_tests.cirros_url_image(name=guid + '-image')
+
+ try:
+ # Create Network
+ self.network_creator = OpenStackNetwork(self.os_creds, self.priv_net_config.network_settings)
+ self.network_creator.create()
+
+ # Create Flavor
+ self.flavor_creator = OpenStackFlavor(
+ self.os_creds,
+ FlavorSettings(name=guid + '-flavor-name', ram=512, disk=1, vcpus=1))
+ self.flavor_creator.create()
+
+ # Create Image
+ self.image_creator = OpenStackImage(self.os_creds, self.os_image_settings)
+ self.image_creator.create()
+
+ except Exception as e:
+ self.tearDown()
+ raise e
+
+ def tearDown(self):
+ """
+ Cleans the created object
+ """
+ for inst_creator in self.inst_creators:
+ try:
+ inst_creator.clean()
+ except Exception as e:
+ logger.error('Unexpected exception cleaning VM instance with message - ' + e.message)
+
+ if self.flavor_creator:
+ try:
+ self.flavor_creator.clean()
+ except Exception as e:
+ logger.error('Unexpected exception cleaning flavor with message - ' + e.message)
+
+ if self.network_creator:
+ try:
+ self.network_creator.clean()
+ except Exception as e:
+ logger.error('Unexpected exception cleaning network with message - ' + e.message)
+
+ if self.image_creator:
+ try:
+ self.image_creator.clean()
+ except Exception as e:
+ logger.error('Unexpected exception cleaning image with message - ' + e.message)
+
+ def test_deploy_vm_to_each_compute_node(self):
+ """
+ Tests the creation of OpenStack VM instances to each compute node.
+ """
+ from snaps.openstack.utils import nova_utils
+ nova = nova_utils.nova_client(self.os_creds)
+ zones = nova_utils.get_nova_availability_zones(nova)
+
+ # Create Instance on each server/zone
+ ctr = 0
+ for zone in zones:
+ inst_name = self.vm_inst_name + '-' + zone
+ ctr += 1
+ port_settings = PortSettings(name=self.port_base_name + '-' + str(ctr),
+ network_name=self.priv_net_config.network_settings.name)
+
+ instance_settings = VmInstanceSettings(
+ name=inst_name, flavor=self.flavor_creator.flavor_settings.name, availability_zone=zone,
+ port_settings=[port_settings])
+ inst_creator = OpenStackVmInstance(
+ self.os_creds, instance_settings, self.image_creator.image_settings)
+ self.inst_creators.append(inst_creator)
+ inst_creator.create()
+
+ # Validate instances to ensure they've been deployed to the correct server
+ index = 0
+ for zone in zones:
+ creator = self.inst_creators[index]
+ self.assertTrue(creator.vm_active(block=True))
+ vm = creator.get_vm_inst()
+ deployed_zone = vm._info['OS-EXT-AZ:availability_zone']
+ deployed_host = vm._info['OS-EXT-SRV-ATTR:host']
+ self.assertEquals(zone, deployed_zone + ':' + deployed_host)
+ index += 1
+
+
+class CreateInstancePubPrivNetTests(OSIntegrationTestCase):
+ """
+ Test for the CreateInstance class with two NIC/Ports, eth0 with floating IP and eth1 w/o
+ These tests require a Centos image
+ """
+
+ 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__()
+
+ # Initialize for tearDown()
+ self.image_creator = None
+ self.network_creators = list()
+ self.router_creators = list()
+ self.flavor_creator = None
+ self.keypair_creator = None
+ self.inst_creator = None
+
+ 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.port_1_name = self.guid + '-port-1'
+ self.port_2_name = self.guid + '-port-2'
+ self.floating_ip_name = self.guid + 'fip1'
+ self.priv_net_config = openstack_tests.get_priv_net_config(
+ net_name=self.guid + '-priv-net', subnet_name=self.guid + '-priv-subnet',
+ router_name=self.guid + '-priv-router', external_net=self.ext_net_name)
+ self.pub_net_config = openstack_tests.get_pub_net_config(
+ net_name=self.guid + '-pub-net', subnet_name=self.guid + '-pub-subnet',
+ router_name=self.guid + '-pub-router', external_net=self.ext_net_name)
+ image_name = self.__class__.__name__ + '-' + str(uuid.uuid4())
+ self.os_image_settings = openstack_tests.centos_url_image(name=image_name)
+
+ try:
+ # Create Image
+ self.image_creator = OpenStackImage(self.os_creds, self.os_image_settings)
+ self.image_creator.create()
+
+ # First network is public
+ self.network_creators.append(OpenStackNetwork(self.os_creds, self.pub_net_config.network_settings))
+ # Second network is private
+ self.network_creators.append(OpenStackNetwork(self.os_creds, self.priv_net_config.network_settings))
+ for network_creator in self.network_creators:
+ network_creator.create()
+
+ self.router_creators.append(OpenStackRouter(self.os_creds, self.pub_net_config.router_settings))
+ self.router_creators.append(OpenStackRouter(self.os_creds, self.priv_net_config.router_settings))
+
+ # Create Routers
+ for router_creator in self.router_creators:
+ router_creator.create()
+
+ # Create Flavor
+ self.flavor_creator = OpenStackFlavor(
+ self.admin_os_creds,
+ FlavorSettings(name=self.guid + '-flavor-name', ram=2048, disk=10, vcpus=2))
+ self.flavor_creator.create()
+
+ # Create Keypair
+ self.keypair_creator = OpenStackKeypair(
+ self.os_creds, KeypairSettings(
+ name=self.keypair_name, public_filepath=self.keypair_pub_filepath,
+ private_filepath=self.keypair_priv_filepath))
+ self.keypair_creator.create()
+ except Exception as e:
+ self.tearDown()
+ raise Exception(e.message)
+
+ def tearDown(self):
+ """
+ Cleans the created objects
+ """
+ if self.inst_creator:
+ try:
+ self.inst_creator.clean()
+ except Exception as e:
+ logger.error('Unexpected exception cleaning VM instance with message - ' + e.message)
+
+ if self.keypair_creator:
+ try:
+ self.keypair_creator.clean()
+ except Exception as e:
+ logger.error('Unexpected exception cleaning keypair with message - ' + e.message)
+
+ 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()
+ except Exception as e:
+ logger.error('Unexpected exception cleaning flavor with message - ' + e.message)
+
+ for router_creator in self.router_creators:
+ try:
+ router_creator.clean()
+ except Exception as e:
+ logger.error('Unexpected exception cleaning router with message - ' + e.message)
+
+ for network_creator in self.network_creators:
+ try:
+ network_creator.clean()
+ except Exception as e:
+ logger.error('Unexpected exception cleaning network with message - ' + e.message)
+
+ if self.image_creator:
+ try:
+ self.image_creator.clean()
+ except Exception as e:
+ logger.error('Unexpected exception cleaning image with message - ' + e.message)
+
+ super(self.__class__, self).__clean__()
+
+ def test_dual_ports_dhcp(self):
+ """
+ Tests the creation of an OpenStack instance with a dual ports/NICs with a DHCP assigned IP.
+ NOTE: This test and any others that call ansible will most likely fail unless you do one of
+ two things:
+ 1. Have a ~/.ansible.cfg (or alternate means) to set host_key_checking = False
+ 2. Set the following environment variable in your executing shell: ANSIBLE_HOST_KEY_CHECKING=False
+ Should this not be performed, the creation of the host ssh key will cause your ansible calls to fail.
+ """
+ # 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
+
+ # Create instance
+ instance_settings = VmInstanceSettings(
+ name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=ports_settings,
+ floating_ip_settings=[FloatingIpSettings(
+ name=self.floating_ip_name, port_name=self.port_1_name,
+ router_name=self.pub_net_config.router_settings.name)])
+
+ self.inst_creator = OpenStackVmInstance(
+ self.os_creds, instance_settings, self.image_creator.image_settings,
+ keypair_settings=self.keypair_creator.keypair_settings)
+
+ vm_inst = self.inst_creator.create(block=True)
+
+ self.assertEquals(vm_inst, self.inst_creator.get_vm_inst())
+
+ # Effectively blocks until VM has been properly activated
+ self.assertTrue(self.inst_creator.vm_active(block=True))
+
+ # Effectively blocks until VM's ssh port has been opened
+ self.assertTrue(self.inst_creator.vm_ssh_active(block=True))
+
+ 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
+
+
+class InstanceSecurityGroupTests(OSIntegrationTestCase):
+ """
+ Tests that include, add, and remove security groups from VM instances
+ """
+ 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.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
+ self.vm_inst_name = self.guid + '-inst'
+ self.nova = nova_utils.nova_client(self.os_creds)
+ self.os_image_settings = openstack_tests.cirros_url_image(name=self.guid + '-image')
+
+ 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.port_1_name = self.guid + 'port-1'
+ self.port_2_name = self.guid + 'port-2'
+ self.floating_ip_name = self.guid + 'fip1'
+
+ self.pub_net_config = openstack_tests.get_pub_net_config(
+ net_name=self.guid + '-pub-net', subnet_name=self.guid + '-pub-subnet',
+ router_name=self.guid + '-pub-router', external_net=self.ext_net_name)
+
+ # Initialize for tearDown()
+ self.image_creator = None
+ self.keypair_creator = None
+ self.flavor_creator = None
+ self.network_creator = None
+ self.router_creator = None
+ self.inst_creator = None
+ self.sec_grp_creators = list()
+
+ try:
+ # Create Image
+ self.image_creator = OpenStackImage(self.os_creds, self.os_image_settings)
+ self.image_creator.create()
+
+ # Create Network
+ self.network_creator = OpenStackNetwork(self.os_creds, self.pub_net_config.network_settings)
+ self.network_creator.create()
+
+ # Create Router
+ self.router_creator = OpenStackRouter(self.os_creds, self.pub_net_config.router_settings)
+ self.router_creator.create()
+
+ # Create Flavor
+ self.flavor_creator = OpenStackFlavor(
+ self.admin_os_creds,
+ FlavorSettings(name=self.guid + '-flavor-name', ram=2048, disk=10, vcpus=2))
+ self.flavor_creator.create()
+
+ self.keypair_creator = OpenStackKeypair(
+ self.os_creds, KeypairSettings(
+ name=self.keypair_name, public_filepath=self.keypair_pub_filepath,
+ private_filepath=self.keypair_priv_filepath))
+ self.keypair_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 - ' + e.message)
+
+ for sec_grp_creator in self.sec_grp_creators:
+ try:
+ sec_grp_creator.clean()
+ except Exception as e:
+ logger.error('Unexpected exception cleaning security group with message - ' + e.message)
+
+ if self.keypair_creator:
+ try:
+ self.keypair_creator.clean()
+ except Exception as e:
+ logger.error('Unexpected exception cleaning keypair with message - ' + e.message)
+
+ 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()
+ except Exception as e:
+ logger.error('Unexpected exception cleaning flavor with message - ' + e.message)
+
+ if self.router_creator:
+ try:
+ self.router_creator.clean()
+ except Exception as e:
+ logger.error('Unexpected exception cleaning router with message - ' + e.message)
+
+ if self.network_creator:
+ try:
+ self.network_creator.clean()
+ except Exception as e:
+ logger.error('Unexpected exception cleaning network with message - ' + e.message)
+
+ if self.image_creator:
+ try:
+ self.image_creator.clean()
+ except Exception as e:
+ logger.error('Unexpected exception cleaning image with message - ' + e.message)
+
+ super(self.__class__, self).__clean__()
+
+ def test_add_security_group(self):
+ """
+ Tests the addition of a security group created after the instance.
+ """
+ # Create instance
+ instance_settings = VmInstanceSettings(
+ name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name)
+ self.inst_creator = OpenStackVmInstance(self.os_creds, instance_settings, self.image_creator.image_settings)
+ vm_inst = self.inst_creator.create()
+ self.assertIsNotNone(vm_inst)
+
+ # Create security group object to add to instance
+ sec_grp_settings = SecurityGroupSettings(name=self.guid + '-name', description='hello group')
+ sec_grp_creator = OpenStackSecurityGroup(self.os_creds, sec_grp_settings)
+ sec_grp = sec_grp_creator.create()
+ self.sec_grp_creators.append(sec_grp_creator)
+
+ # Check that group has not been added
+ self.assertFalse(inst_has_sec_grp(self.inst_creator.get_vm_inst(), sec_grp_settings.name))
+
+ # Add security group to instance after activated
+ self.inst_creator.add_security_group(sec_grp)
+
+ # Validate that security group has been added
+ self.assertTrue(inst_has_sec_grp(self.inst_creator.get_vm_inst(), sec_grp_settings.name))
+
+ def test_add_invalid_security_group(self):
+ """
+ Tests the addition of a security group that no longer exists.
+ """
+ # Create instance
+ instance_settings = VmInstanceSettings(
+ name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name)
+ self.inst_creator = OpenStackVmInstance(self.os_creds, instance_settings, self.image_creator.image_settings)
+ vm_inst = self.inst_creator.create()
+ self.assertIsNotNone(vm_inst)
+
+ # Create security group object to add to instance
+ sec_grp_settings = SecurityGroupSettings(name=self.guid + '-name', description='hello group')
+ sec_grp_creator = OpenStackSecurityGroup(self.os_creds, sec_grp_settings)
+ sec_grp = sec_grp_creator.create()
+ sec_grp_creator.clean()
+ self.sec_grp_creators.append(sec_grp_creator)
+
+ # Check that group has not been added
+ self.assertFalse(inst_has_sec_grp(self.inst_creator.get_vm_inst(), sec_grp_settings.name))
+
+ # Add security group to instance after activated
+ self.assertFalse(self.inst_creator.add_security_group(sec_grp))
+
+ # Validate that security group has been added
+ self.assertFalse(inst_has_sec_grp(self.inst_creator.get_vm_inst(), sec_grp_settings.name))
+
+ def test_remove_security_group(self):
+ """
+ Tests the removal of a security group created before and added to the instance.
+ """
+ # Create security group object to add to instance
+ sec_grp_settings = SecurityGroupSettings(name=self.guid + '-name', description='hello group')
+ sec_grp_creator = OpenStackSecurityGroup(self.os_creds, sec_grp_settings)
+ sec_grp = sec_grp_creator.create()
+ self.sec_grp_creators.append(sec_grp_creator)
+
+ # Create instance
+ instance_settings = VmInstanceSettings(
+ name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name,
+ security_group_names=[sec_grp_settings.name])
+ self.inst_creator = OpenStackVmInstance(self.os_creds, instance_settings, self.image_creator.image_settings)
+ vm_inst = self.inst_creator.create()
+ self.assertIsNotNone(vm_inst)
+
+ # Check that group has been added
+ self.assertTrue(inst_has_sec_grp(vm_inst, sec_grp_settings.name))
+
+ # Add security group to instance after activated
+ self.assertTrue(self.inst_creator.remove_security_group(sec_grp))
+
+ # Validate that security group has been added
+ self.assertFalse(inst_has_sec_grp(self.inst_creator.get_vm_inst(), sec_grp_settings.name))
+
+ def test_remove_security_group_never_added(self):
+ """
+ Tests the removal of a security group that was never added in the first place.
+ """
+ # Create security group object to add to instance
+ sec_grp_settings = SecurityGroupSettings(name=self.guid + '-name', description='hello group')
+ sec_grp_creator = OpenStackSecurityGroup(self.os_creds, sec_grp_settings)
+ sec_grp = sec_grp_creator.create()
+ self.sec_grp_creators.append(sec_grp_creator)
+
+ # Create instance
+ instance_settings = VmInstanceSettings(
+ name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name)
+ self.inst_creator = OpenStackVmInstance(self.os_creds, instance_settings, self.image_creator.image_settings)
+ vm_inst = self.inst_creator.create()
+ self.assertIsNotNone(vm_inst)
+
+ # Check that group has been added
+ self.assertFalse(inst_has_sec_grp(vm_inst, sec_grp_settings.name))
+
+ # Add security group to instance after activated
+ self.assertFalse(self.inst_creator.remove_security_group(sec_grp))
+
+ # Validate that security group has been added
+ self.assertFalse(inst_has_sec_grp(self.inst_creator.get_vm_inst(), sec_grp_settings.name))
+
+ def test_add_same_security_group(self):
+ """
+ Tests the addition of a security group created before add added to the instance.
+ """
+ # Create security group object to add to instance
+ sec_grp_settings = SecurityGroupSettings(name=self.guid + '-name', description='hello group')
+ sec_grp_creator = OpenStackSecurityGroup(self.os_creds, sec_grp_settings)
+ sec_grp = sec_grp_creator.create()
+ self.sec_grp_creators.append(sec_grp_creator)
+
+ # Create instance
+ instance_settings = VmInstanceSettings(
+ name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name,
+ security_group_names=[sec_grp_settings.name])
+ self.inst_creator = OpenStackVmInstance(self.os_creds, instance_settings, self.image_creator.image_settings)
+ vm_inst = self.inst_creator.create()
+ self.assertIsNotNone(vm_inst)
+
+ # Check that group has been added
+ self.assertTrue(inst_has_sec_grp(vm_inst, sec_grp_settings.name))
+
+ # Add security group to instance after activated
+ self.assertTrue(self.inst_creator.add_security_group(sec_grp))
+
+ # Validate that security group has been added
+ self.assertTrue(inst_has_sec_grp(self.inst_creator.get_vm_inst(), sec_grp_settings.name))
+
+
+def inst_has_sec_grp(vm_inst, sec_grp_name):
+ """
+ Returns true if instance has a security group of a given name
+ :return:
+ """
+ if not hasattr(vm_inst, 'security_groups'):
+ return False
+
+ found = False
+ for sec_grp_dict in vm_inst.security_groups:
+ if sec_grp_name in sec_grp_dict['name']:
+ found = True
+ break
+ return found
+
+
+def validate_ssh_client(instance_creator):
+ """
+ Returns True if instance_creator returns an SSH client that is valid
+ :param instance_creator: the object responsible for creating the VM instance
+ :return: T/F
+ """
+ ssh_active = instance_creator.vm_ssh_active(block=True)
+
+ if ssh_active:
+ ssh_client = instance_creator.ssh_client()
+ if ssh_client:
+ out = ssh_client.exec_command('pwd')[1]
+ 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
diff --git a/snaps/openstack/tests/create_keypairs_tests.py b/snaps/openstack/tests/create_keypairs_tests.py
new file mode 100644
index 0000000..e4409a9
--- /dev/null
+++ b/snaps/openstack/tests/create_keypairs_tests.py
@@ -0,0 +1,203 @@
+# Copyright (c) 2016 Cable Television Laboratories, Inc. ("CableLabs")
+# and others. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+import os
+import uuid
+import unittest
+
+from Crypto.PublicKey import RSA
+
+from snaps.openstack.create_keypairs import KeypairSettings, OpenStackKeypair
+from snaps.openstack.utils import nova_utils
+from snaps.openstack.tests.os_source_file_test import OSIntegrationTestCase
+
+__author__ = 'spisarski'
+
+
+class KeypairSettingsUnitTests(unittest.TestCase):
+ """
+ Tests the construction of the KeypairSettings class
+ """
+
+ def test_no_params(self):
+ with self.assertRaises(Exception):
+ KeypairSettings()
+
+ def test_empty_config(self):
+ with self.assertRaises(Exception):
+ KeypairSettings(config=dict())
+
+ def test_name_only(self):
+ settings = KeypairSettings(name='foo')
+ self.assertEquals('foo', settings.name)
+ self.assertIsNone(settings.public_filepath)
+ self.assertIsNone(settings.private_filepath)
+
+ def test_config_with_name_only(self):
+ settings = KeypairSettings(config={'name': 'foo'})
+ self.assertEquals('foo', settings.name)
+ self.assertIsNone(settings.public_filepath)
+ self.assertIsNone(settings.private_filepath)
+
+ def test_name_pub_only(self):
+ settings = KeypairSettings(name='foo', public_filepath='/foo/bar.pub')
+ self.assertEquals('foo', settings.name)
+ self.assertEquals('/foo/bar.pub', settings.public_filepath)
+ self.assertIsNone(settings.private_filepath)
+
+ def test_config_with_name_pub_only(self):
+ settings = KeypairSettings(config={'name': 'foo', 'public_filepath': '/foo/bar.pub'})
+ self.assertEquals('foo', settings.name)
+ self.assertEquals('/foo/bar.pub', settings.public_filepath)
+ self.assertIsNone(settings.private_filepath)
+
+ def test_name_priv_only(self):
+ settings = KeypairSettings(name='foo', private_filepath='/foo/bar')
+ self.assertEquals('foo', settings.name)
+ self.assertIsNone(settings.public_filepath)
+ self.assertEquals('/foo/bar', settings.private_filepath)
+
+ def test_config_with_name_priv_only(self):
+ settings = KeypairSettings(config={'name': 'foo', 'private_filepath': '/foo/bar'})
+ self.assertEquals('foo', settings.name)
+ self.assertIsNone(settings.public_filepath)
+ self.assertEquals('/foo/bar', settings.private_filepath)
+
+ def test_all(self):
+ settings = KeypairSettings(name='foo', public_filepath='/foo/bar.pub', private_filepath='/foo/bar')
+ self.assertEquals('foo', settings.name)
+ self.assertEquals('/foo/bar.pub', settings.public_filepath)
+ self.assertEquals('/foo/bar', settings.private_filepath)
+
+ def test_config_all(self):
+ settings = KeypairSettings(config={'name': 'foo', 'public_filepath': '/foo/bar.pub',
+ 'private_filepath': '/foo/bar'})
+ self.assertEquals('foo', settings.name)
+ self.assertEquals('/foo/bar.pub', settings.public_filepath)
+ self.assertEquals('/foo/bar', settings.private_filepath)
+
+
+class CreateKeypairsTests(OSIntegrationTestCase):
+ """
+ Tests for the OpenStackKeypair class
+ """
+
+ def setUp(self):
+ super(self.__class__, self).__start__()
+
+ guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
+ self.priv_file_path = 'tmp/' + guid
+ self.pub_file_path = self.priv_file_path + '.pub'
+ self.nova = nova_utils.nova_client(self.os_creds)
+ self.keypair_name = guid
+
+ self.keypair_creator = None
+
+ def tearDown(self):
+ """
+ Cleanup of created keypair
+ """
+ if self.keypair_creator:
+ self.keypair_creator.clean()
+
+ try:
+ os.remove(self.pub_file_path)
+ except:
+ pass
+
+ try:
+ os.remove(self.priv_file_path)
+ except:
+ pass
+
+ super(self.__class__, self).__clean__()
+
+ def test_create_keypair_only(self):
+ """
+ Tests the creation of a generated keypair without saving to file
+ :return:
+ """
+ self.keypair_creator = OpenStackKeypair(self.os_creds, KeypairSettings(name=self.keypair_name))
+ self.keypair_creator.create()
+
+ keypair = nova_utils.keypair_exists(self.nova, self.keypair_creator.get_keypair())
+ self.assertEquals(self.keypair_creator.get_keypair(), keypair)
+
+ def test_create_delete_keypair(self):
+ """
+ Tests the creation then deletion of an OpenStack keypair to ensure clean() does not raise an Exception.
+ """
+ # Create Image
+ self.keypair_creator = OpenStackKeypair(self.os_creds, KeypairSettings(name=self.keypair_name))
+ created_keypair = self.keypair_creator.create()
+ self.assertIsNotNone(created_keypair)
+
+ # Delete Image manually
+ nova_utils.delete_keypair(self.nova, created_keypair)
+
+ self.assertIsNone(nova_utils.get_keypair_by_name(self.nova, self.keypair_name))
+
+ # Must not throw an exception when attempting to cleanup non-existent image
+ self.keypair_creator.clean()
+ self.assertIsNone(self.keypair_creator.get_keypair())
+
+ def test_create_keypair_save_pub_only(self):
+ """
+ Tests the creation of a generated keypair and saves the public key only
+ :return:
+ """
+ self.keypair_creator = OpenStackKeypair(
+ self.os_creds, KeypairSettings(name=self.keypair_name, public_filepath=self.pub_file_path))
+ self.keypair_creator.create()
+
+ keypair = nova_utils.keypair_exists(self.nova, self.keypair_creator.get_keypair())
+ self.assertEquals(self.keypair_creator.get_keypair(), keypair)
+
+ file_key = open(os.path.expanduser(self.pub_file_path)).read()
+ self.assertEquals(self.keypair_creator.get_keypair().public_key, file_key)
+
+ def test_create_keypair_save_both(self):
+ """
+ Tests the creation of a generated keypair and saves both private and public key files[
+ :return:
+ """
+ self.keypair_creator = OpenStackKeypair(
+ self.os_creds, KeypairSettings(name=self.keypair_name, public_filepath=self.pub_file_path,
+ private_filepath=self.priv_file_path))
+ self.keypair_creator.create()
+
+ keypair = nova_utils.keypair_exists(self.nova, self.keypair_creator.get_keypair())
+ self.assertEquals(self.keypair_creator.get_keypair(), keypair)
+
+ file_key = open(os.path.expanduser(self.pub_file_path)).read()
+ self.assertEquals(self.keypair_creator.get_keypair().public_key, file_key)
+
+ self.assertTrue(os.path.isfile(self.priv_file_path))
+
+ def test_create_keypair_from_file(self):
+ """
+ Tests the creation of an existing public keypair from a file
+ :return:
+ """
+ keys = RSA.generate(1024)
+ nova_utils.save_keys_to_files(keys=keys, pub_file_path=self.pub_file_path)
+ self.keypair_creator = OpenStackKeypair(
+ self.os_creds, KeypairSettings(name=self.keypair_name, public_filepath=self.pub_file_path))
+ self.keypair_creator.create()
+
+ keypair = nova_utils.keypair_exists(self.nova, self.keypair_creator.get_keypair())
+ self.assertEquals(self.keypair_creator.get_keypair(), keypair)
+
+ file_key = open(os.path.expanduser(self.pub_file_path)).read()
+ self.assertEquals(self.keypair_creator.get_keypair().public_key, file_key)
diff --git a/snaps/openstack/tests/create_network_tests.py b/snaps/openstack/tests/create_network_tests.py
new file mode 100644
index 0000000..a2b17f8
--- /dev/null
+++ b/snaps/openstack/tests/create_network_tests.py
@@ -0,0 +1,533 @@
+# Copyright (c) 2016 Cable Television Laboratories, Inc. ("CableLabs")
+# and others. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+import uuid
+import unittest
+
+from snaps.openstack.create_network import OpenStackNetwork, NetworkSettings, SubnetSettings, PortSettings
+from snaps.openstack import create_router
+from snaps.openstack.tests import openstack_tests
+from snaps.openstack.tests.os_source_file_test import OSIntegrationTestCase, OSComponentTestCase
+from snaps.openstack.utils import neutron_utils
+from snaps.openstack.utils.tests import neutron_utils_tests
+
+__author__ = 'spisarski'
+
+
+class NetworkSettingsUnitTests(unittest.TestCase):
+ """
+ Tests the construction of the NetworkSettings class
+ """
+
+ def test_no_params(self):
+ with self.assertRaises(Exception):
+ NetworkSettings()
+
+ def test_empty_config(self):
+ with self.assertRaises(Exception):
+ NetworkSettings(config=dict())
+
+ def test_name_only(self):
+ settings = NetworkSettings(name='foo')
+ self.assertEquals('foo', settings.name)
+ self.assertTrue(settings.admin_state_up)
+ self.assertIsNone(settings.shared)
+ self.assertIsNone(settings.project_name)
+ self.assertFalse(settings.external)
+ self.assertIsNone(settings.network_type)
+ self.assertEquals(0, len(settings.subnet_settings))
+
+ def test_config_with_name_only(self):
+ settings = NetworkSettings(config={'name': 'foo'})
+ self.assertEquals('foo', settings.name)
+ self.assertTrue(settings.admin_state_up)
+ self.assertIsNone(settings.shared)
+ self.assertIsNone(settings.project_name)
+ self.assertFalse(settings.external)
+ self.assertIsNone(settings.network_type)
+ self.assertEquals(0, len(settings.subnet_settings))
+
+ def test_all(self):
+ sub_settings = SubnetSettings(name='foo-subnet', cidr='10.0.0.0/24')
+ settings = NetworkSettings(name='foo', admin_state_up=False, shared=True, project_name='bar', external=True,
+ network_type='flat', physical_network='phy', subnet_settings=[sub_settings])
+ self.assertEquals('foo', settings.name)
+ self.assertFalse(settings.admin_state_up)
+ self.assertTrue(settings.shared)
+ self.assertEquals('bar', settings.project_name)
+ self.assertTrue(settings.external)
+ self.assertEquals('flat', settings.network_type)
+ self.assertEquals('phy', settings.physical_network)
+ self.assertEquals(1, len(settings.subnet_settings))
+ self.assertEquals('foo-subnet', settings.subnet_settings[0].name)
+
+ def test_config_all(self):
+ settings = NetworkSettings(config={'name': 'foo', 'admin_state_up': False, 'shared': True,
+ 'project_name': 'bar', 'external': True, 'network_type': 'flat',
+ 'physical_network': 'phy',
+ 'subnets':
+ [{'subnet': {'name': 'foo-subnet', 'cidr': '10.0.0.0/24'}}]})
+ self.assertEquals('foo', settings.name)
+ self.assertFalse(settings.admin_state_up)
+ self.assertTrue(settings.shared)
+ self.assertEquals('bar', settings.project_name)
+ self.assertTrue(settings.external)
+ self.assertEquals('flat', settings.network_type)
+ self.assertEquals('phy', settings.physical_network)
+ self.assertEquals(1, len(settings.subnet_settings))
+ self.assertEquals('foo-subnet', settings.subnet_settings[0].name)
+
+
+class SubnetSettingsUnitTests(unittest.TestCase):
+ """
+ Tests the construction of the SubnetSettings class
+ """
+
+ def test_no_params(self):
+ with self.assertRaises(Exception):
+ SubnetSettings()
+
+ def test_empty_config(self):
+ with self.assertRaises(Exception):
+ SubnetSettings(config=dict())
+
+ def test_name_only(self):
+ with self.assertRaises(Exception):
+ SubnetSettings(name='foo')
+
+ def test_config_with_name_only(self):
+ with self.assertRaises(Exception):
+ SubnetSettings(config={'name': 'foo'})
+
+ def test_name_cidr_only(self):
+ settings = SubnetSettings(name='foo', cidr='10.0.0.0/24')
+ self.assertEquals('foo', settings.name)
+ self.assertEquals('10.0.0.0/24', settings.cidr)
+ self.assertEquals(4, settings.ip_version)
+ self.assertIsNone(settings.project_name)
+ self.assertIsNone(settings.start)
+ self.assertIsNone(settings.end)
+ self.assertIsNone(settings.enable_dhcp)
+ self.assertEquals(1, len(settings.dns_nameservers))
+ self.assertEquals('8.8.8.8', settings.dns_nameservers[0])
+ self.assertIsNone(settings.host_routes)
+ self.assertIsNone(settings.destination)
+ self.assertIsNone(settings.nexthop)
+ self.assertIsNone(settings.ipv6_ra_mode)
+ self.assertIsNone(settings.ipv6_address_mode)
+
+ def test_config_with_name_cidr_only(self):
+ settings = SubnetSettings(config={'name': 'foo', 'cidr': '10.0.0.0/24'})
+ self.assertEquals('foo', settings.name)
+ self.assertEquals('10.0.0.0/24', settings.cidr)
+ self.assertEquals(4, settings.ip_version)
+ self.assertIsNone(settings.project_name)
+ self.assertIsNone(settings.start)
+ self.assertIsNone(settings.end)
+ self.assertIsNone(settings.gateway_ip)
+ self.assertIsNone(settings.enable_dhcp)
+ self.assertEquals(1, len(settings.dns_nameservers))
+ self.assertEquals('8.8.8.8', settings.dns_nameservers[0])
+ self.assertIsNone(settings.host_routes)
+ self.assertIsNone(settings.destination)
+ self.assertIsNone(settings.nexthop)
+ self.assertIsNone(settings.ipv6_ra_mode)
+ self.assertIsNone(settings.ipv6_address_mode)
+
+ def test_all(self):
+ host_routes = {'destination': '0.0.0.0/0', 'nexthop': '123.456.78.9'}
+ settings = SubnetSettings(name='foo', cidr='10.0.0.0/24', ip_version=6, project_name='bar-project',
+ start='10.0.0.2', end='10.0.0.101', gateway_ip='10.0.0.1', enable_dhcp=False,
+ dns_nameservers=['8.8.8.8'], host_routes=[host_routes], destination='dest',
+ nexthop='hop', ipv6_ra_mode='dhcpv6-stateful', ipv6_address_mode='slaac')
+ self.assertEquals('foo', settings.name)
+ self.assertEquals('10.0.0.0/24', settings.cidr)
+ self.assertEquals(6, settings.ip_version)
+ self.assertEquals('bar-project', settings.project_name)
+ self.assertEquals('10.0.0.2', settings.start)
+ self.assertEquals('10.0.0.101', settings.end)
+ self.assertEquals('10.0.0.1', settings.gateway_ip)
+ self.assertEquals(False, settings.enable_dhcp)
+ self.assertEquals(1, len(settings.dns_nameservers))
+ self.assertEquals('8.8.8.8', settings.dns_nameservers[0])
+ self.assertEquals(1, len(settings.host_routes))
+ self.assertEquals(host_routes, settings.host_routes[0])
+ self.assertEquals('dest', settings.destination)
+ self.assertEquals('hop', settings.nexthop)
+ self.assertEquals('dhcpv6-stateful', settings.ipv6_ra_mode)
+ self.assertEquals('slaac', settings.ipv6_address_mode)
+
+ def test_config_all(self):
+ host_routes = {'destination': '0.0.0.0/0', 'nexthop': '123.456.78.9'}
+ settings = SubnetSettings(config={'name': 'foo', 'cidr': '10.0.0.0/24', 'ip_version': 6,
+ 'project_name': 'bar-project', 'start': '10.0.0.2', 'end': '10.0.0.101',
+ 'gateway_ip': '10.0.0.1', 'enable_dhcp': False,
+ 'dns_nameservers': ['8.8.8.8'], 'host_routes': [host_routes],
+ 'destination': 'dest', 'nexthop': 'hop', 'ipv6_ra_mode': 'dhcpv6-stateful',
+ 'ipv6_address_mode': 'slaac'})
+ self.assertEquals('foo', settings.name)
+ self.assertEquals('10.0.0.0/24', settings.cidr)
+ self.assertEquals(6, settings.ip_version)
+ self.assertEquals('bar-project', settings.project_name)
+ self.assertEquals('10.0.0.2', settings.start)
+ self.assertEquals('10.0.0.101', settings.end)
+ self.assertEquals('10.0.0.1', settings.gateway_ip)
+ self.assertEquals(False, settings.enable_dhcp)
+ self.assertEquals(1, len(settings.dns_nameservers))
+ self.assertEquals('8.8.8.8', settings.dns_nameservers[0])
+ self.assertEquals(1, len(settings.host_routes))
+ self.assertEquals(host_routes, settings.host_routes[0])
+ self.assertEquals('dest', settings.destination)
+ self.assertEquals('hop', settings.nexthop)
+ self.assertEquals('dhcpv6-stateful', settings.ipv6_ra_mode)
+ self.assertEquals('slaac', settings.ipv6_address_mode)
+
+
+class PortSettingsUnitTests(unittest.TestCase):
+ """
+ Tests the construction of the PortSettings class
+ """
+
+ def test_no_params(self):
+ with self.assertRaises(Exception):
+ PortSettings()
+
+ def test_empty_config(self):
+ with self.assertRaises(Exception):
+ PortSettings(config=dict())
+
+ def test_name_only(self):
+ with self.assertRaises(Exception):
+ PortSettings(name='foo')
+
+ def test_config_name_only(self):
+ with self.assertRaises(Exception):
+ PortSettings(config={'name': 'foo'})
+
+ def test_name_netname_only(self):
+ settings = PortSettings(name='foo', network_name='bar')
+ self.assertEquals('foo', settings.name)
+ self.assertEquals('bar', settings.network_name)
+ self.assertTrue(settings.admin_state_up)
+ self.assertIsNone(settings.project_name)
+ self.assertIsNone(settings.mac_address)
+ self.assertIsNone(settings.ip_addrs)
+ self.assertIsNone(settings.fixed_ips)
+ self.assertIsNone(settings.security_groups)
+ self.assertIsNone(settings.allowed_address_pairs)
+ self.assertIsNone(settings.opt_value)
+ self.assertIsNone(settings.opt_name)
+ self.assertIsNone(settings.device_owner)
+ self.assertIsNone(settings.device_id)
+
+ def test_config_with_name_netname_only(self):
+ settings = PortSettings(config={'name': 'foo', 'network_name': 'bar'})
+ self.assertEquals('foo', settings.name)
+ self.assertEquals('bar', settings.network_name)
+ self.assertTrue(settings.admin_state_up)
+ self.assertIsNone(settings.project_name)
+ self.assertIsNone(settings.mac_address)
+ self.assertIsNone(settings.ip_addrs)
+ self.assertIsNone(settings.fixed_ips)
+ self.assertIsNone(settings.security_groups)
+ self.assertIsNone(settings.allowed_address_pairs)
+ self.assertIsNone(settings.opt_value)
+ self.assertIsNone(settings.opt_name)
+ self.assertIsNone(settings.device_owner)
+ self.assertIsNone(settings.device_id)
+
+ def test_all(self):
+ ip_addrs = [{'subnet_name', 'foo-sub', 'ip', '10.0.0.10'}]
+ fixed_ips = {'sub_id', '10.0.0.10'}
+ allowed_address_pairs = {'10.0.0.101', '1234.5678'}
+
+ settings = PortSettings(name='foo', network_name='bar', admin_state_up=False, project_name='foo-project',
+ mac_address='1234', ip_addrs=ip_addrs, fixed_ips=fixed_ips,
+ security_groups=['foo_grp_id'], allowed_address_pairs=allowed_address_pairs,
+ opt_value='opt value', opt_name='opt name', device_owner='owner',
+ device_id='device number')
+ self.assertEquals('foo', settings.name)
+ self.assertEquals('bar', settings.network_name)
+ self.assertFalse(settings.admin_state_up)
+ self.assertEquals('foo-project', settings.project_name)
+ self.assertEquals('1234', settings.mac_address)
+ self.assertEquals(ip_addrs, settings.ip_addrs)
+ self.assertEquals(fixed_ips, settings.fixed_ips)
+ self.assertEquals(1, len(settings.security_groups))
+ self.assertEquals('foo_grp_id', settings.security_groups[0])
+ self.assertEquals(allowed_address_pairs, settings.allowed_address_pairs)
+ self.assertEquals('opt value', settings.opt_value)
+ self.assertEquals('opt name', settings.opt_name)
+ self.assertEquals('owner', settings.device_owner)
+ self.assertEquals('device number', settings.device_id)
+
+ def test_config_all(self):
+ ip_addrs = [{'subnet_name', 'foo-sub', 'ip', '10.0.0.10'}]
+ fixed_ips = {'sub_id', '10.0.0.10'}
+ allowed_address_pairs = {'10.0.0.101', '1234.5678'}
+
+ settings = PortSettings(config={'name': 'foo', 'network_name': 'bar', 'admin_state_up': False,
+ 'project_name': 'foo-project', 'mac_address': '1234', 'ip_addrs': ip_addrs,
+ 'fixed_ips': fixed_ips, 'security_groups': ['foo_grp_id'],
+ 'allowed_address_pairs': allowed_address_pairs, 'opt_value': 'opt value',
+ 'opt_name': 'opt name', 'device_owner': 'owner', 'device_id': 'device number'})
+ self.assertEquals('foo', settings.name)
+ self.assertEquals('bar', settings.network_name)
+ self.assertFalse(settings.admin_state_up)
+ self.assertEquals('foo-project', settings.project_name)
+ self.assertEquals('1234', settings.mac_address)
+ self.assertEquals(ip_addrs, settings.ip_addrs)
+ self.assertEquals(fixed_ips, settings.fixed_ips)
+ self.assertEquals(1, len(settings.security_groups))
+ self.assertEquals('foo_grp_id', settings.security_groups[0])
+ self.assertEquals(allowed_address_pairs, settings.allowed_address_pairs)
+ self.assertEquals('opt value', settings.opt_value)
+ self.assertEquals('opt name', settings.opt_name)
+ self.assertEquals('owner', settings.device_owner)
+ self.assertEquals('device number', settings.device_id)
+
+
+class CreateNetworkSuccessTests(OSIntegrationTestCase):
+ """
+ Test for the CreateNework class defined in create_nework.py
+ """
+
+ def setUp(self):
+ """
+ Sets up object for test
+ """
+ super(self.__class__, self).__start__()
+
+ guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
+ self.net_config = openstack_tests.get_pub_net_config(
+ net_name=guid + '-pub-net', subnet_name=guid + '-pub-subnet',
+ router_name=guid + '-pub-router', external_net=self.ext_net_name)
+
+ self.neutron = neutron_utils.neutron_client(self.os_creds)
+
+ # Initialize for cleanup
+ self.net_creator = None
+ self.router_creator = None
+ self.neutron = neutron_utils.neutron_client(self.os_creds)
+
+ def tearDown(self):
+ """
+ Cleans the network
+ """
+ if self.router_creator:
+ self.router_creator.clean()
+
+ if self.net_creator:
+ if len(self.net_creator.get_subnets()) > 0:
+ # Validate subnet has been deleted
+ neutron_utils_tests.validate_subnet(
+ self.neutron, self.net_creator.network_settings.subnet_settings[0].name,
+ self.net_creator.network_settings.subnet_settings[0].cidr, False)
+
+ if self.net_creator.get_network():
+ # Validate network has been deleted
+ neutron_utils_tests.validate_network(self.neutron, self.net_creator.network_settings.name,
+ False)
+ self.net_creator.clean()
+
+ super(self.__class__, self).__clean__()
+
+ def test_create_network_without_router(self):
+ """
+ Tests the creation of an OpenStack network without a router.
+ """
+ # Create Nework
+ self.net_creator = OpenStackNetwork(self.os_creds, self.net_config.network_settings)
+ self.net_creator.create()
+
+ # Validate network was created
+ neutron_utils_tests.validate_network(self.neutron, self.net_creator.network_settings.name, True)
+
+ # Validate subnets
+ neutron_utils_tests.validate_subnet(
+ self.neutron, self.net_creator.network_settings.subnet_settings[0].name,
+ self.net_creator.network_settings.subnet_settings[0].cidr, True)
+
+ def test_create_delete_network(self):
+ """
+ Tests the creation of an OpenStack network, it's deletion, then cleanup.
+ """
+ # Create Nework
+ self.net_creator = OpenStackNetwork(self.os_creds, self.net_config.network_settings)
+ self.net_creator.create()
+
+ # Validate network was created
+ neutron_utils_tests.validate_network(self.neutron, self.net_creator.network_settings.name, True)
+
+ neutron_utils.delete_network(self.neutron, self.net_creator.get_network())
+ self.assertIsNone(neutron_utils.get_network(self.neutron, self.net_creator.network_settings.name))
+
+ # This shall not throw an exception here
+ self.net_creator.clean()
+
+ def test_create_network_with_router(self):
+ """
+ Tests the creation of an OpenStack network with a router.
+ """
+ # Create Network
+ self.net_creator = OpenStackNetwork(self.os_creds, self.net_config.network_settings)
+ self.net_creator.create()
+
+ # Create Router
+ self.router_creator = create_router.OpenStackRouter(self.os_creds, self.net_config.router_settings)
+ self.router_creator.create()
+
+ # Validate network was created
+ neutron_utils_tests.validate_network(self.neutron, self.net_creator.network_settings.name, True)
+
+ # Validate subnets
+ neutron_utils_tests.validate_subnet(
+ self.neutron, self.net_creator.network_settings.subnet_settings[0].name,
+ self.net_creator.network_settings.subnet_settings[0].cidr, True)
+
+ # Validate routers
+ neutron_utils_tests.validate_router(self.neutron, self.router_creator.router_settings.name, True)
+
+ neutron_utils_tests.validate_interface_router(self.router_creator.get_internal_router_interface(),
+ self.router_creator.get_router(),
+ self.net_creator.get_subnets()[0])
+
+ def test_create_networks_same_name(self):
+ """
+ Tests the creation of an OpenStack network and ensures that the OpenStackNetwork object will not create
+ a second.
+ """
+ # Create Nework
+ self.net_creator = OpenStackNetwork(self.os_creds, self.net_config.network_settings)
+ self.net_creator.create()
+
+ self.net_creator2 = OpenStackNetwork(self.os_creds, self.net_config.network_settings)
+ self.net_creator2.create()
+
+ self.assertEquals(self.net_creator.get_network()['network']['id'],
+ self.net_creator2.get_network()['network']['id'])
+
+
+class CreateNetworkTypeTests(OSComponentTestCase):
+ """
+ Test for the CreateNework class defined in create_nework.py for testing creating networks of different types
+ """
+
+ def setUp(self):
+ """
+ Sets up object for test
+ """
+ guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
+ self.net_config = openstack_tests.get_pub_net_config(
+ net_name=guid + '-pub-net', subnet_name=guid + '-pub-subnet')
+
+ self.neutron = neutron_utils.neutron_client(self.os_creds)
+
+ # Initialize for cleanup
+ self.net_creator = None
+ self.neutron = neutron_utils.neutron_client(self.os_creds)
+
+ def tearDown(self):
+ """
+ Cleans the network
+ """
+ if self.net_creator:
+ if len(self.net_creator.get_subnets()) > 0:
+ # Validate subnet has been deleted
+ neutron_utils_tests.validate_subnet(
+ self.neutron, self.net_creator.network_settings.subnet_settings[0].name,
+ self.net_creator.network_settings.subnet_settings[0].cidr, False)
+
+ if self.net_creator.get_network():
+ # Validate network has been deleted
+ neutron_utils_tests.validate_network(self.neutron, self.net_creator.network_settings.name,
+ False)
+ self.net_creator.clean()
+ # TODO - determine why this is not working on Newton
+ # - Unable to create the network. No tenant network is available for allocation.
+ # def test_create_network_type_vlan(self):
+ # """
+ # Tests the creation of an OpenStack network of type vlan.
+ # """
+ # # Create Network
+ # network_type = 'vlan'
+ # net_settings = NetworkSettings(name=self.net_config.network_settings.name,
+ # subnet_settings=self.net_config.network_settings.subnet_settings,
+ # network_type=network_type)
+ #
+ # # When setting the network_type, creds must be admin
+ # self.net_creator = OpenStackNetwork(self.os_creds, net_settings)
+ # network = self.net_creator.create()
+ #
+ # # Validate network was created
+ # neutron_utils_tests.validate_network(self.neutron, net_settings.name, True)
+ #
+ # self.assertEquals(network_type, network['network']['provider:network_type'])
+
+ def test_create_network_type_vxlan(self):
+ """
+ Tests the creation of an OpenStack network of type vxlan.
+ """
+ # Create Network
+ network_type = 'vxlan'
+ net_settings = NetworkSettings(name=self.net_config.network_settings.name,
+ subnet_settings=self.net_config.network_settings.subnet_settings,
+ network_type=network_type)
+
+ # When setting the network_type, creds must be admin
+ self.net_creator = OpenStackNetwork(self.os_creds, net_settings)
+ network = self.net_creator.create()
+
+ # Validate network was created
+ neutron_utils_tests.validate_network(self.neutron, net_settings.name, True)
+
+ self.assertEquals(network_type, network['network']['provider:network_type'])
+
+ # TODO - determine what value we need to place into physical_network
+ # - Do not know what vaule to place into the 'physical_network' setting.
+ # def test_create_network_type_flat(self):
+ # """
+ # Tests the creation of an OpenStack network of type flat.
+ # """
+ # # Create Network
+ # network_type = 'flat'
+ #
+ # # Unable to find documentation on how to find a value that will work here.
+ # # https://visibilityspots.org/vlan-flat-neutron-provider.html
+ # # https://community.rackspace.com/products/f/45/t/4225
+ # # It appears that this may be due to how OPNFV is configuring OpenStack.
+ # physical_network = '???'
+ # net_settings = NetworkSettings(name=self.net_config.network_settings.name,
+ # subnet_settings=self.net_config.network_settings.subnet_settings,
+ # network_type=network_type, physical_network=physical_network)
+ # self.net_creator = OpenStackNetwork(self.os_creds, net_settings)
+ # network = self.net_creator.create()
+ #
+ # # Validate network was created
+ # neutron_utils_tests.validate_network(self.neutron, net_settings.name, True)
+ #
+ # self.assertEquals(network_type, network['network']['provider:network_type'])
+
+ def test_create_network_type_foo(self):
+ """
+ Tests the creation of an OpenStack network of type foo which should raise an exception.
+ """
+ # Create Network
+ network_type = 'foo'
+ net_settings = NetworkSettings(name=self.net_config.network_settings.name,
+ subnet_settings=self.net_config.network_settings.subnet_settings,
+ network_type=network_type)
+ self.net_creator = OpenStackNetwork(self.os_creds, net_settings)
+ with self.assertRaises(Exception):
+ self.net_creator.create()
diff --git a/snaps/openstack/tests/create_project_tests.py b/snaps/openstack/tests/create_project_tests.py
new file mode 100644
index 0000000..9d53467
--- /dev/null
+++ b/snaps/openstack/tests/create_project_tests.py
@@ -0,0 +1,228 @@
+# Copyright (c) 2016 Cable Television Laboratories, Inc. ("CableLabs")
+# and others. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+import uuid
+import unittest
+
+from snaps.openstack.create_project import OpenStackProject, ProjectSettings
+from snaps.openstack.create_security_group import OpenStackSecurityGroup
+from snaps.openstack.create_security_group import SecurityGroupSettings
+from snaps.openstack.create_user import OpenStackUser
+from snaps.openstack.create_user import UserSettings
+from snaps.openstack.tests.os_source_file_test import OSComponentTestCase
+from snaps.openstack.utils import keystone_utils
+
+__author__ = 'spisarski'
+
+
+class ProjectSettingsUnitTests(unittest.TestCase):
+ """
+ Tests the construction of the ProjectSettings class
+ """
+
+ def test_no_params(self):
+ with self.assertRaises(Exception):
+ ProjectSettings()
+
+ def test_empty_config(self):
+ with self.assertRaises(Exception):
+ ProjectSettings(config=dict())
+
+ def test_name_only(self):
+ settings = ProjectSettings(name='foo')
+ self.assertEquals('foo', settings.name)
+ self.assertEquals('default', settings.domain)
+ self.assertIsNone(settings.description)
+ self.assertTrue(settings.enabled)
+
+ def test_config_with_name_only(self):
+ settings = ProjectSettings(config={'name': 'foo'})
+ self.assertEquals('foo', settings.name)
+ self.assertEquals('default', settings.domain)
+ self.assertIsNone(settings.description)
+ self.assertTrue(settings.enabled)
+
+ def test_all(self):
+ settings = ProjectSettings(name='foo', domain='bar', description='foobar', enabled=False)
+ self.assertEquals('foo', settings.name)
+ self.assertEquals('bar', settings.domain)
+ self.assertEquals('foobar', settings.description)
+ self.assertFalse(settings.enabled)
+
+ def test_config_all(self):
+ settings = ProjectSettings(config={'name': 'foo', 'domain': 'bar', 'description': 'foobar', 'enabled': False})
+ self.assertEquals('foo', settings.name)
+ self.assertEquals('bar', settings.domain)
+ self.assertEquals('foobar', settings.description)
+ self.assertFalse(settings.enabled)
+
+
+class CreateProjectSuccessTests(OSComponentTestCase):
+ """
+ Test for the CreateImage class defined in create_image.py
+ """
+
+ def setUp(self):
+ """
+ Instantiates the CreateImage object that is responsible for downloading and creating an OS image file
+ within OpenStack
+ """
+ guid = str(uuid.uuid4())[:-19]
+ guid = self.__class__.__name__ + '-' + guid
+ self.project_settings = ProjectSettings(name=guid + '-name')
+
+ self.keystone = keystone_utils.keystone_client(self.os_creds)
+
+ # Initialize for cleanup
+ self.project_creator = None
+
+ def tearDown(self):
+ """
+ Cleans the image and downloaded image file
+ """
+ if self.project_creator:
+ self.project_creator.clean()
+
+ def test_create_project(self):
+ """
+ Tests the creation of an OpenStack project.
+ """
+ self.project_creator = OpenStackProject(self.os_creds, self.project_settings)
+ created_project = self.project_creator.create()
+ self.assertIsNotNone(created_project)
+
+ retrieved_project = keystone_utils.get_project(keystone=self.keystone, project_name=self.project_settings.name)
+ self.assertIsNotNone(retrieved_project)
+ self.assertEquals(created_project, retrieved_project)
+
+ def test_create_project_2x(self):
+ """
+ Tests the creation of an OpenStack project twice to ensure it only creates one.
+ """
+ self.project_creator = OpenStackProject(self.os_creds, self.project_settings)
+ created_project = self.project_creator.create()
+ self.assertIsNotNone(created_project)
+
+ retrieved_project = keystone_utils.get_project(keystone=self.keystone, project_name=self.project_settings.name)
+ self.assertIsNotNone(retrieved_project)
+ self.assertEquals(created_project, retrieved_project)
+
+ project2 = OpenStackProject(self.os_creds, self.project_settings).create()
+ self.assertEquals(retrieved_project, project2)
+
+ def test_create_delete_project(self):
+ """
+ Tests the creation of an OpenStack project, it's deletion, then cleanup.
+ """
+ # Create Image
+ self.project_creator = OpenStackProject(self.os_creds, self.project_settings)
+ created_project = self.project_creator.create()
+ self.assertIsNotNone(created_project)
+
+ keystone_utils.delete_project(self.keystone, created_project)
+
+ self.project_creator.clean()
+
+ self.assertIsNone(self.project_creator.get_project())
+
+ # TODO - Expand tests
+
+
+class CreateProjectUserTests(OSComponentTestCase):
+ """
+ Test for the CreateImage class defined in create_image.py
+ """
+
+ def setUp(self):
+ """
+ Instantiates the CreateImage object that is responsible for downloading and creating an OS image file
+ within OpenStack
+ """
+ guid = str(uuid.uuid4())[:-19]
+ self.guid = self.__class__.__name__ + '-' + guid
+ self.project_settings = ProjectSettings(name=self.guid + '-name')
+
+ self.keystone = keystone_utils.keystone_client(self.os_creds)
+
+ # Initialize for cleanup
+ self.project_creator = None
+ self.user_creators = list()
+
+ self.sec_grp_creators = list()
+
+ def tearDown(self):
+ """
+ Cleans the image and downloaded image file
+ """
+ for sec_grp_creator in self.sec_grp_creators:
+ sec_grp_creator.clean()
+
+ for user_creator in self.user_creators:
+ user_creator.clean()
+
+ if self.project_creator:
+ self.project_creator.clean()
+
+ def test_create_project_sec_grp_one_user(self):
+ """
+ Tests the creation of an OpenStack object to a project with a new users and to create a security group
+ """
+ self.project_creator = OpenStackProject(self.os_creds, self.project_settings)
+ created_project = self.project_creator.create()
+ self.assertIsNotNone(created_project)
+
+ user_creator = OpenStackUser(self.os_creds, UserSettings(name=self.guid + '-user', password=self.guid))
+ self.project_creator.assoc_user(user_creator.create())
+ self.user_creators.append(user_creator)
+
+ sec_grp_os_creds = user_creator.get_os_creds(self.project_creator.get_project().name)
+ sec_grp_creator = OpenStackSecurityGroup(
+ sec_grp_os_creds, SecurityGroupSettings(name=self.guid + '-name', description='hello group'))
+ sec_grp = sec_grp_creator.create()
+ self.assertIsNotNone(sec_grp)
+ self.sec_grp_creators.append(sec_grp_creator)
+
+ if self.keystone.version == keystone_utils.V2_VERSION:
+ self.assertEquals(self.project_creator.get_project().id, sec_grp['security_group']['tenant_id'])
+ else:
+ self.assertEquals(self.project_creator.get_project().id, sec_grp['security_group']['project_id'])
+
+ def test_create_project_sec_grp_two_users(self):
+ """
+ Tests the creation of an OpenStack object to a project with two new users and use each user to create a
+ security group
+ """
+ self.project_creator = OpenStackProject(self.os_creds, self.project_settings)
+ created_project = self.project_creator.create()
+ self.assertIsNotNone(created_project)
+
+ user_creator_1 = OpenStackUser(self.os_creds, UserSettings(name=self.guid + '-user1', password=self.guid))
+ self.project_creator.assoc_user(user_creator_1.create())
+ self.user_creators.append(user_creator_1)
+
+ user_creator_2 = OpenStackUser(self.os_creds, UserSettings(name=self.guid + '-user2', password=self.guid))
+ self.project_creator.assoc_user(user_creator_2.create())
+ self.user_creators.append(user_creator_2)
+
+ ctr = 0
+ for user_creator in self.user_creators:
+ ctr += 1
+ sec_grp_os_creds = user_creator.get_os_creds(self.project_creator.get_project().name)
+
+ sec_grp_creator = OpenStackSecurityGroup(
+ sec_grp_os_creds, SecurityGroupSettings(name=self.guid + '-name', description='hello group'))
+ sec_grp = sec_grp_creator.create()
+ self.assertIsNotNone(sec_grp)
+ self.sec_grp_creators.append(sec_grp_creator)
+ self.assertEquals(self.project_creator.get_project().id, sec_grp['security_group']['tenant_id'])
diff --git a/snaps/openstack/tests/create_router_tests.py b/snaps/openstack/tests/create_router_tests.py
new file mode 100644
index 0000000..3e22714
--- /dev/null
+++ b/snaps/openstack/tests/create_router_tests.py
@@ -0,0 +1,264 @@
+# Copyright (c) 2016 Cable Television Laboratories, Inc. ("CableLabs")
+# and others. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import uuid
+
+from snaps.openstack import create_network
+from snaps.openstack import create_router
+from snaps.openstack.create_network import NetworkSettings
+from snaps.openstack.create_network import OpenStackNetwork
+from snaps.openstack.tests.os_source_file_test import OSIntegrationTestCase
+from snaps.openstack.create_router import RouterSettings
+from snaps.openstack.utils import neutron_utils
+
+__author__ = 'mmakati'
+
+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'
+
+
+class CreateRouterSuccessTests(OSIntegrationTestCase):
+ """
+ Class for testing routers with various positive scenarios expected to succeed
+ """
+
+ def setUp(self):
+ """
+ Initializes objects used for router testing
+ """
+ super(self.__class__, self).__start__()
+
+ self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
+ self.router_creator = None
+ self.network_creator1 = None
+ self.network_creator2 = None
+ self.neutron = neutron_utils.neutron_client(self.os_creds)
+
+ def tearDown(self):
+ """
+ Cleans the remote OpenStack objects used for router testing
+ """
+ if self.router_creator:
+ self.router_creator.clean()
+
+ if self.network_creator1:
+ self.network_creator1.clean()
+
+ if self.network_creator2:
+ self.network_creator2.clean()
+
+ super(self.__class__, self).__clean__()
+
+ def test_create_router_vanilla(self):
+ """
+ Test creation of a most basic router with minimal options.
+ """
+ router_settings = RouterSettings(name=self.guid + '-pub-router', external_gateway=self.ext_net_name)
+
+ self.router_creator = create_router.OpenStackRouter(self.os_creds, router_settings)
+ self.router_creator.create()
+
+ router = neutron_utils.get_router_by_name(self.neutron, router_settings.name)
+ self.assertIsNotNone(router)
+
+ self.assertTrue(verify_router_attributes(router, self.router_creator, ext_gateway=self.ext_net_name))
+
+ def test_create_delete_router(self):
+ """
+ Test that clean() will not raise an exception if the router is deleted by another process.
+ """
+ self.router_settings = RouterSettings(name=self.guid + '-pub-router', external_gateway=self.ext_net_name)
+
+ self.router_creator = create_router.OpenStackRouter(self.os_creds, self.router_settings)
+ created_router = self.router_creator.create()
+ self.assertIsNotNone(created_router)
+ retrieved_router = neutron_utils.get_router_by_name(self.neutron, self.router_settings.name)
+ self.assertIsNotNone(retrieved_router)
+
+ neutron_utils.delete_router(self.neutron, created_router)
+
+ retrieved_router = neutron_utils.get_router_by_name(self.neutron, self.router_settings.name)
+ self.assertIsNone(retrieved_router)
+
+ # Should not raise an exception
+ self.router_creator.clean()
+
+ def test_create_router_admin_state_false(self):
+ """
+ Test creation of a basic router with admin state down.
+ """
+ router_settings = RouterSettings(name=self.guid + '-pub-router', admin_state_up=False)
+
+ self.router_creator = create_router.OpenStackRouter(self.os_creds, router_settings)
+ self.router_creator.create()
+
+ router = neutron_utils.get_router_by_name(self.neutron, router_settings.name)
+ self.assertIsNotNone(router)
+
+ self.assertTrue(verify_router_attributes(router, self.router_creator, admin_state=False))
+
+ def test_create_router_admin_state_True(self):
+ """
+ Test creation of a basic router with admin state Up.
+ """
+ router_settings = RouterSettings(name=self.guid + '-pub-router', admin_state_up=True)
+
+ self.router_creator = create_router.OpenStackRouter(self.os_creds, router_settings)
+ self.router_creator.create()
+
+ router = neutron_utils.get_router_by_name(self.neutron, router_settings.name)
+ self.assertIsNotNone(router)
+
+ self.assertTrue(verify_router_attributes(router, self.router_creator, admin_state=True))
+
+ def test_create_router_private_network(self):
+ """
+ Test creation of a router connected with two private networks and no external gateway
+ """
+ network_settings1 = NetworkSettings(name=self.guid + '-pub-net1',
+ subnet_settings=[
+ create_network.SubnetSettings(cidr=cidr1,
+ name=self.guid + '-pub-subnet1',
+ gateway_ip=static_gateway_ip1)])
+ network_settings2 = NetworkSettings(name=self.guid + '-pub-net2',
+ subnet_settings=[
+ create_network.SubnetSettings(cidr=cidr2,
+ name=self.guid + '-pub-subnet2',
+ gateway_ip=static_gateway_ip2)])
+
+ self.network_creator1 = OpenStackNetwork(self.os_creds, network_settings1)
+ self.network_creator2 = OpenStackNetwork(self.os_creds, network_settings2)
+
+ self.network_creator1.create()
+ self.network_creator2.create()
+
+ port_settings = [create_network.PortSettings(name=self.guid + '-port1', ip_addrs=[
+ {'subnet_name': network_settings1.subnet_settings[0].name, 'ip': static_gateway_ip1}],
+ network_name=network_settings1.name)
+ , create_network.PortSettings(name=self.guid + '-port2', ip_addrs=[
+ {'subnet_name': network_settings2.subnet_settings[0].name, 'ip': static_gateway_ip2}],
+ network_name=network_settings2.name)]
+
+ router_settings = RouterSettings(name=self.guid + '-pub-router', port_settings=port_settings)
+ self.router_creator = create_router.OpenStackRouter(self.os_creds, router_settings)
+ self.router_creator.create()
+
+ router = neutron_utils.get_router_by_name(self.neutron, router_settings.name)
+
+ self.assertTrue(verify_router_attributes(router, self.router_creator))
+
+ def test_create_router_external_network(self):
+ """
+ Test creation of a router connected to an external network and a private network.
+ """
+ network_settings = NetworkSettings(name=self.guid + '-pub-net1',
+ subnet_settings=[
+ create_network.SubnetSettings(cidr=cidr1,
+ name=self.guid + '-pub-subnet1',
+ gateway_ip=static_gateway_ip1)])
+ self.network_creator1 = OpenStackNetwork(self.os_creds, network_settings)
+ self.network_creator1.create()
+
+ port_settings = [create_network.PortSettings(name=self.guid + '-port1', ip_addrs=[
+ {'subnet_name': network_settings.subnet_settings[0].name, 'ip': static_gateway_ip1}],
+ network_name=network_settings.name)]
+
+ router_settings = RouterSettings(name=self.guid + '-pub-router',
+ external_gateway=self.ext_net_name, port_settings=port_settings)
+ self.router_creator = create_router.OpenStackRouter(self.os_creds, router_settings)
+ self.router_creator.create()
+
+ router = neutron_utils.get_router_by_name(self.neutron, router_settings.name)
+
+ self.assertTrue(verify_router_attributes(router, self.router_creator, ext_gateway=self.ext_net_name))
+
+
+class CreateRouterNegativeTests(OSIntegrationTestCase):
+ """
+ Class for testing routers with various negative scenarios expected to fail.
+ """
+
+ def setUp(self):
+ """
+ Initializes objects used for router testing
+ """
+ super(self.__class__, self).__start__()
+
+ self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
+ self.router_creator = None
+
+ def tearDown(self):
+ """
+ Cleans the remote OpenStack objects used for router testing
+ """
+ if self.router_creator:
+ self.router_creator.clean()
+
+ super(self.__class__, self).__clean__()
+
+ def test_create_router_noname(self):
+ """
+ Test creating a router without a name.
+ """
+ with self.assertRaises(Exception):
+ router_settings = RouterSettings(name=None, external_gateway=self.ext_net_name)
+ self.router_creator = create_router.OpenStackRouter(self.os_creds, router_settings)
+ self.router_creator.create()
+
+ def test_create_router_invalid_gateway_name(self):
+ """
+ Test creating a router without a valid network gateway name.
+ """
+ with self.assertRaises(Exception):
+ router_settings = RouterSettings(name=self.guid + '-pub-router', external_gateway="Invalid_name")
+ self.router_creator = create_router.OpenStackRouter(self.os_creds, router_settings)
+ self.router_creator.create()
+
+
+def verify_router_attributes(router_operational, router_creator, admin_state=True, ext_gateway=None):
+ """
+ Helper function to validate the attributes of router created with the one operational
+ :param router_operational: Operational Router object returned from neutron utils
+ :param router_creator: router_creator object returned from creating a router in the router test functions
+ :param admin_state: True if router is expected to be Up, else False
+ :param snat: True is enable_snat is True, else False
+ :param ext_gateway: None if router is not connected to external gateway
+ :return:
+ """
+
+ router = router_creator.get_router()
+
+ if not router_operational:
+ return False
+ elif not router_creator:
+ return False
+ elif not (router_operational['router']['name'] == router_creator.router_settings.name):
+ return False
+ elif not (router_operational['router']['id'] == router['router']['id']):
+ return False
+ elif not (router_operational['router']['status'] == router['router']['status']):
+ return False
+ elif not (router_operational['router']['tenant_id'] == router['router']['tenant_id']):
+ return False
+ elif not (admin_state == router_operational['router']['admin_state_up']):
+ return False
+ elif (ext_gateway is None) and (router_operational['router']['external_gateway_info'] is not None):
+ return False
+ elif ext_gateway is not None:
+ if router_operational['router']['external_gateway_info'] is None:
+ return False
+ return True
diff --git a/snaps/openstack/tests/create_security_group_tests.py b/snaps/openstack/tests/create_security_group_tests.py
new file mode 100644
index 0000000..079be0c
--- /dev/null
+++ b/snaps/openstack/tests/create_security_group_tests.py
@@ -0,0 +1,355 @@
+# Copyright (c) 2016 Cable Television Laboratories, Inc. ("CableLabs")
+# and others. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+import uuid
+import unittest
+
+from snaps.openstack import create_security_group
+from snaps.openstack.create_security_group import SecurityGroupSettings, SecurityGroupRuleSettings, Direction, \
+ Ethertype, Protocol
+from snaps.openstack.tests import validation_utils
+from snaps.openstack.tests.os_source_file_test import OSIntegrationTestCase
+from snaps.openstack.utils import neutron_utils
+
+__author__ = 'spisarski'
+
+
+class SecurityGroupRuleSettingsUnitTests(unittest.TestCase):
+ """
+ Tests the construction of the SecurityGroupRuleSettings class
+ """
+
+ def test_no_params(self):
+ with self.assertRaises(Exception):
+ SecurityGroupRuleSettings()
+
+ def test_empty_config(self):
+ with self.assertRaises(Exception):
+ SecurityGroupRuleSettings(config=dict())
+
+ def test_name_only(self):
+ with self.assertRaises(Exception):
+ SecurityGroupRuleSettings(sec_grp_name='foo')
+
+ def test_config_with_name_only(self):
+ with self.assertRaises(Exception):
+ SecurityGroupRuleSettings(config={'sec_grp_name': 'foo'})
+
+ def test_name_and_direction(self):
+ settings = SecurityGroupRuleSettings(sec_grp_name='foo', direction=Direction.ingress)
+ self.assertEquals('foo', settings.sec_grp_name)
+ self.assertEquals(Direction.ingress, settings.direction)
+
+ def test_config_name_and_direction(self):
+ settings = SecurityGroupRuleSettings(config={'sec_grp_name': 'foo', 'direction': 'ingress'})
+ self.assertEquals('foo', settings.sec_grp_name)
+ self.assertEquals(Direction.ingress, settings.direction)
+
+ def test_all(self):
+ settings = SecurityGroupRuleSettings(
+ sec_grp_name='foo', description='fubar', direction=Direction.egress, remote_group_id='rgi',
+ protocol=Protocol.icmp, ethertype=Ethertype.IPv6, port_range_min=1, port_range_max=2,
+ remote_ip_prefix='prfx')
+ self.assertEquals('foo', settings.sec_grp_name)
+ self.assertEquals('fubar', settings.description)
+ self.assertEquals(Direction.egress, settings.direction)
+ self.assertEquals('rgi', settings.remote_group_id)
+ self.assertEquals(Protocol.icmp, settings.protocol)
+ self.assertEquals(Ethertype.IPv6, settings.ethertype)
+ self.assertEquals(1, settings.port_range_min)
+ self.assertEquals(2, settings.port_range_max)
+ self.assertEquals('prfx', settings.remote_ip_prefix)
+
+ def test_config_all(self):
+ settings = SecurityGroupRuleSettings(
+ config={'sec_grp_name': 'foo',
+ 'description': 'fubar',
+ 'direction': 'egress',
+ 'remote_group_id': 'rgi',
+ 'protocol': 'tcp',
+ 'ethertype': 'IPv6',
+ 'port_range_min': 1,
+ 'port_range_max': 2,
+ 'remote_ip_prefix': 'prfx'})
+ self.assertEquals('foo', settings.sec_grp_name)
+ self.assertEquals('fubar', settings.description)
+ self.assertEquals(Direction.egress, settings.direction)
+ self.assertEquals('rgi', settings.remote_group_id)
+ self.assertEquals(Protocol.tcp, settings.protocol)
+ self.assertEquals(Ethertype.IPv6, settings.ethertype)
+ self.assertEquals(1, settings.port_range_min)
+ self.assertEquals(2, settings.port_range_max)
+ self.assertEquals('prfx', settings.remote_ip_prefix)
+
+
+class SecurityGroupSettingsUnitTests(unittest.TestCase):
+ """
+ Tests the construction of the SecurityGroupSettings class
+ """
+
+ def test_no_params(self):
+ with self.assertRaises(Exception):
+ SecurityGroupSettings()
+
+ def test_empty_config(self):
+ with self.assertRaises(Exception):
+ SecurityGroupSettings(config=dict())
+
+ def test_name_only(self):
+ settings = SecurityGroupSettings(name='foo')
+ self.assertEquals('foo', settings.name)
+
+ def test_config_with_name_only(self):
+ settings = SecurityGroupSettings(config={'name': 'foo'})
+ self.assertEquals('foo', settings.name)
+
+ def test_invalid_rule(self):
+ rule_setting = SecurityGroupRuleSettings(sec_grp_name='bar', direction=Direction.ingress)
+ with self.assertRaises(Exception):
+ SecurityGroupSettings(name='foo', rule_settings=[rule_setting])
+
+ def test_all(self):
+ rule_settings = list()
+ rule_settings.append(SecurityGroupRuleSettings(sec_grp_name='bar', direction=Direction.egress))
+ rule_settings.append(SecurityGroupRuleSettings(sec_grp_name='bar', direction=Direction.ingress))
+ settings = SecurityGroupSettings(
+ name='bar', description='fubar', project_name='foo', rule_settings=rule_settings)
+
+ self.assertEquals('bar', settings.name)
+ self.assertEquals('fubar', settings.description)
+ self.assertEquals('foo', settings.project_name)
+ self.assertEquals(rule_settings[0], settings.rule_settings[0])
+ self.assertEquals(rule_settings[1], settings.rule_settings[1])
+
+ def test_config_all(self):
+ settings = SecurityGroupSettings(
+ config={'name': 'bar',
+ 'description': 'fubar',
+ 'project_name': 'foo',
+ 'rules': [{'sec_grp_name': 'bar', 'direction': 'ingress'}]})
+
+ self.assertEquals('bar', settings.name)
+ self.assertEquals('fubar', settings.description)
+ self.assertEquals('foo', settings.project_name)
+ self.assertEquals(1, len(settings.rule_settings))
+ self.assertEquals('bar', settings.rule_settings[0].sec_grp_name)
+ self.assertEquals(Direction.ingress, settings.rule_settings[0].direction)
+
+
+class CreateSecurityGroupTests(OSIntegrationTestCase):
+ """
+ Test for the CreateSecurityGroup class defined in create_security_group.py
+ """
+
+ def setUp(self):
+ """
+ Instantiates the CreateSecurityGroup 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.sec_grp_name = guid + 'name'
+ self.neutron = neutron_utils.neutron_client(self.os_creds)
+
+ # Initialize for cleanup
+ self.sec_grp_creator = None
+
+ def tearDown(self):
+ """
+ Cleans the image and downloaded image file
+ """
+ if self.sec_grp_creator:
+ self.sec_grp_creator.clean()
+
+ super(self.__class__, self).__clean__()
+
+ def test_create_group_without_rules(self):
+ """
+ Tests the creation of an OpenStack Security Group without custom rules.
+ """
+ # Create Image
+ sec_grp_settings = SecurityGroupSettings(name=self.sec_grp_name, description='hello group')
+ self.sec_grp_creator = create_security_group.OpenStackSecurityGroup(self.os_creds, sec_grp_settings)
+ self.sec_grp_creator.create()
+
+ sec_grp = neutron_utils.get_security_group(self.neutron, self.sec_grp_name)
+ self.assertIsNotNone(sec_grp)
+
+ validation_utils.objects_equivalent(self.sec_grp_creator.get_security_group(), sec_grp)
+ rules = neutron_utils.get_rules_by_security_group(self.neutron, self.sec_grp_creator.get_security_group())
+ self.assertEquals(len(self.sec_grp_creator.get_rules()), len(rules))
+ validation_utils.objects_equivalent(self.sec_grp_creator.get_rules(), rules)
+
+ def test_create_delete_group(self):
+ """
+ Tests the creation of an OpenStack Security Group without custom rules.
+ """
+ # Create Image
+ sec_grp_settings = SecurityGroupSettings(name=self.sec_grp_name, description='hello group')
+ self.sec_grp_creator = create_security_group.OpenStackSecurityGroup(self.os_creds, sec_grp_settings)
+ created_sec_grp = self.sec_grp_creator.create()
+ self.assertIsNotNone(created_sec_grp)
+
+ neutron_utils.delete_security_group(self.neutron, created_sec_grp)
+ self.assertIsNone(neutron_utils.get_security_group(self.neutron, self.sec_grp_creator.sec_grp_settings.name))
+
+ self.sec_grp_creator.clean()
+
+ def test_create_group_with_one_simple_rule(self):
+ """
+ Tests the creation of an OpenStack Security Group with one simple custom rule.
+ """
+ # Create Image
+ sec_grp_rule_settings = list()
+ sec_grp_rule_settings.append(SecurityGroupRuleSettings(sec_grp_name=self.sec_grp_name,
+ direction=Direction.ingress))
+ sec_grp_settings = SecurityGroupSettings(name=self.sec_grp_name, description='hello group',
+ rule_settings=sec_grp_rule_settings)
+ self.sec_grp_creator = create_security_group.OpenStackSecurityGroup(self.os_creds, sec_grp_settings)
+ self.sec_grp_creator.create()
+
+ sec_grp = neutron_utils.get_security_group(self.neutron, self.sec_grp_name)
+ validation_utils.objects_equivalent(self.sec_grp_creator.get_security_group(), sec_grp)
+ rules = neutron_utils.get_rules_by_security_group(self.neutron,
+ self.sec_grp_creator.get_security_group())
+ self.assertEquals(len(self.sec_grp_creator.get_rules()), len(rules))
+ validation_utils.objects_equivalent(self.sec_grp_creator.get_rules(), rules)
+
+ def test_create_group_with_several_rules(self):
+ """
+ Tests the creation of an OpenStack Security Group with one simple custom rule.
+ """
+ # Create Image
+ sec_grp_rule_settings = list()
+ sec_grp_rule_settings.append(SecurityGroupRuleSettings(sec_grp_name=self.sec_grp_name,
+ direction=Direction.ingress))
+ sec_grp_rule_settings.append(SecurityGroupRuleSettings(sec_grp_name=self.sec_grp_name,
+ direction=Direction.egress,
+ protocol=Protocol.udp,
+ ethertype=Ethertype.IPv6))
+ sec_grp_rule_settings.append(SecurityGroupRuleSettings(sec_grp_name=self.sec_grp_name,
+ direction=Direction.egress,
+ protocol=Protocol.udp,
+ ethertype=Ethertype.IPv4,
+ port_range_min=10,
+ port_range_max=20))
+ sec_grp_settings = SecurityGroupSettings(name=self.sec_grp_name, description='hello group',
+ rule_settings=sec_grp_rule_settings)
+ self.sec_grp_creator = create_security_group.OpenStackSecurityGroup(self.os_creds, sec_grp_settings)
+ self.sec_grp_creator.create()
+
+ sec_grp = neutron_utils.get_security_group(self.neutron, self.sec_grp_name)
+ validation_utils.objects_equivalent(self.sec_grp_creator.get_security_group(), sec_grp)
+ rules = neutron_utils.get_rules_by_security_group(self.neutron, self.sec_grp_creator.get_security_group())
+ self.assertEquals(len(self.sec_grp_creator.get_rules()), len(rules))
+ validation_utils.objects_equivalent(self.sec_grp_creator.get_rules(), rules)
+
+ def test_add_rule(self):
+ """
+ Tests the creation of an OpenStack Security Group with one simple custom rule then adds one after creation.
+ """
+ # Create Image
+ sec_grp_rule_settings = list()
+ sec_grp_rule_settings.append(SecurityGroupRuleSettings(sec_grp_name=self.sec_grp_name,
+ direction=Direction.ingress))
+ sec_grp_settings = SecurityGroupSettings(name=self.sec_grp_name, description='hello group',
+ rule_settings=sec_grp_rule_settings)
+ self.sec_grp_creator = create_security_group.OpenStackSecurityGroup(self.os_creds, sec_grp_settings)
+ self.sec_grp_creator.create()
+
+ sec_grp = neutron_utils.get_security_group(self.neutron, self.sec_grp_name)
+ validation_utils.objects_equivalent(self.sec_grp_creator.get_security_group(), sec_grp)
+ rules = neutron_utils.get_rules_by_security_group(self.neutron,
+ self.sec_grp_creator.get_security_group())
+ self.assertEquals(len(self.sec_grp_creator.get_rules()), len(rules))
+ validation_utils.objects_equivalent(self.sec_grp_creator.get_rules(), rules)
+
+ self.sec_grp_creator.add_rule(SecurityGroupRuleSettings(sec_grp_name=self.sec_grp_creator.sec_grp_settings.name,
+ direction=Direction.egress, protocol=Protocol.icmp))
+ rules2 = neutron_utils.get_rules_by_security_group(self.neutron, self.sec_grp_creator.get_security_group())
+ self.assertEquals(len(rules) + 1, len(rules2))
+
+ def test_remove_rule_by_id(self):
+ """
+ Tests the creation of an OpenStack Security Group with two simple custom rules then removes one by the rule ID.
+ """
+ # Create Image
+ sec_grp_rule_settings = list()
+ sec_grp_rule_settings.append(SecurityGroupRuleSettings(sec_grp_name=self.sec_grp_name,
+ direction=Direction.ingress))
+ sec_grp_rule_settings.append(SecurityGroupRuleSettings(sec_grp_name=self.sec_grp_name,
+ direction=Direction.egress,
+ protocol=Protocol.udp,
+ ethertype=Ethertype.IPv6))
+ sec_grp_rule_settings.append(SecurityGroupRuleSettings(sec_grp_name=self.sec_grp_name,
+ direction=Direction.egress,
+ protocol=Protocol.udp,
+ ethertype=Ethertype.IPv4,
+ port_range_min=10,
+ port_range_max=20))
+ sec_grp_settings = SecurityGroupSettings(name=self.sec_grp_name, description='hello group',
+ rule_settings=sec_grp_rule_settings)
+ self.sec_grp_creator = create_security_group.OpenStackSecurityGroup(self.os_creds, sec_grp_settings)
+ self.sec_grp_creator.create()
+
+ sec_grp = neutron_utils.get_security_group(self.neutron, self.sec_grp_name)
+ validation_utils.objects_equivalent(self.sec_grp_creator.get_security_group(), sec_grp)
+ rules = neutron_utils.get_rules_by_security_group(self.neutron,
+ self.sec_grp_creator.get_security_group())
+ self.assertEquals(len(self.sec_grp_creator.get_rules()), len(rules))
+ validation_utils.objects_equivalent(self.sec_grp_creator.get_rules(), rules)
+
+ self.sec_grp_creator.remove_rule(rule_id=rules[0]['security_group_rule']['id'])
+ rules_after_del = neutron_utils.get_rules_by_security_group(self.neutron,
+ self.sec_grp_creator.get_security_group())
+ self.assertEquals(len(rules) - 1, len(rules_after_del))
+
+ def test_remove_rule_by_setting(self):
+ """
+ Tests the creation of an OpenStack Security Group with two simple custom rules then removes one by the rule
+ setting object
+ """
+ # Create Image
+ sec_grp_rule_settings = list()
+ sec_grp_rule_settings.append(SecurityGroupRuleSettings(sec_grp_name=self.sec_grp_name,
+ direction=Direction.ingress))
+ sec_grp_rule_settings.append(SecurityGroupRuleSettings(sec_grp_name=self.sec_grp_name,
+ direction=Direction.egress,
+ protocol=Protocol.udp,
+ ethertype=Ethertype.IPv6))
+ sec_grp_rule_settings.append(SecurityGroupRuleSettings(sec_grp_name=self.sec_grp_name,
+ direction=Direction.egress,
+ protocol=Protocol.udp,
+ ethertype=Ethertype.IPv4,
+ port_range_min=10,
+ port_range_max=20))
+ sec_grp_settings = SecurityGroupSettings(name=self.sec_grp_name, description='hello group',
+ rule_settings=sec_grp_rule_settings)
+ self.sec_grp_creator = create_security_group.OpenStackSecurityGroup(self.os_creds, sec_grp_settings)
+ self.sec_grp_creator.create()
+
+ sec_grp = neutron_utils.get_security_group(self.neutron, self.sec_grp_name)
+ validation_utils.objects_equivalent(self.sec_grp_creator.get_security_group(), sec_grp)
+ rules = neutron_utils.get_rules_by_security_group(self.neutron,
+ self.sec_grp_creator.get_security_group())
+ self.assertEquals(len(self.sec_grp_creator.get_rules()), len(rules))
+ validation_utils.objects_equivalent(self.sec_grp_creator.get_rules(), rules)
+
+ self.sec_grp_creator.remove_rule(rule_setting=sec_grp_rule_settings[0])
+ rules_after_del = neutron_utils.get_rules_by_security_group(self.neutron,
+ self.sec_grp_creator.get_security_group())
+ self.assertEquals(len(rules) - 1, len(rules_after_del))
+
+# TODO - Add more tests with different rules. Rule creation parameters can be somewhat complex
diff --git a/snaps/openstack/tests/create_user_tests.py b/snaps/openstack/tests/create_user_tests.py
new file mode 100644
index 0000000..1f7a163
--- /dev/null
+++ b/snaps/openstack/tests/create_user_tests.py
@@ -0,0 +1,155 @@
+# Copyright (c) 2016 Cable Television Laboratories, Inc. ("CableLabs")
+# and others. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+import uuid
+import unittest
+from snaps.openstack.create_user import OpenStackUser, UserSettings
+from snaps.openstack.tests.os_source_file_test import OSComponentTestCase
+from snaps.openstack.utils import keystone_utils
+
+__author__ = 'spisarski'
+
+
+class UserSettingsUnitTests(unittest.TestCase):
+ """
+ Tests the construction of the UserSettings class
+ """
+
+ def test_no_params(self):
+ with self.assertRaises(Exception):
+ UserSettings()
+
+ def test_empty_config(self):
+ with self.assertRaises(Exception):
+ UserSettings(config=dict())
+
+ def test_name_only(self):
+ with self.assertRaises(Exception):
+ UserSettings(name='foo')
+
+ def test_config_with_name_only(self):
+ with self.assertRaises(Exception):
+ UserSettings(config={'name': 'foo'})
+
+ def test_name_pass_enabled_str(self):
+ with self.assertRaises(Exception):
+ UserSettings(name='foo', password='bar', enabled='true')
+
+ def test_config_with_name_pass_enabled_str(self):
+ with self.assertRaises(Exception):
+ UserSettings(config={'name': 'foo', 'password': 'bar', 'enabled': 'true'})
+
+ def test_name_pass_only(self):
+ settings = UserSettings(name='foo', password='bar')
+ self.assertEquals('foo', settings.name)
+ self.assertEquals('bar', settings.password)
+ self.assertIsNone(settings.project_name)
+ self.assertIsNone(settings.email)
+ self.assertTrue(settings.enabled)
+
+ def test_config_with_name_pass_only(self):
+ settings = UserSettings(config={'name': 'foo', 'password': 'bar'})
+ self.assertEquals('foo', settings.name)
+ self.assertEquals('bar', settings.password)
+ self.assertIsNone(settings.project_name)
+ self.assertIsNone(settings.email)
+ self.assertTrue(settings.enabled)
+
+ def test_all(self):
+ settings = UserSettings(name='foo', password='bar', project_name='proj-foo', email='foo@bar.com', enabled=False)
+ self.assertEquals('foo', settings.name)
+ self.assertEquals('bar', settings.password)
+ self.assertEquals('proj-foo', settings.project_name)
+ self.assertEquals('foo@bar.com', settings.email)
+ self.assertFalse(settings.enabled)
+
+ def test_config_all(self):
+ settings = UserSettings(config={'name': 'foo', 'password': 'bar', 'project_name': 'proj-foo',
+ 'email': 'foo@bar.com', 'enabled': False})
+ self.assertEquals('foo', settings.name)
+ self.assertEquals('bar', settings.password)
+ self.assertEquals('proj-foo', settings.project_name)
+ self.assertEquals('foo@bar.com', settings.email)
+ self.assertFalse(settings.enabled)
+
+
+class CreateUserSuccessTests(OSComponentTestCase):
+ """
+ Test for the CreateImage class defined in create_image.py
+ """
+
+ def setUp(self):
+ """
+ Instantiates the CreateImage object that is responsible for downloading and creating an OS image file
+ within OpenStack
+ """
+ guid = str(uuid.uuid4())[:-19]
+ guid = self.__class__.__name__ + '-' + guid
+ self.user_settings = UserSettings(name=guid + '-name', password=guid + '-password')
+
+ self.keystone = keystone_utils.keystone_client(self.os_creds)
+
+ # Initialize for cleanup
+ self.user_creator = None
+
+ def tearDown(self):
+ """
+ Cleans the image and downloaded image file
+ """
+ if self.user_creator:
+ self.user_creator.clean()
+
+ def test_create_user(self):
+ """
+ Tests the creation of an OpenStack user.
+ """
+ self.user_creator = OpenStackUser(self.os_creds, self.user_settings)
+ created_user = self.user_creator.create()
+ self.assertIsNotNone(created_user)
+
+ retrieved_user = keystone_utils.get_user(self.keystone, self.user_settings.name)
+ self.assertIsNotNone(retrieved_user)
+ self.assertEquals(created_user, retrieved_user)
+
+ def test_create_user_2x(self):
+ """
+ Tests the creation of an OpenStack user twice to ensure it only creates one.
+ """
+ self.user_creator = OpenStackUser(self.os_creds, self.user_settings)
+ created_user = self.user_creator.create()
+ self.assertIsNotNone(created_user)
+
+ retrieved_user = keystone_utils.get_user(self.keystone, self.user_settings.name)
+ self.assertIsNotNone(retrieved_user)
+ self.assertEquals(created_user, retrieved_user)
+
+ # Create user for the second time to ensure it is the same
+ user2 = OpenStackUser(self.os_creds, self.user_settings).create()
+ self.assertEquals(retrieved_user, user2)
+
+ def test_create_delete_user(self):
+ """
+ Tests the creation of an OpenStack user then delete.
+ """
+ # Create Image
+ self.user_creator = OpenStackUser(self.os_creds, self.user_settings)
+ created_user = self.user_creator.create()
+ self.assertIsNotNone(created_user)
+
+ keystone_utils.delete_user(self.keystone, created_user)
+
+ # Delete user
+ self.user_creator.clean()
+ self.assertIsNone(self.user_creator.get_user())
+
diff --git a/snaps/openstack/tests/openstack_tests.py b/snaps/openstack/tests/openstack_tests.py
new file mode 100644
index 0000000..dab2ea2
--- /dev/null
+++ b/snaps/openstack/tests/openstack_tests.py
@@ -0,0 +1,144 @@
+# Copyright (c) 2016 Cable Television Laboratories, Inc. ("CableLabs")
+# and others. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+import re
+
+from snaps import file_utils
+from snaps.openstack.create_network import NetworkSettings, SubnetSettings
+from snaps.openstack.create_router import RouterSettings
+from snaps.openstack.os_credentials import OSCreds, ProxySettings
+from snaps.openstack.create_image import ImageSettings
+import logging
+
+__author__ = 'spisarski'
+
+
+logger = logging.getLogger('openstack_tests')
+
+
+def get_credentials(os_env_file=None, proxy_settings_str=None, ssh_proxy_cmd=None, dev_os_env_file=None):
+ """
+ Returns the OpenStack credentials object. It first attempts to retrieve them from a standard OpenStack source file.
+ If that file is None, it will attempt to retrieve them with a YAML file.
+ it will retrieve them from a
+ :param os_env_file: the OpenStack source file
+ :param proxy_settings_str: proxy settings string <host>:<port> (optional)
+ :param ssh_proxy_cmd: the SSH proxy command for your environment (optional)
+ :param dev_os_env_file: the YAML file to retrieve both the OS credentials and proxy settings
+ :return: the SNAPS credentials object
+ """
+ if os_env_file:
+ logger.debug('Reading RC file - ' + os_env_file)
+ config = file_utils.read_os_env_file(os_env_file)
+ proj_name = config.get('OS_PROJECT_NAME')
+ if not proj_name:
+ proj_name = config.get('OS_TENANT_NAME')
+
+ proj_domain_id = 'default'
+ user_domain_id = 'default'
+
+ if config.get('OS_PROJECT_DOMAIN_ID'):
+ proj_domain_id = config['OS_PROJECT_DOMAIN_ID']
+ if config.get('OS_USER_DOMAIN_ID'):
+ user_domain_id = config['OS_USER_DOMAIN_ID']
+ if config.get('OS_IDENTITY_API_VERSION'):
+ version = int(config['OS_IDENTITY_API_VERSION'])
+ else:
+ version = 2
+
+ proxy_settings = None
+ if proxy_settings_str:
+ tokens = re.split(':', proxy_settings_str)
+ proxy_settings = ProxySettings(tokens[0], tokens[1], ssh_proxy_cmd)
+
+ os_creds = OSCreds(username=config['OS_USERNAME'],
+ password=config['OS_PASSWORD'],
+ auth_url=config['OS_AUTH_URL'],
+ project_name=proj_name,
+ identity_api_version=version,
+ user_domain_id=user_domain_id,
+ project_domain_id=proj_domain_id,
+ proxy_settings=proxy_settings)
+ else:
+ logger.info('Reading development os_env file - ' + dev_os_env_file)
+ config = file_utils.read_yaml(dev_os_env_file)
+ identity_api_version = config.get('identity_api_version')
+ if not identity_api_version:
+ identity_api_version = 2
+
+ proxy_settings = None
+ proxy_str = config.get('http_proxy')
+ if proxy_str:
+ tokens = re.split(':', proxy_str)
+ proxy_settings = ProxySettings(tokens[0], tokens[1], config.get('ssh_proxy_cmd'))
+
+ os_creds = OSCreds(username=config['username'], password=config['password'],
+ auth_url=config['os_auth_url'], project_name=config['project_name'],
+ identity_api_version=identity_api_version,
+ proxy_settings=proxy_settings)
+
+ logger.info('OS Credentials = ' + str(os_creds))
+ return os_creds
+
+
+def cirros_url_image(name):
+ return ImageSettings(name=name, image_user='cirros', img_format='qcow2',
+ url='http://download.cirros-cloud.net/0.3.4/cirros-0.3.4-x86_64-disk.img')
+
+
+def file_image_test_settings(name, file_path):
+ return ImageSettings(name=name, image_user='cirros', img_format='qcow2',
+ image_file=file_path)
+
+
+def centos_url_image(name):
+ return ImageSettings(name=name, image_user='centos', img_format='qcow2',
+ url='http://cloud.centos.org/centos/7/images/CentOS-7-x86_64-GenericCloud.qcow2',
+ nic_config_pb_loc='./provisioning/ansible/centos-network-setup/playbooks/configure_host.yml')
+
+
+def ubuntu_url_image(name):
+ return ImageSettings(
+ name=name, image_user='ubuntu', img_format='qcow2',
+ url='http://uec-images.ubuntu.com/releases/trusty/14.04/ubuntu-14.04-server-cloudimg-amd64-disk1.img',
+ nic_config_pb_loc='./provisioning/ansible/ubuntu-network-setup/playbooks/configure_host.yml')
+
+
+def get_priv_net_config(net_name, subnet_name, router_name=None, cidr='10.55.0.0/24', external_net=None):
+ return OSNetworkConfig(net_name, subnet_name, cidr, router_name, external_gateway=external_net)
+
+
+def get_pub_net_config(net_name, subnet_name=None, router_name=None, cidr='10.55.1.0/24', external_net=None):
+ return OSNetworkConfig(net_name, subnet_name, cidr, router_name, external_gateway=external_net)
+
+
+class OSNetworkConfig:
+ """
+ Represents the settings required for the creation of a network in OpenStack
+ """
+
+ def __init__(self, net_name, subnet_name=None, subnet_cidr=None, router_name=None, external_gateway=None):
+
+ if subnet_name and subnet_cidr:
+ self.network_settings = NetworkSettings(
+ name=net_name, subnet_settings=[SubnetSettings(cidr=subnet_cidr, name=subnet_name)])
+ else:
+ self.network_settings = NetworkSettings(name=net_name)
+
+ if router_name:
+ if subnet_name:
+ self.router_settings = RouterSettings(name=router_name, external_gateway=external_gateway,
+ internal_subnets=[subnet_name])
+ else:
+ self.router_settings = RouterSettings(name=router_name, external_gateway=external_gateway)
diff --git a/snaps/openstack/tests/os_source_file_test.py b/snaps/openstack/tests/os_source_file_test.py
new file mode 100644
index 0000000..fa8d197
--- /dev/null
+++ b/snaps/openstack/tests/os_source_file_test.py
@@ -0,0 +1,131 @@
+# Copyright (c) 2016 Cable Television Laboratories, Inc. ("CableLabs")
+# and others. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+import unittest
+import uuid
+
+from snaps import file_utils
+import openstack_tests
+import logging
+
+# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+# To run these tests from an IDE, the CWD must be set to the python directory of this project
+# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+from snaps.openstack.create_project import ProjectSettings
+from snaps.openstack.create_user import UserSettings
+from snaps.openstack.utils import deploy_utils, keystone_utils
+
+dev_os_env_file = 'openstack/tests/conf/os_env.yaml'
+
+
+class OSComponentTestCase(unittest.TestCase):
+
+ """
+ Super for test classes requiring a connection to OpenStack
+ """
+ def __init__(self, method_name='runTest', os_env_file=None, ext_net_name=None, http_proxy_str=None,
+ ssh_proxy_cmd=None, log_level=logging.DEBUG):
+ super(OSComponentTestCase, self).__init__(method_name)
+
+ logging.basicConfig(level=log_level)
+
+ self.os_creds = openstack_tests.get_credentials(os_env_file=os_env_file, proxy_settings_str=http_proxy_str,
+ ssh_proxy_cmd=ssh_proxy_cmd, dev_os_env_file=dev_os_env_file)
+ self.ext_net_name = ext_net_name
+
+ if not self.ext_net_name and file_utils.file_exists(dev_os_env_file):
+ test_conf = file_utils.read_yaml(dev_os_env_file)
+ self.ext_net_name = test_conf.get('ext_net')
+
+ @staticmethod
+ def parameterize(testcase_klass, os_env_file, ext_net_name, http_proxy_str=None, ssh_proxy_cmd=None,
+ log_level=logging.DEBUG):
+ """ Create a suite containing all tests taken from the given
+ subclass, passing them the parameter 'param'.
+ """
+ test_loader = unittest.TestLoader()
+ test_names = test_loader.getTestCaseNames(testcase_klass)
+ suite = unittest.TestSuite()
+ for name in test_names:
+ suite.addTest(testcase_klass(name, os_env_file, ext_net_name, http_proxy_str, ssh_proxy_cmd, log_level))
+ return suite
+
+
+class OSIntegrationTestCase(OSComponentTestCase):
+
+ """
+ Super for test classes requiring a connection to OpenStack
+ """
+ def __init__(self, method_name='runTest', os_env_file=None, ext_net_name=None, http_proxy_str=None,
+ ssh_proxy_cmd=None, use_keystone=False, log_level=logging.DEBUG):
+ super(OSIntegrationTestCase, self).__init__(method_name=method_name, os_env_file=os_env_file,
+ ext_net_name=ext_net_name, http_proxy_str=http_proxy_str,
+ ssh_proxy_cmd=ssh_proxy_cmd, log_level=log_level)
+ self.use_keystone = use_keystone
+ self.keystone = None
+
+ @staticmethod
+ def parameterize(testcase_klass, os_env_file, ext_net_name, http_proxy_str=None, ssh_proxy_cmd=None,
+ use_keystone=False, log_level=logging.DEBUG):
+ """ Create a suite containing all tests taken from the given
+ subclass, passing them the parameter 'param'.
+ """
+ test_loader = unittest.TestLoader()
+ test_names = test_loader.getTestCaseNames(testcase_klass)
+ suite = unittest.TestSuite()
+ for name in test_names:
+ suite.addTest(testcase_klass(name, os_env_file, ext_net_name, http_proxy_str, ssh_proxy_cmd, use_keystone,
+ log_level))
+ return suite
+
+ """
+ Super for test classes that should be run within their own project/tenant as they can run for quite some time
+ """
+ def __start__(self):
+ """
+ Creates a project and user to be leveraged by subclass test methods. If implementing class uses this method,
+ it must call __clean__() else you will be left with unwanted users and tenants
+ """
+ self.project_creator = None
+ self.user_creator = None
+ self.admin_os_creds = self.os_creds
+ self.role = None
+
+ if self.use_keystone:
+ self.keystone = keystone_utils.keystone_client(self.os_creds)
+ guid = self.__class__.__name__ + '-' + str(uuid.uuid4())[:-19]
+ project_name = guid + '-proj'
+ self.project_creator = deploy_utils.create_project(self.admin_os_creds, ProjectSettings(name=project_name))
+
+ self.user_creator = deploy_utils.create_user(
+ self.admin_os_creds, UserSettings(name=guid + '-user', password=guid, project_name=project_name))
+ self.os_creds = self.user_creator.get_os_creds(self.project_creator.project_settings.name)
+
+ # add user to project
+ self.project_creator.assoc_user(self.user_creator.get_user())
+
+ def __clean__(self):
+ """
+ Cleans up test user and project.
+ Must be called at the end of child classes tearDown() if __start__() is called during setUp() else these
+ objects will persist after the test is run
+ """
+ if self.role:
+ keystone_utils.delete_role(self.keystone, self.role)
+
+ if self.project_creator:
+ self.project_creator.clean()
+
+ if self.user_creator:
+ self.user_creator.clean()
diff --git a/snaps/openstack/tests/validation_utils.py b/snaps/openstack/tests/validation_utils.py
new file mode 100644
index 0000000..7c9bd7f
--- /dev/null
+++ b/snaps/openstack/tests/validation_utils.py
@@ -0,0 +1,69 @@
+# Copyright (c) 2016 Cable Television Laboratories, Inc. ("CableLabs")
+# and others. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+from neutronclient.v2_0.client import _DictWithMeta
+
+__author__ = 'spisarski'
+
+
+def objects_equivalent(obj1, obj2):
+ """
+ Returns true if both objects are equivalent
+ :param obj1:
+ :param obj2:
+ :return: T/F
+ """
+ if obj1 is None and obj2 is None:
+ return True
+ if type(obj1) is dict or type(obj1) is _DictWithMeta:
+ return dicts_equivalent(obj1, obj2)
+ elif type(obj1) is list:
+ return lists_equivalent(obj1, obj2)
+ else:
+ return obj1 == obj2
+
+
+def dicts_equivalent(dict1, dict2):
+ """
+ Returns true when each key/value pair is equal
+ :param dict1: dict 1
+ :param dict2: dict 2
+ :return: T/F
+ """
+ if (type(dict1) is dict or type(dict1) is _DictWithMeta) and (type(dict2) is dict or type(dict2) is _DictWithMeta):
+ for key, value1 in dict1.iteritems():
+ if not objects_equivalent(value1, dict2.get(key)):
+ return False
+ return True
+ return False
+
+
+def lists_equivalent(list1, list2):
+ """
+ Returns true when an item in list1 is also contained in list2
+ :param list1: list 1
+ :param list2: list 2
+ :return: T/F
+ """
+ if len(list1) == len(list2) and type(list1) is list and type(list2) is list:
+ for item1 in list1:
+ has_equivalent = False
+ for item2 in list2:
+ has_equivalent = objects_equivalent(item1, item2)
+ if has_equivalent:
+ break
+ if not has_equivalent:
+ return False
+ return True
+ return False