Merge "Replace subnetpool config options with admin-only API"
This commit is contained in:
commit
772b3e3df3
@ -162,12 +162,16 @@
|
||||
# CIDR must be passed to create a subnet and that subnet will not be allocated
|
||||
# from any pool; it will be considered part of the tenant's private address
|
||||
# space.
|
||||
# This option is deprecated for removal in the N release. Please refrain from
|
||||
# using it.
|
||||
# default_ipv4_subnet_pool =
|
||||
|
||||
# Default Subnet Pool to be used for IPv6 subnet-allocation.
|
||||
# Specifies by UUID the pool to be used in case of subnet-create being
|
||||
# called without a subnet-pool ID. See the description for
|
||||
# default_ipv4_subnet_pool for more information.
|
||||
# This option is deprecated for removal in the N release. Please refrain from
|
||||
# using it.
|
||||
# default_ipv6_subnet_pool =
|
||||
|
||||
# Set to True to enable IPv6 Prefix Delegation for subnet-allocation in a
|
||||
|
@ -22,8 +22,10 @@
|
||||
|
||||
"create_subnetpool": "",
|
||||
"create_subnetpool:shared": "rule:admin_only",
|
||||
"create_subnetpool:is_default": "rule:admin_only",
|
||||
"get_subnetpool": "rule:admin_or_owner or rule:shared_subnetpools",
|
||||
"update_subnetpool": "rule:admin_or_owner",
|
||||
"update_subnetpool:is_default": "rule:admin_only",
|
||||
"delete_subnetpool": "rule:admin_or_owner",
|
||||
|
||||
"create_address_scope": "",
|
||||
|
@ -864,6 +864,13 @@ RESOURCE_ATTRIBUTE_MAP = {
|
||||
'validate': {'type:non_negative': None},
|
||||
'convert_to': convert_to_int,
|
||||
'is_visible': True},
|
||||
'is_default': {'allow_post': True,
|
||||
'allow_put': True,
|
||||
'default': False,
|
||||
'convert_to': convert_to_boolean,
|
||||
'is_visible': True,
|
||||
'required_by_policy': True,
|
||||
'enforce_policy': True},
|
||||
SHARED: {'allow_post': True,
|
||||
'allow_put': False,
|
||||
'default': False,
|
||||
|
@ -72,12 +72,14 @@ core_opts = [
|
||||
help=_("Maximum number of fixed ips per port. This option "
|
||||
"is deprecated and will be removed in the N "
|
||||
"release.")),
|
||||
cfg.StrOpt('default_ipv4_subnet_pool',
|
||||
cfg.StrOpt('default_ipv4_subnet_pool', deprecated_for_removal=True,
|
||||
help=_("Default IPv4 subnet-pool to be used for automatic "
|
||||
"subnet CIDR allocation")),
|
||||
cfg.StrOpt('default_ipv6_subnet_pool',
|
||||
"subnet CIDR allocation. This option is deprecated for "
|
||||
"removal in the N release.")),
|
||||
cfg.StrOpt('default_ipv6_subnet_pool', deprecated_for_removal=True,
|
||||
help=_("Default IPv6 subnet-pool to be used for automatic "
|
||||
"subnet CIDR allocation")),
|
||||
"subnet CIDR allocation. This option is deprecated for "
|
||||
"removal in the N release.")),
|
||||
cfg.BoolOpt('ipv6_pd_enabled', default=False,
|
||||
help=_("Enables IPv6 Prefix Delegation for automatic subnet "
|
||||
"CIDR allocation")),
|
||||
|
@ -146,6 +146,7 @@ class DbBasePluginCommon(common_db_mixin.CommonDbMixin):
|
||||
'default_prefixlen': default_prefixlen,
|
||||
'min_prefixlen': min_prefixlen,
|
||||
'max_prefixlen': max_prefixlen,
|
||||
'is_default': subnetpool['is_default'],
|
||||
'shared': subnetpool['shared'],
|
||||
'prefixes': [prefix['cidr']
|
||||
for prefix in subnetpool['prefixes']],
|
||||
|
@ -601,7 +601,7 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon,
|
||||
ipam_subnet)
|
||||
return self._make_subnet_dict(subnet, context=context)
|
||||
|
||||
def _get_subnetpool_id(self, subnet):
|
||||
def _get_subnetpool_id(self, context, subnet):
|
||||
"""Returns the subnetpool id for this request
|
||||
|
||||
If the pool id was explicitly set in the request then that will be
|
||||
@ -630,10 +630,18 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon,
|
||||
'cidr and subnetpool_id')
|
||||
raise n_exc.BadRequest(resource='subnets', msg=msg)
|
||||
|
||||
if ip_version == 6 and cfg.CONF.ipv6_pd_enabled:
|
||||
return constants.IPV6_PD_POOL_ID
|
||||
|
||||
subnetpool = self.get_default_subnetpool(context, ip_version)
|
||||
if subnetpool:
|
||||
return subnetpool['id']
|
||||
|
||||
# Until the default_subnet_pool config options are removed in the N
|
||||
# release, check for them after get_default_subnetpool returns None.
|
||||
# TODO(john-davidge): Remove after Mitaka release.
|
||||
if ip_version == 4:
|
||||
return cfg.CONF.default_ipv4_subnet_pool
|
||||
if cfg.CONF.ipv6_pd_enabled:
|
||||
return constants.IPV6_PD_POOL_ID
|
||||
return cfg.CONF.default_ipv6_subnet_pool
|
||||
|
||||
def create_subnet(self, context, subnet):
|
||||
@ -654,7 +662,7 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon,
|
||||
subnet['subnet']['cidr'] = '%s/%s' % (net.network, net.prefixlen)
|
||||
|
||||
s['tenant_id'] = self._get_tenant_id_for_create(context, s)
|
||||
subnetpool_id = self._get_subnetpool_id(s)
|
||||
subnetpool_id = self._get_subnetpool_id(context, s)
|
||||
if subnetpool_id:
|
||||
self.ipam.validate_pools_with_subnetpool(s)
|
||||
if subnetpool_id == constants.IPV6_PD_POOL_ID:
|
||||
@ -929,6 +937,17 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon,
|
||||
'address_scope_id': address_scope_id}
|
||||
raise n_exc.IllegalSubnetPoolUpdate(reason=msg)
|
||||
|
||||
def _check_default_subnetpool_exists(self, context, ip_version):
|
||||
"""Check if a default already exists for the given IP version.
|
||||
|
||||
There can only be one default subnetpool for each IP family. Raise an
|
||||
InvalidInput error if a default has already been set.
|
||||
"""
|
||||
if self.get_default_subnetpool(context, ip_version):
|
||||
msg = _("A default subnetpool for this IP family has already "
|
||||
"been set. Only one default may exist per IP family")
|
||||
raise n_exc.InvalidInput(error_message=msg)
|
||||
|
||||
def create_subnetpool(self, context, subnetpool):
|
||||
"""Create a subnetpool"""
|
||||
|
||||
@ -936,6 +955,9 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon,
|
||||
sp_reader = subnet_alloc.SubnetPoolReader(sp)
|
||||
if sp_reader.address_scope_id is attributes.ATTR_NOT_SPECIFIED:
|
||||
sp_reader.address_scope_id = None
|
||||
if sp_reader.is_default:
|
||||
self._check_default_subnetpool_exists(context,
|
||||
sp_reader.ip_version)
|
||||
self._validate_address_scope_id(context, sp_reader.address_scope_id,
|
||||
id, sp_reader.prefixes)
|
||||
tenant_id = self._get_tenant_id_for_create(context, sp)
|
||||
@ -948,6 +970,7 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon,
|
||||
sp_reader.default_prefixlen,
|
||||
'min_prefixlen': sp_reader.min_prefixlen,
|
||||
'max_prefixlen': sp_reader.max_prefixlen,
|
||||
'is_default': sp_reader.is_default,
|
||||
'shared': sp_reader.shared,
|
||||
'default_quota': sp_reader.default_quota,
|
||||
'address_scope_id': sp_reader.address_scope_id}
|
||||
@ -986,8 +1009,8 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon,
|
||||
updated['prefixes'] = orig_prefixes
|
||||
|
||||
for key in ['id', 'name', 'ip_version', 'min_prefixlen',
|
||||
'max_prefixlen', 'default_prefixlen', 'shared',
|
||||
'default_quota', 'address_scope_id']:
|
||||
'max_prefixlen', 'default_prefixlen', 'is_default',
|
||||
'shared', 'default_quota', 'address_scope_id']:
|
||||
self._write_key(key, updated, model, new_pool)
|
||||
|
||||
return updated
|
||||
@ -1008,6 +1031,9 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon,
|
||||
updated = self._updated_subnetpool_dict(orig_sp, new_sp)
|
||||
updated['tenant_id'] = orig_sp.tenant_id
|
||||
reader = subnet_alloc.SubnetPoolReader(updated)
|
||||
if reader.is_default and not orig_sp.is_default:
|
||||
self._check_default_subnetpool_exists(context,
|
||||
reader.ip_version)
|
||||
if orig_sp.address_scope_id:
|
||||
self._check_subnetpool_update_allowed(context, id,
|
||||
orig_sp.address_scope_id)
|
||||
@ -1044,6 +1070,14 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon,
|
||||
page_reverse=page_reverse)
|
||||
return collection
|
||||
|
||||
def get_default_subnetpool(self, context, ip_version):
|
||||
"""Retrieve the default subnetpool for the given IP version."""
|
||||
filters = {'is_default': [True],
|
||||
'ip_version': [ip_version]}
|
||||
subnetpool = self.get_subnetpools(context, filters=filters)
|
||||
if subnetpool:
|
||||
return subnetpool[0]
|
||||
|
||||
def delete_subnetpool(self, context, id):
|
||||
"""Delete a subnetpool."""
|
||||
with context.session.begin(subtransactions=True):
|
||||
|
@ -1 +1 @@
|
||||
59cb5b6cf4d
|
||||
13cfb89f881a
|
||||
|
@ -0,0 +1,36 @@
|
||||
# Copyright 2015 Cisco Systems
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
"""add is_default to subnetpool
|
||||
|
||||
Revision ID: 13cfb89f881a
|
||||
Revises: 59cb5b6cf4d
|
||||
Create Date: 2015-09-30 15:58:31.170153
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '13cfb89f881a'
|
||||
down_revision = '59cb5b6cf4d'
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
def upgrade():
|
||||
op.add_column('subnetpools',
|
||||
sa.Column('is_default',
|
||||
sa.Boolean(),
|
||||
nullable=False))
|
@ -236,6 +236,7 @@ class SubnetPool(model_base.BASEV2, HasId, HasTenant):
|
||||
min_prefixlen = sa.Column(sa.Integer, nullable=False)
|
||||
max_prefixlen = sa.Column(sa.Integer, nullable=False)
|
||||
shared = sa.Column(sa.Boolean, nullable=False)
|
||||
is_default = sa.Column(sa.Boolean, nullable=False)
|
||||
default_quota = sa.Column(sa.Integer, nullable=True)
|
||||
hash = sa.Column(sa.String(36), nullable=False, server_default='')
|
||||
address_scope_id = sa.Column(sa.String(36), nullable=True)
|
||||
|
@ -226,7 +226,7 @@ class SubnetPoolReader(object):
|
||||
self._read_id(subnetpool)
|
||||
self._read_prefix_bounds(subnetpool)
|
||||
self._read_attrs(subnetpool,
|
||||
['tenant_id', 'name', 'shared'])
|
||||
['tenant_id', 'name', 'is_default', 'shared'])
|
||||
self._read_address_scope(subnetpool)
|
||||
self.subnetpool = {'id': self.id,
|
||||
'name': self.name,
|
||||
@ -240,6 +240,7 @@ class SubnetPoolReader(object):
|
||||
'default_prefixlen': self.default_prefixlen,
|
||||
'default_quota': self.default_quota,
|
||||
'address_scope_id': self.address_scope_id,
|
||||
'is_default': self.is_default,
|
||||
'shared': self.shared}
|
||||
|
||||
def _read_attrs(self, subnetpool, keys):
|
||||
|
@ -22,8 +22,10 @@
|
||||
|
||||
"create_subnetpool": "",
|
||||
"create_subnetpool:shared": "rule:admin_only",
|
||||
"create_subnetpool:is_default": "rule:admin_only",
|
||||
"get_subnetpool": "rule:admin_or_owner or rule:shared_subnetpools",
|
||||
"update_subnetpool": "rule:admin_or_owner",
|
||||
"update_subnetpool:is_default": "rule:admin_only",
|
||||
"delete_subnetpool": "rule:admin_or_owner",
|
||||
|
||||
"create_address_scope": "",
|
||||
|
@ -2823,6 +2823,30 @@ class TestSubnetsV2(NeutronDbPluginV2TestCase):
|
||||
self.assertEqual(res.status_int, webob.exc.HTTPClientError.code)
|
||||
|
||||
def test_create_subnet_only_ip_version_v4(self):
|
||||
with self.network() as network:
|
||||
tenant_id = network['network']['tenant_id']
|
||||
subnetpool_prefix = '10.0.0.0/8'
|
||||
with self.subnetpool(prefixes=[subnetpool_prefix],
|
||||
admin=True,
|
||||
name="My subnet pool",
|
||||
tenant_id=tenant_id,
|
||||
min_prefixlen='25',
|
||||
is_default=True) as subnetpool:
|
||||
subnetpool_id = subnetpool['subnetpool']['id']
|
||||
data = {'subnet': {'network_id': network['network']['id'],
|
||||
'ip_version': '4',
|
||||
'prefixlen': '27',
|
||||
'tenant_id': tenant_id}}
|
||||
subnet_req = self.new_create_request('subnets', data)
|
||||
res = subnet_req.get_response(self.api)
|
||||
subnet = self.deserialize(self.fmt, res)['subnet']
|
||||
ip_net = netaddr.IPNetwork(subnet['cidr'])
|
||||
self.assertIn(ip_net, netaddr.IPNetwork(subnetpool_prefix))
|
||||
self.assertEqual(27, ip_net.prefixlen)
|
||||
self.assertEqual(subnetpool_id, subnet['subnetpool_id'])
|
||||
|
||||
def test_create_subnet_only_ip_version_v4_old(self):
|
||||
# TODO(john-davidge): Remove after Mitaka release.
|
||||
with self.network() as network:
|
||||
tenant_id = network['network']['tenant_id']
|
||||
subnetpool_prefix = '10.0.0.0/8'
|
||||
@ -2847,6 +2871,30 @@ class TestSubnetsV2(NeutronDbPluginV2TestCase):
|
||||
self.assertEqual(subnetpool_id, subnet['subnetpool_id'])
|
||||
|
||||
def test_create_subnet_only_ip_version_v6(self):
|
||||
with self.network() as network:
|
||||
tenant_id = network['network']['tenant_id']
|
||||
subnetpool_prefix = '2000::/56'
|
||||
with self.subnetpool(prefixes=[subnetpool_prefix],
|
||||
admin=True,
|
||||
name="My ipv6 subnet pool",
|
||||
tenant_id=tenant_id,
|
||||
min_prefixlen='64',
|
||||
is_default=True) as subnetpool:
|
||||
subnetpool_id = subnetpool['subnetpool']['id']
|
||||
cfg.CONF.set_override('ipv6_pd_enabled', False)
|
||||
data = {'subnet': {'network_id': network['network']['id'],
|
||||
'ip_version': '6',
|
||||
'tenant_id': tenant_id}}
|
||||
subnet_req = self.new_create_request('subnets', data)
|
||||
res = subnet_req.get_response(self.api)
|
||||
subnet = self.deserialize(self.fmt, res)['subnet']
|
||||
self.assertEqual(subnetpool_id, subnet['subnetpool_id'])
|
||||
ip_net = netaddr.IPNetwork(subnet['cidr'])
|
||||
self.assertIn(ip_net, netaddr.IPNetwork(subnetpool_prefix))
|
||||
self.assertEqual(64, ip_net.prefixlen)
|
||||
|
||||
def test_create_subnet_only_ip_version_v6_old(self):
|
||||
# TODO(john-davidge): Remove after Mitaka release.
|
||||
with self.network() as network:
|
||||
tenant_id = network['network']['tenant_id']
|
||||
subnetpool_prefix = '2000::/56'
|
||||
@ -2856,9 +2904,9 @@ class TestSubnetsV2(NeutronDbPluginV2TestCase):
|
||||
tenant_id=tenant_id,
|
||||
min_prefixlen='64') as subnetpool:
|
||||
subnetpool_id = subnetpool['subnetpool']['id']
|
||||
cfg.CONF.set_override('ipv6_pd_enabled', False)
|
||||
cfg.CONF.set_override('default_ipv6_subnet_pool',
|
||||
subnetpool_id)
|
||||
cfg.CONF.set_override('ipv6_pd_enabled', False)
|
||||
data = {'subnet': {'network_id': network['network']['id'],
|
||||
'ip_version': '6',
|
||||
'tenant_id': tenant_id}}
|
||||
@ -4858,6 +4906,9 @@ class TestSubnetPoolsV2(NeutronDbPluginV2TestCase):
|
||||
def _validate_max_prefix(self, prefix, subnetpool):
|
||||
self.assertEqual(subnetpool['subnetpool']['max_prefixlen'], prefix)
|
||||
|
||||
def _validate_is_default(self, subnetpool):
|
||||
self.assertTrue(subnetpool['subnetpool']['is_default'])
|
||||
|
||||
def test_create_subnetpool_empty_prefix_list(self):
|
||||
self.assertRaises(webob.exc.HTTPClientError,
|
||||
self._test_create_subnetpool,
|
||||
@ -4866,6 +4917,38 @@ class TestSubnetPoolsV2(NeutronDbPluginV2TestCase):
|
||||
tenant_id=self._tenant_id,
|
||||
min_prefixlen='21')
|
||||
|
||||
def test_create_default_subnetpools(self):
|
||||
for cidr, min_prefixlen in (['fe80::/48', '64'],
|
||||
['10.10.10.0/24', '24']):
|
||||
pool = self._test_create_subnetpool([cidr],
|
||||
admin=True,
|
||||
tenant_id=self._tenant_id,
|
||||
name=self._POOL_NAME,
|
||||
min_prefixlen=min_prefixlen,
|
||||
is_default=True)
|
||||
self._validate_is_default(pool)
|
||||
|
||||
def test_cannot_create_multiple_default_subnetpools(self):
|
||||
for cidr1, cidr2, min_prefixlen in (['fe80::/48', '2001::/48', '64'],
|
||||
['10.10.10.0/24', '10.10.20.0/24',
|
||||
'24']):
|
||||
|
||||
pool = self._test_create_subnetpool([cidr1],
|
||||
admin=True,
|
||||
tenant_id=self._tenant_id,
|
||||
name=self._POOL_NAME,
|
||||
min_prefixlen=min_prefixlen,
|
||||
is_default=True)
|
||||
self._validate_is_default(pool)
|
||||
self.assertRaises(webob.exc.HTTPClientError,
|
||||
self._test_create_subnetpool,
|
||||
[cidr2],
|
||||
admin=True,
|
||||
tenant_id=self._tenant_id,
|
||||
name=self._POOL_NAME,
|
||||
min_prefixlen=min_prefixlen,
|
||||
is_default=True)
|
||||
|
||||
def test_create_subnetpool_ipv4_24_with_defaults(self):
|
||||
subnet = netaddr.IPNetwork('10.10.10.0/24')
|
||||
subnetpool = self._test_create_subnetpool([subnet.cidr],
|
||||
|
@ -43,7 +43,7 @@ class TestSubnetAllocation(testlib_api.SqlTestCase):
|
||||
max_prefixlen=attributes.ATTR_NOT_SPECIFIED,
|
||||
default_prefixlen=attributes.ATTR_NOT_SPECIFIED,
|
||||
default_quota=attributes.ATTR_NOT_SPECIFIED,
|
||||
shared=False):
|
||||
shared=False, is_default=False):
|
||||
subnetpool = {'subnetpool': {'name': name,
|
||||
'tenant_id': self._tenant_id,
|
||||
'prefixes': prefix_list,
|
||||
@ -51,6 +51,7 @@ class TestSubnetAllocation(testlib_api.SqlTestCase):
|
||||
'max_prefixlen': max_prefixlen,
|
||||
'default_prefixlen': default_prefixlen,
|
||||
'shared': shared,
|
||||
'is_default': is_default,
|
||||
'default_quota': default_quota}}
|
||||
return plugin.create_subnetpool(ctx, subnetpool)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user