diff --git a/__init__.py b/__init__.py index 62a98b8..94f505e 100644 --- a/__init__.py +++ b/__init__.py @@ -32,7 +32,7 @@ MODULES = ( (core.ci, "/api/v0.1/ci"), (core.history, "/api/v0.1/history"), (core.account, "/api/v0.1/accounts"), - # (core.special, ""), + (core.special, ""), ) diff --git a/core/__init__.py b/core/__init__.py index 203368d..99d8104 100644 --- a/core/__init__.py +++ b/core/__init__.py @@ -8,4 +8,4 @@ from ci_relation import cirelation from ci import ci from history import history from account import account -# from special import special \ No newline at end of file +from special import special \ No newline at end of file diff --git a/core/attribute.py b/core/attribute.py index fd1aa54..1d79a7b 100644 --- a/core/attribute.py +++ b/core/attribute.py @@ -102,15 +102,21 @@ def delete_attribute(attr_id=None): @attribute.route("/citype/", methods=["GET"]) -def get_attributes_by_type(type_id=None): +@attribute.route("/citype/", methods=["GET"]) +def get_attributes_by_type(type_id=None, type_name=None): manager = CITypeAttributeManager() from models.attribute import CIAttributeCache from models.ci_type import CITypeCache + from models.ci_type import CITypeAttributeCache t = CITypeCache.get(type_id) 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 + CITypeAttributeCache.clean(type_id) unique = CIAttributeCache.get(uniq_id).attr_name return jsonify(attributes=manager.get_attributes_by_type_id(type_id), type_id=type_id, uniq_id=uniq_id, unique=unique) diff --git a/core/ci.py b/core/ci.py index 151e0aa..3f13eae 100644 --- a/core/ci.py +++ b/core/ci.py @@ -16,6 +16,7 @@ from flask import abort from lib.auth import auth_with_key from lib.ci import CIManager +from lib.ci import HostNumStatis from lib.search import Search from lib.search import SearchError from lib.utils import get_page @@ -156,6 +157,14 @@ def update_ci(): return jsonify(ci_id=ci_id) +@ci.route("//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("/", methods=["DELETE"]) @auth_with_key def delete_ci(ci_id=None): @@ -186,4 +195,22 @@ def get_heartbeat(): numfound, result = CIManager().get_heartbeat(page, ci_type, agent_status=agent_status) - return jsonify(numfound=numfound, result=result) \ No newline at end of file + 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) \ No newline at end of file diff --git a/core/ci_type.py b/core/ci_type.py index 85efa12..18aa23c 100644 --- a/core/ci_type.py +++ b/core/ci_type.py @@ -86,4 +86,4 @@ def enable(type_id=None): enable = request.values.get("enable", True) manager = CITypeManager() manager.set_enabled(type_id, enabled=enable) - return jsonify(type_id=type_id) \ No newline at end of file + return jsonify(type_id=type_id) diff --git a/lib/auth.py b/lib/auth.py index ce43d43..5a00b83 100644 --- a/lib/auth.py +++ b/lib/auth.py @@ -18,10 +18,10 @@ from models.account import UserCache def auth_with_key(func): @wraps(func) def wrapper(*args, **kwargs): - if isinstance(getattr(g, 'user', None), User): - identity_changed.send(current_app._get_current_object(), - identity=Identity(g.user.uid)) - return func(*args, **kwargs) + # if isinstance(getattr(g, 'user', None), User): + # identity_changed.send(current_app._get_current_object(), + # identity=Identity(g.user.uid)) + # return func(*args, **kwargs) ip = request.remote_addr if request.data: request_args = dict() @@ -46,7 +46,7 @@ def auth_with_key(func): else: identity_changed.send(current_app._get_current_object(), identity=AnonymousIdentity()) - return abort(400, "invalid _key and _secret") + return abort(401, "invalid _key and _secret") path = request.path @@ -63,6 +63,6 @@ def auth_with_key(func): else: identity_changed.send(current_app._get_current_object(), identity=AnonymousIdentity()) - return abort(400, "invalid _key and _secret") + return abort(401, "invalid _key and _secret") return wrapper diff --git a/lib/ci.py b/lib/ci.py index 28e5f91..e34be25 100644 --- a/lib/ci.py +++ b/lib/ci.py @@ -140,16 +140,16 @@ class CIManager(object): abort(404, "CIType {0} is not existed".format(ci_type_name)) 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) \ - 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) if old_ci is not None: ci_existed = True 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 old_ci.type_id = ci_type.type_id db.session.add(old_ci) @@ -169,7 +169,7 @@ class CIManager(object): except Exception as e: db.session.rollback() 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() histories = list() for p, v in ci_dict.items(): @@ -182,7 +182,7 @@ class CIManager(object): if not ci_existed: self.delete(ci.ci_id) current_app.logger.info(res) - return abort(500, res) + return abort(400, res) if res is not None: histories.append(res) try: @@ -192,12 +192,39 @@ class CIManager(object): db.session.rollback() if not ci_existed: # only add self.delete(ci.ci_id) - return abort(500, "add CI error") + return abort(400, "add CI error") his_manager = CIAttributeHistoryManger() his_manager.add(ci.ci_id, histories) ci_cache.apply_async([ci.ci_id], queue="cmdb_async") 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): ci = db.session.query(CI).filter(CI.ci_id == ci_id).first() if ci is not None: @@ -224,7 +251,7 @@ class CIManager(object): except Exception as e: db.session.rollback() 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 ci_delete.apply_async([ci.ci_id], queue="cmdb_async") return ci_id @@ -485,7 +512,7 @@ class CIRelationManager(object): db.session.rollback() current_app.logger.error("add CIRelation is error, {0}".format( 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 his_manager = CIRelationHistoryManager() 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( "delete CIRelation is error, {0}".format(str(e))) 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.add(cr_id, first_ci, second_ci, cr.relation_type, operate_type="delete") diff --git a/lib/ci_type.py b/lib/ci_type.py index 728beed..51f70ca 100644 --- a/lib/ci_type.py +++ b/lib/ci_type.py @@ -30,6 +30,7 @@ class CITypeAttributeManager(object): for attr in attrs: attr_dict = attr_manager.get_attribute_by_id(attr.attr_id) attr_dict["is_required"] = attr.is_required + attr_dict["order"] = attr.order result.append(attr_dict) return result diff --git a/lib/query_sql.py b/lib/query_sql.py index 960f02b..66e89b1 100644 --- a/lib/query_sql.py +++ b/lib/query_sql.py @@ -88,9 +88,9 @@ FACET_QUERY = """ SELECT {0}.value, count({0}.ci_id) 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} - GROUP BY {0}.ci_id + GROUP BY {0}.value """ QUERY_CI_BY_ATTR_NAME = """ diff --git a/lib/search.py b/lib/search.py index 341950d..72e9b21 100644 --- a/lib/search.py +++ b/lib/search.py @@ -139,6 +139,12 @@ class Search(object): "ORDER BY B.ci_id {1} LIMIT {0:d}, {2};".format( (self.page - 1) * self.count, sort_type, self.count)) 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 FROM ({0}) AS B {1}""".format( query_sql, @@ -148,6 +154,10 @@ class Search(object): (self.page - 1) * self.count, sort_type, self.count, ",".join(self.type_id_list))) 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 FROM ({0}) AS B {1}""".format( query_sql, @@ -172,6 +182,12 @@ class Search(object): (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 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 FROM ({0}) AS C 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 query_sql = FACET_QUERY.format( table_name, self.query_sql, attr.attr_id) + current_app.logger.debug(query_sql) result = db.session.execute(query_sql).fetchall() facet[k] = result facet_result = dict() diff --git a/models/ci_type.py b/models/ci_type.py index a995c82..7ec4e78 100644 --- a/models/ci_type.py +++ b/models/ci_type.py @@ -30,6 +30,7 @@ class CITypeAttribute(db.Model): db.ForeignKey("ci_attributes.attr_id"), primary_key=True) is_required = db.Column(db.Boolean, default=False) + order = db.Column(db.Integer, default=0) __table_args__ = (db.UniqueConstraint("type_id", "attr_id", name="type_attr_uniq"), )