From 277d89b67a6a8ea4f6a7bc216014d55ace5c1d2d Mon Sep 17 00:00:00 2001 From: Pavel Bondar Date: Tue, 23 Jun 2015 12:07:43 +0300 Subject: [PATCH] Bulk move methods to ipam_backend_mixin.py ipam_backend_mixin contains methods common for both backends: pluggable and non-pluggable, so moving methods to make them accessible by backends. Next methods were moved from db_base_plugin_v2.py to ipam_backend_mixin.py: - _validate_subnet_cidr - _validate_network_subnetpools - _allocate_pools_for_subnet - _save_subnet This commit moves methods without any internal changes. All future changes and decomposition of these methods will be handled in next commits. Partially-Implements: blueprint neutron-ipam Change-Id: I1ec786754467fc9039d2276f084f1bceaab15635 --- neutron/db/db_base_plugin_v2.py | 116 ------------------------------- neutron/db/ipam_backend_mixin.py | 116 +++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+), 116 deletions(-) diff --git a/neutron/db/db_base_plugin_v2.py b/neutron/db/db_base_plugin_v2.py index 42c4eb975..ded63c95e 100644 --- a/neutron/db/db_base_plugin_v2.py +++ b/neutron/db/db_base_plugin_v2.py @@ -97,54 +97,6 @@ class NeutronDbPluginV2(ipam_non_pluggable_backend.IpamNonPluggableBackend, event.listen(models_v2.Port.status, 'set', self.nova_notifier.record_port_status_changed) - def _validate_subnet_cidr(self, context, network, new_subnet_cidr): - """Validate the CIDR for a subnet. - - Verifies the specified CIDR does not overlap with the ones defined - for the other subnets specified for this network, or with any other - CIDR if overlapping IPs are disabled. - """ - new_subnet_ipset = netaddr.IPSet([new_subnet_cidr]) - # Disallow subnets with prefix length 0 as they will lead to - # dnsmasq failures (see bug 1362651). - # This is not a discrimination against /0 subnets. - # A /0 subnet is conceptually possible but hardly a practical - # scenario for neutron's use cases. - for cidr in new_subnet_ipset.iter_cidrs(): - if cidr.prefixlen == 0: - err_msg = _("0 is not allowed as CIDR prefix length") - raise n_exc.InvalidInput(error_message=err_msg) - - if cfg.CONF.allow_overlapping_ips: - subnet_list = network.subnets - else: - subnet_list = self._get_all_subnets(context) - for subnet in subnet_list: - if (netaddr.IPSet([subnet.cidr]) & new_subnet_ipset): - # don't give out details of the overlapping subnet - err_msg = (_("Requested subnet with cidr: %(cidr)s for " - "network: %(network_id)s overlaps with another " - "subnet") % - {'cidr': new_subnet_cidr, - 'network_id': network.id}) - LOG.info(_LI("Validation for CIDR: %(new_cidr)s failed - " - "overlaps with subnet %(subnet_id)s " - "(CIDR: %(cidr)s)"), - {'new_cidr': new_subnet_cidr, - 'subnet_id': subnet.id, - 'cidr': subnet.cidr}) - raise n_exc.InvalidInput(error_message=err_msg) - - def _validate_network_subnetpools(self, network, - new_subnetpool_id, ip_version): - """Validate all subnets on the given network have been allocated from - the same subnet pool as new_subnetpool_id - """ - for subnet in network.subnets: - if (subnet.ip_version == ip_version and - new_subnetpool_id != subnet.subnetpool_id): - raise n_exc.NetworkSubnetPoolAffinityError() - def _validate_host_route(self, route, ip_version): try: netaddr.IPNetwork(route['destination']) @@ -160,32 +112,6 @@ class NeutronDbPluginV2(ipam_non_pluggable_backend.IpamNonPluggableBackend, self._validate_ip_version(ip_version, route['destination'], 'destination') - def _allocate_pools_for_subnet(self, context, subnet): - """Create IP allocation pools for a given subnet - - Pools are defined by the 'allocation_pools' attribute, - a list of dict objects with 'start' and 'end' keys for - defining the pool range. - """ - pools = [] - # Auto allocate the pool around gateway_ip - net = netaddr.IPNetwork(subnet['cidr']) - first_ip = net.first + 1 - last_ip = net.last - 1 - gw_ip = int(netaddr.IPAddress(subnet['gateway_ip'] or net.last)) - # Use the gw_ip to find a point for splitting allocation pools - # for this subnet - split_ip = min(max(gw_ip, net.first), net.last) - if split_ip > first_ip: - pools.append({'start': str(netaddr.IPAddress(first_ip)), - 'end': str(netaddr.IPAddress(split_ip - 1))}) - if split_ip < last_ip: - pools.append({'start': str(netaddr.IPAddress(split_ip + 1)), - 'end': str(netaddr.IPAddress(last_ip))}) - # return auto-generated pools - # no need to check for their validity - return pools - def _validate_shared_update(self, context, id, original, updated): # The only case that needs to be validated is when 'shared' # goes from True to False @@ -514,48 +440,6 @@ class NeutronDbPluginV2(ipam_non_pluggable_backend.IpamNonPluggableBackend, external_gateway_info}} l3plugin.update_router(context, id, info) - def _save_subnet(self, context, - network, - subnet_args, - dns_nameservers, - host_routes, - allocation_pools): - - if not attributes.is_attr_set(allocation_pools): - allocation_pools = self._allocate_pools_for_subnet(context, - subnet_args) - else: - self._validate_allocation_pools(allocation_pools, - subnet_args['cidr']) - if subnet_args['gateway_ip']: - self._validate_gw_out_of_pools(subnet_args['gateway_ip'], - allocation_pools) - - self._validate_subnet_cidr(context, network, subnet_args['cidr']) - self._validate_network_subnetpools(network, - subnet_args['subnetpool_id'], - subnet_args['ip_version']) - - subnet = models_v2.Subnet(**subnet_args) - context.session.add(subnet) - if attributes.is_attr_set(dns_nameservers): - for addr in dns_nameservers: - ns = models_v2.DNSNameServer(address=addr, - subnet_id=subnet.id) - context.session.add(ns) - - if attributes.is_attr_set(host_routes): - for rt in host_routes: - route = models_v2.SubnetRoute( - subnet_id=subnet.id, - destination=rt['destination'], - nexthop=rt['nexthop']) - context.session.add(route) - - self._save_allocation_pools(context, subnet, allocation_pools) - - return subnet - def _make_subnet_request(self, tenant_id, subnet, subnetpool): cidr = subnet.get('cidr') subnet_id = subnet.get('id', uuidutils.generate_uuid()) diff --git a/neutron/db/ipam_backend_mixin.py b/neutron/db/ipam_backend_mixin.py index 47c8141d8..af0833014 100644 --- a/neutron/db/ipam_backend_mixin.py +++ b/neutron/db/ipam_backend_mixin.py @@ -167,6 +167,80 @@ class IpamBackendMixin(db_base_plugin_common.DbBasePluginCommon): subnet.update(s) return subnet, changes + def _allocate_pools_for_subnet(self, context, subnet): + """Create IP allocation pools for a given subnet + + Pools are defined by the 'allocation_pools' attribute, + a list of dict objects with 'start' and 'end' keys for + defining the pool range. + """ + pools = [] + # Auto allocate the pool around gateway_ip + net = netaddr.IPNetwork(subnet['cidr']) + first_ip = net.first + 1 + last_ip = net.last - 1 + gw_ip = int(netaddr.IPAddress(subnet['gateway_ip'] or net.last)) + # Use the gw_ip to find a point for splitting allocation pools + # for this subnet + split_ip = min(max(gw_ip, net.first), net.last) + if split_ip > first_ip: + pools.append({'start': str(netaddr.IPAddress(first_ip)), + 'end': str(netaddr.IPAddress(split_ip - 1))}) + if split_ip < last_ip: + pools.append({'start': str(netaddr.IPAddress(split_ip + 1)), + 'end': str(netaddr.IPAddress(last_ip))}) + # return auto-generated pools + # no need to check for their validity + return pools + + def _validate_subnet_cidr(self, context, network, new_subnet_cidr): + """Validate the CIDR for a subnet. + + Verifies the specified CIDR does not overlap with the ones defined + for the other subnets specified for this network, or with any other + CIDR if overlapping IPs are disabled. + """ + new_subnet_ipset = netaddr.IPSet([new_subnet_cidr]) + # Disallow subnets with prefix length 0 as they will lead to + # dnsmasq failures (see bug 1362651). + # This is not a discrimination against /0 subnets. + # A /0 subnet is conceptually possible but hardly a practical + # scenario for neutron's use cases. + for cidr in new_subnet_ipset.iter_cidrs(): + if cidr.prefixlen == 0: + err_msg = _("0 is not allowed as CIDR prefix length") + raise n_exc.InvalidInput(error_message=err_msg) + + if cfg.CONF.allow_overlapping_ips: + subnet_list = network.subnets + else: + subnet_list = self._get_all_subnets(context) + for subnet in subnet_list: + if (netaddr.IPSet([subnet.cidr]) & new_subnet_ipset): + # don't give out details of the overlapping subnet + err_msg = (_("Requested subnet with cidr: %(cidr)s for " + "network: %(network_id)s overlaps with another " + "subnet") % + {'cidr': new_subnet_cidr, + 'network_id': network.id}) + LOG.info(_LI("Validation for CIDR: %(new_cidr)s failed - " + "overlaps with subnet %(subnet_id)s " + "(CIDR: %(cidr)s)"), + {'new_cidr': new_subnet_cidr, + 'subnet_id': subnet.id, + 'cidr': subnet.cidr}) + raise n_exc.InvalidInput(error_message=err_msg) + + def _validate_network_subnetpools(self, network, + new_subnetpool_id, ip_version): + """Validate all subnets on the given network have been allocated from + the same subnet pool as new_subnetpool_id + """ + for subnet in network.subnets: + if (subnet.ip_version == ip_version and + new_subnetpool_id != subnet.subnetpool_id): + raise n_exc.NetworkSubnetPoolAffinityError() + def _validate_allocation_pools(self, ip_pools, subnet_cidr): """Validate IP allocation pools. @@ -283,3 +357,45 @@ class IpamBackendMixin(db_base_plugin_common.DbBasePluginCommon): if not context.is_admin: query = query.filter_by(tenant_id=context.tenant_id) query.delete() + + def _save_subnet(self, context, + network, + subnet_args, + dns_nameservers, + host_routes, + allocation_pools): + + if not attributes.is_attr_set(allocation_pools): + allocation_pools = self._allocate_pools_for_subnet(context, + subnet_args) + else: + self._validate_allocation_pools(allocation_pools, + subnet_args['cidr']) + if subnet_args['gateway_ip']: + self._validate_gw_out_of_pools(subnet_args['gateway_ip'], + allocation_pools) + + self._validate_subnet_cidr(context, network, subnet_args['cidr']) + self._validate_network_subnetpools(network, + subnet_args['subnetpool_id'], + subnet_args['ip_version']) + + subnet = models_v2.Subnet(**subnet_args) + context.session.add(subnet) + if attributes.is_attr_set(dns_nameservers): + for addr in dns_nameservers: + ns = models_v2.DNSNameServer(address=addr, + subnet_id=subnet.id) + context.session.add(ns) + + if attributes.is_attr_set(host_routes): + for rt in host_routes: + route = models_v2.SubnetRoute( + subnet_id=subnet.id, + destination=rt['destination'], + nexthop=rt['nexthop']) + context.session.add(route) + + self._save_allocation_pools(context, subnet, allocation_pools) + + return subnet -- 2.45.2