From cbbc6d5546b7fedbc37190ee3bae654e80fcc310 Mon Sep 17 00:00:00 2001 From: Hemanth Ravi Date: Mon, 20 Oct 2014 11:35:42 -0700 Subject: [PATCH] Group policy API-2 HEAT resources: Classifiers, Rules This is the second patch in the Group Policy resources implementation series. This patch implements: Policy Classifiers Policy Actions Policy Rules In the context of larger Group Policy model, the Policy Rule resource is referenced by Contracts, which will be introduced in the subsequent patch. Change-Id: If6df98133bb517ebfba37e20a988d9837aeee7f8 Implements: blueprint group-based-policy-automation --- .../engine/resources/neutron/grouppolicy.py | 240 ++++++++++ gbpautomation/heat/tests/test_grouppolicy.py | 433 ++++++++++++++++-- 2 files changed, 639 insertions(+), 34 deletions(-) diff --git a/gbpautomation/heat/engine/resources/neutron/grouppolicy.py b/gbpautomation/heat/engine/resources/neutron/grouppolicy.py index 03608d8..8f3e7f8 100644 --- a/gbpautomation/heat/engine/resources/neutron/grouppolicy.py +++ b/gbpautomation/heat/engine/resources/neutron/grouppolicy.py @@ -17,6 +17,7 @@ from gbpautomation.heat.engine.resources.neutron import gbpresource from neutronclient.common.exceptions import NeutronClientException from heat.engine import attributes +from heat.engine import constraints from heat.engine import properties @@ -348,10 +349,249 @@ class L3Policy(gbpresource.GBPResource): self.resource_id, {'l3_policy': prop_diff}) +class PolicyClassifier(gbpresource.GBPResource): + + PROPERTIES = ( + TENANT_ID, NAME, DESCRIPTION, PROTOCOL, PORT_RANGE, + DIRECTION + ) = ( + 'tenant_id', 'name', 'description', 'protocol', 'port_range', + 'direction' + ) + + properties_schema = { + TENANT_ID: properties.Schema( + properties.Schema.STRING, + _('Tenant id of the policy classifier.') + ), + NAME: properties.Schema( + properties.Schema.STRING, + _('Name of the policy classifier.'), + update_allowed=True + ), + DESCRIPTION: properties.Schema( + properties.Schema.STRING, + _('Description of the policy classifier.'), + update_allowed=True + ), + PROTOCOL: properties.Schema( + properties.Schema.STRING, + _('Protocol of traffic described by the policy classifier.'), + constraints=[ + constraints.AllowedValues(['tcp', 'udp', 'icmp', None]) + ], + update_allowed=True + ), + PORT_RANGE: properties.Schema( + properties.Schema.STRING, + _('Port range of traffic described by the policy classifier.'), + update_allowed=True + ), + DIRECTION: properties.Schema( + properties.Schema.STRING, + _('Direction of traffic described by the policy classifier.'), + constraints=[ + constraints.AllowedValues(['in', 'out', 'bi', None]) + ], + update_allowed=True + ) + } + + def _show_resource(self): + client = self.grouppolicy() + pc_id = self.resource_id + return client.show_policy_classifier(pc_id)['policy_classifier'] + + def handle_create(self): + client = self.grouppolicy() + + props = {} + for key in self.properties: + if self.properties.get(key) is not None: + props[key] = self.properties.get(key) + + policy_classifier = client.create_policy_classifier( + {'policy_classifier': props})['policy_classifier'] + + self.resource_id_set(policy_classifier['id']) + + def handle_delete(self): + + client = self.grouppolicy() + pc_id = self.resource_id + + try: + client.delete_policy_classifier(pc_id) + except NeutronClientException as ex: + self.client_plugin().ignore_not_found(ex) + else: + return self._delete_task() + + def handle_update(self, json_snippet, tmpl_diff, prop_diff): + if prop_diff: + self.grouppolicy().update_policy_classifier( + self.resource_id, {'policy_classifier': prop_diff}) + + +class PolicyAction(gbpresource.GBPResource): + + PROPERTIES = ( + TENANT_ID, NAME, DESCRIPTION, ACTION_TYPE, ACTION_VALUE + ) = ( + 'tenant_id', 'name', 'description', 'action_type', 'action_value' + ) + + properties_schema = { + TENANT_ID: properties.Schema( + properties.Schema.STRING, + _('Tenant id of the action.') + ), + NAME: properties.Schema( + properties.Schema.STRING, + _('Name of the action.'), + update_allowed=True + ), + DESCRIPTION: properties.Schema( + properties.Schema.STRING, + _('Description of the action.'), + update_allowed=True + ), + ACTION_TYPE: properties.Schema( + properties.Schema.STRING, + _('Type of action.'), + constraints=[ + constraints.AllowedValues(['allow', 'redirect', None]) + ], + update_allowed=True + ), + ACTION_VALUE: properties.Schema( + properties.Schema.STRING, + _('Value of the action.'), + update_allowed=True + ) + } + + def _show_resource(self): + client = self.grouppolicy() + action_id = self.resource_id + return client.show_policy_action(action_id)['policy_action'] + + def handle_create(self): + client = self.grouppolicy() + + props = {} + for key in self.properties: + if self.properties.get(key) is not None: + props[key] = self.properties.get(key) + + policy_action = client.create_policy_action( + {'policy_action': props})['policy_action'] + + self.resource_id_set(policy_action['id']) + + def handle_delete(self): + + client = self.grouppolicy() + action_id = self.resource_id + + try: + client.delete_policy_action(action_id) + except NeutronClientException as ex: + self.client_plugin().ignore_not_found(ex) + else: + return self._delete_task() + + def handle_update(self, json_snippet, tmpl_diff, prop_diff): + if prop_diff: + self.grouppolicy().update_policy_action( + self.resource_id, {'policy_action': prop_diff}) + + +class PolicyRule(gbpresource.GBPResource): + + PROPERTIES = ( + TENANT_ID, NAME, DESCRIPTION, ENABLED, POLICY_CLASSIFIER_ID, + POLICY_ACTIONS + ) = ( + 'tenant_id', 'name', 'description', 'enabled', 'policy_classifier_id', + 'policy_actions' + ) + + properties_schema = { + TENANT_ID: properties.Schema( + properties.Schema.STRING, + _('Tenant id of the policy rule.') + ), + NAME: properties.Schema( + properties.Schema.STRING, + _('Name of the policy rule.'), + update_allowed=True + ), + DESCRIPTION: properties.Schema( + properties.Schema.STRING, + _('Description of the policy rule.'), + update_allowed=True + ), + ENABLED: properties.Schema( + properties.Schema.BOOLEAN, + _('State of policy rule.'), + default=True, update_allowed=True + ), + POLICY_CLASSIFIER_ID: properties.Schema( + properties.Schema.STRING, + _('Classifier id of the policy rule.'), + required=True, update_allowed=True + ), + POLICY_ACTIONS: properties.Schema( + properties.Schema.LIST, + _('List of actions of the policy rule.'), + default=None, update_allowed=True + ) + } + + def _show_resource(self): + client = self.grouppolicy() + rule_id = self.resource_id + return client.show_policy_rule(rule_id)['policy_rule'] + + def handle_create(self): + client = self.grouppolicy() + + props = {} + for key in self.properties: + if self.properties.get(key) is not None: + props[key] = self.properties.get(key) + + policy_rule = client.create_policy_rule( + {'policy_rule': props})['policy_rule'] + + self.resource_id_set(policy_rule['id']) + + def handle_delete(self): + + client = self.grouppolicy() + rule_id = self.resource_id + + try: + client.delete_policy_rule(rule_id) + except NeutronClientException as ex: + self.client_plugin().ignore_not_found(ex) + else: + return self._delete_task() + + def handle_update(self, json_snippet, tmpl_diff, prop_diff): + if prop_diff: + self.grouppolicy().update_policy_rule( + self.resource_id, {'policy_rule': prop_diff}) + + def resource_mapping(): return { 'OS::Neutron::Endpoint': Endpoint, 'OS::Neutron::EndpointGroup': EndpointGroup, 'OS::Neutron::L2Policy': L2Policy, 'OS::Neutron::L3Policy': L3Policy, + 'OS::Neutron::PolicyClassifier': PolicyClassifier, + 'OS::Neutron::PolicyAction': PolicyAction, + 'OS::Neutron::PolicyRule': PolicyRule } diff --git a/gbpautomation/heat/tests/test_grouppolicy.py b/gbpautomation/heat/tests/test_grouppolicy.py index d96e362..bd68f60 100644 --- a/gbpautomation/heat/tests/test_grouppolicy.py +++ b/gbpautomation/heat/tests/test_grouppolicy.py @@ -11,6 +11,7 @@ # under the License. import copy +import six from gbpautomation.heat.engine.resources.neutron import grouppolicy from gbpclient.v2_0 import client as gbpclient @@ -104,6 +105,65 @@ l3_policy_template = ''' } ''' +policy_classifier_template = ''' +{ + "AWSTemplateFormatVersion" : "2010-09-09", + "Description" : "Template to test neutron policy classifier", + "Parameters" : {}, + "Resources" : { + "policy_classifier": { + "Type": "OS::Neutron::PolicyClassifier", + "Properties": { + "name": "test-policy-classifier", + "description": "test policy classifier resource", + "protocol": "tcp", + "port_range": "8000-9000", + "direction": "bi" + } + } + } +} +''' + +policy_action_template = ''' +{ + "AWSTemplateFormatVersion" : "2010-09-09", + "Description" : "Template to test neutron policy action", + "Parameters" : {}, + "Resources" : { + "policy_action": { + "Type": "OS::Neutron::PolicyAction", + "Properties": { + "name": "test-policy-action", + "description": "test policy action resource", + "action_type": "redirect", + "action_value": "7890" + } + } + } +} +''' + +policy_rule_template = ''' +{ + "AWSTemplateFormatVersion" : "2010-09-09", + "Description" : "Template to test neutron l3 policy", + "Parameters" : {}, + "Resources" : { + "policy_rule": { + "Type": "OS::Neutron::PolicyRule", + "Properties": { + "name": "test-policy-rule", + "description": "test policy rule resource", + "enabled": True, + "policy_classifier_id": "7890", + "policy_actions": ['3456', '1234'] + } + } + } +} +''' + class EndpointTest(HeatTestCase): @@ -195,7 +255,7 @@ class EndpointTest(HeatTestCase): scheduler.TaskRunner(rsrc.delete)) self.assertEqual( 'NeutronClientException: An unknown exception occurred.', - str(error)) + six.text_type(error)) self.assertEqual((rsrc.DELETE, rsrc.FAILED), rsrc.state) self.m.VerifyAll() @@ -344,17 +404,6 @@ class EndpointGroupTest(HeatTestCase): self.assertEqual((rsrc.DELETE, rsrc.FAILED), rsrc.state) self.m.VerifyAll() - def test_attribute_failed(self): - rsrc = self.create_endpoint_group() - self.m.ReplayAll() - scheduler.TaskRunner(rsrc.create)() - error = self.assertRaises(exception.InvalidTemplateAttribute, - rsrc.FnGetAtt, 'l3_policy_id') - self.assertEqual( - 'The Referenced Attribute (endpoint_group l3_policy_id) is ' - 'incorrect.', str(error)) - self.m.VerifyAll() - def test_update(self): rsrc = self.create_endpoint_group() gbpclient.Client.update_endpoint_group( @@ -463,17 +512,6 @@ class L2PolicyTest(HeatTestCase): self.assertEqual((rsrc.DELETE, rsrc.FAILED), rsrc.state) self.m.VerifyAll() - def test_attribute_failed(self): - rsrc = self.create_l2_policy() - self.m.ReplayAll() - scheduler.TaskRunner(rsrc.create)() - error = self.assertRaises(exception.InvalidTemplateAttribute, - rsrc.FnGetAtt, 'endpoint_id') - self.assertEqual( - 'The Referenced Attribute (l2_policy endpoint_id) is ' - 'incorrect.', str(error)) - self.m.VerifyAll() - def test_update(self): rsrc = self.create_l2_policy() gbpclient.Client.update_l2_policy( @@ -586,17 +624,6 @@ class L3PolicyTest(HeatTestCase): self.assertEqual((rsrc.DELETE, rsrc.FAILED), rsrc.state) self.m.VerifyAll() - def test_attribute_failed(self): - rsrc = self.create_l3_policy() - self.m.ReplayAll() - scheduler.TaskRunner(rsrc.create)() - error = self.assertRaises(exception.InvalidTemplateAttribute, - rsrc.FnGetAtt, 'subnet_id') - self.assertEqual( - 'The Referenced Attribute (l3_policy subnet_id) is ' - 'incorrect.', str(error)) - self.m.VerifyAll() - def test_update(self): rsrc = self.create_l3_policy() gbpclient.Client.update_l3_policy( @@ -609,3 +636,341 @@ class L3PolicyTest(HeatTestCase): scheduler.TaskRunner(rsrc.update, update_template)() self.m.VerifyAll() + + +class PolicyClassifierTest(HeatTestCase): + + def setUp(self): + super(PolicyClassifierTest, self).setUp() + self.m.StubOutWithMock(gbpclient.Client, + 'create_policy_classifier') + self.m.StubOutWithMock(gbpclient.Client, + 'delete_policy_classifier') + self.m.StubOutWithMock(gbpclient.Client, + 'show_policy_classifier') + self.m.StubOutWithMock(gbpclient.Client, + 'update_policy_classifier') + self.stub_keystoneclient() + + def create_policy_classifier(self): + gbpclient.Client.create_policy_classifier({ + 'policy_classifier': { + "name": "test-policy-classifier", + "description": "test policy classifier resource", + "protocol": "tcp", + "port_range": "8000-9000", + "direction": "bi" + } + }).AndReturn({'policy_classifier': {'id': '5678'}}) + + snippet = template_format.parse(policy_classifier_template) + stack = utils.parse_stack(snippet) + resource_defns = stack.t.resource_definitions(stack) + return grouppolicy.PolicyClassifier( + 'policy_classifier', resource_defns['policy_classifier'], stack) + + def test_create(self): + rsrc = self.create_policy_classifier() + self.m.ReplayAll() + scheduler.TaskRunner(rsrc.create)() + self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state) + self.m.VerifyAll() + + def test_create_failed(self): + gbpclient.Client.create_policy_classifier({ + 'policy_classifier': { + "name": "test-policy-classifier", + "description": "test policy classifier resource", + "protocol": "tcp", + "port_range": "8000-9000", + "direction": "bi" + } + }).AndRaise(grouppolicy.NeutronClientException()) + self.m.ReplayAll() + + snippet = template_format.parse(policy_classifier_template) + stack = utils.parse_stack(snippet) + resource_defns = stack.t.resource_definitions(stack) + rsrc = grouppolicy.PolicyClassifier( + 'policy_classifier', resource_defns['policy_classifier'], stack) + + error = self.assertRaises(exception.ResourceFailure, + scheduler.TaskRunner(rsrc.create)) + self.assertEqual( + 'NeutronClientException: An unknown exception occurred.', + str(error)) + self.assertEqual((rsrc.CREATE, rsrc.FAILED), rsrc.state) + self.m.VerifyAll() + + def test_delete(self): + gbpclient.Client.delete_policy_classifier('5678') + gbpclient.Client.show_policy_classifier('5678').AndRaise( + grouppolicy.NeutronClientException(status_code=404)) + + rsrc = self.create_policy_classifier() + self.m.ReplayAll() + scheduler.TaskRunner(rsrc.create)() + scheduler.TaskRunner(rsrc.delete)() + self.assertEqual((rsrc.DELETE, rsrc.COMPLETE), rsrc.state) + self.m.VerifyAll() + + def test_delete_already_gone(self): + gbpclient.Client.delete_policy_classifier('5678').AndRaise( + grouppolicy.NeutronClientException(status_code=404)) + + rsrc = self.create_policy_classifier() + self.m.ReplayAll() + scheduler.TaskRunner(rsrc.create)() + scheduler.TaskRunner(rsrc.delete)() + self.assertEqual((rsrc.DELETE, rsrc.COMPLETE), rsrc.state) + self.m.VerifyAll() + + def test_delete_failed(self): + gbpclient.Client.delete_policy_classifier('5678').AndRaise( + grouppolicy.NeutronClientException(status_code=400)) + + rsrc = self.create_policy_classifier() + self.m.ReplayAll() + scheduler.TaskRunner(rsrc.create)() + error = self.assertRaises(exception.ResourceFailure, + scheduler.TaskRunner(rsrc.delete)) + self.assertEqual( + 'NeutronClientException: An unknown exception occurred.', + str(error)) + self.assertEqual((rsrc.DELETE, rsrc.FAILED), rsrc.state) + self.m.VerifyAll() + + def test_update(self): + rsrc = self.create_policy_classifier() + gbpclient.Client.update_policy_classifier( + '5678', {'policy_classifier': {'protocol': 'udp'}}) + self.m.ReplayAll() + scheduler.TaskRunner(rsrc.create)() + + update_template = copy.deepcopy(rsrc.t) + update_template['Properties']['protocol'] = 'udp' + scheduler.TaskRunner(rsrc.update, update_template)() + + self.m.VerifyAll() + + +class PolicyActionTest(HeatTestCase): + + def setUp(self): + super(PolicyActionTest, self).setUp() + self.m.StubOutWithMock(gbpclient.Client, 'create_policy_action') + self.m.StubOutWithMock(gbpclient.Client, 'delete_policy_action') + self.m.StubOutWithMock(gbpclient.Client, 'show_policy_action') + self.m.StubOutWithMock(gbpclient.Client, 'update_policy_action') + self.stub_keystoneclient() + + def create_policy_action(self): + gbpclient.Client.create_policy_action({ + 'policy_action': { + "name": "test-policy-action", + "description": "test policy action resource", + "action_type": "redirect", + "action_value": "7890" + } + }).AndReturn({'policy_action': {'id': '5678'}}) + + snippet = template_format.parse(policy_action_template) + stack = utils.parse_stack(snippet) + resource_defns = stack.t.resource_definitions(stack) + return grouppolicy.PolicyAction( + 'policy_action', resource_defns['policy_action'], stack) + + def test_create(self): + rsrc = self.create_policy_action() + self.m.ReplayAll() + scheduler.TaskRunner(rsrc.create)() + self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state) + self.m.VerifyAll() + + def test_create_failed(self): + gbpclient.Client.create_policy_action({ + 'policy_action': { + "name": "test-policy-action", + "description": "test policy action resource", + "action_type": "redirect", + "action_value": "7890" + } + }).AndRaise(grouppolicy.NeutronClientException()) + self.m.ReplayAll() + + snippet = template_format.parse(policy_action_template) + stack = utils.parse_stack(snippet) + resource_defns = stack.t.resource_definitions(stack) + rsrc = grouppolicy.PolicyAction( + 'policy_action', resource_defns['policy_action'], stack) + + error = self.assertRaises(exception.ResourceFailure, + scheduler.TaskRunner(rsrc.create)) + self.assertEqual( + 'NeutronClientException: An unknown exception occurred.', + str(error)) + self.assertEqual((rsrc.CREATE, rsrc.FAILED), rsrc.state) + self.m.VerifyAll() + + def test_delete(self): + gbpclient.Client.delete_policy_action('5678') + gbpclient.Client.show_policy_action('5678').AndRaise( + grouppolicy.NeutronClientException(status_code=404)) + + rsrc = self.create_policy_action() + self.m.ReplayAll() + scheduler.TaskRunner(rsrc.create)() + scheduler.TaskRunner(rsrc.delete)() + self.assertEqual((rsrc.DELETE, rsrc.COMPLETE), rsrc.state) + self.m.VerifyAll() + + def test_delete_already_gone(self): + gbpclient.Client.delete_policy_action('5678').AndRaise( + grouppolicy.NeutronClientException(status_code=404)) + + rsrc = self.create_policy_action() + self.m.ReplayAll() + scheduler.TaskRunner(rsrc.create)() + scheduler.TaskRunner(rsrc.delete)() + self.assertEqual((rsrc.DELETE, rsrc.COMPLETE), rsrc.state) + self.m.VerifyAll() + + def test_delete_failed(self): + gbpclient.Client.delete_policy_action('5678').AndRaise( + grouppolicy.NeutronClientException(status_code=400)) + + rsrc = self.create_policy_action() + self.m.ReplayAll() + scheduler.TaskRunner(rsrc.create)() + error = self.assertRaises(exception.ResourceFailure, + scheduler.TaskRunner(rsrc.delete)) + self.assertEqual( + 'NeutronClientException: An unknown exception occurred.', + str(error)) + self.assertEqual((rsrc.DELETE, rsrc.FAILED), rsrc.state) + self.m.VerifyAll() + + def test_update(self): + rsrc = self.create_policy_action() + gbpclient.Client.update_policy_action( + '5678', {'policy_action': {'action_type': 'allow'}}) + self.m.ReplayAll() + scheduler.TaskRunner(rsrc.create)() + + update_template = copy.deepcopy(rsrc.t) + update_template['Properties']['action_type'] = 'allow' + scheduler.TaskRunner(rsrc.update, update_template)() + + self.m.VerifyAll() + + +class PolicyRuleTest(HeatTestCase): + + def setUp(self): + super(PolicyRuleTest, self).setUp() + self.m.StubOutWithMock(gbpclient.Client, 'create_policy_rule') + self.m.StubOutWithMock(gbpclient.Client, 'delete_policy_rule') + self.m.StubOutWithMock(gbpclient.Client, 'show_policy_rule') + self.m.StubOutWithMock(gbpclient.Client, 'update_policy_rule') + self.stub_keystoneclient() + + def create_policy_rule(self): + gbpclient.Client.create_policy_rule({ + 'policy_rule': { + "name": "test-policy-rule", + "description": "test policy rule resource", + "enabled": True, + "policy_classifier_id": "7890", + "policy_actions": ['3456', '1234'] + } + }).AndReturn({'policy_rule': {'id': '5678'}}) + + snippet = template_format.parse(policy_rule_template) + stack = utils.parse_stack(snippet) + resource_defns = stack.t.resource_definitions(stack) + return grouppolicy.PolicyRule( + 'policy_rule', resource_defns['policy_rule'], stack) + + def test_create(self): + rsrc = self.create_policy_rule() + self.m.ReplayAll() + scheduler.TaskRunner(rsrc.create)() + self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state) + self.m.VerifyAll() + + def test_create_failed(self): + gbpclient.Client.create_policy_rule({ + 'policy_rule': { + "name": "test-policy-rule", + "description": "test policy rule resource", + "enabled": True, + "policy_classifier_id": "7890", + "policy_actions": ['3456', '1234'] + } + }).AndRaise(grouppolicy.NeutronClientException()) + self.m.ReplayAll() + + snippet = template_format.parse(policy_rule_template) + stack = utils.parse_stack(snippet) + resource_defns = stack.t.resource_definitions(stack) + rsrc = grouppolicy.PolicyRule( + 'policy_rule', resource_defns['policy_rule'], stack) + + error = self.assertRaises(exception.ResourceFailure, + scheduler.TaskRunner(rsrc.create)) + self.assertEqual( + 'NeutronClientException: An unknown exception occurred.', + str(error)) + self.assertEqual((rsrc.CREATE, rsrc.FAILED), rsrc.state) + self.m.VerifyAll() + + def test_delete(self): + gbpclient.Client.delete_policy_rule('5678') + gbpclient.Client.show_policy_rule('5678').AndRaise( + grouppolicy.NeutronClientException(status_code=404)) + + rsrc = self.create_policy_rule() + self.m.ReplayAll() + scheduler.TaskRunner(rsrc.create)() + scheduler.TaskRunner(rsrc.delete)() + self.assertEqual((rsrc.DELETE, rsrc.COMPLETE), rsrc.state) + self.m.VerifyAll() + + def test_delete_already_gone(self): + gbpclient.Client.delete_policy_rule('5678').AndRaise( + grouppolicy.NeutronClientException(status_code=404)) + + rsrc = self.create_policy_rule() + self.m.ReplayAll() + scheduler.TaskRunner(rsrc.create)() + scheduler.TaskRunner(rsrc.delete)() + self.assertEqual((rsrc.DELETE, rsrc.COMPLETE), rsrc.state) + self.m.VerifyAll() + + def test_delete_failed(self): + gbpclient.Client.delete_policy_rule('5678').AndRaise( + grouppolicy.NeutronClientException(status_code=400)) + + rsrc = self.create_policy_rule() + self.m.ReplayAll() + scheduler.TaskRunner(rsrc.create)() + error = self.assertRaises(exception.ResourceFailure, + scheduler.TaskRunner(rsrc.delete)) + self.assertEqual( + 'NeutronClientException: An unknown exception occurred.', + str(error)) + self.assertEqual((rsrc.DELETE, rsrc.FAILED), rsrc.state) + self.m.VerifyAll() + + def test_update(self): + rsrc = self.create_policy_rule() + gbpclient.Client.update_policy_rule( + '5678', {'policy_rule': {'enabled': False}}) + self.m.ReplayAll() + scheduler.TaskRunner(rsrc.create)() + + update_template = copy.deepcopy(rsrc.t) + update_template['Properties']['enabled'] = False + scheduler.TaskRunner(rsrc.update, update_template)() + + self.m.VerifyAll()