From e7acfee7a8707d1e5f570bf5ce8190a24c068f0b Mon Sep 17 00:00:00 2001 From: Pavlo Shchelokovskyy Date: Fri, 12 Dec 2014 09:27:30 +0000 Subject: [PATCH] Allow floating_ip_pool on Nova-net in Sahara This patch removes neutron.network constraint from floating_ip_pool property of Sahara Node Group Template resource. That allows proper floating ip assignment on Nova-network. Also validation for this property is softened, so that it is not required on Neutron. Change-Id: I1cf796c92c27947d6c23888a47f50d4601fdbb1e Closes-Bug: #1399469 --- heat/engine/clients/os/neutron.py | 3 ++ heat/engine/resources/sahara_templates.py | 40 +++++++++++++++-------- heat/tests/test_sahara_templates.py | 27 +++++++++++++-- 3 files changed, 54 insertions(+), 16 deletions(-) diff --git a/heat/engine/clients/os/neutron.py b/heat/engine/clients/os/neutron.py index 13f68ab5b1..382e164c08 100644 --- a/heat/engine/clients/os/neutron.py +++ b/heat/engine/clients/os/neutron.py @@ -63,6 +63,9 @@ class NeutronClientPlugin(client_plugin.ClientPlugin): return False return ex.status_code == 413 + def is_no_unique(self, ex): + return isinstance(ex, exceptions.NeutronClientNoUniqueMatch) + def find_neutron_resource(self, props, key, key_type): return neutronV20.find_resourceid_by_name_or_id( self.client(), key_type, props.get(key)) diff --git a/heat/engine/resources/sahara_templates.py b/heat/engine/resources/sahara_templates.py index 23394ac4f5..a29e081064 100644 --- a/heat/engine/resources/sahara_templates.py +++ b/heat/engine/resources/sahara_templates.py @@ -135,10 +135,10 @@ class SaharaNodeGroupTemplate(resource.Resource): ), FLOATING_IP_POOL: properties.Schema( properties.Schema.STRING, - _("Name or UUID of the Neutron floating IP network to use."), - constraints=[ - constraints.CustomConstraint('neutron.network'), - ], + _("Name or UUID of the Neutron floating IP network or " + "name of the Nova floating ip pool to use. " + "Should not be provided when used with Nova-network " + "that auto-assign floating IPs."), ), NODE_CONFIGS: properties.Schema( properties.Schema.MAP, @@ -171,11 +171,10 @@ class SaharaNodeGroupTemplate(resource.Resource): auto_security_group = self.properties[self.AUTO_SECURITY_GROUP] availability_zone = self.properties[self.AVAILABILITY_ZONE] vol_availability_zone = self.properties[self.VOLUMES_AVAILABILITY_ZONE] - if floating_ip_pool: + if floating_ip_pool and self.is_using_neutron(): floating_ip_pool = self.client_plugin( - 'neutron').find_neutron_resource(self.properties, - self.FLOATING_IP_POOL, - 'network') + 'neutron').find_neutron_resource( + self.properties, self.FLOATING_IP_POOL, 'network') node_configs = self.properties.get(self.NODE_CONFIGS) node_group_template = self.client().node_group_templates.create( @@ -213,11 +212,26 @@ class SaharaNodeGroupTemplate(resource.Resource): res = super(SaharaNodeGroupTemplate, self).validate() if res: return res - # NOTE(pshchelo): floating ip pool must be set for Neutron - if (self.is_using_neutron() and - not self.properties.get(self.FLOATING_IP_POOL)): - msg = _("%s must be provided.") % self.FLOATING_IP_POOL - raise exception.StackValidationFailed(message=msg) + pool = self.properties[self.FLOATING_IP_POOL] + if pool: + if self.is_using_neutron(): + try: + self.client_plugin('neutron').find_neutron_resource( + self.properties, self.FLOATING_IP_POOL, 'network') + except Exception as ex: + if (self.client_plugin('neutron').is_not_found(ex) + or self.client_plugin('neutron').is_no_unique(ex)): + raise exception.StackValidationFailed( + message=ex.message) + raise + else: + try: + self.client('nova').floating_ip_pools.find(name=pool) + except Exception as ex: + if self.client_plugin('nova').is_not_found(ex): + raise exception.StackValidationFailed( + message=ex.message) + raise class SaharaClusterTemplate(resource.Resource): diff --git a/heat/tests/test_sahara_templates.py b/heat/tests/test_sahara_templates.py index a08d5da81c..3d37445cfe 100644 --- a/heat/tests/test_sahara_templates.py +++ b/heat/tests/test_sahara_templates.py @@ -149,13 +149,34 @@ class SaharaNodeGroupTemplateTest(common.HeatTestCase): self.assertEqual(expected, six.text_type(ex)) self.ngt_mgr.delete.assert_called_once_with(self.fake_ngt.id) - def test_validate_no_floatingippool_on_neutron_fails(self): - self.t['resources']['node-group']['properties'].pop('floating_ip_pool') + def test_validate_floatingippool_on_neutron_fails(self): ngt = self._init_ngt(self.t) self.patchobject(ngt, 'is_using_neutron').return_value = True + + self.patchobject( + neutron.NeutronClientPlugin, 'find_neutron_resource' + ).side_effect = [ + neutron.exceptions.NeutronClientNoUniqueMatch(message='Too many'), + neutron.exceptions.NeutronClientException(message='Not found', + status_code=404) + ] ex = self.assertRaises(exception.StackValidationFailed, ngt.validate) - self.assertEqual('floating_ip_pool must be provided.', + self.assertEqual('Too many', six.text_type(ex)) + ex = self.assertRaises(exception.StackValidationFailed, ngt.validate) + self.assertEqual('Not found', + six.text_type(ex)) + + def test_validate_floatingippool_on_novanetwork_fails(self): + ngt = self._init_ngt(self.t) + self.patchobject(ngt, 'is_using_neutron').return_value = False + nova_mock = mock.MagicMock() + nova_mock.floating_ip_pools.find.side_effect = ( + nova.exceptions.NotFound(404, message='Not found')) + self.patchobject(nova.NovaClientPlugin, + '_create').return_value = nova_mock + ex = self.assertRaises(exception.StackValidationFailed, ngt.validate) + self.assertEqual('Not found', six.text_type(ex)) def test_validate_flavor_constraint_return_false(self): self.t['resources']['node-group']['properties'].pop('floating_ip_pool')