add proxy ip pool to proxy group extension

As part of the proxy group extension, a new proxy_ip_pool attribute
is added to the L3Policy object. This attribute defines the pool
from which proxy PTG subnets should be generated.

Partially implements blueprint node-centric-chain-plugin

Change-Id: I65f35457f2cc229999fe197a46e4ee4191f59eeb
This commit is contained in:
Ivar Lazzaro 2015-08-03 15:01:38 -07:00
parent 090f94a381
commit a08befaf87
8 changed files with 108 additions and 7 deletions

View File

@ -36,4 +36,14 @@ class ProxyGatewayMapping(model_base.BASEV2):
sa.String(36), sa.ForeignKey('gp_policy_targets.id',
ondelete="CASCADE"), primary_key=True)
proxy_gateway = sa.Column(sa.Boolean, nullable=False)
group_default_gateway = sa.Column(sa.Boolean, nullable=False)
group_default_gateway = sa.Column(sa.Boolean, nullable=False)
class ProxyIPPoolMapping(model_base.BASEV2):
__tablename__ = 'gp_proxy_ip_pool_mapping'
l3_policy_id = sa.Column(
sa.String(36), sa.ForeignKey('gp_l3_policies.id', ondelete="CASCADE"),
primary_key=True)
proxy_ip_pool = sa.Column(sa.String(64), nullable=False)
proxy_subnet_prefix_length = sa.Column(sa.Integer, nullable=False)

View File

@ -1087,11 +1087,14 @@ class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
@staticmethod
def validate_ip_pool(ip_pool, ip_version):
attr._validate_subnet(ip_pool)
ip_net = netaddr.IPNetwork(ip_pool, version=ip_version)
ip_net = netaddr.IPNetwork(ip_pool)
if ip_net.version != ip_version:
raise gpolicy.InvalidIpPoolVersion(ip_pool=ip_pool,
version=ip_version)
if (ip_net.size <= 3):
err_msg = "Too few available IPs in the pool."
raise gpolicy.InvalidIpPoolSize(ip_pool=ip_pool, err_msg=err_msg,
size=ip_net.size)
size=ip_net.size)
if (ip_net.prefixlen == 0):
err_msg = "Prefix length of 0 is invalid."

View File

@ -59,6 +59,18 @@ def upgrade():
name='group_proxy_mapping_fk_ptg_id'),
)
op.create_table(
'gp_proxy_ip_pool_mapping',
sa.Column('l3_policy_id', sa.String(length=36), nullable=False),
sa.Column('proxy_ip_pool', sa.String(length=64), nullable=False),
sa.Column('proxy_subnet_prefix_length', sa.Integer, nullable=False),
sa.PrimaryKeyConstraint('l3_policy_id'),
sa.ForeignKeyConstraint(['l3_policy_id'], ['gp_l3_policies.id'],
ondelete='CASCADE',
name='proxy_ip_pool_mapping_fk_l3_policy_id'),
)
def downgrade():
pass

View File

@ -54,6 +54,20 @@ EXTENDED_ATTRIBUTES_2_0 = {
'allow_post': False, 'allow_put': False,
'validate': {'type:uuid_or_none': None}, 'is_visible': True,
'enforce_policy': True},
# TODO(ivar): The APIs should allow the creation of a group with a
# custom subnet prefix length. It may be useful for both the proxy
# groups and traditional ones.
},
gp.L3_POLICIES: {
'proxy_ip_pool': {'allow_post': True, 'allow_put': False,
'validate': {'type:subnet': None},
'default': '192.168.0.0/16', 'is_visible': True},
'proxy_subnet_prefix_length': {'allow_post': True, 'allow_put': True,
'convert_to': attr.convert_to_int,
# for ipv4 legal values are 2 to 30
# for ipv6 legal values are 2 to 127
'default': 29, 'is_visible': True},
# Proxy IP version is the same as the standard L3 pool ip version
},
gp.POLICY_TARGETS: {
# This policy target will be used to reach the -proxied- PTG
@ -94,7 +108,7 @@ class Driver_proxy_group(extensions.ExtensionDescriptor):
@classmethod
def get_updated(cls):
return "2015-07-31T10:00:00-00:00"
return "2015-08-03T10:00:00-00:00"
def get_extended_resources(self, version):
if version == "2.0":

View File

@ -92,7 +92,7 @@ class NetworkServicePolicyNotFound(nexc.NotFound):
class InvalidDefaultSubnetPrefixLength(nexc.InvalidInput):
message = _("Default subnet prefix length %(length)s is invalid for"
message = _("Default subnet prefix length %(length)s is invalid for "
"ipv%(protocol)s")
@ -111,6 +111,10 @@ class InvalidIpPoolPrefixLength(nexc.InvalidInput):
"Prefix Length=%(prefixlen)s")
class InvalidIpPoolVersion(nexc.InvalidInput):
message = _("%(ip_pool)s is not a ipv%(version)s address.")
class PolicyClassifierNotFound(nexc.NotFound):
message = _("PolicyClassifier %(policy_classifier_id)s could not be found")

View File

@ -14,6 +14,7 @@ from neutron.api.v2 import attributes
from oslo_log import log as logging
from gbpservice.neutron.db.grouppolicy.extensions import group_proxy_db as db
from gbpservice.neutron.db.grouppolicy import group_policy_db as gp_db
from gbpservice.neutron.extensions import driver_proxy_group
from gbpservice.neutron.services.grouppolicy import (
group_policy_driver_api as api)
@ -90,4 +91,25 @@ class ProxyGroupDriver(api.ExtensionDriver):
if not record:
# The group of this PT is not a proxy
raise driver_proxy_group.InvalidProxyGatewayGroup(
group_id=ptg_id)
group_id=ptg_id)
@api.default_extension_behavior(db.ProxyIPPoolMapping)
def process_create_l3_policy(self, session, data, result):
data = data['l3_policy']
gp_db.GroupPolicyDbPlugin.validate_ip_pool(
data['proxy_ip_pool'], data['ip_version'])
gp_db.GroupPolicyDbPlugin.validate_subnet_prefix_length(
data['ip_version'], data['proxy_subnet_prefix_length'],
data['proxy_ip_pool'])
@api.default_extension_behavior(db.ProxyIPPoolMapping)
def process_update_l3_policy(self, session, data, result):
data = data['l3_policy']
if 'proxy_subnet_prefix_length' in data:
gp_db.GroupPolicyDbPlugin.validate_subnet_prefix_length(
result['ip_version'], data['proxy_subnet_prefix_length'],
result['proxy_ip_pool'])
@api.default_extension_behavior(db.ProxyIPPoolMapping)
def extend_l3_policy_dict(self, session, result):
pass

View File

@ -72,6 +72,7 @@ class ExtensionManager(stevedore.named.NamedExtensionManager):
try:
getattr(driver.obj, method_name)(session, data, result)
except (gp_exc.GroupPolicyException, n_exc.NeutronException):
# This is an exception for the user.
raise
except Exception:
LOG.exception(

View File

@ -24,11 +24,22 @@ class ExtensionDriverTestCase(test_ext_base.ExtensionDriverTestBase):
_extension_path = None
def test_proxy_group_extension(self):
ptg = self.create_policy_target_group()['policy_target_group']
l3p = self.create_l3_policy()['l3_policy']
self.assertEqual('192.168.0.0/16', l3p['proxy_ip_pool'])
self.assertEqual(29, l3p['proxy_subnet_prefix_length'])
l2p = self.create_l2_policy(l3_policy_id=l3p['id'])['l2_policy']
ptg = self.create_policy_target_group(
l2_policy_id=l2p['id'])['policy_target_group']
self.assertIsNone(ptg['proxy_group_id'])
self.assertIsNone(ptg['proxied_group_id'])
self.assertIsNone(ptg['proxy_type'])
# Verify Default L3P pool mapping on show
l3p = self.show_l3_policy(l3p['id'])['l3_policy']
self.assertEqual('192.168.0.0/16', l3p['proxy_ip_pool'])
self.assertEqual(29, l3p['proxy_subnet_prefix_length'])
ptg_proxy = self.create_policy_target_group(
proxied_group_id=ptg['id'])['policy_target_group']
self.assertIsNone(ptg_proxy['proxy_group_id'])
@ -141,3 +152,27 @@ class ExtensionDriverTestCase(test_ext_base.ExtensionDriverTestBase):
expected_res_status=400)
self.assertEqual('InvalidProxyGatewayGroup',
res['NeutronError']['type'])
def test_proxy_pool_invalid_prefix_length(self):
l3p = self.create_l3_policy(proxy_subnet_prefix_length=29)['l3_policy']
res = self.update_l3_policy(l3p['id'], proxy_subnet_prefix_length=32,
expected_res_status=400)
self.assertEqual('InvalidDefaultSubnetPrefixLength',
res['NeutronError']['type'])
# Verify change didn't persist
l3p = self.show_l3_policy(l3p['id'])['l3_policy']
self.assertEqual(29, l3p['proxy_subnet_prefix_length'])
# Verify it fails in creation
res = self.create_l3_policy(
proxy_subnet_prefix_length=32, expected_res_status=400)
self.assertEqual('InvalidDefaultSubnetPrefixLength',
res['NeutronError']['type'])
def test_proxy_pool_invalid_version(self):
# proxy_ip_pool is of a different version
res = self.create_l3_policy(ip_version=6, ip_pool='1::1/16',
proxy_ip_pool='192.168.0.0/16',
expected_res_status=400)
self.assertEqual('InvalidIpPoolVersion', res['NeutronError']['type'])