feat: add 'physical_network' and 'category' to portgroup object

The portgroup object added 'physical_network' and 'category' fields in
API 1.102 and 1.103 respectively.

Change-Id: Id12c56affb599ef98d102cf437bceffd993bea5f
Signed-off-by: Doug Goldstein <cardoe@cardoe.com>
This commit is contained in:
Doug Goldstein
2026-01-21 09:34:56 -06:00
parent 8a1ff4fc27
commit 3514f052dc
6 changed files with 187 additions and 6 deletions

View File

@@ -81,6 +81,17 @@ class CreateBaremetalPortGroup(command.ShowOne):
action='store_true',
help=_("Ports that are members of this port group "
"cannot be used as stand-alone ports."))
parser.add_argument(
'--physical-network',
dest='physical_network',
metavar='<physical network>',
help=_("Name of the physical network to which the ports in "
"this port group are connected."))
parser.add_argument(
'--category',
dest='category',
metavar='<port category>',
help=_("An optional category for the port group."))
return parser
@@ -89,7 +100,7 @@ class CreateBaremetalPortGroup(command.ShowOne):
baremetal_client = self.app.client_manager.baremetal
field_list = ['node_uuid', 'address', 'name', 'uuid', 'extra', 'mode',
'properties']
'properties', 'physical_network', 'category']
fields = dict((k, v) for (k, v) in vars(parsed_args).items()
if k in field_list and v is not None)
if parsed_args.support_standalone_ports:
@@ -352,6 +363,17 @@ class SetBaremetalPortGroup(command.Command):
help=_("Ports that are members of this port group "
"cannot be used as stand-alone ports.")
)
parser.add_argument(
'--physical-network',
metavar='<physical network>',
dest='physical_network',
help=_("Set a physical network for the ports in this port group"))
parser.add_argument(
'--category',
metavar='<category>',
dest='category',
help=_("Set a category for this port group"))
return parser
@@ -371,6 +393,16 @@ class SetBaremetalPortGroup(command.Command):
name = ["name=%s" % parsed_args.name]
properties.extend(utils.args_array_to_patch(
'add', name))
if parsed_args.physical_network:
physical_network = [
f"physical_network={parsed_args.physical_network}"
]
properties.extend(utils.args_array_to_patch(
'add', physical_network))
if parsed_args.category:
category = [f"category={parsed_args.category}"]
properties.extend(utils.args_array_to_patch(
'add', category))
if parsed_args.support_standalone_ports:
properties.extend(utils.args_array_to_patch(
'add', ["standalone_ports_supported=True"]))
@@ -432,6 +464,17 @@ class UnsetBaremetalPortGroup(command.Command):
help=_('Property to unset on this baremetal port group '
'(repeat option to unset multiple properties).'),
)
parser.add_argument(
'--physical-network',
action='store_true',
dest='physical_network',
help=_("Unset the physical network on this baremetal port group."))
parser.add_argument(
'--category',
dest='category',
action='store_true',
help=_("Unset the category for this port group."))
return parser
@@ -447,6 +490,12 @@ class UnsetBaremetalPortGroup(command.Command):
if parsed_args.address:
properties.extend(utils.args_array_to_patch('remove',
['address']))
if parsed_args.physical_network:
properties.extend(utils.args_array_to_patch('remove',
['physical_network']))
if parsed_args.category:
properties.extend(utils.args_array_to_patch('remove',
['category']))
if parsed_args.extra:
properties.extend(utils.args_array_to_patch('remove',
['extra/' + x for x in parsed_args.extra]))

View File

@@ -141,6 +141,7 @@ baremetal_portgroup_extra = {'key1': 'value1',
'key2': 'value2'}
baremetal_portgroup_properties = {'key1': 'value11',
'key2': 'value22'}
baremetal_portgroup_category = 'Green'
PORTGROUP = {'uuid': baremetal_portgroup_uuid,
'name': baremetal_portgroup_name,
@@ -149,6 +150,8 @@ PORTGROUP = {'uuid': baremetal_portgroup_uuid,
'extra': baremetal_portgroup_extra,
'mode': baremetal_portgroup_mode,
'properties': baremetal_portgroup_properties,
'physical_network': baremetal_port_physical_network,
'category': baremetal_portgroup_category,
}
VIFS = {'vifs': [{'id': 'aaa-aa'}]}

View File

@@ -219,6 +219,63 @@ class TestCreateBaremetalPortGroup(TestBaremetalPortGroup):
self.check_parser,
self.cmd, arglist, verifylist)
def test_baremetal_portgroup_create_physical_network(self):
arglist = [
'--address', baremetal_fakes.baremetal_portgroup_address,
'--node', baremetal_fakes.baremetal_uuid,
'--physical-network',
baremetal_fakes.baremetal_port_physical_network,
]
verifylist = [
('node_uuid', baremetal_fakes.baremetal_uuid),
('address', baremetal_fakes.baremetal_portgroup_address),
('physical_network',
baremetal_fakes.baremetal_port_physical_network),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
# DisplayCommandBase.take_action() returns two tuples
self.cmd.take_action(parsed_args)
# Set expected values
args = {
'address': baremetal_fakes.baremetal_portgroup_address,
'node_uuid': baremetal_fakes.baremetal_uuid,
'physical_network':
baremetal_fakes.baremetal_port_physical_network,
}
self.baremetal_mock.portgroup.create.assert_called_once_with(**args)
def test_baremetal_portgroup_create_category(self):
arglist = [
'--address', baremetal_fakes.baremetal_portgroup_address,
'--node', baremetal_fakes.baremetal_uuid,
'--category', baremetal_fakes.baremetal_portgroup_category,
]
verifylist = [
('node_uuid', baremetal_fakes.baremetal_uuid),
('address', baremetal_fakes.baremetal_portgroup_address),
('category', baremetal_fakes.baremetal_portgroup_category),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
# DisplayCommandBase.take_action() returns two tuples
self.cmd.take_action(parsed_args)
# Set expected values
args = {
'address': baremetal_fakes.baremetal_portgroup_address,
'node_uuid': baremetal_fakes.baremetal_uuid,
'category': baremetal_fakes.baremetal_portgroup_category,
}
self.baremetal_mock.portgroup.create.assert_called_once_with(**args)
class TestShowBaremetalPortGroup(TestBaremetalPortGroup):
@@ -251,16 +308,19 @@ class TestShowBaremetalPortGroup(TestBaremetalPortGroup):
self.baremetal_mock.portgroup.get.assert_called_with(*args,
fields=None)
collist = ('address', 'extra', 'mode', 'name', 'node_uuid',
'properties', 'uuid')
collist = ('address', 'category', 'extra', 'mode', 'name',
'node_uuid', 'physical_network', 'properties',
'uuid')
self.assertEqual(collist, columns)
datalist = (
baremetal_fakes.baremetal_portgroup_address,
baremetal_fakes.baremetal_portgroup_category,
baremetal_fakes.baremetal_portgroup_extra,
baremetal_fakes.baremetal_portgroup_mode,
baremetal_fakes.baremetal_portgroup_name,
baremetal_fakes.baremetal_uuid,
baremetal_fakes.baremetal_port_physical_network,
baremetal_fakes.baremetal_portgroup_properties,
baremetal_fakes.baremetal_portgroup_uuid,
)
@@ -385,7 +445,8 @@ class TestBaremetalPortGroupList(TestBaremetalPortGroup):
collist = ('UUID', 'Address', 'Created At', 'Extra',
'Standalone Ports Supported', 'Node UUID', 'Name',
'Updated At', 'Internal Info', 'Mode', 'Properties')
'Updated At', 'Internal Info', 'Mode', 'Properties',
'Physical Network', 'Category')
self.assertEqual(collist, columns)
datalist = ((baremetal_fakes.baremetal_portgroup_uuid,
@@ -398,7 +459,10 @@ class TestBaremetalPortGroupList(TestBaremetalPortGroup):
'',
'',
baremetal_fakes.baremetal_portgroup_mode,
baremetal_fakes.baremetal_portgroup_properties),)
baremetal_fakes.baremetal_portgroup_properties,
baremetal_fakes.baremetal_port_physical_network,
baremetal_fakes.baremetal_portgroup_category,
),)
self.assertEqual(datalist, tuple(data))
def test_baremetal_portgroup_list_fields(self):
@@ -670,6 +734,40 @@ class TestBaremetalPortGroupSet(TestBaremetalPortGroup):
self.cmd.take_action(parsed_args)
self.assertFalse(self.baremetal_mock.portgroup.update.called)
def test_baremetal_portgroup_set_physical_network(self):
new_portgroup_physnet = 'physnet2'
arglist = [
baremetal_fakes.baremetal_portgroup_uuid,
'--physical-network', new_portgroup_physnet]
verifylist = [
('portgroup', baremetal_fakes.baremetal_portgroup_uuid),
('physical_network', new_portgroup_physnet)]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.baremetal_mock.portgroup.update.assert_called_once_with(
baremetal_fakes.baremetal_portgroup_uuid,
[{'path': '/physical_network', 'value': new_portgroup_physnet,
'op': 'add'}])
def test_baremetal_portgroup_set_category(self):
new_portgroup_category = 'Purple'
arglist = [
baremetal_fakes.baremetal_portgroup_uuid,
'--category', new_portgroup_category]
verifylist = [
('portgroup', baremetal_fakes.baremetal_portgroup_uuid),
('category', new_portgroup_category)]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.baremetal_mock.portgroup.update.assert_called_once_with(
baremetal_fakes.baremetal_portgroup_uuid,
[{'path': '/category', 'value': new_portgroup_category,
'op': 'add'}])
class TestBaremetalPortGroupUnset(TestBaremetalPortGroup):
def setUp(self):
@@ -762,3 +860,25 @@ class TestBaremetalPortGroupUnset(TestBaremetalPortGroup):
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.assertFalse(self.baremetal_mock.portgroup.update.called)
def test_baremetal_portgroup_unset_physical_network(self):
arglist = ['portgroup', '--physical-network']
verifylist = [('physical_network', True)]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.baremetal_mock.portgroup.update.assert_called_once_with(
'portgroup',
[{'path': '/physical_network', 'op': 'remove'}])
def test_baremetal_portgroup_unset_category(self):
arglist = ['portgroup', '--category']
verifylist = [('category', True)]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.baremetal_mock.portgroup.update.assert_called_once_with(
'portgroup',
[{'path': '/category', 'op': 'remove'}])

View File

@@ -28,7 +28,7 @@ class PortgroupManager(base.CreateManager):
_resource_name = 'portgroups'
_creation_attributes = ['address', 'extra', 'name', 'node_uuid',
'standalone_ports_supported', 'mode', 'properties',
'uuid']
'uuid', 'physical_network', 'category']
def list(self, node=None, address=None, limit=None, marker=None,
sort_key=None, sort_dir=None, detail=False, fields=None,

View File

@@ -390,6 +390,8 @@ PORTGROUP_DETAILED_RESOURCE = Resource(
'internal_info',
'mode',
'properties',
'physical_network',
'category',
],
sort_excluded=[
'extra',

View File

@@ -0,0 +1,7 @@
---
features:
- |
Adds ``physical_network`` field and ``category`` field support, which is
introduced in ironic API 1.102 and 1.103 respectively. The ``physical_network``
field is reflected into the port objects that are part of the port group
while the ``category`` is informational text for trait based scheduling.