Add Heat Capabilities Actions

This patch adds the Actions for retrieving and updating the capabilites
for a given deployment.

Change-Id: I27b00613afc8d9ab07ac3270221d8dc58b0150dc
This commit is contained in:
Ryan Brady
2016-03-16 11:57:26 -04:00
parent 737f2bbbd2
commit c00e4e28df
3 changed files with 318 additions and 0 deletions

View File

@@ -56,3 +56,5 @@ mistral.actions =
tripleo.upload_default_templates = tripleo_common.actions.templates:UploadTemplatesAction
tripleo.create_container = tripleo_common.actions.plan:CreateContainerAction
tripleo.create_plan = tripleo_common.actions.plan:CreatePlanAction
tripleo.get_capabilities = tripleo_common.actions.heat_capabilities:GetCapabilitiesAction
tripleo.update_capabilities = tripleo_common.actions.heat_capabilities:UpdateCapabilitiesAction

View File

@@ -0,0 +1,140 @@
# Copyright 2106 Red Hat, Inc.
# 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 yaml
from mistral.workflow import utils as mistral_workflow_utils
from tripleo_common.actions import base
from tripleo_common import constants
LOG = logging.getLogger(__name__)
class GetCapabilitiesAction(base.TripleOAction):
"""Gets list of available heat environments
Parses the capabilities_map.yaml file in a given plan and
returns a list of environments
:param container: name of the swift container / plan name
:return: list of environment files in swift container
"""
def __init__(self, container=constants.DEFAULT_CONTAINER_NAME):
super(GetCapabilitiesAction, self).__init__()
self.container = container
def run(self):
environments = {}
try:
map_file = self._get_object_client().get_object(
self.container, 'capabilities-map.yaml')
capabilities = yaml.safe_load(map_file[1])
except Exception:
err_msg = (
"Error parsing capabilities-map.yaml.")
LOG.exception(err_msg)
return mistral_workflow_utils.Result(
None,
err_msg
)
# identify all environments
for topic in capabilities['topics']:
for eg in topic['environment_groups']:
for env in eg['environments']:
environments[env['file']] = {'enabled': False}
try:
mistral_client = self._get_workflow_client()
mistral_env = mistral_client.environments.get(self.container)
except Exception as mistral_err:
err_msg = ("Error retrieving mistral "
"environment. %s" % mistral_err)
LOG.exception(err_msg)
return mistral_workflow_utils.Result(
None,
err_msg
)
selected_envs = [item['path'] for item in
mistral_env.variables['environments']
if 'path' in item]
for item in selected_envs:
if item in environments:
environments[item]['enabled'] = True
else:
environments[item] = {'enabled': False}
return environments
class UpdateCapabilitiesAction(base.TripleOAction):
"""Updates Mistral Environment with selected environments
Takes a list of environment files and depending on the value of the
enabled flag, adds or removes them from the Mistral Environment.
:param environments: list of environments
:param container: name of the swift container / plan name
:return: the updated mistral environment
"""
def __init__(self, environments,
container=constants.DEFAULT_CONTAINER_NAME):
super(UpdateCapabilitiesAction, self).__init__()
self.container = container
self.environments = environments
def run(self):
mistral_client = self._get_workflow_client()
mistral_env = None
try:
mistral_env = mistral_client.environments.get(self.container)
except Exception as mistral_err:
err_msg = (
"Error retrieving mistral "
"environment. %s" % mistral_err)
LOG.exception(err_msg)
return mistral_workflow_utils.Result(
None,
err_msg
)
for k, v in self.environments.items():
if v.get('enabled', False):
mistral_env.variables['environments'].append(
{'path': k}
)
else:
# see if it resides in mistral env and if so, remove it
if {'path': k} in mistral_env.variables['environments']:
mistral_env.variables['environments'].pop({'path': k})
env_kwargs = {
'name': mistral_env.name,
'variables': mistral_env.variables
}
try:
mistral_client.environments.update(**env_kwargs)
except Exception as mistral_err:
err_msg = (
"Error retrieving mistral "
"environment. %s" % mistral_err)
LOG.exception(err_msg)
return mistral_workflow_utils.Result(
None,
err_msg
)
return mistral_env

View File

@@ -0,0 +1,176 @@
# Copyright 2016 Red Hat, Inc.
# 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 mock
from mistral.workflow import utils as mistral_workflow_utils
from tripleo_common.actions import heat_capabilities
from tripleo_common.tests import base
MAPPING_YAML_CONTENTS = """root_template: /path/to/overcloud.yaml
root_environment: /path/to/environment.yaml
topics:
- title: Fake Single Environment Group Configuration
description:
environment_groups:
- title:
description: Random fake string of text
environments:
- file: /path/to/network-isolation.json
title: Default Configuration
description:
- title: Fake Multiple Environment Group Configuration
description:
environment_groups:
- title: Random Fake 1
description: Random fake string of text
environments:
- file: /path/to/ceph-storage-env.yaml
title: Fake1
description: Random fake string of text
- title: Random Fake 2
description:
environments:
- file: /path/to/poc-custom-env.yaml
title: Fake2
description:
"""
class GetCapabilitiesActionTest(base.TestCase):
def setUp(self):
super(GetCapabilitiesActionTest, self).setUp()
self.container_name = 'test-container'
@mock.patch('tripleo_common.actions.base.TripleOAction._get_object_client')
def test_run_yaml_error(self, get_obj_client_mock):
# setup swift
swift = mock.MagicMock()
swift.get_object.return_value = mock.Mock(side_effect=ValueError)
get_obj_client_mock.return_value = swift
action = heat_capabilities.GetCapabilitiesAction(self.container_name)
expected = mistral_workflow_utils.Result(
data=None,
error="Error parsing capabilities-map.yaml.")
self.assertEqual(expected, action.run())
@mock.patch('tripleo_common.actions.base.TripleOAction._get_object_client')
@mock.patch(
'tripleo_common.actions.base.TripleOAction._get_workflow_client')
def test_run_mistral_error(self, get_workflow_client_mock,
get_obj_client_mock):
# setup swift
swift = mock.MagicMock()
swift.get_object.return_value = ({}, MAPPING_YAML_CONTENTS)
get_obj_client_mock.return_value = swift
# setup mistral
mistral = mock.MagicMock()
mistral.environments.get = mock.Mock(
side_effect=Exception)
get_workflow_client_mock.return_value = mistral
action = heat_capabilities.GetCapabilitiesAction(self.container_name)
expected = mistral_workflow_utils.Result(
data=None,
error="Error retrieving mistral environment. ")
self.assertEqual(expected, action.run())
@mock.patch('tripleo_common.actions.base.TripleOAction._get_object_client')
@mock.patch(
'tripleo_common.actions.base.TripleOAction._get_workflow_client')
def test_run(self, get_workflow_client_mock, get_obj_client_mock):
# setup swift
swift = mock.MagicMock()
swift.get_object.return_value = ({}, MAPPING_YAML_CONTENTS)
get_obj_client_mock.return_value = swift
# setup mistral
mistral = mock.MagicMock()
get_workflow_client_mock.return_value = mistral
action = heat_capabilities.GetCapabilitiesAction(self.container_name)
self.assertEqual({
'/path/to/ceph-storage-env.yaml': {'enabled': False},
'/path/to/network-isolation.json': {'enabled': False},
'/path/to/poc-custom-env.yaml': {'enabled': False}},
action.run())
class UpdateCapabilitiesActionTest(base.TestCase):
def setUp(self,):
super(UpdateCapabilitiesActionTest, self).setUp()
self.container_name = 'test-container'
@mock.patch(
'tripleo_common.actions.base.TripleOAction._get_workflow_client')
def test_run(self, get_workflow_client_mock):
# setup mistral
mistral = mock.MagicMock()
mocked_env = mock.MagicMock()
mocked_env.variables = {
'environments': [
{'path': '/path/to/overcloud-default-env.yaml'}
]
}
mistral.environments.get.return_value = mocked_env
get_workflow_client_mock.return_value = mistral
environments = {'/path/to/ceph-storage-env.yaml': {'enabled': False},
'/path/to/network-isolation.json': {'enabled': False},
'/path/to/poc-custom-env.yaml': {'enabled': True}}
action = heat_capabilities.UpdateCapabilitiesAction(
environments, self.container_name)
self.assertEqual({
'environments': [
{'path': '/path/to/overcloud-default-env.yaml'},
{'path': '/path/to/poc-custom-env.yaml'}
]},
action.run().variables)
@mock.patch(
'tripleo_common.actions.base.TripleOAction._get_object_client')
@mock.patch(
'tripleo_common.actions.base.TripleOAction._get_workflow_client')
def test_run_mistral_error(self, get_workflow_client_mock,
get_obj_client_mock):
# setup swift
swift = mock.MagicMock()
swift.get_object.return_value = ({}, MAPPING_YAML_CONTENTS)
get_obj_client_mock.return_value = swift
# setup mistral
mistral = mock.MagicMock()
mistral.environments.get = mock.Mock(
side_effect=Exception)
get_workflow_client_mock.return_value = mistral
action = heat_capabilities.UpdateCapabilitiesAction(
{}, self.container_name)
expected = mistral_workflow_utils.Result(
data=None,
error="Error retrieving mistral environment. ")
self.assertEqual(expected, action.run())