diff options
-rw-r--r-- | heatclient/osc/v1/software_config.py | 85 | ||||
-rw-r--r-- | heatclient/tests/unit/osc/v1/test_sotware_config.py | 118 | ||||
-rw-r--r-- | setup.cfg | 1 |
3 files changed, 204 insertions, 0 deletions
diff --git a/heatclient/osc/v1/software_config.py b/heatclient/osc/v1/software_config.py index c0ea931..f25f326 100644 --- a/heatclient/osc/v1/software_config.py +++ b/heatclient/osc/v1/software_config.py @@ -14,12 +14,19 @@ """Orchestration v1 software config action implementations""" import logging +import six + +from six.moves.urllib import request +import yaml from cliff import command from cliff import lister from openstackclient.common import exceptions as exc from openstackclient.common import utils +from heatclient.common import format_utils +from heatclient.common import template_format +from heatclient.common import utils as heat_utils from heatclient import exc as heat_exc from heatclient.openstack.common._i18n import _ @@ -101,3 +108,81 @@ def _list_config(heat_client, args): columns = ['id', 'name', 'group', 'creation_time'] return (columns, (utils.get_item_properties(s, columns) for s in scs)) + + +class CreateConfig(format_utils.JsonFormat): + """Create software config""" + + log = logging.getLogger(__name__ + ".CreateConfig") + + def get_parser(self, prog_name): + parser = super(CreateConfig, self).get_parser(prog_name) + parser.add_argument( + 'name', + metavar='<CONFIG_NAME>', + help=_('Name of the software config to create') + ) + parser.add_argument( + '--config-file', + metavar='<FILE or URL>', + help=_('Path to JSON/YAML containing map defining ' + '<inputs>, <outputs>, and <options>') + ) + parser.add_argument( + '--definition-file', + metavar='<FILE or URL>', + help=_('Path to software config script/data') + ) + parser.add_argument( + '--group', + metavar='<GROUP_NAME>', + default='Heat::Ungrouped', + help=_('Group name of tool expected by the software config') + ) + return parser + + def take_action(self, parsed_args): + self.log.debug("take_action(%s)", parsed_args) + heat_client = self.app.client_manager.orchestration + return _create_config(heat_client, parsed_args) + + +def _create_config(heat_client, args): + config = { + 'group': args.group, + 'config': '' + } + + defn = {} + if args.definition_file: + defn_url = heat_utils.normalise_file_path_to_url( + args.definition_file) + defn_raw = request.urlopen(defn_url).read() or '{}' + defn = yaml.load(defn_raw, Loader=template_format.yaml_loader) + + config['inputs'] = defn.get('inputs', []) + config['outputs'] = defn.get('outputs', []) + config['options'] = defn.get('options', {}) + + if args.config_file: + config_url = heat_utils.normalise_file_path_to_url( + args.config_file) + config['config'] = request.urlopen(config_url).read() + + # build a mini-template with a config resource and validate it + validate_template = { + 'heat_template_version': '2013-05-23', + 'resources': { + args.name: { + 'type': 'OS::Heat::SoftwareConfig', + 'properties': config + } + } + } + heat_client.stacks.validate(template=validate_template) + + config['name'] = args.name + sc = heat_client.software_configs.create(**config).to_dict() + rows = list(six.itervalues(sc)) + columns = list(six.iterkeys(sc)) + return columns, rows diff --git a/heatclient/tests/unit/osc/v1/test_sotware_config.py b/heatclient/tests/unit/osc/v1/test_sotware_config.py index 00260fa..0257747 100644 --- a/heatclient/tests/unit/osc/v1/test_sotware_config.py +++ b/heatclient/tests/unit/osc/v1/test_sotware_config.py @@ -12,6 +12,7 @@ # import mock +import yaml from openstackclient.common import exceptions as exc @@ -91,3 +92,120 @@ class TestListConfig(TestConfig): self.cmd.take_action(parsed_args) self.mock_client.software_configs.list.assert_called_with( marker='id123') + + +class TestCreateConfig(TestConfig): + + def setUp(self): + super(TestCreateConfig, self).setUp() + self.cmd = software_config.CreateConfig(self.app, None) + self.mock_client.stacks.validate = mock.Mock() + self.mock_client.software_configs.create = mock.Mock( + return_value=software_configs.SoftwareConfig(None, {})) + + def test_config_create(self): + properties = { + 'config': '', + 'group': 'Heat::Ungrouped', + 'name': 'test', + 'options': {}, + 'inputs': [], + 'outputs': [] + } + arglist = ['test'] + parsed_args = self.check_parser(self.cmd, arglist, []) + columns, rows = self.cmd.take_action(parsed_args) + self.mock_client.stacks.validate.assert_called_with(**{ + 'template': { + 'heat_template_version': '2013-05-23', + 'resources': { + 'test': { + 'type': 'OS::Heat::SoftwareConfig', + 'properties': properties}}}}) + self.mock_client.software_configs.create.assert_called_with( + **properties) + + def test_config_create_group(self): + properties = { + 'config': '', + 'group': 'group', + 'name': 'test', + 'options': {}, + 'inputs': [], + 'outputs': [] + } + arglist = ['test', '--group', 'group'] + parsed_args = self.check_parser(self.cmd, arglist, []) + columns, rows = self.cmd.take_action(parsed_args) + self.mock_client.stacks.validate.assert_called_with(**{ + 'template': { + 'heat_template_version': '2013-05-23', + 'resources': { + 'test': { + 'type': 'OS::Heat::SoftwareConfig', + 'properties': properties}}}}) + self.mock_client.software_configs.create.assert_called_with( + **properties) + + @mock.patch('six.moves.urllib.request.urlopen') + def test_config_create_config_file(self, urlopen): + properties = { + 'config': 'config', + 'group': 'Heat::Ungrouped', + 'name': 'test', + 'options': {}, + 'inputs': [], + 'outputs': [] + } + data = mock.Mock() + data.read.side_effect = ['config'] + urlopen.return_value = data + + arglist = ['test', '--config-file', 'config_file'] + parsed_args = self.check_parser(self.cmd, arglist, []) + columns, rows = self.cmd.take_action(parsed_args) + self.mock_client.stacks.validate.assert_called_with(**{ + 'template': { + 'heat_template_version': '2013-05-23', + 'resources': { + 'test': { + 'type': 'OS::Heat::SoftwareConfig', + 'properties': properties}}}}) + self.mock_client.software_configs.create.assert_called_with( + **properties) + + @mock.patch('six.moves.urllib.request.urlopen') + def test_config_create_definition_file(self, urlopen): + definition = { + 'inputs': [ + {'name': 'input'}, + ], + 'outputs': [ + {'name': 'output'} + ], + 'options': {'option': 'value'} + } + + properties = { + 'config': '', + 'group': 'Heat::Ungrouped', + 'name': 'test' + } + properties.update(definition) + + data = mock.Mock() + data.read.side_effect = [yaml.safe_dump(definition)] + urlopen.return_value = data + + arglist = ['test', '--definition-file', 'definition-file'] + parsed_args = self.check_parser(self.cmd, arglist, []) + columns, rows = self.cmd.take_action(parsed_args) + self.mock_client.stacks.validate.assert_called_with(**{ + 'template': { + 'heat_template_version': '2013-05-23', + 'resources': { + 'test': { + 'type': 'OS::Heat::SoftwareConfig', + 'properties': properties}}}}) + self.mock_client.software_configs.create.assert_called_with( + **properties) @@ -32,6 +32,7 @@ openstack.cli.extension = openstack.orchestration.v1 = orchestration_template_function_list = heatclient.osc.v1.template:FunctionList orchestration_template_version_list = heatclient.osc.v1.template:VersionList + software_config_create = heatclient.osc.v1.software_config:CreateConfig software_config_delete = heatclient.osc.v1.software_config:DeleteConfig software_config_list = heatclient.osc.v1.software_config:ListConfig software_deployment_delete = heatclient.osc.v1.software_deployment:DeleteDeployment |