diff --git a/heat/engine/clients/os/nova.py b/heat/engine/clients/os/nova.py index 052b973e4..62c532d04 100644 --- a/heat/engine/clients/os/nova.py +++ b/heat/engine/clients/os/nova.py @@ -432,3 +432,23 @@ class ServerConstraint(constraints.BaseCustomConstraint): def validate_with_client(self, client, server): client.client_plugin('nova').get_server(server) + + +class KeypairConstraint(constraints.BaseCustomConstraint): + + expected_exceptions = (exception.UserKeyPairMissing,) + + def validate_with_client(self, client, key_name): + if not key_name: + # Don't validate empty key, which can happen when you + # use a KeyPair resource + return True + client.client_plugin('nova').get_keypair(key_name) + + +class FlavorConstraint(constraints.BaseCustomConstraint): + + expected_exceptions = (exception.FlavorMissing,) + + def validate_with_client(self, client, flavor): + client.client_plugin('nova').get_flavor_id(flavor) diff --git a/heat/engine/resources/nova_keypair.py b/heat/engine/resources/nova_keypair.py index 065daa4a3..6a53112cd 100644 --- a/heat/engine/resources/nova_keypair.py +++ b/heat/engine/resources/nova_keypair.py @@ -11,7 +11,6 @@ # License for the specific language governing permissions and limitations # under the License. -from heat.common import exception from heat.common.i18n import _ from heat.engine import attributes from heat.engine import constraints @@ -133,17 +132,5 @@ class KeyPair(resource.Resource): return self.resource_id -class KeypairConstraint(constraints.BaseCustomConstraint): - - expected_exceptions = (exception.UserKeyPairMissing,) - - def validate_with_client(self, client, value): - if not value: - # Don't validate empty key, which can happen when you use a KeyPair - # resource - return True - client.client_plugin('nova').get_keypair(value) - - def resource_mapping(): return {'OS::Nova::KeyPair': KeyPair} diff --git a/heat/engine/resources/server.py b/heat/engine/resources/server.py index ec0a7b0b0..306d1a30c 100644 --- a/heat/engine/resources/server.py +++ b/heat/engine/resources/server.py @@ -1143,14 +1143,6 @@ class Server(stack_user.StackUser): return defn.freeze(properties=props) -class FlavorConstraint(constraints.BaseCustomConstraint): - - expected_exceptions = (exception.FlavorMissing,) - - def validate_with_client(self, client, value): - client.client_plugin('nova').get_flavor_id(value) - - def resource_mapping(): return { 'OS::Nova::Server': Server, diff --git a/heat/tests/common.py b/heat/tests/common.py index c69b4fe8e..8ccb04bcf 100644 --- a/heat/tests/common.py +++ b/heat/tests/common.py @@ -27,9 +27,9 @@ import testtools from heat.common import messaging from heat.engine.clients.os import glance from heat.engine.clients.os import keystone +from heat.engine.clients.os import nova from heat.engine import environment from heat.engine import resources -from heat.engine.resources import nova_keypair from heat.engine import scheduler from heat.tests import fakes from heat.tests import utils @@ -143,8 +143,8 @@ class HeatTestCase(testscenarios.WithScenarios, return fkc def stub_KeypairConstraint_validate(self): - self.m.StubOutWithMock(nova_keypair.KeypairConstraint, 'validate') - nova_keypair.KeypairConstraint.validate( + self.m.StubOutWithMock(nova.KeypairConstraint, 'validate') + nova.KeypairConstraint.validate( mox.IgnoreArg(), mox.IgnoreArg()).MultipleTimes().AndReturn(True) def stub_ImageConstraint_validate(self, num=None): diff --git a/heat/tests/test_notifications.py b/heat/tests/test_notifications.py index 88fe25ce6..1b317dab1 100644 --- a/heat/tests/test_notifications.py +++ b/heat/tests/test_notifications.py @@ -17,6 +17,7 @@ from oslo.utils import timeutils from heat.common import exception from heat.common import template_format from heat.engine.clients.os import glance +from heat.engine.clients.os import nova from heat.engine import environment from heat.engine import parser from heat.engine import resource @@ -24,7 +25,6 @@ from heat.engine import resource from heat.engine.resources import autoscaling from heat.engine.resources import instance from heat.engine.resources import loadbalancer -from heat.engine.resources import nova_keypair from heat.engine.resources import user from heat.engine.resources import wait_condition as waitc from heat.engine import signal_responder as signal @@ -166,7 +166,7 @@ class ScaleNotificationTest(common.HeatTestCase): def mock_stack_except_for_group(self): self.m_validate = self.patchobject(parser.Stack, 'validate') - self.patchobject(nova_keypair.KeypairConstraint, 'validate') + self.patchobject(nova.KeypairConstraint, 'validate') self.patchobject(glance.ImageConstraint, 'validate') self.patchobject(instance.Instance, 'handle_create')\ .return_value = True diff --git a/heat/tests/test_nova_client.py b/heat/tests/test_nova_client.py index 8d930bb0a..112b952da 100644 --- a/heat/tests/test_nova_client.py +++ b/heat/tests/test_nova_client.py @@ -12,6 +12,7 @@ # under the License. """Tests for :module:'heat.engine.resources.nova_utls'.""" +import collections import mock from novaclient import exceptions as nova_exceptions from oslo.config import cfg @@ -22,6 +23,7 @@ from heat.common import exception from heat.engine.clients.os import nova from heat.tests import common from heat.tests import utils +from heat.tests.v1_1 import fakes as fakes_v1_1 class NovaClientPluginTestCase(common.HeatTestCase): @@ -289,3 +291,50 @@ class ServerConstraintTest(NovaClientPluginTestCase): self.mock_get_server.side_effect = exception.ServerNotFound( server='bar') self.assertFalse(self.constraint.validate("bar", self.ctx)) + + +class FlavorConstraintTest(common.HeatTestCase): + + def test_validate(self): + client = fakes_v1_1.FakeClient() + self.stub_keystoneclient() + self.m.StubOutWithMock(nova.NovaClientPlugin, '_create') + nova.NovaClientPlugin._create().AndReturn(client) + client.flavors = self.m.CreateMockAnything() + + flavor = collections.namedtuple("Flavor", ["id", "name"]) + flavor.id = "1234" + flavor.name = "foo" + client.flavors.list().MultipleTimes().AndReturn([flavor]) + self.m.ReplayAll() + + constraint = nova.FlavorConstraint() + ctx = utils.dummy_context() + self.assertFalse(constraint.validate("bar", ctx)) + self.assertTrue(constraint.validate("foo", ctx)) + self.assertTrue(constraint.validate("1234", ctx)) + + self.m.VerifyAll() + + +class KeypairConstraintTest(common.HeatTestCase): + + def test_validation(self): + client = fakes_v1_1.FakeClient() + self.m.StubOutWithMock(nova.NovaClientPlugin, '_create') + nova.NovaClientPlugin._create().AndReturn(client) + client.keypairs = self.m.CreateMockAnything() + + key = collections.namedtuple("Key", ["name"]) + key.name = "foo" + client.keypairs.get('bar').AndRaise(fakes_v1_1.fake_exception()) + client.keypairs.get(key.name).AndReturn(key) + self.m.ReplayAll() + + constraint = nova.KeypairConstraint() + ctx = utils.dummy_context() + self.assertFalse(constraint.validate("bar", ctx)) + self.assertTrue(constraint.validate("foo", ctx)) + self.assertTrue(constraint.validate("", ctx)) + + self.m.VerifyAll() diff --git a/heat/tests/test_nova_keypair.py b/heat/tests/test_nova_keypair.py index 3ff5de082..ed6130c07 100644 --- a/heat/tests/test_nova_keypair.py +++ b/heat/tests/test_nova_keypair.py @@ -11,7 +11,6 @@ # License for the specific language governing permissions and limitations # under the License. -import collections import copy import six @@ -178,26 +177,3 @@ class NovaKeyPairTest(common.HeatTestCase): self.assertEqual((tp_test.CREATE, tp_test.COMPLETE), tp_test.state) self.assertEqual(tp_test.resource_id, created_key.name) self.m.VerifyAll() - - -class KeypairConstraintTest(common.HeatTestCase): - - def test_validation(self): - client = fakes.FakeClient() - self.m.StubOutWithMock(nova.NovaClientPlugin, '_create') - nova.NovaClientPlugin._create().AndReturn(client) - client.keypairs = self.m.CreateMockAnything() - - key = collections.namedtuple("Key", ["name"]) - key.name = "foo" - client.keypairs.get('bar').AndRaise(fakes.fake_exception()) - client.keypairs.get(key.name).AndReturn(key) - self.m.ReplayAll() - - constraint = nova_keypair.KeypairConstraint() - ctx = utils.dummy_context() - self.assertFalse(constraint.validate("bar", ctx)) - self.assertTrue(constraint.validate("foo", ctx)) - self.assertTrue(constraint.validate("", ctx)) - - self.m.VerifyAll() diff --git a/heat/tests/test_server.py b/heat/tests/test_server.py index 646fcc83b..94acd8b6e 100644 --- a/heat/tests/test_server.py +++ b/heat/tests/test_server.py @@ -36,7 +36,6 @@ from heat.engine import scheduler from heat.engine import template from heat.openstack.common import uuidutils from heat.tests import common -from heat.tests import fakes from heat.tests import utils from heat.tests.v1_1 import fakes as fakes_v1_1 @@ -2757,27 +2756,3 @@ class ServersTest(common.HeatTestCase): self.assertEqual((stack.RESTORE, stack.COMPLETE), stack.state) self.m.VerifyAll() - - -class FlavorConstraintTest(common.HeatTestCase): - - def test_validate(self): - client = fakes.FakeClient() - self.stub_keystoneclient() - self.m.StubOutWithMock(nova.NovaClientPlugin, '_create') - nova.NovaClientPlugin._create().AndReturn(client) - client.flavors = self.m.CreateMockAnything() - - flavor = collections.namedtuple("Flavor", ["id", "name"]) - flavor.id = "1234" - flavor.name = "foo" - client.flavors.list().MultipleTimes().AndReturn([flavor]) - self.m.ReplayAll() - - constraint = servers.FlavorConstraint() - ctx = utils.dummy_context() - self.assertFalse(constraint.validate("bar", ctx)) - self.assertTrue(constraint.validate("foo", ctx)) - self.assertTrue(constraint.validate("1234", ctx)) - - self.m.VerifyAll() diff --git a/setup.cfg b/setup.cfg index c790199ac..4f5bc8217 100644 --- a/setup.cfg +++ b/setup.cfg @@ -49,15 +49,15 @@ heat.clients = sahara = heat.engine.clients.os.sahara:SaharaClientPlugin heat.constraints = - nova.flavor = heat.engine.resources.server:FlavorConstraint + nova.flavor = heat.engine.clients.os.nova:FlavorConstraint neutron.network = heat.engine.clients.os.neutron:NetworkConstraint neutron.port = heat.engine.clients.os.neutron:PortConstraint neutron.router = heat.engine.clients.os.neutron:RouterConstraint neutron.subnet = heat.engine.clients.os.neutron:SubnetConstraint glance.image = heat.engine.clients.os.glance:ImageConstraint iso_8601 = heat.engine.resources.iso_8601:ISO8601Constraint - nova.keypair = heat.engine.resources.nova_keypair:KeypairConstraint nova.server = heat.engine.clients.os.nova:ServerConstraint + nova.keypair = heat.engine.clients.os.nova:KeypairConstraint heat.stack_lifecycle_plugins =