Merge "Start passing portgroup information to Neutron"

This commit is contained in:
Jenkins 2017-07-24 13:42:06 +00:00 committed by Gerrit Code Review
commit 7cbcb6003d
5 changed files with 90 additions and 8 deletions

View File

@ -328,7 +328,14 @@ def get_node_portmap(task):
"""Extract the switch port information for the node.
:param task: a task containing the Node object.
:returns: a dictionary in the form {port.uuid: port.local_link_connection}
:returns: a dictionary in the form
{
port.uuid: {
'switch_id': 'abc',
'port_id': 'Po0/1',
'other_llc_key': 'val'
}
}
"""
portmap = {}
@ -339,6 +346,41 @@ def get_node_portmap(task):
# necessary info? (probably)
def get_local_group_information(task, portgroup):
"""Extract the portgroup information.
:param task: a task containing the Node object.
:param portgroup: Ironic portgroup object to extract data for.
:returns: a dictionary in the form:
{
'id': portgroup.uuid,
'name': portgroup.name,
'bond_mode': portgroup.mode,
'bond_properties': {
'bond_propertyA': 'valueA',
'bond_propertyB': 'valueB',
}
{
"""
portgroup_properties = {}
for prop, value in portgroup.properties.items():
# These properties are the bonding driver options described
# at https://www.kernel.org/doc/Documentation/networking/bonding.txt .
# cloud-init checks the same way, parameter name has to start with
# 'bond'. Keep this structure when passing properties to neutron ML2
# drivers.
key = prop if prop.startswith('bond') else 'bond_%s' % prop
portgroup_properties[key] = value
return {
'id': portgroup.uuid,
'name': portgroup.name,
'bond_mode': portgroup.mode,
'bond_properties': portgroup_properties
}
def rollback_ports(task, network_uuid):
"""Attempts to delete any ports created by cleaning/provisioning

View File

@ -231,6 +231,7 @@ def plug_port_to_tenant_network(task, port_like_obj, client=None):
node = task.node
local_link_info = []
local_group_info = {}
client_id_opt = None
vif_id = (
@ -253,6 +254,8 @@ def plug_port_to_tenant_network(task, port_like_obj, client=None):
if p.portgroup_id == port_like_obj.id]
for port in pg_ports:
local_link_info.append(port.local_link_connection)
local_group_info = neutron.get_local_group_information(
task, port_like_obj)
else:
# We iterate only on ports or portgroups, no need to check
# that it is a port
@ -268,11 +271,13 @@ def plug_port_to_tenant_network(task, port_like_obj, client=None):
'port': {
'binding:vnic_type': 'baremetal',
'binding:host_id': node.uuid,
'binding:profile': {
'local_link_information': local_link_info,
},
}
}
binding_profile = {'local_link_information': local_link_info}
if local_group_info:
binding_profile['local_group_information'] = local_group_info
body['port']['binding:profile'] = binding_profile
if client_id_opt:
body['port']['extra_dhcp_opts'] = [client_id_opt]

View File

@ -398,6 +398,25 @@ class TestNeutronNetworkActions(db_base.DbTestCase):
portmap
)
def test_get_local_group_information(self):
pg = object_utils.create_test_portgroup(
self.context, node_id=self.node.id,
uuid=uuidutils.generate_uuid(),
address='52:54:55:cf:2d:32',
mode='802.3ad', properties={'bond_opt1': 'foo',
'opt2': 'bar'},
name='test-pg'
)
expected = {
'id': pg.uuid,
'name': pg.name,
'bond_mode': pg.mode,
'bond_properties': {'bond_opt1': 'foo', 'bond_opt2': 'bar'},
}
with task_manager.acquire(self.context, self.node.uuid) as task:
res = neutron.get_local_group_information(task, pg)
self.assertEqual(expected, res)
@mock.patch.object(neutron, 'remove_ports_from_network')
def test_rollback_ports(self, remove_mock):
with task_manager.acquire(self.context, self.node.uuid) as task:

View File

@ -364,8 +364,11 @@ class NeutronInterfaceTestCase(db_base.DbTestCase):
self.node.save()
self._test_configure_tenant_networks(is_client_id=True)
@mock.patch.object(neutron_common, 'get_client')
def test_configure_tenant_networks_with_portgroups(self, client_mock):
@mock.patch.object(neutron_common, 'get_client', autospec=True)
@mock.patch.object(neutron_common, 'get_local_group_information',
autospec=True)
def test_configure_tenant_networks_with_portgroups(
self, glgi_mock, client_mock):
pg = utils.create_test_portgroup(
self.context, node_id=self.node.id, address='ff:54:00:cf:2d:32',
extra={'vif_port_id': uuidutils.generate_uuid()})
@ -387,6 +390,8 @@ class NeutronInterfaceTestCase(db_base.DbTestCase):
)
upd_mock = mock.Mock()
client_mock.return_value.update_port = upd_mock
local_group_info = {'a': 'b'}
glgi_mock.return_value = local_group_info
expected_body = {
'port': {
'binding:vnic_type': 'baremetal',
@ -395,16 +400,22 @@ class NeutronInterfaceTestCase(db_base.DbTestCase):
}
call1_body = copy.deepcopy(expected_body)
call1_body['port']['binding:profile'] = {
'local_link_information': [self.port.local_link_connection]
'local_link_information': [self.port.local_link_connection],
}
call2_body = copy.deepcopy(expected_body)
call2_body['port']['binding:profile'] = {
'local_link_information': [port1.local_link_connection,
port2.local_link_connection]
port2.local_link_connection],
'local_group_information': local_group_info
}
with task_manager.acquire(self.context, self.node.id) as task:
# Override task.portgroups here, to have ability to check
# that mocked get_local_group_information was called with
# this portgroup object.
task.portgroups = [pg]
self.interface.configure_tenant_networks(task)
client_mock.assert_called_once_with()
glgi_mock.assert_called_once_with(task, pg)
upd_mock.assert_has_calls(
[mock.call(self.port.extra['vif_port_id'], call1_body),
mock.call(pg.extra['vif_port_id'], call2_body)]

View File

@ -0,0 +1,5 @@
---
features:
- Passes port group information (``portgroup.mode`` and
``portgroup.properties``) to Neutron via Neutron ``port.binding:profile``
field.