Add OS::Heat::None resource

Adds a new resource, designed to enable easy "stubbing out"
of resources via the environment resource_registry.

It takes any properties, and returns any attribute (as None),
meaning it can be uses in place of "noop" nested stacks which
dummy an existing resources by matching parameters/outputs to
properties/attributes.

Implements: blueprint noop-resource
Change-Id: Idc485a9fcf7287030dda22f893486279be9e1a68
This commit is contained in:
Steven Hardy 2015-07-10 09:39:00 +01:00
parent bd7895c555
commit 8f02c9b540
3 changed files with 142 additions and 0 deletions

View File

@ -0,0 +1,56 @@
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import six
import uuid
from heat.engine import properties
from heat.engine import resource
from heat.engine import support
class NoneResource(resource.Resource):
'''
A resource which enables easily disabling certain resources via the
resource_registry. It does nothing, but can effectively stub out
any other resource because it will accept any properties and return
any attribute (as None). Note this resource always does nothing
on update (e.g it is not replaced even if a change to the stubbed
resource properties would cause replacement).
'''
support_status = support.SupportStatus(version='5.0.0')
properties_schema = {}
attributes_schema = {}
def _needs_update(self, after, before, after_props, before_props,
prev_resource):
return False
def reparse(self):
self.properties = properties.Properties(schema={}, data={})
def handle_create(self):
self.resource_id_set(six.text_type(uuid.uuid4()))
def validate(self):
pass
def FnGetAtt(self, key, *path):
return None
def resource_mapping():
return {
'OS::Heat::None': NoneResource,
}

View File

@ -0,0 +1,77 @@
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from heat.common import template_format
from heat.tests import common
from heat.tests import utils
class NoneResourceTest(common.HeatTestCase):
tmpl = '''
heat_template_version: 2015-10-15
resources:
none:
type: OS::Heat::None
properties:
ignored: foo
outputs:
anything:
value: {get_attr: [none, anything]}
'''
def _create_none_stack(self):
self.t = template_format.parse(self.tmpl)
self.stack = utils.parse_stack(self.t)
self.rsrc = self.stack['none']
self.assertIsNone(self.rsrc.validate())
self.stack.create()
self.assertEqual(self.rsrc.CREATE, self.rsrc.action)
self.assertEqual(self.rsrc.COMPLETE, self.rsrc.status)
self.assertEqual(self.stack.CREATE, self.stack.action)
self.assertEqual(self.stack.COMPLETE, self.stack.status)
self.assertEqual(None, self.stack.output('anything'))
def test_none_stack_create(self):
self._create_none_stack()
def test_none_stack_update_nochange(self):
self._create_none_stack()
before_refid = self.rsrc.FnGetRefId()
self.assertIsNotNone(before_refid)
utils.update_stack(self.stack, self.t)
self.assertEqual((self.stack.UPDATE, self.stack.COMPLETE),
self.stack.state)
self.assertEqual(before_refid, self.stack['none'].FnGetRefId())
def test_none_stack_update_add_prop(self):
self._create_none_stack()
before_refid = self.rsrc.FnGetRefId()
self.assertIsNotNone(before_refid)
new_t = self.t.copy()
new_t['resources']['none']['properties']['another'] = 123
utils.update_stack(self.stack, new_t)
self.assertEqual((self.stack.UPDATE, self.stack.COMPLETE),
self.stack.state)
self.assertEqual(before_refid, self.stack['none'].FnGetRefId())
def test_none_stack_update_del_prop(self):
self._create_none_stack()
before_refid = self.rsrc.FnGetRefId()
self.assertIsNotNone(before_refid)
new_t = self.t.copy()
del(new_t['resources']['none']['properties']['ignored'])
utils.update_stack(self.stack, new_t)
self.assertEqual((self.stack.UPDATE, self.stack.COMPLETE),
self.stack.state)
self.assertEqual(before_refid, self.stack['none'].FnGetRefId())

View File

@ -102,6 +102,15 @@ def parse_stack(t, params=None, files=None, stack_name=None,
return stk
def update_stack(stk, new_t, params=None, files=None):
ctx = dummy_context()
templ = template.Template(new_t, files=files,
env=environment.Environment(params))
updated_stack = stack.Stack(ctx, 'updated_stack', templ)
stk.update(updated_stack)
class PhysName(object):
mock_short_id = 'x' * 12