summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ironicclient/common/base.py17
-rw-r--r--ironicclient/common/http.py2
-rwxr-xr-xironicclient/osc/v1/baremetal_node.py113
-rw-r--r--ironicclient/tests/unit/osc/v1/fakes.py1
-rw-r--r--ironicclient/tests/unit/osc/v1/test_baremetal_node.py186
-rw-r--r--ironicclient/tests/unit/v1/test_node.py73
-rw-r--r--ironicclient/tests/unit/v1/test_node_shell.py1
-rw-r--r--ironicclient/v1/node.py47
-rw-r--r--ironicclient/v1/resource_fields.py7
-rw-r--r--releasenotes/notes/traits-support-8864f6816abecdb2.yaml20
-rw-r--r--setup.cfg3
11 files changed, 464 insertions, 6 deletions
diff --git a/ironicclient/common/base.py b/ironicclient/common/base.py
index 294f06a..563ceb0 100644
--- a/ironicclient/common/base.py
+++ b/ironicclient/common/base.py
@@ -170,25 +170,34 @@ class Manager(object):
return object_list
- def _list(self, url, response_key=None, obj_class=None, body=None):
+ def __list(self, url, response_key=None, body=None):
resp, body = self.api.json_request('GET', url)
+ data = self._format_body_data(body, response_key)
+ return data
+ def _list(self, url, response_key=None, obj_class=None, body=None):
if obj_class is None:
obj_class = self.resource_class
- data = self._format_body_data(body, response_key)
+ data = self.__list(url, response_key=response_key, body=body)
return [obj_class(self, res, loaded=True) for res in data if res]
+ def _list_primitives(self, url, response_key=None):
+ return self.__list(url, response_key=response_key)
+
def _update(self, resource_id, patch, method='PATCH'):
"""Update a resource.
:param resource_id: Resource identifier.
- :param patch: New version of a given resource.
+ :param patch: New version of a given resource, a dictionary or None.
:param method: Name of the method for the request.
"""
url = self._path(resource_id)
- resp, body = self.api.json_request(method, url, body=patch)
+ kwargs = {}
+ if patch is not None:
+ kwargs['body'] = patch
+ resp, body = self.api.json_request(method, url, **kwargs)
# PATCH/PUT requests may not return a body
if body:
return self.resource_class(self, body)
diff --git a/ironicclient/common/http.py b/ironicclient/common/http.py
index e56bef0..35d1ccb 100644
--- a/ironicclient/common/http.py
+++ b/ironicclient/common/http.py
@@ -44,7 +44,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 = 35
+LAST_KNOWN_API_VERSION = 37
LATEST_VERSION = '1.{}'.format(LAST_KNOWN_API_VERSION)
LOG = logging.getLogger(__name__)
diff --git a/ironicclient/osc/v1/baremetal_node.py b/ironicclient/osc/v1/baremetal_node.py
index 990905f..350ba52 100755
--- a/ironicclient/osc/v1/baremetal_node.py
+++ b/ironicclient/osc/v1/baremetal_node.py
@@ -1574,3 +1574,116 @@ class InjectNmiBaremetalNode(command.Command):
baremetal_client = self.app.client_manager.baremetal
baremetal_client.node.inject_nmi(parsed_args.node)
+
+
+class ListTraitsBaremetalNode(command.Lister):
+ """List a node's traits."""
+
+ log = logging.getLogger(__name__ + ".ListTraitsBaremetalNode")
+
+ def get_parser(self, prog_name):
+ parser = super(ListTraitsBaremetalNode, self).get_parser(prog_name)
+
+ parser.add_argument(
+ 'node',
+ metavar='<node>',
+ help=_("Name or UUID of the node"))
+
+ return parser
+
+ def take_action(self, parsed_args):
+ self.log.debug("take_action(%s)", parsed_args)
+
+ labels = res_fields.TRAIT_RESOURCE.labels
+
+ baremetal_client = self.app.client_manager.baremetal
+ traits = baremetal_client.node.get_traits(parsed_args.node)
+
+ return (labels, [[trait] for trait in traits])
+
+
+class AddTraitBaremetalNode(command.Command):
+ """Add traits to a node."""
+
+ log = logging.getLogger(__name__ + ".AddTraitBaremetalNode")
+
+ def get_parser(self, prog_name):
+ parser = super(AddTraitBaremetalNode, self).get_parser(prog_name)
+
+ parser.add_argument(
+ 'node',
+ metavar='<node>',
+ help=_("Name or UUID of the node"))
+ parser.add_argument(
+ 'traits',
+ nargs='+',
+ metavar='<trait>',
+ help=_("Trait(s) to add"))
+
+ 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 trait in parsed_args.traits:
+ try:
+ baremetal_client.node.add_trait(parsed_args.node, trait)
+ print(_('Added trait %s') % trait)
+ except exc.ClientException as e:
+ failures.append(_("Failed to add trait %(trait)s: %(error)s")
+ % {'trait': trait, 'error': e})
+
+ if failures:
+ raise exc.ClientException("\n".join(failures))
+
+
+class RemoveTraitBaremetalNode(command.Command):
+ """Remove trait(s) from a node."""
+
+ log = logging.getLogger(__name__ + ".RemoveTraitBaremetalNode")
+
+ def get_parser(self, prog_name):
+ parser = super(RemoveTraitBaremetalNode, self).get_parser(prog_name)
+
+ parser.add_argument(
+ 'node',
+ metavar='<node>',
+ help=_("Name or UUID of the node"))
+ all_or_trait = parser.add_mutually_exclusive_group(required=True)
+ all_or_trait.add_argument(
+ '--all',
+ dest='remove_all',
+ action='store_true',
+ help=_("Remove all traits"))
+ all_or_trait.add_argument(
+ 'traits',
+ metavar='<trait>',
+ nargs='*',
+ default=[],
+ help=_("Trait(s) to remove"))
+
+ return parser
+
+ def take_action(self, parsed_args):
+ self.log.debug("take_action(%s)", parsed_args)
+
+ baremetal_client = self.app.client_manager.baremetal
+
+ failures = []
+ if parsed_args.remove_all:
+ baremetal_client.node.remove_all_traits(parsed_args.node)
+ else:
+ for trait in parsed_args.traits:
+ try:
+ baremetal_client.node.remove_trait(parsed_args.node, trait)
+ print(_('Removed trait %s') % trait)
+ except exc.ClientException as e:
+ failures.append(_("Failed to remove trait %(trait)s: "
+ "%(error)s")
+ % {'trait': trait, 'error': e})
+
+ if failures:
+ raise exc.ClientException("\n".join(failures))
diff --git a/ironicclient/tests/unit/osc/v1/fakes.py b/ironicclient/tests/unit/osc/v1/fakes.py
index faa479a..37e04e1 100644
--- a/ironicclient/tests/unit/osc/v1/fakes.py
+++ b/ironicclient/tests/unit/osc/v1/fakes.py
@@ -137,6 +137,7 @@ PORTGROUP = {'uuid': baremetal_portgroup_uuid,
}
VIFS = {'vifs': [{'id': 'aaa-aa'}]}
+TRAITS = ['CUSTOM_FOO', 'CUSTOM_BAR']
baremetal_volume_connector_uuid = 'vvv-cccccc-vvvv'
baremetal_volume_connector_type = 'iqn'
diff --git a/ironicclient/tests/unit/osc/v1/test_baremetal_node.py b/ironicclient/tests/unit/osc/v1/test_baremetal_node.py
index ef62756..ca74b0b 100644
--- a/ironicclient/tests/unit/osc/v1/test_baremetal_node.py
+++ b/ironicclient/tests/unit/osc/v1/test_baremetal_node.py
@@ -591,7 +591,7 @@ class TestBaremetalList(TestBaremetal):
'Current RAID configuration', 'Reservation',
'Resource Class',
'Target Power State', 'Target Provision State',
- 'Target RAID configuration',
+ 'Target RAID configuration', 'Traits',
'Updated At', 'Inspection Finished At',
'Inspection Started At', 'UUID', 'Name',
'Boot Interface', 'Console Interface',
@@ -627,6 +627,7 @@ class TestBaremetalList(TestBaremetal):
'',
'',
'',
+ '',
baremetal_fakes.baremetal_uuid,
baremetal_fakes.baremetal_name,
'',
@@ -2663,3 +2664,186 @@ class TestBaremetalInject(TestBaremetal):
self.baremetal_mock.node.inject_nmi.assert_called_once_with(
'node_uuid')
+
+
+class TestListTraits(TestBaremetal):
+ def setUp(self):
+ super(TestListTraits, self).setUp()
+
+ self.baremetal_mock.node.get_traits.return_value = (
+ baremetal_fakes.TRAITS)
+
+ # Get the command object to test
+ self.cmd = baremetal_node.ListTraitsBaremetalNode(self.app, None)
+
+ def test_baremetal_list_traits(self):
+ arglist = ['node_uuid']
+ verifylist = [('node', 'node_uuid')]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.cmd.take_action(parsed_args)
+
+ self.baremetal_mock.node.get_traits.assert_called_once_with(
+ 'node_uuid')
+
+
+class TestAddTrait(TestBaremetal):
+ def setUp(self):
+ super(TestAddTrait, self).setUp()
+
+ # Get the command object to test
+ self.cmd = baremetal_node.AddTraitBaremetalNode(self.app, None)
+
+ def test_baremetal_add_trait(self):
+ arglist = ['node_uuid', 'CUSTOM_FOO']
+ verifylist = [('node', 'node_uuid'), ('traits', ['CUSTOM_FOO'])]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.cmd.take_action(parsed_args)
+
+ self.baremetal_mock.node.add_trait.assert_called_once_with(
+ 'node_uuid', 'CUSTOM_FOO')
+
+ def test_baremetal_add_traits_multiple(self):
+ arglist = ['node_uuid', 'CUSTOM_FOO', 'CUSTOM_BAR']
+ verifylist = [('node', 'node_uuid'),
+ ('traits', ['CUSTOM_FOO', 'CUSTOM_BAR'])]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.cmd.take_action(parsed_args)
+
+ expected_calls = [
+ mock.call('node_uuid', 'CUSTOM_FOO'),
+ mock.call('node_uuid', 'CUSTOM_BAR'),
+ ]
+ self.assertEqual(expected_calls,
+ self.baremetal_mock.node.add_trait.call_args_list)
+
+ def test_baremetal_add_traits_multiple_with_failure(self):
+ arglist = ['node_uuid', 'CUSTOM_FOO', 'CUSTOM_BAR']
+ verifylist = [('node', 'node_uuid'),
+ ('traits', ['CUSTOM_FOO', 'CUSTOM_BAR'])]
+
+ self.baremetal_mock.node.add_trait.side_effect = [
+ '', exc.ClientException]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.assertRaises(exc.ClientException,
+ self.cmd.take_action,
+ parsed_args)
+
+ expected_calls = [
+ mock.call('node_uuid', 'CUSTOM_FOO'),
+ mock.call('node_uuid', 'CUSTOM_BAR'),
+ ]
+ self.assertEqual(expected_calls,
+ self.baremetal_mock.node.add_trait.call_args_list)
+
+ def test_baremetal_add_traits_no_traits(self):
+ arglist = ['node_uuid']
+ verifylist = [('node', 'node_uuid')]
+
+ self.assertRaises(oscutils.ParserException,
+ self.check_parser,
+ self.cmd,
+ arglist,
+ verifylist)
+
+
+class TestRemoveTrait(TestBaremetal):
+ def setUp(self):
+ super(TestRemoveTrait, self).setUp()
+
+ # Get the command object to test
+ self.cmd = baremetal_node.RemoveTraitBaremetalNode(self.app, None)
+
+ def test_baremetal_remove_trait(self):
+ arglist = ['node_uuid', 'CUSTOM_FOO']
+ verifylist = [('node', 'node_uuid'), ('traits', ['CUSTOM_FOO'])]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.cmd.take_action(parsed_args)
+
+ self.baremetal_mock.node.remove_trait.assert_called_once_with(
+ 'node_uuid', 'CUSTOM_FOO')
+
+ def test_baremetal_remove_trait_multiple(self):
+ arglist = ['node_uuid', 'CUSTOM_FOO', 'CUSTOM_BAR']
+ verifylist = [('node', 'node_uuid'),
+ ('traits', ['CUSTOM_FOO', 'CUSTOM_BAR'])]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.cmd.take_action(parsed_args)
+
+ expected_calls = [
+ mock.call('node_uuid', 'CUSTOM_FOO'),
+ mock.call('node_uuid', 'CUSTOM_BAR'),
+ ]
+ self.assertEqual(expected_calls,
+ self.baremetal_mock.node.remove_trait.call_args_list)
+
+ def test_baremetal_remove_trait_multiple_with_failure(self):
+ arglist = ['node_uuid', 'CUSTOM_FOO', 'CUSTOM_BAR']
+ verifylist = [('node', 'node_uuid'),
+ ('traits', ['CUSTOM_FOO', 'CUSTOM_BAR'])]
+
+ self.baremetal_mock.node.remove_trait.side_effect = [
+ '', exc.ClientException]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.assertRaises(exc.ClientException,
+ self.cmd.take_action,
+ parsed_args)
+
+ expected_calls = [
+ mock.call('node_uuid', 'CUSTOM_FOO'),
+ mock.call('node_uuid', 'CUSTOM_BAR'),
+ ]
+ self.assertEqual(expected_calls,
+ self.baremetal_mock.node.remove_trait.call_args_list)
+
+ def test_baremetal_remove_trait_all(self):
+ arglist = ['node_uuid', '--all']
+ verifylist = [('node', 'node_uuid'), ('remove_all', True)]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.cmd.take_action(parsed_args)
+
+ self.baremetal_mock.node.remove_all_traits.assert_called_once_with(
+ 'node_uuid')
+
+ def test_baremetal_remove_trait_traits_and_all(self):
+ arglist = ['node_uuid', 'CUSTOM_FOO', '--all']
+ verifylist = [('node', 'node_uuid'),
+ ('traits', ['CUSTOM_FOO']),
+ ('remove_all', True)]
+
+ self.assertRaises(oscutils.ParserException,
+ self.check_parser,
+ self.cmd,
+ arglist,
+ verifylist)
+
+ self.baremetal_mock.node.remove_all_traits.assert_not_called()
+ self.baremetal_mock.node.remove_trait.assert_not_called()
+
+ def test_baremetal_remove_traits_no_traits_no_all(self):
+ arglist = ['node_uuid']
+ verifylist = [('node', 'node_uuid')]
+
+ self.assertRaises(oscutils.ParserException,
+ self.check_parser,
+ self.cmd,
+ arglist,
+ verifylist)
+
+ self.baremetal_mock.node.remove_all_traits.assert_not_called()
+ self.baremetal_mock.node.remove_trait.assert_not_called()
diff --git a/ironicclient/tests/unit/v1/test_node.py b/ironicclient/tests/unit/v1/test_node.py
index a60ad31..7fde845 100644
--- a/ironicclient/tests/unit/v1/test_node.py
+++ b/ironicclient/tests/unit/v1/test_node.py
@@ -103,6 +103,7 @@ NODE_VENDOR_PASSTHRU_METHOD = {"heartbeat": {"attach": "false",
"async": "true"}}
VIFS = {'vifs': [{'id': 'aaa-aaa'}]}
+TRAITS = {'traits': ['CUSTOM_FOO', 'CUSTOM_BAR']}
CREATE_NODE = copy.deepcopy(NODE1)
del CREATE_NODE['uuid']
@@ -448,6 +449,32 @@ fake_responses = {
{},
VIFS,
),
+ },
+ '/v1/nodes/%s/traits' % NODE1['uuid']:
+ {
+ 'GET': (
+ {},
+ TRAITS,
+ ),
+ 'PUT': (
+ {},
+ None,
+ ),
+ 'DELETE': (
+ {},
+ None,
+ ),
+ },
+ '/v1/nodes/%s/traits/CUSTOM_FOO' % NODE1['uuid']:
+ {
+ 'PUT': (
+ {},
+ None,
+ ),
+ 'DELETE': (
+ {},
+ None,
+ ),
}
}
@@ -1641,3 +1668,49 @@ class NodeManagerTest(testtools.TestCase):
self.assertEqual(4, mock_get.call_count)
mock_sleep.assert_called_with(node._DEFAULT_POLL_INTERVAL)
self.assertEqual(3, mock_sleep.call_count)
+
+ def test_node_get_traits(self):
+ traits = self.mgr.get_traits(NODE1['uuid'])
+ expect = [
+ ('GET', '/v1/nodes/%s/traits' % NODE1['uuid'], {}, None),
+ ]
+ self.assertEqual(expect, self.api.calls)
+ self.assertEqual(TRAITS['traits'], traits)
+
+ def test_node_add_trait(self):
+ trait = 'CUSTOM_FOO'
+ resp = self.mgr.add_trait(NODE1['uuid'], trait)
+ expect = [
+ ('PUT', '/v1/nodes/%s/traits/%s' % (NODE1['uuid'], trait),
+ {}, None),
+ ]
+ self.assertEqual(expect, self.api.calls)
+ self.assertIsNone(resp)
+
+ def test_node_set_traits(self):
+ traits = ['CUSTOM_FOO', 'CUSTOM_BAR']
+ resp = self.mgr.set_traits(NODE1['uuid'], traits)
+ expect = [
+ ('PUT', '/v1/nodes/%s/traits' % NODE1['uuid'],
+ {}, {'traits': traits}),
+ ]
+ self.assertEqual(expect, self.api.calls)
+ self.assertIsNone(resp)
+
+ def test_node_remove_all_traits(self):
+ resp = self.mgr.remove_all_traits(NODE1['uuid'])
+ expect = [
+ ('DELETE', '/v1/nodes/%s/traits' % NODE1['uuid'], {}, None),
+ ]
+ self.assertEqual(expect, self.api.calls)
+ self.assertIsNone(resp)
+
+ def test_node_remove_trait(self):
+ trait = 'CUSTOM_FOO'
+ resp = self.mgr.remove_trait(NODE1['uuid'], trait)
+ expect = [
+ ('DELETE', '/v1/nodes/%s/traits/%s' % (NODE1['uuid'], trait),
+ {}, None),
+ ]
+ self.assertEqual(expect, self.api.calls)
+ self.assertIsNone(resp)
diff --git a/ironicclient/tests/unit/v1/test_node_shell.py b/ironicclient/tests/unit/v1/test_node_shell.py
index b30eb20..f861572 100644
--- a/ironicclient/tests/unit/v1/test_node_shell.py
+++ b/ironicclient/tests/unit/v1/test_node_shell.py
@@ -65,6 +65,7 @@ class NodeShellTest(utils.BaseTestCase):
'resource_class',
'target_power_state',
'target_provision_state',
+ 'traits',
'updated_at',
'inspection_finished_at',
'inspection_started_at',
diff --git a/ironicclient/v1/node.py b/ironicclient/v1/node.py
index 135a67a..b8571ab 100644
--- a/ironicclient/v1/node.py
+++ b/ironicclient/v1/node.py
@@ -553,6 +553,53 @@ class NodeManager(base.CreateManager):
path = "%s/vendor_passthru/methods" % node_ident
return self._get_as_dict(path)
+ def get_traits(self, node_ident):
+ """Get traits for a node.
+
+ :param node_ident: node UUID or name.
+ """
+ path = "%s/traits" % node_ident
+ return self._list_primitives(self._path(path), 'traits')
+
+ def add_trait(self, node_ident, trait):
+ """Add a trait to a node.
+
+ :param node_ident: node UUID or name.
+ :param trait: trait to add to the node.
+ """
+ path = "%s/traits/%s" % (node_ident, trait)
+ return self.update(path, None, http_method='PUT')
+
+ def set_traits(self, node_ident, traits):
+ """Set traits for a node.
+
+ Removes any existing traits and adds the traits passed in to this
+ method.
+
+ :param node_ident: node UUID or name.
+ :param traits: list of traits to add to the node.
+ """
+ path = "%s/traits" % node_ident
+ body = {'traits': traits}
+ return self.update(path, body, http_method='PUT')
+
+ def remove_trait(self, node_ident, trait):
+ """Remove a trait from a node.
+
+ :param node_ident: node UUID or name.
+ :param trait: trait to remove from the node.
+ """
+ path = "%s/traits/%s" % (node_ident, trait)
+ return self.delete(path)
+
+ def remove_all_traits(self, node_ident):
+ """Remove all traits from a node.
+
+ :param node_ident: node UUID or name.
+ """
+ path = "%s/traits" % node_ident
+ return self.delete(path)
+
def wait_for_provision_state(self, node_ident, expected_state,
timeout=0,
poll_interval=_DEFAULT_POLL_INTERVAL,
diff --git a/ironicclient/v1/resource_fields.py b/ironicclient/v1/resource_fields.py
index 8ff5ad8..d027135 100644
--- a/ironicclient/v1/resource_fields.py
+++ b/ironicclient/v1/resource_fields.py
@@ -87,6 +87,7 @@ class Resource(object):
'target_power_state': 'Target Power State',
'target_provision_state': 'Target Provision State',
'target_raid_config': 'Target RAID configuration',
+ 'traits': 'Traits',
'type': 'Type',
'updated_at': 'Updated At',
'uuid': 'UUID',
@@ -210,6 +211,7 @@ NODE_DETAILED_RESOURCE = Resource(
'target_power_state',
'target_provision_state',
'target_raid_config',
+ 'traits',
'updated_at',
'inspection_finished_at',
'inspection_started_at',
@@ -239,6 +241,7 @@ NODE_DETAILED_RESOURCE = Resource(
'properties',
'raid_config',
'target_raid_config',
+ 'traits',
])
NODE_RESOURCE = Resource(
['uuid',
@@ -319,6 +322,10 @@ VIF_RESOURCE = Resource(
['id'],
)
+TRAIT_RESOURCE = Resource(
+ ['traits'],
+)
+
# Drivers
DRIVER_DETAILED_RESOURCE = Resource(
['name',
diff --git a/releasenotes/notes/traits-support-8864f6816abecdb2.yaml b/releasenotes/notes/traits-support-8864f6816abecdb2.yaml
new file mode 100644
index 0000000..d4dc5f3
--- /dev/null
+++ b/releasenotes/notes/traits-support-8864f6816abecdb2.yaml
@@ -0,0 +1,20 @@
+---
+features:
+ - |
+ Adds support for reading and modifying traits for a node, including adding
+ traits to the detailed output of a node. This is available starting
+ with Bare Metal API version 1.37.
+
+ The new commands are:
+
+ * ``openstack baremetal node trait list <node>``
+ * ``openstack baremetal node add trait <node> <trait> [...]``
+ * ``openstack baremetal node remove trait <node> [<trait> [...]] [--all]``
+
+ It also adds the following methods to the Python SDK:
+
+ * ``NodeManager.get_traits``
+ * ``NodeManager.add_trait``
+ * ``NodeManager.set_traits``
+ * ``NodeManager.remove_trait``
+ * ``NodeManager.remove_all_traits``
diff --git a/setup.cfg b/setup.cfg
index 31d6f57..4a40c8d 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -42,6 +42,7 @@ openstack.baremetal.v1 =
baremetal_driver_raid_property_list = ironicclient.osc.v1.baremetal_driver:ListBaremetalDriverRaidProperty
baremetal_driver_show = ironicclient.osc.v1.baremetal_driver:ShowBaremetalDriver
baremetal_node_abort = ironicclient.osc.v1.baremetal_node:AbortBaremetalNode
+ baremetal_node_add_trait = ironicclient.osc.v1.baremetal_node:AddTraitBaremetalNode
baremetal_node_adopt = ironicclient.osc.v1.baremetal_node:AdoptBaremetalNode
baremetal_node_boot_device_set = ironicclient.osc.v1.baremetal_node:BootdeviceSetBaremetalNode
baremetal_node_boot_device_show = ironicclient.osc.v1.baremetal_node:BootdeviceShowBaremetalNode
@@ -64,8 +65,10 @@ openstack.baremetal.v1 =
baremetal_node_provide = ironicclient.osc.v1.baremetal_node:ProvideBaremetalNode
baremetal_node_reboot = ironicclient.osc.v1.baremetal_node:RebootBaremetalNode
baremetal_node_rebuild = ironicclient.osc.v1.baremetal_node:RebuildBaremetalNode
+ baremetal_node_remove_trait = ironicclient.osc.v1.baremetal_node:RemoveTraitBaremetalNode
baremetal_node_set = ironicclient.osc.v1.baremetal_node:SetBaremetalNode
baremetal_node_show = ironicclient.osc.v1.baremetal_node:ShowBaremetalNode
+ baremetal_node_trait_list = ironicclient.osc.v1.baremetal_node:ListTraitsBaremetalNode
baremetal_node_undeploy = ironicclient.osc.v1.baremetal_node:UndeployBaremetalNode
baremetal_node_unset = ironicclient.osc.v1.baremetal_node:UnsetBaremetalNode
baremetal_node_validate = ironicclient.osc.v1.baremetal_node:ValidateBaremetalNode