Realize /api/v0.1/ci_relations/s [done]

This commit is contained in:
pycook 2019-11-21 18:21:03 +08:00
parent bc7b51c544
commit 31a97d7ad0
24 changed files with 451 additions and 229 deletions

View File

@ -10,7 +10,11 @@ from flask.cli import with_appcontext
import api.lib.cmdb.ci import api.lib.cmdb.ci
from api.extensions import db from api.extensions import db
from api.extensions import rd from api.extensions import rd
from api.lib.cmdb.const import REDIS_PREFIX_CI
from api.lib.cmdb.const import REDIS_PREFIX_CI_RELATION
from api.lib.cmdb.const import ValueTypeEnum
from api.models.cmdb import CI from api.models.cmdb import CI
from api.models.cmdb import CIRelation
@click.command() @click.command()
@ -21,12 +25,12 @@ def init_cache():
if current_app.config.get("USE_ES"): if current_app.config.get("USE_ES"):
from api.extensions import es from api.extensions import es
from api.models.cmdb import Attribute from api.models.cmdb import Attribute
from api.lib.cmdb.const import type_map from api.lib.cmdb.utils import ValueTypeMap
attributes = Attribute.get_by(to_dict=False) attributes = Attribute.get_by(to_dict=False)
for attr in attributes: for attr in attributes:
other = dict() other = dict()
other['index'] = True if attr.is_index else False other['index'] = True if attr.is_index else False
if attr.value_type == Attribute.TEXT: if attr.value_type == ValueTypeEnum.TEXT:
other['analyzer'] = 'ik_max_word' other['analyzer'] = 'ik_max_word'
other['search_analyzer'] = 'ik_smart' other['search_analyzer'] = 'ik_smart'
if attr.is_index: if attr.is_index:
@ -37,7 +41,7 @@ def init_cache():
} }
} }
try: try:
es.update_mapping(attr.name, type_map['es_type'][attr.value_type], other) es.update_mapping(attr.name, ValueTypeMap.es_type[attr.value_type], other)
except Exception as e: except Exception as e:
print(e) print(e)
@ -48,7 +52,7 @@ def init_cache():
if res: if res:
continue continue
else: else:
res = rd.get([ci.id]) res = rd.get([ci.id], REDIS_PREFIX_CI)
if res and list(filter(lambda x: x, res)): if res and list(filter(lambda x: x, res)):
continue continue
@ -58,7 +62,15 @@ def init_cache():
if current_app.config.get("USE_ES"): if current_app.config.get("USE_ES"):
es.create(ci_dict) es.create(ci_dict)
else: else:
rd.delete(ci.id) rd.create_or_update({ci.id: json.dumps(ci_dict)}, REDIS_PREFIX_CI)
rd.add({ci.id: json.dumps(ci_dict)})
ci_relations = CIRelation.get_by(to_dict=False)
relations = dict()
for cr in ci_relations:
relations.setdefault(cr.first_ci_id, []).append(cr.second_ci_id)
for i in relations:
relations[i] = json.dumps(relations[i])
if relations:
rd.create_or_update(relations, REDIS_PREFIX_CI_RELATION)
db.session.remove() db.session.remove()

View File

@ -19,5 +19,5 @@ migrate = Migrate()
cache = Cache() cache = Cache()
celery = Celery() celery = Celery()
cors = CORS(supports_credentials=True) cors = CORS(supports_credentials=True)
rd = RedisHandler(prefix="CMDB_CI") # TODO rd = RedisHandler()
es = ESHandler() es = ESHandler()

View File

@ -5,7 +5,8 @@ from flask import current_app
from api.extensions import db from api.extensions import db
from api.lib.cmdb.cache import AttributeCache from api.lib.cmdb.cache import AttributeCache
from api.lib.cmdb.const import type_map from api.lib.cmdb.const import ValueTypeEnum
from api.lib.cmdb.utils import ValueTypeMap
from api.lib.decorator import kwargs_required from api.lib.decorator import kwargs_required
from api.models.cmdb import Attribute from api.models.cmdb import Attribute
from api.models.cmdb import CITypeAttribute from api.models.cmdb import CITypeAttribute
@ -22,13 +23,13 @@ class AttributeManager(object):
@staticmethod @staticmethod
def get_choice_values(attr_id, value_type): def get_choice_values(attr_id, value_type):
choice_table = type_map.get("choice").get(value_type) choice_table = ValueTypeMap.choice.get(value_type)
choice_values = choice_table.get_by(fl=["value"], attr_id=attr_id) choice_values = choice_table.get_by(fl=["value"], attr_id=attr_id)
return [choice_value["value"] for choice_value in choice_values] return [choice_value["value"] for choice_value in choice_values]
@staticmethod @staticmethod
def _add_choice_values(_id, value_type, choice_values): def _add_choice_values(_id, value_type, choice_values):
choice_table = type_map.get("choice").get(value_type) choice_table = ValueTypeMap.choice.get(value_type)
db.session.query(choice_table).filter(choice_table.attr_id == _id).delete() db.session.query(choice_table).filter(choice_table.attr_id == _id).delete()
db.session.flush() db.session.flush()
@ -121,7 +122,7 @@ class AttributeManager(object):
from api.extensions import es from api.extensions import es
other = dict() other = dict()
other['index'] = True if attr.is_index else False other['index'] = True if attr.is_index else False
if attr.value_type == Attribute.TEXT: if attr.value_type == ValueTypeEnum.TEXT:
other['analyzer'] = 'ik_max_word' other['analyzer'] = 'ik_max_word'
other['search_analyzer'] = 'ik_smart' other['search_analyzer'] = 'ik_smart'
if attr.is_index: if attr.is_index:
@ -131,7 +132,7 @@ class AttributeManager(object):
"ignore_above": 256 "ignore_above": 256
} }
} }
es.update_mapping(name, type_map['es_type'][attr.value_type], other) es.update_mapping(name, ValueTypeMap.es_type[attr.value_type], other)
return attr.id return attr.id
@ -172,7 +173,7 @@ class AttributeManager(object):
name = attr.name name = attr.name
if attr.is_choice: if attr.is_choice:
choice_table = type_map["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 db.session.query(choice_table).filter(choice_table.attr_id == _id).delete() # FIXME: session conflict
db.session.flush() db.session.flush()

View File

@ -18,13 +18,14 @@ from api.lib.cmdb.ci_type import CITypeManager
from api.lib.cmdb.const import CMDB_QUEUE from api.lib.cmdb.const import CMDB_QUEUE
from api.lib.cmdb.const import ExistPolicy from api.lib.cmdb.const import ExistPolicy
from api.lib.cmdb.const import OperateType from api.lib.cmdb.const import OperateType
from api.lib.cmdb.const import REDIS_PREFIX_CI
from api.lib.cmdb.const import RetKey from api.lib.cmdb.const import RetKey
from api.lib.cmdb.const import TableMap
from api.lib.cmdb.const import type_map
from api.lib.cmdb.history import AttributeHistoryManger from api.lib.cmdb.history import AttributeHistoryManger
from api.lib.cmdb.history import CIRelationHistoryManager from api.lib.cmdb.history import CIRelationHistoryManager
from api.lib.cmdb.search.db.query_sql import QUERY_CIS_BY_IDS from api.lib.cmdb.search.ci.db.query_sql import QUERY_CIS_BY_IDS
from api.lib.cmdb.search.db.query_sql import QUERY_CIS_BY_VALUE_TABLE from api.lib.cmdb.search.ci.db.query_sql import QUERY_CIS_BY_VALUE_TABLE
from api.lib.cmdb.utils import TableMap
from api.lib.cmdb.utils import ValueTypeMap
from api.lib.cmdb.value import AttributeValueManager from api.lib.cmdb.value import AttributeValueManager
from api.lib.decorator import kwargs_required from api.lib.decorator import kwargs_required
from api.lib.utils import handle_arg_list from api.lib.utils import handle_arg_list
@ -33,6 +34,8 @@ from api.models.cmdb import CIRelation
from api.models.cmdb import CITypeAttribute from api.models.cmdb import CITypeAttribute
from api.tasks.cmdb import ci_cache from api.tasks.cmdb import ci_cache
from api.tasks.cmdb import ci_delete from api.tasks.cmdb import ci_delete
from api.tasks.cmdb import ci_relation_cache
from api.tasks.cmdb import ci_relation_delete
class CIManager(object): class CIManager(object):
@ -302,7 +305,7 @@ class CIManager(object):
@staticmethod @staticmethod
def _get_cis_from_cache(ci_ids, ret_key=RetKey.NAME, fields=None): def _get_cis_from_cache(ci_ids, ret_key=RetKey.NAME, fields=None):
res = rd.get(ci_ids) res = rd.get(ci_ids, REDIS_PREFIX_CI)
if res is not None and None not in res and ret_key == RetKey.NAME: if res is not None and None not in res and ret_key == RetKey.NAME:
res = list(map(json.loads, res)) res = list(map(json.loads, res))
if not fields: if not fields:
@ -332,7 +335,7 @@ class CIManager(object):
ci_ids = ",".join(ci_ids) ci_ids = ",".join(ci_ids)
if value_tables is None: if value_tables is None:
value_tables = type_map["table_name"].values() value_tables = ValueTypeMap.table_name.values()
value_sql = " UNION ".join([QUERY_CIS_BY_VALUE_TABLE.format(value_table, ci_ids) value_sql = " UNION ".join([QUERY_CIS_BY_VALUE_TABLE.format(value_table, ci_ids)
for value_table in value_tables]) for value_table in value_tables])
@ -362,7 +365,7 @@ class CIManager(object):
else: else:
return abort(400, "invalid ret key") return abort(400, "invalid ret key")
value = type_map["serialize2"][value_type](value) value = ValueTypeMap.serialize2[value_type](value)
if is_list: if is_list:
ci_dict.setdefault(attr_key, []).append(value) ci_dict.setdefault(attr_key, []).append(value)
else: else:
@ -532,6 +535,9 @@ class CIRelationManager(object):
second_ci_id=second_ci_id, second_ci_id=second_ci_id,
relation_type_id=relation_type_id) relation_type_id=relation_type_id)
CIRelationHistoryManager().add(existed, OperateType.ADD) CIRelationHistoryManager().add(existed, OperateType.ADD)
ci_relation_cache.apply_async(args=(first_ci_id, second_ci_id), queue=CMDB_QUEUE)
if more is not None: if more is not None:
existed.upadte(more=more) existed.upadte(more=more)
@ -545,6 +551,8 @@ class CIRelationManager(object):
his_manager = CIRelationHistoryManager() his_manager = CIRelationHistoryManager()
his_manager.add(cr, operate_type=OperateType.DELETE) his_manager.add(cr, operate_type=OperateType.DELETE)
ci_relation_delete.apply_async(args=(cr.first_ci_id, cr.second_ci_id), queue=CMDB_QUEUE)
return cr_id return cr_id
@classmethod @classmethod
@ -553,4 +561,7 @@ class CIRelationManager(object):
second_ci_id=second_ci_id, second_ci_id=second_ci_id,
to_dict=False, to_dict=False,
first=True) first=True)
ci_relation_delete.apply_async(args=(first_ci_id, second_ci_id), queue=CMDB_QUEUE)
return cls.delete(cr.cr_id) return cls.delete(cr.cr_id)

View File

@ -4,6 +4,7 @@
from flask import abort from flask import abort
from flask import current_app from flask import current_app
from api.extensions import db
from api.lib.cmdb.attribute import AttributeManager from api.lib.cmdb.attribute import AttributeManager
from api.lib.cmdb.cache import AttributeCache from api.lib.cmdb.cache import AttributeCache
from api.lib.cmdb.cache import CITypeAttributeCache from api.lib.cmdb.cache import CITypeAttributeCache
@ -263,8 +264,26 @@ class CITypeRelationManager(object):
manage relation between CITypes manage relation between CITypes
""" """
def __init__(self): @staticmethod
pass def get():
res = CITypeRelation.get_by(to_dict=False)
for idx, item in enumerate(res):
_item = item.to_dict()
res[idx] = _item
res[idx]['parent'] = item.parent.to_dict()
res[idx]['child'] = item.child.to_dict()
res[idx]['relation_type'] = item.relation_type.to_dict()
return res
@staticmethod
def get_child_type_ids(type_id, level):
ids = [type_id]
query = db.session.query(CITypeRelation).filter(CITypeRelation.deleted.is_(False))
for _ in range(0, level):
ids = [i.child_id for i in query.filter(CITypeRelation.parent_id.in_(ids))]
return ids
@staticmethod @staticmethod
def _wrap_relation_type_dict(type_id, relation_inst): def _wrap_relation_type_dict(type_id, relation_inst):

View File

@ -1,160 +1,57 @@
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*-
from __future__ import unicode_literals from api.lib.utils import BaseEnum
import datetime
import six
from markupsafe import escape
from api.lib.cmdb.cache import AttributeCache
from api.models.cmdb import Attribute
from api.models.cmdb import CIIndexValueDateTime
from api.models.cmdb import CIIndexValueFloat
from api.models.cmdb import CIIndexValueInteger
from api.models.cmdb import CIIndexValueText
from api.models.cmdb import CIValueDateTime
from api.models.cmdb import CIValueFloat
from api.models.cmdb import CIValueInteger
from api.models.cmdb import CIValueText
from api.models.cmdb import FloatChoice
from api.models.cmdb import IntegerChoice
from api.models.cmdb import TextChoice
def string2int(x): class ValueTypeEnum(BaseEnum):
return int(float(x)) INT = "0"
FLOAT = "1"
TEXT = "2"
DATETIME = "3"
DATE = "4"
TIME = "5"
def str2datetime(x): class CIStatusEnum(BaseEnum):
try: REVIEW = "0"
return datetime.datetime.strptime(x, "%Y-%m-%d") VALIDATE = "1"
except ValueError:
pass
return datetime.datetime.strptime(x, "%Y-%m-%d %H:%M:%S")
type_map = { class ExistPolicy(BaseEnum):
'deserialize': {
Attribute.INT: string2int,
Attribute.FLOAT: float,
Attribute.TEXT: lambda x: escape(x).encode('utf-8').decode('utf-8'),
Attribute.TIME: lambda x: escape(x).encode('utf-8').decode('utf-8'),
Attribute.DATETIME: str2datetime,
Attribute.DATE: str2datetime,
},
'serialize': {
Attribute.INT: int,
Attribute.FLOAT: float,
Attribute.TEXT: lambda x: x if isinstance(x, six.text_type) else str(x),
Attribute.TIME: lambda x: x if isinstance(x, six.text_type) else str(x),
Attribute.DATE: lambda x: x.strftime("%Y-%m-%d"),
Attribute.DATETIME: lambda x: x.strftime("%Y-%m-%d %H:%M:%S"),
},
'serialize2': {
Attribute.INT: int,
Attribute.FLOAT: float,
Attribute.TEXT: lambda x: x.decode() if not isinstance(x, six.string_types) else x,
Attribute.TIME: lambda x: x.decode() if not isinstance(x, six.string_types) else x,
Attribute.DATE: lambda x: x.decode() if not isinstance(x, six.string_types) else x,
Attribute.DATETIME: lambda x: x.decode() if not isinstance(x, six.string_types) else x,
},
'choice': {
Attribute.INT: IntegerChoice,
Attribute.FLOAT: FloatChoice,
Attribute.TEXT: TextChoice,
},
'table': {
Attribute.INT: CIValueInteger,
Attribute.TEXT: CIValueText,
Attribute.DATETIME: CIValueDateTime,
Attribute.DATE: CIValueDateTime,
Attribute.TIME: CIValueText,
Attribute.FLOAT: CIValueFloat,
'index_{0}'.format(Attribute.INT): CIIndexValueInteger,
'index_{0}'.format(Attribute.TEXT): CIIndexValueText,
'index_{0}'.format(Attribute.DATETIME): CIIndexValueDateTime,
'index_{0}'.format(Attribute.DATE): CIIndexValueDateTime,
'index_{0}'.format(Attribute.TIME): CIIndexValueText,
'index_{0}'.format(Attribute.FLOAT): CIIndexValueFloat,
},
'table_name': {
Attribute.INT: 'c_value_integers',
Attribute.TEXT: 'c_value_texts',
Attribute.DATETIME: 'c_value_datetime',
Attribute.DATE: 'c_value_datetime',
Attribute.TIME: 'c_value_texts',
Attribute.FLOAT: 'c_value_floats',
'index_{0}'.format(Attribute.INT): 'c_value_index_integers',
'index_{0}'.format(Attribute.TEXT): 'c_value_index_texts',
'index_{0}'.format(Attribute.DATETIME): 'c_value_index_datetime',
'index_{0}'.format(Attribute.DATE): 'c_value_index_datetime',
'index_{0}'.format(Attribute.TIME): 'c_value_index_texts',
'index_{0}'.format(Attribute.FLOAT): 'c_value_index_floats',
},
'es_type': {
Attribute.INT: 'long',
Attribute.TEXT: 'text',
Attribute.DATETIME: 'text',
Attribute.DATE: 'text',
Attribute.TIME: 'text',
Attribute.FLOAT: 'float'
}
}
class TableMap(object):
def __init__(self, attr_name=None):
self.attr_name = attr_name
@property
def table(self):
attr = AttributeCache.get(self.attr_name)
i = "index_{0}".format(attr.value_type) if attr.is_index else attr.value_type
return type_map["table"].get(i)
@property
def table_name(self):
attr = AttributeCache.get(self.attr_name)
i = "index_{0}".format(attr.value_type) if attr.is_index else attr.value_type
return type_map["table_name"].get(i)
class ExistPolicy(object):
REJECT = "reject" REJECT = "reject"
NEED = "need" NEED = "need"
IGNORE = "ignore" IGNORE = "ignore"
REPLACE = "replace" REPLACE = "replace"
class OperateType(object): class OperateType(BaseEnum):
ADD = "0" ADD = "0"
DELETE = "1" DELETE = "1"
UPDATE = "2" UPDATE = "2"
class RetKey(object): class RetKey(BaseEnum):
ID = "id" ID = "id"
NAME = "name" NAME = "name"
ALIAS = "alias" ALIAS = "alias"
class ResourceType(object): class ResourceType(BaseEnum):
CI = "CIType" CI = "CIType"
class PermEnum(object): class PermEnum(BaseEnum):
ADD = "add" ADD = "add"
UPDATE = "update" UPDATE = "update"
DELETE = "delete" DELETE = "delete"
READ = "read" READ = "read"
class RoleEnum(object): class RoleEnum(BaseEnum):
CONFIG = "admin" CONFIG = "admin"
CMDB_QUEUE = "cmdb_async" CMDB_QUEUE = "cmdb_async"
REDIS_PREFIX = "CMDB_CI" REDIS_PREFIX_CI = "CMDB_CI"
REDIS_PREFIX_CI_RELATION = "CMDB_CI_RELATION"

View File

@ -7,6 +7,7 @@ from flask import g
from api.extensions import db 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 RelationTypeCache from api.lib.cmdb.cache import RelationTypeCache
from api.lib.cmdb.const import OperateType
from api.lib.perm.acl.cache import UserCache from api.lib.perm.acl.cache import UserCache
from api.models.cmdb import Attribute from api.models.cmdb import Attribute
from api.models.cmdb import AttributeHistory from api.models.cmdb import AttributeHistory
@ -112,7 +113,7 @@ class AttributeHistoryManger(object):
class CIRelationHistoryManager(object): class CIRelationHistoryManager(object):
@staticmethod @staticmethod
def add(rel_obj, operate_type=CIRelationHistory.ADD): def add(rel_obj, operate_type=OperateType.ADD):
record = OperationRecord.create(uid=g.user.uid) record = OperationRecord.create(uid=g.user.uid)
CIRelationHistory.create(relation_id=rel_obj.id, CIRelationHistory.create(relation_id=rel_obj.id,

View File

@ -1,3 +1,11 @@
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*-
__all__ = ['db', 'es'] __all__ = ['ci', 'ci_relation', 'SearchError']
class SearchError(Exception):
def __init__(self, v):
self.v = v
def __str__(self):
return self.v

View File

@ -0,0 +1,3 @@
# -*- coding:utf-8 -*-
__all__ = ['db', 'es']

View File

@ -12,25 +12,25 @@ from api.lib.cmdb.cache import AttributeCache
from api.lib.cmdb.cache import CITypeCache from api.lib.cmdb.cache import CITypeCache
from api.lib.cmdb.ci import CIManager from api.lib.cmdb.ci import CIManager
from api.lib.cmdb.const import RetKey from api.lib.cmdb.const import RetKey
from api.lib.cmdb.const import TableMap from api.lib.cmdb.const import ValueTypeEnum
from api.lib.cmdb.search.db.query_sql import FACET_QUERY from api.lib.cmdb.search import SearchError
from api.lib.cmdb.search.db.query_sql import QUERY_CI_BY_ATTR_NAME from api.lib.cmdb.search.ci.db.query_sql import FACET_QUERY
from api.lib.cmdb.search.db.query_sql import QUERY_CI_BY_TYPE from api.lib.cmdb.search.ci.db.query_sql import QUERY_CI_BY_ATTR_NAME
from api.lib.cmdb.search.ci.db.query_sql import QUERY_CI_BY_TYPE
from api.lib.cmdb.utils import TableMap
from api.lib.utils import handle_arg_list from api.lib.utils import handle_arg_list
from api.models.cmdb import Attribute
from api.models.cmdb import CI from api.models.cmdb import CI
class SearchError(Exception):
def __init__(self, v):
self.v = v
def __str__(self):
return self.v
class Search(object): class Search(object):
def __init__(self, query=None, fl=None, facet_field=None, page=1, ret_key=RetKey.NAME, count=1, sort=None): def __init__(self, query=None,
fl=None,
facet_field=None,
page=1,
ret_key=RetKey.NAME,
count=1,
sort=None,
ci_ids=None):
self.orig_query = query self.orig_query = query
self.fl = fl self.fl = fl
self.facet_field = facet_field self.facet_field = facet_field
@ -38,6 +38,7 @@ class Search(object):
self.ret_key = ret_key self.ret_key = ret_key
self.count = count self.count = count
self.sort = sort self.sort = sort
self.ci_ids = ci_ids or []
self.query_sql = "" self.query_sql = ""
self.type_id_list = [] self.type_id_list = []
self.only_type_query = False self.only_type_query = False
@ -60,10 +61,10 @@ class Search(object):
operator, key = self._operator_proc(key) operator, key = self._operator_proc(key)
if key in ('ci_type', 'type', '_type'): if key in ('ci_type', 'type', '_type'):
return '_type', Attribute.TEXT, operator, None return '_type', ValueTypeEnum.TEXT, operator, None
if key in ('id', 'ci_id', '_id'): if key in ('id', 'ci_id', '_id'):
return '_id', Attribute.TEXT, operator, None return '_id', ValueTypeEnum.TEXT, operator, None
attr = AttributeCache.get(key) attr = AttributeCache.get(key)
if attr: if attr:
@ -286,6 +287,13 @@ class Search(object):
alias += "AA" alias += "AA"
return None, query_sql return None, query_sql
def _filter_ids(self, query_sql):
if self.ci_ids:
return "SELECT * FROM ({0}) AS IN_QUERY WHERE IN_QUERY.ci_id in ({1})".format(
query_sql, ",".join(list(map(str, self.ci_ids))))
return query_sql
def _query_build_raw(self): def _query_build_raw(self):
queries = handle_arg_list(self.orig_query) queries = handle_arg_list(self.orig_query)
@ -298,6 +306,7 @@ class Search(object):
s = time.time() s = time.time()
if query_sql: if query_sql:
query_sql = self._filter_ids(query_sql)
self.query_sql = query_sql self.query_sql = query_sql
current_app.logger.debug(query_sql) current_app.logger.debug(query_sql)
numfound, res = self._execute_sql(query_sql) numfound, res = self._execute_sql(query_sql)

View File

@ -8,20 +8,20 @@ from flask import current_app
from api.extensions import es from api.extensions import es
from api.lib.cmdb.cache import AttributeCache from api.lib.cmdb.cache import AttributeCache
from api.lib.cmdb.const import RetKey from api.lib.cmdb.const import RetKey
from api.lib.cmdb.const import ValueTypeEnum
from api.lib.cmdb.search import SearchError
from api.lib.utils import handle_arg_list from api.lib.utils import handle_arg_list
from api.models.cmdb import Attribute
class SearchError(Exception):
def __init__(self, v):
self.v = v
def __str__(self):
return self.v
class Search(object): class Search(object):
def __init__(self, query=None, fl=None, facet_field=None, page=1, ret_key=RetKey.NAME, count=1, sort=None): def __init__(self, query=None,
fl=None,
facet_field=None,
page=1,
ret_key=RetKey.NAME,
count=1,
sort=None,
ci_ids=None):
self.orig_query = query self.orig_query = query
self.fl = fl self.fl = fl
self.facet_field = facet_field self.facet_field = facet_field
@ -29,6 +29,7 @@ class Search(object):
self.ret_key = ret_key self.ret_key = ret_key
self.count = count or current_app.config.get("DEFAULT_PAGE_COUNT") self.count = count or current_app.config.get("DEFAULT_PAGE_COUNT")
self.sort = sort or "ci_id" self.sort = sort or "ci_id"
self.ci_ids = ci_ids or []
self.query = dict(query=dict(bool=dict(should=[], must=[], must_not=[]))) self.query = dict(query=dict(bool=dict(should=[], must=[], must_not=[])))
@ -58,10 +59,10 @@ class Search(object):
operator, key = self._operator_proc(key) operator, key = self._operator_proc(key)
if key in ('ci_type', 'type', '_type'): if key in ('ci_type', 'type', '_type'):
return 'ci_type', Attribute.TEXT, operator return 'ci_type', ValueTypeEnum.TEXT, operator
if key in ('id', 'ci_id', '_id'): if key in ('id', 'ci_id', '_id'):
return 'ci_id', Attribute.TEXT, operator return 'ci_id', ValueTypeEnum.TEXT, operator
attr = AttributeCache.get(key) attr = AttributeCache.get(key)
if attr: if attr:
@ -79,6 +80,10 @@ class Search(object):
} }
}) })
def _filter_ids(self):
if self.ci_ids:
self.query['query']['bool'].update(dict(filter=dict(terms=dict(ci_id=self.ci_ids))))
@staticmethod @staticmethod
def _digit(s): def _digit(s):
if s.isdigit(): if s.isdigit():
@ -171,6 +176,8 @@ class Search(object):
self._facet_build() self._facet_build()
self._filter_ids()
return es.read(self.query, filter_path=filter_path) return es.read(self.query, filter_path=filter_path)
def _facet_build(self): def _facet_build(self):
@ -183,7 +190,7 @@ class Search(object):
field: { field: {
"terms": { "terms": {
"field": "{0}.keyword".format(field) "field": "{0}.keyword".format(field)
if attr.value_type not in (Attribute.INT, Attribute.FLOAT) else field if attr.value_type not in (ValueTypeEnum.INT, ValueTypeEnum.FLOAT) else field
} }
} }
}) })
@ -212,7 +219,7 @@ class Search(object):
raise SearchError("Sort by <{0}> does not exist".format(field)) raise SearchError("Sort by <{0}> does not exist".format(field))
sort_by = "{0}.keyword".format(field) \ sort_by = "{0}.keyword".format(field) \
if attr.value_type not in (Attribute.INT, Attribute.FLOAT) else field if attr.value_type not in (ValueTypeEnum.INT, ValueTypeEnum.FLOAT) else field
sorts.append({sort_by: {"order": sort_type}}) sorts.append({sort_by: {"order": sort_type}})
self.query.update(dict(sort=sorts)) self.query.update(dict(sort=sorts))

View File

@ -0,0 +1 @@
# -*- coding:utf-8 -*-

View File

@ -0,0 +1,56 @@
# -*- coding:utf-8 -*-
import json
from flask import abort
from flask import current_app
from api.extensions import rd
from api.lib.cmdb.ci_type import CITypeRelationManager
from api.lib.cmdb.const import REDIS_PREFIX_CI_RELATION
from api.lib.cmdb.search.ci.db.search import Search as SearchFromDB
from api.lib.cmdb.search.ci.es.search import Search as SearchFromES
from api.models.cmdb import CI
class Search(object):
def __init__(self, root_id, level=1, query=None, fl=None, facet_field=None, page=1, count=None, sort=None):
self.orig_query = query
self.fl = fl
self.facet_field = facet_field
self.page = page
self.count = count or current_app.config.get("DEFAULT_PAGE_COUNT")
self.sort = sort or ("ci_id" if current_app.config.get("USE_ES") else None)
self.root_id = root_id
self.level = int(level)
def search(self):
ci = CI.get_by_id(self.root_id) or abort(404, "CI <{0}> does not exist".format(self.root_id))
ids = [self.root_id]
for _ in range(0, self.level):
_tmp = list(map(json.loads, filter(lambda x: x is not None, rd.get(ids, REDIS_PREFIX_CI_RELATION))))
ids = [j for i in _tmp for j in i]
if not self.orig_query or ("_type:" not in self.orig_query
and "type_id:" not in self.orig_query
and "ci_type:" not in self.orig_query):
type_ids = CITypeRelationManager.get_child_type_ids(ci.type_id, self.level)
self.orig_query = "_type:({0}),{1}".format(";".join(list(map(str, type_ids))), self.orig_query)
if current_app.config.get("USE_ES"):
return SearchFromES(self.orig_query,
fl=self.fl,
facet_field=self.facet_field,
page=self.page,
count=self.count,
sort=self.sort,
ci_ids=ids).search()
else:
return SearchFromDB(self.orig_query,
fl=self.fl,
facet_field=self.facet_field,
page=self.page,
count=self.count,
sort=self.sort,
ci_ids=ids).search()

116
api/lib/cmdb/utils.py Normal file
View File

@ -0,0 +1,116 @@
# -*- coding:utf-8 -*-
from __future__ import unicode_literals
import datetime
import six
from markupsafe import escape
import api.models.cmdb as model
from api.lib.cmdb.cache import AttributeCache
from api.lib.cmdb.const import ValueTypeEnum
def string2int(x):
return int(float(x))
def str2datetime(x):
try:
return datetime.datetime.strptime(x, "%Y-%m-%d")
except ValueError:
pass
return datetime.datetime.strptime(x, "%Y-%m-%d %H:%M:%S")
class ValueTypeMap(object):
deserialize = {
ValueTypeEnum.INT: string2int,
ValueTypeEnum.FLOAT: float,
ValueTypeEnum.TEXT: lambda x: escape(x).encode('utf-8').decode('utf-8'),
ValueTypeEnum.TIME: lambda x: escape(x).encode('utf-8').decode('utf-8'),
ValueTypeEnum.DATETIME: str2datetime,
ValueTypeEnum.DATE: str2datetime,
}
serialize = {
ValueTypeEnum.INT: int,
ValueTypeEnum.FLOAT: float,
ValueTypeEnum.TEXT: lambda x: x if isinstance(x, six.text_type) else str(x),
ValueTypeEnum.TIME: lambda x: x if isinstance(x, six.text_type) else str(x),
ValueTypeEnum.DATE: lambda x: x.strftime("%Y-%m-%d"),
ValueTypeEnum.DATETIME: lambda x: x.strftime("%Y-%m-%d %H:%M:%S"),
}
serialize2 = {
ValueTypeEnum.INT: int,
ValueTypeEnum.FLOAT: float,
ValueTypeEnum.TEXT: lambda x: x.decode() if not isinstance(x, six.string_types) else x,
ValueTypeEnum.TIME: lambda x: x.decode() if not isinstance(x, six.string_types) else x,
ValueTypeEnum.DATE: lambda x: x.decode() if not isinstance(x, six.string_types) else x,
ValueTypeEnum.DATETIME: lambda x: x.decode() if not isinstance(x, six.string_types) else x,
}
choice = {
ValueTypeEnum.INT: model.IntegerChoice,
ValueTypeEnum.FLOAT: model.FloatChoice,
ValueTypeEnum.TEXT: model.TextChoice,
}
table = {
ValueTypeEnum.INT: model.CIValueInteger,
ValueTypeEnum.TEXT: model.CIValueText,
ValueTypeEnum.DATETIME: model.CIValueDateTime,
ValueTypeEnum.DATE: model.CIValueDateTime,
ValueTypeEnum.TIME: model.CIValueText,
ValueTypeEnum.FLOAT: model.CIValueFloat,
'index_{0}'.format(ValueTypeEnum.INT): model.CIIndexValueInteger,
'index_{0}'.format(ValueTypeEnum.TEXT): model.CIIndexValueText,
'index_{0}'.format(ValueTypeEnum.DATETIME): model.CIIndexValueDateTime,
'index_{0}'.format(ValueTypeEnum.DATE): model.CIIndexValueDateTime,
'index_{0}'.format(ValueTypeEnum.TIME): model.CIIndexValueText,
'index_{0}'.format(ValueTypeEnum.FLOAT): model.CIIndexValueFloat,
}
table_name = {
ValueTypeEnum.INT: 'c_value_integers',
ValueTypeEnum.TEXT: 'c_value_texts',
ValueTypeEnum.DATETIME: 'c_value_datetime',
ValueTypeEnum.DATE: 'c_value_datetime',
ValueTypeEnum.TIME: 'c_value_texts',
ValueTypeEnum.FLOAT: 'c_value_floats',
'index_{0}'.format(ValueTypeEnum.INT): 'c_value_index_integers',
'index_{0}'.format(ValueTypeEnum.TEXT): 'c_value_index_texts',
'index_{0}'.format(ValueTypeEnum.DATETIME): 'c_value_index_datetime',
'index_{0}'.format(ValueTypeEnum.DATE): 'c_value_index_datetime',
'index_{0}'.format(ValueTypeEnum.TIME): 'c_value_index_texts',
'index_{0}'.format(ValueTypeEnum.FLOAT): 'c_value_index_floats',
}
es_type = {
ValueTypeEnum.INT: 'long',
ValueTypeEnum.TEXT: 'text',
ValueTypeEnum.DATETIME: 'text',
ValueTypeEnum.DATE: 'text',
ValueTypeEnum.TIME: 'text',
ValueTypeEnum.FLOAT: 'float'
}
class TableMap(object):
def __init__(self, attr_name=None):
self.attr_name = attr_name
@property
def table(self):
attr = AttributeCache.get(self.attr_name)
i = "index_{0}".format(attr.value_type) if attr.is_index else attr.value_type
return ValueTypeMap.table.get(i)
@property
def table_name(self):
attr = AttributeCache.get(self.attr_name)
i = "index_{0}".format(attr.value_type) if attr.is_index else attr.value_type
return ValueTypeMap.table_name.get(i)

View File

@ -3,7 +3,6 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import markupsafe
from flask import abort from flask import abort
from api.extensions import db from api.extensions import db
@ -11,11 +10,11 @@ from api.lib.cmdb.attribute import AttributeManager
from api.lib.cmdb.cache import AttributeCache from api.lib.cmdb.cache import AttributeCache
from api.lib.cmdb.const import ExistPolicy from api.lib.cmdb.const import ExistPolicy
from api.lib.cmdb.const import OperateType from api.lib.cmdb.const import OperateType
from api.lib.cmdb.const import TableMap from api.lib.cmdb.const import ValueTypeEnum
from api.lib.cmdb.const import type_map
from api.lib.cmdb.history import AttributeHistoryManger from api.lib.cmdb.history import AttributeHistoryManger
from api.lib.cmdb.utils import TableMap
from api.lib.cmdb.utils import ValueTypeMap
from api.lib.utils import handle_arg_list from api.lib.utils import handle_arg_list
from api.models.cmdb import Attribute
class AttributeValueManager(object): class AttributeValueManager(object):
@ -58,9 +57,9 @@ class AttributeValueManager(object):
field_name = getattr(attr, ret_key) field_name = getattr(attr, ret_key)
if attr.is_list: if attr.is_list:
res[field_name] = [type_map["serialize"][attr.value_type](i.value) for i in rs] res[field_name] = [ValueTypeMap.serialize[attr.value_type](i.value) for i in rs]
else: else:
res[field_name] = type_map["serialize"][attr.value_type](rs[0].value) if rs else None res[field_name] = ValueTypeMap.serialize[attr.value_type](rs[0].value) if rs else None
if unique_key is not None and attr.id == unique_key.id and rs: if unique_key is not None and attr.id == unique_key.id and rs:
res['unique'] = unique_key.name res['unique'] = unique_key.name
@ -71,7 +70,7 @@ class AttributeValueManager(object):
def __deserialize_value(value_type, value): def __deserialize_value(value_type, value):
if not value: if not value:
return value return value
deserialize = type_map["deserialize"][value_type] deserialize = ValueTypeMap.deserialize[value_type]
try: try:
v = deserialize(value) v = deserialize(value)
return v return v
@ -133,7 +132,7 @@ class AttributeValueManager(object):
for v in value_list: for v in value_list:
v = self._validate(attr, v, value_table, ci_id) v = self._validate(attr, v, value_table, ci_id)
if not v and attr.value_type != Attribute.TEXT: if not v and attr.value_type != ValueTypeEnum.TEXT:
v = None v = None
if operate_type == OperateType.ADD: if operate_type == OperateType.ADD:

View File

@ -29,10 +29,27 @@ def handle_arg_list(arg):
return list(filter(lambda x: x != "", arg.strip().split(","))) if isinstance(arg, six.string_types) else arg return list(filter(lambda x: x != "", arg.strip().split(","))) if isinstance(arg, six.string_types) else arg
class BaseEnum(object):
_ALL_ = set() # type: Set[str]
@classmethod
def is_valid(cls, item):
return item in cls.all()
@classmethod
def all(cls):
if not cls._ALL_:
cls._ALL_ = {
getattr(cls, attr)
for attr in dir(cls)
if not attr.startswith("_") and not callable(getattr(cls, attr))
}
return cls._ALL_
class RedisHandler(object): class RedisHandler(object):
def __init__(self, flask_app=None, prefix=None): def __init__(self, flask_app=None):
self.flask_app = flask_app self.flask_app = flask_app
self.prefix = prefix
self.r = None self.r = None
def init_app(self, app): def init_app(self, app):
@ -49,26 +66,26 @@ class RedisHandler(object):
current_app.logger.warning(str(e)) current_app.logger.warning(str(e))
current_app.logger.error("init redis connection failed") current_app.logger.error("init redis connection failed")
def get(self, key_ids): def get(self, key_ids, prefix):
try: try:
value = self.r.hmget(self.prefix, key_ids) value = self.r.hmget(prefix, key_ids)
except Exception as e: except Exception as e:
current_app.logger.error("get redis error, {0}".format(str(e))) current_app.logger.error("get redis error, {0}".format(str(e)))
return return
return value return value
def _set(self, obj): def _set(self, obj, prefix):
try: try:
self.r.hmset(self.prefix, obj) self.r.hmset(prefix, obj)
except Exception as e: except Exception as e:
current_app.logger.error("set redis error, {0}".format(str(e))) current_app.logger.error("set redis error, {0}".format(str(e)))
def add(self, obj): def create_or_update(self, obj, prefix):
self._set(obj) self._set(obj, prefix)
def delete(self, key_id): def delete(self, key_id, prefix):
try: try:
ret = self.r.hdel(self.prefix, key_id) ret = self.r.hdel(prefix, key_id)
if not ret: if not ret:
current_app.logger.warn("[{0}] is not in redis".format(key_id)) current_app.logger.warn("[{0}] is not in redis".format(key_id))
except Exception as e: except Exception as e:

View File

@ -4,6 +4,9 @@
import datetime import datetime
from api.extensions import db from api.extensions import db
from api.lib.cmdb.const import CIStatusEnum
from api.lib.cmdb.const import OperateType
from api.lib.cmdb.const import ValueTypeEnum
from api.lib.database import Model from api.lib.database import Model
@ -58,16 +61,9 @@ class CITypeRelation(Model):
class Attribute(Model): class Attribute(Model):
__tablename__ = "c_attributes" __tablename__ = "c_attributes"
INT = "0"
FLOAT = "1"
TEXT = "2"
DATETIME = "3"
DATE = "4"
TIME = "5"
name = db.Column(db.String(32), nullable=False) name = db.Column(db.String(32), nullable=False)
alias = db.Column(db.String(32), nullable=False) alias = db.Column(db.String(32), nullable=False)
value_type = db.Column(db.Enum(INT, FLOAT, TEXT, DATETIME, DATE, TIME), default=TEXT, nullable=False) value_type = db.Column(db.Enum(*ValueTypeEnum.all()), default=ValueTypeEnum.TEXT, nullable=False)
is_choice = db.Column(db.Boolean, default=False) is_choice = db.Column(db.Boolean, default=False)
is_list = db.Column(db.Boolean, default=False) is_list = db.Column(db.Boolean, default=False)
@ -111,11 +107,8 @@ class CITypeAttributeGroupItem(Model):
class CI(Model): class CI(Model):
__tablename__ = "c_cis" __tablename__ = "c_cis"
REVIEW = "0"
VALIDATE = "1"
type_id = db.Column(db.Integer, db.ForeignKey("c_ci_types.id"), nullable=False) type_id = db.Column(db.Integer, db.ForeignKey("c_ci_types.id"), nullable=False)
status = db.Column(db.Enum(REVIEW, VALIDATE, name="status")) status = db.Column(db.Enum(*CIStatusEnum.all(), name="status"))
heartbeat = db.Column(db.DateTime, default=lambda: datetime.datetime.now()) heartbeat = db.Column(db.DateTime, default=lambda: datetime.datetime.now())
ci_type = db.relationship("CIType", backref="c_cis.type_id") ci_type = db.relationship("CIType", backref="c_cis.type_id")
@ -270,11 +263,7 @@ class OperationRecord(Model):
class AttributeHistory(Model): class AttributeHistory(Model):
__tablename__ = "c_attribute_histories" __tablename__ = "c_attribute_histories"
ADD = "0" operate_type = db.Column(db.Enum(*OperateType.all(), name="operate_type"))
DELETE = "1"
UPDATE = "2"
operate_type = db.Column(db.Enum(ADD, DELETE, UPDATE, name="operate_type"))
record_id = db.Column(db.Integer, db.ForeignKey("c_records.id"), nullable=False) record_id = db.Column(db.Integer, db.ForeignKey("c_records.id"), nullable=False)
ci_id = db.Column(db.Integer, index=True, nullable=False) ci_id = db.Column(db.Integer, index=True, nullable=False)
attr_id = db.Column(db.Integer, index=True) attr_id = db.Column(db.Integer, index=True)
@ -285,10 +274,7 @@ class AttributeHistory(Model):
class CIRelationHistory(Model): class CIRelationHistory(Model):
__tablename__ = "c_relation_histories" __tablename__ = "c_relation_histories"
ADD = "0" operate_type = db.Column(db.Enum(OperateType.ADD, OperateType.DELETE, name="operate_type"))
DELETE = "1"
operate_type = db.Column(db.Enum(ADD, DELETE, name="operate_type"))
record_id = db.Column(db.Integer, db.ForeignKey("c_records.id"), nullable=False) record_id = db.Column(db.Integer, db.ForeignKey("c_records.id"), nullable=False)
first_ci_id = db.Column(db.Integer) first_ci_id = db.Column(db.Integer)
second_ci_id = db.Column(db.Integer) second_ci_id = db.Column(db.Integer)

View File

@ -9,9 +9,11 @@ from flask import current_app
import api.lib.cmdb.ci import api.lib.cmdb.ci
from api.extensions import celery from api.extensions import celery
from api.extensions import db from api.extensions import db
from api.extensions import rd
from api.extensions import es from api.extensions import es
from api.extensions import rd
from api.lib.cmdb.const import CMDB_QUEUE from api.lib.cmdb.const import CMDB_QUEUE
from api.lib.cmdb.const import REDIS_PREFIX_CI
from api.lib.cmdb.const import REDIS_PREFIX_CI_RELATION
@celery.task(name="cmdb.ci_cache", queue=CMDB_QUEUE) @celery.task(name="cmdb.ci_cache", queue=CMDB_QUEUE)
@ -24,10 +26,9 @@ def ci_cache(ci_id):
if current_app.config.get("USE_ES"): if current_app.config.get("USE_ES"):
es.update(ci_id, ci) es.update(ci_id, ci)
else: else:
rd.delete(ci_id) rd.create_or_update({ci_id: json.dumps(ci)}, REDIS_PREFIX_CI)
rd.add({ci_id: json.dumps(ci)})
current_app.logger.info("%d flush.........." % ci_id) current_app.logger.info("{0} flush..........".format(ci_id))
@celery.task(name="cmdb.ci_delete", queue=CMDB_QUEUE) @celery.task(name="cmdb.ci_delete", queue=CMDB_QUEUE)
@ -37,6 +38,29 @@ def ci_delete(ci_id):
if current_app.config.get("USE_ES"): if current_app.config.get("USE_ES"):
es.delete(ci_id) es.delete(ci_id)
else: else:
rd.delete(ci_id) rd.delete(ci_id, REDIS_PREFIX_CI)
current_app.logger.info("%d delete.........." % ci_id) current_app.logger.info("{0} delete..........".format(ci_id))
@celery.task(name="cmdb.ci_relation_cache", queue=CMDB_QUEUE)
def ci_relation_cache(parent_id, child_id):
children = rd.get([parent_id], REDIS_PREFIX_CI_RELATION)[0]
children = json.loads(children) if children is not None else []
children.append(child_id)
rd.create_or_update({parent_id: json.dumps(list(set(children)))}, REDIS_PREFIX_CI_RELATION)
current_app.logger.info("ADD ci relation cache: {0} -> {1}".format(parent_id, child_id))
@celery.task(name="cmdb.ci_relation_delete", queue=CMDB_QUEUE)
def ci_relation_delete(parent_id, child_id):
children = rd.get([parent_id], REDIS_PREFIX_CI_RELATION)[0]
children = json.loads(children) if children is not None else []
if child_id in children:
children.remove(child_id)
rd.create_or_update({parent_id: json.dumps(list(set(children)))}, REDIS_PREFIX_CI_RELATION)
current_app.logger.info("DELETE ci relation cache: {0} -> {1}".format(parent_id, child_id))

View File

@ -12,9 +12,9 @@ from api.lib.cmdb.ci import CIManager
from api.lib.cmdb.const import ExistPolicy from api.lib.cmdb.const import ExistPolicy
from api.lib.cmdb.const import ResourceType, PermEnum from api.lib.cmdb.const import ResourceType, PermEnum
from api.lib.cmdb.const import RetKey from api.lib.cmdb.const import RetKey
from api.lib.cmdb.search.db.search import Search as SearchFromDB from api.lib.cmdb.search import SearchError
from api.lib.cmdb.search.es.search import Search as SearchFromES from api.lib.cmdb.search.ci.db.search import Search as SearchFromDB
from api.lib.cmdb.search.db.search import SearchError from api.lib.cmdb.search.ci.es.search import Search as SearchFromES
from api.lib.perm.acl.acl import has_perm_from_args from api.lib.perm.acl.acl import has_perm_from_args
from api.lib.perm.auth import auth_abandoned from api.lib.perm.auth import auth_abandoned
from api.lib.utils import get_page from api.lib.utils import get_page
@ -126,13 +126,13 @@ class CISearchView(APIView):
def get(self): def get(self):
"""@params: q: query statement """@params: q: query statement
fl: filter by column fl: filter by column
count: the number of ci count/page_size: the number of ci
ret_key: id, name, alias ret_key: id, name, alias
facet: statistic facet: statistic
""" """
page = get_page(request.values.get("page", 1)) page = get_page(request.values.get("page", 1))
count = get_page_size(request.values.get("count")) count = get_page_size(request.values.get("count") or request.values.get("page_size"))
query = request.values.get('q', "") query = request.values.get('q', "")
fl = handle_arg_list(request.values.get('fl', "")) fl = handle_arg_list(request.values.get('fl', ""))
@ -140,8 +140,6 @@ class CISearchView(APIView):
if ret_key not in (RetKey.NAME, RetKey.ALIAS, RetKey.ID): if ret_key not in (RetKey.NAME, RetKey.ALIAS, RetKey.ID):
ret_key = RetKey.NAME ret_key = RetKey.NAME
facet = handle_arg_list(request.values.get("facet", "")) facet = handle_arg_list(request.values.get("facet", ""))
fl = list(filter(lambda x: x != "", fl))
facet = list(filter(lambda x: x != "", facet))
sort = request.values.get("sort") sort = request.values.get("sort")
start = time.time() start = time.time()

View File

@ -1,14 +1,62 @@
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*-
import time
from flask import abort
from flask import current_app
from flask import request from flask import request
from api.lib.cmdb.ci import CIRelationManager from api.lib.cmdb.ci import CIRelationManager
from api.lib.cmdb.search import SearchError
from api.lib.cmdb.search.ci_relation.search import Search
from api.lib.perm.auth import auth_abandoned
from api.lib.utils import get_page from api.lib.utils import get_page
from api.lib.utils import get_page_size from api.lib.utils import get_page_size
from api.lib.utils import handle_arg_list
from api.resource import APIView from api.resource import APIView
class CIRelationSearchView(APIView):
url_prefix = ("/ci_relations/s", "/ci_relations/search")
@auth_abandoned
def get(self):
"""@params: q: query statement
fl: filter by column
count: the number of ci
root_id: ci id
level: default is 1
facet: statistic
"""
page = get_page(request.values.get("page", 1))
count = get_page_size(request.values.get("count") or request.values.get("page_size"))
root_id = request.values.get('root_id')
level = request.values.get('level', 1)
query = request.values.get('q', "")
fl = handle_arg_list(request.values.get('fl', ""))
facet = handle_arg_list(request.values.get("facet", ""))
sort = request.values.get("sort")
start = time.time()
s = Search(root_id, level, query, fl, facet, page, count, sort)
try:
response, counter, total, page, numfound, facet = s.search()
except SearchError as e:
return abort(400, str(e))
current_app.logger.debug("search time is :{0}".format(time.time() - start))
return self.jsonify(numfound=numfound,
total=total,
page=page,
facet=facet,
counter=counter,
result=response)
class GetSecondCIsView(APIView): class GetSecondCIsView(APIView):
url_prefix = "/ci_relations/<int:first_ci_id>/second_cis" url_prefix = "/ci_relations/<int:first_ci_id>/second_cis"

View File

@ -25,18 +25,26 @@ class GetParentsView(APIView):
class CITypeRelationView(APIView): class CITypeRelationView(APIView):
url_prefix = "/ci_type_relations/<int:parent_id>/<int:child_id>" url_prefix = ("/ci_type_relations", "/ci_type_relations/<int:parent_id>/<int:child_id>")
@role_required(RoleEnum.CONFIG)
def get(self):
res = CITypeRelationManager.get()
return self.jsonify(res)
@role_required(RoleEnum.CONFIG) @role_required(RoleEnum.CONFIG)
@args_required("relation_type_id") @args_required("relation_type_id")
def post(self, parent_id, child_id): def post(self, parent_id, child_id):
relation_type_id = request.values.get("relation_type_id") relation_type_id = request.values.get("relation_type_id")
ctr_id = CITypeRelationManager.add(parent_id, child_id, relation_type_id) ctr_id = CITypeRelationManager.add(parent_id, child_id, relation_type_id)
return self.jsonify(ctr_id=ctr_id) return self.jsonify(ctr_id=ctr_id)
@role_required(RoleEnum.CONFIG) @role_required(RoleEnum.CONFIG)
def delete(self, parent_id, child_id): def delete(self, parent_id, child_id):
CITypeRelationManager.delete_2(parent_id, child_id) CITypeRelationManager.delete_2(parent_id, child_id)
return self.jsonify(code=200, parent_id=parent_id, child_id=child_id) return self.jsonify(code=200, parent_id=parent_id, child_id=child_id)
@ -46,4 +54,5 @@ class CITypeRelationDelete2View(APIView):
@role_required(RoleEnum.CONFIG) @role_required(RoleEnum.CONFIG)
def delete(self, ctr_id): def delete(self, ctr_id):
CITypeRelationManager.delete(ctr_id) CITypeRelationManager.delete(ctr_id)
return self.jsonify(code=200, ctr_id=ctr_id) return self.jsonify(code=200, ctr_id=ctr_id)