Group Policy API-3 HEAT resources: Contracts
This is the third patch in the Group Policy resources implementation series. This patch implements: Contracts In the context of larger Group Policy model, Contracts contain Policy Rules and Endpoint Groups consume or provide Contracts. Change-Id: I9d92913f656af5a5d177f0cff5f3b306ced06fdf Implements: blueprint group-based-policy-automation
This commit is contained in:
parent
cbbc6d5546
commit
ca098b6bc5
|
@ -30,9 +30,9 @@ class Endpoint(gbpresource.GBPResource):
|
||||||
)
|
)
|
||||||
|
|
||||||
ATTRIBUTES = (
|
ATTRIBUTES = (
|
||||||
NEUTRON_PORT_ID
|
PORT_ID
|
||||||
) = (
|
) = (
|
||||||
'neutron_port_id'
|
'port_id'
|
||||||
)
|
)
|
||||||
|
|
||||||
properties_schema = {
|
properties_schema = {
|
||||||
|
@ -59,7 +59,7 @@ class Endpoint(gbpresource.GBPResource):
|
||||||
}
|
}
|
||||||
|
|
||||||
attributes_schema = {
|
attributes_schema = {
|
||||||
NEUTRON_PORT_ID: attributes.Schema(
|
PORT_ID: attributes.Schema(
|
||||||
_("Neutron port id of this endpoint")
|
_("Neutron port id of this endpoint")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -84,8 +84,8 @@ class Endpoint(gbpresource.GBPResource):
|
||||||
def _resolve_attribute(self, name):
|
def _resolve_attribute(self, name):
|
||||||
client = self.grouppolicy()
|
client = self.grouppolicy()
|
||||||
ep_id = self.resource_id
|
ep_id = self.resource_id
|
||||||
if name == 'neutron_port_id':
|
if name == 'port_id':
|
||||||
return client.show_endpoint(ep_id)['endpoint']['neutron_port_id']
|
return client.show_endpoint(ep_id)['endpoint']['port_id']
|
||||||
return super(Endpoint, self)._resolve_attribute(name)
|
return super(Endpoint, self)._resolve_attribute(name)
|
||||||
|
|
||||||
def handle_delete(self):
|
def handle_delete(self):
|
||||||
|
@ -585,6 +585,84 @@ class PolicyRule(gbpresource.GBPResource):
|
||||||
self.resource_id, {'policy_rule': prop_diff})
|
self.resource_id, {'policy_rule': prop_diff})
|
||||||
|
|
||||||
|
|
||||||
|
class Contract(gbpresource.GBPResource):
|
||||||
|
|
||||||
|
PROPERTIES = (
|
||||||
|
TENANT_ID, NAME, DESCRIPTION, PARENT_ID, CHILD_CONTRACTS,
|
||||||
|
POLICY_RULES
|
||||||
|
) = (
|
||||||
|
'tenant_id', 'name', 'description', 'parent_id', 'child_contracts',
|
||||||
|
'policy_rules'
|
||||||
|
)
|
||||||
|
|
||||||
|
properties_schema = {
|
||||||
|
TENANT_ID: properties.Schema(
|
||||||
|
properties.Schema.STRING,
|
||||||
|
_('Tenant id of the contract.')
|
||||||
|
),
|
||||||
|
NAME: properties.Schema(
|
||||||
|
properties.Schema.STRING,
|
||||||
|
_('Name of the contract.'),
|
||||||
|
update_allowed=True
|
||||||
|
),
|
||||||
|
DESCRIPTION: properties.Schema(
|
||||||
|
properties.Schema.STRING,
|
||||||
|
_('Description of the contract.'),
|
||||||
|
update_allowed=True
|
||||||
|
),
|
||||||
|
PARENT_ID: properties.Schema(
|
||||||
|
properties.Schema.STRING,
|
||||||
|
_('Parent id of the contract.'),
|
||||||
|
update_allowed=False
|
||||||
|
),
|
||||||
|
CHILD_CONTRACTS: properties.Schema(
|
||||||
|
properties.Schema.LIST,
|
||||||
|
_('List of child contracts.'),
|
||||||
|
default=None, update_allowed=True
|
||||||
|
),
|
||||||
|
POLICY_RULES: properties.Schema(
|
||||||
|
properties.Schema.LIST,
|
||||||
|
_('List of policy rules.'),
|
||||||
|
default=None, update_allowed=True
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
def _show_resource(self):
|
||||||
|
client = self.grouppolicy()
|
||||||
|
contract_id = self.resource_id
|
||||||
|
return client.show_contract(contract_id)['contract']
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
contract = client.create_contract(
|
||||||
|
{'contract': props})['contract']
|
||||||
|
|
||||||
|
self.resource_id_set(contract['id'])
|
||||||
|
|
||||||
|
def handle_delete(self):
|
||||||
|
|
||||||
|
client = self.grouppolicy()
|
||||||
|
contract_id = self.resource_id
|
||||||
|
|
||||||
|
try:
|
||||||
|
client.delete_contract(contract_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_contract(
|
||||||
|
self.resource_id, {'contract': prop_diff})
|
||||||
|
|
||||||
|
|
||||||
def resource_mapping():
|
def resource_mapping():
|
||||||
return {
|
return {
|
||||||
'OS::Neutron::Endpoint': Endpoint,
|
'OS::Neutron::Endpoint': Endpoint,
|
||||||
|
@ -593,5 +671,6 @@ def resource_mapping():
|
||||||
'OS::Neutron::L3Policy': L3Policy,
|
'OS::Neutron::L3Policy': L3Policy,
|
||||||
'OS::Neutron::PolicyClassifier': PolicyClassifier,
|
'OS::Neutron::PolicyClassifier': PolicyClassifier,
|
||||||
'OS::Neutron::PolicyAction': PolicyAction,
|
'OS::Neutron::PolicyAction': PolicyAction,
|
||||||
'OS::Neutron::PolicyRule': PolicyRule
|
'OS::Neutron::PolicyRule': PolicyRule,
|
||||||
|
'OS::Neutron::Contract': Contract
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,8 +119,8 @@ policy_classifier_template = '''
|
||||||
"protocol": "tcp",
|
"protocol": "tcp",
|
||||||
"port_range": "8000-9000",
|
"port_range": "8000-9000",
|
||||||
"direction": "bi"
|
"direction": "bi"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
'''
|
'''
|
||||||
|
@ -138,8 +138,8 @@ policy_action_template = '''
|
||||||
"description": "test policy action resource",
|
"description": "test policy action resource",
|
||||||
"action_type": "redirect",
|
"action_type": "redirect",
|
||||||
"action_value": "7890"
|
"action_value": "7890"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
'''
|
'''
|
||||||
|
@ -147,7 +147,7 @@ policy_action_template = '''
|
||||||
policy_rule_template = '''
|
policy_rule_template = '''
|
||||||
{
|
{
|
||||||
"AWSTemplateFormatVersion" : "2010-09-09",
|
"AWSTemplateFormatVersion" : "2010-09-09",
|
||||||
"Description" : "Template to test neutron l3 policy",
|
"Description" : "Template to test neutron policy rule",
|
||||||
"Parameters" : {},
|
"Parameters" : {},
|
||||||
"Resources" : {
|
"Resources" : {
|
||||||
"policy_rule": {
|
"policy_rule": {
|
||||||
|
@ -164,6 +164,26 @@ policy_rule_template = '''
|
||||||
}
|
}
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
contract_template = '''
|
||||||
|
{
|
||||||
|
"AWSTemplateFormatVersion" : "2010-09-09",
|
||||||
|
"Description" : "Template to test contract",
|
||||||
|
"Parameters" : {},
|
||||||
|
"Resources" : {
|
||||||
|
"contract": {
|
||||||
|
"Type": "OS::Neutron::Contract",
|
||||||
|
"Properties": {
|
||||||
|
"name": "test-contract",
|
||||||
|
"description": "test contract resource",
|
||||||
|
"parent_id": "3456",
|
||||||
|
"child_contracts": ["7890", "1234"],
|
||||||
|
"policy_rules": ["2345", "6789"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
class EndpointTest(HeatTestCase):
|
class EndpointTest(HeatTestCase):
|
||||||
|
|
||||||
|
@ -263,10 +283,10 @@ class EndpointTest(HeatTestCase):
|
||||||
rsrc = self.create_endpoint()
|
rsrc = self.create_endpoint()
|
||||||
gbpclient.Client.show_endpoint('5678').MultipleTimes(
|
gbpclient.Client.show_endpoint('5678').MultipleTimes(
|
||||||
).AndReturn(
|
).AndReturn(
|
||||||
{'endpoint': {'neutron_port_id': '1234'}})
|
{'endpoint': {'port_id': '1234'}})
|
||||||
self.m.ReplayAll()
|
self.m.ReplayAll()
|
||||||
scheduler.TaskRunner(rsrc.create)()
|
scheduler.TaskRunner(rsrc.create)()
|
||||||
self.assertEqual('1234', rsrc.FnGetAtt('neutron_port_id'))
|
self.assertEqual('1234', rsrc.FnGetAtt('port_id'))
|
||||||
self.m.VerifyAll()
|
self.m.VerifyAll()
|
||||||
|
|
||||||
def test_attribute_failed(self):
|
def test_attribute_failed(self):
|
||||||
|
@ -974,3 +994,115 @@ class PolicyRuleTest(HeatTestCase):
|
||||||
scheduler.TaskRunner(rsrc.update, update_template)()
|
scheduler.TaskRunner(rsrc.update, update_template)()
|
||||||
|
|
||||||
self.m.VerifyAll()
|
self.m.VerifyAll()
|
||||||
|
|
||||||
|
|
||||||
|
class ContractTest(HeatTestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(ContractTest, self).setUp()
|
||||||
|
self.m.StubOutWithMock(gbpclient.Client, 'create_contract')
|
||||||
|
self.m.StubOutWithMock(gbpclient.Client, 'delete_contract')
|
||||||
|
self.m.StubOutWithMock(gbpclient.Client, 'show_contract')
|
||||||
|
self.m.StubOutWithMock(gbpclient.Client, 'update_contract')
|
||||||
|
self.stub_keystoneclient()
|
||||||
|
|
||||||
|
def create_contract(self):
|
||||||
|
gbpclient.Client.create_contract({
|
||||||
|
'contract': {
|
||||||
|
"name": "test-contract",
|
||||||
|
"description": "test contract resource",
|
||||||
|
"parent_id": "3456",
|
||||||
|
"child_contracts": ["7890", "1234"],
|
||||||
|
"policy_rules": ["2345", "6789"]
|
||||||
|
}
|
||||||
|
}).AndReturn({'contract': {'id': '5678'}})
|
||||||
|
|
||||||
|
snippet = template_format.parse(contract_template)
|
||||||
|
stack = utils.parse_stack(snippet)
|
||||||
|
resource_defns = stack.t.resource_definitions(stack)
|
||||||
|
return grouppolicy.Contract(
|
||||||
|
'contract', resource_defns['contract'], stack)
|
||||||
|
|
||||||
|
def test_create(self):
|
||||||
|
rsrc = self.create_contract()
|
||||||
|
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_contract({
|
||||||
|
'contract': {
|
||||||
|
"name": "test-contract",
|
||||||
|
"description": "test contract resource",
|
||||||
|
"parent_id": "3456",
|
||||||
|
"child_contracts": ["7890", "1234"],
|
||||||
|
"policy_rules": ["2345", "6789"]
|
||||||
|
}
|
||||||
|
}).AndRaise(grouppolicy.NeutronClientException())
|
||||||
|
self.m.ReplayAll()
|
||||||
|
|
||||||
|
snippet = template_format.parse(contract_template)
|
||||||
|
stack = utils.parse_stack(snippet)
|
||||||
|
resource_defns = stack.t.resource_definitions(stack)
|
||||||
|
rsrc = grouppolicy.Contract(
|
||||||
|
'contract', resource_defns['contract'], 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_contract('5678')
|
||||||
|
gbpclient.Client.show_contract('5678').AndRaise(
|
||||||
|
grouppolicy.NeutronClientException(status_code=404))
|
||||||
|
|
||||||
|
rsrc = self.create_contract()
|
||||||
|
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_contract('5678').AndRaise(
|
||||||
|
grouppolicy.NeutronClientException(status_code=404))
|
||||||
|
|
||||||
|
rsrc = self.create_contract()
|
||||||
|
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_contract('5678').AndRaise(
|
||||||
|
grouppolicy.NeutronClientException(status_code=400))
|
||||||
|
|
||||||
|
rsrc = self.create_contract()
|
||||||
|
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_contract()
|
||||||
|
gbpclient.Client.update_contract(
|
||||||
|
'5678', {'contract': {'child_contracts': ["1234"]}})
|
||||||
|
self.m.ReplayAll()
|
||||||
|
scheduler.TaskRunner(rsrc.create)()
|
||||||
|
|
||||||
|
update_template = copy.deepcopy(rsrc.t)
|
||||||
|
update_template['Properties']['child_contracts'] = ["1234"]
|
||||||
|
scheduler.TaskRunner(rsrc.update, update_template)()
|
||||||
|
|
||||||
|
self.m.VerifyAll()
|
||||||
|
|
Loading…
Reference in New Issue