自己的项目都是python3.6开发。想使用蓝鲸的流程系统,真是千难万难。魔改路上真是一路坎坷。由于BK-SOPS需要结合蓝鲸的一整套服务才能够运行,所以单独把标准运维的流程系统抽出来然后融合进自己的系统。
看看蓝鲸标准运维的功能
最大的坑,元类。
之前我都不知道元类这个东西是做什么的。一脸懵逼。
元类就是在构建类时候运行的,蓝鲸的组件就是在构建类时候把组件写到一个公共类,然后构造流程时候通过get方法,返回组件类。
from pipeline.component_framework.component import Component
class TestComponent(Component):
name = 'test'
code = 'test'
bound_service = TestService
form = 'test.js'
这就是个标准的test组件。继承Component,看看Component的结构
from pipeline.component_framework.base import ComponentMeta
class Component(object,metaclass=ComponentMeta):
def __init__(self, data_dict):
self.data_dict = data_dict
@classmethod
def outputs_format(cls):
outputs = cls.bound_service().outputs()
outputs = map(lambda oi: oi._asdict(), outputs)
return outputs
def clean_execute_data(self, context):
return self.data_dict
def data_for_execution(self, context, pipeline_data):
data_dict = self.clean_execute_data(context)
inputs = {}
for key, tag_info in data_dict.items():
if tag_info is None:
raise ComponentDataLackException('Lack of inputs: %s' % key)
inputs[key] = get_variable(key, tag_info, context, pipeline_data)
return DataObject(inputs)
def service(self):
return self.bound_service()
坑人的部分就在这里!!这里好像是因为经典类,和新式类的问题导致的
Python2
class Component(object):
__metaclass__ = ComponentMeta
python3
class Component(object,metaclass=ComponentMeta):
研究了好久为什么通过ComponentLibrary获取不到自己定义的组件。ComponentLibrary就是一个组件库,Component类初始化时候会到ComponentLibrary组件库类中,注册的方法就是通过元类,也就是上面的ComponentMeta
class ComponentMeta(type):
def __new__(cls, name, bases, attrs):
super_new = super(ComponentMeta, cls).__new__
# Also ensure initialization is only performed for subclasses of Model
# (excluding Model class itself).
parents = [b for b in bases if isinstance(b, ComponentMeta)]
if not parents:
return super_new(cls, name, bases, attrs)
# Create the class
module_name = attrs.pop('__module__')
new_class = super_new(cls, name, bases, {'__module__': module_name})
module = importlib.import_module(new_class.__module__)
# Add all attributes to the class
attrs.setdefault('desc', '')
for obj_name, obj in attrs.items():
setattr(new_class, obj_name, obj)
# check
if not getattr(new_class, 'name', None):
raise ValueError("component %s name can't be empty" %
new_class.__name__)
if not getattr(new_class, 'code', None):
raise ValueError("component %s code can't be empty" %
new_class.__name__)
if not getattr(new_class, 'bound_service', None) or not issubclass(new_class.bound_service, Service):
raise ValueError("component %s service can't be empty and must be subclass of Service" %
new_class.__name__)
if not getattr(new_class, 'form', None):
setattr(new_class, 'form', None)
# category/group name
group_name = getattr(
module, "__group_name__",
new_class.__module__.split(".")[-1].title()
)
setattr(new_class, 'group_name', group_name)
new_name = u"%s-%s" % (group_name, new_class.name)
# category/group name
group_icon = getattr(
module, "__group_icon__",
''
)
setattr(new_class, 'group_icon', group_icon)
if not getattr(module, '__register_ignore__', False):
# 就是在这里
ComponentLibrary.components[new_class.code] = new_class
# try:
# ComponentModel.objects.update_or_create(
# code=new_class.code,
# defaults={
# 'name': new_name,
# 'status': __debug__,
# }
# )
# except Exception as e:
# if not isinstance(e, ProgrammingError):
# logging.exception(e)
return new_class
下面再看看ComponentLibrary这个东西,很有趣的一种设计方法。
class ComponentLibrary(object):
components = {}
def __new__(cls, *args, **kwargs):
component_code = kwargs.get('component_code', None)
if args:
component_code = args[0]
if not component_code:
raise ValueError('please pass a component_code in args or kwargs: '
'ComponentLibrary(\'code\') or ComponentLibrary(component_code=\'code\')')
if component_code not in cls.components:
raise ComponentNotExistException('component %s does not exist.' %
component_code)
return cls.components[component_code]
@classmethod
def get_component_class(cls, component_code):
return cls.components.get(component_code)
@classmethod
def get_component(cls, component_code, data_dict):
return cls.get_component_class(component_code)(data_dict)
受益匪浅。大牛的设计思想果然牛逼