summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuul <zuul@review.openstack.org>2018-03-01 12:51:47 +0000
committerGerrit Code Review <review@openstack.org>2018-03-01 12:51:47 +0000
commit930a93fdc1c68667afc678c45de8f9c9f56f6b63 (patch)
treee210c4aaa94b5f819536c66eaa7d831365184026
parentfec91472b09d06674886b03ff58e9527de53086c (diff)
parentf064206916faa3f7b3308d36746151ad105e3bf6 (diff)
downloadheat-930a93fdc1c68667afc678c45de8f9c9f56f6b63.tar.gz
Merge "Replace deprecated nova calls for floatingip"
-rw-r--r--heat/engine/clients/client_exception.py4
-rw-r--r--heat/engine/clients/os/nova.py34
-rw-r--r--heat/engine/resources/openstack/nova/floatingip.py33
-rw-r--r--heat/tests/openstack/nova/test_floatingip.py167
4 files changed, 125 insertions, 113 deletions
diff --git a/heat/engine/clients/client_exception.py b/heat/engine/clients/client_exception.py
index 19a58bf0a..b2529535d 100644
--- a/heat/engine/clients/client_exception.py
+++ b/heat/engine/clients/client_exception.py
@@ -25,3 +25,7 @@ class EntityMatchNotFound(exception.HeatException):
class EntityUniqueMatchNotFound(EntityMatchNotFound):
msg_fmt = _("No %(entity)s unique match found for %(args)s.")
+
+
+class InterfaceNotFound(exception.HeatException):
+ msg_fmt = _("No network interface found for server %(id)s.")
diff --git a/heat/engine/clients/os/nova.py b/heat/engine/clients/os/nova.py
index 148266a3e..97dc66a48 100644
--- a/heat/engine/clients/os/nova.py
+++ b/heat/engine/clients/os/nova.py
@@ -19,17 +19,20 @@ import os
import pkgutil
import string
+from neutronclient.common import exceptions as q_exceptions
from novaclient import client as nc
from novaclient import exceptions
from oslo_config import cfg
from oslo_log import log as logging
from oslo_serialization import jsonutils
+from oslo_utils import netutils
import six
from six.moves.urllib import parse as urlparse
import tenacity
from heat.common import exception
from heat.common.i18n import _
+from heat.engine.clients import client_exception
from heat.engine.clients import client_plugin
from heat.engine.clients import os as os_client
from heat.engine import constraints
@@ -100,7 +103,8 @@ class NovaClientPlugin(client_plugin.ClientPlugin):
return client
def is_not_found(self, ex):
- return isinstance(ex, exceptions.NotFound)
+ return isinstance(ex, (exceptions.NotFound,
+ q_exceptions.NotFound))
def is_over_limit(self, ex):
return isinstance(ex, exceptions.OverLimit)
@@ -672,6 +676,34 @@ echo -e '%s\tALL=(ALL)\tNOPASSWD: ALL' >> /etc/sudoers
{'att': attach_id, 'srv': server_id})
return False
+ def associate_floatingip(self, server_id, floatingip_id):
+ iface_list = self.fetch_server(server_id).interface_list()
+ if len(iface_list) == 0:
+ raise client_exception.InterfaceNotFound(id=server_id)
+ if len(iface_list) > 1:
+ LOG.warning("Multiple interfaces found for server %s, "
+ "using the first one.", server_id)
+
+ port_id = iface_list[0].port_id
+ fixed_ips = iface_list[0].fixed_ips
+ fixed_address = next(ip['ip_address'] for ip in fixed_ips
+ if netutils.is_valid_ipv4(ip['ip_address']))
+ request_body = {
+ 'floatingip': {
+ 'port_id': port_id,
+ 'fixed_ip_address': fixed_address}}
+
+ self.clients.client('neutron').update_floatingip(floatingip_id,
+ request_body)
+
+ def dissociate_floatingip(self, floatingip_id):
+ request_body = {
+ 'floatingip': {
+ 'port_id': None,
+ 'fixed_ip_address': None}}
+ self.clients.client('neutron').update_floatingip(floatingip_id,
+ request_body)
+
def interface_detach(self, server_id, port_id):
with self.ignore_not_found:
server = self.fetch_server(server_id)
diff --git a/heat/engine/resources/openstack/nova/floatingip.py b/heat/engine/resources/openstack/nova/floatingip.py
index c89eca120..789bb7662 100644
--- a/heat/engine/resources/openstack/nova/floatingip.py
+++ b/heat/engine/resources/openstack/nova/floatingip.py
@@ -109,7 +109,6 @@ class NovaFloatingIp(resource.Resource):
def handle_delete(self):
with self.client_plugin('neutron').ignore_not_found:
self.neutron().delete_floatingip(self.resource_id)
- return True
def _resolve_attribute(self, key):
if self.resource_id is None:
@@ -167,49 +166,29 @@ class NovaFloatingIpAssociation(resource.Resource):
return self.physical_resource_name_or_FnGetRefId()
def handle_create(self):
- server = self.client().servers.get(self.properties[self.SERVER])
- fl_ip = self.neutron().show_floatingip(
- self.properties[self.FLOATING_IP])
-
- ip_address = fl_ip['floatingip']['floating_ip_address']
- self.client().servers.add_floating_ip(server, ip_address)
+ self.client_plugin().associate_floatingip(
+ self.properties[self.SERVER], self.properties[self.FLOATING_IP])
self.resource_id_set(self.id)
def handle_delete(self):
if self.resource_id is None:
return
-
- try:
- server = self.client().servers.get(self.properties[self.SERVER])
- if server:
- fl_ip = self.neutron().show_floatingip(
- self.properties[self.FLOATING_IP])
- ip_address = fl_ip['floatingip']['floating_ip_address']
- self.client().servers.remove_floating_ip(server, ip_address)
- except Exception as e:
- if not (self.client_plugin().is_not_found(e)
- or self.client_plugin().is_conflict(e)
- or self.client_plugin('neutron').is_not_found(e)):
- raise
+ with self.client_plugin().ignore_not_found:
+ self.client_plugin().dissociate_floatingip(
+ self.properties[self.FLOATING_IP])
def handle_update(self, json_snippet, tmpl_diff, prop_diff):
if prop_diff:
# If floating_ip in prop_diff, we need to remove the old floating
# ip from the old server, and then to add the new floating ip
# to the old/new(if the server_id is changed) server.
- # If prop_diff only has the server_id, no need to remove the
- # floating ip from the old server, nova does this automatically
- # when calling add_floating_ip().
if self.FLOATING_IP in prop_diff:
self.handle_delete()
server_id = (prop_diff.get(self.SERVER) or
self.properties[self.SERVER])
fl_ip_id = (prop_diff.get(self.FLOATING_IP) or
self.properties[self.FLOATING_IP])
- server = self.client().servers.get(server_id)
- fl_ip = self.neutron().show_floatingip(fl_ip_id)
- ip_address = fl_ip['floatingip']['floating_ip_address']
- self.client().servers.add_floating_ip(server, ip_address)
+ self.client_plugin().associate_floatingip(server_id, fl_ip_id)
self.resource_id_set(self.id)
diff --git a/heat/tests/openstack/nova/test_floatingip.py b/heat/tests/openstack/nova/test_floatingip.py
index 1cd79ca09..45d9d600a 100644
--- a/heat/tests/openstack/nova/test_floatingip.py
+++ b/heat/tests/openstack/nova/test_floatingip.py
@@ -63,28 +63,27 @@ floating_ip_template_with_assoc = '''
class NovaFloatingIPTest(common.HeatTestCase):
def setUp(self):
super(NovaFloatingIPTest, self).setUp()
- self.novaclient = mock.Mock()
- self.m.StubOutWithMock(nova.NovaClientPlugin, '_create')
- self.m.StubOutWithMock(self.novaclient.servers, 'get')
- self.m.StubOutWithMock(neutronclient.Client, 'list_networks')
+ self.novaclient = fakes_nova.FakeClient()
+ self.patchobject(nova.NovaClientPlugin, '_create',
+ return_value=self.novaclient)
self.m.StubOutWithMock(neutronclient.Client,
'create_floatingip')
self.m.StubOutWithMock(neutronclient.Client,
- 'show_floatingip')
- self.m.StubOutWithMock(neutronclient.Client,
'update_floatingip')
self.m.StubOutWithMock(neutronclient.Client,
'delete_floatingip')
- self.m.StubOutWithMock(self.novaclient.servers, 'add_floating_ip')
- self.m.StubOutWithMock(self.novaclient.servers, 'remove_floating_ip')
- self.patchobject(nova.NovaClientPlugin, 'get_server',
- return_value=mock.MagicMock())
- self.patchobject(nova.NovaClientPlugin, 'has_extension',
- return_value=True)
self.patchobject(neutron.NeutronClientPlugin,
'find_resourceid_by_name_or_id',
return_value='eeee')
+ def mock_interface(self, port, ip):
+ class MockIface(object):
+ def __init__(self, port_id, fixed_ip):
+ self.port_id = port_id
+ self.fixed_ips = [{'ip_address': fixed_ip}]
+
+ return MockIface(port, ip)
+
def mock_create_floatingip(self):
neutronclient.Client.create_floatingip({
'floatingip': {'floating_network_id': u'eeee'}
@@ -95,22 +94,28 @@ class NovaFloatingIPTest(common.HeatTestCase):
"floating_ip_address": "11.0.0.1"
}})
- def mock_show_floatingip(self, refid):
- if refid == 'fc68ea2c-b60b-4b4f-bd82-94ec81110766':
- address = '11.0.0.1'
+ def mock_update_floatingip(self,
+ fip='fc68ea2c-b60b-4b4f-bd82-94ec81110766',
+ ex=None, fip_request=None,
+ delete_assc=False):
+ if fip_request:
+ request_body = fip_request
+ elif delete_assc:
+ request_body = {
+ 'floatingip': {
+ 'port_id': None,
+ 'fixed_ip_address': None}}
else:
- address = '11.0.0.2'
- neutronclient.Client.show_floatingip(
- refid,
- ).AndReturn({'floatingip': {
- 'router_id': None,
- 'tenant_id': 'e936e6cd3e0b48dcb9ff853a8f253257',
- 'floating_network_id': 'eeee',
- 'fixed_ip_address': None,
- 'floating_ip_address': address,
- 'port_id': None,
- 'id': 'ffff'
- }})
+ request_body = {
+ 'floatingip': {
+ 'port_id': 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
+ 'fixed_ip_address': '1.2.3.4'}}
+ if ex:
+ neutronclient.Client.update_floatingip(
+ fip, request_body).AndRaise(ex)
+ else:
+ neutronclient.Client.update_floatingip(
+ fip, request_body).AndReturn(None)
def mock_delete_floatingip(self):
id = 'fc68ea2c-b60b-4b4f-bd82-94ec81110766'
@@ -127,10 +132,12 @@ class NovaFloatingIPTest(common.HeatTestCase):
self.stack)
def prepare_floating_ip_assoc(self):
- nova.NovaClientPlugin._create().AndReturn(
- self.novaclient)
- self.novaclient.servers.get('67dc62f9-efde-4c8b-94af-013e00f5dc57')
- self.mock_show_floatingip('fc68ea2c-b60b-4b4f-bd82-94ec81110766')
+ return_server = self.novaclient.servers.list()[1]
+ self.patchobject(self.novaclient.servers, 'get',
+ return_value=return_server)
+ iface = self.mock_interface('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
+ '1.2.3.4')
+ self.patchobject(return_server, 'interface_list', return_value=[iface])
template = template_format.parse(floating_ip_template_with_assoc)
self.stack = utils.parse_stack(template)
resource_defns = self.stack.t.resource_definitions(self.stack)
@@ -169,9 +176,7 @@ class NovaFloatingIPTest(common.HeatTestCase):
def test_delete_floating_ip_assoc_successful_if_create_failed(self):
rsrc = self.prepare_floating_ip_assoc()
- self.novaclient.servers.add_floating_ip(None, '11.0.0.1').AndRaise(
- fakes_nova.fake_exception(400))
-
+ self.mock_update_floatingip(fakes_nova.fake_exception(400))
self.m.ReplayAll()
rsrc.validate()
@@ -185,7 +190,7 @@ class NovaFloatingIPTest(common.HeatTestCase):
def test_floating_ip_assoc_create(self):
rsrc = self.prepare_floating_ip_assoc()
- self.novaclient.servers.add_floating_ip(None, '11.0.0.1')
+ self.mock_update_floatingip()
self.m.ReplayAll()
rsrc.validate()
@@ -200,12 +205,8 @@ class NovaFloatingIPTest(common.HeatTestCase):
def test_floating_ip_assoc_delete(self):
rsrc = self.prepare_floating_ip_assoc()
- self.novaclient.servers.add_floating_ip(None, '11.0.0.1')
- self.novaclient.servers.get(
- '67dc62f9-efde-4c8b-94af-013e00f5dc57').AndReturn('server')
- self.novaclient.servers.remove_floating_ip('server', '11.0.0.1')
- self.mock_show_floatingip('fc68ea2c-b60b-4b4f-bd82-94ec81110766')
-
+ self.mock_update_floatingip()
+ self.mock_update_floatingip(delete_assc=True)
self.m.ReplayAll()
rsrc.validate()
@@ -216,16 +217,11 @@ class NovaFloatingIPTest(common.HeatTestCase):
self.m.VerifyAll()
- def create_delete_assoc_with_exc(self, exc_code):
+ def test_floating_ip_assoc_delete_not_found(self):
rsrc = self.prepare_floating_ip_assoc()
- self.novaclient.servers.add_floating_ip(None, '11.0.0.1')
- self.novaclient.servers.get(
- "67dc62f9-efde-4c8b-94af-013e00f5dc57").AndReturn("server")
- self.mock_show_floatingip('fc68ea2c-b60b-4b4f-bd82-94ec81110766')
- self.novaclient.servers.remove_floating_ip("server",
- "11.0.0.1").AndRaise(
- fakes_nova.fake_exception(exc_code))
-
+ self.mock_update_floatingip()
+ self.mock_update_floatingip(ex=fakes_nova.fake_exception(404),
+ delete_assc=True)
self.m.ReplayAll()
rsrc.validate()
@@ -236,26 +232,28 @@ class NovaFloatingIPTest(common.HeatTestCase):
self.m.VerifyAll()
- def test_floating_ip_assoc_delete_conflict(self):
- self.create_delete_assoc_with_exc(exc_code=409)
-
- def test_floating_ip_assoc_delete_not_found(self):
- self.create_delete_assoc_with_exc(exc_code=404)
-
def test_floating_ip_assoc_update_server_id(self):
rsrc = self.prepare_floating_ip_assoc()
- # for create
- self.novaclient.servers.add_floating_ip(None, '11.0.0.1')
- # for update
- self.novaclient.servers.get(
- '2146dfbf-ba77-4083-8e86-d052f671ece5').AndReturn('server')
- self.novaclient.servers.add_floating_ip('server', '11.0.0.1')
- self.mock_show_floatingip('fc68ea2c-b60b-4b4f-bd82-94ec81110766')
+ self.mock_update_floatingip()
+ fip_request = {'floatingip': {
+ 'fixed_ip_address': '4.5.6.7',
+ 'port_id': 'bbbbb-bbbb-bbbb-bbbbbbbbb'}
+ }
+ self.mock_update_floatingip(fip_request=fip_request)
self.m.ReplayAll()
rsrc.validate()
scheduler.TaskRunner(rsrc.create)()
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
+
+ # for update
+ return_server = self.novaclient.servers.list()[2]
+ self.patchobject(self.novaclient.servers, 'get',
+ return_value=return_server)
+ iface = self.mock_interface('bbbbb-bbbb-bbbb-bbbbbbbbb',
+ '4.5.6.7')
+ self.patchobject(return_server, 'interface_list', return_value=[iface])
+
# update with the new server_id
props = copy.deepcopy(rsrc.properties.data)
update_server_id = '2146dfbf-ba77-4083-8e86-d052f671ece5'
@@ -270,17 +268,11 @@ class NovaFloatingIPTest(common.HeatTestCase):
def test_floating_ip_assoc_update_fl_ip(self):
rsrc = self.prepare_floating_ip_assoc()
# for create
- self.novaclient.servers.add_floating_ip(None, '11.0.0.1')
+ self.mock_update_floatingip()
# mock for delete the old association
- self.novaclient.servers.get(
- '67dc62f9-efde-4c8b-94af-013e00f5dc57').AndReturn('server')
- self.novaclient.servers.remove_floating_ip('server', '11.0.0.1')
+ self.mock_update_floatingip(delete_assc=True)
# mock for new association
- self.novaclient.servers.get(
- '67dc62f9-efde-4c8b-94af-013e00f5dc57').AndReturn('server')
- self.novaclient.servers.add_floating_ip('server', '11.0.0.2')
- self.mock_show_floatingip('fc68ea2c-b60b-4b4f-bd82-94ec81110766')
- self.mock_show_floatingip('fc68ea2c-cccc-4b4f-bd82-94ec81110766')
+ self.mock_update_floatingip(fip='fc68ea2c-dddd-4b4f-bd82-94ec81110766')
self.m.ReplayAll()
rsrc.validate()
@@ -288,7 +280,7 @@ class NovaFloatingIPTest(common.HeatTestCase):
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
# update with the new floatingip
props = copy.deepcopy(rsrc.properties.data)
- props['floating_ip'] = 'fc68ea2c-cccc-4b4f-bd82-94ec81110766'
+ props['floating_ip'] = 'fc68ea2c-dddd-4b4f-bd82-94ec81110766'
update_snippet = rsrc_defn.ResourceDefinition(rsrc.name, rsrc.type(),
props)
scheduler.TaskRunner(rsrc.update, update_snippet)()
@@ -299,28 +291,33 @@ class NovaFloatingIPTest(common.HeatTestCase):
def test_floating_ip_assoc_update_both(self):
rsrc = self.prepare_floating_ip_assoc()
# for create
- self.novaclient.servers.add_floating_ip(None, '11.0.0.1')
+ self.mock_update_floatingip()
# mock for delete the old association
- self.novaclient.servers.get(
- '67dc62f9-efde-4c8b-94af-013e00f5dc57').AndReturn('server')
- self.novaclient.servers.remove_floating_ip('server', '11.0.0.1')
+ self.mock_update_floatingip(delete_assc=True)
# mock for new association
- self.novaclient.servers.get(
- '2146dfbf-ba77-4083-8e86-d052f671ece5').AndReturn('new_server')
- self.novaclient.servers.add_floating_ip('new_server', '11.0.0.2')
- self.mock_show_floatingip('fc68ea2c-b60b-4b4f-bd82-94ec81110766')
- self.mock_show_floatingip('fc68ea2c-cccc-4b4f-bd82-94ec81110766')
-
+ fip_request = {'floatingip': {
+ 'fixed_ip_address': '4.5.6.7',
+ 'port_id': 'bbbbb-bbbb-bbbb-bbbbbbbbb'}
+ }
+ self.mock_update_floatingip(fip='fc68ea2c-dddd-4b4f-bd82-94ec81110766',
+ fip_request=fip_request)
self.m.ReplayAll()
rsrc.validate()
scheduler.TaskRunner(rsrc.create)()
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
- # update with the new floatingip
+ # update with the new floatingip and server
+ return_server = self.novaclient.servers.list()[2]
+ self.patchobject(self.novaclient.servers, 'get',
+ return_value=return_server)
+ iface = self.mock_interface('bbbbb-bbbb-bbbb-bbbbbbbbb',
+ '4.5.6.7')
+ self.patchobject(return_server, 'interface_list', return_value=[iface])
+
props = copy.deepcopy(rsrc.properties.data)
update_server_id = '2146dfbf-ba77-4083-8e86-d052f671ece5'
props['server_id'] = update_server_id
- props['floating_ip'] = 'fc68ea2c-cccc-4b4f-bd82-94ec81110766'
+ props['floating_ip'] = 'fc68ea2c-dddd-4b4f-bd82-94ec81110766'
update_snippet = rsrc_defn.ResourceDefinition(rsrc.name, rsrc.type(),
props)
scheduler.TaskRunner(rsrc.update, update_snippet)()