Openstack Neutron扩展实现细节(QOS)

107 篇文章 0 订阅
98 篇文章 0 订阅

https://wenku.baidu.com/view/7e6fe84d1611cc7931b765ce05087632311274ff


Openstack Neutron扩展实现细节

 

1   目的

本文已QOS为例子,记录通过Neutron的扩展机制扩展网络服务所注意的细节,帮助后续的开发人员快速上手

2   Neutron的架构

Neutron分为三个部分:neutron-client,neutron-server,网络服务代理。

 

 

Neturon-client提供两种接口,Shell命令行与开发SDK;内部完成REST请求的封装、发送,应答的处理。

Neutron-server处理来自client的请求,根据请求的路径调用相应的插件进行处理,配置信息存储导数据库,调度选择目标代理,并将网络配置发送给相应的代理

Agent是网络服务直接提供的部分,不同的网络服务由不同的代理完成,比如二层网络的配置由Openvswitch-agent完成。L3-agent完成路由的配置,dhcp-agent完成dnsmasq的配置,lbass-agent完成各种硬件或软件的负载均衡的配置

3   Neutron的代码的修改

Neutron代码主要是要增加常量定义

neutron\plugins\common\constants.py

QOS="QOS"[A1] 

EXT_TO_SERVICE_MAPPING = {

   'dummy': DUMMY,

   'lbaas': LOADBALANCER,

   'lbaasv2': LOADBALANCERV2,

   'fwaas': FIREWALL,

   'vpnaas': VPN,

   'metering': METERING,

    'qos':QOS,[A2] 

   'router': L3_ROUTER_NAT

}

 

4   Neutron的Server部分

4.1    扩展的Rest接口定义

4.1.1 资源的属性定义表

资源的属性定义表格式如下,定义了Rest接口提供了配置的资源类型,对资源进行操作的属性要求;RESOURCE_ATTRIBUTE_MAP的key为每一种资源名的复数形式,Value为该资源的scheme描述。

RESOURCE_ATTRIBUTE_MAP = {

    'qos_rules'[A3] : {[A4] 

       'id': {'allow_post': False, 'allow_put': False,

               'validate': {'type:uuid': None},

               'is_visible': True,

               'primary_key': True},

       'tenant_id': {'allow_post': True, 'allow_put': False,

                       'validate':{'type:string':attr.TENANT_ID_MAX_LEN},

                      'required_by_policy': True,

                      'is_visible': True},

       'network_id': {'allow_post': True, 'allow_put': False,

                      'validate': {'type:uuid':None},

                      'is_visible': True},

       'port_id': {'allow_post': True, 'allow_put': False,

                    'validate': {'type:uuid':None},

                    'is_visible': True},

       'max_kbps': {'allow_post': True, 'allow_put': True,

                     'is_visible': True,'convert_to': convert_to_unsigned_int_or_none},

       'max_burst_kbps': {'allow_post': True, 'allow_put': True,

                           'is_visible':True,'convert_to': convert_to_unsigned_int_or_none},

    }

}

 

REST接口有post,put,get,delete四种方法,post为创建资源,put为修改某个资源,get为获取某个资源,delete为删除某个资源

 

资源的每个属性都定义了一些约束:

allow_pos True:创建时可以指定;False:创建时不能指定

allow_put True:可以修改;False:不允许修改

validate:验证值的合法性,可以验证最大长度,数据类型,或者是枚举值

is_visible:是否可见,list资源时属性值是否可以返回

 

4.1.2 扩展的描述

该文件的路径为$包名/extensions/qos.py

class Qos[A5] (extensions.ExtensionDescriptor):

 

   @classmethod

   def get_name(cls):

       return "QOS service"

 

   @classmethod

   def get_alias(cls):

       return "qos[A6] "

 

   @classmethod

   def get_description(cls):

       return "Extension for QOS service"

 

   @classmethod

   def get_namespace(cls):

       return "http://wiki.openstack.org/neutron/QOS/API_1.0"

 

   @classmethod

   def get_updated(cls):

       return "2015-04-07T10:00:00-00:00"

 

   @classmethod

   def get_resources(cls):

       special_mappings = {}

       plural_mappings = resource_helper.build_plural_mappings(

           special_mappings, RESOURCE_ATTRIBUTE_MAP)

       attr.PLURALS.update(plural_mappings)

       return resource_helper.build_resource_info(plural_mappings,RESOURCE_ATTRIBUTE_MAP,constants.QOS)

 

 

   @classmethod

   def get_plugin_interface(cls):

       return QOSPluginBase

 

   def update_attributes_map(self, attributes):

       super(Qos, self).update_attributes_map(

           attributes, extension_attrs_map=RESOURCE_ATTRIBUTE_MAP)

 

   def get_extended_resources(self, version):

       if version == "2.0":

           return RESOURCE_ATTRIBUTE_MAP

       else:

           return {}

 

 

扩展的描述需要从extensions.ExtensionDescriptor继承, get_name, get_description,get_namespace, get_updated四个函数返回的内容,是在调用neutron ext-show qos命令时显示的内容。

 

def get_resources(cls):

       special_mappings[A7]  = {}

       plural_mappings = resource_helper.build_plural_mappings[A8] (

           special_mappings, RESOURCE_ATTRIBUTE_MAP)

       attr.PLURALS.update(plural_mappings)

       return resource_helper.build_resource_info[A9] (plural_mappings,RESOURCE_ATTRIBUTE_MAP,constants.QOS[A10] )

 

 

4.1.3 插件接口的定义

插件的接口必须从ServicePluginBase继承,get_plugin_name, get_plugin_type, get_plugin_description必须实现,为插件的基础信息。

@six.add_metaclass(abc.ABCMeta)

class QOSPluginBase(ServicePluginBase):

 

   def get_plugin_name(self):

       return constants.QOS

 

   def get_plugin_type(self):

       return constants.QOS[A11] 

 

   def get_plugin_description(self):

       return 'qos service plugin'

 

   @abc.abstractmethod

   def get_qos_rules(self, context, filters=None, fields=None):

       pass

 

   @abc.abstractmethod

   def get_qos_rule(self, context, id, fields=None):

       pass

 

   @abc.abstractmethod

   def create_qos_rule(self, context, qos_rule[A12] ):

       """

       qos_rule={'qos_rule':{'network_id':'uuid','port_id':'uuid','max_kbps':10,'max_burst_kbps':10}}

       """

       pass

 

   @abc.abstractmethod

   def update_qos_rule(self, context, id, qos_rule[A13] ):

       pass

 

   @abc.abstractmethod

   def delete_qos_rule(self, context, id):

       pass

 

 

必须为每个资源定义5个接口,分别为:

#list资源的接口

def get_资源复数名(self, context,filters=None, fields=None)

#show单个资源的接口

def get_资源单数名(self, context,id, fields=None):

#create单个资源的接口

def create_资源单数名(self, context, data):

#update单个资源的接口

def update _资源单数名(self, context, id,data):

#delete单个资源的接口

def delete _资源单数名(self, context, id):

 

4.1.4 插件的数据库实现

4.1.4.1定义数据库模型类

class QosRule(model_base.BASEV2, models_v2.HasId,models_v2.HasTenant[A14] ):

    __tablename__ = 'qos_rules'[A15] 

   __table_args__ = (

       sa.schema.UniqueConstraint[A16] ('port_id',

                                  name='uniq_qos_rule_port'),

    )

   network_id = sa.Column(sa.String(36),nullable=False)

   port_id = sa.Column(sa.String(36),nullable=False)

   max_kbps = sa.Column(sa.Integer)

max_burst_kbps= sa.Column(sa.Integer)

 

4.1.4.2插件数据库操作类

需要多重继承插件接口类与base_db.CommonDbMixin

classQOSPluginDB(QOSPluginBase,base_db.CommonDbMixin):

    def _make_qos_dict(self, qos, fields=None):

        res = {'id': qos['id'],

               'tenant_id': qos['tenant_id'],

               'network_id':qos['network_id'],

               'port_id':qos['port_id'],

               'max_kbps':qos['max_kbps'],

              'max_burst_kbps':qos['max_burst_kbps']}

        return self._fields(res, fields)

 

    def _get_qos(self,context,id):

        try:

            return self._get_by_id(context,QosRule, id)

        except exc.NoResultFound:

            raise QosNotFound(Qos_id=id)

 

    def create_qos_rule[A17] (self, context, qos_rule):

        tenant_id =self._get_tenant_id_for_create(context, qos_rule)

        withcontext.session.begin(subtransactions=True):

            qos_db =QosRule(id=uuidutils.generate_uuid(),

                           tenant_id=tenant_id,

                          network_id=qos_rule['network_id'],

                          port_id=qos_rule['port_id'],

                           max_kbps=qos_rule['max_kbps'],

                          max_burst_kbps=qos_rule['max_burst_kbps'])

            context.session.add(qos_db)

        return self._make_qos_dict(qos_db)

 

    def get_qos_rule[A18] (self, context, id,fields=None):

        LOG.debug(_("get_qos_rule()called"))

        qos = self._get_qos(context, id)

        return self._make_qos_dict(qos, fields)

 

    def get_qos_rule[A19] s(self,context,filters=None, fields=None):

        LOG.debug(_("get_qos_rules()called"))

        return self._get_collection(context,QosRule,

                                   self._make_qos_dict,

                                   filters=filters, fields=fields)

 

    def update_qos_rule[A20] (self, context, id,qos_rule):

        LOG.debug(_("update_qos_rule()called"))

        withcontext.session.begin(subtransactions=True):

            qos_db = self._get_qos(context, id)

            qos_db.update(qos_rule)

        return self._make_qos_dict(qos_db)

 

 

    def delete_qos_rule[A21] (self, context, id):

        LOG.debug(_("delete_qos_rule()called"))

        withcontext.session.begin(subtransactions=True):

            qos = self._get_qos(context, id)

            context.session.delete(qos)

4.1.5 插件调度类的实现

Agent可以在不同的计算节点,网络节点上运行,插件调度类找到对应的Agent;根据Agent的主机名,获取需要的配置信息。

调度类从agentschedulers_db.AgentSchedulerDbMixin继承

classQosAgentSchedulerDbMixin(agentschedulers_db.AgentSchedulerDbMixin):

   def get_agent_by_qos(self, context, qos_rule_id, active=None):

       #根据QOS的ID,查询Agent

       query =context.session.query(QosAgentBinding)

       query = query.options(joinedload('agent'))[A22] 

       binding = query.get(qos_rule_id)

 

       if (binding and self.is_eligible_agent(

                active, binding.agent)):

           return {'agent': self._make_agent_dict(binding.agent)}

       return  None

 

   def get_qos_agents(self, context, active=None, filters=None):

       #查询所有qos类型的agent

       query = context.session.query(agents_db.Agent)

       query = query.filter_by(agent_type=qos_const.AGENT_TYPE_QOS)

       if active is not None:

           query = query.filter_by(admin_state_up=active)

       if filters:

           for key, value in filters.iteritems():

                column = getattr(agents_db.Agent,key, None)

                if column:

                    query =query.filter(column.in_(value))

 

       return [agent

                for agent in query

                ifself.is_eligible_agent(active, agent)]

 

   def bind_qos_on_agent[A23] (self, context,qos_rule_id,agent_id):

       with context.session.begin(subtransactions=True):

           bind = QosAgentBinding(qos_rule_id=qos_rule_id,

                           agent_id=agent_id)

           context.session.add(bind)

       return self._make_qos_dict(bind)

 

   def list_qos_on_agent(self, context, host):

       #查询Agent上的所有qos规则

       id=None

       agent = self.get_qos_agents(context,True,{'host':[host]})

       if len(agent)>0:

           id = agent[0]["id"]

       query = context.session.query(QosAgentBinding.qos_rule_id)

       query = query.filter_by(agent_id=id)

       qos_ids = [item[0] for item in query]

       if qos_ids:

           return {'qos_rules': self.get_qos_rules(context, filters={'id': qos_ids})}

       else:

           return {'qos_rules': []}

 

 

   def schedule(self,context,qos_rule,activ_agent):

       #根据规则的定义选择agent

       bind_port = None

       with context.session.begin(subtransactions=True):

           bind_port = context.session.query(PortBinding.host).filter_by(port_id=qos_rule["port_id"]).first()

       if bind_port:

           for agent in activ_agent:

                if bind_port[0] == agent.host:

                    return agent

           msg = _('%(agent_type)s on host %(host)s is invalid.')

           LOG.warn(msg, {'agent_type': agent['agent_type'],

                           'host':bind_port})

       LOG.warn("port_id = %s notrunning",qos_rule["port_id"])

       return None        return None

 

4.1.6 发送给Agent的RPC封装

Agent完成资源在具体设备或软件的配置,当创建、删除、修改资源时,需要将信息发送到Agent。

 

class QOSAgentApi(object):

   """neutron server插件端发送到agent端的rpc."""

 

   def __init__(self, topic):

       target = messaging.Target(topic=topic, version='1.0')

       self.client = n_rpc.get_client(target)

 

 

   def update_qos_rule(self,context,host,qos):

       cctxt = self.client.prepare(server=host[A24] )

       return cctxt.call(context, 'update_qos_rule[A25] ',qos=qos)

 

   def delete_qos_rule(self,context,host,port_id):

       cctxt = self.client.prepare(server=host)

       return cctxt.call(context, 'delete_qos_rule',port_id=port_id)

 

4.1.7 处理Agent消息的callback

class QosCallbacks(object):

   """neutron server处理agent端发送的rpc请求."""

   target = messaging.Target(version='1.0')

 

   def __init__(self, plugin):

       super(QosCallbacks, self).__init__()

       self.plugin = plugin

 

   def get_ready_qos_rules(self, context, host[A26] =None):

       rule_set={}

       with context.session.begin(subtransactions=True):

           qos_rules = self.plugin.list_qos_on_agent(context, host)

           for rule in qos_rules["qos_rules"]:

                rule_set[rule['port_id']] =rule

       return rule_set

 

 

4.1.8 插件实现

必须要从插件接口类继承

classQosPlugin(QOSPluginDB,QosAgentSchedulerDbMixin):

 

   supported_extension_aliases = ["qos[A27] ","service-type"]

 

   def __init__(self):

       self.agent_rpc= QOSAgentApi(qos_const.QOS_AGENT)[A28] 

       self.agent_endpoints = [

           agent_callbacks.QosCallbacks(self),

           agents_db.AgentExtRpcCallback[A29] (self)

       ]

       self.conn = n_rpc.create_connection(new=True)

       self.conn.create_consumer(qos_const.QOS_PLUGIN,self.agent_endpoints,fanout=False)[A30] 

       self.conn.consume_in_threads()

 

 

   def create_qos_rule[A31] (self, context, qos_rule):

       

 

    defupdate_qos_rule[A32] (self, context, id,qos_rule):

       

 

   def delete_qos_rule(self, context, id):

       

5   Neutron的Agent部分

5.1    AgentMnager的实现

从periodic_task.PeriodicTasks继承,可以周期性执行某些任务

classQOSAgentManager(periodic_task.PeriodicTasks):

 

    #history

   #   1.0 Initial version

   target = oslo_messaging.Target(version='1.0')

 

   def __init__(self, conf):

       super(QOSAgentManager, self).__init__()

       self.conf = conf

       self.context = ncontext.get_admin_context_without_session()

       self.plugin_rpc = agent_api.QOSAgentApi(

           qos_const.QOS_PLUGIN[A33] ,

           self.context,

           self.conf.host

       )

       self._load_drivers()

 

       self.agent_state = {

           'binary': 'neutron-qos-agent',

            'host': conf.host,

           'topic': qos_const.QOS_AGENT,

           'configurations': {'device_drivers':self.device_driver.__class__.__name__},

           'agent_type': qos_const.AGENT_TYPE_QOS[A34] ,

           'start_flag': True}

       self.admin_state_up = True

 

       self._setup_state_rpc()

       self.needs_resync = False

       self.qos_rules={}

       # pool_id->device_driver_name mapping used to store known instances

 

   def _load_drivers(self):

       #加载驱动,QOS可以通过OVS实现也可以通过其他方式实现,根据配置加载不同的驱动,取决与二层虚拟化的实现

       self.device_driver = None

       driver =provconfig.get_provider_driver_class(self.conf.device_driver,DEVICE_DRIVERS)

       try:

           self.device_driver =importutils.import_object(driver,cfg,self.plugin_rpc)

       except ImportError:

           msg = _('Error importing QOS device driver: %s')

           raise SystemExit(msg % driver)

 

   def _setup_state_rpc(self):

       self.state_rpc = agent_rpc.PluginReportStateAPI[A35] (

           qos_const.QOS_PLUGIN)

       report_interval = self.conf.AGENT.report_interval

       if report_interval:

           heartbeat = loopingcall.FixedIntervalLoopingCall(

                self._report_state)

           heartbeat.start(interval=report_interval)

 

   def _report_state(self):

       #上报agent的状态

       try:

           self.state_rpc.report_state(self.context, self.agent_state)

           self.agent_state.pop('start_flag', None)

       except Exception:

           LOG.exception(_LE("Failed reporting state!"))

 

   def initialize_service_hook(self, started_by):

       self.sync_state()

 

   @periodic_task.periodic_task

   def periodic_resync(self, context):

       if self.needs_resync:

           self.needs_resync = False

           self.sync_state()

 

 

   def sync_state(self):

       known_rules = set(self.qos_rules.keys())

       try:

           ready_rules = self.plugin_rpc.get_ready_qos_rules()

           LOG.info("load ready_rules:%r",ready_rules)

           for port_id in known_rules - set(ready_rules.keys()):

                self._destroy_qos_rule(port_id)

 

           for port_id,rule in ready_rules.items():

                if port_id in self.qos_rules:

                    if rule !=self.qos_rules[port_id]:

                        LOG.info("port_id= %s has update old_rule=%rnew_rule=%r",port_id,self.qos_rules[port_id],rule)

                       self.update_qos_rule(None,rule)

                else:

                    LOG.info("port_id = %screate rule=%r",port_id,rule)

                    self.update_qos_rule(None,rule)

 

       except Exception:

           LOG.exception(_LE('Unable to retrieve ready devices'))

           self.needs_resync = True

 

   def _destroy_qos_rule(self,port_id):

       try:

           self.device_driver.delete({'port_id':port_id})

       except Exception:

           LOG.exception(_LE('Unable to destroy qos rule on port: %s'), port_id)

           self.needs_resync = True

 

   def delete_qos_rule(self,context,port_id):

        LOG.debug("begin call delete_qos_ruleport_id=%s",port_id)

       self._destroy_qos_rule(port_id)

 

   def update_qos_rule(self,context,qos):

       LOG.debug("begin call update_qos_rule rule=%r",qos)

       try:

           port_id = qos['port_id']

           self.qos_rules[port_id] = qos

           self.device_driver.update(qos)

           LOG.debug("update_qos_rule end")

       except Exception:

           import traceback

           LOG.exception("%s",traceback.format_exc())

           LOG.exception(_LE('Unable to update qos rule on port: %s'),qos['port_id'])

           self.needs_resync = True

 

 

   def agent_updated(self, context, payload):

       """Handle the agent_updated notificationevent."""

       if payload['admin_state_up'] != self.admin_state_up:

           self.admin_state_up = payload['admin_state_up']

           if self.admin_state_up:

                self.needs_resync = True

           else:

                for port_name inself.qos_rules.keys():

                   LOG.info(_LI("Destroying qos rule on port %s due to agent "

                                "disabling"), port_name)

                   self._destroy_qos_rule(port_name)

           LOG.info(_LI("Agent_updated by server side %s!"), payload)

 

5.2    驱动部分

Agent的驱动部分对具体设备进行配置

这里QosOVSAgentDriver对OVS添加QOS的定义

class QosOVSAgentDriver(AgentDeviceDriver):

 

   def __init__(self,cfg,plugin_rpc):

       super(QosOVSAgentDriver, self).__init__(cfg,plugin_rpc)

       # TODO(QoS) check if we can get this configuration

       #  as constructor arguments

       self.br_int_name = cfg.CONF.OVS.integration_bridge

       self.br_int = None

       self.handlers = {}

       self.initialize()

 

   def initialize(self):

       self.br_int = QosOVSBridge(self.br_int_name)

 

   def create(self, rules):

       self._update_bw_limit_rule(rules)

 

   def update(self, rules):

       self._update_bw_limit_rule(rules)

 

   def delete(self, rules):

       self._delete_bw_limit_rule(rules)

 

   def _update_bw_limit_rule(self, rule):

       

 

   def _delete_bw_limit_rule(self, rule):

      

6   Neutron的Client部分

 

6.1    SDK的封装

 

neutronclient\neutron\v2_0\增加目录:qos

添加qos的命令定义

neutronclient\neutron\v2_0\qos\qos_rule.py

 

创建的命令需要从neutronv20.CreateCommand继承

 

classCreateQosRule(neutronv20.CreateCommand):

    resource ='qos_rule'[A36] 

   list_columns = ["id"]

   _formatters = {}

 

   def add_known_arguments[A37] (self, parser):

       parser.add_argument(

           '--network-id',required=True,help=_('network ID.'))

       parser.add_argument(

           '--port-id',required=True,help=_('Port ID.'))

       parser.add_argument(

           '--max-kbps',required=True,help=_('max bandwidth in kps.'))

        parser.add_argument(

           '--max-burst-kbps',required=True,help=_('max burst bandwidth in kps.'))

 

   def args2body[A38] (self, parsed_args):

       body={self.resource:{}}

       neutronv20.update_dict(parsed_args,body[self.resource],['network_id','port_id','max_kbps','max_burst_kbps'])

       return body

 

 

class ListQosRule(neutronv20.ListCommand):[A39] 

   resource = 'qos_rule'

    list_columns[A40]  =["id",'network_id','port_id','max_kbps','max_burst_kbps']

   _formatters = {}

    pagination_support[A41]  = True

    sorting_support[A42]  = True

 

class UpdateQosRule(neutronv20.UpdateCommand):[A43] 

   resource = 'qos_rule'

 

 

class ShowQosRule(neutronv20.ShowCommand):[A44] 

   resource = 'qos_rule'

 

 

class DeleteQosRule(neutronv20.DeleteCommand)[A45] :

resource ='qos_rule'

 

ListCommand最终调用neutronclient\v2_0\client.py中定义的list_ resource[A46] (复数形式)

UpdateCommand最终调用neutronclient\v2_0\client.py中定义的update_ resource[A47] 

ShowCommand最终调用neutronclient\v2_0\client.py中定义的show_ resource[A48] (

DeleteCommand最终调用neutronclient\v2_0\client.py中定义的delete_ resource[A49] (

 

6.2    Client的api接口定义

修改neutronclient\v2_0\client.py

 

qos_rules_path="/qos/qos_rules"

qos_rule_path="/qos[A50] /qos_rules[A51] /%s"

 

EXTED_PLURALS = {

   @APIParamsCall

   def update_qos_rule(self, qos_rule_id, body=None):[A52] 

       """Update a new qos rule."""

       return self.put(self.qos_rule_path % qos_rule_id, body=body)

 

   @APIParamsCall

   def list_qos_rules(self, retrieve_all=True, **_params):[A53] 

       """Fetch a list of all new qos rule for atenant."""

       return self.list('qos_rules', self.qos_rules_path,

                         retrieve_all,**_params)

 

   @APIParamsCall

   def show_qos_rule(self, qos_rule_id, **_params):

       """Fetch information of a certain packetfilter."""

       return self.get(self.qos_rule_path % qos_rule_id,

                        params=_params)

   @APIParamsCall

   def delete_qos_rule(self, qos_rule_id):

       """Delete the specified packet filter."""

       return self.delete(self.qos_rule_path % qos_rule_id)

 

6.3    定义shell命令

neutronclient\shell.py

COMMAND_V2 = {

    …

   'nec-packet-filter-delete': packetfilter.DeletePacketFilter,

    'qos-rule-create':qos_rule.CreateQosRule,

    'qos-rule-update':qos_rule.UpdateQosRule,

    'qos-rule-list':qos_rule.ListQosRule,

    'qos-rule-show':qos_rule.ShowQosRule,

    'qos-rule-delete':qos_rule.DeleteQosRule,

[A54] 

 

}

7   打包

7.1    数据库建库代码

neutron-qos\neutron_qos\db\migration\alembic_migrations\versions增加文件

 

kilo_release.py文件,文件内容如下

revision = 'kilo[A55] '

down_revision = 'qos[A56] '

 

 

def upgrade():

   """A no-op migration for marking the Kilorelease."""

Pass

 

neutron-qos\neutron_qos\db\migration\alembic_migrations\versions增加文件

qos.py,文件内容如下:

 

revision = 'qos[A57] '

down_revision = 'start_neutron_qos'

 

from alembic import op

import sqlalchemy as sa

 

def upgrade():

    op.create_table([A58] 

       u'qos_rules',

       sa.Column(u'tenant_id', sa.String(255), nullable=True),

       sa.Column(u'id', sa.String(36), nullable=False),

       sa.Column(u'network_id', sa.String(36), nullable=False),

       sa.Column(u'port_id', sa.String(36), nullable=False),

       sa.Column(u'max_kbps', sa.Integer(), nullable=False),

       sa.Column(u'max_burst_kbps', sa.Integer(), nullable=True),

       sa.PrimaryKeyConstraint(u'id'),

       sa.UniqueConstraint(u'port_id'),

    )

 

   op.create_table(

       u'qosagentbindings',

       sa.Column(u'qos_rule_id', sa.String(36), nullable=False),

       sa.Column(u'agent_id', sa.String(36), nullable=False),

       sa.PrimaryKeyConstraint(u'qos_rule_id'),

       sa.ForeignKeyConstraint([u'qos_rule_id'], [u'qos_rules.id']),

       sa.ForeignKeyConstraint([u'agent_id'], [u'agents.id']),

    )

7.2    代码结构

-neutron-qos

AUTHORS

ChangeLog

MANIFEST.in[A59] 

setup.cfg[A60] 

PKG-INFO

README.rst

Requirements.txt[A61] 

Setup.py

-bin

             neutron-qos-agent

-etc

             neutron-qos-agent.service

       qos_agent.ini

-neutron_qos

-patch

      neutron.tar.gz      

      neutronclient.tar.gz

7.3    MANIFEST.in   

includeREADME.rst

includeChangeLog

includeLICENSE

includeneutron_qos/db/migration/alembic.ini

includeneutron_qos/db/migration/alembic_migrations/versions/qos.py

includeneutron_qos/db/migration/alembic_migrations/versions/kilo_release.py

includeneutron_qos/db/migration/alembic_migrations/versions/ start_neutron_qos.py

[A62] 

includepatch/neutron.tar.gz

includepatch/neutronclient.tar.gz

includeetc/neutron-qos-agent.service

includeetc/qos_agent.ini

includebin/neturon-qos-agent

 

exclude.gitignore

exclude.gitreview

 

global-exclude*.pyc

 

7.4    setup.cfg

[metadata]

name = neutron-qos

version = 1.0.1

summary = OpenStack Networking QOS as aService

description-file =

   README.rst

author = tangjuan

author-email = tangj@s-ec.com

home-page =www.s-ec.com

classifier =

   Environment :: OpenStack

   Intended Audience :: Information Technology

   Intended Audience :: System Administrators

   License :: OSI Approved :: Apache Software License

   Operating System :: POSIX :: Linux

   Programming Language :: Python

   Programming Language :: Python :: 2

   Programming Language :: Python :: 2.7

 

[files]

packages =

    neutron_qos[A63] 

data_files =

    /etc/neutron[A64]  =

       etc/qos_agent.ini

   /usr/lib/systemd/system =

       etc/neutron-qos-agent.service

   /usr/bin =

       bin/neturon-qos-agent

   /tmp=

       patch/neutron.tar.gz

       patch/neutronclient.tar.gz

 

[global]

setup-hooks =

   pbr.hooks.setup_hook

 

[entry_points]

device_drivers=

    ovs=neutron_qos.agent.driver.ovs_driver:QosOVSAgentDriver

console_scripts=

    neutron-qos-agent =neutron_qos.agent.agent:main

[A65] 

 

[wheel]

universal = 1

 

 

7.5    setup.py

try:

   import multiprocessing  # noqa

except ImportError:

   pass

 

setuptools.setup(

   setup_requires=['pbr>=1.3'],

   pbr=True)

7.6    etc/neutron-qos-agent.service

[Unit]

Description=OpenStack Neutron QOS Agent

After=syslog.target network.target

 

[Service]

Type=simple

User=neutron

ExecStart=/usr/bin/neutron-qos-agent--config-file /usr/share/neutron/neutron-dist.conf --config-file/etc/neutron/neutron.conf --config-file /etc/neutron/qos_agent.ini--config-file /etc/neutron/plugins/openvswitch/ovs_neutron_plugin.ini--config-dir /etc/neutron/conf.d/neutron-qos-agent --log-file /var/log/neutron/qos-agent.log

PrivateTmp=false

KillMode=process

 

[Install]

WantedBy=multi-user.target

 

7.7    bin/neturon-qos-agent

 

7.8    制作rpm包

python setup.py  bdist_rpm

 


 [A1]服务类型的定义

 [A2]REST请求url开始的前缀与服务类型的映射,neutron-server会根据前缀查找对应的服务插件完成处理

 [A3]资源的名字,为复数形式,list访问的url为:/扩展的前缀/资源的复数名

Get,delete,update的url:/扩展的前缀/资源的单数名

 [A4]字典定义资源需要的属性

 [A5]扩展文件存放在extensions目录下,类的名字必须与文件名一致,且首字母大写。

 [A6]扩展的别名,在插件的supported_extension_aliases中的名字需要与这个一致

 [A7]如果复数不是简单的为单数后+s,需要指定转换关系。如果policy的复数为polices;special_mappings [A7] = {‘polices’,’ policy’}

 [A8]构建单复数的映射表

 [A9]构造REST处理的controller对象,并对

 [A10]处理扩展服务请求的插件类型

 [A11]必须与扩展描述的defget_resource函数中指定的插件类型一致。

 [A12]这里传递的数据为一个字典,字典的key为资源的单数名,value为资源每个属性的值

 [A13]这里传递的数据为一个字典,字典的key为资源的单数名,value为资源每个属性的值

 [A14]表示有id字段,tenant_id的字段

 [A15]可以指定,不指定时表名为小写类名+s

 [A16]定义一个唯一约束

 [A17]完成资源对象在数据库中添加一条记录

 [A18]从数据库中根据id删除一条资源记录

 [A19]从数据库中查询符合条件的所有记录

 [A20]修改数据库资源的记录

 [A21]从数据库中删除指定资源的记录

 [A22]联合查询agent表

 [A23]更新规则与agent的对应关系

 [A24]将消息通过消息队列发送给指定host的代理,host为代理所在机器的主机名

 [A25]消息名,Agent端需要实现该函数

 [A26]Host为发送该消息的Agent所在机器的主机名

 [A27]名称需要与扩展描述中定义的get_alias返回值一致

 [A28]定义rpc的处理器,qos_const.QOS_AGENT为消息的主题,需要与AEGENT端一致

 [A29]Agent状态更新上报消息的处理器

 [A30]处理agent发送的消息

 [A31]先更新数据库,再查找对应的agent,将消息通过agent_rpc发送到代理

 [A32]先更新数据库,再查找对应的agent,将消息通过agent_rpc发送到代理

 [A33]需要与server端插件连接的callback的主题一致

 [A34]Agent的类型,service在调度查找Agent时会根据类型查找,与service端调度代码一致

 [A35]通过改API上报server端Agent的状态,server端会更新agents表

 [A36]资源名称的单数形式,这个属性会是生成的body对象字典中的key值,服务端需要根据这个key值取出资源的属性值

 [A37]定义创建时需要的字段

 [A38]将命令行传递的参数转为body的内容

 [A39]查询的命令,从neutronv20.ListCommand继承

 [A40]显示的字段

 [A41]是否支持分页

 [A42]是否支持排序

 [A43]更新命令,从neutronv20.UpdateCommand继承

 [A44]显示单个的命令,从neutronv20.ShowCommand继承

 [A45]删除的命令,从neutronv20.DeleteCommand继承

 [A46]为类中定义的resource变量值

 [A47]为类中定义的resource变量值

 [A48]为类中定义的resource变量值

 [A49]为类中定义的resource变量值

 [A50]与neutron常量EXT_TO_SERVICE_MAPPING定义的一致

 [A51]资源的复数形式,与neutron-server中扩展中定义的一致

 [A52]参数个数固定,

 [A53]参数个数固定

 [A54]增加shell命令对应的命令类

 [A55]前一个版本为kilo

 [A56]执行upgrade函数升级到qos版本,会查找下个版本号为qos的升级代码

 [A57]前一个版本为qos,执行upgrade函数后,会查找start_neutron_qos的版本进行升级

 [A58]创建脚本

 [A59]需要打包的数据文件,代码目录下没有__init__.py的目录下的文件将被当作数据文件

 [A60]打包的配置文件

 [A61]依赖的包

 [A62]Versions目录下没有__init__.py文件,默认只当作数据文件,需要指定打包的这个目录下的温条件

 [A63]包的路径

 [A64]数据文件安装的目录

 [A65]entry_ports定义

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值