openstack之ml2源码分析-port流程梳理

由于笔者水平实在有限,本文只是依据源码对port的创建流程作简单分析,如有问题,欢迎指出;

路径:neutron.plugins.ml2.plugin.py

首先从create方法着手:

@utils.transaction_guard
@db_api.retry_if_session_inactive()
def create_port(self, context, port):
    self._before_create_port(context, port)
    result, mech_context = self._create_port_db(context, port)
    return self._after_create_port(context, result, mech_context)

此函数分为三步,首先进入第一个函数查看:

    def _before_create_port(self, context, port):
        attrs = port[port_def.RESOURCE_NAME]
        if not attrs.get('status'):
            attrs['status'] = const.PORT_STATUS_DOWN

        registry.notify(resources.PORT, events.BEFORE_CREATE, self,
                        context=context, port=attrs)
        # NOTE(kevinbenton): triggered outside of transaction since it
        # emits 'AFTER' events if it creates.
        self._ensure_default_security_group(context, attrs['tenant_id'])

此函数就是将port的信息提取出来;

进入第二个函数查看:

    def _create_port_db(self, context, port):
        attrs = port[port_def.RESOURCE_NAME]
        with db_api.context_manager.writer.using(context):
            dhcp_opts = attrs.get(edo_ext.EXTRADHCPOPTS, [])

            “将port信息写入DB”
            port_db = self.create_port_db(context, port)
            result = self._make_port_dict(port_db, process_extensions=False)

            “通过extension manager调用extension driver的接口”
            self.extension_manager.process_create_port(context, attrs, result)

            "检查port的sercurity属性;之后的语句都是为port添加不同的字段,至于每个字段的含义            
            就不一一探究(主要是也还不清楚。。。)"
            self._portsec_ext_port_create_processing(context, result, port)

            # sgids must be got after portsec checked with security group
            sgids = self._get_security_groups_on_port(context, port)
            self._process_port_create_security_group(context, result, sgids)
            network = self.get_network(context, result['network_id'])
            binding = db.add_port_binding(context, result['id'])
            mech_context = driver_context.PortContext(self, context, result,
                                                      network, binding, None)
            self._process_port_binding(mech_context, attrs)

            result[addr_apidef.ADDRESS_PAIRS] = (
                self._process_create_allowed_address_pairs(
                    context, result,
                    attrs.get(addr_apidef.ADDRESS_PAIRS)))
            self._process_port_create_extra_dhcp_opts(context, result,
                                                      dhcp_opts)
            kwargs = {'context': context, 'port': result}
            registry.notify(
                resources.PORT, events.PRECOMMIT_CREATE, self, **kwargs)
            “通过mechanism manager调用merchanism driver的precommit接口
            self.mechanism_manager.create_port_precommit(mech_context)
            self._setup_dhcp_agent_provisioning_component(context, result)

        resource_extend.apply_funcs('ports', result, port_db)
        return result, mech_context

再来详细看下create_port_precommit函数:

    def create_port_precommit(self, context):
        """Notify all mechanism drivers during port creation.

        :raises: DB retriable error if create_network_precommit raises them
        See neutron.db.api.is_retriable for what db exception is retriable
        or neutron.plugins.ml2.common.MechanismDriverError
        if any mechanism driver create_port_precommit call fails.

        Called within the database transaction. If a mechanism driver
        raises an exception, then a MechanismDriverError is propagated
        to the caller, triggering a rollback. There is no guarantee
        that all mechanism drivers are called in this case.
        """
        self._call_on_drivers("create_port_precommit", context,
                              raise_db_retriable=True)

通过此方法,依据配置文件mechanism drivers的配置,调用该厂商的内部代码;

接下来看第三个函数:

    def _after_create_port(self, context, result, mech_context):
        # notify any plugin that is interested in port create events
        kwargs = {'context': context, 'port': result}
        registry.notify(resources.PORT, events.AFTER_CREATE, self, **kwargs)

        try:
            “通过mechanism manager调用mechanism driver的postcommit接口,这同之前调用 
             precommit,通过调用对应厂商的代码完成下一步操作”
            self.mechanism_manager.create_port_postcommit(mech_context)
        except ml2_exc.MechanismDriverError:
            with excutils.save_and_reraise_exception():
                LOG.error("mechanism_manager.create_port_postcommit "
                          "failed, deleting port '%s'", result['id'])
                “注意此处的回退操作,若调用失败,则会删除库中已创建的port,以恢复初始状态”
                self.delete_port(context, result['id'], l3_port_check=False)
        try:
            “此步会进入port绑定方法”
            bound_context = self._bind_port_if_needed(mech_context)
        except ml2_exc.MechanismDriverError:
            with excutils.save_and_reraise_exception():
                LOG.error("_bind_port_if_needed "
                          "failed, deleting port '%s'", result['id'])
                “回退操作”
                self.delete_port(context, result['id'], l3_port_check=False)

        return bound_context.current

接下来看port绑定方法,此函数的调用比较多,就不粘贴所有语句了,选取重点说一下:

def _bind_port_if_needed(self, context, allow_notify=False,
                             need_notify=False, allow_commit=True):
    ....
    “会调用_attempt_binding函数,”
    bind_context, need_notify, try_again = self._attempt_binding(
                context, need_notify)
    ....

def _attempt_binding(self, context, need_notify):
    ....
    bind_context = self._bind_port(context)
    ....

接下来调用_bind_port函数:

    def _bind_port(self, orig_context):
        # Construct a new PortContext from the one from the previous
        # transaction.
        port = orig_context.current
        orig_binding = orig_context._binding
        new_binding = models.PortBinding(
            host=orig_binding.host,
            vnic_type=orig_binding.vnic_type,
            profile=orig_binding.profile,
            vif_type=portbindings.VIF_TYPE_UNBOUND,
            vif_details=''
        )
        self._update_port_dict_binding(port, new_binding)
        new_context = driver_context.PortContext(
            self, orig_context._plugin_context, port,
            orig_context.network.current, new_binding, None,
            original_port=orig_context.original)

        # Attempt to bind the port and return the context with the
        # result.
        “相信大家看到这个就比较熟悉了,通过mechanism manager调用driver的接口”
        self.mechanism_manager.bind_port(new_context)
        return new_context

篇幅也很长了,port的create过程就到这里吧

你可能感兴趣的:(openstack)