Add `openstack overcloud plan deploy`

This command will start an overcloud deploy of the plan with
Mistral and wait for it to finish.

Closes-Bug: #1616015
Change-Id: Ie990bfb29dd245a1c83891495aa3f4ec7a0051e8
This commit is contained in:
Dougal Matthews 2016-08-25 08:47:16 +01:00
parent 0d0b50806b
commit d1866edc83
5 changed files with 124 additions and 34 deletions

View File

@ -74,6 +74,7 @@ openstack.tripleoclient.v1 =
overcloud_parameters_set = tripleoclient.v1.overcloud_parameters:SetParameters
overcloud_plan_create = tripleoclient.v1.overcloud_plan:CreatePlan
overcloud_plan_delete = tripleoclient.v1.overcloud_plan:DeletePlan
overcloud_plan_deploy = tripleoclient.v1.overcloud_plan:DeployPlan
overcloud_plan_list = tripleoclient.v1.overcloud_plan:ListPlans
overcloud_profiles_match = tripleoclient.v1.overcloud_profiles:MatchProfiles
overcloud_profiles_list = tripleoclient.v1.overcloud_profiles:ListProfiles

View File

@ -225,3 +225,59 @@ class TestOvercloudCreatePlan(utils.TestCommand):
'container': 'overcast',
'queue_name': 'UUID4'
})
class TestOvercloudDeployPlan(utils.TestCommand):
def setUp(self):
super(TestOvercloudDeployPlan, self).setUp()
app_args = mock.Mock()
app_args.verbose_level = 1
self.cmd = overcloud_plan.DeployPlan(self.app, app_args)
self.workflow = self.app.client_manager.workflow_engine = mock.Mock()
self.orch = self.app.client_manager.orchestration = mock.Mock()
self.websocket = mock.Mock()
self.websocket.__enter__ = lambda s: self.websocket
self.websocket.__exit__ = lambda s, *exc: None
self.tripleoclient = mock.Mock()
self.tripleoclient.messaging_websocket.return_value = self.websocket
self.app.client_manager.tripleoclient = self.tripleoclient
# Mock UUID4 generation for every test
uuid4_patcher = mock.patch('uuid.uuid4', return_value="UUID4")
self.mock_uuid4 = uuid4_patcher.start()
self.addCleanup(self.mock_uuid4.stop)
@mock.patch('tripleoclient.utils.wait_for_stack_ready', autospec=True)
def test_overcloud_deploy_plan(self, mock_for_stack_ready):
# Setup
arglist = ['overcast']
verifylist = [
('name', 'overcast')
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
# No existing stack, this is a new deploy.
self.orch.stacks.get.return_value = None
self.websocket.wait_for_message.return_value = {
'status': 'SUCCESS'
}
mock_for_stack_ready.return_value = True
# Run
self.cmd.take_action(parsed_args)
# Verify
self.workflow.executions.create.assert_called_once_with(
'tripleo.deployment.v1.deploy_plan',
workflow_input={
'container': 'overcast',
'queue_name': 'UUID4'
}
)

View File

@ -28,7 +28,6 @@ import time
import uuid
import yaml
from heatclient.common import event_utils
from heatclient.common import template_utils
from keystoneclient import exceptions as kscexc
from os_cloud_config import keystone
@ -286,39 +285,8 @@ class DeployOvercloud(command.Command):
stack_name, objectclient, env, moved_files, tht_root,
workflow_client)
self._start_mistral_deploy(clients, stack, stack_name)
def _start_mistral_deploy(self, clients, stack, plan_name):
deployment.deploy(clients, container=plan_name,
queue_name=str(uuid.uuid4()))
orchestration_client = clients.orchestration
if stack is None:
self.log.info("Performing Heat stack create")
action = 'CREATE'
marker = None
else:
self.log.info("Performing Heat stack update")
# Make sure existing parameters for stack are reused
# Find the last top-level event to use for the first marker
events = event_utils.get_events(orchestration_client,
stack_id=plan_name,
event_args={'sort_dir': 'desc',
'limit': 1})
marker = events[0].id if events else None
action = 'UPDATE'
time.sleep(10)
verbose_events = self.app_args.verbose_level > 0
create_result = utils.wait_for_stack_ready(
orchestration_client, plan_name, marker, action, verbose_events)
if not create_result:
if stack is None:
raise exceptions.DeploymentError("Heat Stack create failed.")
else:
raise exceptions.DeploymentError("Heat Stack update failed.")
deployment.deploy_and_wait(self.log, clients, stack, stack_name,
self.app_args.verbose_level)
def _load_environment_directories(self, directories):
if os.environ.get('TRIPLEO_ENVIRONMENT_DIRECTORY'):
@ -1076,6 +1044,7 @@ class DeployOvercloud(command.Command):
orchestration_client = clients.orchestration
stack = utils.get_stack(orchestration_client, parsed_args.stack)
parameters = self._update_parameters(
parsed_args, clients.network, stack)

View File

@ -17,6 +17,8 @@ import uuid
from osc_lib.command import command
from osc_lib.i18n import _
from tripleoclient import utils
from tripleoclient.workflows import deployment
from tripleoclient.workflows import plan_management
@ -111,3 +113,25 @@ class CreatePlan(command.Command):
else:
plan_management.create_default_plan(
clients, container=name, queue_name=str(uuid.uuid4()))
class DeployPlan(command.Command):
"""Deploy a deployment plan"""
log = logging.getLogger(__name__ + ".DeployPlan")
def get_parser(self, prog_name):
parser = super(DeployPlan, self).get_parser(prog_name)
parser.add_argument('name', help=_('The name of the plan to deploy.'))
return parser
def take_action(self, parsed_args):
self.log.debug("take_action(%s)" % parsed_args)
clients = self.app.client_manager
orchestration_client = clients.orchestration
stack = utils.get_stack(orchestration_client, parsed_args.name)
print("Starting to deploy plan: {}".format(parsed_args.name))
deployment.deploy_and_wait(self.log, clients, stack, parsed_args.name,
self.app_args.verbose_level)

View File

@ -12,6 +12,13 @@
from __future__ import print_function
import pprint
import time
import uuid
from heatclient.common import event_utils
from tripleoclient import exceptions
from tripleoclient import utils
def deploy(clients, **workflow_input):
@ -28,3 +35,36 @@ def deploy(clients, **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 deploy_and_wait(log, clients, stack, plan_name, verbose_level):
"""Start the deploy and wait for it to finish"""
deploy(clients, container=plan_name, queue_name=str(uuid.uuid4()))
orchestration_client = clients.orchestration
if stack is None:
log.info("Performing Heat stack create")
action = 'CREATE'
marker = None
else:
log.info("Performing Heat stack update")
# Make sure existing parameters for stack are reused
# Find the last top-level event to use for the first marker
events = event_utils.get_events(orchestration_client,
stack_id=plan_name,
event_args={'sort_dir': 'desc',
'limit': 1})
marker = events[0].id if events else None
action = 'UPDATE'
time.sleep(10)
verbose_events = verbose_level > 0
create_result = utils.wait_for_stack_ready(
orchestration_client, plan_name, marker, action, verbose_events)
if not create_result:
if stack is None:
raise exceptions.DeploymentError("Heat Stack create failed.")
else:
raise exceptions.DeploymentError("Heat Stack update failed.")