Implement stack update as mistral actions
This is the first step to making package updates available as a mistral action. Change-Id: I8a1f2dbffa19c2d8c93684562d2fb16aef6667db Closes-Bug: #1614928
This commit is contained in:
parent
888a5131e4
commit
960bc9ea29
|
@ -69,6 +69,9 @@ mistral.actions =
|
|||
tripleo.deployment.overcloudrc = tripleo_common.actions.deployment:OvercloudRcAction
|
||||
tripleo.heat_capabilities.get = tripleo_common.actions.heat_capabilities:GetCapabilitiesAction
|
||||
tripleo.heat_capabilities.update = tripleo_common.actions.heat_capabilities:UpdateCapabilitiesAction
|
||||
tripleo.package_update.clear_breakpoints = tripleo_common.actions.package_update:ClearBreakpointsAction
|
||||
tripleo.package_update.cancel_stack_update = tripleo_common.actions.package_update:CancelStackUpdateAction
|
||||
tripleo.package_update.update_stack = tripleo_common.actions.package_update:UpdateStackAction
|
||||
tripleo.parameters.get = tripleo_common.actions.parameters:GetParametersAction
|
||||
tripleo.parameters.reset = tripleo_common.actions.parameters:ResetParametersAction
|
||||
tripleo.parameters.update = tripleo_common.actions.parameters:UpdateParametersAction
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
# 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 logging
|
||||
import time
|
||||
|
||||
from heatclient.common import template_utils
|
||||
from heatclient import exc as heat_exc
|
||||
from mistral.workflow import utils as mistral_workflow_utils
|
||||
|
||||
from tripleo_common.actions import base
|
||||
from tripleo_common.actions import templates
|
||||
from tripleo_common import constants
|
||||
from tripleo_common.update import PackageUpdateManager
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ClearBreakpointsAction(base.TripleOAction):
|
||||
def __init__(self, stack_id, refs):
|
||||
super(ClearBreakpointsAction, self).__init__()
|
||||
self.stack_id = stack_id
|
||||
self.refs = refs
|
||||
|
||||
def run(self):
|
||||
heat = self.get_orchestration_client()
|
||||
nova = self.get_compute_client()
|
||||
update_manager = PackageUpdateManager(heat, nova, self.stack_id)
|
||||
update_manager.clear_breakpoints(self.refs)
|
||||
|
||||
|
||||
class CancelStackUpdateAction(base.TripleOAction):
|
||||
def __init__(self, stack_id):
|
||||
super(CancelStackUpdateAction, self).__init__()
|
||||
self.stack_id = stack_id
|
||||
|
||||
def run(self):
|
||||
heat = self.get_orchestration_client()
|
||||
nova = self.get_compute_client()
|
||||
update_manager = PackageUpdateManager(heat, nova, self.stack_id)
|
||||
update_manager.cancel()
|
||||
|
||||
|
||||
class UpdateStackAction(templates.ProcessTemplatesAction):
|
||||
|
||||
def __init__(self, timeout, container=constants.DEFAULT_CONTAINER_NAME):
|
||||
super(UpdateStackAction, self).__init__(container)
|
||||
self.timeout_mins = timeout
|
||||
|
||||
def run(self):
|
||||
# get the stack. Error if doesn't exist
|
||||
heat = self.get_orchestration_client()
|
||||
try:
|
||||
stack = heat.stacks.get(self.container)
|
||||
except heat_exc.HTTPNotFound:
|
||||
msg = "Error retrieving stack: %s" % self.container
|
||||
LOG.exception(msg)
|
||||
return mistral_workflow_utils.Result("", msg)
|
||||
|
||||
parameters = dict()
|
||||
timestamp = int(time.time())
|
||||
parameters['DeployIdentifier'] = timestamp
|
||||
parameters['UpdateIdentifier'] = timestamp
|
||||
parameters['StackAction'] = 'UPDATE'
|
||||
|
||||
wc = self.get_workflow_client()
|
||||
try:
|
||||
wf_env = wc.environments.get(self.container)
|
||||
except Exception:
|
||||
msg = "Error retrieving mistral environment: %s" % self.container
|
||||
LOG.exception(msg)
|
||||
return mistral_workflow_utils.Result("", msg)
|
||||
|
||||
if 'parameter_defaults' not in wf_env.variables:
|
||||
wf_env.variables['parameter_defaults'] = {}
|
||||
wf_env.variables['parameter_defaults'].update(parameters)
|
||||
env_kwargs = {
|
||||
'name': wf_env.name,
|
||||
'variables': wf_env.variables,
|
||||
}
|
||||
template_utils.deep_update(wf_env.variables, {
|
||||
'resource_registry': {
|
||||
'resources': {
|
||||
'*': {
|
||||
'*': {
|
||||
constants.UPDATE_RESOURCE_NAME: {
|
||||
'hooks': 'pre-update'}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
# store params changes back to db before call to process templates
|
||||
wc.environments.update(**env_kwargs)
|
||||
|
||||
# process all plan files and create or update a stack
|
||||
processed_data = super(UpdateStackAction, self).run()
|
||||
|
||||
# If we receive a 'Result' instance it is because the parent action
|
||||
# had an error.
|
||||
if isinstance(processed_data, mistral_workflow_utils.Result):
|
||||
return processed_data
|
||||
|
||||
stack_args = processed_data.copy()
|
||||
stack_args['timeout_mins'] = self.timeout_mins
|
||||
stack_args['existing'] = 'true'
|
||||
|
||||
LOG.info("Performing Heat stack update")
|
||||
LOG.info('updating stack: %s', stack.stack_name)
|
||||
return heat.stacks.update(stack.id, **stack_args)
|
|
@ -0,0 +1,143 @@
|
|||
# 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 tripleo_common.actions import package_update
|
||||
from tripleo_common.tests import base
|
||||
|
||||
|
||||
class ClearBreakpointsActionTest(base.TestCase):
|
||||
|
||||
def setUp(self,):
|
||||
super(ClearBreakpointsActionTest, self).setUp()
|
||||
self.stack_id = 'stack_id'
|
||||
self.refs = 'refs'
|
||||
|
||||
@mock.patch('tripleo_common.actions.package_update.PackageUpdateManager')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_orchestration_client')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_compute_client')
|
||||
def test_run(self, mock_compute_client,
|
||||
mock_orchestration_client,
|
||||
mock_update_manager):
|
||||
action = package_update.ClearBreakpointsAction(self.stack_id,
|
||||
self.refs)
|
||||
result = action.run()
|
||||
self.assertEqual(None, result)
|
||||
mock_compute_client.assert_called_once()
|
||||
mock_orchestration_client.assert_called_once()
|
||||
mock_update_manager().clear_breakpoints.assert_called_once_with(
|
||||
self.refs)
|
||||
|
||||
|
||||
class CancelStackUpdateActionTest(base.TestCase):
|
||||
|
||||
def setUp(self,):
|
||||
super(CancelStackUpdateActionTest, self).setUp()
|
||||
self.stack_id = 'stack_id'
|
||||
|
||||
@mock.patch('tripleo_common.actions.package_update.PackageUpdateManager')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_orchestration_client')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_compute_client')
|
||||
def test_run(self, mock_compute_client,
|
||||
mock_orchestration_client,
|
||||
mock_update_manager):
|
||||
action = package_update.CancelStackUpdateAction(self.stack_id)
|
||||
result = action.run()
|
||||
self.assertEqual(None, result)
|
||||
mock_compute_client.assert_called_once()
|
||||
mock_orchestration_client.assert_called_once()
|
||||
mock_update_manager().cancel.assert_called_once()
|
||||
|
||||
|
||||
class UpdateStackActionTest(base.TestCase):
|
||||
|
||||
def setUp(self,):
|
||||
super(UpdateStackActionTest, self).setUp()
|
||||
self.timeout = 1
|
||||
self.container = 'container'
|
||||
|
||||
@mock.patch('mistral.context.ctx')
|
||||
@mock.patch('tripleo_common.actions.templates.ProcessTemplatesAction.run')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_workflow_client')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_orchestration_client')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_compute_client')
|
||||
@mock.patch('tripleo_common.actions.package_update.time')
|
||||
@mock.patch('heatclient.common.template_utils.get_template_contents')
|
||||
def test_run(self, mock_template_contents,
|
||||
mock_time,
|
||||
mock_compute_client,
|
||||
mock_orchestration_client,
|
||||
mock_workflow_client,
|
||||
mock_templates_run,
|
||||
mock_ctx,):
|
||||
mock_ctx.return_value = mock.MagicMock()
|
||||
heat = mock.MagicMock()
|
||||
heat.stacks.get.return_value = mock.MagicMock(
|
||||
stack_name='stack', id='stack_id')
|
||||
mock_orchestration_client.return_value = heat
|
||||
|
||||
mock_template_contents.return_value = ({}, {
|
||||
'heat_template_version': '2016-04-30'
|
||||
})
|
||||
mock_mistral = mock.MagicMock()
|
||||
mock_env = mock.MagicMock()
|
||||
mock_env.variables = {
|
||||
'temp_environment': 'temp_environment',
|
||||
'template': 'template',
|
||||
'environments': [{u'path': u'environments/test.yaml'}],
|
||||
'parameter_defaults': {'random_data': 'a_value'},
|
||||
}
|
||||
mock_mistral.environments.get.return_value = mock_env
|
||||
mock_workflow_client.return_value = mock_mistral
|
||||
|
||||
# freeze time at datetime.datetime(2016, 9, 8, 16, 24, 24)
|
||||
mock_time.time.return_value = 1473366264
|
||||
|
||||
mock_templates_run.return_value = {
|
||||
'StackAction': 'UPDATE',
|
||||
'DeployIdentifier': 1473366264,
|
||||
'UpdateIdentifier': 1473366264
|
||||
}
|
||||
|
||||
action = package_update.UpdateStackAction(self.timeout,
|
||||
container=self.container)
|
||||
action.run()
|
||||
|
||||
# verify parameters are as expected
|
||||
expected_defaults = {
|
||||
'StackAction': 'UPDATE',
|
||||
'DeployIdentifier': 1473366264,
|
||||
'UpdateIdentifier': 1473366264,
|
||||
'random_data': 'a_value',
|
||||
}
|
||||
self.assertEqual(
|
||||
expected_defaults, mock_env.variables['parameter_defaults'])
|
||||
|
||||
print(heat.mock_calls)
|
||||
heat.stacks.update.assert_called_once_with(
|
||||
'stack_id',
|
||||
StackAction='UPDATE',
|
||||
DeployIdentifier=1473366264,
|
||||
UpdateIdentifier=1473366264,
|
||||
existing='true',
|
||||
timeout_mins=1
|
||||
)
|
|
@ -0,0 +1,103 @@
|
|||
---
|
||||
version: '2.0'
|
||||
name: tripleo.package_update.v1
|
||||
description: TripleO update workflows
|
||||
|
||||
workflows:
|
||||
|
||||
# Updates a workload cloud stack
|
||||
package_update_plan:
|
||||
description: Take a container and perform a package update with possible breakpoints
|
||||
|
||||
input:
|
||||
- container
|
||||
- timeout: 240
|
||||
- queue_name: tripleo
|
||||
|
||||
tasks:
|
||||
update:
|
||||
action: tripleo.package_update.update_stack container=<% $.container %> timeout=<% $.timeout %>
|
||||
on-success: send_message
|
||||
on-error: set_update_failed
|
||||
|
||||
set_update_failed:
|
||||
on-success: send_message
|
||||
publish:
|
||||
status: FAILED
|
||||
message: <% task(update).result %>
|
||||
|
||||
send_message:
|
||||
action: zaqar.queue_post
|
||||
input:
|
||||
queue_name: <% $.queue_name %>
|
||||
messages:
|
||||
body:
|
||||
type: tripleo.package_update.v1.package_update_plan
|
||||
payload:
|
||||
status: <% $.get('status', 'SUCCESS') %>
|
||||
message: <% $.get('message', '') %>
|
||||
execution: <% execution() %>
|
||||
|
||||
# Clear an update breakpoint
|
||||
clear_breakpoints:
|
||||
description: Clear any pending breakpoints and continue with update
|
||||
|
||||
input:
|
||||
- stack_id
|
||||
- refs
|
||||
- queue_name: tripleo
|
||||
|
||||
tasks:
|
||||
clear:
|
||||
action: tripleo.package_update.clear_breakpoints stack_id=<% $.stack_id %> refs=<% $.refs %>
|
||||
on-success: send_message
|
||||
on-error: set_clear_breakpoints_failed
|
||||
|
||||
set_clear_breakpoints_failed:
|
||||
on-success: send_message
|
||||
publish:
|
||||
status: FAILED
|
||||
message: <% task(clear).result %>
|
||||
|
||||
send_message:
|
||||
action: zaqar.queue_post
|
||||
input:
|
||||
queue_name: <% $.queue_name %>
|
||||
messages:
|
||||
body:
|
||||
type: tripleo.package_update.v1.clear_breakpoints
|
||||
payload:
|
||||
status: <% $.get('status', 'SUCCESS') %>
|
||||
message: <% $.get('message', '') %>
|
||||
execution: <% execution() %>
|
||||
|
||||
cancel_stack_update:
|
||||
description: Cancel a currently running stack update
|
||||
|
||||
input:
|
||||
- stack_id
|
||||
- queue_name: tripleo
|
||||
|
||||
tasks:
|
||||
cancel_stack_update:
|
||||
action: tripleo.package_update.cancel_stack_update stack_id=<% $.stack_id %>
|
||||
on-success: send_message
|
||||
on-error: set_cancel_stack_update_failed
|
||||
|
||||
set_cancel_stack_update_failed:
|
||||
on-success: send_message
|
||||
publish:
|
||||
status: FAILED
|
||||
message: <% task(cancel_stack_update).result %>
|
||||
|
||||
send_message:
|
||||
action: zaqar.queue_post
|
||||
input:
|
||||
queue_name: <% $.queue_name
|
||||
messages:
|
||||
body:
|
||||
type: tripleo.package_update.v1.cancel_stack_update
|
||||
payload:
|
||||
status: <% $.get('status', 'SUCCESS') %>
|
||||
message: <% $.get('message', '') %>
|
||||
execution: <% execution() %>
|
Loading…
Reference in New Issue