facet query fix

This commit is contained in:
pycook 2016-04-12 13:54:09 +08:00
parent f515988dbd
commit b2f0afd73d
11 changed files with 102 additions and 23 deletions

View File

@ -32,7 +32,7 @@ MODULES = (
(core.ci, "/api/v0.1/ci"), (core.ci, "/api/v0.1/ci"),
(core.history, "/api/v0.1/history"), (core.history, "/api/v0.1/history"),
(core.account, "/api/v0.1/accounts"), (core.account, "/api/v0.1/accounts"),
# (core.special, ""), (core.special, ""),
) )

View File

@ -8,4 +8,4 @@ from ci_relation import cirelation
from ci import ci from ci import ci
from history import history from history import history
from account import account from account import account
# from special import special from special import special

View File

@ -102,15 +102,21 @@ def delete_attribute(attr_id=None):
@attribute.route("/citype/<int:type_id>", methods=["GET"]) @attribute.route("/citype/<int:type_id>", methods=["GET"])
def get_attributes_by_type(type_id=None): @attribute.route("/citype/<string:type_name>", methods=["GET"])
def get_attributes_by_type(type_id=None, type_name=None):
manager = CITypeAttributeManager() manager = CITypeAttributeManager()
from models.attribute import CIAttributeCache from models.attribute import CIAttributeCache
from models.ci_type import CITypeCache from models.ci_type import CITypeCache
from models.ci_type import CITypeAttributeCache
t = CITypeCache.get(type_id) t = CITypeCache.get(type_id)
if not t: if not t:
return abort(400, "CIType {0} is not existed".format(type_id)) t = CITypeCache.get(type_name)
if not t:
return abort(400, "CIType {0} is not existed".format(type_id))
type_id = t.type_id
uniq_id = t.uniq_id uniq_id = t.uniq_id
CITypeAttributeCache.clean(type_id)
unique = CIAttributeCache.get(uniq_id).attr_name unique = CIAttributeCache.get(uniq_id).attr_name
return jsonify(attributes=manager.get_attributes_by_type_id(type_id), return jsonify(attributes=manager.get_attributes_by_type_id(type_id),
type_id=type_id, uniq_id=uniq_id, unique=unique) type_id=type_id, uniq_id=uniq_id, unique=unique)

View File

@ -16,6 +16,7 @@ from flask import abort
from lib.auth import auth_with_key from lib.auth import auth_with_key
from lib.ci import CIManager from lib.ci import CIManager
from lib.ci import HostNumStatis
from lib.search import Search from lib.search import Search
from lib.search import SearchError from lib.search import SearchError
from lib.utils import get_page from lib.utils import get_page
@ -156,6 +157,14 @@ def update_ci():
return jsonify(ci_id=ci_id) return jsonify(ci_id=ci_id)
@ci.route("/<int:ci_id>/unique", methods=["PUT"])
@auth_with_key
def update_ci_unique(ci_id):
m = CIManager()
m.update_unique_value(ci_id, request.values)
return jsonify(ci_id=ci_id)
@ci.route("/<int:ci_id>", methods=["DELETE"]) @ci.route("/<int:ci_id>", methods=["DELETE"])
@auth_with_key @auth_with_key
def delete_ci(ci_id=None): def delete_ci(ci_id=None):
@ -186,4 +195,22 @@ def get_heartbeat():
numfound, result = CIManager().get_heartbeat(page, numfound, result = CIManager().get_heartbeat(page,
ci_type, ci_type,
agent_status=agent_status) agent_status=agent_status)
return jsonify(numfound=numfound, result=result) return jsonify(numfound=numfound, result=result)
######################### just for frontend ###################################
@ci.route("/hosts/nums", methods=["GET"])
def get_hosts_nums():
ci_type = request.args.get("ci_type", "").strip()
ci_ids = request.args.get("ci_ids", "").strip()
ci_id_list = ci_ids.split(",")
ci_id_list = map(str, filter(lambda x: x != "", ci_id_list))
res = {}
if ci_type == "bu":
res = HostNumStatis().get_hosts_by_bu(ci_id_list)
elif ci_type == "product":
res = HostNumStatis().get_hosts_by_product(ci_id_list)
elif ci_type == "project":
res = HostNumStatis().get_hosts_by_project(ci_id_list)
return jsonify(hosts=res)

View File

@ -86,4 +86,4 @@ def enable(type_id=None):
enable = request.values.get("enable", True) enable = request.values.get("enable", True)
manager = CITypeManager() manager = CITypeManager()
manager.set_enabled(type_id, enabled=enable) manager.set_enabled(type_id, enabled=enable)
return jsonify(type_id=type_id) return jsonify(type_id=type_id)

View File

@ -18,10 +18,10 @@ from models.account import UserCache
def auth_with_key(func): def auth_with_key(func):
@wraps(func) @wraps(func)
def wrapper(*args, **kwargs): def wrapper(*args, **kwargs):
if isinstance(getattr(g, 'user', None), User): # if isinstance(getattr(g, 'user', None), User):
identity_changed.send(current_app._get_current_object(), # identity_changed.send(current_app._get_current_object(),
identity=Identity(g.user.uid)) # identity=Identity(g.user.uid))
return func(*args, **kwargs) # return func(*args, **kwargs)
ip = request.remote_addr ip = request.remote_addr
if request.data: if request.data:
request_args = dict() request_args = dict()
@ -46,7 +46,7 @@ def auth_with_key(func):
else: else:
identity_changed.send(current_app._get_current_object(), identity_changed.send(current_app._get_current_object(),
identity=AnonymousIdentity()) identity=AnonymousIdentity())
return abort(400, "invalid _key and _secret") return abort(401, "invalid _key and _secret")
path = request.path path = request.path
@ -63,6 +63,6 @@ def auth_with_key(func):
else: else:
identity_changed.send(current_app._get_current_object(), identity_changed.send(current_app._get_current_object(),
identity=AnonymousIdentity()) identity=AnonymousIdentity())
return abort(400, "invalid _key and _secret") return abort(401, "invalid _key and _secret")
return wrapper return wrapper

View File

@ -140,16 +140,16 @@ class CIManager(object):
abort(404, "CIType {0} is not existed".format(ci_type_name)) abort(404, "CIType {0} is not existed".format(ci_type_name))
unique_key = CIAttributeCache.get(ci_type.uniq_id) \ unique_key = CIAttributeCache.get(ci_type.uniq_id) \
or abort(500, 'illegality unique attribute') or abort(400, 'illegality unique attribute')
unique = ci_dict.get(unique_key.attr_name) \ unique = ci_dict.get(unique_key.attr_name) \
or abort(500, '{0} missing'.format(unique_key.attr_name)) or abort(400, '{0} missing'.format(unique_key.attr_name))
old_ci = self.ci_is_exist(ci_type, unique_key, unique) old_ci = self.ci_is_exist(ci_type, unique_key, unique)
if old_ci is not None: if old_ci is not None:
ci_existed = True ci_existed = True
if exist_policy == 'reject': if exist_policy == 'reject':
return abort(500, 'CI is existed') return abort(400, 'CI is existed')
if old_ci.type_id != ci_type.type_id: # update ci_type if old_ci.type_id != ci_type.type_id: # update ci_type
old_ci.type_id = ci_type.type_id old_ci.type_id = ci_type.type_id
db.session.add(old_ci) db.session.add(old_ci)
@ -169,7 +169,7 @@ class CIManager(object):
except Exception as e: except Exception as e:
db.session.rollback() db.session.rollback()
current_app.logger.error('add CI error: {0}'.format(str(e))) current_app.logger.error('add CI error: {0}'.format(str(e)))
return abort(500, 'add CI error') return abort(400, 'add CI error')
value_manager = AttributeValueManager() value_manager = AttributeValueManager()
histories = list() histories = list()
for p, v in ci_dict.items(): for p, v in ci_dict.items():
@ -182,7 +182,7 @@ class CIManager(object):
if not ci_existed: if not ci_existed:
self.delete(ci.ci_id) self.delete(ci.ci_id)
current_app.logger.info(res) current_app.logger.info(res)
return abort(500, res) return abort(400, res)
if res is not None: if res is not None:
histories.append(res) histories.append(res)
try: try:
@ -192,12 +192,39 @@ class CIManager(object):
db.session.rollback() db.session.rollback()
if not ci_existed: # only add if not ci_existed: # only add
self.delete(ci.ci_id) self.delete(ci.ci_id)
return abort(500, "add CI error") return abort(400, "add CI error")
his_manager = CIAttributeHistoryManger() his_manager = CIAttributeHistoryManger()
his_manager.add(ci.ci_id, histories) his_manager.add(ci.ci_id, histories)
ci_cache.apply_async([ci.ci_id], queue="cmdb_async") ci_cache.apply_async([ci.ci_id], queue="cmdb_async")
return ci.ci_id return ci.ci_id
def update_unique_value(self, ci_id, args):
ci = self.get_ci_by_id(ci_id, need_children=False)
unique_key = ci.get("unique")
attr = CIAttributeCache.get(unique_key)
table_key = "index_{0}".format(attr.value_type) \
if attr.is_index else attr.value_type
value_table = type_map.get("table").get(table_key)
v = args.get(unique_key)
if value_table and v:
item = db.session.query(value_table).filter(
value_table.ci_id == ci_id).filter(
value_table.attr_id == attr.attr_id).first()
if item:
converter = type_map.get("converter").get(attr.value_type)
try:
item.value = converter(v)
except:
return abort(400, "value is illegal")
db.session.add(item)
try:
db.session.commit()
except Exception as e:
db.session.rollback()
current_app.logger.error(str(e))
return abort(400, "update unique failed")
ci_cache.apply_async([ci_id], queue="cmdb_async")
def delete(self, ci_id): def delete(self, ci_id):
ci = db.session.query(CI).filter(CI.ci_id == ci_id).first() ci = db.session.query(CI).filter(CI.ci_id == ci_id).first()
if ci is not None: if ci is not None:
@ -224,7 +251,7 @@ class CIManager(object):
except Exception as e: except Exception as e:
db.session.rollback() db.session.rollback()
current_app.logger.error("delete CI error, {0}".format(str(e))) current_app.logger.error("delete CI error, {0}".format(str(e)))
return abort(500, "delete CI error, {0}".format(str(e))) return abort(400, "delete CI error, {0}".format(str(e)))
# TODO: write history # TODO: write history
ci_delete.apply_async([ci.ci_id], queue="cmdb_async") ci_delete.apply_async([ci.ci_id], queue="cmdb_async")
return ci_id return ci_id
@ -485,7 +512,7 @@ class CIRelationManager(object):
db.session.rollback() db.session.rollback()
current_app.logger.error("add CIRelation is error, {0}".format( current_app.logger.error("add CIRelation is error, {0}".format(
str(e))) str(e)))
return abort(500, "add CIRelation is error, {0}".format(str(e))) return abort(400, "add CIRelation is error, {0}".format(str(e)))
# write history # write history
his_manager = CIRelationHistoryManager() his_manager = CIRelationHistoryManager()
his_manager.add(cr.cr_id, cr.first_ci_id, cr.second_ci_id, his_manager.add(cr.cr_id, cr.first_ci_id, cr.second_ci_id,
@ -507,7 +534,7 @@ class CIRelationManager(object):
current_app.logger.error( current_app.logger.error(
"delete CIRelation is error, {0}".format(str(e))) "delete CIRelation is error, {0}".format(str(e)))
return abort( return abort(
500, "delete CIRelation is error, {0}".format(str(e))) 400, "delete CIRelation is error, {0}".format(str(e)))
his_manager = CIRelationHistoryManager() his_manager = CIRelationHistoryManager()
his_manager.add(cr_id, first_ci, second_ci, his_manager.add(cr_id, first_ci, second_ci,
cr.relation_type, operate_type="delete") cr.relation_type, operate_type="delete")

View File

@ -30,6 +30,7 @@ class CITypeAttributeManager(object):
for attr in attrs: for attr in attrs:
attr_dict = attr_manager.get_attribute_by_id(attr.attr_id) attr_dict = attr_manager.get_attribute_by_id(attr.attr_id)
attr_dict["is_required"] = attr.is_required attr_dict["is_required"] = attr.is_required
attr_dict["order"] = attr.order
result.append(attr_dict) result.append(attr_dict)
return result return result

View File

@ -88,9 +88,9 @@ FACET_QUERY = """
SELECT {0}.value, SELECT {0}.value,
count({0}.ci_id) count({0}.ci_id)
FROM {0} FROM {0}
INNER JOIN ({1}) AS B ON B.ci_id={0}.ci_id INNER JOIN ({1}) AS F ON F.ci_id={0}.ci_id
WHERE {0}.attr_id={2:d} WHERE {0}.attr_id={2:d}
GROUP BY {0}.ci_id GROUP BY {0}.value
""" """
QUERY_CI_BY_ATTR_NAME = """ QUERY_CI_BY_ATTR_NAME = """

View File

@ -139,6 +139,12 @@ class Search(object):
"ORDER BY B.ci_id {1} LIMIT {0:d}, {2};".format( "ORDER BY B.ci_id {1} LIMIT {0:d}, {2};".format(
(self.page - 1) * self.count, sort_type, self.count)) (self.page - 1) * self.count, sort_type, self.count))
elif self.type_id_list: elif self.type_id_list:
self.query_sql = """SELECT B.ci_id
FROM ({0}) AS B {1}""".format(
query_sql,
"INNER JOIN cis on cis.ci_id=B.ci_id "
"WHERE cis.type_id in ({0}) ".format(
",".join(self.type_id_list)))
return """SELECT SQL_CALC_FOUND_ROWS DISTINCT B.ci_id return """SELECT SQL_CALC_FOUND_ROWS DISTINCT B.ci_id
FROM ({0}) AS B {1}""".format( FROM ({0}) AS B {1}""".format(
query_sql, query_sql,
@ -148,6 +154,10 @@ class Search(object):
(self.page - 1) * self.count, sort_type, self.count, (self.page - 1) * self.count, sort_type, self.count,
",".join(self.type_id_list))) ",".join(self.type_id_list)))
else: else:
self.query_sql = """SELECT B.ci_id
FROM ({0}) AS B {1}""".format(
query_sql,
"INNER JOIN cis on cis.ci_id=B.ci_id ")
return """SELECT SQL_CALC_FOUND_ROWS DISTINCT B.ci_id return """SELECT SQL_CALC_FOUND_ROWS DISTINCT B.ci_id
FROM ({0}) AS B {1}""".format( FROM ({0}) AS B {1}""".format(
query_sql, query_sql,
@ -172,6 +182,12 @@ class Search(object):
(self.page - 1) * self.count, (self.page - 1) * self.count,
sort_type, self.count) sort_type, self.count)
elif self.type_id_list: elif self.type_id_list:
self.query_sql = """SELECT C.ci_id
FROM ({0}) AS C
INNER JOIN cis on cis.ci_id=C.ci_id
WHERE cis.type_id in ({1})""".format(
new_table,
",".join(self.type_id_list))
return """SELECT SQL_CALC_FOUND_ROWS DISTINCT C.ci_id return """SELECT SQL_CALC_FOUND_ROWS DISTINCT C.ci_id
FROM ({0}) AS C FROM ({0}) AS C
INNER JOIN cis on cis.ci_id=C.ci_id INNER JOIN cis on cis.ci_id=C.ci_id
@ -306,6 +322,7 @@ class Search(object):
table_name = TableMap(attr_name=k).table_name table_name = TableMap(attr_name=k).table_name
query_sql = FACET_QUERY.format( query_sql = FACET_QUERY.format(
table_name, self.query_sql, attr.attr_id) table_name, self.query_sql, attr.attr_id)
current_app.logger.debug(query_sql)
result = db.session.execute(query_sql).fetchall() result = db.session.execute(query_sql).fetchall()
facet[k] = result facet[k] = result
facet_result = dict() facet_result = dict()

View File

@ -30,6 +30,7 @@ class CITypeAttribute(db.Model):
db.ForeignKey("ci_attributes.attr_id"), db.ForeignKey("ci_attributes.attr_id"),
primary_key=True) primary_key=True)
is_required = db.Column(db.Boolean, default=False) is_required = db.Column(db.Boolean, default=False)
order = db.Column(db.Integer, default=0)
__table_args__ = (db.UniqueConstraint("type_id", "attr_id", __table_args__ = (db.UniqueConstraint("type_id", "attr_id",
name="type_attr_uniq"), ) name="type_attr_uniq"), )