From 41bf090d010516176037de0032bc38cad1125639 Mon Sep 17 00:00:00 2001 From: Ana Krivokapic Date: Thu, 26 Jan 2017 19:35:11 +0100 Subject: [PATCH] Add plan export command Depends-On: I789c960f61a30ccd4b076fcae4b3e1b80e825585 Implements: blueprint plan-export-command Change-Id: Ibedca0d80f93ab5e4bf7f105472bb384bc9506e6 --- .../plan-export-command-3fb76c91c77d7b24.yaml | 3 + setup.cfg | 1 + tripleoclient/tests/v1/test_overcloud_plan.py | 56 +++++++++++++++++++ tripleoclient/v1/overcloud_plan.py | 51 +++++++++++++++++ tripleoclient/workflows/plan_management.py | 24 ++++++++ 5 files changed, 135 insertions(+) create mode 100644 releasenotes/notes/plan-export-command-3fb76c91c77d7b24.yaml diff --git a/releasenotes/notes/plan-export-command-3fb76c91c77d7b24.yaml b/releasenotes/notes/plan-export-command-3fb76c91c77d7b24.yaml new file mode 100644 index 000000000..27fd2a17a --- /dev/null +++ b/releasenotes/notes/plan-export-command-3fb76c91c77d7b24.yaml @@ -0,0 +1,3 @@ +--- +features: + - Add a new plan export command for exporting deployment plans. diff --git a/setup.cfg b/setup.cfg index af2d7784c..46473939b 100644 --- a/setup.cfg +++ b/setup.cfg @@ -78,6 +78,7 @@ openstack.tripleoclient.v1 = 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_plan_export = tripleoclient.v1.overcloud_plan:ExportPlan overcloud_profiles_match = tripleoclient.v1.overcloud_profiles:MatchProfiles overcloud_profiles_list = tripleoclient.v1.overcloud_profiles:ListProfiles overcloud_raid_create = tripleoclient.v1.overcloud_raid:CreateRAID diff --git a/tripleoclient/tests/v1/test_overcloud_plan.py b/tripleoclient/tests/v1/test_overcloud_plan.py index d45768e1c..09e3fe543 100644 --- a/tripleoclient/tests/v1/test_overcloud_plan.py +++ b/tripleoclient/tests/v1/test_overcloud_plan.py @@ -359,3 +359,59 @@ class TestOvercloudDeployPlan(utils.TestCommand): 'queue_name': 'UUID4' } ) + + +class TestOvercloudExportPlan(utils.TestCommand): + + def setUp(self): + super(TestOvercloudExportPlan, self).setUp() + self.cmd = overcloud_plan.ExportPlan(self.app, None) + self.app.client_manager = mock.Mock() + self.clients = self.app.client_manager + + # 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 urlopen + f = mock.Mock() + f.read.return_value = 'tarball contents' + urlopen_patcher = mock.patch('six.moves.urllib.request.urlopen', + return_value=f) + self.mock_urlopen = urlopen_patcher.start() + self.addCleanup(self.mock_urlopen.stop) + + @mock.patch( + 'tripleoclient.workflows.plan_management.export_deployment_plan', + autospec=True) + def test_export_plan(self, export_deployment_plan_mock): + parsed_args = self.check_parser(self.cmd, ['test-plan'], + [('plans', ['test-plan'])]) + + export_deployment_plan_mock.return_value = 'http://fake-url.com' + + with mock.patch('six.moves.builtins.open', mock.mock_open()): + self.cmd.take_action(parsed_args) + + export_deployment_plan_mock.assert_called_once_with( + self.clients, plan='test-plan', queue_name='UUID4') + + @mock.patch( + 'tripleoclient.workflows.plan_management.export_deployment_plan', + autospec=True) + def test_export_multiple_plans(self, export_deployment_plan_mock): + argslist = ['test-plan1', 'test-plan2'] + verifylist = [('plans', ['test-plan1', 'test-plan2'])] + parsed_args = self.check_parser(self.cmd, argslist, verifylist) + + export_deployment_plan_mock.return_value = 'http://fake-url.com' + + with mock.patch('six.moves.builtins.open', mock.mock_open()): + self.cmd.take_action(parsed_args) + + expected = [ + mock.call(self.clients, plan='test-plan1', queue_name='UUID4'), + mock.call(self.clients, plan='test-plan2', queue_name='UUID4'), + ] + self.assertEqual(export_deployment_plan_mock.call_args_list, expected) diff --git a/tripleoclient/v1/overcloud_plan.py b/tripleoclient/v1/overcloud_plan.py index 130f05114..a6a5373c6 100644 --- a/tripleoclient/v1/overcloud_plan.py +++ b/tripleoclient/v1/overcloud_plan.py @@ -12,10 +12,13 @@ import json import logging +import os.path import uuid from osc_lib.command import command from osc_lib.i18n import _ +from six.moves.urllib import request + from tripleoclient import utils from tripleoclient.workflows import deployment @@ -146,3 +149,51 @@ class DeployPlan(command.Command): self.app_args.verbose_level, timeout=parsed_args.timeout, run_validations=parsed_args.run_validations) + + +class ExportPlan(command.Command): + """Export a deployment plan""" + + log = logging.getLogger(__name__ + ".ExportPlan") + + def get_parser(self, prog_name): + parser = super(ExportPlan, self).get_parser(prog_name) + parser.add_argument('plans', metavar='', nargs='+', + help=_('Name of the plan(s) to export.')) + parser.add_argument('--output-files', '-o', metavar='', + nargs='+', default=[], + help=_('Name of the output file(s) for exports. ' + 'Each will default to ".tar.gz".') + ) + parser.add_argument('--force-overwrite', '-f', action='store_true', + default=False, + help=_('Overwrite output files if they exist.')) + return parser + + def take_action(self, parsed_args): + self.log.debug("take_action(%s)" % parsed_args) + clients = self.app.client_manager + plans = parsed_args.plans + outfiles = parsed_args.output_files + overwrite = parsed_args.force_overwrite + + for i, plan in enumerate(plans): + print("Exporting plan %s..." % plan) + + try: + tarball_name = outfiles[i] + except IndexError: + tarball_name = '%s.tar.gz' % plan + + if os.path.exists(tarball_name) and not overwrite: + print("File '%s' already exists, not exporting." + % tarball_name) + continue + + tempurl = plan_management.export_deployment_plan( + clients, plan=plan, queue_name=str(uuid.uuid4())) + f = request.urlopen(tempurl) + tarball_contents = f.read() + + with open(tarball_name, 'w') as f: + f.write(tarball_contents) diff --git a/tripleoclient/workflows/plan_management.py b/tripleoclient/workflows/plan_management.py index 096967553..fda4dc8f0 100644 --- a/tripleoclient/workflows/plan_management.py +++ b/tripleoclient/workflows/plan_management.py @@ -183,3 +183,27 @@ def update_plan_from_templates(clients, name, tht_root, roles_file=None, update_deployment_plan(clients, container=name, queue_name=str(uuid.uuid4()), generate_passwords=generate_passwords) + + +def export_deployment_plan(clients, **workflow_input): + workflow_client = clients.workflow_engine + tripleoclients = clients.tripleoclient + queue_name = workflow_input['queue_name'] + + execution = base.start_workflow( + workflow_client, + 'tripleo.plan_management.v1.export_deployment_plan', + workflow_input=workflow_input + ) + + with tripleoclients.messaging_websocket(queue_name) as ws: + for payload in base.wait_for_messages(workflow_client, ws, execution, + _WORKFLOW_TIMEOUT): + if 'message' in payload: + print(payload['message']) + + if payload['status'] == 'SUCCESS': + return payload['tempurl'] + else: + raise exceptions.WorkflowServiceError( + 'Exception exporting plan: {}'.format(payload['message']))