Re-factor and improve update_networks_matching_iface_port

* Implement _find_best_match() using subset intersection.
* Reduce number of expensive external neutron calls to get net_id by
  moving this outside the inner loop.

Unit test updated, we now do a better job at matching and populate more
data when updating.

Partial-Bug: #1696483
Partial-Bug: #1702279
Change-Id: I2157d35e1c58f3960d5b6aa86199d93bb5b88401
This commit is contained in:
Harald Jensas 2017-12-21 11:58:42 +01:00
parent c874d9d5d6
commit 07b9b1a033
2 changed files with 48 additions and 33 deletions

View File

@ -267,6 +267,31 @@ class ServerNetworkMixin(object):
self.client('neutron').update_floatingip(
floating_ip, {'floatingip': {'port_id': None}})
def _find_best_match(self, existing_interfaces, specified_net):
specified_net_items = set(specified_net.items())
if specified_net.get(self.NETWORK_PORT) is not None:
for iface in existing_interfaces:
if (iface[self.NETWORK_PORT] ==
specified_net[self.NETWORK_PORT] and
specified_net_items.issubset(set(iface.items()))):
return iface
elif specified_net.get(self.NETWORK_FIXED_IP) is not None:
for iface in existing_interfaces:
if (iface[self.NETWORK_FIXED_IP] ==
specified_net[self.NETWORK_FIXED_IP] and
specified_net_items.issubset(set(iface.items()))):
return iface
else:
# Best subset intersection
best, matches, num = None, 0, 0
for iface in existing_interfaces:
iface_items = set(iface.items())
if specified_net_items.issubset(iface_items):
num = len(specified_net_items.intersection(iface_items))
if num > matches:
best, matches = iface, num
return best
def _exclude_not_updated_networks(self, old_nets, new_nets):
# make networks similar by adding None vlues for not used keys
for key in self._NETWORK_KEYS:
@ -289,38 +314,28 @@ class ServerNetworkMixin(object):
return net_id
def update_networks_matching_iface_port(self, nets, interfaces):
iface_managed_keys = (self.NETWORK_PORT, self.NETWORK_ID,
self.NETWORK_FIXED_IP)
def find_equal(port, net_id, ip, nets):
for net in nets:
if (net.get('port') == port or
(net.get('fixed_ip') == ip and
self._get_network_id(net) == net_id)):
return net
def find_poor_net(net_id, nets):
for net in nets:
if (not net.get('port') and not net.get('fixed_ip') and
self._get_network_id(net) == net_id):
return net
for iface in interfaces:
# get interface properties
def get_iface_props(iface):
ipaddr = None
if len(iface.fixed_ips) > 0:
ipaddr = iface.fixed_ips[0]['ip_address']
props = {'port': iface.port_id,
'net_id': iface.net_id,
'ip': ipaddr,
'nets': nets}
# try to match by port or network_id with fixed_ip
net = find_equal(**props)
if net is not None:
net['port'] = props['port']
continue
# find poor net that has only network_id
net = find_poor_net(props['net_id'], nets)
if net is not None:
net['port'] = props['port']
return {self.NETWORK_PORT: iface.port_id,
self.NETWORK_ID: iface.net_id,
self.NETWORK_FIXED_IP: ipaddr}
interfaces_net_props = [get_iface_props(iface) for iface in interfaces]
for net in nets:
if net[self.NETWORK_PORT] is None:
net[self.NETWORK_ID] = self._get_network_id(net)
net_reduced = {k: v for k, v in net.items()
if k in iface_managed_keys and v is not None}
match = self._find_best_match(interfaces_net_props,
net_reduced)
if match is not None:
net.update(match)
interfaces_net_props.remove(match)
def _get_available_networks(self):
# first we get the private networks owned by the tenant

View File

@ -3400,8 +3400,8 @@ class ServersTest(common.HeatTestCase):
# all networks should get port id
expected = [
{'port': 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
'network': None,
'fixed_ip': None,
'network': 'gggggggg-1111-1111-1111-gggggggggggg',
'fixed_ip': '10.0.0.13',
'subnet': None,
'floating_ip': None,
'port_extra_properties': None,
@ -3419,7 +3419,7 @@ class ServersTest(common.HeatTestCase):
'tag': None},
{'port': 'cccccccc-cccc-cccc-cccc-cccccccccccc',
'network': 'gggggggg-1111-1111-1111-gggggggggggg',
'fixed_ip': None,
'fixed_ip': '10.0.0.11',
'subnet': None,
'port_extra_properties': None,
'floating_ip': None,
@ -3427,8 +3427,8 @@ class ServersTest(common.HeatTestCase):
'allocate_network': None,
'tag': None},
{'port': 'dddddddd-dddd-dddd-dddd-dddddddddddd',
'network': None,
'fixed_ip': None,
'network': 'gggggggg-1111-1111-1111-gggggggggggg',
'fixed_ip': '10.0.0.12',
'subnet': None,
'port_extra_properties': None,
'floating_ip': None,