neutron添加plugin和extensions
neutron中plugin通常会绑定一个extension,用于实现资源的创建,controller的构建等。plugin分为core和service两种类型,core由openstack配置,主要为network、port、subnet、sbunetpool;我们构建通常为service_plugin。
core_plugin在neutron/plugins/ml2中,service_plugin在neutron/services/** 中。
一. 为neutron添加plugin识别
在neutron中,想要加载自己构建的service_plugin,有两种添加形式:
- 第一种是在neutron/plugins/common/constant.py中DEFAULT_SERVICE_PLUGINS添加自己构建的plugin名。
- 第二种是在/etc/neutron/neutron.conf种的service_plugin添加自己构建的plugin名。
具体举例如下:
# Maps default service plugins entry points to their extension aliases
DEFAULT_SERVICE_PLUGINS = {
'auto_allocate': 'auto-allocated-topology',
'tag': 'tag',
'timestamp': 'timestamp',
'network_ip_availability': 'network-ip-availability',
'flavors': 'flavors',
'revisions': 'revisions',
'peering':'peering', #添加的plugin名
}
二. 在neutron中添加plugin定义
这里主要是让neutron知道我们定义的名字是什么,同时定义plugin的resource_map。
这一部分的定义在/usr/local/lib/python3.10/dist-packages/neutron_lib/api/definitions/中,添加peering.py的定义文件。
# peering.py
from neutron_lib.api import converters
PEERING = 'peering'
SERVICE_PROFILES = 'service_profiles'
NEXT_PROVIDERS = 'next_providers'
PEERINGS = 'peerings'
ALIAS = 'peering'
NAME = 'Neutron Service Peerings'
DESCRIPTION = 'peering speification for Neutron advance services'
API_PREFIX = ''
UPDATED_TIMESTAMP = '2022-12-19T10:00:00-00:00'
RESOURCE_ATTRIBUTE_MAP = {
'peerings' : {
'id': {'allow_post': False, 'allow_put': False,
'validate': {'type:uuid': None},
'is_visible': True, 'primary_key': True},
'name': {'allow_post': True, 'allow_put': True,
'default': '', 'is_visible': True},
'description': {'allow_post': True, 'allow_put': True,
'default': '', 'is_visible': True},
'tenant_id': {'allow_post': True, 'allow_put': False,
'is_visible': False, 'default': False},
'accept_network_id': {'allow_post': True, 'allow_put': False,
'is_visible': True},
'accept_network_name': {'allow_post': True, 'allow_put': False,
'is_visible': True, 'default': ''},
'accept_tenant_id': {'allow_post': True, 'allow_put': False,
'is_visible': True},
'request_network_id': {'allow_post': True, 'allow_put': False,
'is_visible': True},
'request_network_name': {'allow_post': True, 'allow_put': False,
'is_visible': True, 'default': ''},
'request_tenant_id': {'allow_post': True, 'allow_put': False,
'is_visible': True},
'network_type': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'physical_network': {'allow_post': False, 'allow_put': False,
'is_visible': True, 'default': ''},
'segmentation_id': {'allow_post': False, 'allow_put': False,
'is_visible': True},
}
}
SUB_RESOURCE_ATTRIBUTE_MAP = {}
ACTION_MAP = {}
REQUIRED_EXTENSIONS = {}
OPTIONAL_EXTENSIONS = {}
ACTION_STATUS = {}
三. 编写plugin文件
plugin文件需要在/neutron/services/目录下新建plugin目录,这里的新建的目录为/peering。
在/peering目录下需要实现plugin文件和init文件,init文件可以为空,plugin文件实现如下:
#peering_plugin.py
from oslo_config import cfg
from oslo_log import log as logging
from oslo_serialization import jsonutils
from oslo_utils import uuidutils
from neutron.extensions import peering
from neutron_lib.plugins import directory
LOG = logging.getLogger(__name__)
class PeeringPlugin(peering.PeeringPluginBase):
supported_extension_aliases = ['peering']
def __init__(self):
super(PeeringPlugin, self).__init__()
LOG.info('init PeeringPlugin')
#self.type_manager = directory.get_plugin('CORE').type_manager
def get_plugin_description(self):
return "peering plugin------------------------------"
def get_plugin_type(cls):
return 'peering'
def _format_peering_dict_from_db(self):
peering_resp_dict = {
'id': '123',
'name': "peering_test",
'description': "peering test"
}
return peering_resp_dict
def get_peerings(self,context,filters=None,fields=None):
LOG.info("get_peerings")
peering_resp = [self._format_peering_dict_from_db()]
#return peering_resp
return {}
def get_peering(self,context,id,fields=None):
LOG.info("get_peering")
return self._format_peering_dict_from_db()
def create_peering(self,context,peering):
peering = peering['peering']
peering_id = uuidutils-generate_uuid()
peering['id'] = peering_id
LOG.info("create_peering")
return self._format_peering_dict_from_db()
def update_peering(self,context,id,peering):
LOG.info("update_peering")
return self._format_peering_dict_from_db()
def delete_peering(self,context,id):
LOG.info("delete_peering")
return
- PeeringPlugin继承了PeeringPluginBase类,该类定义了PeeringPlugin需要实现的基础的增删改查方法类型,基类在extension文件中定义。
- get_peerings方法不能直接return,返回空会导致api请求无资源,最少返回一个空的字典{}
- plugin的功能放在extension中实现,再通过supported_extension_aliases 绑定对应的extension。
四. 编写extension文件
该文件主要实现了plugin的资源创建,以及定义了plugin的基类。实现如下:
peering.py
import abc
import itertools
import re
from neutron_lib.api import extensions as api_extensions
from neutron_lib.api.definitions import peering as apidef
from neutron_lib.plugins import constants
from neutron_lib.plugins import directory
from neutron_lib.services import base as service_base
import six
from neutron.api import extensions
from neutron.api.v2 import base
from neutron.api.v2 import resource_helper
class Peering(api_extensions.APIExtensionDescriptor):
api_definition = apidef
@classmethod
def get_name(cls):
return 'peering'
@classmethod
def get_alias(cls):
return 'peering'
@classmethod
def get_description(cls):
return 'The peering request extension.'
@classmethod
def get_namespace(cls):
return '****://docs.openstack.org/ext/agent/api/v2.0'
@classmethod
def get_update(cls):
return '2022-12-12T10:00:00:00-00:00'
@classmethod
def get_plugin_interface(cls):
return PeeringPluginBase
@classmethod
def get_resources(cls):
plural_mappings = resource_helper.build_plural_mappings(
{},apidef.RESOURCE_ATTRIBUTE_MAP)
resources = resource_helper.build_resource_info(
plural_mappings,
apidef.RESOURCE_ATTRIBUTE_MAP,
'peering')
return resources
@six.add_metaclass(abc.ABCMeta)
class PeeringPluginBase(service_base.ServicePluginBase):
path_prefix = ''
@classmethod
def get_plugin_type(cls):
return 'peering'
def get_plugin_description(self):
return 'Peering Service Plugin'
@abc.abstractmethod
def get_peerings(self,context,filters=None,fields=None):
pass
@abc.abstractmethod
def get_peering(self,context,id,fields=None):
pass
@abc.abstractmethod
def create_peering(self,context,peering):
pass
@abc.abstractmethod
def update_peering(self,context,id,peering):
pass
@abc.abstractmethod
def delete_peering(self,context,id):
pass
- 实现资源创建和功能的类Peering继承自api_extensions.APIExtensionDescriptor实现了必要的方法,最重要的实现了get_resources方法,该方法创建mapping映射以及resource。
- PeeringPluginBase继承自service_base.ServicePluginBase,主要定义了一个plugin应该实现的类。
五. 为neutron添加plugin入口
最后一部分,为peering添加plugin的入口,这样在api请求来的时候,controller知道从哪里去构建对象。该部分代码位于:/neutron/neutron.egg-info/entry_points.txt中,增加的代码如下:
# entry_points.txt
peering = neutron.services.peering.peering_plugin:PeeringPlugin