Associate floating IPs with first v4 fixed IP if none specified

In the absence of a specified fixed address with which to associate a
floating IP, the first IPv4 address on the port should be associated.
Without the check for IPv4, IPv6 ports can be associated with a (IPv4)
floating IP, which is not supported.

Change-Id: Ib66a9109cc1c7999474daca5970d0af1f70886e4
Closes-Bug: 1437855
This commit is contained in:
Andrew Boik
2015-03-29 10:18:48 -04:00
parent 6ae446bb17
commit c5dfd2c3ef
3 changed files with 45 additions and 9 deletions
@@ -15,6 +15,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import netaddr
from oslo_log import log as logging
from oslo_utils import uuidutils
import webob
@@ -200,10 +201,19 @@ class FloatingIPActionController(wsgi.Controller):
raise webob.exc.HTTPBadRequest(explanation=msg)
if not fixed_address:
fixed_address = fixed_ips[0]['address']
try:
fixed_address = (ip['address'] for ip in fixed_ips if
netaddr.valid_ipv4(ip['address'])).next()
except StopIteration:
msg = _('Unable to associate floating ip %(address)s '
'to any fixed IPs for instance %(id)s. '
'Instance has no fixed IPv4 addresses to '
'associate.') % (
{'address': address, 'id': id})
raise webob.exc.HTTPBadRequest(explanation=msg)
if len(fixed_ips) > 1:
LOG.warning(_LW('multiple fixed_ips exist, using the first: '
'%s'), fixed_address)
LOG.warning(_LW('multiple fixed_ips exist, using the first '
'IPv4 fixed_ip: %s'), fixed_address)
try:
self.network_api.associate_floating_ip(context, instance,
@@ -15,6 +15,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import netaddr
from oslo_log import log as logging
from oslo_utils import uuidutils
import webob
@@ -212,10 +213,19 @@ class FloatingIPActionController(wsgi.Controller):
raise webob.exc.HTTPBadRequest(explanation=msg)
if not fixed_address:
fixed_address = fixed_ips[0]['address']
try:
fixed_address = (ip['address'] for ip in fixed_ips if
netaddr.valid_ipv4(ip['address'])).next()
except StopIteration:
msg = _('Unable to associate floating ip %(address)s '
'to any fixed IPs for instance %(id)s. '
'Instance has no fixed IPv4 addresses to '
'associate.') % (
{'address': address, 'id': id})
raise webob.exc.HTTPBadRequest(explanation=msg)
if len(fixed_ips) > 1:
LOG.warning(_LW('multiple fixed_ips exist, using the first: '
'%s'), fixed_address)
LOG.warning(_LW('multiple fixed_ips exist, using the first '
'IPv4 fixed_ip: %s'), fixed_address)
try:
self.network_api.associate_floating_ip(context, instance,
@@ -481,9 +481,7 @@ class FloatingIpTestV21(test.TestCase):
def test_floating_ip_release(self):
self.controller.delete(self.fake_req, 1)
def test_floating_ip_associate(self):
fixed_address = '192.168.1.100'
def _test_floating_ip_associate(self, fixed_address):
def fake_associate_floating_ip(*args, **kwargs):
self.assertEqual(fixed_address, kwargs['fixed_address'])
@@ -495,6 +493,24 @@ class FloatingIpTestV21(test.TestCase):
body=body)
self.assertEqual(202, rsp.status_int)
def test_floating_ip_associate(self):
self._test_floating_ip_associate(fixed_address='192.168.1.100')
@mock.patch.object(network.model.NetworkInfo, 'fixed_ips')
def test_associate_floating_ip_v4v6_fixed_ip(self, fixed_ips_mock):
fixed_address = '192.168.1.100'
fixed_ips_mock.return_value = [{'address': 'fc00:2001:db8::100'},
{'address': fixed_address}]
self._test_floating_ip_associate(fixed_address=fixed_address)
@mock.patch.object(network.model.NetworkInfo, 'fixed_ips',
return_value=[{'address': 'fc00:2001:db8::100'}])
def test_associate_floating_ip_v6_fixed_ip(self, fixed_ips_mock):
body = dict(addFloatingIp=dict(address=self.floating_ip))
self.assertRaises(webob.exc.HTTPBadRequest,
self.manager._add_floating_ip, self.fake_req,
TEST_INST, body=body)
def test_floating_ip_associate_invalid_instance(self):
def fake_get(self, context, id, expected_attrs=None,