Migrate overcloud update to a mistral workflow
This moves the package update to using a mistral workflow. Change-Id: I5176746ca4843202a385206289be66f7e6450f48 Depends-On: I8a1f2dbffa19c2d8c93684562d2fb16aef6667db Closes-Bug: #1614928
This commit is contained in:
parent
076df58f30
commit
7a31915c49
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
fixes:
|
||||||
|
- Fixes `bug 1614928
|
||||||
|
<https://bugs.launchpad.net/tripleo/+bug/1614928>`__ Moves the package
|
||||||
|
update command to use a workflow.
|
@ -79,6 +79,8 @@ openstack.tripleoclient.v1 =
|
|||||||
overcloud_profiles_match = tripleoclient.v1.overcloud_profiles:MatchProfiles
|
overcloud_profiles_match = tripleoclient.v1.overcloud_profiles:MatchProfiles
|
||||||
overcloud_profiles_list = tripleoclient.v1.overcloud_profiles:ListProfiles
|
overcloud_profiles_list = tripleoclient.v1.overcloud_profiles:ListProfiles
|
||||||
overcloud_raid_create = tripleoclient.v1.overcloud_raid:CreateRAID
|
overcloud_raid_create = tripleoclient.v1.overcloud_raid:CreateRAID
|
||||||
|
overcloud_update_abort = tripleoclient.v1.overcloud_update:AbortUpdateOvercloud
|
||||||
|
overcloud_update_clear_breakpoints = tripleoclient.v1.overcloud_update:ClearBreakpointsOvercloud
|
||||||
overcloud_update_stack = tripleoclient.v1.overcloud_update:UpdateOvercloud
|
overcloud_update_stack = tripleoclient.v1.overcloud_update:UpdateOvercloud
|
||||||
overcloud_execute = tripleoclient.v1.overcloud_execute:RemoteExecute
|
overcloud_execute = tripleoclient.v1.overcloud_execute:RemoteExecute
|
||||||
undercloud_install = tripleoclient.v1.undercloud:InstallUndercloud
|
undercloud_install = tripleoclient.v1.undercloud:InstallUndercloud
|
||||||
|
@ -26,14 +26,23 @@ class TestOvercloudUpdate(fakes.TestOvercloudUpdate):
|
|||||||
super(TestOvercloudUpdate, self).setUp()
|
super(TestOvercloudUpdate, self).setUp()
|
||||||
|
|
||||||
# Get the command object to test
|
# Get the command object to test
|
||||||
self.cmd = overcloud_update.UpdateOvercloud(self.app, None)
|
app_args = mock.Mock()
|
||||||
|
app_args.verbose_level = 1
|
||||||
|
self.cmd = overcloud_update.UpdateOvercloud(self.app, app_args)
|
||||||
|
|
||||||
@mock.patch('tripleoclient.workflows.templates.process_templates',
|
@mock.patch('tripleoclient.utils.get_stack',
|
||||||
autospec=True)
|
autospec=True)
|
||||||
@mock.patch('tripleo_common.update.PackageUpdateManager')
|
@mock.patch('tripleoclient.v1.overcloud_update.UpdateOvercloud.log',
|
||||||
def test_update_out(self, update_manager, mock_process_templates):
|
autospec=True)
|
||||||
update_manager.return_value.get_status.return_value = (
|
@mock.patch('tripleoclient.workflows.package_update.update_and_wait',
|
||||||
'COMPLETE', {})
|
autospec=True)
|
||||||
|
def test_update_out(self, mock_update_wait, mock_logger, mock_get_stack):
|
||||||
|
mock_update_wait.return_value = 'COMPLETE'
|
||||||
|
mock_stack = mock.Mock()
|
||||||
|
mock_stack.stack_name = 'mystack'
|
||||||
|
mock_get_stack.return_value = mock_stack
|
||||||
|
# mock_logger.return_value = mock.Mock()
|
||||||
|
|
||||||
argslist = ['overcloud', '-i', '--templates']
|
argslist = ['overcloud', '-i', '--templates']
|
||||||
verifylist = [
|
verifylist = [
|
||||||
('stack', 'overcloud'),
|
('stack', 'overcloud'),
|
||||||
@ -41,24 +50,17 @@ class TestOvercloudUpdate(fakes.TestOvercloudUpdate):
|
|||||||
('templates', '/usr/share/openstack-tripleo-heat-templates/')
|
('templates', '/usr/share/openstack-tripleo-heat-templates/')
|
||||||
]
|
]
|
||||||
|
|
||||||
mock_process_templates.return_value = {
|
|
||||||
'stack_name': 'mystack',
|
|
||||||
'environment': {},
|
|
||||||
'files': {},
|
|
||||||
'templates': 'template body',
|
|
||||||
}
|
|
||||||
parsed_args = self.check_parser(self.cmd, argslist, verifylist)
|
parsed_args = self.check_parser(self.cmd, argslist, verifylist)
|
||||||
self.cmd.take_action(parsed_args)
|
self.cmd.take_action(parsed_args)
|
||||||
update_manager.get_status.called_once()
|
mock_update_wait.assert_called_once_with(
|
||||||
update_manager.update.called_once()
|
mock_logger,
|
||||||
update_manager.do_interactive_update.called_once()
|
self.app.client_manager,
|
||||||
|
mock_stack, 'mystack', 1, 0)
|
||||||
|
|
||||||
@mock.patch('tripleoclient.workflows.templates.process_templates',
|
@mock.patch('tripleoclient.workflows.package_update.update_and_wait',
|
||||||
autospec=True)
|
autospec=True)
|
||||||
@mock.patch('tripleo_common.update.PackageUpdateManager')
|
def test_update_failed(self, mock_update_wait):
|
||||||
def test_update_failed(self, update_manager, mock_process_templates):
|
mock_update_wait.return_value = 'FAILED'
|
||||||
update_manager.return_value.get_status.return_value = (
|
|
||||||
'FAILED', {})
|
|
||||||
argslist = ['overcloud', '-i', '--templates']
|
argslist = ['overcloud', '-i', '--templates']
|
||||||
verifylist = [
|
verifylist = [
|
||||||
('stack', 'overcloud'),
|
('stack', 'overcloud'),
|
||||||
@ -66,12 +68,6 @@ class TestOvercloudUpdate(fakes.TestOvercloudUpdate):
|
|||||||
('templates', '/usr/share/openstack-tripleo-heat-templates/')
|
('templates', '/usr/share/openstack-tripleo-heat-templates/')
|
||||||
]
|
]
|
||||||
parsed_args = self.check_parser(self.cmd, argslist, verifylist)
|
parsed_args = self.check_parser(self.cmd, argslist, verifylist)
|
||||||
mock_process_templates.return_value = {
|
|
||||||
'stack_name': 'mystack',
|
|
||||||
'environment': {},
|
|
||||||
'files': {},
|
|
||||||
'templates': 'template body',
|
|
||||||
}
|
|
||||||
|
|
||||||
self.assertRaises(exceptions.DeploymentError,
|
self.assertRaises(exceptions.DeploymentError,
|
||||||
self.cmd.take_action, parsed_args)
|
self.cmd.take_action, parsed_args)
|
||||||
|
@ -14,15 +14,16 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
import uuid
|
||||||
|
|
||||||
from osc_lib.command import command
|
from osc_lib.command import command
|
||||||
from osc_lib.i18n import _
|
from osc_lib.i18n import _
|
||||||
from osc_lib import utils
|
from osc_lib import utils
|
||||||
from tripleo_common import update
|
|
||||||
|
|
||||||
from tripleoclient import constants
|
from tripleoclient import constants
|
||||||
from tripleoclient import exceptions
|
from tripleoclient import exceptions
|
||||||
from tripleoclient.workflows import templates
|
from tripleoclient import utils as oooutils
|
||||||
|
from tripleoclient.workflows import package_update
|
||||||
|
|
||||||
|
|
||||||
class UpdateOvercloud(command.Command):
|
class UpdateOvercloud(command.Command):
|
||||||
@ -47,7 +48,9 @@ class UpdateOvercloud(command.Command):
|
|||||||
parser.add_argument('-i', '--interactive', dest='interactive',
|
parser.add_argument('-i', '--interactive', dest='interactive',
|
||||||
action='store_true')
|
action='store_true')
|
||||||
parser.add_argument('-a', '--abort', dest='abort_update',
|
parser.add_argument('-a', '--abort', dest='abort_update',
|
||||||
action='store_true')
|
action='store_true',
|
||||||
|
help=_('DEPRECATED. Please use the command'
|
||||||
|
'"openstack overcloud update abort"'))
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'-e', '--environment-file', metavar='<HEAT ENVIRONMENT FILE>',
|
'-e', '--environment-file', metavar='<HEAT ENVIRONMENT FILE>',
|
||||||
action='append', dest='environment_files',
|
action='append', dest='environment_files',
|
||||||
@ -60,7 +63,9 @@ class UpdateOvercloud(command.Command):
|
|||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--answers-file',
|
'--answers-file',
|
||||||
help=_('Path to a YAML file with arguments and parameters.')
|
help=_('Path to a YAML file with arguments and parameters. '
|
||||||
|
'DEPRECATED. Not necessary when used with a plan. Will '
|
||||||
|
'be silently ignored, and removed in the "P" release.')
|
||||||
)
|
)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
@ -68,32 +73,75 @@ class UpdateOvercloud(command.Command):
|
|||||||
self.log.debug("take_action(%s)" % parsed_args)
|
self.log.debug("take_action(%s)" % parsed_args)
|
||||||
clients = self.app.client_manager
|
clients = self.app.client_manager
|
||||||
|
|
||||||
workflow = clients.workflow_engine
|
stack = oooutils.get_stack(clients.orchestration,
|
||||||
stack_fields = templates.process_templates(
|
parsed_args.stack)
|
||||||
workflow, container=parsed_args.stack)
|
|
||||||
|
|
||||||
update_manager = update.PackageUpdateManager(
|
|
||||||
heatclient=clients.orchestration,
|
|
||||||
novaclient=clients.compute,
|
|
||||||
stack_id=parsed_args.stack,
|
|
||||||
stack_fields=stack_fields)
|
|
||||||
if parsed_args.abort_update:
|
|
||||||
print("cancelling package update on stack {0}".format(
|
|
||||||
parsed_args.stack))
|
|
||||||
update_manager.cancel()
|
|
||||||
else:
|
|
||||||
status, resources = update_manager.get_status()
|
|
||||||
if status not in ['IN_PROGRESS', 'WAITING']:
|
|
||||||
print("starting package update on stack {0}".format(
|
|
||||||
parsed_args.stack))
|
|
||||||
update_manager.update()
|
|
||||||
|
|
||||||
|
stack_name = stack.stack_name
|
||||||
if parsed_args.interactive:
|
if parsed_args.interactive:
|
||||||
update_manager.do_interactive_update()
|
timeout = 0
|
||||||
status, _ = update_manager.get_status()
|
|
||||||
|
status = package_update.update_and_wait(
|
||||||
|
self.log, clients, stack, stack_name,
|
||||||
|
self.app_args.verbose_level, timeout)
|
||||||
if status not in ['COMPLETE']:
|
if status not in ['COMPLETE']:
|
||||||
raise exceptions.DeploymentError("Stack update failed.")
|
raise exceptions.DeploymentError("Stack update failed.")
|
||||||
else:
|
else:
|
||||||
status, _ = update_manager.get_status()
|
status = package_update.update(clients, container=stack_name,
|
||||||
print("stack {0} status: {1}".format(parsed_args.stack,
|
queue_name=str(uuid.uuid4()))
|
||||||
status))
|
print("stack {0} status: {1}".format(parsed_args.stack, status))
|
||||||
|
|
||||||
|
|
||||||
|
class AbortUpdateOvercloud(command.Command):
|
||||||
|
"""Aborts a package update on overcloud nodes"""
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__ + ".AbortUpdateOvercloud")
|
||||||
|
|
||||||
|
def get_parser(self, prog_name):
|
||||||
|
parser = super(AbortUpdateOvercloud, self).get_parser(prog_name)
|
||||||
|
parser.add_argument('stack', nargs='?',
|
||||||
|
help=_('Name or ID of heat stack to abort a '
|
||||||
|
'running update '
|
||||||
|
'(default=Env: OVERCLOUD_STACK_NAME)'),
|
||||||
|
default=utils.env('OVERCLOUD_STACK_NAME'))
|
||||||
|
return parser
|
||||||
|
|
||||||
|
def take_action(self, parsed_args):
|
||||||
|
self.log.debug("take_action(%s)" % parsed_args)
|
||||||
|
clients = self.app.client_manager
|
||||||
|
|
||||||
|
heat = clients.orchestration
|
||||||
|
|
||||||
|
stack = oooutils.get_stack(heat, parsed_args.stack)
|
||||||
|
|
||||||
|
package_update.abort_update(clients, stack_id=stack.id)
|
||||||
|
|
||||||
|
|
||||||
|
class ClearBreakpointsOvercloud(command.Command):
|
||||||
|
"""Clears a set of breakpoints on a currently updating overcloud"""
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__ + ".ClearBreakpointsOvercloud")
|
||||||
|
|
||||||
|
def get_parser(self, prog_name):
|
||||||
|
parser = super(ClearBreakpointsOvercloud, self).get_parser(prog_name)
|
||||||
|
parser.add_argument('stack', nargs='?',
|
||||||
|
help=_('Name or ID of heat stack to clear a '
|
||||||
|
'breakpoint or set of breakpoints '
|
||||||
|
'(default=Env: OVERCLOUD_STACK_NAME)'),
|
||||||
|
default=utils.env('OVERCLOUD_STACK_NAME'))
|
||||||
|
parser.add_argument('--ref',
|
||||||
|
action='append',
|
||||||
|
dest='refs',
|
||||||
|
help=_('Breakpoint to clear'))
|
||||||
|
|
||||||
|
return parser
|
||||||
|
|
||||||
|
def take_action(self, parsed_args):
|
||||||
|
self.log.debug("take_action(%s)" % parsed_args)
|
||||||
|
clients = self.app.client_manager
|
||||||
|
|
||||||
|
heat = clients.orchestration
|
||||||
|
|
||||||
|
stack = oooutils.get_stack(heat, parsed_args.stack)
|
||||||
|
|
||||||
|
package_update.clear_breakpoints(clients, stack_id=stack.id,
|
||||||
|
refs=parsed_args.refs)
|
||||||
|
95
tripleoclient/workflows/package_update.py
Normal file
95
tripleoclient/workflows/package_update.py
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
# 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.
|
||||||
|
from __future__ import print_function
|
||||||
|
|
||||||
|
import pprint
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
from tripleo_common import update as update_common
|
||||||
|
|
||||||
|
from tripleoclient.workflows import base
|
||||||
|
|
||||||
|
|
||||||
|
def update(clients, **workflow_input):
|
||||||
|
workflow_client = clients.workflow_engine
|
||||||
|
tripleoclients = clients.tripleoclient
|
||||||
|
queue_name = workflow_input['queue_name']
|
||||||
|
|
||||||
|
execution = base.start_workflow(
|
||||||
|
workflow_client,
|
||||||
|
'tripleo.update.v1.update_plan',
|
||||||
|
workflow_input=workflow_input
|
||||||
|
)
|
||||||
|
|
||||||
|
with tripleoclients.messaging_websocket(queue_name) as ws:
|
||||||
|
message = ws.wait_for_message(execution.id)
|
||||||
|
assert message['status'] == "SUCCESS", pprint.pformat(message)
|
||||||
|
|
||||||
|
|
||||||
|
def update_and_wait(log, clients, stack, plan_name, verbose_level,
|
||||||
|
timeout=None):
|
||||||
|
"""Start the update and wait for it to give breakpoints or finish"""
|
||||||
|
|
||||||
|
log.info("Performing Heat stack update")
|
||||||
|
queue_name = str(uuid.uuid4())
|
||||||
|
|
||||||
|
workflow_input = {
|
||||||
|
"container": plan_name,
|
||||||
|
"queue_name": queue_name,
|
||||||
|
}
|
||||||
|
|
||||||
|
if timeout is not None:
|
||||||
|
workflow_input['timeout'] = timeout
|
||||||
|
|
||||||
|
update(clients, **workflow_input)
|
||||||
|
|
||||||
|
update_manager = update_common.PackageUpdateManager(
|
||||||
|
heatclient=clients.orchestration,
|
||||||
|
novaclient=clients.compute,
|
||||||
|
stack_id=stack)
|
||||||
|
|
||||||
|
update_manager.do_interactive_update()
|
||||||
|
|
||||||
|
|
||||||
|
def abort_update(clients, **workflow_input):
|
||||||
|
|
||||||
|
workflow_client = clients.workflow_engine
|
||||||
|
tripleoclients = clients.tripleoclient
|
||||||
|
workflow_input['queue_name'] = str(uuid.uuid4())
|
||||||
|
queue_name = workflow_input['queue_name']
|
||||||
|
|
||||||
|
execution = base.start_workflow(
|
||||||
|
workflow_client,
|
||||||
|
'tripleo.update.v1.cancel_stack_update',
|
||||||
|
workflow_input=workflow_input
|
||||||
|
)
|
||||||
|
|
||||||
|
with tripleoclients.messaging_websocket(queue_name) as ws:
|
||||||
|
message = ws.wait_for_message(execution.id)
|
||||||
|
assert message['status'] == "SUCCESS", pprint.pformat(message)
|
||||||
|
|
||||||
|
|
||||||
|
def clear_breakpoints(clients, **workflow_input):
|
||||||
|
workflow_client = clients.workflow_engine
|
||||||
|
tripleoclients = clients.tripleoclient
|
||||||
|
workflow_input['queue_name'] = str(uuid.uuid4())
|
||||||
|
queue_name = workflow_input['queue_name']
|
||||||
|
|
||||||
|
execution = base.start_workflow(
|
||||||
|
workflow_client,
|
||||||
|
'tripleo.update.v1.clear_breakpoints',
|
||||||
|
workflow_input=workflow_input
|
||||||
|
)
|
||||||
|
|
||||||
|
with tripleoclients.messaging_websocket(queue_name) as ws:
|
||||||
|
message = ws.wait_for_message(execution.id)
|
||||||
|
assert message['status'] == "SUCCESS", pprint.pformat(message)
|
Loading…
Reference in New Issue
Block a user