This commit is contained in:
pycook 2023-09-01 18:07:44 +08:00
parent 03f2ff912d
commit 366311e59b
3 changed files with 66 additions and 46 deletions

View File

@ -10,8 +10,11 @@ from api.extensions import db
from api.lib.cmdb.cache import AttributeCache from api.lib.cmdb.cache import AttributeCache
from api.lib.cmdb.cache import CITypeAttributesCache from api.lib.cmdb.cache import CITypeAttributesCache
from api.lib.cmdb.cache import CITypeCache from api.lib.cmdb.cache import CITypeCache
from api.lib.cmdb.const import BUILTIN_KEYWORDS
from api.lib.cmdb.const import CITypeOperateType from api.lib.cmdb.const import CITypeOperateType
from api.lib.cmdb.const import PermEnum, ResourceTypeEnum, RoleEnum from api.lib.cmdb.const import PermEnum
from api.lib.cmdb.const import ResourceTypeEnum
from api.lib.cmdb.const import RoleEnum
from api.lib.cmdb.const import ValueTypeEnum from api.lib.cmdb.const import ValueTypeEnum
from api.lib.cmdb.history import CITypeHistoryManager from api.lib.cmdb.history import CITypeHistoryManager
from api.lib.cmdb.resp_format import ErrFormat from api.lib.cmdb.resp_format import ErrFormat
@ -41,7 +44,7 @@ class AttributeManager(object):
ret_key = choice_web_hook.get('ret_key') ret_key = choice_web_hook.get('ret_key')
headers = choice_web_hook.get('headers') or {} headers = choice_web_hook.get('headers') or {}
payload = choice_web_hook.get('payload') or {} payload = choice_web_hook.get('payload') or {}
method = choice_web_hook.get('method', 'GET').lower() method = (choice_web_hook.get('method') or 'GET').lower()
try: try:
res = getattr(requests, method)(url, headers=headers, data=payload).json() res = getattr(requests, method)(url, headers=headers, data=payload).json()
@ -56,14 +59,16 @@ class AttributeManager(object):
return [[i, {}] for i in (res.get(ret_key_list[-1]) or [])] return [[i, {}] for i in (res.get(ret_key_list[-1]) or [])]
except Exception as e: except Exception as e:
current_app.logger.error(str(e)) current_app.logger.error("get choice values failed: {}".format(e))
return [] return []
@classmethod @classmethod
def get_choice_values(cls, attr_id, value_type, choice_web_hook, choice_web_hook_parse=True): def get_choice_values(cls, attr_id, value_type, choice_web_hook, choice_web_hook_parse=True):
if choice_web_hook and isinstance(choice_web_hook, dict) and choice_web_hook_parse: if choice_web_hook:
if choice_web_hook_parse:
if isinstance(choice_web_hook, dict):
return cls._get_choice_values_from_web_hook(choice_web_hook) return cls._get_choice_values_from_web_hook(choice_web_hook)
elif choice_web_hook and not choice_web_hook_parse: else:
return [] return []
choice_table = ValueTypeMap.choice.get(value_type) choice_table = ValueTypeMap.choice.get(value_type)
@ -74,26 +79,25 @@ class AttributeManager(object):
@staticmethod @staticmethod
def add_choice_values(_id, value_type, choice_values): def add_choice_values(_id, value_type, choice_values):
choice_table = ValueTypeMap.choice.get(value_type) choice_table = ValueTypeMap.choice.get(value_type)
if choice_table is None:
return
choice_table.get_by(attr_id=_id, only_query=True).delete()
db.session.query(choice_table).filter(choice_table.attr_id == _id).delete()
db.session.flush()
choice_values = choice_values
for v, option in choice_values: for v, option in choice_values:
table = choice_table(attr_id=_id, value=v, option=option) choice_table.create(attr_id=_id, value=v, option=option, commit=False)
db.session.add(table)
try: try:
db.session.flush() db.session.flush()
except: except Exception as e:
current_app.logger.warning("add choice values failed: {}".format(e))
return abort(400, ErrFormat.invalid_choice_values) return abort(400, ErrFormat.invalid_choice_values)
@staticmethod @staticmethod
def _del_choice_values(_id, value_type): def _del_choice_values(_id, value_type):
choice_table = ValueTypeMap.choice.get(value_type) choice_table = ValueTypeMap.choice.get(value_type)
if choice_table is not None: choice_table and choice_table.get_by(attr_id=_id, only_query=True).delete()
db.session.query(choice_table).filter(choice_table.attr_id == _id).delete()
db.session.flush() db.session.flush()
@classmethod @classmethod
@ -116,8 +120,8 @@ class AttributeManager(object):
attrs = attrs[(page - 1) * page_size:][:page_size] attrs = attrs[(page - 1) * page_size:][:page_size]
res = list() res = list()
for attr in attrs: for attr in attrs:
attr["is_choice"] and attr.update(dict(choice_value=cls.get_choice_values( attr["is_choice"] and attr.update(
attr["id"], attr["value_type"], attr["choice_web_hook"]))) dict(choice_value=cls.get_choice_values(attr["id"], attr["value_type"], attr["choice_web_hook"])))
attr['is_choice'] and attr.pop('choice_web_hook', None) attr['is_choice'] and attr.pop('choice_web_hook', None)
res.append(attr) res.append(attr)
@ -126,30 +130,31 @@ class AttributeManager(object):
def get_attribute_by_name(self, name): def get_attribute_by_name(self, name):
attr = Attribute.get_by(name=name, first=True) attr = Attribute.get_by(name=name, first=True)
if attr and attr["is_choice"]: if attr.get("is_choice"):
attr.update(dict(choice_value=self.get_choice_values( attr["choice_value"] = self.get_choice_values(attr["id"], attr["value_type"], attr["choice_web_hook"])
attr["id"], attr["value_type"], attr["choice_web_hook"])))
return attr return attr
def get_attribute_by_alias(self, alias): def get_attribute_by_alias(self, alias):
attr = Attribute.get_by(alias=alias, first=True) attr = Attribute.get_by(alias=alias, first=True)
if attr and attr["is_choice"]: if attr.get("is_choice"):
attr.update(dict(choice_value=self.get_choice_values( attr["choice_value"] = self.get_choice_values(attr["id"], attr["value_type"], attr["choice_web_hook"])
attr["id"], attr["value_type"], attr["choice_web_hook"])))
return attr return attr
def get_attribute_by_id(self, _id): def get_attribute_by_id(self, _id):
attr = Attribute.get_by_id(_id).to_dict() attr = Attribute.get_by_id(_id).to_dict()
if attr and attr["is_choice"]: if attr.get("is_choice"):
attr.update(dict(choice_value=self.get_choice_values( attr["choice_value"] = self.get_choice_values(attr["id"], attr["value_type"], attr["choice_web_hook"])
attr["id"], attr["value_type"], attr["choice_web_hook"])))
return attr return attr
def get_attribute(self, key, choice_web_hook_parse=True): def get_attribute(self, key, choice_web_hook_parse=True):
attr = AttributeCache.get(key).to_dict() attr = AttributeCache.get(key).to_dict()
if attr and attr["is_choice"]: if attr.get("is_choice"):
attr.update(dict(choice_value=self.get_choice_values( attr["choice_value"] = self.get_choice_values(
attr["id"], attr["value_type"], attr["choice_web_hook"])), choice_web_hook_parse=choice_web_hook_parse) attr["id"], attr["value_type"], attr["choice_web_hook"], choice_web_hook_parse=choice_web_hook_parse)
return attr return attr
@staticmethod @staticmethod
@ -165,8 +170,9 @@ class AttributeManager(object):
is_choice = True if choice_value or kwargs.get('choice_web_hook') else False is_choice = True if choice_value or kwargs.get('choice_web_hook') else False
name = kwargs.pop("name") name = kwargs.pop("name")
if name in {'id', '_id', 'ci_id', 'type', '_type', 'ci_type'}: if name in BUILTIN_KEYWORDS:
return abort(400, ErrFormat.attribute_name_cannot_be_builtin) return abort(400, ErrFormat.attribute_name_cannot_be_builtin)
alias = kwargs.pop("alias", "") alias = kwargs.pop("alias", "")
alias = name if not alias else alias alias = name if not alias else alias
Attribute.get_by(name=name, first=True) and abort(400, ErrFormat.attribute_name_duplicate.format(name)) Attribute.get_by(name=name, first=True) and abort(400, ErrFormat.attribute_name_duplicate.format(name))
@ -219,7 +225,8 @@ class AttributeManager(object):
for i in CITypeAttribute.get_by(attr_id=attr_id, to_dict=False): for i in CITypeAttribute.get_by(attr_id=attr_id, to_dict=False):
CITypeAttributesCache.clean(i.type_id) CITypeAttributesCache.clean(i.type_id)
def _change_index(self, attr, old, new): @staticmethod
def _change_index(attr, old, new):
from api.lib.cmdb.utils import TableMap from api.lib.cmdb.utils import TableMap
from api.tasks.cmdb import batch_ci_cache from api.tasks.cmdb import batch_ci_cache
from api.lib.cmdb.const import CMDB_QUEUE from api.lib.cmdb.const import CMDB_QUEUE
@ -228,11 +235,11 @@ class AttributeManager(object):
new_table = TableMap(attr=attr, is_index=new).table new_table = TableMap(attr=attr, is_index=new).table
ci_ids = [] ci_ids = []
for i in db.session.query(old_table).filter(getattr(old_table, 'attr_id') == attr.id): for i in old_table.get_by(attr_id=attr.id, to_dict=False):
new_table.create(ci_id=i.ci_id, attr_id=attr.id, value=i.value, flush=True) new_table.create(ci_id=i.ci_id, attr_id=attr.id, value=i.value, flush=True)
ci_ids.append(i.ci_id) ci_ids.append(i.ci_id)
db.session.query(old_table).filter(getattr(old_table, 'attr_id') == attr.id).delete() old_table.get_by(attr_id=attr.id, only_query=True).delete()
try: try:
db.session.commit() db.session.commit()
@ -331,24 +338,25 @@ class AttributeManager(object):
ref = CITypeAttribute.get_by(attr_id=_id, to_dict=False, first=True) ref = CITypeAttribute.get_by(attr_id=_id, to_dict=False, first=True)
if ref is not None: if ref is not None:
ci_type = CITypeCache.get(ref.type_id) ci_type = CITypeCache.get(ref.type_id)
return abort(400, ErrFormat.attribute_is_ref_by_type.format(ci_type.alias)) return abort(400, ErrFormat.attribute_is_ref_by_type.format(ci_type and ci_type.alias or ref.type_id))
if attr.uid != current_user.uid and not is_app_admin('cmdb'): if attr.uid != current_user.uid and not is_app_admin('cmdb'):
return abort(403, ErrFormat.cannot_delete_attribute) return abort(403, ErrFormat.cannot_delete_attribute)
if attr.is_choice: if attr.is_choice:
choice_table = ValueTypeMap.choice.get(attr.value_type) choice_table = ValueTypeMap.choice.get(attr.value_type)
db.session.query(choice_table).filter(choice_table.attr_id == _id).delete() # FIXME: session conflict choice_table.get_by(attr_id=_id, only_query=True).delete()
db.session.flush()
AttributeCache.clean(attr)
attr.soft_delete() attr.soft_delete()
AttributeCache.clean(attr)
for i in PreferenceShowAttributes.get_by(attr_id=_id, to_dict=False): for i in PreferenceShowAttributes.get_by(attr_id=_id, to_dict=False):
i.soft_delete() i.soft_delete(commit=False)
for i in CITypeAttributeGroupItem.get_by(attr_id=_id, to_dict=False): for i in CITypeAttributeGroupItem.get_by(attr_id=_id, to_dict=False):
i.soft_delete() i.soft_delete(commit=False)
db.session.commit()
return name return name

View File

@ -34,6 +34,7 @@ class AttributeCache(object):
attr = attr or Attribute.get_by(alias=key, first=True, to_dict=False) attr = attr or Attribute.get_by(alias=key, first=True, to_dict=False)
if attr is not None: if attr is not None:
cls.set(attr) cls.set(attr)
return attr return attr
@classmethod @classmethod
@ -67,6 +68,7 @@ class CITypeCache(object):
ct = ct or CIType.get_by(alias=key, first=True, to_dict=False) ct = ct or CIType.get_by(alias=key, first=True, to_dict=False)
if ct is not None: if ct is not None:
cls.set(ct) cls.set(ct)
return ct return ct
@classmethod @classmethod
@ -98,6 +100,7 @@ class RelationTypeCache(object):
ct = RelationType.get_by(name=key, first=True, to_dict=False) or RelationType.get_by_id(key) ct = RelationType.get_by(name=key, first=True, to_dict=False) or RelationType.get_by_id(key)
if ct is not None: if ct is not None:
cls.set(ct) cls.set(ct)
return ct return ct
@classmethod @classmethod
@ -133,12 +136,15 @@ class CITypeAttributesCache(object):
attrs = attrs or cache.get(cls.PREFIX_ID.format(key)) attrs = attrs or cache.get(cls.PREFIX_ID.format(key))
if not attrs: if not attrs:
attrs = CITypeAttribute.get_by(type_id=key, to_dict=False) attrs = CITypeAttribute.get_by(type_id=key, to_dict=False)
if not attrs: if not attrs:
ci_type = CIType.get_by(name=key, first=True, to_dict=False) ci_type = CIType.get_by(name=key, first=True, to_dict=False)
if ci_type is not None: if ci_type is not None:
attrs = CITypeAttribute.get_by(type_id=ci_type.id, to_dict=False) attrs = CITypeAttribute.get_by(type_id=ci_type.id, to_dict=False)
if attrs is not None: if attrs is not None:
cls.set(key, attrs) cls.set(key, attrs)
return attrs return attrs
@classmethod @classmethod
@ -155,13 +161,16 @@ class CITypeAttributesCache(object):
attrs = attrs or cache.get(cls.PREFIX_ID2.format(key)) attrs = attrs or cache.get(cls.PREFIX_ID2.format(key))
if not attrs: if not attrs:
attrs = CITypeAttribute.get_by(type_id=key, to_dict=False) attrs = CITypeAttribute.get_by(type_id=key, to_dict=False)
if not attrs: if not attrs:
ci_type = CIType.get_by(name=key, first=True, to_dict=False) ci_type = CIType.get_by(name=key, first=True, to_dict=False)
if ci_type is not None: if ci_type is not None:
attrs = CITypeAttribute.get_by(type_id=ci_type.id, to_dict=False) attrs = CITypeAttribute.get_by(type_id=ci_type.id, to_dict=False)
if attrs is not None: if attrs is not None:
attrs = [(i, AttributeCache.get(i.attr_id)) for i in attrs] attrs = [(i, AttributeCache.get(i.attr_id)) for i in attrs]
cls.set2(key, attrs) cls.set2(key, attrs)
return attrs return attrs
@classmethod @classmethod
@ -204,10 +213,11 @@ class CITypeAttributeCache(object):
attr = cache.get(cls.PREFIX_ID.format(type_id, attr_id)) attr = cache.get(cls.PREFIX_ID.format(type_id, attr_id))
attr = attr or cache.get(cls.PREFIX_ID.format(type_id, attr_id)) attr = attr or cache.get(cls.PREFIX_ID.format(type_id, attr_id))
if not attr: attr = attr or CITypeAttribute.get_by(type_id=type_id, attr_id=attr_id, first=True, to_dict=False)
attr = CITypeAttribute.get_by(type_id=type_id, attr_id=attr_id, first=True, to_dict=False)
if attr is not None: if attr is not None:
cls.set(type_id, attr_id, attr) cls.set(type_id, attr_id, attr)
return attr return attr
@classmethod @classmethod

View File

@ -99,5 +99,7 @@ CMDB_QUEUE = "one_cmdb_async"
REDIS_PREFIX_CI = "ONE_CMDB" REDIS_PREFIX_CI = "ONE_CMDB"
REDIS_PREFIX_CI_RELATION = "CMDB_CI_RELATION" REDIS_PREFIX_CI_RELATION = "CMDB_CI_RELATION"
BUILTIN_KEYWORDS = {'id', '_id', 'ci_id', 'type', '_type', 'ci_type'}
L_TYPE = None L_TYPE = None
L_CI = None L_CI = None