def batch_update(cls, ci_ids, parents): """ only for many to one :param ci_ids: :param parents: :return: """ from api.lib.cmdb.utils import TableMap if parents is not None and isinstance(parents, dict): for attr_name in parents: if parents[attr_name]: attr = AttributeCache.get(attr_name) value_table = TableMap(attr_name=attr.name).table parent = value_table.get_by(attr_id=attr.id, value=parents[attr_name], first=True, to_dict=False) if not parent: return abort( 404, "{0}: {1} is not found".format( attr_name, parents[attr_name])) parent_id = parent.ci_id for ci_id in ci_ids: cls.add(parent_id, ci_id, many_to_one=True)
def delete(ci_id): ci = CI.get_by_id(ci_id) or abort( 404, "CI <{0}> is not found".format(ci_id)) attrs = CITypeAttribute.get_by(type_id=ci.type_id, to_dict=False) attr_names = set( [AttributeCache.get(attr.attr_id).name for attr in attrs]) for attr_name in attr_names: value_table = TableMap(attr_name=attr_name).table for item in value_table.get_by(ci_id=ci_id, to_dict=False): item.delete() for item in CIRelation.get_by(first_ci_id=ci_id, to_dict=False): ci_relation_delete.apply_async(args=(item.first_ci_id, item.second_ci_id), queue=CMDB_QUEUE) item.delete() for item in CIRelation.get_by(second_ci_id=ci_id, to_dict=False): ci_relation_delete.apply_async(args=(item.first_ci_id, item.second_ci_id), queue=CMDB_QUEUE) item.delete() ci.delete() # TODO: soft delete AttributeHistoryManger.add(ci_id, [(None, OperateType.DELETE, None, None)]) ci_delete.apply_async([ci.id], queue=CMDB_QUEUE) return ci_id
def get_attr_values(self, fields, ci_id, ret_key="name", unique_key=None, use_master=False): """ :param fields: :param ci_id: :param ret_key: It can be name or alias :param unique_key: primary attribute :param use_master: Only for master-slave read-write separation :return: """ res = dict() for field in fields: attr = self._get_attr(field) if not attr: continue value_table = TableMap(attr_name=attr.name).table rs = value_table.get_by(ci_id=ci_id, attr_id=attr.id, use_master=use_master, to_dict=False) field_name = getattr(attr, ret_key) if attr.is_list: res[field_name] = [ValueTypeMap.serialize[attr.value_type](i.value) for i in rs] else: 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: res['unique'] = unique_key.name return res
def delete_attr_value(attr_id, ci_id): attr = AttributeCache.get(attr_id) if attr is not None: value_table = TableMap(attr_name=attr.name).table for item in value_table.get_by(attr_id=attr.id, ci_id=ci_id, to_dict=False): item.delete()
def ci_is_exist(unique_key, unique_value): """ :param unique_key: is a attribute :param unique_value: :return: """ value_table = TableMap(attr_name=unique_key.name).table unique = value_table.get_by(attr_id=unique_key.id, value=unique_value, to_dict=False, first=True) if unique: return CI.get_by_id(unique.ci_id)
def create_or_update_attr_value(self, key, value, ci, _no_attribute_policy=ExistPolicy.IGNORE): """ add or update attribute value, then write history :param key: id, name or alias :param value: :param ci: instance object :param _no_attribute_policy: ignore or reject :return: """ attr = self._get_attr(key) if attr is None: if _no_attribute_policy == ExistPolicy.IGNORE: return if _no_attribute_policy == ExistPolicy.REJECT: return abort(400, 'attribute {0} does not exist'.format(key)) value_table = TableMap(attr_name=attr.name).table if attr.is_list: value_list = [ self._validate(attr, i, value_table, ci) for i in handle_arg_list(value) ] if not value_list: self.__check_is_required(ci.type_id, attr, '') existed_attrs = value_table.get_by(attr_id=attr.id, ci_id=ci.id, to_dict=False) existed_values = [i.value for i in existed_attrs] added = set(value_list) - set(existed_values) deleted = set(existed_values) - set(value_list) for v in added: value_table.create(ci_id=ci.id, attr_id=attr.id, value=v) self._write_change(ci.id, attr.id, OperateType.ADD, None, v) for v in deleted: existed_attr = existed_attrs[existed_values.index(v)] existed_attr.delete() self._write_change(ci.id, attr.id, OperateType.DELETE, v, None) else: value = self._validate(attr, value, value_table, ci) existed_attr = value_table.get_by(attr_id=attr.id, ci_id=ci.id, first=True, to_dict=False) existed_value = existed_attr and existed_attr.value if existed_value is None: value_table.create(ci_id=ci.id, attr_id=attr.id, value=value) self._write_change(ci.id, attr.id, OperateType.ADD, None, value) else: existed_attr.update(value=value) self._write_change(ci.id, attr.id, OperateType.UPDATE, existed_value, value)
def add_heartbeat(ci_type, unique_value): ci_type = CITypeManager().check_is_existed(ci_type) unique_key = AttributeCache.get(ci_type.unique_id) value_table = TableMap(attr_name=unique_key.name).table v = value_table.get_by(attr_id=unique_key.id, value=unique_value, to_dict=False, first=True) \ or abort(404, "not found") ci = CI.get_by_id(v.ci_id) or abort(404, "CI <{0}> is not found".format(v.ci_id)) ci.update(heartbeat=datetime.datetime.now())
def create_or_update_attr_value(self, key, value, ci_id, _no_attribute_policy=ExistPolicy.IGNORE): """ add or update attribute value, then write history :param key: id, name or alias :param value: :param ci_id: :param _no_attribute_policy: ignore or reject :return: """ attr = self._get_attr(key) if attr is None: if _no_attribute_policy == ExistPolicy.IGNORE: return if _no_attribute_policy == ExistPolicy.REJECT: return abort(400, 'attribute {0} does not exist'.format(key)) value_table = TableMap(attr_name=attr.name).table existed_attr = value_table.get_by(attr_id=attr.id, ci_id=ci_id, first=True, to_dict=False) existed_value = existed_attr and existed_attr.value operate_type = OperateType.ADD if existed_attr is None else OperateType.UPDATE value_list = handle_arg_list(value) if attr.is_list else [value] if not isinstance(value, list): value_list = [value] for v in value_list: v = self._validate(attr, v, value_table, ci_id) if not v and attr.value_type != ValueTypeEnum.TEXT: v = None if operate_type == OperateType.ADD: if v is not None: value_table.create(ci_id=ci_id, attr_id=attr.id, value=v) self._write_change(ci_id, attr.id, operate_type, None, v) elif existed_attr.value != v: if v is not None: existed_attr.update(value=v) else: existed_attr.delete() self._write_change(ci_id, attr.id, operate_type, existed_value, v)
def _sort_handler(sort_by, query_sql): if sort_by.startswith("+"): sort_type = "asc" sort_by = sort_by[1:] elif sort_by.startswith("-"): sort_type = "desc" sort_by = sort_by[1:] else: sort_type = "asc" attr = AttributeCache.get(sort_by) if attr is None: return query_sql attr_id = attr.id value_table = TableMap(attr_name=sort_by).table ci_table = query_sql.subquery() query_sql = db.session.query(ci_table.c.id, value_table.value).join( value_table, value_table.ci_id == ci_table.c.id).filter( value_table.attr_id == attr_id).filter( ci_table.deleted.is_(False)).order_by( getattr(value_table.value, sort_type)()) return query_sql
def _query_wrap_for_device(self, query_sql, **kwargs): _type = kwargs.pop("_type", False) or kwargs.pop("type", False) or kwargs.pop("ci_type", False) if _type: ci_type = CITypeCache.get(_type) if ci_type is None: return query_sql = query_sql.filter(CI.type_id == ci_type.id) for k, v in kwargs.items(): attr = AttributeCache.get(k) if attr is None: continue value_table = TableMap(attr_name=k).table ci_table = query_sql.subquery() query_sql = db.session.query(ci_table.c.id).join( value_table, value_table.ci_id == ci_table.c.id).filter( value_table.attr_id == attr.id).filter(ci_table.deleted.is_(False)).filter( value_table.value.ilike(v.replace("*", "%"))) # current_app.logger.debug(query_sql) sort_by = kwargs.pop("sort", "") if sort_by: query_sql = self._sort_handler(sort_by, query_sql) return query_sql
def __sort_by_field(self, field, sort_type, query_sql): attr = AttributeCache.get(field) attr_id = attr.id table_name = TableMap(attr_name=attr.name).table_name _v_query_sql = """SELECT {0}.ci_id, {1}.value FROM ({2}) AS {0} INNER JOIN {1} ON {1}.ci_id = {0}.ci_id WHERE {1}.attr_id = {3}""".format("ALIAS", table_name, query_sql, attr_id) new_table = _v_query_sql if self.only_type_query or not self.type_id_list: return "SELECT SQL_CALC_FOUND_ROWS DISTINCT C.ci_id, C.value " \ "FROM ({0}) AS C " \ "ORDER BY C.value {2} " \ "LIMIT {1:d}, {3};".format(new_table, (self.page - 1) * self.count, sort_type, self.count) elif self.type_id_list: self.query_sql = """SELECT C.ci_id FROM ({0}) AS C INNER JOIN c_cis on c_cis.id=C.ci_id WHERE c_cis.type_id IN ({1})""".format(new_table, ",".join(self.type_id_list)) return """SELECT SQL_CALC_FOUND_ROWS DISTINCT C.ci_id, C.value FROM ({0}) AS C INNER JOIN c_cis on c_cis.id=C.ci_id WHERE c_cis.type_id IN ({4}) ORDER BY C.value {2} LIMIT {1:d}, {3};""".format(new_table, (self.page - 1) * self.count, sort_type, self.count, ",".join(self.type_id_list))
def _comparison_query_handler(attr, v): table_name = TableMap(attr_name=attr.name).table_name if v.startswith(">=") or v.startswith("<="): comparison_query = "{0} '{1}'".format(v[:2], v[2:].replace("*", "%")) else: comparison_query = "{0} '{1}'".format(v[0], v[1:].replace("*", "%")) _query_sql = QUERY_CI_BY_ATTR_NAME.format(table_name, attr.id, comparison_query) return _query_sql
def __query_build_by_field(self, queries): query_sql, alias, operator = "", "A", "&" is_first, only_type_query_special = True, True for q in queries: _query_sql = "" if ":" in q: k = q.split(":")[0].strip() v = ":".join(q.split(":")[1:]).strip() current_app.logger.debug(v) field, field_type, operator, attr = self._attr_name_proc(k) if field == "_type": _query_sql = self._type_query_handler(v) current_app.logger.debug(_query_sql) elif field == "_id": # exclude all others ci = CI.get_by_id(v) if ci is not None: return 1, [str(v)] elif field: if attr is None: raise SearchError("{0} is not found".format(field)) # in query if v.startswith("(") and v.endswith(")"): _query_sql = self._in_query_handler(attr, v) # range query elif v.startswith("[") and v.endswith("]") and "_TO_" in v: _query_sql = self._range_query_handler(attr, v) # comparison query elif v.startswith(">=") or v.startswith("<=") or v.startswith(">") or v.startswith("<"): _query_sql = self._comparison_query_handler(attr, v) else: table_name = TableMap(attr_name=attr.name).table_name _query_sql = QUERY_CI_BY_ATTR_NAME.format( table_name, attr.id, 'LIKE "{0}"'.format(v.replace("*", "%"))) else: raise SearchError("argument q format invalid: {0}".format(q)) elif q: raise SearchError("argument q format invalid: {0}".format(q)) if is_first and _query_sql and not self.only_type_query: query_sql = "SELECT * FROM ({0}) AS {1}".format(_query_sql, alias) is_first = False alias += "A" elif self.only_type_query and only_type_query_special: is_first = False only_type_query_special = False query_sql = _query_sql elif _query_sql: query_sql = self._wrap_sql(operator, alias, _query_sql, query_sql) alias += "AA" return None, query_sql
def _facet_build(self): facet = {} for f in self.facet_field: k, field_type, _, attr = self._attr_name_proc(f) if k: table_name = TableMap(attr_name=k).table_name query_sql = FACET_QUERY.format(table_name, self.query_sql, attr.id) current_app.logger.debug(query_sql) result = db.session.execute(query_sql).fetchall() facet[k] = result facet_result = dict() for k, v in facet.items(): if not k.startswith('_'): a = getattr(AttributeCache.get(k), self.ret_key) facet_result[a] = [(f[0], f[1], a) for f in v] return facet_result
def _range_query_handler(attr, v): start, end = [x.strip() for x in v[1:-1].split("_TO_")] table_name = TableMap(attr_name=attr.name).table_name range_query = "BETWEEN '{0}' AND '{1}'".format(start.replace("*", "%"), end.replace("*", "%")) _query_sql = QUERY_CI_BY_ATTR_NAME.format(table_name, attr.id, range_query) return _query_sql
def _in_query_handler(attr, v): new_v = v[1:-1].split(";") table_name = TableMap(attr_name=attr.name).table_name in_query = " OR {0}.value ".format(table_name).join(['LIKE "{0}"'.format(_v.replace("*", "%")) for _v in new_v]) _query_sql = QUERY_CI_BY_ATTR_NAME.format(table_name, attr.id, in_query) return _query_sql