From 66528c7c8d4fce5cb36e9e676ac7a367b646f20c Mon Sep 17 00:00:00 2001 From: Mark Goddard Date: Tue, 2 May 2017 21:04:44 +0100 Subject: [PATCH] Add physical network to port commands This commit adds support to the openstack client for the physical network attribute of baremetal ports for the following commands: - create - list - set - show - unset It also adds support to the ironic client for the physical network attribute of baremetal ports for the following commands: - port-create - port-list - port-show - port-update For OSC, the latest API version has been bumped to 1.34. Change-Id: I26948e274b9b0bed170f11de45f0ade48d8b3285 Depends-On: I7023a1d6618608c867c31396fa677d3016ca493e Partial-Bug: #1666009 --- ironicclient/osc/plugin.py | 2 +- ironicclient/osc/v1/baremetal_port.py | 30 ++++++++- ironicclient/tests/unit/osc/v1/fakes.py | 1 + .../tests/unit/osc/v1/test_baremetal_port.py | 62 ++++++++++++++++++- ironicclient/tests/unit/v1/test_port.py | 4 ++ ironicclient/tests/unit/v1/test_port_shell.py | 17 ++++- ironicclient/v1/port.py | 4 +- ironicclient/v1/port_shell.py | 6 +- ironicclient/v1/resource_fields.py | 2 + ...ort-physical-network-6ea8860d773e473c.yaml | 5 ++ 10 files changed, 125 insertions(+), 8 deletions(-) create mode 100644 releasenotes/notes/port-physical-network-6ea8860d773e473c.yaml diff --git a/ironicclient/osc/plugin.py b/ironicclient/osc/plugin.py index a1c88edc1..41d7853ba 100644 --- a/ironicclient/osc/plugin.py +++ b/ironicclient/osc/plugin.py @@ -26,7 +26,7 @@ LOG = logging.getLogger(__name__) API_VERSION_OPTION = 'os_baremetal_api_version' API_NAME = 'baremetal' -LAST_KNOWN_API_VERSION = 33 +LAST_KNOWN_API_VERSION = 34 API_VERSIONS = { '1.%d' % i: 'ironicclient.v1.client.Client' for i in range(1, LAST_KNOWN_API_VERSION + 1) diff --git a/ironicclient/osc/v1/baremetal_port.py b/ironicclient/osc/v1/baremetal_port.py index 8e57465f5..3e934fec9 100644 --- a/ironicclient/osc/v1/baremetal_port.py +++ b/ironicclient/osc/v1/baremetal_port.py @@ -91,6 +91,13 @@ class CreateBaremetalPort(command.ShowOne): metavar='', help=_("UUID of the port group that this port belongs to.")) + parser.add_argument( + '--physical-network', + dest='physical_network', + metavar='', + help=_("Name of the physical network to which this port is " + "connected.")) + return parser def take_action(self, parsed_args): @@ -110,7 +117,8 @@ class CreateBaremetalPort(command.ShowOne): parsed_args.local_link_connection_deprecated) field_list = ['address', 'uuid', 'extra', 'node_uuid', 'pxe_enabled', - 'local_link_connection', 'portgroup_uuid'] + 'local_link_connection', 'portgroup_uuid', + 'physical_network'] 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') @@ -201,6 +209,12 @@ class UnsetBaremetalPort(command.Command): dest='portgroup', help=_("Remove port from the port group")) + parser.add_argument( + '--physical-network', + action='store_true', + dest='physical_network', + help=_("Unset the physical network on this baremetal port.")) + return parser def take_action(self, parsed_args): @@ -215,6 +229,9 @@ class UnsetBaremetalPort(command.Command): if parsed_args.portgroup: properties.extend(utils.args_array_to_patch('remove', ['portgroup_uuid'])) + if parsed_args.physical_network: + properties.extend(utils.args_array_to_patch('remove', + ['physical_network'])) if properties: baremetal_client.port.update(parsed_args.port, properties) @@ -285,6 +302,12 @@ class SetBaremetalPort(command.Command): help=_("Indicates that this port should not be used when " "PXE booting this node") ) + parser.add_argument( + '--physical-network', + metavar='', + dest='physical_network', + help=_("Set the name of the physical network to which this port " + "is connected.")) return parser @@ -314,6 +337,11 @@ class SetBaremetalPort(command.Command): if parsed_args.pxe_enabled is not None: properties.extend(utils.args_array_to_patch( 'add', ['pxe_enabled=%s' % parsed_args.pxe_enabled])) + if parsed_args.physical_network: + physical_network = ["physical_network=%s" % + parsed_args.physical_network] + properties.extend(utils.args_array_to_patch('add', + physical_network)) if properties: baremetal_client.port.update(parsed_args.port, properties) diff --git a/ironicclient/tests/unit/osc/v1/fakes.py b/ironicclient/tests/unit/osc/v1/fakes.py index 9254155c5..50340e11a 100644 --- a/ironicclient/tests/unit/osc/v1/fakes.py +++ b/ironicclient/tests/unit/osc/v1/fakes.py @@ -52,6 +52,7 @@ baremetal_port_uuid = 'zzz-zzzzzz-zzzz' baremetal_port_address = 'AA:BB:CC:DD:EE:FF' baremetal_port_extra = {'key1': 'value1', 'key2': 'value2'} +baremetal_port_physical_network = 'physnet1' BAREMETAL_PORT = { 'uuid': baremetal_port_uuid, diff --git a/ironicclient/tests/unit/osc/v1/test_baremetal_port.py b/ironicclient/tests/unit/osc/v1/test_baremetal_port.py index 7b9bc1bb7..beae396da 100644 --- a/ironicclient/tests/unit/osc/v1/test_baremetal_port.py +++ b/ironicclient/tests/unit/osc/v1/test_baremetal_port.py @@ -225,6 +225,35 @@ class TestCreateBaremetalPort(TestBaremetalPort): self.baremetal_mock.port.create.assert_called_once_with(**args) + def test_baremetal_port_create_physical_network(self): + arglist = [ + baremetal_fakes.baremetal_port_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_port_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_port_address, + 'node_uuid': baremetal_fakes.baremetal_uuid, + 'physical_network': baremetal_fakes.baremetal_port_physical_network + } + + self.baremetal_mock.port.create.assert_called_once_with(**args) + class TestShowBaremetalPort(TestBaremetalPort): def setUp(self): @@ -356,6 +385,18 @@ class TestBaremetalPortUnset(TestBaremetalPort): 'port', [{'path': '/portgroup_uuid', 'op': 'remove'}]) + def test_baremetal_port_unset_physical_network(self): + arglist = ['port', '--physical-network'] + verifylist = [('port', 'port'), + ('physical_network', True)] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.cmd.take_action(parsed_args) + self.baremetal_mock.port.update.assert_called_once_with( + 'port', + [{'path': '/physical_network', 'op': 'remove'}]) + class TestBaremetalPortSet(TestBaremetalPort): def setUp(self): @@ -476,6 +517,23 @@ class TestBaremetalPortSet(TestBaremetalPort): baremetal_fakes.baremetal_port_uuid, [{'path': '/pxe_enabled', 'value': 'False', 'op': 'add'}]) + def test_baremetal_port_set_physical_network(self): + new_physical_network = 'physnet2' + arglist = [ + baremetal_fakes.baremetal_port_uuid, + '--physical-network', new_physical_network] + verifylist = [ + ('port', baremetal_fakes.baremetal_port_uuid), + ('physical_network', new_physical_network)] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.cmd.take_action(parsed_args) + self.baremetal_mock.port.update.assert_called_once_with( + baremetal_fakes.baremetal_port_uuid, + [{'path': '/physical_network', 'value': new_physical_network, + 'op': 'add'}]) + def test_baremetal_port_set_no_options(self): arglist = [] verifylist = [] @@ -645,7 +703,8 @@ class TestBaremetalPortList(TestBaremetalPort): collist = ('UUID', 'Address', 'Created At', 'Extra', 'Node UUID', 'Local Link Connection', 'Portgroup UUID', - 'PXE boot enabled', 'Updated At', 'Internal Info') + 'PXE boot enabled', 'Physical Network', 'Updated At', + 'Internal Info') self.assertEqual(collist, columns) datalist = (( @@ -658,6 +717,7 @@ class TestBaremetalPortList(TestBaremetalPort): '', '', '', + '', '' ), ) self.assertEqual(datalist, tuple(data)) diff --git a/ironicclient/tests/unit/v1/test_port.py b/ironicclient/tests/unit/v1/test_port.py index 6eac45ac0..8817381e6 100644 --- a/ironicclient/tests/unit/v1/test_port.py +++ b/ironicclient/tests/unit/v1/test_port.py @@ -28,6 +28,7 @@ PORT = {'uuid': '11111111-2222-3333-4444-555555555555', 'pxe_enabled': True, 'local_link_connection': {}, 'portgroup_uuid': '55555555-4444-3333-2222-111111111111', + 'physical_network': 'physnet1', 'extra': {}} PORT2 = {'uuid': '55555555-4444-3333-2222-111111111111', @@ -36,6 +37,7 @@ PORT2 = {'uuid': '55555555-4444-3333-2222-111111111111', 'pxe_enabled': True, 'local_link_connection': {}, 'portgroup_uuid': '55555555-4444-3333-2222-111111111111', + 'physical_network': 'physnet2', 'extra': {}} CREATE_PORT = copy.deepcopy(PORT) @@ -300,6 +302,7 @@ class PortManagerTest(testtools.TestCase): self.assertEqual(PORT['local_link_connection'], port.local_link_connection) self.assertEqual(PORT['portgroup_uuid'], port.portgroup_uuid) + self.assertEqual(PORT['physical_network'], port.physical_network) def test_ports_show_by_address(self): port = self.mgr.get_by_address(PORT['address']) @@ -315,6 +318,7 @@ class PortManagerTest(testtools.TestCase): self.assertEqual(PORT['local_link_connection'], port.local_link_connection) self.assertEqual(PORT['portgroup_uuid'], port.portgroup_uuid) + self.assertEqual(PORT['physical_network'], port.physical_network) def test_port_show_fields(self): port = self.mgr.get(PORT['uuid'], fields=['uuid', 'address']) diff --git a/ironicclient/tests/unit/v1/test_port_shell.py b/ironicclient/tests/unit/v1/test_port_shell.py index d797db11c..ce0e5876d 100644 --- a/ironicclient/tests/unit/v1/test_port_shell.py +++ b/ironicclient/tests/unit/v1/test_port_shell.py @@ -31,8 +31,9 @@ class PortShellTest(utils.BaseTestCase): with mock.patch.object(cliutils, 'print_dict', fake_print_dict): port = object() p_shell._print_port_show(port) - exp = ['address', 'created_at', 'extra', 'node_uuid', 'updated_at', - 'uuid', 'pxe_enabled', 'local_link_connection', 'internal_info', + exp = ['address', 'created_at', 'extra', 'node_uuid', + 'physical_network', 'updated_at', 'uuid', 'pxe_enabled', + 'local_link_connection', 'internal_info', 'portgroup_uuid'] act = actual.keys() self.assertEqual(sorted(exp), sorted(act)) @@ -288,6 +289,18 @@ class PortShellTest(utils.BaseTestCase): address='address', node_uuid='uuid', portgroup_uuid='portgroup-uuid') + def test_do_port_create_physical_network(self): + client_mock = mock.MagicMock() + args = mock.MagicMock() + args.address = 'address' + args.node_uuid = 'uuid' + args.physical_network = 'physnet1' + args.json = False + p_shell.do_port_create(client_mock, args) + client_mock.port.create.assert_called_once_with( + address='address', node_uuid='uuid', + physical_network='physnet1') + def test_do_port_delete(self): client_mock = mock.MagicMock() args = mock.MagicMock() diff --git a/ironicclient/v1/port.py b/ironicclient/v1/port.py index 61d405be5..384a849de 100644 --- a/ironicclient/v1/port.py +++ b/ironicclient/v1/port.py @@ -28,8 +28,8 @@ class Port(base.Resource): class PortManager(base.CreateManager): resource_class = Port _creation_attributes = ['address', 'extra', 'local_link_connection', - 'node_uuid', 'portgroup_uuid', 'pxe_enabled', - 'uuid'] + 'node_uuid', 'physical_network', 'portgroup_uuid', + 'pxe_enabled', 'uuid'] _resource_name = 'ports' def list(self, address=None, limit=None, marker=None, sort_key=None, diff --git a/ironicclient/v1/port_shell.py b/ironicclient/v1/port_shell.py index a6a0091e9..e360b6799 100644 --- a/ironicclient/v1/port_shell.py +++ b/ironicclient/v1/port_shell.py @@ -162,6 +162,10 @@ def do_port_list(cc, args): metavar='', help='Indicates whether this Port should be used when ' 'PXE booting this Node.') +@cliutils.arg( + '--physical-network', + metavar='', + help="Physical network of the port.") @cliutils.arg( '-e', '--extra', metavar="", @@ -176,7 +180,7 @@ def do_port_create(cc, args): """Create a new port.""" field_list = ['address', 'extra', 'node_uuid', 'uuid', 'local_link_connection', 'portgroup_uuid', - 'pxe_enabled'] + 'pxe_enabled', 'physical_network'] fields = dict((k, v) for (k, v) in vars(args).items() if k in field_list and not (v is None)) fields = utils.args_array_to_dict(fields, 'extra') diff --git a/ironicclient/v1/resource_fields.py b/ironicclient/v1/resource_fields.py index ae4969824..8ff5ad85d 100644 --- a/ironicclient/v1/resource_fields.py +++ b/ironicclient/v1/resource_fields.py @@ -106,6 +106,7 @@ class Resource(object): 'storage_interface': 'Storage Interface', 'vendor_interface': 'Vendor Interface', 'standalone_ports_supported': 'Standalone Ports Supported', + 'physical_network': 'Physical Network', 'id': 'ID', 'connector_id': 'Connector ID', } @@ -265,6 +266,7 @@ PORT_DETAILED_RESOURCE = Resource( 'local_link_connection', 'portgroup_uuid', 'pxe_enabled', + 'physical_network', 'updated_at', 'internal_info', ], diff --git a/releasenotes/notes/port-physical-network-6ea8860d773e473c.yaml b/releasenotes/notes/port-physical-network-6ea8860d773e473c.yaml new file mode 100644 index 000000000..420fcfdd9 --- /dev/null +++ b/releasenotes/notes/port-physical-network-6ea8860d773e473c.yaml @@ -0,0 +1,5 @@ +--- +features: + - | + Adds support for the ``port.physical_network`` field, which was introduced + in API version 1.34.