Remove update_allowed_keys definition and usage

The update_allowed_keys attribute didn't really define any useful
policy, and prevented automatic update which should be handled by the
base Resource class like DeletionPolicy. This patch removes the usage
and the various definitions around the code base.

Change-Id: I78494aba07b6badeca8e95f1875ca8e4b9b0290c
Co-Authored-By: ala.rezmerita@cloudwatt.com
Partial-Bug: #1316171
This commit is contained in:
Thomas Herve 2014-05-05 17:37:56 +02:00
parent 322f61f5c7
commit 65e068557d
32 changed files with 30 additions and 144 deletions

View File

@ -53,8 +53,6 @@ class MarconiQueue(resource.Resource):
"href": _("The resource href of the queue.") "href": _("The resource href of the queue.")
} }
update_allowed_keys = ('Properties',)
def __init__(self, name, json_snippet, stack): def __init__(self, name, json_snippet, stack):
super(MarconiQueue, self).__init__(name, json_snippet, stack) super(MarconiQueue, self).__init__(name, json_snippet, stack)
self.clients = clients.Clients(self.context) self.clients = clients.Clients(self.context)

View File

@ -251,7 +251,6 @@ class Group(resource.Resource):
# resource. # resource.
} }
update_allowed_keys = ('Properties',)
# Everything can be changed. # Everything can be changed.
update_allowed_properties = (GROUP_CONFIGURATION, LAUNCH_CONFIGURATION) update_allowed_properties = (GROUP_CONFIGURATION, LAUNCH_CONFIGURATION)
@ -413,7 +412,6 @@ class ScalingPolicy(resource.Resource):
), ),
} }
update_allowed_keys = ('Properties',)
# Everything other than group can be changed. # Everything other than group can be changed.
update_allowed_properties = ( update_allowed_properties = (
NAME, CHANGE, CHANGE_PERCENT, DESIRED_CAPACITY, COOLDOWN, TYPE, ARGS, NAME, CHANGE, CHANGE_PERCENT, DESIRED_CAPACITY, COOLDOWN, TYPE, ARGS,
@ -502,7 +500,6 @@ class WebHook(resource.Resource):
), ),
} }
update_allowed_keys = ('Properties',)
# Everything other than policy can be changed. # Everything other than policy can be changed.
update_allowed_properties = (NAME, METADATA) update_allowed_properties = (NAME, METADATA)

View File

@ -146,8 +146,6 @@ class CloudDns(resource.Resource):
), ),
} }
update_allowed_keys = ('Properties',)
def cloud_dns(self): def cloud_dns(self):
return self.stack.clients.cloud_dns() return self.stack.clients.cloud_dns()

View File

@ -367,8 +367,6 @@ class CloudLoadBalancer(resource.Resource):
'PublicIp': _('Public IP address of the specified ' 'PublicIp': _('Public IP address of the specified '
'instance.')} 'instance.')}
update_allowed_keys = ('Properties',)
def __init__(self, name, json_snippet, stack): def __init__(self, name, json_snippet, stack):
super(CloudLoadBalancer, self).__init__(name, json_snippet, stack) super(CloudLoadBalancer, self).__init__(name, json_snippet, stack)
self.clb = self.cloud_lb() self.clb = self.cloud_lb()

View File

@ -76,10 +76,6 @@ class Resource(object):
# If True, this resource must be created before it can be referenced. # If True, this resource must be created before it can be referenced.
strict_dependency = True strict_dependency = True
# Resource implementation set this to the subset of template keys
# which are supported for handle_update, used by update_template_diff
update_allowed_keys = ()
# Resource implementation set this to the subset of resource properties # Resource implementation set this to the subset of resource properties
# supported for handle_update, used by update_template_diff_properties # supported for handle_update, used by update_template_diff_properties
update_allowed_properties = () update_allowed_properties = ()
@ -242,12 +238,8 @@ class Resource(object):
''' '''
Returns the difference between the before and after json snippets. If Returns the difference between the before and after json snippets. If
something has been removed in after which exists in before we set it to something has been removed in after which exists in before we set it to
None. If any keys have changed which are not in update_allowed_keys, None.
raises UpdateReplace if the differing keys are not in
update_allowed_keys
''' '''
update_allowed_set = set(self.update_allowed_keys)
# Create a set containing the keys in both current and update template # Create a set containing the keys in both current and update template
template_keys = set(before.keys()) template_keys = set(before.keys())
template_keys.update(set(after.keys())) template_keys.update(set(after.keys()))
@ -256,9 +248,6 @@ class Resource(object):
changed_keys_set = set([k for k in template_keys changed_keys_set = set([k for k in template_keys
if before.get(k) != after.get(k)]) if before.get(k) != after.get(k)])
if not changed_keys_set.issubset(update_allowed_set):
raise UpdateReplace(self.name)
return dict((k, after.get(k)) for k in changed_keys_set) return dict((k, after.get(k)) for k in changed_keys_set)
def update_template_diff_properties(self, after_props, before_props): def update_template_diff_properties(self, after_props, before_props):

View File

@ -139,8 +139,6 @@ class InstanceGroup(stack_resource.StackResource):
), ),
} }
update_allowed_keys = ('Properties', 'UpdatePolicy',)
attributes_schema = { attributes_schema = {
"InstanceList": _("A comma-delimited list of server ip addresses. " "InstanceList": _("A comma-delimited list of server ip addresses. "
"(Heat extension).") "(Heat extension).")
@ -560,8 +558,6 @@ class AutoScalingGroup(InstanceGroup, CooldownMixin):
schema=rolling_update_schema) schema=rolling_update_schema)
} }
update_allowed_keys = ('Properties', 'UpdatePolicy')
def handle_create(self): def handle_create(self):
if self.properties[self.DESIRED_CAPACITY]: if self.properties[self.DESIRED_CAPACITY]:
num_to_create = self.properties[self.DESIRED_CAPACITY] num_to_create = self.properties[self.DESIRED_CAPACITY]
@ -904,8 +900,6 @@ class AutoScalingResourceGroup(AutoScalingGroup):
), ),
} }
update_allowed_keys = ('Properties',)
# Override the InstanceGroup attributes_schema; we don't want any # Override the InstanceGroup attributes_schema; we don't want any
# attributes. # attributes.
attributes_schema = {} attributes_schema = {}
@ -1007,8 +1001,6 @@ class ScalingPolicy(signal_responder.SignalResponder, CooldownMixin):
), ),
} }
update_allowed_keys = ('Properties',)
attributes_schema = { attributes_schema = {
"AlarmUrl": _("A signed url to handle the alarm. " "AlarmUrl": _("A signed url to handle the alarm. "
"(Heat extension).") "(Heat extension).")
@ -1147,8 +1139,6 @@ class AutoScalingPolicy(ScalingPolicy):
), ),
} }
update_allowed_keys = ('Properties',)
attributes_schema = { attributes_schema = {
"alarm_url": _("A signed url to handle the alarm.") "alarm_url": _("A signed url to handle the alarm.")
} }

View File

@ -148,8 +148,6 @@ class CeilometerAlarm(resource.Resource):
} }
properties_schema.update(common_properties_schema) properties_schema.update(common_properties_schema)
update_allowed_keys = ('Properties',)
def handle_create(self): def handle_create(self):
props = actions_to_urls(self.stack, self.parsed_template('Properties')) props = actions_to_urls(self.stack, self.parsed_template('Properties'))
props['name'] = self.physical_resource_name() props['name'] = self.physical_resource_name()
@ -220,8 +218,6 @@ class CombinationAlarm(resource.Resource):
} }
properties_schema.update(common_properties_schema) properties_schema.update(common_properties_schema)
update_allowed_keys = ('Properties',)
def handle_create(self): def handle_create(self):
properties = actions_to_urls(self.stack, properties = actions_to_urls(self.stack,
self.parsed_template('Properties')) self.parsed_template('Properties'))

View File

@ -131,8 +131,6 @@ class CloudWatchAlarm(resource.Resource):
strict_dependency = False strict_dependency = False
update_allowed_keys = ('Properties',)
def handle_create(self): def handle_create(self):
wr = watchrule.WatchRule(context=self.context, wr = watchrule.WatchRule(context=self.context,
watch_name=self.physical_resource_name(), watch_name=self.physical_resource_name(),

View File

@ -308,8 +308,6 @@ class Instance(resource.Resource):
'PublicIp': _('Public IP address of the specified ' 'PublicIp': _('Public IP address of the specified '
'instance.')} 'instance.')}
update_allowed_keys = ('Metadata', 'Properties')
# Server host name limit to 53 characters by due to typical default # Server host name limit to 53 characters by due to typical default
# linux HOST_NAME_MAX of 64, minus the .novalocal appended to the name # linux HOST_NAME_MAX of 64, minus the .novalocal appended to the name
physical_resource_name_limit = 53 physical_resource_name_limit = 53

View File

@ -355,8 +355,6 @@ class LoadBalancer(stack_resource.StackResource):
"security group.") "security group.")
} }
update_allowed_keys = ('Properties',)
def _haproxy_config(self, templ, instances): def _haproxy_config(self, templ, instances):
# initial simplifications: # initial simplifications:
# - only one Listener # - only one Listener

View File

@ -70,8 +70,6 @@ class Firewall(neutron.NeutronResource):
'show': _('All attributes.'), 'show': _('All attributes.'),
} }
update_allowed_keys = ('Properties',)
def _show_resource(self): def _show_resource(self):
return self.neutron().show_firewall(self.resource_id)['firewall'] return self.neutron().show_firewall(self.resource_id)['firewall']
@ -153,8 +151,6 @@ class FirewallPolicy(neutron.NeutronResource):
'tenant_id': _('Id of the tenant owning the firewall policy.') 'tenant_id': _('Id of the tenant owning the firewall policy.')
} }
update_allowed_keys = ('Properties',)
def _show_resource(self): def _show_resource(self):
return self.neutron().show_firewall_policy(self.resource_id)[ return self.neutron().show_firewall_policy(self.resource_id)[
'firewall_policy'] 'firewall_policy']
@ -289,8 +285,6 @@ class FirewallRule(neutron.NeutronResource):
'tenant_id': _('Id of the tenant owning the firewall.') 'tenant_id': _('Id of the tenant owning the firewall.')
} }
update_allowed_keys = ('Properties',)
def _show_resource(self): def _show_resource(self):
return self.neutron().show_firewall_rule( return self.neutron().show_firewall_rule(
self.resource_id)['firewall_rule'] self.resource_id)['firewall_rule']

View File

@ -94,8 +94,6 @@ class HealthMonitor(neutron.NeutronResource):
), ),
} }
update_allowed_keys = ('Properties',)
attributes_schema = { attributes_schema = {
'admin_state_up': _('The administrative state of this health ' 'admin_state_up': _('The administrative state of this health '
'monitor.'), 'monitor.'),
@ -286,8 +284,6 @@ class Pool(neutron.NeutronResource):
), ),
} }
update_allowed_keys = ('Properties',)
attributes_schema = { attributes_schema = {
'admin_state_up': _('The administrative state of this pool.'), 'admin_state_up': _('The administrative state of this pool.'),
'name': _('Name of the pool.'), 'name': _('Name of the pool.'),
@ -502,8 +498,6 @@ class PoolMember(neutron.NeutronResource):
'show': _('All attributes.'), 'show': _('All attributes.'),
} }
update_allowed_keys = ('Properties',)
def handle_create(self): def handle_create(self):
pool = self.properties[self.POOL_ID] pool = self.properties[self.POOL_ID]
client = self.neutron() client = self.neutron()
@ -574,8 +568,6 @@ class LoadBalancer(resource.Resource):
), ),
} }
update_allowed_keys = ('Properties',)
def handle_create(self): def handle_create(self):
pool = self.properties[self.POOL_ID] pool = self.properties[self.POOL_ID]
client = self.neutron() client = self.neutron()

View File

@ -84,8 +84,6 @@ class Net(neutron.NeutronResource):
"show": _("All attributes."), "show": _("All attributes."),
} }
update_allowed_keys = ('Properties',)
def handle_create(self): def handle_create(self):
props = self.prepare_properties( props = self.prepare_properties(
self.properties, self.properties,

View File

@ -127,8 +127,6 @@ class NetworkGateway(neutron.NeutronResource):
"show": _("All attributes.") "show": _("All attributes.")
} }
update_allowed_keys = ('Properties',)
def _show_resource(self): def _show_resource(self):
return self.neutron().show_network_gateway( return self.neutron().show_network_gateway(
self.resource_id)['network_gateway'] self.resource_id)['network_gateway']

View File

@ -165,8 +165,6 @@ class Port(neutron.NeutronResource):
"show": _("All attributes."), "show": _("All attributes."),
} }
update_allowed_keys = ('Properties',)
def validate(self): def validate(self):
super(Port, self).validate() super(Port, self).validate()
self._validate_depr_property_required(self.properties, self._validate_depr_property_required(self.properties,

View File

@ -60,8 +60,6 @@ class ProviderNet(net.Net):
), ),
} }
update_allowed_keys = ('Properties',)
attributes_schema = { attributes_schema = {
"status": _("The status of the network."), "status": _("The status of the network."),
"subnets": _("Subnets of this network."), "subnets": _("Subnets of this network."),

View File

@ -94,8 +94,6 @@ class Router(neutron.NeutronResource):
"show": _("All attributes."), "show": _("All attributes."),
} }
update_allowed_keys = ('Properties',)
def add_dependencies(self, deps): def add_dependencies(self, deps):
super(Router, self).add_dependencies(deps) super(Router, self).add_dependencies(deps)
external_gw = self.properties.get(self.EXTERNAL_GATEWAY) external_gw = self.properties.get(self.EXTERNAL_GATEWAY)

View File

@ -131,8 +131,6 @@ class SecurityGroup(neutron.NeutronResource):
{"direction": "egress", "ethertype": "IPv6"} {"direction": "egress", "ethertype": "IPv6"}
] ]
update_allowed_keys = ('Properties',)
def validate(self): def validate(self):
super(SecurityGroup, self).validate() super(SecurityGroup, self).validate()
if self.properties.get(self.NAME) == 'default': if self.properties.get(self.NAME) == 'default':

View File

@ -154,8 +154,6 @@ class Subnet(neutron.NeutronResource):
"show": _("All attributes."), "show": _("All attributes."),
} }
update_allowed_keys = ('Properties',)
@classmethod @classmethod
def _null_gateway_ip(cls, props): def _null_gateway_ip(cls, props):
if cls.GATEWAY_IP not in props: if cls.GATEWAY_IP not in props:

View File

@ -85,8 +85,6 @@ class VPNService(neutron.NeutronResource):
'show': _('All attributes.'), 'show': _('All attributes.'),
} }
update_allowed_keys = ('Properties',)
def _show_resource(self): def _show_resource(self):
return self.neutron().show_vpnservice(self.resource_id)['vpnservice'] return self.neutron().show_vpnservice(self.resource_id)['vpnservice']
@ -272,8 +270,6 @@ class IPsecSiteConnection(neutron.NeutronResource):
'with the ipsec site connection.') 'with the ipsec site connection.')
} }
update_allowed_keys = ('Properties',)
def _show_resource(self): def _show_resource(self):
return self.neutron().show_ipsec_site_connection(self.resource_id)[ return self.neutron().show_ipsec_site_connection(self.resource_id)[
'ipsec_site_connection'] 'ipsec_site_connection']
@ -411,8 +407,6 @@ class IKEPolicy(neutron.NeutronResource):
'policy.'), 'policy.'),
} }
update_allowed_keys = ('Properties',)
def _show_resource(self): def _show_resource(self):
return self.neutron().show_ikepolicy(self.resource_id)['ikepolicy'] return self.neutron().show_ikepolicy(self.resource_id)['ikepolicy']
@ -550,8 +544,6 @@ class IPsecPolicy(neutron.NeutronResource):
'transform_protocol': _('The transform protocol of the ipsec policy.') 'transform_protocol': _('The transform protocol of the ipsec policy.')
} }
update_allowed_keys = ('Properties',)
def _show_resource(self): def _show_resource(self):
return self.neutron().show_ipsecpolicy(self.resource_id)['ipsecpolicy'] return self.neutron().show_ipsecpolicy(self.resource_id)['ipsecpolicy']

View File

@ -87,7 +87,6 @@ class ResourceGroup(stack_resource.StackResource):
attributes_schema = { attributes_schema = {
"refs": _("A list of resource IDs for the resources in the group") "refs": _("A list of resource IDs for the resources in the group")
} }
update_allowed_keys = ("Properties",)
def validate(self): def validate(self):
# validate our basic properties # validate our basic properties

View File

@ -323,8 +323,6 @@ class Server(stack_user.StackUser):
'address of the server.'), 'address of the server.'),
} }
update_allowed_keys = ('Metadata', 'Properties')
# Server host name limit to 53 characters by due to typical default # Server host name limit to 53 characters by due to typical default
# linux HOST_NAME_MAX of 64, minus the .novalocal appended to the name # linux HOST_NAME_MAX of 64, minus the .novalocal appended to the name
physical_resource_name_limit = 53 physical_resource_name_limit = 53

View File

@ -155,8 +155,6 @@ class SoftwareDeployment(signal_responder.SignalResponder):
"execution"), "execution"),
} }
update_allowed_keys = ('Properties',)
def _signal_transport_cfn(self): def _signal_transport_cfn(self):
return self.properties.get( return self.properties.get(
self.SIGNAL_TRANSPORT) == self.CFN_SIGNAL self.SIGNAL_TRANSPORT) == self.CFN_SIGNAL

View File

@ -54,8 +54,6 @@ class NestedStack(stack_resource.StackResource):
), ),
} }
update_allowed_keys = ('Properties',)
def child_template(self): def child_template(self):
try: try:
template_data = urlfetch.get(self.properties[self.TEMPLATE_URL]) template_data = urlfetch.get(self.properties[self.TEMPLATE_URL])

View File

@ -57,7 +57,6 @@ class TemplateResource(stack_resource.StackResource):
self._parsed_nested = None self._parsed_nested = None
self.stack = stack self.stack = stack
self.validation_exception = None self.validation_exception = None
self.update_allowed_keys = ('Properties',)
tri = stack.env.get_resource_info( tri = stack.env.get_resource_info(
json_snippet['Type'], json_snippet['Type'],

View File

@ -345,8 +345,6 @@ class VolumeAttachment(resource.Resource):
), ),
} }
update_allowed_keys = ('Properties',)
def handle_create(self): def handle_create(self):
server_id = self.properties[self.INSTANCE_ID] server_id = self.properties[self.INSTANCE_ID]
volume_id = self.properties[self.VOLUME_ID] volume_id = self.properties[self.VOLUME_ID]

View File

@ -182,8 +182,6 @@ class WaitCondition(resource.Resource):
'condition signals sent to the handle.'), 'condition signals sent to the handle.'),
} }
update_allowed_keys = ('Properties',)
def __init__(self, name, json_snippet, stack): def __init__(self, name, json_snippet, stack):
super(WaitCondition, self).__init__(name, json_snippet, stack) super(WaitCondition, self).__init__(name, json_snippet, stack)

View File

@ -670,16 +670,6 @@ class InstancesTest(HeatTestCase):
self.assertEqual((instance.UPDATE, instance.COMPLETE), instance.state) self.assertEqual((instance.UPDATE, instance.COMPLETE), instance.state)
self.m.VerifyAll() self.m.VerifyAll()
def test_instance_update_replace(self):
return_server = self.fc.servers.list()[1]
instance = self._create_test_instance(return_server,
'in_update1')
update_template = copy.deepcopy(instance.t)
update_template['Notallowed'] = {'test': 123}
updater = scheduler.TaskRunner(instance.update, update_template)
self.assertRaises(resource.UpdateReplace, updater)
def test_instance_update_properties(self): def test_instance_update_properties(self):
return_server = self.fc.servers.list()[1] return_server = self.fc.servers.list()[1]
instance = self._create_test_instance(return_server, instance = self._create_test_instance(return_server,

View File

@ -297,27 +297,6 @@ class InstanceGroupTest(HeatTestCase):
self.m.VerifyAll() self.m.VerifyAll()
def test_update_fail_badkey(self):
t = template_format.parse(ig_template)
properties = t['Resources']['JobServerGroup']['Properties']
properties['Size'] = '2'
stack = utils.parse_stack(t)
self._stub_create(2)
self.m.ReplayAll()
self.create_resource(t, stack, 'JobServerConfig')
rsrc = self.create_resource(t, stack, 'JobServerGroup')
self.m.ReplayAll()
update_snippet = copy.deepcopy(rsrc.parsed_template())
update_snippet['Metadata'] = 'notallowedforupdate'
updater = scheduler.TaskRunner(rsrc.update, update_snippet)
self.assertRaises(resource.UpdateReplace, updater)
rsrc.delete()
self.m.VerifyAll()
def test_update_fail_badprop(self): def test_update_fail_badprop(self):
t = template_format.parse(ig_template) t = template_format.parse(ig_template)
properties = t['Resources']['JobServerGroup']['Properties'] properties = t['Resources']['JobServerGroup']['Properties']

View File

@ -2462,6 +2462,35 @@ class StackTest(HeatTestCase):
self.stack.state) self.stack.state)
self.assertEqual('smelly', self.stack['AResource'].properties['Foo']) self.assertEqual('smelly', self.stack['AResource'].properties['Foo'])
def test_update_deletion_policy(self):
tmpl = {'HeatTemplateFormatVersion': '2012-12-12',
'Resources': {
'AResource': {'Type': 'ResourceWithPropsType',
'Properties': {'Foo': 'Bar'}}}}
self.stack = parser.Stack(self.ctx, 'update_test_stack',
template.Template(tmpl))
self.stack.store()
self.stack.create()
self.assertEqual((parser.Stack.CREATE, parser.Stack.COMPLETE),
self.stack.state)
resource_id = self.stack['AResource'].id
new_tmpl = {'HeatTemplateFormatVersion': '2012-12-12',
'Resources': {
'AResource': {'Type': 'ResourceWithPropsType',
'DeletionPolicy': 'Retain',
'Properties': {'Foo': 'Bar'}}}}
updated_stack = parser.Stack(self.ctx, 'updated_stack',
template.Template(new_tmpl))
self.stack.update(updated_stack)
self.assertEqual((parser.Stack.UPDATE, parser.Stack.COMPLETE),
self.stack.state)
self.assertEqual(resource_id, self.stack['AResource'].id)
def test_stack_create_timeout(self): def test_stack_create_timeout(self):
self.m.StubOutWithMock(scheduler.DependencyTaskGroup, '__call__') self.m.StubOutWithMock(scheduler.DependencyTaskGroup, '__call__')
self.m.StubOutWithMock(scheduler, 'wallclock') self.m.StubOutWithMock(scheduler, 'wallclock')

View File

@ -316,20 +316,6 @@ class ResourceTest(HeatTestCase):
self.assertNotEqual(res1, res2) self.assertNotEqual(res1, res2)
def test_update_template_diff_empty(self):
tmpl = {'Type': 'Foo'}
update_snippet = {}
res = generic_rsrc.GenericResource('test_resource', tmpl, self.stack)
self.assertRaises(resource.UpdateReplace, res.update_template_diff,
update_snippet, tmpl)
def test_update_template_diff_changed_notallowed(self):
tmpl = {'Type': 'Foo'}
update_snippet = {'Type': 'Bar'}
res = generic_rsrc.GenericResource('test_resource', tmpl, self.stack)
self.assertRaises(resource.UpdateReplace, res.update_template_diff,
update_snippet, tmpl)
def test_update_template_diff_changed_modified(self): def test_update_template_diff_changed_modified(self):
tmpl = {'Type': 'Foo', 'Metadata': {'foo': 123}} tmpl = {'Type': 'Foo', 'Metadata': {'foo': 123}}
update_snippet = {'Type': 'Foo', 'Metadata': {'foo': 456}} update_snippet = {'Type': 'Foo', 'Metadata': {'foo': 456}}

View File

@ -1263,16 +1263,6 @@ class ServersTest(HeatTestCase):
self.assertEqual((server.UPDATE, server.FAILED), server.state) self.assertEqual((server.UPDATE, server.FAILED), server.state)
self.m.VerifyAll() self.m.VerifyAll()
def test_server_update_attr_replace(self):
return_server = self.fc.servers.list()[1]
server = self._create_test_server(return_server,
'update_rep')
update_template = copy.deepcopy(server.t)
update_template['UpdatePolicy'] = {'test': 123}
updater = scheduler.TaskRunner(server.update, update_template)
self.assertRaises(resource.UpdateReplace, updater)
def test_server_update_properties(self): def test_server_update_properties(self):
return_server = self.fc.servers.list()[1] return_server = self.fc.servers.list()[1]
server = self._create_test_server(return_server, server = self._create_test_server(return_server,