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 = {
'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,
}
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
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
[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会根据前缀查找对应的服务插件完成处理
[A4]字典定义资源需要的属性
[A5]扩展文件存放在extensions目录下,类的名字必须与文件名一致,且首字母大写。
[A6]扩展的别名,在插件的supported_extension_aliases中的名字需要与这个一致
[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定义