diff --git a/gbpservice/neutron/db/grouppolicy/extensions/group_proxy_db.py b/gbpservice/neutron/db/grouppolicy/extensions/group_proxy_db.py index 5e810528a..c96c6d49f 100644 --- a/gbpservice/neutron/db/grouppolicy/extensions/group_proxy_db.py +++ b/gbpservice/neutron/db/grouppolicy/extensions/group_proxy_db.py @@ -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) \ No newline at end of file + 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) diff --git a/gbpservice/neutron/db/grouppolicy/group_policy_db.py b/gbpservice/neutron/db/grouppolicy/group_policy_db.py index 757e3ae5f..25e11d52b 100644 --- a/gbpservice/neutron/db/grouppolicy/group_policy_db.py +++ b/gbpservice/neutron/db/grouppolicy/group_policy_db.py @@ -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." diff --git a/gbpservice/neutron/db/migration/alembic_migrations/versions/acb613677ffa_group_proxy.py b/gbpservice/neutron/db/migration/alembic_migrations/versions/acb613677ffa_group_proxy.py index ea53431c3..1fab7e976 100644 --- a/gbpservice/neutron/db/migration/alembic_migrations/versions/acb613677ffa_group_proxy.py +++ b/gbpservice/neutron/db/migration/alembic_migrations/versions/acb613677ffa_group_proxy.py @@ -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 diff --git a/gbpservice/neutron/extensions/driver_proxy_group.py b/gbpservice/neutron/extensions/driver_proxy_group.py index 526119985..847a65e57 100644 --- a/gbpservice/neutron/extensions/driver_proxy_group.py +++ b/gbpservice/neutron/extensions/driver_proxy_group.py @@ -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": diff --git a/gbpservice/neutron/extensions/group_policy.py b/gbpservice/neutron/extensions/group_policy.py index d4185b98a..adb2bf727 100644 --- a/gbpservice/neutron/extensions/group_policy.py +++ b/gbpservice/neutron/extensions/group_policy.py @@ -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") diff --git a/gbpservice/neutron/services/grouppolicy/drivers/extensions/proxy_group_driver.py b/gbpservice/neutron/services/grouppolicy/drivers/extensions/proxy_group_driver.py index 4e14231ca..172b5fcc5 100644 --- a/gbpservice/neutron/services/grouppolicy/drivers/extensions/proxy_group_driver.py +++ b/gbpservice/neutron/services/grouppolicy/drivers/extensions/proxy_group_driver.py @@ -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) \ No newline at end of file + 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 diff --git a/gbpservice/neutron/services/grouppolicy/extension_manager.py b/gbpservice/neutron/services/grouppolicy/extension_manager.py index d425bac7a..410a06619 100644 --- a/gbpservice/neutron/services/grouppolicy/extension_manager.py +++ b/gbpservice/neutron/services/grouppolicy/extension_manager.py @@ -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( diff --git a/gbpservice/neutron/tests/unit/services/grouppolicy/test_group_proxy_extension.py b/gbpservice/neutron/tests/unit/services/grouppolicy/test_group_proxy_extension.py index 93bb98bd2..e1f77862c 100644 --- a/gbpservice/neutron/tests/unit/services/grouppolicy/test_group_proxy_extension.py +++ b/gbpservice/neutron/tests/unit/services/grouppolicy/test_group_proxy_extension.py @@ -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'])