Deploy templates: client support

Adds OSC support for the deploy templates API.

Change-Id: I0f2f37e840449ee41f747e2a43ed6f53c927094e
Depends-On: https://review.openstack.org/631845
Story: 1722275
Task: 28678
This commit is contained in:
Mark Goddard 2019-02-14 11:25:09 +00:00
parent fdba8ed994
commit cc37253428
15 changed files with 1484 additions and 9 deletions

View File

@ -43,7 +43,7 @@ from ironicclient import exc
# http://specs.openstack.org/openstack/ironic-specs/specs/kilo/api-microversions.html # noqa
# for full details.
DEFAULT_VER = '1.9'
LAST_KNOWN_API_VERSION = 54
LAST_KNOWN_API_VERSION = 55
LATEST_VERSION = '1.{}'.format(LAST_KNOWN_API_VERSION)
LOG = logging.getLogger(__name__)

View File

@ -411,3 +411,19 @@ def poll(timeout, poll_interval, poll_delay_function, timeout_message):
count += 1
raise exc.StateTransitionTimeout(timeout_message)
def handle_json_arg(json_arg, info_desc):
"""Read a JSON argument from stdin, file or string.
:param json_arg: May be a file name containing the JSON, a JSON string, or
'-' indicating that the argument should be read from standard input.
:param info_desc: A string description of the desired information
:returns: A list or dictionary parsed from JSON.
:raises: InvalidAttribute if the argument cannot be parsed.
"""
if json_arg == '-':
json_arg = get_from_stdin(info_desc)
if json_arg:
json_arg = handle_json_or_file_arg(json_arg)
return json_arg

View File

@ -0,0 +1,345 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
import itertools
import json
import logging
from osc_lib.command import command
from osc_lib import utils as oscutils
from ironicclient.common.i18n import _
from ironicclient.common import utils
from ironicclient import exc
from ironicclient.v1 import resource_fields as res_fields
_DEPLOY_STEPS_HELP = _(
"The deploy steps in JSON format. May be the path to a file containing "
"the deploy steps; OR '-', with the deploy steps being read from standard "
"input; OR a string. The value should be a list of deploy-step "
"dictionaries; each dictionary should have keys 'interface', 'step', "
"'args' and 'priority'.")
class CreateBaremetalDeployTemplate(command.ShowOne):
"""Create a new deploy template"""
log = logging.getLogger(__name__ + ".CreateBaremetalDeployTemplate")
def get_parser(self, prog_name):
parser = super(CreateBaremetalDeployTemplate, self).get_parser(
prog_name)
parser.add_argument(
'name',
metavar='<name>',
help=_('Unique name for this deploy template. Must be a valid '
'trait name')
)
parser.add_argument(
'--uuid',
dest='uuid',
metavar='<uuid>',
help=_('UUID of the deploy template.'))
parser.add_argument(
'--extra',
metavar="<key=value>",
action='append',
help=_("Record arbitrary key/value metadata. "
"Can be specified multiple times."))
parser.add_argument(
'--steps',
metavar="<steps>",
required=True,
help=_DEPLOY_STEPS_HELP
)
return parser
def take_action(self, parsed_args):
self.log.debug("take_action(%s)", parsed_args)
baremetal_client = self.app.client_manager.baremetal
steps = utils.handle_json_arg(parsed_args.steps, 'deploy steps')
field_list = ['name', 'uuid', 'extra']
fields = dict((k, v) for (k, v) in vars(parsed_args).items()
if k in field_list and v is not None)
fields = utils.args_array_to_dict(fields, 'extra')
template = baremetal_client.deploy_template.create(steps=steps,
**fields)
data = dict([(f, getattr(template, f, '')) for f in
res_fields.DEPLOY_TEMPLATE_DETAILED_RESOURCE.fields])
return self.dict2columns(data)
class ShowBaremetalDeployTemplate(command.ShowOne):
"""Show baremetal deploy template details."""
log = logging.getLogger(__name__ + ".ShowBaremetalDeployTemplate")
def get_parser(self, prog_name):
parser = super(ShowBaremetalDeployTemplate, self).get_parser(prog_name)
parser.add_argument(
"template",
metavar="<template>",
help=_("Name or UUID of the deploy template.")
)
parser.add_argument(
'--fields',
nargs='+',
dest='fields',
metavar='<field>',
action='append',
choices=res_fields.DEPLOY_TEMPLATE_DETAILED_RESOURCE.fields,
default=[],
help=_("One or more deploy template fields. Only these fields "
"will be fetched from the server.")
)
return parser
def take_action(self, parsed_args):
self.log.debug("take_action(%s)", parsed_args)
baremetal_client = self.app.client_manager.baremetal
fields = list(itertools.chain.from_iterable(parsed_args.fields))
fields = fields if fields else None
template = baremetal_client.deploy_template.get(
parsed_args.template, fields=fields)._info
template.pop("links", None)
return zip(*sorted(template.items()))
class SetBaremetalDeployTemplate(command.Command):
"""Set baremetal deploy template properties."""
log = logging.getLogger(__name__ + ".SetBaremetalDeployTemplate")
def get_parser(self, prog_name):
parser = super(SetBaremetalDeployTemplate, self).get_parser(prog_name)
parser.add_argument(
'template',
metavar='<template>',
help=_("Name or UUID of the deploy template")
)
parser.add_argument(
'--name',
metavar='<name>',
help=_('Set unique name of the deploy template. Must be a valid '
'trait name.')
)
parser.add_argument(
'--steps',
metavar="<steps>",
help=_DEPLOY_STEPS_HELP
)
parser.add_argument(
"--extra",
metavar="<key=value>",
action='append',
help=_('Extra to set on this baremetal deploy template '
'(repeat option to set multiple extras).'),
)
return parser
def take_action(self, parsed_args):
self.log.debug("take_action(%s)", parsed_args)
baremetal_client = self.app.client_manager.baremetal
properties = []
if parsed_args.name:
name = ["name=%s" % parsed_args.name]
properties.extend(utils.args_array_to_patch('add', name))
if parsed_args.steps:
steps = utils.handle_json_arg(parsed_args.steps, 'deploy steps')
steps = ["steps=%s" % json.dumps(steps)]
properties.extend(utils.args_array_to_patch('add', steps))
if parsed_args.extra:
properties.extend(utils.args_array_to_patch(
'add', ['extra/' + x for x in parsed_args.extra]))
if properties:
baremetal_client.deploy_template.update(parsed_args.template,
properties)
else:
self.log.warning("Please specify what to set.")
class UnsetBaremetalDeployTemplate(command.Command):
"""Unset baremetal deploy template properties."""
log = logging.getLogger(__name__ + ".UnsetBaremetalDeployTemplate")
def get_parser(self, prog_name):
parser = super(UnsetBaremetalDeployTemplate, self).get_parser(
prog_name)
parser.add_argument(
'template',
metavar='<template>',
help=_("Name or UUID of the deploy template")
)
parser.add_argument(
"--extra",
metavar="<key>",
action='append',
help=_('Extra to unset on this baremetal deploy template '
'(repeat option to unset multiple extras).'),
)
return parser
def take_action(self, parsed_args):
self.log.debug("take_action(%s)", parsed_args)
baremetal_client = self.app.client_manager.baremetal
properties = []
if parsed_args.extra:
properties.extend(utils.args_array_to_patch('remove',
['extra/' + x for x in parsed_args.extra]))
if properties:
baremetal_client.deploy_template.update(parsed_args.template,
properties)
else:
self.log.warning("Please specify what to unset.")
class DeleteBaremetalDeployTemplate(command.Command):
"""Delete deploy template(s)."""
log = logging.getLogger(__name__ + ".DeleteBaremetalDeployTemplate")
def get_parser(self, prog_name):
parser = super(DeleteBaremetalDeployTemplate, self).get_parser(
prog_name)
parser.add_argument(
"templates",
metavar="<template>",
nargs="+",
help=_("Name(s) or UUID(s) of the deploy template(s) to delete.")
)
return parser
def take_action(self, parsed_args):
self.log.debug("take_action(%s)", parsed_args)
baremetal_client = self.app.client_manager.baremetal
failures = []
for template in parsed_args.templates:
try:
baremetal_client.deploy_template.delete(template)
print(_('Deleted deploy template %s') % template)
except exc.ClientException as e:
failures.append(_("Failed to delete deploy template "
"%(template)s: %(error)s")
% {'template': template, 'error': e})
if failures:
raise exc.ClientException("\n".join(failures))
class ListBaremetalDeployTemplate(command.Lister):
"""List baremetal deploy templates."""
log = logging.getLogger(__name__ + ".ListBaremetalDeployTemplate")
def get_parser(self, prog_name):
parser = super(ListBaremetalDeployTemplate, self).get_parser(prog_name)
parser.add_argument(
'--limit',
metavar='<limit>',
type=int,
help=_('Maximum number of deploy templates to return per request, '
'0 for no limit. Default is the maximum number used '
'by the Baremetal API Service.')
)
parser.add_argument(
'--marker',
metavar='<template>',
help=_('DeployTemplate UUID (for example, of the last deploy '
'template in the list from a previous request). Returns '
'the list of deploy templates after this UUID.')
)
parser.add_argument(
'--sort',
metavar="<key>[:<direction>]",
help=_('Sort output by specified deploy template fields and '
'directions (asc or desc) (default: asc). Multiple fields '
'and directions can be specified, separated by comma.')
)
display_group = parser.add_mutually_exclusive_group()
display_group.add_argument(
'--long',
dest='detail',
action='store_true',
default=False,
help=_("Show detailed information about deploy templates.")
)
display_group.add_argument(
'--fields',
nargs='+',
dest='fields',
metavar='<field>',
action='append',
default=[],
choices=res_fields.DEPLOY_TEMPLATE_DETAILED_RESOURCE.fields,
help=_("One or more deploy template fields. Only these fields "
"will be fetched from the server. Can not be used when "
"'--long' is specified.")
)
return parser
def take_action(self, parsed_args):
self.log.debug("take_action(%s)", parsed_args)
client = self.app.client_manager.baremetal
columns = res_fields.DEPLOY_TEMPLATE_RESOURCE.fields
labels = res_fields.DEPLOY_TEMPLATE_RESOURCE.labels
params = {}
if parsed_args.limit is not None and parsed_args.limit < 0:
raise exc.CommandError(
_('Expected non-negative --limit, got %s') %
parsed_args.limit)
params['limit'] = parsed_args.limit
params['marker'] = parsed_args.marker
if parsed_args.detail:
params['detail'] = parsed_args.detail
columns = res_fields.DEPLOY_TEMPLATE_DETAILED_RESOURCE.fields
labels = res_fields.DEPLOY_TEMPLATE_DETAILED_RESOURCE.labels
elif parsed_args.fields:
params['detail'] = False
fields = itertools.chain.from_iterable(parsed_args.fields)
resource = res_fields.Resource(list(fields))
columns = resource.fields
labels = resource.labels
params['fields'] = columns
self.log.debug("params(%s)", params)
data = client.deploy_template.list(**params)
data = oscutils.sort_items(data, parsed_args.sort)
return (labels,
(oscutils.get_item_properties(s, columns) for s in data))

View File

@ -66,10 +66,7 @@ class ProvisionStateBaremetalNode(command.Command):
baremetal_client = self.app.client_manager.baremetal
clean_steps = getattr(parsed_args, 'clean_steps', None)
if clean_steps == '-':
clean_steps = utils.get_from_stdin('clean steps')
if clean_steps:
clean_steps = utils.handle_json_or_file_arg(clean_steps)
clean_steps = utils.handle_json_arg(clean_steps, 'clean steps')
config_drive = getattr(parsed_args, 'config_drive', None)
rescue_password = getattr(parsed_args, 'rescue_password', None)
@ -1207,9 +1204,8 @@ class SetBaremetalNode(command.Command):
# also being modified.
if parsed_args.target_raid_config:
raid_config = parsed_args.target_raid_config
if raid_config == '-':
raid_config = utils.get_from_stdin('target_raid_config')
raid_config = utils.handle_json_or_file_arg(raid_config)
raid_config = utils.handle_json_arg(raid_config,
'target_raid_config')
baremetal_client.node.set_target_raid_config(parsed_args.node,
raid_config)

View File

@ -443,7 +443,7 @@ class ListBaremetalPort(command.Lister):
type=int,
help=_('Maximum number of ports to return per request, '
'0 for no limit. Default is the maximum number used '
'by the Ironic API Service.')
'by the Baremetal API Service.')
)
parser.add_argument(
'--marker',

View File

@ -401,3 +401,60 @@ class TestCase(base.FunctionalTestBase):
except exceptions.CommandFailed:
if not ignore_exceptions:
raise
def deploy_template_create(self, name, params=''):
"""Create baremetal deploy template and add cleanup.
:param String name: deploy template name
:param String params: additional parameters
:return: JSON object of created deploy template
"""
opts = self.get_opts()
template = self.openstack('baremetal deploy template create {0} {1} '
'{2}'.format(opts, name, params))
template = json.loads(template)
if not template:
self.fail('Baremetal deploy template has not been created!')
self.addCleanup(self.deploy_template_delete, template['uuid'], True)
return template
def deploy_template_list(self, fields=None, params=''):
"""List baremetal deploy templates.
:param List fields: List of fields to show
:param String params: Additional kwargs
:return: list of JSON deploy template objects
"""
opts = self.get_opts(fields=fields)
output = self.openstack('baremetal deploy template list {0} {1}'
.format(opts, params))
return json.loads(output)
def deploy_template_show(self, identifier, fields=None, params=''):
"""Show specified baremetal deploy template.
:param String identifier: Name or UUID of the deploy template
:param List fields: List of fields to show
:param List params: Additional kwargs
:return: JSON object of deploy template
"""
opts = self.get_opts(fields)
output = self.openstack('baremetal deploy template show {0} {1} {2}'
.format(opts, identifier, params))
return json.loads(output)
def deploy_template_delete(self, identifier, ignore_exceptions=False):
"""Try to delete baremetal deploy template by UUID.
:param String identifier: Name or UUID of the deploy template
:param Bool ignore_exceptions: Ignore exception (needed for cleanUp)
:return: raw values output
:raise: CommandFailed exception when command fails to delete a deploy
template
"""
try:
return self.openstack('baremetal deploy template delete {0}'
.format(identifier))
except exceptions.CommandFailed:
if not ignore_exceptions:
raise

View File

@ -0,0 +1,177 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import json
import ddt
from tempest.lib.common.utils import data_utils
from tempest.lib import exceptions
from ironicclient.tests.functional.osc.v1 import base
@ddt.ddt
class BaremetalDeployTemplateTests(base.TestCase):
"""Functional tests for baremetal deploy template commands."""
@staticmethod
def _get_random_trait():
return data_utils.rand_name('CUSTOM', '').replace('-', '_')
def setUp(self):
super(BaremetalDeployTemplateTests, self).setUp()
self.steps = json.dumps([{
'interface': 'bios',
'step': 'apply_configuration',
'args': {},
'priority': 10,
}])
name = self._get_random_trait()
self.template = self.deploy_template_create(
name, params="--steps '%s'" % self.steps)
def tearDown(self):
if self.template is not None:
self.deploy_template_delete(self.template['uuid'])
super(BaremetalDeployTemplateTests, self).tearDown()
def test_list(self):
"""Check baremetal deploy template list command.
Test steps:
1) Create baremetal deploy template in setUp.
2) List baremetal deploy templates.
3) Check deploy template name and UUID in deploy templates list.
"""
template_list = self.deploy_template_list()
self.assertIn(self.template['name'],
[template['Name']
for template in template_list])
self.assertIn(self.template['uuid'],
[template['UUID']
for template in template_list])
def test_list_long(self):
"""Check baremetal deploy template list --long command
Test steps:
1) Create baremetal deploy template in setUp.
2) List baremetal deploy templates with detail=True.
3) Check deploy template fields in output.
"""
template_list = self.deploy_template_list(params='--long')
template = [template for template in template_list
if template['Name'] == self.template['name']][0]
self.assertEqual(self.template['extra'], template['Extra'])
self.assertEqual(self.template['name'], template['Name'])
self.assertEqual(self.template['steps'], template['Steps'])
self.assertEqual(self.template['uuid'], template['UUID'])
def test_show(self):
"""Check baremetal deploy template show command with UUID.
Test steps:
1) Create baremetal deploy template in setUp.
2) Show baremetal deploy template calling it by UUID.
3) Check deploy template fields in output.
"""
template = self.deploy_template_show(self.template['uuid'])
self.assertEqual(self.template['extra'], template['extra'])
self.assertEqual(self.template['name'], template['name'])
self.assertEqual(self.template['steps'], template['steps'])
self.assertEqual(self.template['uuid'], template['uuid'])
def test_delete(self):
"""Check baremetal deploy template delete command.
Test steps:
1) Create baremetal deploy template in setUp.
2) Delete baremetal deploy template by UUID.
3) Check that deploy template deleted successfully and not in list.
"""
output = self.deploy_template_delete(self.template['uuid'])
self.assertIn('Deleted deploy template {0}'.format(
self.template['uuid']), output)
template_list = self.deploy_template_list()
self.assertNotIn(self.template['name'],
[template['Name'] for template in template_list])
self.assertNotIn(self.template['uuid'],
[template['UUID'] for template in template_list])
self.template = None
def test_set_steps(self):
"""Check baremetal deploy template set command for steps.
Test steps:
1) Create baremetal deploy template in setUp.
2) Set steps for deploy template.
3) Check that baremetal deploy template steps were set.
"""
steps = [{
'interface': 'bios',
'step': 'apply_configuration',
'args': {},
'priority': 20,
}]
self.openstack("baremetal deploy template set --steps '{0}' {1}"
.format(json.dumps(steps), self.template['uuid']))
show_prop = self.deploy_template_show(self.template['uuid'],
fields=['steps'])
self.assertEqual(steps, show_prop['steps'])
def test_set_unset(self):
"""Check baremetal deploy template set and unset commands.
Test steps:
1) Create baremetal deploy template in setUp.
2) Set extra data for deploy template.
3) Check that baremetal deploy template extra data was set.
4) Unset extra data for deploy template.
5) Check that baremetal deploy template extra data was unset.
"""
extra_key = 'ext'
extra_value = 'testdata'
self.openstack(
'baremetal deploy template set --extra {0}={1} {2}'
.format(extra_key, extra_value, self.template['uuid']))
show_prop = self.deploy_template_show(self.template['uuid'],
fields=['extra'])
self.assertEqual(extra_value, show_prop['extra'][extra_key])
self.openstack('baremetal deploy template unset --extra {0} {1}'
.format(extra_key, self.template['uuid']))
show_prop = self.deploy_template_show(self.template['uuid'],
fields=['extra'])
self.assertNotIn(extra_key, show_prop['extra'])
@ddt.data(
('--uuid', '', 'expected one argument'),
('--uuid', '!@#$^*&%^', 'Expected a UUID'),
('', '', 'too few arguments'),
('', 'not/a/name', 'Deploy template name must be a valid trait'),
('', 'foo', 'Deploy template name must be a valid trait'),
('--steps', '', 'expected one argument'),
('--steps', '[]', 'No deploy steps specified'))
@ddt.unpack
def test_create_negative(self, argument, value, ex_text):
"""Check errors on invalid input parameters."""
base_cmd = 'baremetal deploy template create'
if argument != '':
base_cmd += ' %s' % self._get_random_trait()
if argument != '--steps':
base_cmd += " --steps '%s'" % self.steps
command = self.construct_cmd(base_cmd, argument, value)
self.assertRaisesRegex(exceptions.CommandFailed, ex_text,
self.openstack, command)

View File

@ -14,6 +14,8 @@
# under the License.
#
import json
import mock
from osc_lib.tests import utils
@ -201,6 +203,22 @@ ALLOCATION = {
'node_uuid': baremetal_uuid,
}
baremetal_deploy_template_uuid = 'ddd-tttttt-dddd'
baremetal_deploy_template_name = 'DeployTemplate-name'
baremetal_deploy_template_steps = json.dumps([{
'interface': 'raid',
'step': 'create_configuration',
'args': {},
'priority': 10
}])
baremetal_deploy_template_extra = {'key1': 'value1', 'key2': 'value2'}
DEPLOY_TEMPLATE = {
'uuid': baremetal_deploy_template_uuid,
'name': baremetal_deploy_template_name,
'steps': baremetal_deploy_template_steps,
'extra': baremetal_deploy_template_extra,
}
class TestBaremetal(utils.TestCommand):

View File

@ -0,0 +1,450 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
import copy
import json
import mock
from osc_lib.tests import utils as osctestutils
from ironicclient import exc
from ironicclient.osc.v1 import baremetal_deploy_template
from ironicclient.tests.unit.osc.v1 import fakes as baremetal_fakes
class TestBaremetalDeployTemplate(baremetal_fakes.TestBaremetal):
def setUp(self):
super(TestBaremetalDeployTemplate, self).setUp()
self.baremetal_mock = self.app.client_manager.baremetal
self.baremetal_mock.reset_mock()
class TestCreateBaremetalDeployTemplate(TestBaremetalDeployTemplate):
def setUp(self):
super(TestCreateBaremetalDeployTemplate, self).setUp()
self.baremetal_mock.deploy_template.create.return_value = (
baremetal_fakes.FakeBaremetalResource(
None,
copy.deepcopy(baremetal_fakes.DEPLOY_TEMPLATE),
loaded=True,
))
# Get the command object to test
self.cmd = baremetal_deploy_template.CreateBaremetalDeployTemplate(
self.app, None)
def test_baremetal_deploy_template_create(self):
arglist = [
baremetal_fakes.baremetal_deploy_template_name,
'--steps', baremetal_fakes.baremetal_deploy_template_steps,
]
verifylist = [
('name', baremetal_fakes.baremetal_deploy_template_name),
('steps', baremetal_fakes.baremetal_deploy_template_steps),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
# Set expected values
args = {
'name': baremetal_fakes.baremetal_deploy_template_name,
'steps': json.loads(
baremetal_fakes.baremetal_deploy_template_steps),
}
self.baremetal_mock.deploy_template.create.assert_called_once_with(
**args)
def test_baremetal_deploy_template_create_uuid(self):
arglist = [
baremetal_fakes.baremetal_deploy_template_name,
'--steps', baremetal_fakes.baremetal_deploy_template_steps,
'--uuid', baremetal_fakes.baremetal_deploy_template_uuid,
]
verifylist = [
('name', baremetal_fakes.baremetal_deploy_template_name),
('steps', baremetal_fakes.baremetal_deploy_template_steps),
('uuid', baremetal_fakes.baremetal_deploy_template_uuid),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
# Set expected values
args = {
'name': baremetal_fakes.baremetal_deploy_template_name,
'steps': json.loads(
baremetal_fakes.baremetal_deploy_template_steps),
'uuid': baremetal_fakes.baremetal_deploy_template_uuid,
}
self.baremetal_mock.deploy_template.create.assert_called_once_with(
**args)
def test_baremetal_deploy_template_create_no_name(self):
arglist = [
'--steps', baremetal_fakes.baremetal_deploy_template_steps,
]
verifylist = [
('steps', baremetal_fakes.baremetal_deploy_template_steps),
]
self.assertRaises(osctestutils.ParserException,
self.check_parser,
self.cmd, arglist, verifylist)
self.assertFalse(self.baremetal_mock.deploy_template.create.called)
def test_baremetal_deploy_template_create_no_steps(self):
arglist = [
'--name', baremetal_fakes.baremetal_deploy_template_name,
]
verifylist = [
('name', baremetal_fakes.baremetal_deploy_template_name),
]
self.assertRaises(osctestutils.ParserException,
self.check_parser,
self.cmd, arglist, verifylist)
self.assertFalse(self.baremetal_mock.deploy_template.create.called)
class TestShowBaremetalDeployTemplate(TestBaremetalDeployTemplate):
def setUp(self):
super(TestShowBaremetalDeployTemplate, self).setUp()
self.baremetal_mock.deploy_template.get.return_value = (
baremetal_fakes.FakeBaremetalResource(
None,
copy.deepcopy(baremetal_fakes.DEPLOY_TEMPLATE),
loaded=True))
self.cmd = baremetal_deploy_template.ShowBaremetalDeployTemplate(
self.app, None)
def test_baremetal_deploy_template_show(self):
arglist = [baremetal_fakes.baremetal_deploy_template_uuid]
verifylist = [('template',
baremetal_fakes.baremetal_deploy_template_uuid)]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
# Set expected values
args = [baremetal_fakes.baremetal_deploy_template_uuid]
self.baremetal_mock.deploy_template.get.assert_called_with(
*args, fields=None)
collist = (
'extra',
'name',
'steps',
'uuid')
self.assertEqual(collist, columns)
datalist = (
baremetal_fakes.baremetal_deploy_template_extra,
baremetal_fakes.baremetal_deploy_template_name,
baremetal_fakes.baremetal_deploy_template_steps,
baremetal_fakes.baremetal_deploy_template_uuid)
self.assertEqual(datalist, tuple(data))
def test_baremetal_deploy_template_show_no_template(self):
arglist = []
verifylist = []
self.assertRaises(osctestutils.ParserException,
self.check_parser,
self.cmd, arglist, verifylist)
class TestBaremetalDeployTemplateSet(TestBaremetalDeployTemplate):
def setUp(self):
super(TestBaremetalDeployTemplateSet, self).setUp()
self.baremetal_mock.deploy_template.update.return_value = (
baremetal_fakes.FakeBaremetalResource(
None,
copy.deepcopy(baremetal_fakes.DEPLOY_TEMPLATE),
loaded=True))
self.cmd = baremetal_deploy_template.SetBaremetalDeployTemplate(
self.app, None)
def test_baremetal_deploy_template_set_name(self):
new_name = 'foo'
arglist = [
baremetal_fakes.baremetal_deploy_template_uuid,
'--name', new_name]
verifylist = [
('template', baremetal_fakes.baremetal_deploy_template_uuid),
('name', new_name)]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.baremetal_mock.deploy_template.update.assert_called_once_with(
baremetal_fakes.baremetal_deploy_template_uuid,
[{'path': '/name', 'value': new_name, 'op': 'add'}])
def test_baremetal_deploy_template_set_steps(self):
arglist = [
baremetal_fakes.baremetal_deploy_template_uuid,
'--steps', baremetal_fakes.baremetal_deploy_template_steps]
verifylist = [
('template', baremetal_fakes.baremetal_deploy_template_uuid),
('steps', baremetal_fakes.baremetal_deploy_template_steps)]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
expected_steps = json.loads(
baremetal_fakes.baremetal_deploy_template_steps)
self.cmd.take_action(parsed_args)
self.baremetal_mock.deploy_template.update.assert_called_once_with(
baremetal_fakes.baremetal_deploy_template_uuid,
[{'path': '/steps', 'value': expected_steps, 'op': 'add'}])
def test_baremetal_deploy_template_set_no_options(self):
arglist = []
verifylist = []
self.assertRaises(osctestutils.ParserException,
self.check_parser,
self.cmd, arglist, verifylist)
class TestBaremetalDeployTemplateUnset(TestBaremetalDeployTemplate):
def setUp(self):
super(TestBaremetalDeployTemplateUnset, self).setUp()
self.baremetal_mock.deploy_template.update.return_value = (
baremetal_fakes.FakeBaremetalResource(
None,
copy.deepcopy(baremetal_fakes.DEPLOY_TEMPLATE),
loaded=True))
self.cmd = baremetal_deploy_template.UnsetBaremetalDeployTemplate(
self.app, None)
def test_baremetal_deploy_template_unset_extra(self):
arglist = [
baremetal_fakes.baremetal_deploy_template_uuid, '--extra', 'key1']
verifylist = [('template',
baremetal_fakes.baremetal_deploy_template_uuid),
('extra', ['key1'])]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.baremetal_mock.deploy_template.update.assert_called_once_with(
baremetal_fakes.baremetal_deploy_template_uuid,
[{'path': '/extra/key1', 'op': 'remove'}])
def test_baremetal_deploy_template_unset_multiple_extras(self):
arglist = [
baremetal_fakes.baremetal_deploy_template_uuid,
'--extra', 'key1', '--extra', 'key2']
verifylist = [('template',
baremetal_fakes.baremetal_deploy_template_uuid),
('extra', ['key1', 'key2'])]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.baremetal_mock.deploy_template.update.assert_called_once_with(
baremetal_fakes.baremetal_deploy_template_uuid,
[{'path': '/extra/key1', 'op': 'remove'},
{'path': '/extra/key2', 'op': 'remove'}])
def test_baremetal_deploy_template_unset_no_options(self):
arglist = []
verifylist = []
self.assertRaises(osctestutils.ParserException,
self.check_parser,
self.cmd, arglist, verifylist)
def test_baremetal_deploy_template_unset_no_property(self):
uuid = baremetal_fakes.baremetal_deploy_template_uuid
arglist = [uuid]
verifylist = [('template', uuid)]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.assertFalse(self.baremetal_mock.deploy_template.update.called)
class TestBaremetalDeployTemplateDelete(TestBaremetalDeployTemplate):
def setUp(self):
super(TestBaremetalDeployTemplateDelete, self).setUp()
self.cmd = baremetal_deploy_template.DeleteBaremetalDeployTemplate(
self.app, None)
def test_baremetal_deploy_template_delete(self):
arglist = ['zzz-zzzzzz-zzzz']
verifylist = []
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
args = 'zzz-zzzzzz-zzzz'
self.baremetal_mock.deploy_template.delete.assert_called_with(args)
def test_baremetal_deploy_template_delete_multiple(self):
arglist = ['zzz-zzzzzz-zzzz', 'fakename']
verifylist = []
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
args = ['zzz-zzzzzz-zzzz', 'fakename']
self.baremetal_mock.deploy_template.delete.has_calls(
[mock.call(x) for x in args])
self.assertEqual(
2, self.baremetal_mock.deploy_template.delete.call_count)
def test_baremetal_deploy_template_delete_multiple_with_fail(self):
arglist = ['zzz-zzzzzz-zzzz', 'badname']
verifylist = []
self.baremetal_mock.deploy_template.delete.side_effect = [
'', exc.ClientException]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.assertRaises(exc.ClientException,
self.cmd.take_action,
parsed_args)
args = ['zzz-zzzzzz-zzzz', 'badname']
self.baremetal_mock.deploy_template.delete.has_calls(
[mock.call(x) for x in args])
self.assertEqual(
2, self.baremetal_mock.deploy_template.delete.call_count)
def test_baremetal_deploy_template_delete_no_template(self):
arglist = []
verifylist = []
self.assertRaises(osctestutils.ParserException,
self.check_parser,
self.cmd, arglist, verifylist)
class TestBaremetalDeployTemplateList(TestBaremetalDeployTemplate):
def setUp(self):
super(TestBaremetalDeployTemplateList, self).setUp()
self.baremetal_mock.deploy_template.list.return_value = [
baremetal_fakes.FakeBaremetalResource(
None,
copy.deepcopy(baremetal_fakes.DEPLOY_TEMPLATE),
loaded=True)
]
self.cmd = baremetal_deploy_template.ListBaremetalDeployTemplate(
self.app, None)
def test_baremetal_deploy_template_list(self):
arglist = []
verifylist = []
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
kwargs = {
'marker': None,
'limit': None}
self.baremetal_mock.deploy_template.list.assert_called_with(**kwargs)
collist = (
"UUID",
"Name")
self.assertEqual(collist, columns)
datalist = ((
baremetal_fakes.baremetal_deploy_template_uuid,
baremetal_fakes.baremetal_deploy_template_name
), )
self.assertEqual(datalist, tuple(data))
def test_baremetal_deploy_template_list_long(self):
arglist = ['--long']
verifylist = [('detail', True)]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
kwargs = {
'detail': True,
'marker': None,
'limit': None,
}
self.baremetal_mock.deploy_template.list.assert_called_with(**kwargs)
collist = ('UUID', 'Name', 'Steps', 'Extra', 'Created At',
'Updated At')
self.assertEqual(collist, columns)
datalist = ((
baremetal_fakes.baremetal_deploy_template_uuid,
baremetal_fakes.baremetal_deploy_template_name,
baremetal_fakes.baremetal_deploy_template_steps,
baremetal_fakes.baremetal_deploy_template_extra,
'',
'',
), )
self.assertEqual(datalist, tuple(data))
def test_baremetal_deploy_template_list_fields(self):
arglist = ['--fields', 'uuid', 'steps']
verifylist = [('fields', [['uuid', 'steps']])]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
kwargs = {
'marker': None,
'limit': None,
'detail': False,
'fields': ('uuid', 'steps')
}
self.baremetal_mock.deploy_template.list.assert_called_with(**kwargs)
def test_baremetal_deploy_template_list_fields_multiple(self):
arglist = ['--fields', 'uuid', 'name', '--fields', 'steps']
verifylist = [('fields', [['uuid', 'name'], ['steps']])]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
kwargs = {
'marker': None,
'limit': None,
'detail': False,
'fields': ('uuid', 'name', 'steps')
}
self.baremetal_mock.deploy_template.list.assert_called_with(**kwargs)
def test_baremetal_deploy_template_list_invalid_fields(self):
arglist = ['--fields', 'uuid', 'invalid']
verifylist = [('fields', [['uuid', 'invalid']])]
self.assertRaises(osctestutils.ParserException,
self.check_parser,
self.cmd, arglist, verifylist)

View File

@ -0,0 +1,291 @@
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import copy
import testtools
from testtools.matchers import HasLength
from ironicclient import exc
from ironicclient.tests.unit import utils
import ironicclient.v1.deploy_template
DEPLOY_TEMPLATE = {'uuid': '11111111-2222-3333-4444-555555555555',
'name': 'fake-template',
'steps': {},
'extra': {}}
DEPLOY_TEMPLATE2 = {'uuid': '55555555-4444-3333-2222-111111111111',
'name': 'fake-template2',
'steps': {},
'extra': {}}
CREATE_DEPLOY_TEMPLATE = copy.deepcopy(DEPLOY_TEMPLATE)
del CREATE_DEPLOY_TEMPLATE['uuid']
CREATE_DEPLOY_TEMPLATE_WITH_UUID = copy.deepcopy(DEPLOY_TEMPLATE)
UPDATED_DEPLOY_TEMPLATE = copy.deepcopy(DEPLOY_TEMPLATE)
NEW_NAME = 'fake-template3'
UPDATED_DEPLOY_TEMPLATE['name'] = NEW_NAME
fake_responses = {
'/v1/deploy_templates':
{
'GET': (
{},
{"deploy_templates": [DEPLOY_TEMPLATE]},
),
'POST': (
{},
CREATE_DEPLOY_TEMPLATE,
),
},
'/v1/deploy_templates/?detail=True':
{
'GET': (
{},
{"deploy_templates": [DEPLOY_TEMPLATE]},
),
},
'/v1/deploy_templates/?fields=uuid,name':
{
'GET': (
{},
{"deploy_templates": [DEPLOY_TEMPLATE]},
),
},
'/v1/deploy_templates/%s' % DEPLOY_TEMPLATE['uuid']:
{
'GET': (
{},
DEPLOY_TEMPLATE,
),
'DELETE': (
{},
None,
),
'PATCH': (
{},
UPDATED_DEPLOY_TEMPLATE,
),
},
'/v1/deploy_templates/%s?fields=uuid,name' % DEPLOY_TEMPLATE['uuid']:
{
'GET': (
{},
DEPLOY_TEMPLATE,
),
},
}
fake_responses_pagination = {
'/v1/deploy_templates':
{
'GET': (
{},
{"deploy_templates": [DEPLOY_TEMPLATE],
"next": "http://127.0.0.1:6385/v1/deploy_templates/?limit=1"}
),
},
'/v1/deploy_templates/?limit=1':
{
'GET': (
{},
{"deploy_templates": [DEPLOY_TEMPLATE2]}
),
},
'/v1/deploy_templates/?marker=%s' % DEPLOY_TEMPLATE['uuid']:
{
'GET': (
{},
{"deploy_templates": [DEPLOY_TEMPLATE2]}
),
},
}
fake_responses_sorting = {
'/v1/deploy_templates/?sort_key=updated_at':
{
'GET': (
{},
{"deploy_templates": [DEPLOY_TEMPLATE2, DEPLOY_TEMPLATE]}
),
},
'/v1/deploy_templates/?sort_dir=desc':
{
'GET': (
{},
{"deploy_templates": [DEPLOY_TEMPLATE2, DEPLOY_TEMPLATE]}
),
},
}
class DeployTemplateManagerTest(testtools.TestCase):
def setUp(self):
super(DeployTemplateManagerTest, self).setUp()
self.api = utils.FakeAPI(fake_responses)
self.mgr = ironicclient.v1.deploy_template.DeployTemplateManager(
self.api)
def test_deploy_templates_list(self):
deploy_templates = self.mgr.list()
expect = [
('GET', '/v1/deploy_templates', {}, None),
]
self.assertEqual(expect, self.api.calls)
self.assertEqual(1, len(deploy_templates))
def test_deploy_templates_list_detail(self):
deploy_templates = self.mgr.list(detail=True)
expect = [
('GET', '/v1/deploy_templates/?detail=True', {}, None),
]
self.assertEqual(expect, self.api.calls)
self.assertEqual(1, len(deploy_templates))
def test_deploy_template_list_fields(self):
deploy_templates = self.mgr.list(fields=['uuid', 'name'])
expect = [
('GET', '/v1/deploy_templates/?fields=uuid,name', {}, None),
]
self.assertEqual(expect, self.api.calls)
self.assertEqual(1, len(deploy_templates))
def test_deploy_template_list_detail_and_fields_fail(self):
self.assertRaises(exc.InvalidAttribute, self.mgr.list,
detail=True, fields=['uuid', 'name'])
def test_deploy_templates_list_limit(self):
self.api = utils.FakeAPI(fake_responses_pagination)
self.mgr = ironicclient.v1.deploy_template.DeployTemplateManager(
self.api)
deploy_templates = self.mgr.list(limit=1)
expect = [
('GET', '/v1/deploy_templates/?limit=1', {}, None),
]
self.assertEqual(expect, self.api.calls)
self.assertThat(deploy_templates, HasLength(1))
def test_deploy_templates_list_marker(self):
self.api = utils.FakeAPI(fake_responses_pagination)
self.mgr = ironicclient.v1.deploy_template.DeployTemplateManager(
self.api)
deploy_templates = self.mgr.list(marker=DEPLOY_TEMPLATE['uuid'])
expect = [
('GET',
'/v1/deploy_templates/?marker=%s' % DEPLOY_TEMPLATE['uuid'], {},
None),
]
self.assertEqual(expect, self.api.calls)
self.assertThat(deploy_templates, HasLength(1))
def test_deploy_templates_list_pagination_no_limit(self):
self.api = utils.FakeAPI(fake_responses_pagination)
self.mgr = ironicclient.v1.deploy_template.DeployTemplateManager(
self.api)
deploy_templates = self.mgr.list(limit=0)
expect = [
('GET', '/v1/deploy_templates', {}, None),
('GET', '/v1/deploy_templates/?limit=1', {}, None)
]
self.assertEqual(expect, self.api.calls)
self.assertThat(deploy_templates, HasLength(2))
def test_deploy_templates_list_sort_key(self):
self.api = utils.FakeAPI(fake_responses_sorting)
self.mgr = ironicclient.v1.deploy_template.DeployTemplateManager(
self.api)
deploy_templates = self.mgr.list(sort_key='updated_at')
expect = [
('GET', '/v1/deploy_templates/?sort_key=updated_at', {}, None)
]
self.assertEqual(expect, self.api.calls)
self.assertEqual(2, len(deploy_templates))
def test_deploy_templates_list_sort_dir(self):
self.api = utils.FakeAPI(fake_responses_sorting)
self.mgr = ironicclient.v1.deploy_template.DeployTemplateManager(
self.api)
deploy_templates = self.mgr.list(sort_dir='desc')
expect = [
('GET', '/v1/deploy_templates/?sort_dir=desc', {}, None)
]
self.assertEqual(expect, self.api.calls)
self.assertEqual(2, len(deploy_templates))
def test_deploy_templates_show(self):
deploy_template = self.mgr.get(DEPLOY_TEMPLATE['uuid'])
expect = [
('GET', '/v1/deploy_templates/%s' % DEPLOY_TEMPLATE['uuid'], {},
None),
]
self.assertEqual(expect, self.api.calls)
self.assertEqual(DEPLOY_TEMPLATE['uuid'], deploy_template.uuid)
self.assertEqual(DEPLOY_TEMPLATE['name'], deploy_template.name)
self.assertEqual(DEPLOY_TEMPLATE['steps'], deploy_template.steps)
self.assertEqual(DEPLOY_TEMPLATE['extra'], deploy_template.extra)
def test_deploy_template_show_fields(self):
deploy_template = self.mgr.get(DEPLOY_TEMPLATE['uuid'],
fields=['uuid', 'name'])
expect = [
('GET', '/v1/deploy_templates/%s?fields=uuid,name' %
DEPLOY_TEMPLATE['uuid'], {}, None),
]
self.assertEqual(expect, self.api.calls)
self.assertEqual(DEPLOY_TEMPLATE['uuid'], deploy_template.uuid)
self.assertEqual(DEPLOY_TEMPLATE['name'], deploy_template.name)
def test_create(self):
deploy_template = self.mgr.create(**CREATE_DEPLOY_TEMPLATE)
expect = [
('POST', '/v1/deploy_templates', {}, CREATE_DEPLOY_TEMPLATE),
]
self.assertEqual(expect, self.api.calls)
self.assertTrue(deploy_template)
def test_create_with_uuid(self):
deploy_template = self.mgr.create(**CREATE_DEPLOY_TEMPLATE_WITH_UUID)
expect = [
('POST', '/v1/deploy_templates', {},
CREATE_DEPLOY_TEMPLATE_WITH_UUID),
]
self.assertEqual(expect, self.api.calls)
self.assertTrue(deploy_template)
def test_delete(self):
deploy_template = self.mgr.delete(
template_id=DEPLOY_TEMPLATE['uuid'])
expect = [
('DELETE', '/v1/deploy_templates/%s' % DEPLOY_TEMPLATE['uuid'], {},
None),
]
self.assertEqual(expect, self.api.calls)
self.assertIsNone(deploy_template)
def test_update(self):
patch = {'op': 'replace',
'value': NEW_NAME,
'path': '/name'}
deploy_template = self.mgr.update(
template_id=DEPLOY_TEMPLATE['uuid'], patch=patch)
expect = [
('PATCH', '/v1/deploy_templates/%s' % DEPLOY_TEMPLATE['uuid'],
{}, patch),
]
self.assertEqual(expect, self.api.calls)
self.assertEqual(NEW_NAME, deploy_template.name)

View File

@ -23,6 +23,7 @@ from ironicclient import exc
from ironicclient.v1 import allocation
from ironicclient.v1 import chassis
from ironicclient.v1 import conductor
from ironicclient.v1 import deploy_template
from ironicclient.v1 import driver
from ironicclient.v1 import events
from ironicclient.v1 import node
@ -103,6 +104,8 @@ class Client(object):
self.conductor = conductor.ConductorManager(self.http_client)
self.events = events.EventManager(self.http_client)
self.allocation = allocation.AllocationManager(self.http_client)
self.deploy_template = deploy_template.DeployTemplateManager(
self.http_client)
@property
def current_api_version(self):

View File

@ -0,0 +1,86 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from ironicclient.common import base
from ironicclient.common.i18n import _
from ironicclient.common import utils
from ironicclient import exc
class DeployTemplate(base.Resource):
def __repr__(self):
return "<DeployTemplate %s>" % self._info
class DeployTemplateManager(base.CreateManager):
resource_class = DeployTemplate
_creation_attributes = ['extra', 'name', 'steps', 'uuid']
_resource_name = 'deploy_templates'
def list(self, limit=None, marker=None, sort_key=None, sort_dir=None,
detail=False, fields=None):
"""Retrieve a list of deploy templates.
:param marker: Optional, the UUID of a deploy template, eg the last
template from a previous result set. Return the next
result set.
:param limit: The maximum number of results to return per
request, if:
1) limit > 0, the maximum number of deploy templates to return.
2) limit == 0, return the entire list of deploy templates.
3) limit param is NOT specified (None), the number of items
returned respect the maximum imposed by the Ironic API
(see Ironic's api.max_limit option).
:param sort_key: Optional, field used for sorting.
:param sort_dir: Optional, direction of sorting, either 'asc' (the
default) or 'desc'.
:param detail: Optional, boolean whether to return detailed information
about deploy templates.
:param fields: Optional, a list with a specified set of fields
of the resource to be returned. Can not be used
when 'detail' is set.
:returns: A list of deploy templates.
"""
if limit is not None:
limit = int(limit)
if detail and fields:
raise exc.InvalidAttribute(_("Can't fetch a subset of fields "
"with 'detail' set"))
filters = utils.common_filters(marker, limit, sort_key, sort_dir,
fields, detail=detail)
path = ''
if filters:
path += '?' + '&'.join(filters)
if limit is None:
return self._list(self._path(path), "deploy_templates")
else:
return self._list_pagination(self._path(path), "deploy_templates",
limit=limit)
def get(self, template_id, fields=None):
return self._get(resource_id=template_id, fields=fields)
def delete(self, template_id):
return self._delete(resource_id=template_id)
def update(self, template_id, patch):
return self._update(resource_id=template_id, patch=patch)

View File

@ -104,6 +104,7 @@ class Resource(object):
'reservation': 'Reservation',
'resource_class': 'Resource Class',
'state': 'State',
'steps': 'Steps',
'target_power_state': 'Target Power State',
'target_provision_state': 'Target Provision State',
'target_raid_config': 'Target RAID configuration',
@ -513,3 +514,21 @@ ALLOCATION_RESOURCE = Resource(
'node_uuid',
],
)
# Deploy templates
DEPLOY_TEMPLATE_DETAILED_RESOURCE = Resource(
['uuid',
'name',
'steps',
'extra',
'created_at',
'updated_at',
],
sort_excluded=['extra', 'steps']
)
DEPLOY_TEMPLATE_RESOURCE = Resource(
['uuid',
'name',
],
)

View File

@ -0,0 +1,11 @@
---
features:
- |
Adds Python API and CLI for the deploy templates API introduced in API
version 1.55. The following new commands are available:
* ``openstack baremetal deploy template create``
* ``openstack baremetal deploy template delete``
* ``openstack baremetal deploy template list``
* ``openstack baremetal deploy template set``
* ``openstack baremetal deploy template show``

View File

@ -40,6 +40,12 @@ openstack.baremetal.v1 =
baremetal_chassis_show = ironicclient.osc.v1.baremetal_chassis:ShowBaremetalChassis
baremetal_chassis_unset = ironicclient.osc.v1.baremetal_chassis:UnsetBaremetalChassis
baremetal_create = ironicclient.osc.v1.baremetal_create:CreateBaremetal
baremetal_deploy_template_create = ironicclient.osc.v1.baremetal_deploy_template:CreateBaremetalDeployTemplate
baremetal_deploy_template_delete = ironicclient.osc.v1.baremetal_deploy_template:DeleteBaremetalDeployTemplate
baremetal_deploy_template_list = ironicclient.osc.v1.baremetal_deploy_template:ListBaremetalDeployTemplate
baremetal_deploy_template_set = ironicclient.osc.v1.baremetal_deploy_template:SetBaremetalDeployTemplate
baremetal_deploy_template_unset = ironicclient.osc.v1.baremetal_deploy_template:UnsetBaremetalDeployTemplate
baremetal_deploy_template_show = ironicclient.osc.v1.baremetal_deploy_template:ShowBaremetalDeployTemplate
baremetal_driver_list = ironicclient.osc.v1.baremetal_driver:ListBaremetalDriver
baremetal_driver_passthru_call = ironicclient.osc.v1.baremetal_driver:PassthruCallBaremetalDriver
baremetal_driver_passthru_list = ironicclient.osc.v1.baremetal_driver:PassthruListBaremetalDriver