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
This commit is contained in:
Mark Goddard 2017-05-02 21:04:44 +01:00
parent 545b5c3019
commit 66528c7c8d
10 changed files with 125 additions and 8 deletions

View File

@ -26,7 +26,7 @@ LOG = logging.getLogger(__name__)
API_VERSION_OPTION = 'os_baremetal_api_version' API_VERSION_OPTION = 'os_baremetal_api_version'
API_NAME = 'baremetal' API_NAME = 'baremetal'
LAST_KNOWN_API_VERSION = 33 LAST_KNOWN_API_VERSION = 34
API_VERSIONS = { API_VERSIONS = {
'1.%d' % i: 'ironicclient.v1.client.Client' '1.%d' % i: 'ironicclient.v1.client.Client'
for i in range(1, LAST_KNOWN_API_VERSION + 1) for i in range(1, LAST_KNOWN_API_VERSION + 1)

View File

@ -91,6 +91,13 @@ class CreateBaremetalPort(command.ShowOne):
metavar='<uuid>', metavar='<uuid>',
help=_("UUID of the port group that this port belongs to.")) help=_("UUID of the port group that this port belongs to."))
parser.add_argument(
'--physical-network',
dest='physical_network',
metavar='<physical network>',
help=_("Name of the physical network to which this port is "
"connected."))
return parser return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
@ -110,7 +117,8 @@ class CreateBaremetalPort(command.ShowOne):
parsed_args.local_link_connection_deprecated) parsed_args.local_link_connection_deprecated)
field_list = ['address', 'uuid', 'extra', 'node_uuid', 'pxe_enabled', 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() fields = dict((k, v) for (k, v) in vars(parsed_args).items()
if k in field_list and v is not None) if k in field_list and v is not None)
fields = utils.args_array_to_dict(fields, 'extra') fields = utils.args_array_to_dict(fields, 'extra')
@ -201,6 +209,12 @@ class UnsetBaremetalPort(command.Command):
dest='portgroup', dest='portgroup',
help=_("Remove port from the port group")) 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 return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
@ -215,6 +229,9 @@ class UnsetBaremetalPort(command.Command):
if parsed_args.portgroup: if parsed_args.portgroup:
properties.extend(utils.args_array_to_patch('remove', properties.extend(utils.args_array_to_patch('remove',
['portgroup_uuid'])) ['portgroup_uuid']))
if parsed_args.physical_network:
properties.extend(utils.args_array_to_patch('remove',
['physical_network']))
if properties: if properties:
baremetal_client.port.update(parsed_args.port, 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 " help=_("Indicates that this port should not be used when "
"PXE booting this node") "PXE booting this node")
) )
parser.add_argument(
'--physical-network',
metavar='<physical network>',
dest='physical_network',
help=_("Set the name of the physical network to which this port "
"is connected."))
return parser return parser
@ -314,6 +337,11 @@ class SetBaremetalPort(command.Command):
if parsed_args.pxe_enabled is not None: if parsed_args.pxe_enabled is not None:
properties.extend(utils.args_array_to_patch( properties.extend(utils.args_array_to_patch(
'add', ['pxe_enabled=%s' % parsed_args.pxe_enabled])) '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: if properties:
baremetal_client.port.update(parsed_args.port, properties) baremetal_client.port.update(parsed_args.port, properties)

View File

@ -52,6 +52,7 @@ baremetal_port_uuid = 'zzz-zzzzzz-zzzz'
baremetal_port_address = 'AA:BB:CC:DD:EE:FF' baremetal_port_address = 'AA:BB:CC:DD:EE:FF'
baremetal_port_extra = {'key1': 'value1', baremetal_port_extra = {'key1': 'value1',
'key2': 'value2'} 'key2': 'value2'}
baremetal_port_physical_network = 'physnet1'
BAREMETAL_PORT = { BAREMETAL_PORT = {
'uuid': baremetal_port_uuid, 'uuid': baremetal_port_uuid,

View File

@ -225,6 +225,35 @@ class TestCreateBaremetalPort(TestBaremetalPort):
self.baremetal_mock.port.create.assert_called_once_with(**args) 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): class TestShowBaremetalPort(TestBaremetalPort):
def setUp(self): def setUp(self):
@ -356,6 +385,18 @@ class TestBaremetalPortUnset(TestBaremetalPort):
'port', 'port',
[{'path': '/portgroup_uuid', 'op': 'remove'}]) [{'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): class TestBaremetalPortSet(TestBaremetalPort):
def setUp(self): def setUp(self):
@ -476,6 +517,23 @@ class TestBaremetalPortSet(TestBaremetalPort):
baremetal_fakes.baremetal_port_uuid, baremetal_fakes.baremetal_port_uuid,
[{'path': '/pxe_enabled', 'value': 'False', 'op': 'add'}]) [{'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): def test_baremetal_port_set_no_options(self):
arglist = [] arglist = []
verifylist = [] verifylist = []
@ -645,7 +703,8 @@ class TestBaremetalPortList(TestBaremetalPort):
collist = ('UUID', 'Address', 'Created At', 'Extra', 'Node UUID', collist = ('UUID', 'Address', 'Created At', 'Extra', 'Node UUID',
'Local Link Connection', 'Portgroup 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) self.assertEqual(collist, columns)
datalist = (( datalist = ((
@ -658,6 +717,7 @@ class TestBaremetalPortList(TestBaremetalPort):
'', '',
'', '',
'', '',
'',
'' ''
), ) ), )
self.assertEqual(datalist, tuple(data)) self.assertEqual(datalist, tuple(data))

View File

@ -28,6 +28,7 @@ PORT = {'uuid': '11111111-2222-3333-4444-555555555555',
'pxe_enabled': True, 'pxe_enabled': True,
'local_link_connection': {}, 'local_link_connection': {},
'portgroup_uuid': '55555555-4444-3333-2222-111111111111', 'portgroup_uuid': '55555555-4444-3333-2222-111111111111',
'physical_network': 'physnet1',
'extra': {}} 'extra': {}}
PORT2 = {'uuid': '55555555-4444-3333-2222-111111111111', PORT2 = {'uuid': '55555555-4444-3333-2222-111111111111',
@ -36,6 +37,7 @@ PORT2 = {'uuid': '55555555-4444-3333-2222-111111111111',
'pxe_enabled': True, 'pxe_enabled': True,
'local_link_connection': {}, 'local_link_connection': {},
'portgroup_uuid': '55555555-4444-3333-2222-111111111111', 'portgroup_uuid': '55555555-4444-3333-2222-111111111111',
'physical_network': 'physnet2',
'extra': {}} 'extra': {}}
CREATE_PORT = copy.deepcopy(PORT) CREATE_PORT = copy.deepcopy(PORT)
@ -300,6 +302,7 @@ class PortManagerTest(testtools.TestCase):
self.assertEqual(PORT['local_link_connection'], self.assertEqual(PORT['local_link_connection'],
port.local_link_connection) port.local_link_connection)
self.assertEqual(PORT['portgroup_uuid'], port.portgroup_uuid) self.assertEqual(PORT['portgroup_uuid'], port.portgroup_uuid)
self.assertEqual(PORT['physical_network'], port.physical_network)
def test_ports_show_by_address(self): def test_ports_show_by_address(self):
port = self.mgr.get_by_address(PORT['address']) port = self.mgr.get_by_address(PORT['address'])
@ -315,6 +318,7 @@ class PortManagerTest(testtools.TestCase):
self.assertEqual(PORT['local_link_connection'], self.assertEqual(PORT['local_link_connection'],
port.local_link_connection) port.local_link_connection)
self.assertEqual(PORT['portgroup_uuid'], port.portgroup_uuid) self.assertEqual(PORT['portgroup_uuid'], port.portgroup_uuid)
self.assertEqual(PORT['physical_network'], port.physical_network)
def test_port_show_fields(self): def test_port_show_fields(self):
port = self.mgr.get(PORT['uuid'], fields=['uuid', 'address']) port = self.mgr.get(PORT['uuid'], fields=['uuid', 'address'])

View File

@ -31,8 +31,9 @@ class PortShellTest(utils.BaseTestCase):
with mock.patch.object(cliutils, 'print_dict', fake_print_dict): with mock.patch.object(cliutils, 'print_dict', fake_print_dict):
port = object() port = object()
p_shell._print_port_show(port) p_shell._print_port_show(port)
exp = ['address', 'created_at', 'extra', 'node_uuid', 'updated_at', exp = ['address', 'created_at', 'extra', 'node_uuid',
'uuid', 'pxe_enabled', 'local_link_connection', 'internal_info', 'physical_network', 'updated_at', 'uuid', 'pxe_enabled',
'local_link_connection', 'internal_info',
'portgroup_uuid'] 'portgroup_uuid']
act = actual.keys() act = actual.keys()
self.assertEqual(sorted(exp), sorted(act)) self.assertEqual(sorted(exp), sorted(act))
@ -288,6 +289,18 @@ class PortShellTest(utils.BaseTestCase):
address='address', node_uuid='uuid', address='address', node_uuid='uuid',
portgroup_uuid='portgroup-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): def test_do_port_delete(self):
client_mock = mock.MagicMock() client_mock = mock.MagicMock()
args = mock.MagicMock() args = mock.MagicMock()

View File

@ -28,8 +28,8 @@ class Port(base.Resource):
class PortManager(base.CreateManager): class PortManager(base.CreateManager):
resource_class = Port resource_class = Port
_creation_attributes = ['address', 'extra', 'local_link_connection', _creation_attributes = ['address', 'extra', 'local_link_connection',
'node_uuid', 'portgroup_uuid', 'pxe_enabled', 'node_uuid', 'physical_network', 'portgroup_uuid',
'uuid'] 'pxe_enabled', 'uuid']
_resource_name = 'ports' _resource_name = 'ports'
def list(self, address=None, limit=None, marker=None, sort_key=None, def list(self, address=None, limit=None, marker=None, sort_key=None,

View File

@ -162,6 +162,10 @@ def do_port_list(cc, args):
metavar='<boolean>', metavar='<boolean>',
help='Indicates whether this Port should be used when ' help='Indicates whether this Port should be used when '
'PXE booting this Node.') 'PXE booting this Node.')
@cliutils.arg(
'--physical-network',
metavar='<physical network>',
help="Physical network of the port.")
@cliutils.arg( @cliutils.arg(
'-e', '--extra', '-e', '--extra',
metavar="<key=value>", metavar="<key=value>",
@ -176,7 +180,7 @@ def do_port_create(cc, args):
"""Create a new port.""" """Create a new port."""
field_list = ['address', 'extra', 'node_uuid', 'uuid', field_list = ['address', 'extra', 'node_uuid', 'uuid',
'local_link_connection', 'portgroup_uuid', 'local_link_connection', 'portgroup_uuid',
'pxe_enabled'] 'pxe_enabled', 'physical_network']
fields = dict((k, v) for (k, v) in vars(args).items() fields = dict((k, v) for (k, v) in vars(args).items()
if k in field_list and not (v is None)) if k in field_list and not (v is None))
fields = utils.args_array_to_dict(fields, 'extra') fields = utils.args_array_to_dict(fields, 'extra')

View File

@ -106,6 +106,7 @@ class Resource(object):
'storage_interface': 'Storage Interface', 'storage_interface': 'Storage Interface',
'vendor_interface': 'Vendor Interface', 'vendor_interface': 'Vendor Interface',
'standalone_ports_supported': 'Standalone Ports Supported', 'standalone_ports_supported': 'Standalone Ports Supported',
'physical_network': 'Physical Network',
'id': 'ID', 'id': 'ID',
'connector_id': 'Connector ID', 'connector_id': 'Connector ID',
} }
@ -265,6 +266,7 @@ PORT_DETAILED_RESOURCE = Resource(
'local_link_connection', 'local_link_connection',
'portgroup_uuid', 'portgroup_uuid',
'pxe_enabled', 'pxe_enabled',
'physical_network',
'updated_at', 'updated_at',
'internal_info', 'internal_info',
], ],

View File

@ -0,0 +1,5 @@
---
features:
- |
Adds support for the ``port.physical_network`` field, which was introduced
in API version 1.34.