summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--heatclient/osc/v1/software_config.py85
-rw-r--r--heatclient/tests/unit/osc/v1/test_sotware_config.py118
-rw-r--r--setup.cfg1
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)
diff --git a/setup.cfg b/setup.cfg
index 5f77f1a..90dedd1 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -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