使neutron不能创建相同名字以及相同cidr的子网

今天测试部的说,平台上创建两个相同名字的子网以及相同cidr的子网,严重影响一些根据名字和cidr进行的一些常规操作,
应要求修改代码使得不能创建相同名字以及相同cidr的子网。
过程如下,大神请绕过,有问题请多多指教!


创建子网的接口,这里直接从插件的接口开始,如下:
vim .../neutron/plugins/ml2/plugin.py
    @utils.transaction_guard
    @db_api.retry_if_session_inactive()
    def create_subnet(self, context, subnet):
        result, mech_context = self._create_subnet_db(context, subnet)
        kwargs = {'context': context, 'subnet': result}
        registry.notify(resources.SUBNET, events.AFTER_CREATE, self, **kwargs)
        try:
            self.mechanism_manager.create_subnet_postcommit(mech_context)
        except ml2_exc.MechanismDriverError:
            with excutils.save_and_reraise_exception():
                LOG.error(_LE("mechanism_manager.create_subnet_postcommit "
                              "failed, deleting subnet '%s'"), result['id'])
                self.delete_subnet(context, result['id'])
        return result
 注释:(1)result, mech_context = self._create_subnet_db(context, subnet)
         这里主要进行数据库操作,保存子网信息到数据库  
         使用户不能创建同名字以及同cidr的子网,需要查询数据库中是否有对应的子网,如果有,则报错“已存在,不能创建”,如果没有,则创建


vim .../neutron/plugins/ml2/plugin.py
    def _create_subnet_db(self, context, subnet):
        session = context.session
        # FIXME(kevinbenton): this is a mess because create_subnet ends up
        # calling _update_router_gw_ports which ends up calling update_port
        # on a router port inside this transaction. Need to find a way to
        # separate router updates from the subnet update operation.
        setattr(context, 'GUARD_TRANSACTION', False)
        with session.begin(subtransactions=True):
            result = super(Ml2Plugin, self).create_subnet(context, subnet)
            self.extension_manager.process_create_subnet(
                context, subnet[attributes.SUBNET], result)
            network = self.get_network(context, result['network_id'])
            mech_context = driver_context.SubnetContext(self, context,
                                                        result, network)
            self.mechanism_manager.create_subnet_precommit(mech_context)


        return result, mech_context
        
注释:class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
                dvr_mac_db.DVRDbMixin,
                external_net_db.External_net_db_mixin,
                sg_db_rpc.SecurityGroupServerRpcMixin,
                agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
                addr_pair_db.AllowedAddressPairsMixin,
                vlantransparent_db.Vlantransparent_db_mixin,
                extradhcpopt_db.ExtraDhcpOptMixin,
                address_scope_db.AddressScopeDbMixin,
                service_type_db.SubnetServiceTypeMixin):...
                
       with session.begin(subtransactions=True):
          result = super(Ml2Plugin, self).create_subnet(context, subnet)
       连接到数据库后,调用class NeutronDbPluginV2类中的create_subnet()
       
vim .../nuetron/db/db_base_plugin_v2.py   
    @db_api.retry_if_session_inactive()
    def create_subnet(self, context, subnet):
        s = subnet['subnet']
        cidr = s.get('cidr', constants.ATTR_NOT_SPECIFIED)
        prefixlen = s.get('prefixlen', constants.ATTR_NOT_SPECIFIED)
        has_cidr = validators.is_attr_set(cidr)
        has_prefixlen = validators.is_attr_set(prefixlen)


        if has_cidr and has_prefixlen:
            msg = _('cidr and prefixlen must not be supplied together')
            raise exc.BadRequest(resource='subnets', msg=msg)


        if has_cidr:
            # turn the CIDR into a proper subnet
            net = netaddr.IPNetwork(s['cidr'])
            subnet['subnet']['cidr'] = '%s/%s' % (net.network, net.prefixlen)


        subnetpool_id = self._get_subnetpool_id(context, s)
        if not subnetpool_id and not has_cidr:
            msg = _('a subnetpool must be specified in the absence of a cidr')
            raise exc.BadRequest(resource='subnets', msg=msg)


        if subnetpool_id:
            self.ipam.validate_pools_with_subnetpool(s)
            if subnetpool_id == constants.IPV6_PD_POOL_ID:
                if has_cidr:
                    # We do not currently support requesting a specific
                    # cidr with IPv6 prefix delegation. Set the subnetpool_id
                    # to None and allow the request to continue as normal.
                    subnetpool_id = None
                    self._validate_subnet(context, s)
                else:
                    prefix = n_const.PROVISIONAL_IPV6_PD_PREFIX
                    subnet['subnet']['cidr'] = prefix
                    self._validate_subnet_for_pd(s)
        else:
            if not has_cidr:
                msg = _('A cidr must be specified in the absence of a '
                        'subnet pool')
                raise exc.BadRequest(resource='subnets', msg=msg)
            self._validate_subnet(context, s)


        return self._create_subnet(context, subnet, subnetpool_id)
注:前面是一些参数分析,这里我们只关注self._create_subnet(context, subnet, subnetpool_id)


vim .../nuetron/db/db_base_plugin_v2.py
    def _create_subnet(self, context, subnet, subnetpool_id):
        s = subnet['subnet']
        with context.session.begin(subtransactions=True):
            network = self._get_network(context, s["network_id"])
            subnet, ipam_subnet = self.ipam.allocate_subnet(context,
                                                            network,
                                                            s,
                                                            subnetpool_id)
        if hasattr(network, 'external') and network.external:
            self._update_router_gw_ports(context,
                                         network,
                                         subnet)
        # If this subnet supports auto-addressing, then update any
        # internal ports on the network with addresses for this subnet.
        if ipv6_utils.is_auto_address_subnet(subnet):
            updated_ports = self.ipam.add_auto_addrs_on_network_ports(context,
                                subnet, ipam_subnet)
            for port_id in updated_ports:
                port_info = {'port': {'id': port_id}}
                self.update_port(context, port_id, port_info)


        return self._make_subnet_dict(subnet, context=context)
至此完成数据库的操作。


修改代码:
vim .../nuetron/db/db_base_plugin_v2.py        


    def _create_subnet(self, context, subnet, subnetpool_id):
        s = subnet['subnet']
        
        #-------------------------------------------------------------------
        #获取待创建的子网名以及cidr
        subnet_cidr = subnet['subnet']['cidr']
        subnet_name = subnet['subnet']['name']
        #-------------------------------------------------------------------
        
        with context.session.begin(subtransactions=True):
            #-------------------------------------------------------------------
            #通过子网名和cidr判断数据库中是否存在相同的子网
            subnet_exist_by_cidr = self._get_subnet_by_cidr(context,subnet_cidr)
            subnet_exist_by_name = self._get_subnet_by_name(context,subnet_name)
            if subnet_exist_by_cidr or subnet_exist_by_name:
                msg = _('subnet has exist,please create other cidr subnet ')
                raise exc.BadRequest(resource='subnets', msg=msg)
            if subnet_exist_by_name:
                msg = _('same name subnet has exist,please create other name subnet ')
            #-------------------------------------------------------------------
                
                
                raise exc.BadRequest(resource='subnets', msg=msg)
            network = self._get_network(context, s["network_id"])
            subnet, ipam_subnet = self.ipam.allocate_subnet(context,
                                                            network,
                                                            s,
                                                            subnetpool_id)
        if hasattr(network, 'external') and network.external:
            self._update_router_gw_ports(context,
                                         network,
                                         subnet)
        # If this subnet supports auto-addressing, then update any
        # internal ports on the network with addresses for this subnet.
        if ipv6_utils.is_auto_address_subnet(subnet):
            updated_ports = self.ipam.add_auto_addrs_on_network_ports(context,
                                subnet, ipam_subnet)
            for port_id in updated_ports:
                port_info = {'port': {'id': port_id}}
                self.update_port(context, port_id, port_info)


        return self._make_subnet_dict(subnet, context=context)


#通过cidr以及name查询Subnet的数据库,如下:        
vim .../neutron/db/db_base_plugin_common.py
class DbBasePluginCommon(common_db_mixin.CommonDbMixin):
#-------------------------------------------------------------------
    def _get_subnet_by_cidr(self,context,cidr):
        try:
            subnet = self._get_by_cidr(context, models_v2.Subnet, cidr)
        except exc.NoResultFound:
            return None
        return subnet


    def _get_subnet_by_name(self,context,name):
        try:
            subnet = self._get_by_name(context, models_v2.Subnet, name)
        except exc.NoResultFound:
            return None
        return subnet
#-------------------------------------------------------------------
        
Subnet表的属性如下:models_v2.Subnet 子网对应的表
vim .../db/models_v2.py
class Subnet(standard_attr.HasStandardAttributes, model_base.BASEV2,
             model_base.HasId, model_base.HasProject):
    """Represents a neutron subnet.


    When a subnet is created the first and last entries will be created. These
    are used for the IP allocation.
    """


    name = sa.Column(sa.String(attr.NAME_MAX_LEN))
    network_id = sa.Column(sa.String(36), sa.ForeignKey('networks.id'))
    # Added by the segments service plugin
    segment_id = sa.Column(sa.String(36), sa.ForeignKey('networksegments.id'))
    subnetpool_id = sa.Column(sa.String(36), index=True)
    # NOTE: Explicitly specify join conditions for the relationship because
    # subnetpool_id in subnet might be 'prefix_delegation' when the IPv6 Prefix
    # Delegation is enabled
    subnetpool = orm.relationship(
        'SubnetPool', lazy='joined',
        foreign_keys='Subnet.subnetpool_id',
        primaryjoin='Subnet.subnetpool_id==SubnetPool.id')
    ip_version = sa.Column(sa.Integer, nullable=False)
    cidr = sa.Column(sa.String(64), nullable=False)
    gateway_ip = sa.Column(sa.String(64))
    revises_on_change = ('networks', )
    allocation_pools = orm.relationship(IPAllocationPool,
                                        backref='subnet',
                                        lazy="subquery",
                                        cascade='delete')
    enable_dhcp = sa.Column(sa.Boolean())
    dns_nameservers = orm.relationship(DNSNameServer,
                                       backref='subnet',
                                       cascade='all, delete, delete-orphan',
                                       order_by=DNSNameServer.order,
                                       lazy='subquery')
    routes = orm.relationship(SubnetRoute,
                              backref='subnet',
                              cascade='all, delete, delete-orphan',
                              lazy='subquery')
    ipv6_ra_mode = sa.Column(sa.Enum(constants.IPV6_SLAAC,
                                     constants.DHCPV6_STATEFUL,
                                     constants.DHCPV6_STATELESS,
                                     name='ipv6_ra_modes'),
                             nullable=True)
    ipv6_address_mode = sa.Column(sa.Enum(constants.IPV6_SLAAC,
                                          constants.DHCPV6_STATEFUL,
                                          constants.DHCPV6_STATELESS,
                                          name='ipv6_address_modes'),
                                  nullable=True)
    # subnets don't have their own rbac_entries, they just inherit from
    # the network rbac entries
    rbac_entries = orm.relationship(
        rbac_db_models.NetworkRBAC, lazy='subquery', uselist=True,
        foreign_keys='Subnet.network_id',
        primaryjoin='Subnet.network_id==NetworkRBAC.object_id')
    api_collections = [attr.SUBNETS]
    #这里我们只关注name和cidr两个属性:
      name = sa.Column(sa.String(attr.NAME_MAX_LEN))
      cidr = sa.Column(sa.String(64), nullable=False)
      
vim .../neutron/db/common_db_mixin.py
class CommonDbMixin(object):
#-------------------------------------------------------------------
    def _get_by_cidr(self, context, model, cidr):
        query = self._model_query(context, model)
        return query.filter(model.cidr == cidr).first()


    def _get_by_name(self, context, model, name):
        query = self._model_query(context, model)
        return query.filter(model.name == name).first()
#-------------------------------------------------------------------
        
#query.filter(model.cidr == cidr).first()
#query.filter(model.name == name).first() 查询并返回第一个实例Subnet
至此,修改完成,重启neutron-server服务,测试达到理想效果。


补充一下,这里修改的方法并不是唯一,只是通过和数据库已有的数据库做比较的途径来实现;
还有一种方法就是,设计子网的表时,限定name和cidr是主键,不能在表格中重复,可以达到name和cidr不能同时相同,
但可以有一个相同(算是一个不足吧),并且要求就是升级数据库版本(算是第二个不足吧)。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值