Updates supporting ironic-neutron integration
This patchset adds port creation with new optional parameters specifying new port attributes (local_link_connection, pxe_enabled). It also adds new parameter network_interface to node object. Co-Authored-By: Vasyl Saienko (vsaienko@mirantis.com) Co-Authored-By: William Stevenson (will.stevenson@sap.com) Partial-bug: #1526403 Depends-on: I67495196c3334f51ed034f4ca6e32a3e01a58f15 Change-Id: If2fb996783b9ac26a5bae2aadd6387207750def9
This commit is contained in:
parent
d2debb7a38
commit
d1ea9b44f6
|
@ -23,7 +23,7 @@ LOG = logging.getLogger(__name__)
|
||||||
DEFAULT_BAREMETAL_API_VERSION = '1.6'
|
DEFAULT_BAREMETAL_API_VERSION = '1.6'
|
||||||
API_VERSION_OPTION = 'os_baremetal_api_version'
|
API_VERSION_OPTION = 'os_baremetal_api_version'
|
||||||
API_NAME = 'baremetal'
|
API_NAME = 'baremetal'
|
||||||
LAST_KNOWN_API_VERSION = 14
|
LAST_KNOWN_API_VERSION = 20
|
||||||
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)
|
||||||
|
|
|
@ -151,6 +151,11 @@ class CreateBaremetalNode(show.ShowOne):
|
||||||
'--name',
|
'--name',
|
||||||
metavar='<name>',
|
metavar='<name>',
|
||||||
help="Unique name for the node.")
|
help="Unique name for the node.")
|
||||||
|
parser.add_argument(
|
||||||
|
'--network-interface',
|
||||||
|
metavar='<network_interface>',
|
||||||
|
help='Network interface used for switching node to '
|
||||||
|
'cleaning/provisioning networks.')
|
||||||
|
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
@ -160,7 +165,8 @@ class CreateBaremetalNode(show.ShowOne):
|
||||||
baremetal_client = self.app.client_manager.baremetal
|
baremetal_client = self.app.client_manager.baremetal
|
||||||
|
|
||||||
field_list = ['chassis_uuid', 'driver', 'driver_info',
|
field_list = ['chassis_uuid', 'driver', 'driver_info',
|
||||||
'properties', 'extra', 'uuid', 'name']
|
'properties', 'extra', 'uuid', 'name',
|
||||||
|
'network_interface']
|
||||||
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 not (v is None))
|
if k in field_list and not (v is None))
|
||||||
fields = utils.args_array_to_dict(fields, 'driver_info')
|
fields = utils.args_array_to_dict(fields, 'driver_info')
|
||||||
|
@ -554,6 +560,11 @@ class SetBaremetalNode(command.Command):
|
||||||
metavar="<driver>",
|
metavar="<driver>",
|
||||||
help="Set the driver for the node",
|
help="Set the driver for the node",
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--network-interface',
|
||||||
|
metavar='<network_interface>',
|
||||||
|
help='Set the network interface for the node',
|
||||||
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--property",
|
"--property",
|
||||||
metavar="<key=value>",
|
metavar="<key=value>",
|
||||||
|
@ -603,6 +614,11 @@ class SetBaremetalNode(command.Command):
|
||||||
driver = ["driver=%s" % parsed_args.driver]
|
driver = ["driver=%s" % parsed_args.driver]
|
||||||
properties.extend(utils.args_array_to_patch(
|
properties.extend(utils.args_array_to_patch(
|
||||||
'add', driver))
|
'add', driver))
|
||||||
|
if parsed_args.network_interface:
|
||||||
|
network_interface = [
|
||||||
|
"network_interface=%s" % parsed_args.network_interface]
|
||||||
|
properties.extend(utils.args_array_to_patch(
|
||||||
|
'add', network_interface))
|
||||||
if parsed_args.property:
|
if parsed_args.property:
|
||||||
properties.extend(utils.args_array_to_patch(
|
properties.extend(utils.args_array_to_patch(
|
||||||
'add', ['properties/' + x for x in parsed_args.property]))
|
'add', ['properties/' + x for x in parsed_args.property]))
|
||||||
|
|
|
@ -46,6 +46,18 @@ class CreateBaremetalPort(show.ShowOne):
|
||||||
action='append',
|
action='append',
|
||||||
help="Record arbitrary key/value metadata. "
|
help="Record arbitrary key/value metadata. "
|
||||||
"Can be specified multiple times.")
|
"Can be specified multiple times.")
|
||||||
|
parser.add_argument(
|
||||||
|
'-l', '--local-link-connection',
|
||||||
|
metavar="<key=value>",
|
||||||
|
action='append',
|
||||||
|
help="Key/value metadata describing Local link connection "
|
||||||
|
"information. Valid keys are switch_info, switch_id, "
|
||||||
|
"port_id. Can be specified multiple times.")
|
||||||
|
parser.add_argument(
|
||||||
|
'--pxe-enabled',
|
||||||
|
metavar='<boolean>',
|
||||||
|
help='Indicates whether this Port should be used when '
|
||||||
|
'PXE booting this Node.')
|
||||||
|
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
@ -53,10 +65,12 @@ class CreateBaremetalPort(show.ShowOne):
|
||||||
self.log.debug("take_action(%s)" % parsed_args)
|
self.log.debug("take_action(%s)" % parsed_args)
|
||||||
baremetal_client = self.app.client_manager.baremetal
|
baremetal_client = self.app.client_manager.baremetal
|
||||||
|
|
||||||
field_list = ['address', 'extra', 'node_uuid']
|
field_list = ['address', 'extra', 'node_uuid', 'pxe_enabled',
|
||||||
|
'local_link_connection']
|
||||||
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')
|
||||||
|
fields = utils.args_array_to_dict(fields, 'local_link_connection')
|
||||||
port = baremetal_client.port.create(**fields)
|
port = baremetal_client.port.create(**fields)
|
||||||
|
|
||||||
data = dict([(f, getattr(port, f, '')) for f in
|
data = dict([(f, getattr(port, f, '')) for f in
|
||||||
|
|
|
@ -162,6 +162,11 @@ class TestBaremetalCreate(TestBaremetal):
|
||||||
[('name', 'name')],
|
[('name', 'name')],
|
||||||
{'name': 'name'})
|
{'name': 'name'})
|
||||||
|
|
||||||
|
def test_baremetal_create_with_network_interface(self):
|
||||||
|
self.check_with_options(['--network-interface', 'neutron'],
|
||||||
|
[('network_interface', 'neutron')],
|
||||||
|
{'network_interface': 'neutron'})
|
||||||
|
|
||||||
|
|
||||||
class TestBaremetalDelete(TestBaremetal):
|
class TestBaremetalDelete(TestBaremetal):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
@ -315,7 +320,8 @@ class TestBaremetalList(TestBaremetal):
|
||||||
'Target Power State', 'Target Provision State',
|
'Target Power State', 'Target Provision State',
|
||||||
'Target RAID configuration',
|
'Target RAID configuration',
|
||||||
'Updated At', 'Inspection Finished At',
|
'Updated At', 'Inspection Finished At',
|
||||||
'Inspection Started At', 'UUID', 'Name')
|
'Inspection Started At', 'UUID', 'Name',
|
||||||
|
'Network Interface')
|
||||||
self.assertEqual(collist, columns)
|
self.assertEqual(collist, columns)
|
||||||
datalist = ((
|
datalist = ((
|
||||||
'',
|
'',
|
||||||
|
@ -345,6 +351,7 @@ class TestBaremetalList(TestBaremetal):
|
||||||
'',
|
'',
|
||||||
baremetal_fakes.baremetal_uuid,
|
baremetal_fakes.baremetal_uuid,
|
||||||
baremetal_fakes.baremetal_name,
|
baremetal_fakes.baremetal_name,
|
||||||
|
'',
|
||||||
), )
|
), )
|
||||||
self.assertEqual(datalist, tuple(data))
|
self.assertEqual(datalist, tuple(data))
|
||||||
|
|
||||||
|
@ -801,6 +808,25 @@ class TestBaremetalSet(TestBaremetal):
|
||||||
[{'path': '/driver', 'value': 'xxxxx', 'op': 'add'}]
|
[{'path': '/driver', 'value': 'xxxxx', 'op': 'add'}]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_baremetal_set_network_interface(self):
|
||||||
|
arglist = [
|
||||||
|
'node_uuid',
|
||||||
|
'--network-interface', 'xxxxx',
|
||||||
|
]
|
||||||
|
verifylist = [
|
||||||
|
('node', 'node_uuid'),
|
||||||
|
('network_interface', 'xxxxx')
|
||||||
|
]
|
||||||
|
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
|
||||||
|
self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
|
self.baremetal_mock.node.update.assert_called_once_with(
|
||||||
|
'node_uuid',
|
||||||
|
[{'path': '/network_interface', 'value': 'xxxxx', 'op': 'add'}]
|
||||||
|
)
|
||||||
|
|
||||||
def test_baremetal_set_extra(self):
|
def test_baremetal_set_extra(self):
|
||||||
arglist = [
|
arglist = [
|
||||||
'node_uuid',
|
'node_uuid',
|
||||||
|
|
|
@ -53,7 +53,6 @@ PORT = {'id': 456,
|
||||||
'node_id': 123,
|
'node_id': 123,
|
||||||
'address': 'AA:AA:AA:AA:AA:AA',
|
'address': 'AA:AA:AA:AA:AA:AA',
|
||||||
'extra': {}}
|
'extra': {}}
|
||||||
|
|
||||||
POWER_STATE = {'power_state': 'power off',
|
POWER_STATE = {'power_state': 'power off',
|
||||||
'target_power_state': 'power on'}
|
'target_power_state': 'power on'}
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,7 @@ class NodeShellTest(utils.BaseTestCase):
|
||||||
'maintenance',
|
'maintenance',
|
||||||
'maintenance_reason',
|
'maintenance_reason',
|
||||||
'name',
|
'name',
|
||||||
|
'network_interface',
|
||||||
'power_state',
|
'power_state',
|
||||||
'properties',
|
'properties',
|
||||||
'provision_state',
|
'provision_state',
|
||||||
|
|
|
@ -26,12 +26,16 @@ PORT = {'id': 987,
|
||||||
'uuid': '11111111-2222-3333-4444-555555555555',
|
'uuid': '11111111-2222-3333-4444-555555555555',
|
||||||
'node_uuid': '55555555-4444-3333-2222-111111111111',
|
'node_uuid': '55555555-4444-3333-2222-111111111111',
|
||||||
'address': 'AA:BB:CC:DD:EE:FF',
|
'address': 'AA:BB:CC:DD:EE:FF',
|
||||||
|
'pxe_enabled': True,
|
||||||
|
'local_link_connection': {},
|
||||||
'extra': {}}
|
'extra': {}}
|
||||||
|
|
||||||
PORT2 = {'id': 988,
|
PORT2 = {'id': 988,
|
||||||
'uuid': '55555555-4444-3333-2222-111111111111',
|
'uuid': '55555555-4444-3333-2222-111111111111',
|
||||||
'node_uuid': '55555555-4444-3333-2222-111111111111',
|
'node_uuid': '55555555-4444-3333-2222-111111111111',
|
||||||
'address': 'AA:AA:AA:BB:BB:BB',
|
'address': 'AA:AA:AA:BB:BB:BB',
|
||||||
|
'pxe_enabled': True,
|
||||||
|
'local_link_connection': {},
|
||||||
'extra': {}}
|
'extra': {}}
|
||||||
|
|
||||||
CREATE_PORT = copy.deepcopy(PORT)
|
CREATE_PORT = copy.deepcopy(PORT)
|
||||||
|
@ -263,6 +267,9 @@ class PortManagerTest(testtools.TestCase):
|
||||||
self.assertEqual(PORT['uuid'], port.uuid)
|
self.assertEqual(PORT['uuid'], port.uuid)
|
||||||
self.assertEqual(PORT['address'], port.address)
|
self.assertEqual(PORT['address'], port.address)
|
||||||
self.assertEqual(PORT['node_uuid'], port.node_uuid)
|
self.assertEqual(PORT['node_uuid'], port.node_uuid)
|
||||||
|
self.assertEqual(PORT['pxe_enabled'], port.pxe_enabled)
|
||||||
|
self.assertEqual(PORT['local_link_connection'],
|
||||||
|
port.local_link_connection)
|
||||||
|
|
||||||
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'])
|
||||||
|
@ -274,6 +281,9 @@ class PortManagerTest(testtools.TestCase):
|
||||||
self.assertEqual(PORT['uuid'], port.uuid)
|
self.assertEqual(PORT['uuid'], port.uuid)
|
||||||
self.assertEqual(PORT['address'], port.address)
|
self.assertEqual(PORT['address'], port.address)
|
||||||
self.assertEqual(PORT['node_uuid'], port.node_uuid)
|
self.assertEqual(PORT['node_uuid'], port.node_uuid)
|
||||||
|
self.assertEqual(PORT['pxe_enabled'], port.pxe_enabled)
|
||||||
|
self.assertEqual(PORT['local_link_connection'],
|
||||||
|
port.local_link_connection)
|
||||||
|
|
||||||
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'])
|
||||||
|
|
|
@ -32,7 +32,7 @@ class PortShellTest(utils.BaseTestCase):
|
||||||
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', 'updated_at',
|
||||||
'uuid']
|
'uuid', 'pxe_enabled', 'local_link_connection']
|
||||||
act = actual.keys()
|
act = actual.keys()
|
||||||
self.assertEqual(sorted(exp), sorted(act))
|
self.assertEqual(sorted(exp), sorted(act))
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,8 @@ class Node(base.Resource):
|
||||||
class NodeManager(base.CreateManager):
|
class NodeManager(base.CreateManager):
|
||||||
resource_class = Node
|
resource_class = Node
|
||||||
_creation_attributes = ['chassis_uuid', 'driver', 'driver_info',
|
_creation_attributes = ['chassis_uuid', 'driver', 'driver_info',
|
||||||
'extra', 'uuid', 'properties', 'name']
|
'extra', 'uuid', 'properties', 'name',
|
||||||
|
'network_interface']
|
||||||
_resource_name = 'nodes'
|
_resource_name = 'nodes'
|
||||||
|
|
||||||
def list(self, associated=None, maintenance=None, marker=None, limit=None,
|
def list(self, associated=None, maintenance=None, marker=None, limit=None,
|
||||||
|
|
|
@ -202,10 +202,16 @@ def do_node_list(cc, args):
|
||||||
'-n', '--name',
|
'-n', '--name',
|
||||||
metavar='<name>',
|
metavar='<name>',
|
||||||
help="Unique name for the node.")
|
help="Unique name for the node.")
|
||||||
|
@cliutils.arg(
|
||||||
|
'--network-interface',
|
||||||
|
metavar='<network_interface>',
|
||||||
|
help='Network interface used for switching node to cleaning/provisioning '
|
||||||
|
'networks.')
|
||||||
def do_node_create(cc, args):
|
def do_node_create(cc, args):
|
||||||
"""Register a new node with the Ironic service."""
|
"""Register a new node with the Ironic service."""
|
||||||
field_list = ['chassis_uuid', 'driver', 'driver_info',
|
field_list = ['chassis_uuid', 'driver', 'driver_info',
|
||||||
'properties', 'extra', 'uuid', 'name']
|
'properties', 'extra', 'uuid', 'name',
|
||||||
|
'network_interface']
|
||||||
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, 'driver_info')
|
fields = utils.args_array_to_dict(fields, 'driver_info')
|
||||||
|
|
|
@ -27,7 +27,8 @@ class Port(base.Resource):
|
||||||
|
|
||||||
class PortManager(base.CreateManager):
|
class PortManager(base.CreateManager):
|
||||||
resource_class = Port
|
resource_class = Port
|
||||||
_creation_attributes = ['address', 'extra', 'node_uuid', 'uuid']
|
_creation_attributes = ['address', 'extra', 'local_link_connection',
|
||||||
|
'node_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,
|
||||||
|
|
|
@ -143,6 +143,18 @@ def do_port_list(cc, args):
|
||||||
metavar='<node>',
|
metavar='<node>',
|
||||||
required=True,
|
required=True,
|
||||||
help='UUID of the node that this port belongs to.')
|
help='UUID of the node that this port belongs to.')
|
||||||
|
@cliutils.arg(
|
||||||
|
'-l', '--local-link-connection',
|
||||||
|
metavar="<key=value>",
|
||||||
|
action='append',
|
||||||
|
help="Key/value metadata describing Local link connection information. "
|
||||||
|
"Valid keys are switch_info, switch_id, port_id."
|
||||||
|
"Can be specified multiple times.")
|
||||||
|
@cliutils.arg(
|
||||||
|
'--pxe-enabled',
|
||||||
|
metavar='<boolean>',
|
||||||
|
help='Indicates whether this Port should be used when '
|
||||||
|
'PXE booting this Node.')
|
||||||
@cliutils.arg(
|
@cliutils.arg(
|
||||||
'-e', '--extra',
|
'-e', '--extra',
|
||||||
metavar="<key=value>",
|
metavar="<key=value>",
|
||||||
|
@ -155,10 +167,12 @@ def do_port_list(cc, args):
|
||||||
help="UUID of the port.")
|
help="UUID of the port.")
|
||||||
def do_port_create(cc, args):
|
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', 'pxe_enabled']
|
||||||
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')
|
||||||
|
fields = utils.args_array_to_dict(fields, 'local_link_connection')
|
||||||
port = cc.port.create(**fields)
|
port = cc.port.create(**fields)
|
||||||
|
|
||||||
data = dict([(f, getattr(port, f, '')) for f in field_list])
|
data = dict([(f, getattr(port, f, '')) for f in field_list])
|
||||||
|
|
|
@ -64,6 +64,9 @@ class Resource(object):
|
||||||
'target_raid_config': 'Target RAID configuration',
|
'target_raid_config': 'Target RAID configuration',
|
||||||
'updated_at': 'Updated At',
|
'updated_at': 'Updated At',
|
||||||
'uuid': 'UUID',
|
'uuid': 'UUID',
|
||||||
|
'local_link_connection': 'Local Link Connection',
|
||||||
|
'pxe_enabled': 'PXE boot enabled',
|
||||||
|
'network_interface': 'Network Interface',
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, field_ids, sort_excluded=None):
|
def __init__(self, field_ids, sort_excluded=None):
|
||||||
|
@ -151,6 +154,7 @@ NODE_DETAILED_RESOURCE = Resource(
|
||||||
'inspection_started_at',
|
'inspection_started_at',
|
||||||
'uuid',
|
'uuid',
|
||||||
'name',
|
'name',
|
||||||
|
'network_interface',
|
||||||
],
|
],
|
||||||
sort_excluded=[
|
sort_excluded=[
|
||||||
# The server cannot sort on "chassis_uuid" because it isn't a column in
|
# The server cannot sort on "chassis_uuid" because it isn't a column in
|
||||||
|
@ -189,6 +193,8 @@ PORT_DETAILED_RESOURCE = Resource(
|
||||||
'created_at',
|
'created_at',
|
||||||
'extra',
|
'extra',
|
||||||
'node_uuid',
|
'node_uuid',
|
||||||
|
'local_link_connection',
|
||||||
|
'pxe_enabled',
|
||||||
'updated_at',
|
'updated_at',
|
||||||
],
|
],
|
||||||
sort_excluded=[
|
sort_excluded=[
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Add support of new fields:
|
||||||
|
|
||||||
|
* ``node.network_interface`` is introduced in API 1.20,
|
||||||
|
specifies the network interface to use for a node.
|
||||||
|
* ``port.local_link_connection`` contains the port binding
|
||||||
|
profile.
|
||||||
|
* ``port.pxe_enabled`` indicates whether PXE is enabled
|
||||||
|
for the port.
|
||||||
|
|
||||||
|
The ``port.local_link_connection`` and ``port.pxe_enabled`` fields
|
||||||
|
were introduced in API 1.19.
|
Loading…
Reference in New Issue