Created domain object for flavors. 29/37029/2
authorspisarski <s.pisarski@cablelabs.com>
Thu, 6 Jul 2017 19:09:46 +0000 (13:09 -0600)
committerspisarski <s.pisarski@cablelabs.com>
Thu, 6 Jul 2017 19:18:37 +0000 (13:18 -0600)
OpenStack implementation details were leaking out into the
flavor creator.

JIRA: SNAPS-111

Change-Id: I59a77d02e30065a7f4560e74295b2084a83686df
Signed-off-by: spisarski <s.pisarski@cablelabs.com>
snaps/domain/flavor.py [new file with mode: 0644]
snaps/domain/test/flavor_tests.py [new file with mode: 0644]
snaps/openstack/create_flavor.py
snaps/openstack/utils/nova_utils.py
snaps/test_suite_builder.py

diff --git a/snaps/domain/flavor.py b/snaps/domain/flavor.py
new file mode 100644 (file)
index 0000000..035ca64
--- /dev/null
@@ -0,0 +1,43 @@
+# Copyright (c) 2017 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.
+
+
+class Flavor:
+    """
+    SNAPS domain object for Flavors. Should contain attributes that
+    are shared amongst cloud providers
+    """
+    def __init__(self, **kwargs):
+        """
+        Constructor
+        :param name: the flavor's name
+        :param flavor_id: the flavor's id
+        :param ram: the flavor's RAM in MB
+        :param disk: the flavor's disk size in GB
+        :param vcpus: the flavor's number of virtual CPUs
+        :param ephemeral: the flavor's ephemeral disk in GB
+        :param swap: the flavor's swap space in MB
+        :param rxtx_factor: the flavor's RX/TX factor integer value
+        :param is_public: denotes if flavor can be used by other projects
+        """
+        self.name = kwargs.get('name')
+        self.id = kwargs.get('id')
+        self.ram = kwargs.get('ram')
+        self.disk = kwargs.get('disk')
+        self.vcpus = kwargs.get('vcpus')
+        self.ephemeral = kwargs.get('ephemeral')
+        self.swap = kwargs.get('swap')
+        self.rxtx_factor = kwargs.get('rxtx_factor')
+        self.is_public = kwargs.get('is_public')
diff --git a/snaps/domain/test/flavor_tests.py b/snaps/domain/test/flavor_tests.py
new file mode 100644 (file)
index 0000000..4b74bd7
--- /dev/null
@@ -0,0 +1,50 @@
+# Copyright (c) 2017 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
+from snaps.domain.flavor import Flavor
+
+
+class FlavorDomainObjectTests(unittest.TestCase):
+    """
+    Tests the construction of the snaps.domain.test.Flavor class
+    """
+
+    def test_construction_kwargs(self):
+        flavor = Flavor(**{'name': 'name', 'id': 'id', 'ram': 10, 'disk': 20,
+                           'vcpus': 3, 'ephemeral': 30, 'swap': 100,
+                           'rxtx_factor': 5, 'is_public': True})
+        self.assertEqual('name', flavor.name)
+        self.assertEqual('id', flavor.id)
+        self.assertEqual(10, flavor.ram)
+        self.assertEqual(20, flavor.disk)
+        self.assertEqual(3, flavor.vcpus)
+        self.assertEqual(30, flavor.ephemeral)
+        self.assertEqual(100, flavor.swap)
+        self.assertEqual(5, flavor.rxtx_factor)
+        self.assertTrue(flavor.is_public)
+
+    def test_construction_named(self):
+        flavor = Flavor(is_public=True, rxtx_factor=5, swap=100, ephemeral=30,
+                        vcpus=3, disk=20, ram=10, id='id', name='name')
+        self.assertEqual('name', flavor.name)
+        self.assertEqual('id', flavor.id)
+        self.assertEqual(10, flavor.ram)
+        self.assertEqual(20, flavor.disk)
+        self.assertEqual(3, flavor.vcpus)
+        self.assertEqual(30, flavor.ephemeral)
+        self.assertEqual(100, flavor.swap)
+        self.assertEqual(5, flavor.rxtx_factor)
+        self.assertTrue(flavor.is_public)
index f1c7ee3..42264b0 100644 (file)
@@ -60,9 +60,8 @@ class OpenStackFlavor:
             self.__flavor = nova_utils.create_flavor(
                 self.__nova, self.flavor_settings)
             if self.flavor_settings.metadata:
-                self.__flavor.set_keys(self.flavor_settings.metadata)
-            self.__flavor = nova_utils.get_flavor_by_name(
-                self.__nova, self.flavor_settings.name)
+                nova_utils.set_flavor_keys(self.__nova, self.__flavor,
+                                           self.flavor_settings.metadata)
         else:
             logger.info('Did not create flavor due to cleanup mode')
 
index bab0533..d6f9a19 100644 (file)
@@ -21,6 +21,8 @@ from cryptography.hazmat.primitives import serialization
 from cryptography.hazmat.primitives.asymmetric import rsa
 from novaclient.client import Client
 from novaclient.exceptions import NotFound
+
+from snaps.domain.flavor import Flavor
 from snaps.domain.vm_inst import VmInst
 from snaps.openstack.utils import keystone_utils, glance_utils, neutron_utils
 
@@ -290,12 +292,45 @@ def delete_vm_instance(nova, vm_inst):
     nova.servers.delete(vm_inst.id)
 
 
-def get_flavor_by_name(nova, name):
+def get_os_flavor(nova, flavor):
     """
-    Returns a flavor by name
+    Returns to OpenStack flavor object by name
     :param nova: the Nova client
-    :param name: the flavor name to return
-    :return: the OpenStack flavor object or None if not exists
+    :param flavor: the SNAPS flavor domain object
+    :return: the OpenStack Flavor object
+    """
+    try:
+        return nova.flavors.get(flavor.id)
+    except NotFound:
+        return None
+
+
+def get_flavor(nova, flavor):
+    """
+    Returns to OpenStack flavor object by name
+    :param nova: the Nova client
+    :param flavor: the SNAPS flavor domain object
+    :return: the SNAPS Flavor domain object
+    """
+    os_flavor = get_os_flavor(nova, flavor)
+    if os_flavor:
+        return Flavor(
+            name=os_flavor.name, id=os_flavor.id, ram=os_flavor.ram,
+            disk=os_flavor.disk, vcpus=os_flavor.vcpus,
+            ephemeral=os_flavor.ephemeral, swap=os_flavor.swap,
+            rxtx_factor=os_flavor.rxtx_factor, is_public=os_flavor.is_public)
+    try:
+        return nova.flavors.get(flavor.id)
+    except NotFound:
+        return None
+
+
+def get_os_flavor_by_name(nova, name):
+    """
+    Returns to OpenStack flavor object by name
+    :param nova: the Nova client
+    :param name: the name of the flavor to query
+    :return: OpenStack flavor object
     """
     try:
         return nova.flavors.find(name=name)
@@ -303,31 +338,61 @@ def get_flavor_by_name(nova, name):
         return None
 
 
+def get_flavor_by_name(nova, name):
+    """
+    Returns a flavor by name
+    :param nova: the Nova client
+    :param name: the flavor name to return
+    :return: the SNAPS flavor domain object or None if not exists
+    """
+    os_flavor = get_os_flavor_by_name(nova, name)
+    if os_flavor:
+        return Flavor(
+            name=os_flavor.name, id=os_flavor.id, ram=os_flavor.ram,
+            disk=os_flavor.disk, vcpus=os_flavor.vcpus,
+            ephemeral=os_flavor.ephemeral, swap=os_flavor.swap,
+            rxtx_factor=os_flavor.rxtx_factor, is_public=os_flavor.is_public)
+
+
 def create_flavor(nova, flavor_settings):
     """
     Creates and returns and OpenStack flavor object
     :param nova: the Nova client
     :param flavor_settings: the flavor settings
-    :return: the Flavor
+    :return: the SNAPS flavor domain object
     """
-    return nova.flavors.create(name=flavor_settings.name,
-                               flavorid=flavor_settings.flavor_id,
-                               ram=flavor_settings.ram,
-                               vcpus=flavor_settings.vcpus,
-                               disk=flavor_settings.disk,
-                               ephemeral=flavor_settings.ephemeral,
-                               swap=flavor_settings.swap,
-                               rxtx_factor=flavor_settings.rxtx_factor,
-                               is_public=flavor_settings.is_public)
+    os_flavor = nova.flavors.create(
+        name=flavor_settings.name, flavorid=flavor_settings.flavor_id,
+        ram=flavor_settings.ram, vcpus=flavor_settings.vcpus,
+        disk=flavor_settings.disk, ephemeral=flavor_settings.ephemeral,
+        swap=flavor_settings.swap, rxtx_factor=flavor_settings.rxtx_factor,
+        is_public=flavor_settings.is_public)
+    return Flavor(
+        name=os_flavor.name, id=os_flavor.id, ram=os_flavor.ram,
+        disk=os_flavor.disk, vcpus=os_flavor.vcpus,
+        ephemeral=os_flavor.ephemeral, swap=os_flavor.swap,
+        rxtx_factor=os_flavor.rxtx_factor, is_public=os_flavor.is_public)
 
 
 def delete_flavor(nova, flavor):
     """
     Deletes a flavor
     :param nova: the Nova client
-    :param flavor: the OpenStack flavor object
+    :param flavor: the SNAPS flavor domain object
+    """
+    nova.flavors.delete(flavor.id)
+
+
+def set_flavor_keys(nova, flavor, metadata):
+    """
+    Sets metadata on the flavor
+    :param nova: the Nova client
+    :param flavor: the SNAPS flavor domain object
+    :param metadata: the metadata to set
     """
-    nova.flavors.delete(flavor)
+    os_flavor = get_os_flavor(nova, flavor)
+    if os_flavor:
+        os_flavor.set_keys(metadata)
 
 
 def add_security_group(nova, vm, security_group_name):
index 6c28b7e..eb6e65a 100644 (file)
 import logging
 import unittest
 
+from snaps.domain.test.flavor_tests import FlavorDomainObjectTests
 from snaps.domain.test.image_tests import ImageDomainObjectTests
 from snaps.domain.test.stack_tests import StackDomainObjectTests
 from snaps.domain.test.vm_inst_tests import (VmInstDomainObjectTests,
                                              FloatingIpDomainObjectTests)
 from snaps.openstack.tests.conf.os_credentials_tests import (
     ProxySettingsUnitTests, OSCredsUnitTests)
-from snaps.openstack.tests.create_flavor_tests import CreateFlavorTests
+from snaps.openstack.tests.create_flavor_tests import (
+    CreateFlavorTests, FlavorSettingsUnitTests)
 from snaps.openstack.tests.create_image_tests import (
     CreateImageSuccessTests, CreateImageNegativeTests, ImageSettingsUnitTests,
     CreateMultiPartImageTests)
@@ -91,6 +93,10 @@ def add_unit_tests(suite):
         ImageSettingsUnitTests))
     suite.addTest(unittest.TestLoader().loadTestsFromTestCase(
         ImageDomainObjectTests))
+    suite.addTest(unittest.TestLoader().loadTestsFromTestCase(
+        FlavorSettingsUnitTests))
+    suite.addTest(unittest.TestLoader().loadTestsFromTestCase(
+        FlavorDomainObjectTests))
     suite.addTest(unittest.TestLoader().loadTestsFromTestCase(
         KeypairSettingsUnitTests))
     suite.addTest(unittest.TestLoader().loadTestsFromTestCase(