本文地址:http://blog.youkuaiyun.com/spch2008/article/details/9281947
在/usr/share/pyshared/quantum/plugins/openvswitch/ 下创建新包extensions,然后将其连接到/usr/lib/python2.7/dist-packages/quantum/plugins/openvswitch下。
在extensions下创建ovsqos.py,同样需要进行软连接。具体可参见Quantum 数据库增加新表
1. 首先,处理资源属性映射,其实就是对属性进行一些限制。
def convert_to_unsigned_int_or_none(val):
if val is None:
return
try:
val = int(val)
if val < 0:
raise ValueError
except (ValueError, TypeError):
msg = _("'%s' must be a non negative integer.") % val
raise qexception.InvalidInput(error_message=msg)
return val
# Attribute Map
RESOURCE_ATTRIBUTE_MAP = {
'ovsqoss': {
'id': {'allow_post': False, 'allow_put': False,
'is_visible': True,
'primary_key': True},
'name': {'allow_post': True, 'allow_put': True,
'is_visible': True, 'default': '',
'validate': {'type:string': None}},
'rate': {'allow_post': True, 'allow_put': True,
'is_visible': True, 'default': '0',
'convert_to': convert_to_unsigned_int_or_none},
'burst': {'allow_post': True, 'allow_put': True,
'is_visible': True, 'default': '0',
'convert_to': convert_to_unsigned_int_or_none},
'tenant_id': {'allow_post': True, 'allow_put': False,
'required_by_policy': True,
'validate': {'type:string': None},
'is_visible': True},
}
}
convert_to_unsigned_int_or_none将属性值转换成整形。
RESOURCE_ATTRIBUTE_MAP对属性进行制约; allow_put 是否允许用户进行修改,即update; allow_post是否通过用户传来数值进行填充,比如id,
此值为false,如果用户提交过来的数据中有id值,则出错,也就是说id由系统进行分配,不由用户指定;is_visible该属性是否对用户可见,若为false,
用户看不到该值。
2. 同理,qos是port的一个属性,对qos也进行一些限制
OVSQOS = 'ovsqoss'
EXTENDED_ATTRIBUTES_2_0 = {
'ports': {OVSQOS: {'allow_post': True,
'allow_put': True,
'is_visible': True,
'default': attr.ATTR_NOT_SPECIFIED}}}
用户通过quantum port-list, port-update等命令对端口进行修改的时候,ovsqos这个属性是否可以修改,对用户可见等。
3. 最重要的一个类
注意:类名必须与文件同名,且首字母大写。
class Ovsqos(object):
@classmethod
def get_name(cls):
return "ovsqos"
@classmethod
def get_alias(cls):
return "ovsqos"
@classmethod
def get_description(cls):
return "OVS QoS extension."
@classmethod
def get_namespace(cls):
return "http://blog.youkuaiyun.com/spch2008"
@classmethod
def get_updated(cls):
return "2013-06-05T10:00:00-00:00"
@classmethod
def get_resources(cls):
""" Returns Ext Resources """
exts = []
plugin = manager.QuantumManager.get_plugin()
resource_name = 'ovsqos'
collection_name = resource_name.replace('_', '-') + "s"
params = RESOURCE_ATTRIBUTE_MAP.get(resource_name + "s", dict())
controller = base.create_resource(collection_name,
resource_name,
plugin, params, allow_bulk=False)
ex = extensions.ResourceExtension(collection_name,
controller)
exts.append(ex)
return exts
def get_extended_resources(self, version):
if version == "2.0":
return EXTENDED_ATTRIBUTES_2_0
else:
return {}
- get_extended_resources取得扩展属性,然后实际上报告给了(quantum\api\v2\router.py)中的APIRouter的
__init__的ext_mgr.extend_resources("2.0", attributes.RESOURCE_ATTRIBUTE_MAP)
- get_resources 取得资源,用于后续创建路由条目
- get_alias返回一个别名,这个名字很重要。需要在ovs_quantum_plguin.py的OVSQuantumPluginV2属性_supported_extension_aliases
加入该别名
supported_extension_aliases = ["provider", "router", "ovsqos"]
4. quantum\extensions\extensions.py文件的最末尾
def get_extensions_path() 用于取得扩展功能文件,原代码必须使用绝对路径,但是配置文档中给的是相对路径,不一致。
遂将其改为相对路径,代码如下:
def get_extensions_path():
#spch
paths = ':'.join(quantum.extensions.__path__)
#get the prefix path
prefix = "/".join(quantum.__path__[0].split("/")[:-1])
if cfg.CONF.api_extensions_path:
#split the api_extensions_path by ":"
ext_paths = cfg.CONF.api_extensions_path.split(":")
#add prefix for each path
for i in range(len(ext_paths)):
ext_paths[i] = prefix + ext_paths[i]
ext_paths.append(paths)
paths = ":".join(ext_paths)
return paths
5. 将扩展功能写入配置文件中,使得OpenStack系统可以加载qos功能
quantum.conf 中:
api_extensions_path = /quantum/plugins/openvswitch/extensions
完整代码如下:
'''
Created on 2013-6-5
@author: spch2008
'''
from abc import abstractmethod
from quantum.api.v2 import attributes as attr
from quantum.api.v2 import base
from quantum.extensions import extensions
from quantum.common import exceptions as qexception
from quantum import manager
import logging
LOG = logging.getLogger(__name__)
def convert_to_unsigned_int_or_none(val):
if val is None:
return
try:
val = int(val)
if val < 0:
raise ValueError
except (ValueError, TypeError):
msg = _("'%s' must be a non negative integer.") % val
raise qexception.InvalidInput(error_message=msg)
return val
# Attribute Map
RESOURCE_ATTRIBUTE_MAP = {
'ovsqoss': {
'id': {'allow_post': False, 'allow_put': False,
'is_visible': True,
'primary_key': True},
'name': {'allow_post': True, 'allow_put': True,
'is_visible': True, 'default': '',
'validate': {'type:string': None}},
'rate': {'allow_post': True, 'allow_put': True,
'is_visible': True, 'default': '0',
'convert_to': convert_to_unsigned_int_or_none},
'burst': {'allow_post': True, 'allow_put': True,
'is_visible': True, 'default': '0',
'convert_to': convert_to_unsigned_int_or_none},
'tenant_id': {'allow_post': True, 'allow_put': False,
'required_by_policy': True,
'validate': {'type:string': None},
'is_visible': True},
}
}
OVSQOS = 'ovsqoss'
EXTENDED_ATTRIBUTES_2_0 = {
'ports': {OVSQOS: {'allow_post': True,
'allow_put': True,
'is_visible': True,
'default': attr.ATTR_NOT_SPECIFIED}}}
class Ovsqos(object):
@classmethod
def get_name(cls):
return "ovsqos"
@classmethod
def get_alias(cls):
return "ovsqos"
@classmethod
def get_description(cls):
return "OVS QoS extension."
@classmethod
def get_namespace(cls):
return "http://blog.youkuaiyun.com/spch2008"
@classmethod
def get_updated(cls):
return "2013-06-05T10:00:00-00:00"
@classmethod
def get_resources(cls):
""" Returns Ext Resources """
exts = []
plugin = manager.QuantumManager.get_plugin()
resource_name = 'ovsqos'
collection_name = resource_name.replace('_', '-') + "s"
params = RESOURCE_ATTRIBUTE_MAP.get(resource_name + "s", dict())
controller = base.create_resource(collection_name,
resource_name,
plugin, params, allow_bulk=False)
ex = extensions.ResourceExtension(collection_name,
controller)
exts.append(ex)
return exts
def get_extended_resources(self, version):
if version == "2.0":
return EXTENDED_ATTRIBUTES_2_0
else:
return {}
class OVSPluginBase(object):
@abstractmethod
def create_ovsqos(self, context, ovsqos):
pass
@abstractmethod
def get_ovsqoss(self, context, filters, fields):
pass
@abstractmethod
def get_ovsqos(self, context, rule_id, fields):
pass
@abstractmethod
def delete_ovsqos(self, context, rule_id):
pass
@abstractmethod
def update_ovsqos(self, context, rule_id, ovsqos):
pass