Support shared resource on APIC driver

Closes-bug: 1402428

Change-Id: Ic3bd7da911eaaafe112bf769fab390248b1f219f
This commit is contained in:
Ivar Lazzaro
2014-11-17 14:41:23 -08:00
parent 4ee6e1d5ca
commit add8cf18be
2 changed files with 586 additions and 228 deletions

View File

@@ -71,6 +71,11 @@ class PATNotSupportedByApicDriver(gpexc.GroupPolicyBadRequest):
message = _("Port address translation is not supported by APIC driver.")
class SharedAttributeUpdateNotSupportedOnApic(gpexc.GroupPolicyBadRequest):
message = _("Resource shared attribute update not supported on APIC "
"GBP driver for resource of type %(type)s")
class ApicMappingDriver(api.ResourceMappingDriver):
"""Apic Mapping driver for Group Policy plugin.
@@ -145,7 +150,9 @@ class ApicMappingDriver(api.ResourceMappingDriver):
'network_type': network[pn.NETWORK_TYPE],
'l2_policy_id': ptg['l2_policy_id'],
'tenant_id': port['tenant_id'],
'host': port['binding:host_id']
'host': port['binding:host_id'],
'ptg_apic_tentant': (ptg['tenant_id'] if not ptg['shared'] else
apic_manager.TENANT_COMMON)
}
def create_dhcp_policy_target_if_needed(self, plugin_context, port):
@@ -200,8 +207,7 @@ class ApicMappingDriver(api.ResourceMappingDriver):
if port_min and port_max:
attrs['dToPort'] = port_max
attrs['dFromPort'] = port_min
tenant = self.name_mapper.tenant(context,
context.current['tenant_id'])
tenant = self._tenant_by_sharing_policy(context.current)
policy_rule = self.name_mapper.policy_rule(context,
context.current['id'])
self.apic_manager.create_tenant_filter(policy_rule, owner=tenant,
@@ -211,8 +217,8 @@ class ApicMappingDriver(api.ResourceMappingDriver):
pass
def create_policy_rule_set_postcommit(self, context):
# Create APIC contract
tenant = self.name_mapper.tenant(context, context.current['tenant_id'])
# Create APIC policy_rule_set
tenant = self._tenant_by_sharing_policy(context.current)
contract = self.name_mapper.policy_rule_set(context,
context.current['id'])
with self.apic_manager.apic.transaction(None) as trs:
@@ -235,14 +241,17 @@ class ApicMappingDriver(api.ResourceMappingDriver):
def create_policy_target_group_postcommit(self, context):
super(ApicMappingDriver, self).create_policy_target_group_postcommit(
context)
tenant = self.name_mapper.tenant(context, context.current['tenant_id'])
tenant = self._tenant_by_sharing_policy(context.current)
l2_policy = self.name_mapper.l2_policy(context,
context.current['l2_policy_id'])
ptg = self.name_mapper.policy_target_group(context,
epg = self.name_mapper.policy_target_group(context,
context.current['id'])
l2_policy_object = context._plugin.get_l2_policy(
context._plugin_context, context.current['l2_policy_id'])
bd_owner = self._tenant_by_sharing_policy(l2_policy_object)
with self.apic_manager.apic.transaction(None) as trs:
self.apic_manager.ensure_epg_created(tenant, ptg,
self.apic_manager.ensure_epg_created(tenant, epg,
bd_owner=bd_owner,
bd_name=l2_policy)
subnets = self._subnet_ids_to_objects(context._plugin_context,
context.current['subnets'])
@@ -262,25 +271,27 @@ class ApicMappingDriver(api.ResourceMappingDriver):
def update_l2_policy_precommit(self, context):
self._reject_non_shared_net_on_shared_l2p(context)
self._reject_shared_update(context, 'l2_policy')
def create_l2_policy_postcommit(self, context):
super(ApicMappingDriver, self).create_l2_policy_postcommit(context)
tenant = self.name_mapper.tenant(context, context.current['tenant_id'])
tenant = self._tenant_by_sharing_policy(context.current)
l3_policy = self.name_mapper.l3_policy(context,
context.current['l3_policy_id'])
l2_policy = self.name_mapper.l2_policy(context, context.current['id'])
l3_policy_object = context._plugin.get_l3_policy(
context._plugin_context, context.current['l3_policy_id'])
ctx_owner = self._tenant_by_sharing_policy(l3_policy_object)
self.apic_manager.ensure_bd_created_on_apic(tenant, l2_policy,
ctx_owner=tenant,
ctx_owner=ctx_owner,
ctx_name=l3_policy)
def create_l3_policy_precommit(self, context):
self._check_l3p_es(context)
def create_l3_policy_postcommit(self, context):
tenant = self.name_mapper.tenant(context, context.current['tenant_id'])
tenant = self._tenant_by_sharing_policy(context.current)
l3_policy = self.name_mapper.l3_policy(context, context.current['id'])
self.apic_manager.ensure_context_enforced(tenant, l3_policy)
external_segments = context.current['external_segments']
if external_segments:
@@ -293,7 +304,7 @@ class ApicMappingDriver(api.ResourceMappingDriver):
def delete_policy_rule_postcommit(self, context):
# TODO(ivar): delete Contract subject entries to avoid reference leak
tenant = self.name_mapper.tenant(context, context.current['tenant_id'])
tenant = self._tenant_by_sharing_policy(context.current)
policy_rule = self.name_mapper.policy_rule(context,
context.current['id'])
self.apic_manager.delete_tenant_filter(policy_rule, owner=tenant)
@@ -303,11 +314,11 @@ class ApicMappingDriver(api.ResourceMappingDriver):
pass
def delete_policy_rule_set_postcommit(self, context):
# TODO(ivar): disassociate EPGs to avoid reference leak
tenant = self.name_mapper.tenant(context, context.current['tenant_id'])
policy_rule_set = self.name_mapper.policy_rule_set(
context, context.current['id'])
self.apic_manager.delete_contract(policy_rule_set, owner=tenant)
# TODO(ivar): disassociate PTGs to avoid reference leak
tenant = self._tenant_by_sharing_policy(context.current)
contract = self.name_mapper.policy_rule_set(context,
context.current['id'])
self.apic_manager.delete_contract(contract, owner=tenant)
def delete_policy_target_postcommit(self, context):
port = self._core_plugin.get_port(context._plugin_context,
@@ -326,7 +337,7 @@ class ApicMappingDriver(api.ResourceMappingDriver):
[], subnets)
for subnet_id in context.current['subnets']:
self._cleanup_subnet(context._plugin_context, subnet_id, None)
tenant = self.name_mapper.tenant(context, context.current['tenant_id'])
tenant = self._tenant_by_sharing_policy(context.current)
ptg = self.name_mapper.policy_target_group(context,
context.current['id'])
@@ -334,13 +345,13 @@ class ApicMappingDriver(api.ResourceMappingDriver):
def delete_l2_policy_postcommit(self, context):
super(ApicMappingDriver, self).delete_l2_policy_postcommit(context)
tenant = self.name_mapper.tenant(context, context.current['tenant_id'])
tenant = self._tenant_by_sharing_policy(context.current)
l2_policy = self.name_mapper.l2_policy(context, context.current['id'])
self.apic_manager.delete_bd_on_apic(tenant, l2_policy)
def delete_l3_policy_postcommit(self, context):
tenant = self.name_mapper.tenant(context, context.current['tenant_id'])
tenant = self._tenant_by_sharing_policy(context.current)
l3_policy = self.name_mapper.l3_policy(context, context.current['id'])
self.apic_manager.ensure_context_deleted(tenant, l3_policy)
@@ -353,11 +364,11 @@ class ApicMappingDriver(api.ResourceMappingDriver):
for es in ess:
self._unplug_l3p_from_es(context, es)
def update_policy_target_precommit(self, context):
pass
def update_policy_rule_set_precommit(self, context):
self._reject_shared_update(context, 'policy_rule_set')
def update_policy_target_postcommit(self, context):
# TODO(ivar): redo binding procedure if the EPG is modified,
# TODO(ivar): redo binding procedure if the PTG is modified,
# not doable unless driver extension framework is in place
pass
@@ -368,6 +379,7 @@ class ApicMappingDriver(api.ResourceMappingDriver):
def update_policy_target_group_precommit(self, context):
if set(context.original['subnets']) - set(context.current['subnets']):
raise gpexc.PolicyTargetGroupSubnetRemovalNotSupported()
self._reject_shared_update(context, 'policy_target_group')
def update_policy_target_group_postcommit(self, context):
# TODO(ivar): refactor parent to avoid code duplication
@@ -417,6 +429,7 @@ class ApicMappingDriver(api.ResourceMappingDriver):
context.current['tenant_id'], subnets=new_subnets)
def update_l3_policy_precommit(self, context):
self._reject_shared_update(context, 'l3_policy')
self._check_l3p_es(context)
def update_l3_policy_postcommit(self, context):
@@ -495,8 +508,7 @@ class ApicMappingDriver(api.ResourceMappingDriver):
default_gateway = ext_info['gateway_ip']
es_name = self.name_mapper.external_segment(
context, context.current['id'])
es_tenant = self.name_mapper.tenant(
context, context.current['tenant_id'])
es_tenant = self._tenant_by_sharing_policy(context.current)
ep_names = [self.name_mapper.external_policy(context, x)
for x in context.current['external_policies']]
@@ -638,30 +650,31 @@ class ApicMappingDriver(api.ResourceMappingDriver):
transaction=None):
# REVISIT(ivar): figure out what should be moved in apicapi instead
if policy_rules:
tenant = self.name_mapper.tenant(context,
context.current['tenant_id'])
policy_rule_set = self.name_mapper.policy_rule_set(
context, context.current['id'])
tenant = self._tenant_by_sharing_policy(policy_rule_set)
contract = self.name_mapper.policy_rule_set(context,
context.current['id'])
in_dir = [g_const.GP_DIRECTION_BI, g_const.GP_DIRECTION_IN]
out_dir = [g_const.GP_DIRECTION_BI, g_const.GP_DIRECTION_OUT]
filters = {'id': policy_rules}
for rule in context._plugin.get_policy_rules(
context._plugin_context, filters=filters):
policy_rule = self.name_mapper.policy_rule(context, rule['id'])
rule_owner = self._tenant_by_sharing_policy(rule)
classifier = context._plugin.get_policy_classifier(
context._plugin_context, rule['policy_classifier_id'])
with self.apic_manager.apic.transaction(transaction) as trs:
mgr = self.apic_manager
if classifier['direction'] in in_dir:
# Contract and subject are the same thing in this case
mgr.manage_contract_subject_in_filter(
policy_rule_set, policy_rule_set, policy_rule,
owner=tenant, transaction=trs, unset=unset)
# PRS and subject are the same thing in this case
self.apic_manager.manage_contract_subject_in_filter(
contract, contract, policy_rule, owner=tenant,
transaction=trs, unset=unset,
rule_owner=rule_owner)
if classifier['direction'] in out_dir:
# Contract and subject are the same thing in this case
mgr.manage_contract_subject_out_filter(
policy_rule_set, policy_rule_set, policy_rule,
owner=tenant, transaction=trs, unset=unset)
# PRS and subject are the same thing in this case
self.apic_manager.manage_contract_subject_out_filter(
contract, contract, policy_rule, owner=tenant,
transaction=trs, unset=unset,
rule_owner=rule_owner)
@lockutils.synchronized('apic-portlock')
def _manage_policy_target_port(self, plugin_context, pt):
@@ -674,9 +687,10 @@ class ApicMappingDriver(api.ResourceMappingDriver):
# TODO(ivar): change APICAPI to not expect a resource context
plugin_context._plugin = self.gbp_plugin
plugin_context._plugin_context = plugin_context
tenant_id = self.name_mapper.tenant(plugin_context,
port['tenant_id'])
ptg = self.name_mapper.policy_target_group(
ptg_object = self.gbp_plugin.get_policy_target_group(
plugin_context, port_details['ptg_id'])
tenant_id = self._tenant_by_sharing_policy(ptg_object)
epg = self.name_mapper.policy_target_group(
plugin_context, port_details['ptg_id'])
bd = self.name_mapper.l2_policy(
plugin_context, port_details['l2_policy_id'])
@@ -684,7 +698,7 @@ class ApicMappingDriver(api.ResourceMappingDriver):
# Create a static path attachment for the host/epg/switchport
with self.apic_manager.apic.transaction() as trs:
self.apic_manager.ensure_path_created_for_port(
tenant_id, ptg, port['binding:host_id'], seg,
tenant_id, epg, port['binding:host_id'], seg,
bd_name=bd,
transaction=trs)
@@ -694,33 +708,37 @@ class ApicMappingDriver(api.ResourceMappingDriver):
# TODO(ivar): change APICAPI to not expect a resource context
plugin_context._plugin = self.gbp_plugin
plugin_context._plugin_context = plugin_context
mapped_tenant = self.name_mapper.tenant(plugin_context,
ptg['tenant_id'])
mapped_tenant = self._tenant_by_sharing_policy(ptg)
mapped_ptg = self.name_mapper.policy_target_group(plugin_context,
ptg['id'])
ptg['id'])
provided = [added_provided, removed_provided]
consumed = [added_consumed, removed_consumed]
methods = [self.apic_manager.set_contract_for_epg,
self.apic_manager.unset_contract_for_epg]
with self.apic_manager.apic.transaction(transaction) as trs:
for x in xrange(len(provided)):
for c in provided[x]:
c = self.name_mapper.policy_rule_set(plugin_context, c)
for c in self.gbp_plugin.get_policy_rule_sets(
plugin_context, filters={'id': provided[x]}):
c_owner = self._tenant_by_sharing_policy(c)
c = self.name_mapper.policy_rule_set(plugin_context,
c['id'])
methods[x](mapped_tenant, mapped_ptg, c, provider=True,
transaction=trs)
contract_owner=c_owner, transaction=trs)
for x in xrange(len(consumed)):
for c in consumed[x]:
c = self.name_mapper.policy_rule_set(plugin_context, c)
for c in self.gbp_plugin.get_policy_rule_sets(
plugin_context, filters={'id': consumed[x]}):
c_owner = self._tenant_by_sharing_policy(c)
c = self.name_mapper.policy_rule_set(plugin_context,
c['id'])
methods[x](mapped_tenant, mapped_ptg, c, provider=False,
transaction=trs)
contract_owner=c_owner, transaction=trs)
def _manage_ep_policy_rule_sets(
self, plugin_context, es, ep, added_provided, added_consumed,
removed_provided, removed_consumed, transaction=None):
plugin_context._plugin = self.gbp_plugin
plugin_context._plugin_context = plugin_context
mapped_tenant = self.name_mapper.tenant(plugin_context,
es['tenant_id'])
mapped_tenant = self._tenant_by_sharing_policy(es)
mapped_es = self.name_mapper.external_segment(plugin_context, es['id'])
mapped_ep = self.name_mapper.external_policy(plugin_context,
@@ -748,8 +766,9 @@ class ApicMappingDriver(api.ResourceMappingDriver):
# TODO(ivar): change APICAPI to not expect a resource context
plugin_context._plugin = self.gbp_plugin
plugin_context._plugin_context = plugin_context
mapped_tenant = self.name_mapper.tenant(plugin_context,
ptg['tenant_id'])
l2_policy_object = self.gbp_plugin.get_l2_policy(
plugin_context, ptg['l2_policy_id'])
mapped_tenant = self._tenant_by_sharing_policy(l2_policy_object)
mapped_l2p = self.name_mapper.l2_policy(plugin_context,
ptg['l2_policy_id'])
subnets = [added_subnets, removed_subnets]
@@ -779,11 +798,12 @@ class ApicMappingDriver(api.ResourceMappingDriver):
# TODO(ivar): change APICAPI to not expect a resource context
context._plugin = self.gbp_plugin
context._plugin_context = context
atenant_id = self.name_mapper.tenant(context,
port_info['tenant_id'])
ptg = self.name_mapper.policy_target_group(context,
ptg_object = self.gbp_plugin.get_policy_target_group(
context, port_info['ptg_id'])
atenant_id = self._tenant_by_sharing_policy(ptg_object)
epg = self.name_mapper.policy_target_group(context,
port_info['ptg_id'])
self._delete_port_path(context, atenant_id, ptg, port_info)
self._delete_port_path(context, atenant_id, epg, port_info)
def _get_default_security_group(self, context, ptg_id, tenant_id):
# Default SG in APIC mapping is per tenant, and allows all the traffic
@@ -886,8 +906,7 @@ class ApicMappingDriver(api.ResourceMappingDriver):
default_gateway = ext_info['gateway_ip']
es_name = self.name_mapper.external_segment(
context, es['id'])
es_tenant = self.name_mapper.tenant(
context, es['tenant_id'])
es_tenant = self._tenant_by_sharing_policy(es)
with self.apic_manager.apic.transaction() as trs:
# Create External Routed Network connected to the proper
# L3 Context
@@ -906,7 +925,7 @@ class ApicMappingDriver(api.ResourceMappingDriver):
def _unplug_l3p_from_es(self, context, es):
es_name = self.name_mapper.external_segment(context, es['id'])
es_tenant = self.name_mapper.tenant(context, es['tenant_id'])
es_tenant = self._tenant_by_sharing_policy(es)
self.apic_manager.delete_external_routed_network(
es_name, owner=es_tenant)
@@ -932,7 +951,7 @@ class ApicMappingDriver(api.ResourceMappingDriver):
"mapping driver.") % es['id'])
continue
es_name = self.name_mapper.external_segment(context, es['id'])
es_tenant = self.name_mapper.tenant(context, es['tenant_id'])
es_tenant = self._tenant_by_sharing_policy(es)
with self.apic_manager.apic.transaction() as trs:
# Create External EPG
subnets = set(x['destination'] for
@@ -959,7 +978,7 @@ class ApicMappingDriver(api.ResourceMappingDriver):
"mapping driver.") % es['id'])
continue
es_name = self.name_mapper.external_segment(context, es['id'])
es_tenant = self.name_mapper.tenant(context, es['tenant_id'])
es_tenant = self._tenant_by_sharing_policy(es)
self.apic_manager.ensure_external_epg_deleted(
es_name, external_epg=ep_name, owner=es_tenant)
@@ -983,3 +1002,13 @@ class ApicMappingDriver(api.ResourceMappingDriver):
if ptgass:
return self.gbp_plugin.get_policy_target_group(
plugin_context, ptgass['policy_target_group_id'])
def _reject_shared_update(self, context, type):
if context.original.get('shared') != context.current.get('shared'):
raise SharedAttributeUpdateNotSupportedOnApic(type=type)
def _tenant_by_sharing_policy(self, object):
if not object.get('shared'):
return self.name_mapper.tenant(None, object['tenant_id'])
else:
return apic_manager.TENANT_COMMON