Add support for node inventory
Adds REST API version 1.81, which supports querying a node's hardware inventory using the python client library, and also using the baremetal CLI using the `baremetal node inventory save [--file <filename>] <node>` command. Change-Id: Idf6ba4cbf7035e0617edc67f55c93b434d9a76aa
This commit is contained in:
parent
a01ba938c2
commit
0b6b282d40
@ -37,7 +37,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 = 78
|
||||
LAST_KNOWN_API_VERSION = 81
|
||||
LATEST_VERSION = '1.{}'.format(LAST_KNOWN_API_VERSION)
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
@ -18,6 +18,7 @@ import argparse
|
||||
import itertools
|
||||
import json
|
||||
import logging
|
||||
import sys
|
||||
|
||||
from osc_lib.command import command
|
||||
from osc_lib import utils as oscutils
|
||||
@ -2233,3 +2234,33 @@ class NodeHistoryEventGet(command.ShowOne):
|
||||
data.pop('links')
|
||||
|
||||
return self.dict2columns(data)
|
||||
|
||||
|
||||
class NodeInventorySave(command.Command):
|
||||
"""Get hardware inventory of a node (in JSON format) or save it to file."""
|
||||
|
||||
log = logging.getLogger(__name__ + ".NodeInventorySave")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(NodeInventorySave, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
"node",
|
||||
metavar="<node>",
|
||||
help=_("Name or UUID of the node"))
|
||||
parser.add_argument("--file",
|
||||
metavar="<filename>",
|
||||
help="Save inspection data to file with name "
|
||||
"(default: stdout).")
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug("take_action(%s)", parsed_args)
|
||||
|
||||
baremetal_client = self.app.client_manager.baremetal
|
||||
inventory = baremetal_client.node.get_inventory(parsed_args.node)
|
||||
|
||||
if parsed_args.file:
|
||||
with open(parsed_args.file, 'w') as fp:
|
||||
json.dump(inventory, fp)
|
||||
else:
|
||||
json.dump(inventory, sys.stdout)
|
||||
|
@ -241,6 +241,23 @@ NODE_HISTORY = [
|
||||
'links': {'href': 'url', 'rel': 'self'},
|
||||
}
|
||||
]
|
||||
NODE_INVENTORY = [
|
||||
{
|
||||
'inventory':
|
||||
{
|
||||
'memory': {'physical_mb': 3072},
|
||||
'cpu': {'count': 1,
|
||||
'model_name': 'qemu64',
|
||||
'architecture': 'x86_64'},
|
||||
'disks': [{'name': 'testvm2.qcow2',
|
||||
'size': 11811160064}],
|
||||
'interfaces': [{'mac_address': '52:54:00:11:2d:26'}],
|
||||
'system_vendor': {'product_name': 'testvm2',
|
||||
'manufacturer': 'Sushy Emulator'},
|
||||
'boot': {'current_boot_mode': 'uefi'}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
class TestBaremetal(utils.TestCommand):
|
||||
|
@ -15,7 +15,9 @@
|
||||
#
|
||||
|
||||
import copy
|
||||
import io
|
||||
import json
|
||||
import sys
|
||||
from unittest import mock
|
||||
|
||||
from osc_lib.tests import utils as oscutils
|
||||
@ -4302,3 +4304,40 @@ class TestNodeHistoryEventGet(TestBaremetal):
|
||||
|
||||
self.assertEqual(expected_columns, columns)
|
||||
self.assertEqual(expected_data, tuple(data))
|
||||
|
||||
|
||||
class TestNodeInventorySave(TestBaremetal):
|
||||
def setUp(self):
|
||||
super(TestNodeInventorySave, self).setUp()
|
||||
|
||||
self.baremetal_mock.node.get_inventory.return_value = (
|
||||
baremetal_fakes.NODE_INVENTORY[0])
|
||||
|
||||
# Get the command object to test
|
||||
self.cmd = baremetal_node.NodeInventorySave(self.app, None)
|
||||
|
||||
def test_baremetal_node_inventory_save(self):
|
||||
arglist = ['node_uuid']
|
||||
verifylist = [('node', 'node_uuid')]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
buf = io.StringIO()
|
||||
with mock.patch.object(sys, 'stdout', buf):
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
self.baremetal_mock.node.get_inventory.assert_called_once_with(
|
||||
'node_uuid')
|
||||
|
||||
expected_data = {'memory': {'physical_mb': 3072},
|
||||
'cpu': {'count': 1,
|
||||
'model_name': 'qemu64',
|
||||
'architecture': 'x86_64'},
|
||||
'disks': [{'name': 'testvm2.qcow2',
|
||||
'size': 11811160064}],
|
||||
'interfaces': [{'mac_address': '52:54:00:11:2d:26'}],
|
||||
'system_vendor': {'product_name': 'testvm2',
|
||||
'manufacturer': 'Sushy Emulator'},
|
||||
'boot': {'current_boot_mode': 'uefi'}}
|
||||
inventory = json.loads(buf.getvalue())
|
||||
self.assertEqual(expected_data, inventory['inventory'])
|
||||
|
@ -108,6 +108,13 @@ NODE_VENDOR_PASSTHRU_METHOD = {"heartbeat": {"attach": "false",
|
||||
|
||||
VIFS = {'vifs': [{'id': 'aaa-aaa'}]}
|
||||
TRAITS = {'traits': ['CUSTOM_FOO', 'CUSTOM_BAR']}
|
||||
INVENTORY = {'inventory': [{'memory': {'physical_mb': '3072'},
|
||||
'cpu': {'count': 1, 'architecture': 'x86_64',
|
||||
'model_name': 'qemu64'},
|
||||
'disks': [{'name': 'testvm2.qcow2',
|
||||
'size': 11811160064}],
|
||||
'interfaces':
|
||||
[{'mac_address': '52:54:00:c7:02:45'}]}]}
|
||||
|
||||
CREATE_NODE = copy.deepcopy(NODE1)
|
||||
del CREATE_NODE['uuid']
|
||||
@ -543,6 +550,13 @@ fake_responses = {
|
||||
{},
|
||||
None,
|
||||
),
|
||||
},
|
||||
'/v1/nodes/%s/inventory' % NODE1['uuid']:
|
||||
{
|
||||
'GET': (
|
||||
{},
|
||||
INVENTORY,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@ -2148,3 +2162,11 @@ class NodeManagerTest(testtools.TestCase):
|
||||
]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertIsNone(resp)
|
||||
|
||||
def test_node_get_inventory(self):
|
||||
inventory = self.mgr.get_inventory(NODE1['uuid'])
|
||||
expect = [
|
||||
('GET', '/v1/nodes/%s/inventory' % NODE1['uuid'], {}, None),
|
||||
]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertEqual(INVENTORY, inventory)
|
||||
|
@ -1099,3 +1099,22 @@ class NodeManager(base.CreateManager):
|
||||
return self._get_as_dict(
|
||||
path, os_ironic_api_version=os_ironic_api_version,
|
||||
global_request_id=global_request_id)
|
||||
|
||||
def get_inventory(self,
|
||||
node_ident,
|
||||
os_ironic_api_version=None,
|
||||
global_request_id=None):
|
||||
"""Get the hardware inventory of the node.
|
||||
|
||||
Requires API version 1.81.
|
||||
|
||||
:param node_ident: The name or UUID of the node.
|
||||
:param os_ironic_api_version: String version (e.g. "1.81") to use for
|
||||
the request. If not specified, the client's default is used.
|
||||
:param global_request_id: String containing global request ID header
|
||||
value (in form "req-<UUID>") to use for the request.
|
||||
"""
|
||||
path = "%s/inventory" % node_ident
|
||||
return self._get_as_dict(
|
||||
path, os_ironic_api_version=os_ironic_api_version,
|
||||
global_request_id=global_request_id)
|
||||
|
@ -0,0 +1,7 @@
|
||||
features:
|
||||
- |
|
||||
Adds support for API version ``1.81``, allowing users to retrieve a node's
|
||||
hardware inventory using the
|
||||
``baremetal node inventory [--file <filename>] save <node>`` command.
|
||||
- Adds a ``get_inventory`` method to the python client library. This method
|
||||
allows operators to query recorded node inventory from an ironic API.
|
@ -73,6 +73,7 @@ openstack.baremetal.v1 =
|
||||
baremetal_node_history_list = ironicclient.osc.v1.baremetal_node:NodeHistoryList
|
||||
baremetal_node_history_get = ironicclient.osc.v1.baremetal_node:NodeHistoryEventGet
|
||||
baremetal_node_inspect = ironicclient.osc.v1.baremetal_node:InspectBaremetalNode
|
||||
baremetal_node_inventory_save = ironicclient.osc.v1.baremetal_node:NodeInventorySave
|
||||
baremetal_node_list = ironicclient.osc.v1.baremetal_node:ListBaremetalNode
|
||||
baremetal_node_maintenance_set = ironicclient.osc.v1.baremetal_node:MaintenanceSetBaremetalNode
|
||||
baremetal_node_maintenance_unset = ironicclient.osc.v1.baremetal_node:MaintenanceUnsetBaremetalNode
|
||||
|
Loading…
Reference in New Issue
Block a user