Merge "Fail if FIP doens't have the requested port_id"

This commit is contained in:
Jenkins 2016-04-23 13:38:49 +00:00 committed by Gerrit Code Review
commit 983f8e1420
3 changed files with 110 additions and 28 deletions

View File

@ -313,15 +313,21 @@ def normalize_neutron_floating_ips(ips):
]
"""
ret = [dict(
id=ip['id'],
fixed_ip_address=ip.get('fixed_ip_address'),
floating_ip_address=ip['floating_ip_address'],
network=ip['floating_network_id'],
attached=(ip.get('port_id') is not None and
ip.get('port_id') != ''),
status=ip['status']
) for ip in ips]
ret = []
for ip in ips:
network_id = ip.get('floating_network_id', ip.get('network'))
ret.append(dict(
id=ip['id'],
fixed_ip_address=ip.get('fixed_ip_address'),
floating_ip_address=ip['floating_ip_address'],
network=network_id,
floating_network_id=network_id,
port_id=ip.get('port_id'),
router_id=ip.get('router_id'),
attached=(ip.get('port_id') is not None and
ip.get('port_id') != ''),
status=ip['status'],
))
return meta.obj_list_to_dict(ret)

View File

@ -3300,7 +3300,8 @@ class OpenStackCloud(object):
return [f_ip]
def create_floating_ip(self, network=None, server=None,
fixed_address=None, nat_destination=None):
fixed_address=None, nat_destination=None,
wait=False, timeout=60):
"""Allocate a new floating IP from a network or a pool.
:param network: Nova pool name or Neutron network name or id
@ -3312,6 +3313,12 @@ class OpenStackCloud(object):
:param nat_destination: (optional) Name or id of the network
that the fixed IP to attach the floating
IP to should be on.
:param wait: (optional) Whether to wait for the IP to be active.
Defaults to False. Only applies if a server is
provided.
:param timeout: (optional) How long to wait for the IP to be active.
Defaults to 60. Only applies if a server is
provided.
:returns: a floating IP address
@ -3319,13 +3326,11 @@ class OpenStackCloud(object):
"""
if self._use_neutron_floating():
try:
f_ips = _utils.normalize_neutron_floating_ips(
[self._neutron_create_floating_ip(
network_name_or_id=network, server=server,
fixed_address=fixed_address,
nat_destination=nat_destination)]
)
return f_ips[0]
return self._neutron_create_floating_ip(
network_name_or_id=network, server=server,
fixed_address=fixed_address,
nat_destination=nat_destination,
wait=wait, timeout=timeout)
except OpenStackCloudURINotFound as e:
self.log.debug(
"Something went wrong talking to neutron API: "
@ -3337,9 +3342,15 @@ class OpenStackCloud(object):
[self._nova_create_floating_ip(pool=network)])
return f_ips[0]
def _submit_create_fip(self, kwargs):
# Split into a method to aid in test mocking
return _utils.normalize_neutron_floating_ips(
[self.manager.submitTask(_tasks.NeutronFloatingIPCreate(
body={'floatingip': kwargs}))['floatingip']])[0]
def _neutron_create_floating_ip(
self, network_name_or_id=None, server=None,
fixed_address=None, nat_destination=None):
fixed_address=None, nat_destination=None, wait=False, timeout=60):
with _utils.neutron_exceptions(
"unable to create floating IP for net "
"{0}".format(network_name_or_id)):
@ -3358,6 +3369,7 @@ class OpenStackCloud(object):
kwargs = {
'floating_network_id': networks[0]['id'],
}
port = None
if server:
(port, fixed_ip_address) = self._get_free_fixed_port(
server, fixed_address=fixed_address,
@ -3365,8 +3377,37 @@ class OpenStackCloud(object):
if port:
kwargs['port_id'] = port['id']
kwargs['fixed_ip_address'] = fixed_ip_address
return self.manager.submitTask(_tasks.NeutronFloatingIPCreate(
body={'floatingip': kwargs}))['floatingip']
fip = self._submit_create_fip(kwargs)
fip_id = fip['id']
if port:
if fip['port_id'] != port['id']:
raise OpenStackCloudException(
"Attempted to create FIP on port {port} for server"
" {server} but something went wrong".format(
port=port['id'], server=server['id']))
# The FIP is only going to become active in this context
# when we've attached it to something, which only occurs
# if we've provided a port as a parameter
if wait:
try:
for count in _utils._iterate_timeout(
timeout,
"Timeout waiting for the floating IP"
" to be ACTIVE"):
fip = self.get_floating_ip(fip_id)
if fip['status'] == 'ACTIVE':
break
except OpenStackCloudTimeout:
self.log.error(
"Timed out on floating ip {fip} becoming active."
" Deleting".format(fip=fip_id))
try:
self.delete_floating_ip(fip_id)
except Exception:
pass
raise
return fip
def _nova_create_floating_ip(self, pool=None):
with _utils.shade_exceptions(
@ -3753,9 +3794,17 @@ class OpenStackCloud(object):
if reuse:
f_ip = self.available_floating_ip(network=network)
else:
start_time = time.time()
f_ip = self.create_floating_ip(
network=network, nat_destination=nat_destination)
network=network, nat_destination=nat_destination,
wait=wait, timeout=timeout)
timeout = timeout - (time.time() - start_time)
# We run attach as a second call rather than in the create call
# because there are code flows where we will not have an attached
# FIP yet. However, even if it was attached in the create, we run
# the attach function below to get back the server dict refreshed
# with the FIP information.
return self._attach_ip_to_server(
server=server, floating_ip=f_ip, fixed_address=fixed_address,
wait=wait, timeout=timeout)
@ -3820,7 +3869,10 @@ class OpenStackCloud(object):
if reuse:
f_ip = self.available_floating_ip()
else:
f_ip = self.create_floating_ip(server=server)
start_time = time.time()
f_ip = self.create_floating_ip(
server=server, wait=wait, timeout=timeout)
timeout = timeout - (time.time() - start_time)
if server:
# This gets passed in for both nova and neutron
# but is only meaninful for the neutron logic branch
@ -3828,6 +3880,11 @@ class OpenStackCloud(object):
created = True
try:
# We run attach as a second call rather than in the create call
# because there are code flows where we will not have an attached
# FIP yet. However, even if it was attached in the create, we run
# the attach function below to get back the server dict refreshed
# with the FIP information.
return self._attach_ip_to_server(
server=server, floating_ip=f_ip, wait=wait, timeout=timeout,
skip_attach=skip_attach)

View File

@ -19,6 +19,7 @@ test_floating_ip_neutron
Tests Floating IP resource methods for Neutron
"""
import mock
from mock import patch
import os_client_config
@ -340,20 +341,22 @@ class TestFloatingIP(base.TestCase):
mock_keystone_session,
mock_nova_client):
mock_has_service.return_value = True
mock__neutron_create_floating_ip.return_value = \
self.mock_floating_ip_list_rep['floatingips'][0]
fip = _utils.normalize_neutron_floating_ips(
self.mock_floating_ip_list_rep['floatingips'])[0]
mock__neutron_create_floating_ip.return_value = fip
mock_keystone_session.get_project_id.return_value = \
'4969c491a3c74ee4af974e6d800c62df'
fake_server = meta.obj_to_dict(fakes.FakeServer('1234', '', 'ACTIVE'))
self.client.add_ips_to_server(
dict(id='1234'), ip_pool='my-network', reuse=False)
fake_server, ip_pool='my-network', reuse=False)
mock__neutron_create_floating_ip.assert_called_once_with(
network_name_or_id='my-network', server=None,
fixed_address=None, nat_destination=None)
fixed_address=None, nat_destination=None, wait=False, timeout=60)
mock_attach_ip_to_server.assert_called_once_with(
server={'id': '1234'}, fixed_address=None,
floating_ip=self.floating_ip, wait=False, timeout=60)
server=fake_server, fixed_address=None,
floating_ip=fip, wait=False, timeout=mock.ANY)
@patch.object(OpenStackCloud, 'keystone_session')
@patch.object(OpenStackCloud, '_neutron_create_floating_ip')
@ -564,3 +567,19 @@ class TestFloatingIP(base.TestCase):
mock_delete_floating_ip.assert_called_once_with(
id="this-is-a-floating-ip-id",
timeout=60, wait=False)
@patch.object(OpenStackCloud, '_submit_create_fip')
@patch.object(OpenStackCloud, '_get_free_fixed_port')
@patch.object(OpenStackCloud, 'get_external_networks')
def test_create_floating_ip_no_port(
self, mock_get_ext_nets, mock_get_free_fixed_port,
mock_submit_create_fip):
fake_port = dict(id='port-id')
mock_get_ext_nets.return_value = [self.mock_get_network_rep]
mock_get_free_fixed_port.return_value = (fake_port, '10.0.0.2')
mock_submit_create_fip.return_value = dict(port_id=None)
self.assertRaises(
exc.OpenStackCloudException,
self.client._neutron_create_floating_ip,
server=dict(id='some-server'))