为 Adjutant 创建功能集¶
Adjutant 支持通过附加功能集引入新的动作、任务和委托 API。功能集是这些元素的集合,可能包含一些特定于功能集的额外配置。这允许公司特定或部署者特定的更改轻松地存在于核心服务之外,并在需要时简单地扩展核心服务。
一个这样的插件示例可以在这里找到(尽管它可能尚未采用新的“功能集”插件机制):https://github.com/catalyst-cloud/adjutant-odoo
一旦你拥有所有要包含在功能集中的动作、任务、委托 API 或通知处理程序,你就可以通过创建一个功能集类来注册它们
from adjutant.feature_set import BaseFeatureSet
from myplugin.actions import MyCustonAction
from myplugin.tasks import MyCustonTask
from myplugin.apis import MyCustonAPI
from myplugin.handlers import MyCustonNotificationHandler
class MyFeatureSet(BaseFeatureSet):
actions = [
MyCustonAction,
]
tasks = [
MyCustonTask,
]
delegate_apis = [
MyCustonAPI,
]
notification_handlers = [
MyCustonNotificationHandler,
]
然后将其添加到库入口点
adjutant.feature_sets =
custom_thing = myplugin.features:MyFeatureSet
如果你的插件需要自定义配置,并且该配置应该在所有动作、任务、API 或通知处理程序中可访问且相同,那么你可以将配置注册到功能集本身
from confspirator import groups
....
class MyFeatureSet(BaseFeatureSet):
.....
config = groups.DynamicNameConfigGroup(
children=[
fields.StrConfig(
'myconfig',
help_text="Some custom config.",
required=True,
default="Stuff",
),
]
)
可以通过 Adjutant 的配置在以下位置访问它:CONF.feature_sets.MyFeatureSet.myconfig
构建委托 API¶
新的委托 API 应该从 adjutant.api.v1.base.BaseDelegateAPI 继承
来自插件的新委托 API 可以通过使用相同的 URL 注册来有效地“覆盖”默认委托 API。但是,它必须具有不同的类名,并且必须从 ACTIVE_DELEGATE_APIS 中删除之前的委托 API。
可以在 adjutant.api.v1.openstack 中找到委托 API 的示例
最少情况下,它们可以如下所示
class MyCustomAPI(BaseDelegateAPI):
url = r'^custom/mycoolstuff/?$'
@utils.authenticated
def post(self, request):
self.task_manager.create_from_request('my_custom_task', request)
return Response({'notes': ['task created']}, status=202)
可以使用在 adjutant.api.utils 中找到的 mod_or_admin、project_admin 和 admin 装饰器来限制访问。请求处理程序是相当标准的 django 视图处理程序,可以执行任何需要的代码。任务的附加信息应放置在 request.data 中。
你还可以通过设置 config_group 为委托 API 添加自定义配置
class MyCustomAPI(BaseDelegateAPI):
url = r'^custom/mycoolstuff/?$'
config_group = groups.DynamicNameConfigGroup(
children=[
fields.StrConfig(
'myconfig',
help_text="Some custom config.",
required=True,
default="Stuff",
),
]
)
构建任务¶
任务必须从 adjutant.tasks.v1.base.BaseTask 派生。可以在 adjutant.tasks.v1 中找到任务示例
最少情况下,任务应该定义它们所需的字段
class My(MyPluginTask):
task_type = "my_custom_task"
default_actions = [
"MyCustomAction",
]
duplicate_policy = "cancel" # default is cancel
然后还有其他可选值可以设置
class My(MyPluginTask):
....
# previous task_types
deprecated_task_types = ['create_project']
# config defaults for the task (used to generate default config):
allow_auto_approve = True
additional_actions = None
token_expiry = None
action_config = None
email_config = None
notification_config = None
构建动作¶
动作必须从 adjutant.actions.v1.base.BaseAction 派生。
序列化器可以继承自 rest_framework.serializers.Serializer,也可以继承自 adjutant.actions.v1.serializers 中的当前序列化器。
可以在 adjutant.actions.v1 中找到动作示例
最少情况下,动作应该定义它们所需的字段并实现 3 个函数
class MyCustomAction(BaseAction):
required = [
'user_id',
'value1',
]
serializer = MyCustomActionSerializer
def _prepare(self):
# Do some validation here
pass
def _approve(self):
# Do some logic here
self.action.task.cache['value'] = self.value1
def _submit(self, token_data, keystone_user=None):
# Do some logic here
self.add_note("Submit action performed")
在动作任务缓存中设置的信息在电子邮件模板下可用:task.cache.value,动作数据在 action.ActionName.value 中可用。
如果需要发送令牌电子邮件,则动作还应实现
def _get_email(self):
return self.keystone_user.email
如果动作不需要外部审批,则此函数应在预审批阶段运行
self.set_auto_approve(True)
如果动作需要令牌,则应在发布审批阶段设置
self.action.need_token = True
self.set_token_fields(["confirm"])
所有动作必须与序列化器配对,以进行基本数据结构检查,但还应在动作期间检查数据有效性。序列化器是 django-rest-framework 序列化器,但 adjutant.actions.v1.serializers 中还有两个基本序列化器可用,BaseUserNameSerializer 和 BaseUserIdSerializer。
动作所需的所有字段必须通过序列化器传递,否则它们将无法被动作访问。
示例
from adjutant.actions.v1.serializers import BaseUserIdSerializer
from rest_framework import serializers
class MyCustomActionSerializer(BaseUserIdSerializer):
value_1 = serializers.CharField()
构建通知处理程序¶
通知处理程序也可以通过插件添加
from adjutant.notifications.models import BaseNotificationHandler
from adjutant.plugins import register_notification_handler
class NewNotificationHandler(BaseNotificationHandler):
config_group = groups.DynamicNameConfigGroup(
children=[
fields.BoolConfig(
"do_this_thing",
help_text="Should we do the thing?",
default=False,
),
]
)
def _notify(self, task, notification):
conf = self.settings(task, notification)
if conf.do_this_thing:
# do something with the task and notification
然后你需要设置处理程序以默认方式用于任务,或用于特定任务
workflow:
task_defaults:
notifications:
standard_handlers:
- NewNotificationHandler
standard_handler_settings:
NewNotificationHandler:
do_this_thing: true
tasks:
some_task:
notifications:
standard_handlers: null
error_handlers:
- NewNotificationHandler
error_handler_settings:
NewNotificationHandler:
do_this_thing: true
使用身份管理器和 Openstack 客户端¶
身份管理器旨在取代对 Keystone 客户端的访问。它可以从 adjutant.actions.user_store.IdentityManager 导入。访问其他 Openstack 客户端的函数位于 adjutant.actions.openstack_clients 中。
未来将对此进行扩展,身份管理器本身也将变得可插拔。