summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/how-to-use/APITests.rst4
-rw-r--r--docs/how-to-use/IntegrationTests.rst3
-rw-r--r--docs/how-to-use/LibraryUsage.rst3
-rw-r--r--snaps/domain/project.py4
-rw-r--r--snaps/domain/test/project_tests.py18
-rw-r--r--snaps/openstack/create_keypairs.py15
-rw-r--r--snaps/openstack/os_credentials.py4
-rw-r--r--snaps/openstack/tests/create_keypairs_tests.py44
-rw-r--r--snaps/openstack/tests/create_project_tests.py38
-rw-r--r--snaps/openstack/utils/keystone_utils.py12
10 files changed, 128 insertions, 17 deletions
diff --git a/docs/how-to-use/APITests.rst b/docs/how-to-use/APITests.rst
index 68a1a07..ff0ab45 100644
--- a/docs/how-to-use/APITests.rst
+++ b/docs/how-to-use/APITests.rst
@@ -91,6 +91,10 @@ create_project_tests.py - CreateProjectSuccessTests
+----------------------------------+---------------+-----------------------------------------------------------+
| Test Name | Keystone API | Description |
+==================================+===============+===========================================================+
+| test_create_project_bad_domain | 3 | Ensures that keystone v3 clients using the domain ID |
+| | | project setting project creation will fail with an invalid|
+| | | domain id/name |
++----------------------------------+---------------+-----------------------------------------------------------+
| test_create_project | 2 & 3 | Tests the creation of a project via the OpenStackProject |
| | | class |
+----------------------------------+---------------+-----------------------------------------------------------+
diff --git a/docs/how-to-use/IntegrationTests.rst b/docs/how-to-use/IntegrationTests.rst
index 92a5301..4cdd94f 100644
--- a/docs/how-to-use/IntegrationTests.rst
+++ b/docs/how-to-use/IntegrationTests.rst
@@ -118,6 +118,9 @@ create_keypairs_tests.py - CreateKeypairsTests
| test_create_keypair_only | 2 | Ensures that a keypair object can be created simply by |
| | | only configuring a name |
+---------------------------------------+---------------+-----------------------------------------------------------+
+| test_create_keypair_large_key | 2 | Ensures that a keypair object can be created with a large |
+| | | key of 10000 bytes |
++---------------------------------------+---------------+-----------------------------------------------------------+
| test_create_delete_keypair | 2 | Ensures that a keypair object is deleted via |
| | | OpenStackKeypair.clean() and subsequent calls do not |
| | | result in exceptions |
diff --git a/docs/how-to-use/LibraryUsage.rst b/docs/how-to-use/LibraryUsage.rst
index 0a137ba..353891e 100644
--- a/docs/how-to-use/LibraryUsage.rst
+++ b/docs/how-to-use/LibraryUsage.rst
@@ -31,7 +31,7 @@ attributes are listed below:
- project\_name (aka. tenant\_name)
- identity\_api\_version (for obtaining Keystone authorization token.
Versions 2.0 & v3 only validated.)
-- image\_api\_version (Glance version 1 currently only validated)
+- image\_api\_version (Glance version 1 & 2 only validated)
- network\_api\_version (Neutron version 2 currently only validated)
- compute\_api\_version (Nova version 2 currently only validated)
- heat\_api\_version (Heat version 1 currently only validated)
@@ -39,6 +39,7 @@ attributes are listed below:
- project\_domain\_id (default='default')
- interface (default='admin', used to specify the endpoint type for keystone: public, admin, internal)
- cacert (default=False, expected values T|F to denote server certificate verification, else value contains the path to an HTTPS certificate)
+- region_name (The region name default=None)
- proxy\_settings
- host (the HTTP proxy host)
diff --git a/snaps/domain/project.py b/snaps/domain/project.py
index 818645b..73357c7 100644
--- a/snaps/domain/project.py
+++ b/snaps/domain/project.py
@@ -19,14 +19,16 @@ class Project:
SNAPS domain object for Projects. Should contain attributes that
are shared amongst cloud providers
"""
- def __init__(self, name, project_id):
+ def __init__(self, name, project_id, domain_id=None):
"""
Constructor
:param name: the project's name
:param project_id: the project's id
+ :param domain_id: the project's domain id
"""
self.name = name
self.id = project_id
+ self.domain_id = domain_id
def __eq__(self, other):
return self.name == other.name and self.id == other.id
diff --git a/snaps/domain/test/project_tests.py b/snaps/domain/test/project_tests.py
index 4056bba..73939f0 100644
--- a/snaps/domain/test/project_tests.py
+++ b/snaps/domain/test/project_tests.py
@@ -22,12 +22,26 @@ class ProjectDomainObjectTests(unittest.TestCase):
Tests the construction of the snaps.domain.test.Project class
"""
- def test_construction_positional(self):
+ def test_construction_positional_minimal(self):
project = Project('foo', '123-456')
self.assertEqual('foo', project.name)
self.assertEqual('123-456', project.id)
+ self.assertIsNone(project.domain_id)
- def test_construction_named(self):
+ def test_construction_positional_all(self):
+ project = Project('foo', '123-456', 'hello')
+ self.assertEqual('foo', project.name)
+ self.assertEqual('123-456', project.id)
+ self.assertEqual('hello', project.domain_id)
+
+ def test_construction_named_minimal(self):
project = Project(project_id='123-456', name='foo')
self.assertEqual('foo', project.name)
self.assertEqual('123-456', project.id)
+ self.assertIsNone(project.domain_id)
+
+ def test_construction_named_all(self):
+ project = Project(domain_id='hello', project_id='123-456', name='foo')
+ self.assertEqual('foo', project.name)
+ self.assertEqual('123-456', project.id)
+ self.assertEqual('hello', project.domain_id)
diff --git a/snaps/openstack/create_keypairs.py b/snaps/openstack/create_keypairs.py
index 16374ad..c81fef5 100644
--- a/snaps/openstack/create_keypairs.py
+++ b/snaps/openstack/create_keypairs.py
@@ -68,13 +68,13 @@ class OpenStackKeypair:
self.keypair_settings.public_filepath)
if self.keypair_settings.delete_on_clean is not None:
- self.__delete_keys_on_clean = self.keypair_settings.delete_on_clean
+ delete_on_clean = self.keypair_settings.delete_on_clean
+ self.__delete_keys_on_clean = delete_on_clean
else:
self.__delete_keys_on_clean = False
else:
logger.info("Creating new keypair")
- # TODO - Make this value configurable
- keys = nova_utils.create_keys(1024)
+ keys = nova_utils.create_keys(self.keypair_settings.key_size)
self.__keypair = nova_utils.upload_keypair(
self.__nova, self.keypair_settings.name,
nova_utils.public_key_openssh(keys))
@@ -83,7 +83,8 @@ class OpenStackKeypair:
self.keypair_settings.private_filepath)
if self.keypair_settings.delete_on_clean is not None:
- self.__delete_keys_on_clean = self.keypair_settings.delete_on_clean
+ delete_on_clean = self.keypair_settings.delete_on_clean
+ self.__delete_keys_on_clean = delete_on_clean
else:
self.__delete_keys_on_clean = True
elif self.__keypair and not os.path.isfile(
@@ -137,6 +138,8 @@ class KeypairSettings:
public key file is or will be stored
:param private_filepath: The path where the generated private key file
will be stored
+ :param key_size: The number of bytes for the key size when it needs to
+ be generated (Must be >=512 default 1024)
:param delete_on_clean: when True, the key files will be deleted when
OpenStackKeypair#clean() is called
:return:
@@ -145,6 +148,7 @@ class KeypairSettings:
self.name = kwargs.get('name')
self.public_filepath = kwargs.get('public_filepath')
self.private_filepath = kwargs.get('private_filepath')
+ self.key_size = int(kwargs.get('key_size', 1024))
if kwargs.get('delete_on_clean') is not None:
if isinstance(kwargs.get('delete_on_clean'), bool):
@@ -157,6 +161,9 @@ class KeypairSettings:
if not self.name:
raise KeypairSettingsError('Name is a required attribute')
+ if self.key_size < 512:
+ raise KeypairSettingsError('key_size must be >=512')
+
class KeypairSettingsError(Exception):
"""
diff --git a/snaps/openstack/os_credentials.py b/snaps/openstack/os_credentials.py
index 3054478..0cecfa5 100644
--- a/snaps/openstack/os_credentials.py
+++ b/snaps/openstack/os_credentials.py
@@ -42,8 +42,8 @@ class OSCreds:
clients
:param heat_api_version: The OpenStack's API version to use for Heat
clients
- :param user_domain_id: Used for v3 APIs
- :param project_domain_id: Used for v3 APIs
+ :param user_domain_id: Used for v3 APIs (default='default')
+ :param project_domain_id: Used for v3 APIs (default='default')
:param interface: Used to specify the endpoint type for keystone as
public, admin, internal
:param proxy_settings: instance of os_credentials.ProxySettings class
diff --git a/snaps/openstack/tests/create_keypairs_tests.py b/snaps/openstack/tests/create_keypairs_tests.py
index 2824c34..0b35095 100644
--- a/snaps/openstack/tests/create_keypairs_tests.py
+++ b/snaps/openstack/tests/create_keypairs_tests.py
@@ -39,9 +39,14 @@ class KeypairSettingsUnitTests(unittest.TestCase):
with self.assertRaises(KeypairSettingsError):
KeypairSettings(**dict())
+ def test_small_key_size(self):
+ with self.assertRaises(KeypairSettingsError):
+ KeypairSettings(name='foo', key_size=511)
+
def test_name_only(self):
settings = KeypairSettings(name='foo')
self.assertEqual('foo', settings.name)
+ self.assertEqual(1024, settings.key_size)
self.assertIsNone(settings.public_filepath)
self.assertIsNone(settings.private_filepath)
self.assertIsNone(settings.delete_on_clean)
@@ -49,6 +54,7 @@ class KeypairSettingsUnitTests(unittest.TestCase):
def test_config_with_name_only(self):
settings = KeypairSettings(**{'name': 'foo'})
self.assertEqual('foo', settings.name)
+ self.assertEqual(1024, settings.key_size)
self.assertIsNone(settings.public_filepath)
self.assertIsNone(settings.private_filepath)
self.assertIsNone(settings.delete_on_clean)
@@ -56,6 +62,7 @@ class KeypairSettingsUnitTests(unittest.TestCase):
def test_name_pub_only(self):
settings = KeypairSettings(name='foo', public_filepath='/foo/bar.pub')
self.assertEqual('foo', settings.name)
+ self.assertEqual(1024, settings.key_size)
self.assertEqual('/foo/bar.pub', settings.public_filepath)
self.assertIsNone(settings.private_filepath)
self.assertIsNone(settings.delete_on_clean)
@@ -64,6 +71,7 @@ class KeypairSettingsUnitTests(unittest.TestCase):
settings = KeypairSettings(
**{'name': 'foo', 'public_filepath': '/foo/bar.pub'})
self.assertEqual('foo', settings.name)
+ self.assertEqual(1024, settings.key_size)
self.assertEqual('/foo/bar.pub', settings.public_filepath)
self.assertIsNone(settings.private_filepath)
self.assertIsNone(settings.delete_on_clean)
@@ -71,6 +79,7 @@ class KeypairSettingsUnitTests(unittest.TestCase):
def test_name_priv_only(self):
settings = KeypairSettings(name='foo', private_filepath='/foo/bar')
self.assertEqual('foo', settings.name)
+ self.assertEqual(1024, settings.key_size)
self.assertIsNone(settings.public_filepath)
self.assertEqual('/foo/bar', settings.private_filepath)
self.assertIsNone(settings.delete_on_clean)
@@ -79,6 +88,7 @@ class KeypairSettingsUnitTests(unittest.TestCase):
settings = KeypairSettings(
**{'name': 'foo', 'private_filepath': '/foo/bar'})
self.assertEqual('foo', settings.name)
+ self.assertEqual(1024, settings.key_size)
self.assertIsNone(settings.public_filepath)
self.assertEqual('/foo/bar', settings.private_filepath)
self.assertIsNone(settings.delete_on_clean)
@@ -86,8 +96,10 @@ class KeypairSettingsUnitTests(unittest.TestCase):
def test_all_delete_bool(self):
settings = KeypairSettings(
name='foo', public_filepath='/foo/bar.pub',
- private_filepath='/foo/bar', delete_on_clean=True)
+ private_filepath='/foo/bar', delete_on_clean=True,
+ key_size=999)
self.assertEqual('foo', settings.name)
+ self.assertEqual(999, settings.key_size)
self.assertEqual('/foo/bar.pub', settings.public_filepath)
self.assertEqual('/foo/bar', settings.private_filepath)
self.assertTrue(settings.delete_on_clean)
@@ -97,6 +109,7 @@ class KeypairSettingsUnitTests(unittest.TestCase):
name='foo', public_filepath='/foo/bar.pub',
private_filepath='/foo/bar', delete_on_clean='True')
self.assertEqual('foo', settings.name)
+ self.assertEqual(1024, settings.key_size)
self.assertEqual('/foo/bar.pub', settings.public_filepath)
self.assertEqual('/foo/bar', settings.private_filepath)
self.assertTrue(settings.delete_on_clean)
@@ -106,6 +119,7 @@ class KeypairSettingsUnitTests(unittest.TestCase):
name='foo', public_filepath='/foo/bar.pub',
private_filepath='/foo/bar', delete_on_clean='true')
self.assertEqual('foo', settings.name)
+ self.assertEqual(1024, settings.key_size)
self.assertEqual('/foo/bar.pub', settings.public_filepath)
self.assertEqual('/foo/bar', settings.private_filepath)
self.assertTrue(settings.delete_on_clean)
@@ -115,6 +129,7 @@ class KeypairSettingsUnitTests(unittest.TestCase):
name='foo', public_filepath='/foo/bar.pub',
private_filepath='/foo/bar', delete_on_clean='False')
self.assertEqual('foo', settings.name)
+ self.assertEqual(1024, settings.key_size)
self.assertEqual('/foo/bar.pub', settings.public_filepath)
self.assertEqual('/foo/bar', settings.private_filepath)
self.assertFalse(settings.delete_on_clean)
@@ -122,8 +137,10 @@ class KeypairSettingsUnitTests(unittest.TestCase):
def test_all_delete_str_false_lc(self):
settings = KeypairSettings(
name='foo', public_filepath='/foo/bar.pub',
- private_filepath='/foo/bar', delete_on_clean='false')
+ private_filepath='/foo/bar', delete_on_clean='false',
+ key_size='999')
self.assertEqual('foo', settings.name)
+ self.assertEqual(999, settings.key_size)
self.assertEqual('/foo/bar.pub', settings.public_filepath)
self.assertEqual('/foo/bar', settings.private_filepath)
self.assertFalse(settings.delete_on_clean)
@@ -131,8 +148,10 @@ class KeypairSettingsUnitTests(unittest.TestCase):
def test_config_all_delete_false_bool(self):
settings = KeypairSettings(
**{'name': 'foo', 'public_filepath': '/foo/bar.pub',
- 'private_filepath': '/foo/bar', 'delete_on_clean': False})
+ 'private_filepath': '/foo/bar', 'delete_on_clean': False,
+ 'key_size': 999})
self.assertEqual('foo', settings.name)
+ self.assertEqual(999, settings.key_size)
self.assertEqual('/foo/bar.pub', settings.public_filepath)
self.assertEqual('/foo/bar', settings.private_filepath)
self.assertFalse(settings.delete_on_clean)
@@ -142,6 +161,7 @@ class KeypairSettingsUnitTests(unittest.TestCase):
**{'name': 'foo', 'public_filepath': '/foo/bar.pub',
'private_filepath': '/foo/bar', 'delete_on_clean': 'False'})
self.assertEqual('foo', settings.name)
+ self.assertEqual(1024, settings.key_size)
self.assertEqual('/foo/bar.pub', settings.public_filepath)
self.assertEqual('/foo/bar', settings.private_filepath)
self.assertFalse(settings.delete_on_clean)
@@ -151,6 +171,7 @@ class KeypairSettingsUnitTests(unittest.TestCase):
**{'name': 'foo', 'public_filepath': '/foo/bar.pub',
'private_filepath': '/foo/bar', 'delete_on_clean': 'false'})
self.assertEqual('foo', settings.name)
+ self.assertEqual(1024, settings.key_size)
self.assertEqual('/foo/bar.pub', settings.public_filepath)
self.assertEqual('/foo/bar', settings.private_filepath)
self.assertFalse(settings.delete_on_clean)
@@ -158,8 +179,10 @@ class KeypairSettingsUnitTests(unittest.TestCase):
def test_config_all_delete_false_str_foo(self):
settings = KeypairSettings(
**{'name': 'foo', 'public_filepath': '/foo/bar.pub',
- 'private_filepath': '/foo/bar', 'delete_on_clean': 'foo'})
+ 'private_filepath': '/foo/bar', 'delete_on_clean': 'foo',
+ 'key_size': '999'})
self.assertEqual('foo', settings.name)
+ self.assertEqual(999, settings.key_size)
self.assertEqual('/foo/bar.pub', settings.public_filepath)
self.assertEqual('/foo/bar', settings.private_filepath)
self.assertFalse(settings.delete_on_clean)
@@ -213,6 +236,19 @@ class CreateKeypairsTests(OSIntegrationTestCase):
self.keypair_creator.get_keypair())
self.assertEqual(self.keypair_creator.get_keypair(), keypair)
+ def test_create_keypair_large_key(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, key_size=10000))
+ self.keypair_creator.create()
+
+ keypair = nova_utils.keypair_exists(self.nova,
+ self.keypair_creator.get_keypair())
+ self.assertEqual(self.keypair_creator.get_keypair(), keypair)
+
def test_create_delete_keypair(self):
"""
Tests the creation then deletion of an OpenStack keypair to ensure
diff --git a/snaps/openstack/tests/create_project_tests.py b/snaps/openstack/tests/create_project_tests.py
index f2af0d9..f388ba5 100644
--- a/snaps/openstack/tests/create_project_tests.py
+++ b/snaps/openstack/tests/create_project_tests.py
@@ -15,6 +15,8 @@
import unittest
import uuid
+from keystoneclient.exceptions import BadRequest
+
from snaps.openstack.create_project import (
OpenStackProject, ProjectSettings, ProjectSettingsError)
from snaps.openstack.create_security_group import OpenStackSecurityGroup
@@ -98,6 +100,19 @@ class CreateProjectSuccessTests(OSComponentTestCase):
if self.project_creator:
self.project_creator.clean()
+ def test_create_project_bad_domain(self):
+ """
+ Tests the creation of an OpenStack project with an invalid domain
+ value. This test will not do anything with a keystone v2.0 client.
+ """
+ if self.keystone.version != keystone_utils.V2_VERSION_STR:
+ self.project_settings.domain = 'foo'
+ self.project_creator = OpenStackProject(self.os_creds,
+ self.project_settings)
+
+ with self.assertRaises(BadRequest):
+ self.project_creator.create()
+
def test_create_project(self):
"""
Tests the creation of an OpenStack project.
@@ -111,6 +126,8 @@ class CreateProjectSuccessTests(OSComponentTestCase):
keystone=self.keystone, project_name=self.project_settings.name)
self.assertIsNotNone(retrieved_project)
self.assertEqual(created_project, retrieved_project)
+ self.assertTrue(validate_project(self.keystone, self.project_settings,
+ created_project))
def test_create_project_2x(self):
"""
@@ -130,6 +147,8 @@ class CreateProjectSuccessTests(OSComponentTestCase):
project2 = OpenStackProject(self.os_creds,
self.project_settings).create()
self.assertEqual(retrieved_project, project2)
+ self.assertTrue(validate_project(self.keystone, self.project_settings,
+ created_project))
def test_create_delete_project(self):
"""
@@ -147,7 +166,8 @@ class CreateProjectSuccessTests(OSComponentTestCase):
self.assertIsNone(self.project_creator.get_project())
- # TODO - Expand tests
+ self.assertTrue(validate_project(self.keystone, self.project_settings,
+ created_project))
class CreateProjectUserTests(OSComponentTestCase):
@@ -254,3 +274,19 @@ class CreateProjectUserTests(OSComponentTestCase):
self.assertEqual(self.project_creator.get_project().id,
sec_grp.project_id)
+
+
+def validate_project(keystone, project_settings, project):
+ """
+ Validates that the project_settings used to create the project have been
+ properly set
+ :param keystone: the keystone client for version checking
+ :param project_settings: the settings used to create the project
+ :param project: the SNAPS-OO Project domain object
+ :return: T/F
+ """
+ if keystone.version == keystone_utils.V2_VERSION_STR:
+ return project_settings.name == project.name
+ else:
+ return (project_settings.name == project.name and
+ project_settings.domain == project.domain_id)
diff --git a/snaps/openstack/utils/keystone_utils.py b/snaps/openstack/utils/keystone_utils.py
index 8446df0..e070a49 100644
--- a/snaps/openstack/utils/keystone_utils.py
+++ b/snaps/openstack/utils/keystone_utils.py
@@ -127,8 +127,12 @@ def get_project(keystone=None, os_creds=None, project_name=None):
projects = keystone.projects.list(**{'name': project_name})
for project in projects:
+ domain_id = None
+ if keystone.version != V2_VERSION_STR:
+ domain_id = project.domain_id
if project.name == project_name:
- return Project(name=project.name, project_id=project.id)
+ return Project(name=project.name, project_id=project.id,
+ domain_id=domain_id)
return None
@@ -140,6 +144,8 @@ def create_project(keystone, project_settings):
:param project_settings: the project configuration
:return: SNAPS-OO Project domain object
"""
+ domain_id = None
+
if keystone.version == V2_VERSION_STR:
os_project = keystone.tenants.create(
project_settings.name, project_settings.description,
@@ -149,8 +155,10 @@ def create_project(keystone, project_settings):
project_settings.name, project_settings.domain,
description=project_settings.description,
enabled=project_settings.enabled)
+ domain_id = os_project.domain_id
- return Project(name=os_project.name, project_id=os_project.id)
+ return Project(
+ name=os_project.name, project_id=os_project.id, domain_id=domain_id)
def delete_project(keystone, project):