Pick most recent rather than first fixed address

If there are multiple fixed ips for a server after nat_destination
filtering, we pick one arbitrarily. The thing we really want to do is
pick the most recent one - since it's the one with the greatest chance
of success.

Removed a test that wasn't actually testing anything.

Change-Id: I73fe5fe58269931ae9a7e52b79c3211d96e69a92
This commit is contained in:
Monty Taylor 2017-05-23 16:05:15 -05:00
parent 072001a628
commit ba0e9451e6
No known key found for this signature in database
GPG Key ID: 7BAE94BC7141A594
3 changed files with 43 additions and 40 deletions

View File

@ -4779,9 +4779,7 @@ class OpenStackCloud(
return (None, None)
port = None
if not fixed_address:
if len(ports) == 1:
port = ports[0]
else:
if len(ports) > 1:
if nat_destination:
nat_network = self.get_network(nat_destination)
if not nat_network:
@ -4793,37 +4791,49 @@ class OpenStackCloud(
else:
nat_network = self.get_nat_destination()
if nat_network:
for maybe_port in ports:
if maybe_port['network_id'] == nat_network['id']:
port = maybe_port
if not port:
raise OpenStackCloudException(
'No port on server {server} was found matching'
' the network configured as the NAT destination'
' {dest}. Please check your config'.format(
server=server['id'], dest=nat_network['name']))
else:
port = ports[0]
warnings.warn(
'During Floating IP creation, multiple private'
' networks were found. {net} is being selected at'
' random to be the destination of the NAT. If that'
' is not what you want, please configure the'
if not nat_network:
raise OpenStackCloudException(
'Multiple ports were found for server {server}'
' but none of the networks are a valid NAT'
' destination, so it is impossible to add a'
' floating IP. If you have a network that is a valid'
' destination for NAT and we could not find it,'
' please file a bug. But also configure the'
' nat_destination property of the networks list in'
' your clouds.yaml file. If you do not have a'
' clouds.yaml file, please make one - your setup'
' is complicated.'.format(net=port['network_id']))
' is complicated.'.format(server=server['id']))
# Select the first available IPv4 address
for address in port.get('fixed_ips', list()):
try:
ip = ipaddress.ip_address(address['ip_address'])
except Exception:
continue
if ip.version == 4:
fixed_address = address['ip_address']
return port, fixed_address
maybe_ports = []
for maybe_port in ports:
if maybe_port['network_id'] == nat_network['id']:
maybe_ports.append(maybe_port)
if not maybe_ports:
raise OpenStackCloudException(
'No port on server {server} was found matching'
' your NAT destination network {dest}. Please '
' check your config'.format(
server=server['id'], dest=nat_network['name']))
ports = maybe_ports
# Select the most recent available IPv4 address
# To do this, sort the ports in reverse order by the created_at
# field which is a string containing an ISO DateTime (which
# thankfully sort properly) This way the most recent port created,
# if there are more than one, will be the arbitrary port we
# select.
for port in sorted(
ports,
key=operator.itemgetter('created_at'),
reverse=True):
for address in port.get('fixed_ips', list()):
try:
ip = ipaddress.ip_address(address['ip_address'])
except Exception:
continue
if ip.version == 4:
fixed_address = address['ip_address']
return port, fixed_address
raise OpenStackCloudException(
"unable to find a free fixed IPv4 address for server "
"{0}".format(server['id']))

View File

@ -21,7 +21,6 @@ Tests floating IP resource methods for Neutron and Nova-network.
from mock import patch
from shade import exc
from shade import meta
from shade import OpenStackCloud
from shade.tests.fakes import FakeServer
@ -225,12 +224,3 @@ class TestFloatingIP(base.TestCase):
mock_add_auto_ip.assert_called_with(
server_dict, wait=False, timeout=60, reuse=True)
@patch.object(OpenStackCloud, 'search_ports', return_value=[{}])
def test_nat_destination_port_when_no_free_fixed_ip(
self, mock_search_ports):
server = {'id': 42}
self.assertRaisesRegexp(
exc.OpenStackCloudException, 'server 42$',
self.cloud._nat_destination_port, server
)

View File

@ -20,6 +20,7 @@ Tests Floating IP resource methods for Neutron
"""
import copy
import datetime
import munch
from shade import exc
@ -101,6 +102,7 @@ class TestFloatingIP(base.RequestsMockTestCase):
'status': 'ACTIVE',
'binding:host_id': 'devstack',
'name': 'first-port',
'created_at': datetime.datetime.now().isoformat(),
'allowed_address_pairs': [],
'admin_state_up': True,
'network_id': '70c1db1f-b701-45bd-96e0-a313ee3430b3',
@ -939,6 +941,7 @@ class TestFloatingIP(base.RequestsMockTestCase):
server_port = {
"id": "port-id",
"device_id": "some-server",
'created_at': datetime.datetime.now().isoformat(),
'fixed_ips': [
{
'subnet_id': 'subnet-id',