Validate number of instance metadata entries

The Server resource arbitrarily limits instance metadata to five
entries, when the actual provider's maxServerMeta limit could be much
higher.  Make the Server resource check the provider's maxServerMeta
absolute limit and enforce that limit in validate().

Change-Id: Ic00fc6f3a41ae783e43bd7f2df8663263d9cbf90
Closes-Bug: #1260427
This commit is contained in:
Jason Dunsmore 2013-12-12 13:05:18 -06:00
parent 86edcb0ba8
commit c772307829
4 changed files with 80 additions and 3 deletions

View File

@ -293,3 +293,9 @@ def server_to_ipaddress(client, server):
for n in server.networks:
if len(server.networks[n]) > 0:
return server.networks[n][0]
def absolute_limits(nova_client):
"""Return the absolute limits as a dictionary."""
limits = nova_client.limits.get()
return dict([(limit.name, limit.value) for limit in list(limits.absolute)])

View File

@ -147,9 +147,8 @@ class Server(resource.Resource):
'Type': 'Map',
'UpdateAllowed': True,
'Description': _('Arbitrary key/value metadata to store for this '
'server. A maximum of five entries is allowed, '
'and both keys and values must be 255 characters '
'or less.')},
'server. Both keys and values must be 255 '
'characters or less.')},
'user_data_format': {
'Type': 'String',
'Default': 'HEAT_CFNTOOLS',
@ -494,6 +493,18 @@ class Server(resource.Resource):
'') % dict(network=network['network'],
server=self.name))
# verify that the number of metadata entries is not greater
# than the maximum number allowed in the provider's absolute
# limits
metadata = self.properties.get('metadata')
if metadata is not None:
limits = nova_utils.absolute_limits(self.nova())
if len(metadata) > limits['maxServerMeta']:
msg = _('Instance metadata must not contain greater than %s '
'entries. This is the maximum number allowed by your '
'service provider') % limits['maxServerMeta']
raise exception.StackValidationFailed(message=msg)
def handle_delete(self):
'''
Delete a server, blocking until it is disposed by OpenStack

View File

@ -1156,3 +1156,57 @@ class ServersTest(HeatTestCase):
self.assertEqual(msg, str(ex))
self.m.VerifyAll()
def test_validate_metadata_too_many(self):
stack_name = 'srv_val_metadata'
(t, stack) = self._setup_test_stack(stack_name)
t['Resources']['WebServer']['Properties']['metadata'] = {'a': 1,
'b': 2,
'c': 3,
'd': 4}
server = servers.Server('server_create_image_err',
t['Resources']['WebServer'], stack)
limits = self.m.CreateMockAnything()
max_server_meta = self.m.CreateMockAnything()
max_server_meta.name = 'maxServerMeta'
max_server_meta.value = 3
limits.absolute = [max_server_meta]
self.m.StubOutWithMock(self.fc.limits, 'get')
self.fc.limits.get().AndReturn(limits)
self.m.StubOutWithMock(server, 'nova')
server.nova().MultipleTimes().AndReturn(self.fc)
self.m.ReplayAll()
ex = self.assertRaises(exception.StackValidationFailed,
server.validate)
self.assertIn('Instance metadata must not contain greater than 3 '
'entries', str(ex))
self.m.VerifyAll()
def test_validate_metadata_okay(self):
stack_name = 'srv_val_metadata'
(t, stack) = self._setup_test_stack(stack_name)
t['Resources']['WebServer']['Properties']['metadata'] = {'a': 1,
'b': 2,
'c': 3}
server = servers.Server('server_create_image_err',
t['Resources']['WebServer'], stack)
limits = self.m.CreateMockAnything()
max_server_meta = self.m.CreateMockAnything()
max_server_meta.name = 'maxServerMeta'
max_server_meta.value = 3
limits.absolute = [max_server_meta]
self.m.StubOutWithMock(self.fc.limits, 'get')
self.fc.limits.get().AndReturn(limits)
self.m.StubOutWithMock(server, 'nova')
server.nova().MultipleTimes().AndReturn(self.fc)
self.m.ReplayAll()
self.assertIsNone(server.validate())
self.m.VerifyAll()

View File

@ -360,3 +360,9 @@ class FakeHTTPClient(base_client.HTTPClient):
'id': '42'},
{'label': 'foo',
'id': '42'}]})
#
# Limits
#
def get_limits(self, *kw):
return (200, {'limits': {'absolute': {'maxServerMeta': 3}}})