From 69011b52937a9a75b0dcf771dc9d2de8e82020d3 Mon Sep 17 00:00:00 2001 From: Rabi Mishra Date: Fri, 3 Jul 2015 19:40:42 +0530 Subject: [PATCH] Fix error when creating deployment from cli This fixes the 'deployment-create' cli command and adds unit test. Change-Id: I3908e8bbad07b1fc372748b9adc8089ce14df015 Closes-Bug: #1464217 --- heatclient/common/deployment_utils.py | 10 +- .../tests/unit/test_deployment_utils.py | 5 +- heatclient/tests/unit/test_shell.py | 129 ++++++++++++++++++ heatclient/v1/shell.py | 13 +- 4 files changed, 144 insertions(+), 13 deletions(-) diff --git a/heatclient/common/deployment_utils.py b/heatclient/common/deployment_utils.py index a296a863..02a3f79b 100644 --- a/heatclient/common/deployment_utils.py +++ b/heatclient/common/deployment_utils.py @@ -25,7 +25,7 @@ def build_derived_config_params(action, source, name, input_values, server_id, signal_transport, signal_id=None): input_values = input_values or {} - inputs = copy.deepcopy(source.inputs) or [] + inputs = copy.deepcopy(source.get('inputs')) or [] for inp in inputs: input_key = inp['name'] @@ -79,11 +79,11 @@ def build_derived_config_params(action, source, name, input_values, _('Unsupported signal transport %s') % signal_transport) return { - 'group': source.group or 'Heat::Ungrouped', - 'config': source.config or '', - 'options': source.options, + 'group': source.get('group') or 'Heat::Ungrouped', + 'config': source.get('config') or '', + 'options': source.get('options') or {}, 'inputs': inputs, - 'outputs': source.outputs, + 'outputs': source.get('outputs') or [], 'name': name } diff --git a/heatclient/tests/unit/test_deployment_utils.py b/heatclient/tests/unit/test_deployment_utils.py index ed0cd987..69a2899a 100644 --- a/heatclient/tests/unit/test_deployment_utils.py +++ b/heatclient/tests/unit/test_deployment_utils.py @@ -19,7 +19,6 @@ import testtools from heatclient.common import deployment_utils from heatclient import exc -from heatclient.v1 import software_configs from testtools import matchers @@ -28,13 +27,13 @@ load_tests = testscenarios.load_tests_apply_scenarios def mock_sc(group=None, config=None, options=None, inputs=None, outputs=None): - return software_configs.SoftwareConfig(None, { + return { 'group': group, 'config': config, 'options': options or {}, 'inputs': inputs or [], 'outputs': outputs or [], - }, True) + } class DerivedConfigTest(testtools.TestCase): diff --git a/heatclient/tests/unit/test_shell.py b/heatclient/tests/unit/test_shell.py index 462c63d7..c0386ce4 100644 --- a/heatclient/tests/unit/test_shell.py +++ b/heatclient/tests/unit/test_shell.py @@ -3679,6 +3679,135 @@ class ShellTestDeployment(ShellBase): '''Patch os.environ to avoid required auth info.''' self.set_fake_env(FAKE_ENV_KEYSTONE_V2) + def test_deploy_create(self): + self.register_keystone_auth_fixture() + self.patch( + 'heatclient.common.deployment_utils.build_derived_config_params') + self.patch( + 'heatclient.common.deployment_utils.build_signal_id') + resp_dict = {'software_deployment': { + 'status': 'INPROGRESS', + 'server_id': '700115e5-0100-4ecc-9ef7-9e05f27d8803', + 'config_id': '18c4fc03-f897-4a1d-aaad-2b7622e60257', + 'output_values': { + 'deploy_stdout': '', + 'deploy_stderr': '', + 'deploy_status_code': 0, + 'result': 'The result value' + }, + 'input_values': {}, + 'action': 'UPDATE', + 'status_reason': 'Outputs received', + 'id': 'abcd' + }} + + config_dict = {'software_config': { + 'inputs': [], + 'group': 'script', + 'name': 'config_name', + 'outputs': [], + 'options': {}, + 'config': 'the config script', + 'id': 'defg'}} + + derived_dict = {'software_config': { + 'inputs': [], + 'group': 'script', + 'name': 'config_name', + 'outputs': [], + 'options': {}, + 'config': 'the config script', + 'id': 'abcd'}} + + deploy_data = {'action': 'UPDATE', + 'config_id': u'abcd', + 'server_id': 'inst01', + 'status': 'IN_PROGRESS', + 'tenant_id': 'asdf'} + + config_string = jsonutils.dumps(config_dict) + headers = {'content-type': 'application/json'} + http_resp = fakes.FakeHTTPResponse(200, 'OK', headers, config_string) + response = (http_resp, config_dict) + if self.client == http.SessionClient: + http.SessionClient.request( + '/software_configs/defg', 'GET').AndReturn(http_resp) + else: + self.client.json_request( + 'GET', '/software_configs/defg').AndReturn(response) + + derived_string = jsonutils.dumps(derived_dict) + http_resp = fakes.FakeHTTPResponse(200, 'OK', headers, derived_string) + response = (http_resp, derived_dict) + if self.client == http.SessionClient: + http.SessionClient.request( + '/software_configs', 'POST', data={}).AndReturn(http_resp) + else: + self.client.json_request( + 'POST', '/software_configs', data={}).AndReturn(response) + + resp_string = jsonutils.dumps(resp_dict) + http_resp = fakes.FakeHTTPResponse(200, 'OK', headers, resp_string) + response = (http_resp, resp_dict) + if self.client == http.SessionClient: + self.client.request( + '/software_deployments', 'POST', + data=deploy_data).AndReturn(http_resp) + else: + self.client.json_request( + 'POST', + '/software_deployments', data=deploy_data).AndReturn(response) + + http_resp = fakes.FakeHTTPResponse(200, 'OK', headers, derived_string) + response = (http_resp, derived_dict) + if self.client == http.SessionClient: + http.SessionClient.request( + '/software_configs', 'POST', data={}).AndReturn(http_resp) + else: + self.client.json_request( + 'POST', '/software_configs', data={}).AndReturn(response) + + http_resp = fakes.FakeHTTPResponse(200, 'OK', headers, resp_string) + response = (http_resp, resp_dict) + if self.client == http.SessionClient: + self.client.request( + '/software_deployments', 'POST', + data=deploy_data).AndReturn(http_resp) + self.client.request( + '/software_configs/defgh', 'GET').AndRaise( + exc.HTTPNotFound()) + else: + self.client.json_request( + 'POST', '/software_deployments').AndReturn(response) + self.client.json_request( + 'GET', '/software_configs/defgh').AndRaise( + exc.HTTPNotFound()) + + self.m.ReplayAll() + + text = self.shell('deployment-create -c defg -sinst01 xxx') + + required = [ + 'status', + 'server_id', + 'config_id', + 'output_values', + 'input_values', + 'action', + 'status_reason', + 'id', + ] + for r in required: + self.assertRegexpMatches(text, r) + + text = self.shell('deployment-create -sinst01 xxx') + for r in required: + self.assertRegexpMatches(text, r) + + self.assertRaises(exc.CommandError, self.shell, + 'deployment-create -c defgh -s inst01 yyy') + self.m.VerifyAll() + def test_deploy_show(self): self.register_keystone_auth_fixture() resp_dict = {'software_deployment': { diff --git a/heatclient/v1/shell.py b/heatclient/v1/shell.py index 2e97ba62..bebc5f6f 100644 --- a/heatclient/v1/shell.py +++ b/heatclient/v1/shell.py @@ -1174,7 +1174,7 @@ def do_config_delete(hc, args): 'CREATE, UPDATE, DELETE, SUSPEND, RESUME')) @utils.arg('-c', '--config', metavar='', help=_('ID of the configuration to deploy.')) -@utils.arg('-s', '--server', metavar='', +@utils.arg('-s', '--server', metavar='', required=True, help=_('ID of the server being deployed to.')) @utils.arg('-t', '--signal-transport', default='TEMP_URL_SIGNAL', @@ -1197,10 +1197,13 @@ def do_config_delete(hc, args): 'deployment. This is used to apply a sort order to the ' 'list of configurations currently deployed to the server.')) def do_deployment_create(hc, args): - try: - config = hc.software_configs.get(config_id=args.config) - except exc.HTTPNotFound: - raise exc.CommandError(_('Configuration not found: %s') % args.id) + config = {} + if args.config: + try: + config = hc.software_configs.get(config_id=args.config) + except exc.HTTPNotFound: + raise exc.CommandError( + _('Configuration not found: %s') % args.config) derrived_params = deployment_utils.build_derived_config_params( action=args.action,