Merge "Group Policy: Resource Mapping Driver (Security Groups)"
This commit is contained in:
@@ -21,11 +21,14 @@ from neutron.common import constants as const
|
||||
from neutron.common import exceptions as n_exc
|
||||
from neutron.common import log
|
||||
from neutron.db import model_base
|
||||
from neutron.extensions import securitygroup as ext_sg
|
||||
from neutron import manager
|
||||
from neutron.notifiers import nova
|
||||
from neutron.openstack.common import log as logging
|
||||
from neutron.plugins.common import constants as pconst
|
||||
|
||||
from gbp.neutron.db.grouppolicy import group_policy_db as gpdb
|
||||
from gbp.neutron.services.grouppolicy.common import constants as gconst
|
||||
from gbp.neutron.services.grouppolicy.common import exceptions as exc
|
||||
from gbp.neutron.services.grouppolicy import group_policy_driver_api as api
|
||||
|
||||
@@ -69,6 +72,20 @@ class OwnedRouter(model_base.BASEV2):
|
||||
nullable=False, primary_key=True)
|
||||
|
||||
|
||||
class ContractSGsMapping(model_base.BASEV2):
|
||||
"""Contract to SGs mapping DB."""
|
||||
|
||||
__tablename__ = 'gpm_contract_sg_mapping'
|
||||
contract_id = sa.Column(sa.String(36),
|
||||
sa.ForeignKey('gp_contracts.id',
|
||||
ondelete='CASCADE'),
|
||||
nullable=False, primary_key=True)
|
||||
provided_sg_id = sa.Column(sa.String(36),
|
||||
sa.ForeignKey('securitygroups.id'))
|
||||
consumed_sg_id = sa.Column(sa.String(36),
|
||||
sa.ForeignKey('securitygroups.id'))
|
||||
|
||||
|
||||
class ResourceMappingDriver(api.PolicyDriver):
|
||||
"""Resource Mapping driver for Group Policy plugin.
|
||||
|
||||
@@ -92,6 +109,8 @@ class ResourceMappingDriver(api.PolicyDriver):
|
||||
# EPG.
|
||||
if not context.current['port_id']:
|
||||
self._use_implicit_port(context)
|
||||
self._assoc_epg_sg_to_ep(context, context.current['id'],
|
||||
context.current['endpoint_group_id'])
|
||||
|
||||
@log.log
|
||||
def update_endpoint_precommit(self, context):
|
||||
@@ -109,8 +128,12 @@ class ResourceMappingDriver(api.PolicyDriver):
|
||||
|
||||
@log.log
|
||||
def delete_endpoint_postcommit(self, context):
|
||||
sg_list = self._generate_list_of_sg_from_epg(
|
||||
context, context.current['endpoint_group_id'])
|
||||
self._disassoc_sgs_from_port(context._plugin_context,
|
||||
context.current['port_id'], sg_list)
|
||||
port_id = context.current['port_id']
|
||||
self._cleanup_port(context, port_id)
|
||||
self._cleanup_port(context._plugin_context, port_id)
|
||||
|
||||
@log.log
|
||||
def create_endpoint_group_precommit(self, context):
|
||||
@@ -130,9 +153,11 @@ class ResourceMappingDriver(api.PolicyDriver):
|
||||
l3p_id)
|
||||
router_id = l3p['routers'][0]
|
||||
for subnet_id in subnets:
|
||||
self._use_explicit_subnet(context, subnet_id, router_id)
|
||||
self._use_explicit_subnet(context._plugin_context, subnet_id,
|
||||
router_id)
|
||||
else:
|
||||
self._use_implicit_subnet(context)
|
||||
self._handle_contracts(context)
|
||||
|
||||
@log.log
|
||||
def update_endpoint_group_precommit(self, context):
|
||||
@@ -141,7 +166,48 @@ class ResourceMappingDriver(api.PolicyDriver):
|
||||
|
||||
@log.log
|
||||
def update_endpoint_group_postcommit(self, context):
|
||||
pass
|
||||
# Three conditions where SG association needs to be changed
|
||||
# (a) list of endpoints change
|
||||
# (b) provided_contracts change
|
||||
# (c) consumed_contracts change
|
||||
epg_id = context.current['id']
|
||||
new_endpoints = list(set(context.current['endpoints']) -
|
||||
set(context.original['endpoints']))
|
||||
if new_endpoints:
|
||||
self._update_sgs_on_ep_with_epg(context, epg_id,
|
||||
new_endpoints, "ASSOCIATE")
|
||||
removed_endpoints = list(set(context.original['endpoints']) -
|
||||
set(context.current['endpoints']))
|
||||
if removed_endpoints:
|
||||
self._update_sgs_on_ep_with_epg(context, epg_id,
|
||||
new_endpoints, "DISASSOCIATE")
|
||||
# generate a list of contracts (SGs) to update on the EPG
|
||||
orig_provided_contracts = context.original['provided_contracts']
|
||||
curr_provided_contracts = context.current['provided_contracts']
|
||||
new_provided_contracts = list(set(curr_provided_contracts) -
|
||||
set(orig_provided_contracts))
|
||||
orig_consumed_contracts = context.original['consumed_contracts']
|
||||
curr_consumed_contracts = context.current['consumed_contracts']
|
||||
new_consumed_contracts = list(set(curr_consumed_contracts) -
|
||||
set(orig_consumed_contracts))
|
||||
# if EPG associated contracts are updated, we need to update
|
||||
# the policy rules, then assoicate SGs to ports
|
||||
if new_provided_contracts or new_consumed_contracts:
|
||||
subnets = context.current['subnets']
|
||||
self._assoc_sg_to_epg(context, subnets, new_provided_contracts,
|
||||
new_consumed_contracts)
|
||||
self._update_sgs_on_epg(context, epg_id,
|
||||
new_provided_contracts,
|
||||
new_consumed_contracts, "ASSOCIATE")
|
||||
# generate the list of contracts (SGs) to remove from current ports
|
||||
removed_provided_contracts = list(set(orig_provided_contracts) -
|
||||
set(curr_provided_contracts))
|
||||
removed_consumed_contracts = list(set(orig_consumed_contracts) -
|
||||
set(curr_consumed_contracts))
|
||||
if removed_provided_contracts or removed_consumed_contracts:
|
||||
self._update_sgs_on_epg(context, epg_id,
|
||||
removed_provided_contracts,
|
||||
removed_consumed_contracts, "DISASSOCIATE")
|
||||
|
||||
@log.log
|
||||
def delete_endpoint_group_precommit(self, context):
|
||||
@@ -155,7 +221,7 @@ class ResourceMappingDriver(api.PolicyDriver):
|
||||
l3p = context._plugin.get_l3_policy(context._plugin_context, l3p_id)
|
||||
router_id = l3p['routers'][0]
|
||||
for subnet_id in context.current['subnets']:
|
||||
self._cleanup_subnet(context, subnet_id, router_id)
|
||||
self._cleanup_subnet(context._plugin_context, subnet_id, router_id)
|
||||
|
||||
@log.log
|
||||
def create_l2_policy_precommit(self, context):
|
||||
@@ -181,7 +247,7 @@ class ResourceMappingDriver(api.PolicyDriver):
|
||||
@log.log
|
||||
def delete_l2_policy_postcommit(self, context):
|
||||
network_id = context.current['network_id']
|
||||
self._cleanup_network(context, network_id)
|
||||
self._cleanup_network(context._plugin_context, network_id)
|
||||
|
||||
@log.log
|
||||
def create_l3_policy_precommit(self, context):
|
||||
@@ -209,7 +275,153 @@ class ResourceMappingDriver(api.PolicyDriver):
|
||||
@log.log
|
||||
def delete_l3_policy_postcommit(self, context):
|
||||
for router_id in context.current['routers']:
|
||||
self._cleanup_router(context, router_id)
|
||||
self._cleanup_router(context._plugin_context, router_id)
|
||||
|
||||
@log.log
|
||||
def create_policy_classifier_precommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log
|
||||
def create_policy_classifier_postcommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log
|
||||
def update_policy_classifier_precommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log
|
||||
def update_policy_classifier_postcommit(self, context):
|
||||
# TODO(ivar): Should affect related SGs
|
||||
pass
|
||||
|
||||
@log.log
|
||||
def delete_policy_classifier_precommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log
|
||||
def delete_policy_classifier_postcommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log
|
||||
def create_policy_action_precommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log
|
||||
def create_policy_action_postcommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log
|
||||
def update_policy_action_precommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log
|
||||
def update_policy_action_postcommit(self, context):
|
||||
# TODO(ivar): Should affect related SGs
|
||||
pass
|
||||
|
||||
@log.log
|
||||
def delete_policy_action_precommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log
|
||||
def delete_policy_action_postcommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log
|
||||
def create_policy_rule_precommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log
|
||||
def create_policy_rule_postcommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log
|
||||
def update_policy_rule_precommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log
|
||||
def update_policy_rule_postcommit(self, context):
|
||||
# TODO(ivar): Should affect related SGs
|
||||
pass
|
||||
|
||||
@log.log
|
||||
def delete_policy_rule_precommit(self, context):
|
||||
# REVISIT(ivar): This will be removed once navigability issue is
|
||||
# solved (bug/1384397)
|
||||
context._rmd_contracts_temp = (
|
||||
context._plugin._get_policy_rule_contracts(context._plugin_context,
|
||||
context.current['id']))
|
||||
|
||||
@log.log
|
||||
def delete_policy_rule_postcommit(self, context):
|
||||
for contract_id in context._rmd_contracts_temp:
|
||||
contract = context._plugin.get_contract(
|
||||
context._plugin_context, contract_id)
|
||||
contract_sg_mappings = self._get_contract_sg_mapping(
|
||||
context._plugin_context.session, contract['id'])
|
||||
epg_mapping = self._get_contract_epg_mapping(context, contract)
|
||||
cidr_mapping = self._get_epg_cidrs_mapping(context, epg_mapping)
|
||||
self._add_or_remove_contract_rule(context, context.current,
|
||||
contract_sg_mappings,
|
||||
cidr_mapping,
|
||||
unset=True)
|
||||
|
||||
@log.log
|
||||
def create_contract_precommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log
|
||||
def create_contract_postcommit(self, context):
|
||||
# creating SGs
|
||||
contract_id = context.current['id']
|
||||
consumed_sg = self._create_contract_sg(context, 'consumed')
|
||||
provided_sg = self._create_contract_sg(context, 'provided')
|
||||
consumed_sg_id = consumed_sg['id']
|
||||
provided_sg_id = provided_sg['id']
|
||||
self._set_contract_sg_mapping(context._plugin_context.session,
|
||||
contract_id, consumed_sg_id,
|
||||
provided_sg_id)
|
||||
self._apply_contract_rules(context, context.current,
|
||||
context.current['policy_rules'])
|
||||
|
||||
@log.log
|
||||
def update_contract_precommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log
|
||||
def update_contract_postcommit(self, context):
|
||||
old_rules = set(context.original['policy_rules'])
|
||||
new_rules = set(context.current['policy_rules'])
|
||||
to_add = new_rules - old_rules
|
||||
to_remove = old_rules - new_rules
|
||||
self._remove_contract_rules(context, context.current, to_remove)
|
||||
self._apply_contract_rules(context, context.current, to_add)
|
||||
|
||||
@log.log
|
||||
def delete_contract_precommit(self, context):
|
||||
mapping = self._get_contract_sg_mapping(
|
||||
context._plugin_context.session, context.current['id'])
|
||||
context._rmd_sg_list_temp = [mapping['provided_sg_id'],
|
||||
mapping['consumed_sg_id']]
|
||||
contract = context._plugin._get_contract(
|
||||
context._plugin_context, context.current['id'])
|
||||
context._rmd_epg_mapping_temp = self._get_contract_epg_mapping(
|
||||
context, contract)
|
||||
|
||||
@log.log
|
||||
def delete_contract_postcommit(self, context):
|
||||
# Disassociate SGs
|
||||
sg_list = context._rmd_sg_list_temp
|
||||
|
||||
epg_mapping = context._rmd_epg_mapping_temp
|
||||
for epgs in epg_mapping.values():
|
||||
for epg in epgs:
|
||||
endpoint_list = epg['endpoints']
|
||||
for ep_id in endpoint_list:
|
||||
self._disassoc_sgs_from_ep(context, ep_id, sg_list)
|
||||
# Delete SGs
|
||||
for sg in sg_list:
|
||||
self._delete_sg(context._plugin_context, sg)
|
||||
|
||||
def _use_implicit_port(self, context):
|
||||
epg_id = context.current['endpoint_group_id']
|
||||
@@ -217,6 +429,8 @@ class ResourceMappingDriver(api.PolicyDriver):
|
||||
epg_id)
|
||||
l2p_id = epg['l2_policy_id']
|
||||
l2p = context._plugin.get_l2_policy(context._plugin_context, l2p_id)
|
||||
sg_id = self._ensure_default_security_group(
|
||||
context._plugin_context, context.current['tenant_id'])
|
||||
attrs = {'tenant_id': context.current['tenant_id'],
|
||||
'name': 'ep_' + context.current['name'],
|
||||
'network_id': l2p['network_id'],
|
||||
@@ -224,15 +438,16 @@ class ResourceMappingDriver(api.PolicyDriver):
|
||||
'fixed_ips': attributes.ATTR_NOT_SPECIFIED,
|
||||
'device_id': '',
|
||||
'device_owner': '',
|
||||
'security_groups': [sg_id],
|
||||
'admin_state_up': True}
|
||||
port = self._create_port(context, attrs)
|
||||
port = self._create_port(context._plugin_context, attrs)
|
||||
port_id = port['id']
|
||||
self._mark_port_owned(context._plugin_context.session, port_id)
|
||||
context.set_port_id(port_id)
|
||||
|
||||
def _cleanup_port(self, context, port_id):
|
||||
if self._port_is_owned(context._plugin_context.session, port_id):
|
||||
self._delete_port(context, port_id)
|
||||
def _cleanup_port(self, plugin_context, port_id):
|
||||
if self._port_is_owned(plugin_context.session, port_id):
|
||||
self._delete_port(plugin_context, port_id)
|
||||
|
||||
def _use_implicit_subnet(self, context):
|
||||
# REVISIT(rkukura): This is a temporary allocation algorithm
|
||||
@@ -257,15 +472,15 @@ class ResourceMappingDriver(api.PolicyDriver):
|
||||
'allocation_pools': attributes.ATTR_NOT_SPECIFIED,
|
||||
'dns_nameservers': attributes.ATTR_NOT_SPECIFIED,
|
||||
'host_routes': attributes.ATTR_NOT_SPECIFIED}
|
||||
subnet = self._create_subnet(context, attrs)
|
||||
subnet = self._create_subnet(context._plugin_context, attrs)
|
||||
subnet_id = subnet['id']
|
||||
try:
|
||||
router_id = l3p['routers'][0]
|
||||
interface_info = {'subnet_id': subnet_id}
|
||||
self._add_router_interface(context, router_id,
|
||||
interface_info)
|
||||
self._mark_subnet_owned(context._plugin_context.session,
|
||||
subnet_id)
|
||||
self._add_router_interface(context._plugin_context,
|
||||
router_id, interface_info)
|
||||
self._mark_subnet_owned(
|
||||
context._plugin_context.session, subnet_id)
|
||||
context.add_subnet(subnet_id)
|
||||
return
|
||||
except n_exc.InvalidInput:
|
||||
@@ -273,7 +488,7 @@ class ResourceMappingDriver(api.PolicyDriver):
|
||||
# here so that it isn't caught below and handled
|
||||
# as if the CIDR is already in use.
|
||||
LOG.exception(_("adding subnet to router failed"))
|
||||
self._delete_subnet(context, subnet['id'])
|
||||
self._delete_subnet(context._plugin_context, subnet['id'])
|
||||
raise exc.GroupPolicyInternalError()
|
||||
except n_exc.BadRequest:
|
||||
# This is expected (CIDR overlap) until we have a
|
||||
@@ -282,43 +497,69 @@ class ResourceMappingDriver(api.PolicyDriver):
|
||||
pass
|
||||
raise exc.NoSubnetAvailable()
|
||||
|
||||
def _use_explicit_subnet(self, context, subnet_id, router_id):
|
||||
def _use_explicit_subnet(self, plugin_context, subnet_id, router_id):
|
||||
interface_info = {'subnet_id': subnet_id}
|
||||
self._add_router_interface(context, router_id, interface_info)
|
||||
self._add_router_interface(plugin_context, router_id,
|
||||
interface_info)
|
||||
|
||||
def _cleanup_subnet(self, context, subnet_id, router_id):
|
||||
def _cleanup_subnet(self, plugin_context, subnet_id, router_id):
|
||||
interface_info = {'subnet_id': subnet_id}
|
||||
self._remove_router_interface(context, router_id, interface_info)
|
||||
if self._subnet_is_owned(context._plugin_context.session, subnet_id):
|
||||
self._delete_subnet(context, subnet_id)
|
||||
self._remove_router_interface(plugin_context, router_id,
|
||||
interface_info)
|
||||
if self._subnet_is_owned(plugin_context.session, subnet_id):
|
||||
self._delete_subnet(plugin_context, subnet_id)
|
||||
|
||||
def _use_implicit_network(self, context):
|
||||
attrs = {'tenant_id': context.current['tenant_id'],
|
||||
'name': 'l2p_' + context.current['name'],
|
||||
'admin_state_up': True,
|
||||
'shared': False}
|
||||
network = self._create_network(context, attrs)
|
||||
network = self._create_network(context._plugin_context, attrs)
|
||||
network_id = network['id']
|
||||
self._mark_network_owned(context._plugin_context.session, network_id)
|
||||
context.set_network_id(network_id)
|
||||
|
||||
def _cleanup_network(self, context, network_id):
|
||||
if self._network_is_owned(context._plugin_context.session, network_id):
|
||||
self._delete_network(context, network_id)
|
||||
def _cleanup_network(self, plugin_context, network_id):
|
||||
if self._network_is_owned(plugin_context.session, network_id):
|
||||
self._delete_network(plugin_context, network_id)
|
||||
|
||||
def _use_implicit_router(self, context):
|
||||
attrs = {'tenant_id': context.current['tenant_id'],
|
||||
'name': 'l3p_' + context.current['name'],
|
||||
'external_gateway_info': None,
|
||||
'admin_state_up': True}
|
||||
router = self._create_router(context, attrs)
|
||||
router = self._create_router(context._plugin_context, attrs)
|
||||
router_id = router['id']
|
||||
self._mark_router_owned(context._plugin_context.session, router_id)
|
||||
context.add_router(router_id)
|
||||
|
||||
def _cleanup_router(self, context, router_id):
|
||||
if self._router_is_owned(context._plugin_context.session, router_id):
|
||||
self._delete_router(context, router_id)
|
||||
def _cleanup_router(self, plugin_context, router_id):
|
||||
if self._router_is_owned(plugin_context.session, router_id):
|
||||
self._delete_router(plugin_context, router_id)
|
||||
|
||||
def _create_contract_sg(self, context, sg_name_prefix):
|
||||
# This method sets up the attributes of security group
|
||||
attrs = {'tenant_id': context.current['tenant_id'],
|
||||
'name': sg_name_prefix + '_' + context.current['name'],
|
||||
'description': '',
|
||||
'security_group_rules': ''}
|
||||
return self._create_sg(context._plugin_context, attrs)
|
||||
|
||||
def _handle_contracts(self, context):
|
||||
# This method handles contract => SG mapping
|
||||
# context is EPG context
|
||||
|
||||
# for all consumed contracts, simply associate
|
||||
# each EP's port from the EPG
|
||||
# rules are expected to be filled out already
|
||||
consumed_contracts = context.current['consumed_contracts']
|
||||
provided_contracts = context.current['provided_contracts']
|
||||
subnets = context.current['subnets']
|
||||
epg_id = context.current['id']
|
||||
self._assoc_sg_to_epg(context, subnets, provided_contracts,
|
||||
consumed_contracts)
|
||||
self._update_sgs_on_epg(context, epg_id, provided_contracts,
|
||||
consumed_contracts, "ASSOCIATE")
|
||||
|
||||
# The following methods perform the necessary subset of
|
||||
# functionality from neutron.api.v2.base.Controller.
|
||||
@@ -327,53 +568,79 @@ class ResourceMappingDriver(api.PolicyDriver):
|
||||
# neutronclient is also a possibility, but presents significant
|
||||
# issues to unit testing as well as overhead and failure modes.
|
||||
|
||||
def _create_port(self, context, attrs):
|
||||
return self._create_resource(self._core_plugin,
|
||||
context._plugin_context,
|
||||
'port', attrs)
|
||||
def _create_port(self, plugin_context, attrs):
|
||||
return self._create_resource(self._core_plugin, plugin_context, 'port',
|
||||
attrs)
|
||||
|
||||
def _delete_port(self, context, port_id):
|
||||
def _update_port(self, plugin_context, port_id, attrs):
|
||||
return self._update_resource(self._core_plugin, plugin_context, 'port',
|
||||
port_id, attrs)
|
||||
|
||||
def _delete_port(self, plugin_context, port_id):
|
||||
self._delete_resource(self._core_plugin,
|
||||
context._plugin_context,
|
||||
'port', port_id)
|
||||
plugin_context, 'port', port_id)
|
||||
|
||||
def _create_subnet(self, context, attrs):
|
||||
return self._create_resource(self._core_plugin,
|
||||
context._plugin_context,
|
||||
def _create_subnet(self, plugin_context, attrs):
|
||||
return self._create_resource(self._core_plugin, plugin_context,
|
||||
'subnet', attrs)
|
||||
|
||||
def _delete_subnet(self, context, subnet_id):
|
||||
self._delete_resource(self._core_plugin,
|
||||
context._plugin_context,
|
||||
'subnet', subnet_id)
|
||||
def _delete_subnet(self, plugin_context, subnet_id):
|
||||
self._delete_resource(self._core_plugin, plugin_context, 'subnet',
|
||||
subnet_id)
|
||||
|
||||
def _create_network(self, context, attrs):
|
||||
return self._create_resource(self._core_plugin,
|
||||
context._plugin_context,
|
||||
def _create_network(self, plugin_context, attrs):
|
||||
return self._create_resource(self._core_plugin, plugin_context,
|
||||
'network', attrs)
|
||||
|
||||
def _delete_network(self, context, network_id):
|
||||
self._delete_resource(self._core_plugin,
|
||||
context._plugin_context,
|
||||
def _delete_network(self, plugin_context, network_id):
|
||||
self._delete_resource(self._core_plugin, plugin_context,
|
||||
'network', network_id)
|
||||
|
||||
def _create_router(self, context, attrs):
|
||||
return self._create_resource(self._l3_plugin,
|
||||
context._plugin_context,
|
||||
'router', attrs)
|
||||
def _create_router(self, plugin_context, attrs):
|
||||
return self._create_resource(self._l3_plugin, plugin_context, 'router',
|
||||
attrs)
|
||||
|
||||
def _add_router_interface(self, context, router_id, interface_info):
|
||||
self._l3_plugin.add_router_interface(context._plugin_context,
|
||||
def _add_router_interface(self, plugin_context, router_id, interface_info):
|
||||
self._l3_plugin.add_router_interface(plugin_context,
|
||||
router_id, interface_info)
|
||||
|
||||
def _remove_router_interface(self, context, router_id, interface_info):
|
||||
self._l3_plugin.remove_router_interface(context._plugin_context,
|
||||
router_id, interface_info)
|
||||
def _remove_router_interface(self, plugin_context, router_id,
|
||||
interface_info):
|
||||
self._l3_plugin.remove_router_interface(plugin_context, router_id,
|
||||
interface_info)
|
||||
|
||||
def _delete_router(self, context, router_id):
|
||||
self._delete_resource(self._l3_plugin,
|
||||
context._plugin_context,
|
||||
'router', router_id)
|
||||
def _delete_router(self, plugin_context, router_id):
|
||||
self._delete_resource(self._l3_plugin, plugin_context, 'router',
|
||||
router_id)
|
||||
|
||||
def _create_sg(self, plugin_context, attrs):
|
||||
return self._create_resource(self._core_plugin, plugin_context,
|
||||
'security_group', attrs)
|
||||
|
||||
def _update_sg(self, plugin_context, sg_id, attrs):
|
||||
return self._update_resouce(self._core_plugin, plugin_context,
|
||||
'security_group', sg_id, attrs)
|
||||
|
||||
def _delete_sg(self, plugin_context, sg_id):
|
||||
self._delete_resource(self._core_plugin, plugin_context,
|
||||
'security_group', sg_id)
|
||||
|
||||
def _create_sg_rule(self, plugin_context, attrs):
|
||||
try:
|
||||
return self._create_resource(self._core_plugin, plugin_context,
|
||||
'security_group_rule', attrs)
|
||||
except ext_sg.SecurityGroupRuleExists as ex:
|
||||
LOG.warn(_('Security Group already exists %s'), ex.message)
|
||||
return
|
||||
|
||||
def _update_sg_rule(self, plugin_context, sg_rule_id, attrs):
|
||||
return self._update_resource(self._core_plugin, plugin_context,
|
||||
'security_group_rule', sg_rule_id,
|
||||
attrs)
|
||||
|
||||
def _delete_sg_rule(self, plugin_context, sg_rule_id):
|
||||
self._delete_resource(self._core_plugin, plugin_context,
|
||||
'security_group_rule', sg_rule_id)
|
||||
|
||||
def _create_resource(self, plugin, context, resource, attrs):
|
||||
# REVISIT(rkukura): Do create.start notification?
|
||||
@@ -493,3 +760,252 @@ class ResourceMappingDriver(api.PolicyDriver):
|
||||
return (session.query(OwnedRouter).
|
||||
filter_by(router_id=router_id).
|
||||
first() is not None)
|
||||
|
||||
def _set_contract_sg_mapping(self, session, contract_id,
|
||||
consumed_sg_id, provided_sg_id):
|
||||
with session.begin(subtransactions=True):
|
||||
mapping = ContractSGsMapping(contract_id=contract_id,
|
||||
consumed_sg_id=consumed_sg_id,
|
||||
provided_sg_id=provided_sg_id)
|
||||
session.add(mapping)
|
||||
|
||||
def _get_contract_sg_mapping(self, session, contract_id):
|
||||
with session.begin(subtransactions=True):
|
||||
return (session.query(ContractSGsMapping).
|
||||
filter_by(contract_id=contract_id).one())
|
||||
|
||||
def _sg_rule(self, context, sg_id, protocol, port_range, cidr,
|
||||
direction, unset=False):
|
||||
port_min, port_max = (gpdb.GroupPolicyDbPlugin.
|
||||
_get_min_max_ports_from_range(port_range))
|
||||
attrs = {'tenant_id': context.current['tenant_id'],
|
||||
'security_group_id': sg_id,
|
||||
'direction': direction,
|
||||
'ethertype': const.IPv4,
|
||||
'protocol': protocol,
|
||||
'port_range_min': port_min,
|
||||
'port_range_max': port_max,
|
||||
'remote_ip_prefix': cidr,
|
||||
'remote_group_id': None}
|
||||
if unset:
|
||||
filters = {}
|
||||
for key in attrs:
|
||||
value = attrs[key]
|
||||
if value:
|
||||
filters[key] = [value]
|
||||
rule = self._core_plugin.get_security_group_rules(
|
||||
context._plugin_context, filters)
|
||||
if rule:
|
||||
self._delete_sg_rule(context._plugin_context, rule[0]['id'])
|
||||
else:
|
||||
return self._create_sg_rule(context._plugin_context, attrs)
|
||||
|
||||
def _sg_ingress_rule(self, context, sg_id, protocol, port_range,
|
||||
cidr, unset=False):
|
||||
return self._sg_rule(context, sg_id, protocol, port_range,
|
||||
cidr, 'ingress', unset)
|
||||
|
||||
def _sg_egress_rule(self, context, sg_id, protocol, port_range,
|
||||
cidr, unset=False):
|
||||
return self._sg_rule(context, sg_id, protocol, port_range,
|
||||
cidr, 'egress', unset)
|
||||
|
||||
def _assoc_sgs_to_ep(self, context, ep_id, sg_list):
|
||||
ep = context._plugin.get_endpoint(context._plugin_context, ep_id)
|
||||
port_id = ep['port_id']
|
||||
port = self._core_plugin.get_port(context._plugin_context, port_id)
|
||||
cur_sg_list = port[ext_sg.SECURITYGROUPS]
|
||||
new_sg_list = cur_sg_list + sg_list
|
||||
port[ext_sg.SECURITYGROUPS] = new_sg_list
|
||||
self._update_port(context._plugin_context, port_id, port)
|
||||
|
||||
def _disassoc_sgs_from_ep(self, context, ep_id, sg_list):
|
||||
ep = context._plugin.get_endpoint(context._plugin_context, ep_id)
|
||||
port_id = ep['port_id']
|
||||
self._disassoc_sgs_from_port(context._plugin_context, port_id, sg_list)
|
||||
|
||||
def _disassoc_sgs_from_port(self, plugin_context, port_id, sg_list):
|
||||
port = self._core_plugin.get_port(plugin_context, port_id)
|
||||
cur_sg_list = port[ext_sg.SECURITYGROUPS]
|
||||
new_sg_list = list(set(cur_sg_list) - set(sg_list))
|
||||
port[ext_sg.SECURITYGROUPS] = new_sg_list
|
||||
self._update_port(plugin_context, port_id, port)
|
||||
|
||||
def _generate_list_of_sg_from_epg(self, context, epg_id):
|
||||
epg = context._plugin.get_endpoint_group(context._plugin_context,
|
||||
epg_id)
|
||||
provided_contracts = epg['provided_contracts']
|
||||
consumed_contracts = epg['consumed_contracts']
|
||||
return(self._generate_list_sg_from_contract_list(context,
|
||||
provided_contracts,
|
||||
consumed_contracts))
|
||||
|
||||
def _generate_list_sg_from_contract_list(self, context,
|
||||
provided_contracts,
|
||||
consumed_contracts):
|
||||
ret_list = []
|
||||
for contract_id in provided_contracts:
|
||||
contract_sg_mappings = self._get_contract_sg_mapping(
|
||||
context._plugin_context.session, contract_id)
|
||||
provided_sg_id = contract_sg_mappings['provided_sg_id']
|
||||
ret_list.append(provided_sg_id)
|
||||
|
||||
for contract_id in consumed_contracts:
|
||||
contract_sg_mappings = self._get_contract_sg_mapping(
|
||||
context._plugin_context.session, contract_id)
|
||||
consumed_sg_id = contract_sg_mappings['consumed_sg_id']
|
||||
ret_list.append(consumed_sg_id)
|
||||
return ret_list
|
||||
|
||||
def _assoc_epg_sg_to_ep(self, context, ep_id, epg_id):
|
||||
sg_list = self._generate_list_of_sg_from_epg(context, epg_id)
|
||||
self._assoc_sgs_to_ep(context, ep_id, sg_list)
|
||||
|
||||
def _update_sgs_on_ep_with_epg(self, context, epg_id, new_ep_list, op):
|
||||
sg_list = self._generate_list_of_sg_from_epg(context, epg_id)
|
||||
for ep_id in new_ep_list:
|
||||
if op == "ASSOCIATE":
|
||||
self._assoc_sgs_to_ep(context, ep_id, sg_list)
|
||||
else:
|
||||
self._disassoc_sgs_from_ep(context, ep_id, sg_list)
|
||||
|
||||
def _update_sgs_on_epg(self, context, epg_id,
|
||||
provided_contracts, consumed_contracts, op):
|
||||
sg_list = self._generate_list_sg_from_contract_list(context,
|
||||
provided_contracts,
|
||||
consumed_contracts)
|
||||
epg = context._plugin.get_endpoint_group(context._plugin_context,
|
||||
epg_id)
|
||||
endpoint_list = epg['endpoints']
|
||||
for ep_id in endpoint_list:
|
||||
if op == "ASSOCIATE":
|
||||
self._assoc_sgs_to_ep(context, ep_id, sg_list)
|
||||
else:
|
||||
self._disassoc_sgs_from_ep(context, ep_id, sg_list)
|
||||
|
||||
# context should be EPG
|
||||
def _assoc_sg_to_epg(self, context, subnets, provided_contracts,
|
||||
consumed_contracts):
|
||||
if not provided_contracts and not consumed_contracts:
|
||||
return
|
||||
|
||||
cidr_list = []
|
||||
for subnet_id in subnets:
|
||||
subnet = self._core_plugin.get_subnet(context._plugin_context,
|
||||
subnet_id)
|
||||
cidr = subnet['cidr']
|
||||
cidr_list.append(cidr)
|
||||
|
||||
prov_cons = ['providing_cidrs', 'consuming_cidrs']
|
||||
for pos, contracts in enumerate([provided_contracts,
|
||||
consumed_contracts]):
|
||||
for contract_id in contracts:
|
||||
contract = context._plugin.get_contract(
|
||||
context._plugin_context, contract_id)
|
||||
contract_sg_mappings = self._get_contract_sg_mapping(
|
||||
context._plugin_context.session, contract_id)
|
||||
cidr_mapping = {prov_cons[pos]: cidr_list,
|
||||
prov_cons[pos - 1]: []}
|
||||
policy_rules = contract['policy_rules']
|
||||
for policy_rule_id in policy_rules:
|
||||
policy_rule = context._plugin.get_policy_rule(
|
||||
context._plugin_context, policy_rule_id)
|
||||
self._add_or_remove_contract_rule(context, policy_rule,
|
||||
contract_sg_mappings,
|
||||
cidr_mapping)
|
||||
|
||||
def _manage_contract_rules(self, context, contract, policy_rules,
|
||||
unset=False):
|
||||
contract_sg_mappings = self._get_contract_sg_mapping(
|
||||
context._plugin_context.session, contract['id'])
|
||||
contract = context._plugin._get_contract(
|
||||
context._plugin_context, contract['id'])
|
||||
epg_mapping = self._get_contract_epg_mapping(context, contract)
|
||||
cidr_mapping = self._get_epg_cidrs_mapping(context, epg_mapping)
|
||||
for policy_rule_id in policy_rules:
|
||||
policy_rule = context._plugin.get_policy_rule(
|
||||
context._plugin_context, policy_rule_id)
|
||||
|
||||
self._add_or_remove_contract_rule(context, policy_rule,
|
||||
contract_sg_mappings,
|
||||
cidr_mapping, unset=unset)
|
||||
|
||||
def _add_or_remove_contract_rule(self, context, policy_rule,
|
||||
contract_sg_mappings, cidr_mapping,
|
||||
unset=False):
|
||||
in_out = [gconst.GP_DIRECTION_IN, gconst.GP_DIRECTION_OUT]
|
||||
prov_cons = [contract_sg_mappings['provided_sg_id'],
|
||||
contract_sg_mappings['consumed_sg_id']]
|
||||
cidr_prov_cons = [cidr_mapping['providing_cidrs'],
|
||||
cidr_mapping['consuming_cidrs']]
|
||||
|
||||
classifier_id = policy_rule['policy_classifier_id']
|
||||
classifier = context._plugin.get_policy_classifier(
|
||||
context._plugin_context, classifier_id)
|
||||
protocol = classifier['protocol']
|
||||
port_range = classifier['port_range']
|
||||
|
||||
for pos, sg in enumerate(prov_cons):
|
||||
if classifier['direction'] in [gconst.GP_DIRECTION_BI,
|
||||
in_out[pos]]:
|
||||
for cidr in cidr_prov_cons[pos - 1]:
|
||||
self._sg_ingress_rule(context, sg, protocol, port_range,
|
||||
cidr, unset=unset)
|
||||
if classifier['direction'] in [gconst.GP_DIRECTION_BI,
|
||||
in_out[pos - 1]]:
|
||||
self._sg_egress_rule(context, sg, protocol, port_range,
|
||||
'0.0.0.0/0', unset=unset)
|
||||
|
||||
def _apply_contract_rules(self, context, contract, policy_rules):
|
||||
self._manage_contract_rules(context, contract, policy_rules)
|
||||
|
||||
def _remove_contract_rules(self, context, contract, policy_rules):
|
||||
self._manage_contract_rules(context, contract, policy_rules,
|
||||
unset=True)
|
||||
|
||||
def _ensure_default_security_group(self, plugin_context, tenant_id):
|
||||
filters = {'name': ['gbp_default'], 'tenant_id': [tenant_id]}
|
||||
default_group = self._core_plugin.get_security_groups(
|
||||
plugin_context, filters)
|
||||
if not default_group:
|
||||
attrs = {'name': 'gbp_default', 'tenant_id': tenant_id,
|
||||
'description': 'default'}
|
||||
ret = self._create_sg(plugin_context, attrs)
|
||||
return ret['id']
|
||||
else:
|
||||
return default_group[0]['id']
|
||||
|
||||
def _get_contract_epg_mapping(self, context, contract):
|
||||
# REVISIT(ivar): This will be removed once navigability issue is
|
||||
# solved (bug/1384398)
|
||||
return {
|
||||
'providing_epgs': self._get_epgs_by_id(
|
||||
context,
|
||||
[x['endpoint_group_id'] for x in contract.get(
|
||||
'providing_endpoint_groups', [])]),
|
||||
'consuming_epgs': self._get_epgs_by_id(
|
||||
context,
|
||||
[x['endpoint_group_id'] for x in contract.get(
|
||||
'consuming_endpoint_groups', [])])}
|
||||
|
||||
def _get_epgs_by_id(self, context, ids):
|
||||
if ids:
|
||||
filters = {'id': ids}
|
||||
return context._plugin.get_endpoint_groups(context._plugin_context,
|
||||
filters)
|
||||
else:
|
||||
return []
|
||||
|
||||
def _get_epg_cidrs(self, context, epgs):
|
||||
cidrs = []
|
||||
for epg in epgs:
|
||||
cidrs.extend([self._core_plugin.get_subnet(
|
||||
context._plugin_context, x)['cidr'] for x in epg['subnets']])
|
||||
return cidrs
|
||||
|
||||
def _get_epg_cidrs_mapping(self, context, epg_mapping):
|
||||
return {
|
||||
'providing_cidrs': self._get_epg_cidrs(
|
||||
context, epg_mapping['providing_epgs']),
|
||||
'consuming_cidrs': self._get_epg_cidrs(
|
||||
context, epg_mapping['consuming_epgs'])}
|
||||
|
||||
Reference in New Issue
Block a user