Adds Heat Manger and tests to ApexLake 31/3931/4
authorVincenzo Riccobene <vincenzox.m.riccobene@intel.com>
Thu, 3 Dec 2015 17:47:25 +0000 (17:47 +0000)
committerAna Cunha <ana.cunha@ericsson.com>
Tue, 8 Dec 2015 09:04:18 +0000 (09:04 +0000)
Adds to ApexLake a module that manages the connection with OpenStack Heat to trigger instantiation and termination of stacks.
Also Moves tests and bin directory in the right place.

JIRA: YARDSTICK-35

Change-Id: I0ea407a3129625a238fb4187896c65a2bcd02700
Signed-off-by: Vincenzo Riccobene <vincenzox.m.riccobene@intel.com>
yardstick/vTC/apexlake/bin/run_tests.sh [moved from yardstick/vTC/apexlake/experimental_framework/bin/run_tests.sh with 100% similarity]
yardstick/vTC/apexlake/experimental_framework/heat_manager.py [new file with mode: 0644]
yardstick/vTC/apexlake/tests/generates_template_test.py [moved from yardstick/vTC/apexlake/experimental_framework/tests/generates_template_test.py with 100% similarity]
yardstick/vTC/apexlake/tests/heat_manager_test.py [new file with mode: 0644]

diff --git a/yardstick/vTC/apexlake/experimental_framework/heat_manager.py b/yardstick/vTC/apexlake/experimental_framework/heat_manager.py
new file mode 100644 (file)
index 0000000..41fc585
--- /dev/null
@@ -0,0 +1,103 @@
+# Copyright (c) 2015 Intel Research and Development Ireland Ltd.
+#
+# 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__ = 'vmriccox'
+
+
+from keystoneclient.v2_0 import client as keystoneClient
+from heatclient import client as heatClient
+from heatclient.common import template_utils
+
+from experimental_framework import common
+
+
+class HeatManager:
+
+    def __init__(self, credentials):
+        self.ip_controller = credentials['ip_controller']
+        self.heat_url = credentials['heat_url']
+        self.user = credentials['user']
+        self.password = credentials['password']
+        self.auth_uri = credentials['auth_uri']
+        self.project_id = credentials['project']
+        self.heat = None
+
+        # TODO: verify that init_heat is useless in the constructor
+        # self.init_heat()
+
+    def init_heat(self):
+        keystone = keystoneClient.Client(username=self.user,
+                                         password=self.password,
+                                         tenant_name=self.project_id,
+                                         auth_url=self.auth_uri)
+        auth_token = keystone.auth_token
+        self.heat = heatClient.Client('1', endpoint=self.heat_url,
+                                      token=auth_token)
+
+    def print_stacks(self, name=None):
+        for stack in self.heat.stacks.list():
+            if (name and stack.stack_name == name) or not name:
+                common.LOG.info("Stack Name: " + stack.stack_name)
+                common.LOG.info("Stack Status: " + stack.stack_status)
+
+    def create_stack(self, template_file, stack_name, parameters):
+        self.init_heat()
+        # self.print_stacks()
+        tpl_files, template = \
+            template_utils.get_template_contents(template_file)
+
+        fields = {
+            'template': template,
+            'files': dict(list(tpl_files.items()))
+        }
+        self.heat.stacks.create(stack_name=stack_name, files=fields['files'],
+                                template=template, parameters=parameters)
+        self.print_stacks(stack_name)
+
+    def is_stack_deployed(self, stack_name):
+        self.init_heat()
+        if stack_name in self.heat.stacks.list():
+            return True
+        return False
+
+    def check_stack_status(self, stack_name):
+        """
+        Returns a string representing the status of a stack from Heat
+        perspective
+        :param stack_name: Name of the stack to be checked (type: str)
+        :return: (type: str)
+        """
+        for stack in self.heat.stacks.list():
+            if stack.stack_name == stack_name:
+                return stack.stack_status
+        return 'NOT_FOUND'
+
+    def validate_heat_template(self, heat_template_file):
+        self.init_heat()
+        if not self.heat.stacks.validate(template=open(heat_template_file,
+                                                       'r').read()):
+            raise ValueError('The provided heat template "' +
+                             heat_template_file +
+                             '" is not in the correct format')
+
+    def delete_stack(self, stack_name):
+        self.init_heat()
+        try:
+            for stack in self.heat.stacks.list():
+                if stack.stack_name == stack_name:
+                    self.heat.stacks.delete(stack.id)
+                    return True
+        except:
+            pass
+        return False
diff --git a/yardstick/vTC/apexlake/tests/heat_manager_test.py b/yardstick/vTC/apexlake/tests/heat_manager_test.py
new file mode 100644 (file)
index 0000000..f89835c
--- /dev/null
@@ -0,0 +1,208 @@
+# Copyright (c) 2015 Intel Research and Development Ireland Ltd.
+#
+# 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__ = 'gpetralx'
+
+
+import unittest
+from experimental_framework import heat_manager
+import mock
+
+
+def get_mock_heat(version, *args, **kwargs):
+    return MockHeat()
+
+
+class MockStacks(object):
+    def __init__(self, stacks):
+        self.stacks = stacks
+
+    def list(self):
+        list_name = list()
+        for stack in self.stacks:
+            list_name.append(stack.stack_name)
+        print list_name
+        return self.stacks
+
+    def validate(self, template=None):
+        return False
+
+    def delete(self, id):
+        for stack in self.stacks:
+            if stack.id == id:
+                return self.stacks.remove(stack)
+
+    def create(self, stack_name=None, files=None, template=None,
+               parameters=None):
+        print stack_name
+        self.stacks.append(MockStack(stack_name))
+
+
+class MockStacks_2(object):
+    def __init__(self, stacks):
+        self.stacks = stacks
+
+    def list(self):
+        raise Exception
+
+
+class MockStack(object):
+    def __init__(self, stack_name):
+        self.name = stack_name
+
+    @property
+    def stack_status(self):
+        return self.stack_name + '_status'
+
+    @property
+    def stack_name(self):
+        return self.name
+
+    @property
+    def id(self):
+        return self.name
+
+    def __eq__(self, other):
+        return self.name == other
+
+
+class MockHeat(object):
+    def __init__(self):
+        stacks = [MockStack('stack_1'), MockStack('stack_2')]
+        self.stacks_list = MockStacks(stacks)
+
+    @property
+    def stacks(self):
+        return self.stacks_list
+
+
+class MockHeat_2(MockHeat):
+    def __init__(self):
+        stacks = [MockStack('stack_1'), MockStack('stack_2')]
+        self.stacks_list = MockStacks_2(stacks)
+
+
+class HeatManagerMock(heat_manager.HeatManager):
+    def init_heat(self):
+        if self.heat is None:
+            self.heat = MockHeat()
+
+
+class HeatManagerMock_2(heat_manager.HeatManager):
+    def init_heat(self):
+        if self.heat is None:
+            self.heat = MockHeat_2()
+
+
+class TestHeatManager(unittest.TestCase):
+
+    def setUp(self):
+        credentials = dict()
+        credentials['ip_controller'] = '1.1.1.1'
+        credentials['heat_url'] = 'http://heat_url'
+        credentials['user'] = 'user'
+        credentials['password'] = 'password'
+        credentials['auth_uri'] = 'auth_uri'
+        credentials['project'] = 'project'
+        self.heat_manager = HeatManagerMock(credentials)
+        self.heat_manager.init_heat()
+
+    def tearDown(self):
+        pass
+
+    def test_is_stack_deployed_for_success(self):
+        self.assertTrue(self.heat_manager.is_stack_deployed('stack_1'))
+        self.assertFalse(self.heat_manager.is_stack_deployed('stack_n'))
+
+    def test_check_status_for_success(self):
+        self.assertEqual('stack_1_status',
+                         self.heat_manager.check_stack_status('stack_1'))
+        self.assertEqual('NOT_FOUND',
+                         self.heat_manager.check_stack_status('stack_x'))
+
+    def test_validate_template_for_success(self):
+        template_file = \
+            'tests/data/test_templates/VTC_base_single_vm_wait_1.yaml'
+        with self.assertRaises(ValueError):
+            self.heat_manager.validate_heat_template(template_file)
+
+    def test_delete_stack_for_success(self):
+        self.assertTrue(self.heat_manager.delete_stack('stack_1'))
+        self.assertFalse(self.heat_manager.delete_stack('stack_x'))
+
+    def test_delete_stack_for_success_2(self):
+        self.assertTrue(self.heat_manager.delete_stack('stack_1'))
+
+    @mock.patch('heatclient.common.template_utils.get_template_contents')
+    @mock.patch('heatclient.client.Client')
+    # @mock.patch('heatclient.client.Client', side_effect=DummyHeatClient)
+    def test_create_stack_for_success(self, mock_stack_create,
+                                      mock_get_template_contents):
+        return_value = ({'template': 'template'}, 'template')
+        mock_get_template_contents.return_value = return_value
+        self.heat_manager.create_stack('template', 'stack_n', 'parameters')
+        self.assertTrue(self.heat_manager.is_stack_deployed('stack_n'))
+
+
+class TestHeatManager_2(unittest.TestCase):
+
+    def setUp(self):
+        credentials = dict()
+        credentials['ip_controller'] = '1.1.1.1'
+        credentials['heat_url'] = 'http://heat_url'
+        credentials['user'] = 'user'
+        credentials['password'] = 'password'
+        credentials['auth_uri'] = 'auth_uri'
+        credentials['project'] = 'project'
+        self.heat_manager = HeatManagerMock_2(credentials)
+
+    def tearDown(self):
+        pass
+
+    def test_delete_stack_for_success_2(self):
+        self.assertFalse(self.heat_manager.delete_stack('stack_1'))
+
+
+class KeystoneMock(object):
+    @property
+    def auth_token(self):
+        return 'token'
+
+
+class TestHeatInit(unittest.TestCase):
+    def setUp(self):
+        credentials = dict()
+        credentials['ip_controller'] = '1.1.1.1'
+        credentials['heat_url'] = 'http://heat_url'
+        credentials['user'] = 'user'
+        credentials['password'] = 'password'
+        credentials['auth_uri'] = 'auth_uri'
+        credentials['project'] = 'project'
+        self.heat_manager = heat_manager.HeatManager(credentials)
+
+    def tearDown(self):
+        pass
+
+    @mock.patch('heatclient.client.Client')
+    @mock.patch('keystoneclient.v2_0.client.Client')
+    def test_heat_init_for_sanity(self, keystone_client, heat_client):
+        keystone_client.return_value = KeystoneMock()
+        heat_client.return_value = MockHeat()
+        self.heat_manager.init_heat()
+        keystone_client.assert_called_once_with(username='user',
+                                                tenant_name='project',
+                                                password='password',
+                                                auth_url='auth_uri')
+        heat_client.assert_called_once_with('1',  endpoint='http://heat_url',
+                                            token='token')