Implement custom constraint for nova server

Many resources have 'InstanceId' property related
with nova server, add nova server custom constraint
to validate the existent of the server.

Change-Id: I4ee5a392488f26b2de708412d58f9c206d6f2c43
Implements: blueprint nova-custom-constraints
This commit is contained in:
huangtianhua 2014-11-12 17:22:40 +08:00
parent a4d98f68ab
commit 7804859d7e
4 changed files with 55 additions and 0 deletions

View File

@ -231,6 +231,10 @@ class ImageNotFound(HeatException):
msg_fmt = _("The Image (%(image_name)s) could not be found.")
class ServerNotFound(HeatException):
msg_fmt = _("The server (%(server)s) could not be found.")
class PhysicalResourceNameAmbiguity(HeatException):
msg_fmt = _(
"Multiple physical resources were found with name (%(name)s).")

View File

@ -32,6 +32,7 @@ from heat.common import exception
from heat.common.i18n import _
from heat.common.i18n import _LW
from heat.engine.clients import client_plugin
from heat.engine import constraints
from heat.engine import scheduler
LOG = logging.getLogger(__name__)
@ -410,8 +411,24 @@ echo -e '%s\tALL=(ALL)\tNOPASSWD: ALL' >> /etc/sudoers
if len(server.networks[n]) > 0:
return server.networks[n][0]
def get_server(self, server):
try:
return self.client().servers.get(server)
except exceptions.NotFound as ex:
LOG.warn(_LW('Server (%(server)s) not found: %(ex)s'),
{'server': server, 'ex': ex})
raise exception.ServerNotFound(server=server)
def absolute_limits(self):
"""Return the absolute limits as a dictionary."""
limits = self.client().limits.get()
return dict([(limit.name, limit.value)
for limit in list(limits.absolute)])
class ServerConstraint(constraints.BaseCustomConstraint):
expected_exceptions = (exception.ServerNotFound,)
def validate_with_client(self, client, server):
client.client_plugin('nova').get_server(server)

View File

@ -96,6 +96,19 @@ class NovaClientPluginTests(NovaClientPluginTestCase):
self.nova_plugin.get_keypair, 'notakey')
self.m.VerifyAll()
def test_get_server(self):
"""Tests the get_server function."""
my_server = self.m.CreateMockAnything()
self.nova_client.servers = self.m.CreateMockAnything()
self.nova_client.servers.get('my_server').AndReturn(my_server)
self.nova_client.servers.get('idontexist').AndRaise(
nova_exceptions.NotFound(404))
self.m.ReplayAll()
self.assertEqual(my_server, self.nova_plugin.get_server('my_server'))
self.assertRaises(exception.ServerNotFound,
self.nova_plugin.get_server, 'idontexist')
self.m.VerifyAll()
def test_get_status(self):
server = self.m.CreateMockAnything()
server.status = 'ACTIVE'
@ -256,3 +269,23 @@ class NovaUtilsMetadataTests(NovaClientPluginTestCase):
}
self.assertEqual(expected, self.nova_plugin.meta_serialize(original))
class ServerConstraintTest(NovaClientPluginTestCase):
def setUp(self):
super(ServerConstraintTest, self).setUp()
self.ctx = utils.dummy_context()
self.mock_get_server = mock.Mock()
self.ctx.clients.client_plugin(
'nova').get_server = self.mock_get_server
self.constraint = nova.ServerConstraint()
def test_validation(self):
self.mock_get_server.return_value = mock.MagicMock()
self.assertTrue(self.constraint.validate("foo", self.ctx))
def test_validation_error(self):
self.mock_get_server.side_effect = exception.ServerNotFound(
server='bar')
self.assertFalse(self.constraint.validate("bar", self.ctx))

View File

@ -57,6 +57,7 @@ heat.constraints =
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
heat.stack_lifecycle_plugins =