将 subnetpool 数据库的记录转化为一个对象 NeutronDbPool
,类似于 Neutron 的 object 一样。
neutron/ipam/driver.py
neutron/ipam/drivers/neutrondb_ipam/driver.py
@six.add_metaclass(abc.ABCMeta)
class Pool(object)
这个类定义了一系列的抽象方法:allocate_subnet
、get_subnet
、update_subnet
、remove_subnet
、get_allocator
,这些方法都要在其子类中实现。
def __init__(self, subnetpool, context):
"""Initialize pool
:param subnetpool: SubnetPool of the address space to use.
:type subnetpool: dict
"""
self._subnetpool = subnetpool
self._context = context
即在 ipam 的实现驱动,该驱动在 /etc/neutron/neutron.conf 中定义 ipam_driver
# Neutron IPAM (IP address management) driver to use. By default, the reference
# implementation of the Neutron IPAM driver is used. (string value)
#ipam_driver = internal
在 setup.cfg 中:
neutron.ipam_drivers =
fake = neutron.tests.unit.ipam.fake_driver:FakeDriver
internal = neutron.ipam.drivers.neutrondb_ipam.driver:NeutronDbPool
我们看一下这个 NeutronDbPool
:
class NeutronDbPool(subnet_alloc.SubnetAllocator)
class SubnetAllocator(driver.Pool)
追踪下来,其实这个 driver 是本类 Pool
的一个实例。
def get_subnet_request_factory(self):
return ipam_req.SubnetRequestFactory
def get_address_request_factory(self):
return ipam_req.AddressRequestFactory
def needs_rollback(self):
return True
neutron/ipam/subnet_alloc.py
在 Pool
类的基础上实现了一些
def __init__(self, subnetpool, context):
super(SubnetAllocator, self).__init__(subnetpool, context)
self._sp_helper = SubnetPoolHelper()
- 判断分配子网请求的
prefixlen
属性在子网池的max_prefixlen
和min_prefixlen
的范围之间 - 若请求为
AnySubnetRequest
类型,则调用_allocate_any_subnet
方法(该方法的最终目的也是构造一个SpecificSubnetRequest
类型的请求) - 若请求为
SpecificSubnetRequest
类型,则调用_allocate_specific_subnet
方法
通过分析 _allocate_any_subnet
和 _allocate_specific_subnet
方法可知:这两个方法只是对子网分配的请求做了验证,验证可以在子网池中分配该子网,但是并没有真正的分配子网。验证通过后,构造一个 SpecificSubnetRequest
类型的分配请求。
- 调用
_lock_subnetpool
锁住当前子网池的数据库记录,防止同时进行两次子网的分配操作。 - 调用
_check_subnetpool_tenant_quota
检查这次请求是否满足 quota 的限制 - 调用
_get_available_prefix_list
获取当前子网池中可分配的cidr
- 从可用的子网池中分配子网
- 根据
cidr
调用ipam_utils.generate_pools
生成以netaddr.IPRange
表示的地址池。 - 返回一个以
IpamSubnet
的实例(该实例的主要作用是构造了一个SpecificSubnetRequest
类型的请求)。
以更新 SubnetPool
数据库的 hash
属性来将当前的这个数据库记录锁住。
- 调用
SubnetPoolHelper.ip_version_subnetpool_quota_unit
获取 quota_unit - 获取该
SubnetPool
数据库记录的default_quota
属性(限制用户可申请的地址池个数) - 若是
default_quota
属性存在,则调用_allocations_used_by_tenant
获取当前租户所拥有的所有的 Ip 地址的个数 - 获取当前用户所拥有的 Ip 地址个数后,调用
_num_quota_units_in_prefixlen
获取这次请求需要的 Ip 地址个数 - 若是当前请求的 IP 地址个数和当前租户已经拥有的 Ip 地址个数超过了 quota 限制,则引发异常
- 查询
Subnet
数据库,获得当前租户从该子网池中分配出来的所有子网 - 调用
_num_quota_units_in_prefixlen
计算当前租户的所用子网中的 ip 地址个数
def _num_quota_units_in_prefixlen(self, prefixlen, quota_unit):
return math.pow(2, quota_unit - prefixlen)
这个方法用来计算当前 cidr 所拥有的 Ip 地址个数。(例:2^(32-16))
- 调用
_get_allocated_cidrs
获取已经分配出去的子网的cidr
- 调用
netaddr.IPSet
获取当前子网池可用的cidr
查询从当前子网池中所有分配出去的子网的 cidr
,并按照 cidr
中的 prefixlen
进行由大到小的排序。
- 调用
_lock_subnetpool
锁住当前子网池的数据库记录,防止同时进行两次子网的分配操作。 - 调用
_check_subnetpool_tenant_quota
检查这次请求是否满足 quota 的限制 - 调用
_get_available_prefix_list
获取子网池中可用的cidr
- 调用
netaddr.all_matching_cidrs
查询是否有满足要求的cidr
- 若是有满足要求的
cidr
,则构造一个IpamSubnet
实例(该实例的主要作用是构造了一个SpecificSubnetRequest
类型的请求) - 若没有满足要求的
cidr
,则引发异常
def get_allocator(self, subnet_ids):
return IpamSubnetGroup(self, subnet_ids)
子网池实现后端
类方法,获取 NeutronDbSubent
描述的一个 subnet 数据库记录
def get_subnet(self, subnet_id):
return NeutronDbSubnet.load(subnet_id, self._context)
- 若本实例的
_subnetpool
不为空,则调用父类的allocate_subnet
方法,验证请求分配的子网是否可以在自己的子网池中分配。验证通过后,构造一个SpecificSubnetRequest
类型的分配请求。 - 调用
NeutronDbSubnet.create_from_subnet_request
进行子网的实际分配(创建数据库记录)。
- 检查
subnet_request
应该包含subnet_id
和allocation_pools
属性 - 调用
NeutronDbSubnet.load
构造一个以NeutronDbSubnet
实例,用来描述的待更新的子网。 - 调用
NeutronDbSubnet.update_allocation_pools
更新子网的地址池
可以看出,这里的更新只处理子网的地址池的更新。
直接调用 IpamSubnetManager.delete
删除子网的数据库记录
def needs_rollback(self):
return False