mirror of https://github.com/veops/cmdb.git
feat(api): ci baseline rollback (#498)
This commit is contained in:
parent
b4326722e6
commit
7d9ef229c2
|
@ -441,10 +441,13 @@ class CIManager(object):
|
||||||
now = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
now = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||||
ci = self.confirm_ci_existed(ci_id)
|
ci = self.confirm_ci_existed(ci_id)
|
||||||
|
|
||||||
raw_dict = copy.deepcopy(ci_dict)
|
|
||||||
|
|
||||||
attrs = CITypeAttributeManager.get_all_attributes(ci.type_id)
|
attrs = CITypeAttributeManager.get_all_attributes(ci.type_id)
|
||||||
ci_type_attrs_name = {attr.name: attr for _, attr in attrs}
|
ci_type_attrs_name = {attr.name: attr for _, attr in attrs}
|
||||||
|
ci_type_attrs_alias2name = {attr.alias: attr.name for _, attr in attrs}
|
||||||
|
ci_dict = {ci_type_attrs_alias2name[k] if k in ci_type_attrs_alias2name else k: v for k, v in ci_dict.items()}
|
||||||
|
|
||||||
|
raw_dict = copy.deepcopy(ci_dict)
|
||||||
|
|
||||||
ci_attr2type_attr = {type_attr.attr_id: type_attr for type_attr, _ in attrs}
|
ci_attr2type_attr = {type_attr.attr_id: type_attr for type_attr, _ in attrs}
|
||||||
for _, attr in attrs:
|
for _, attr in attrs:
|
||||||
if attr.default and attr.default.get('default') == AttributeDefaultValueEnum.UPDATED_AT:
|
if attr.default and attr.default.get('default') == AttributeDefaultValueEnum.UPDATED_AT:
|
||||||
|
@ -825,6 +828,105 @@ class CIManager(object):
|
||||||
|
|
||||||
return data.get('v')
|
return data.get('v')
|
||||||
|
|
||||||
|
def baseline(self, ci_ids, before_date):
|
||||||
|
ci_list = self.get_cis_by_ids(ci_ids, ret_key=RetKey.ALIAS)
|
||||||
|
if not ci_list:
|
||||||
|
return dict()
|
||||||
|
|
||||||
|
ci2changed = dict()
|
||||||
|
changed = AttributeHistoryManger.get_records_for_attributes(
|
||||||
|
before_date, None, None, 1, 100000, None, None, ci_ids=ci_ids, more=True)[1]
|
||||||
|
for records in changed:
|
||||||
|
for change in records[1]:
|
||||||
|
if change['is_computed'] or change['is_password']:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if change.get('default') and change['default'].get('default') == AttributeDefaultValueEnum.UPDATED_AT:
|
||||||
|
continue
|
||||||
|
|
||||||
|
ci2changed.setdefault(change['ci_id'], {})
|
||||||
|
item = (change['old'],
|
||||||
|
change['new'],
|
||||||
|
change.get('is_list'),
|
||||||
|
change.get('value_type'),
|
||||||
|
change['operate_type'])
|
||||||
|
if change.get('is_list'):
|
||||||
|
ci2changed[change['ci_id']].setdefault(change.get('attr_alias'), []).append(item)
|
||||||
|
else:
|
||||||
|
ci2changed[change['ci_id']].update({change.get('attr_alias'): item})
|
||||||
|
|
||||||
|
type2show_name = {}
|
||||||
|
result = []
|
||||||
|
for ci in ci_list:
|
||||||
|
list_attr2item = {}
|
||||||
|
for alias_name, v in (ci2changed.get(ci['_id']) or {}).items():
|
||||||
|
if not alias_name:
|
||||||
|
continue
|
||||||
|
if alias_name == ci.get('unique_alias'):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if ci.get('_type') not in type2show_name:
|
||||||
|
ci_type = CITypeCache.get(ci.get('_type'))
|
||||||
|
show_id = ci_type.show_id or ci_type.unique_id
|
||||||
|
type2show_name[ci['_type']] = AttributeCache.get(show_id).alias
|
||||||
|
|
||||||
|
if isinstance(v, list):
|
||||||
|
for old, new, is_list, value_type, operate_type in v:
|
||||||
|
if alias_name not in list_attr2item:
|
||||||
|
list_attr2item[alias_name] = dict(instance=ci.get(type2show_name[ci['_type']]),
|
||||||
|
attr_name=alias_name,
|
||||||
|
value_type=value_type,
|
||||||
|
is_list=is_list,
|
||||||
|
ci_type=ci.get('ci_type'),
|
||||||
|
unique_alias=ci.get('unique_alias'),
|
||||||
|
unique_value=ci.get(ci['unique_alias']),
|
||||||
|
cur=copy.deepcopy(ci.get(alias_name)),
|
||||||
|
to=ci.get(alias_name) or [])
|
||||||
|
|
||||||
|
old = ValueTypeMap.deserialize[value_type](old) if old else old
|
||||||
|
new = ValueTypeMap.deserialize[value_type](new) if new else new
|
||||||
|
if operate_type == OperateType.ADD:
|
||||||
|
list_attr2item[alias_name]['to'].remove(new)
|
||||||
|
elif operate_type == OperateType.DELETE and old not in list_attr2item[alias_name]['to']:
|
||||||
|
list_attr2item[alias_name]['to'].append(old)
|
||||||
|
continue
|
||||||
|
|
||||||
|
old, value_type = v[0], v[3]
|
||||||
|
old = ValueTypeMap.deserialize[value_type](old) if old else old
|
||||||
|
if isinstance(old, (datetime.datetime, datetime.date)):
|
||||||
|
old = str(old)
|
||||||
|
if ci.get(alias_name) != old:
|
||||||
|
item = dict(instance=ci.get(type2show_name[ci['_type']]),
|
||||||
|
attr_name=alias_name,
|
||||||
|
value_type=value_type,
|
||||||
|
ci_type=ci.get('ci_type'),
|
||||||
|
unique_alias=ci.get('unique_alias'),
|
||||||
|
unique_value=ci.get(ci['unique_alias']),
|
||||||
|
cur=ci.get(alias_name),
|
||||||
|
to=old)
|
||||||
|
result.append(item)
|
||||||
|
|
||||||
|
for alias_name, item in list_attr2item.items():
|
||||||
|
if sorted(item['cur'] or []) != sorted(item['to'] or []):
|
||||||
|
result.append(item)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def rollback(self, ci_id, before_date):
|
||||||
|
baseline_ci = self.baseline([ci_id], before_date)
|
||||||
|
|
||||||
|
payload = dict()
|
||||||
|
for item in baseline_ci:
|
||||||
|
payload[item.get('attr_name')] = item.get('to')
|
||||||
|
|
||||||
|
if payload:
|
||||||
|
payload['ci_type'] = baseline_ci[0]['ci_type']
|
||||||
|
payload[baseline_ci[0]['unique_alias']] = baseline_ci[0]['unique_value']
|
||||||
|
|
||||||
|
self.update(ci_id, **payload)
|
||||||
|
|
||||||
|
return payload
|
||||||
|
|
||||||
|
|
||||||
class CIRelationManager(object):
|
class CIRelationManager(object):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -253,6 +253,13 @@ class CITypeManager(object):
|
||||||
for item in CITypeInheritance.get_by(child_id=type_id, to_dict=False):
|
for item in CITypeInheritance.get_by(child_id=type_id, to_dict=False):
|
||||||
item.delete(commit=False)
|
item.delete(commit=False)
|
||||||
|
|
||||||
|
try:
|
||||||
|
from api.models.cmdb import CITypeReconciliation
|
||||||
|
for item in CITypeReconciliation.get_by(type_id=type_id, to_dict=False):
|
||||||
|
item.delete(commit=False)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
ci_type.soft_delete()
|
ci_type.soft_delete()
|
||||||
|
@ -414,9 +421,6 @@ class CITypeGroupManager(object):
|
||||||
existed = CITypeGroup.get_by_id(gid) or abort(
|
existed = CITypeGroup.get_by_id(gid) or abort(
|
||||||
404, ErrFormat.ci_type_group_not_found.format("id={}".format(gid)))
|
404, ErrFormat.ci_type_group_not_found.format("id={}".format(gid)))
|
||||||
if name is not None and name != existed.name:
|
if name is not None and name != existed.name:
|
||||||
if RoleEnum.CONFIG not in session.get("acl", {}).get("parentRoles", []) and not is_app_admin("cmdb"):
|
|
||||||
return abort(403, ErrFormat.role_required.format(RoleEnum.CONFIG))
|
|
||||||
|
|
||||||
existed.update(name=name)
|
existed.update(name=name)
|
||||||
|
|
||||||
max_order = max([i.order or 0 for i in CITypeGroupItem.get_by(group_id=gid, to_dict=False)] or [0])
|
max_order = max([i.order or 0 for i in CITypeGroupItem.get_by(group_id=gid, to_dict=False)] or [0])
|
||||||
|
|
|
@ -55,6 +55,9 @@ class CITypeOperateType(BaseEnum):
|
||||||
DELETE_UNIQUE_CONSTRAINT = "11" # 删除联合唯一
|
DELETE_UNIQUE_CONSTRAINT = "11" # 删除联合唯一
|
||||||
ADD_RELATION = "12" # 新增关系
|
ADD_RELATION = "12" # 新增关系
|
||||||
DELETE_RELATION = "13" # 删除关系
|
DELETE_RELATION = "13" # 删除关系
|
||||||
|
ADD_RECONCILIATION = "14" # 删除关系
|
||||||
|
UPDATE_RECONCILIATION = "15" # 删除关系
|
||||||
|
DELETE_RECONCILIATION = "16" # 删除关系
|
||||||
|
|
||||||
|
|
||||||
class RetKey(BaseEnum):
|
class RetKey(BaseEnum):
|
||||||
|
@ -98,6 +101,12 @@ class AttributeDefaultValueEnum(BaseEnum):
|
||||||
AUTO_INC_ID = "$auto_inc_id"
|
AUTO_INC_ID = "$auto_inc_id"
|
||||||
|
|
||||||
|
|
||||||
|
class ExecuteStatusEnum(BaseEnum):
|
||||||
|
COMPLETED = '0'
|
||||||
|
FAILED = '1'
|
||||||
|
RUNNING = '2'
|
||||||
|
|
||||||
|
|
||||||
CMDB_QUEUE = "one_cmdb_async"
|
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"
|
||||||
|
|
|
@ -26,7 +26,7 @@ from api.models.cmdb import OperationRecord
|
||||||
class AttributeHistoryManger(object):
|
class AttributeHistoryManger(object):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_records_for_attributes(start, end, username, page, page_size, operate_type, type_id,
|
def get_records_for_attributes(start, end, username, page, page_size, operate_type, type_id,
|
||||||
ci_id=None, attr_id=None):
|
ci_id=None, attr_id=None, ci_ids=None, more=False):
|
||||||
|
|
||||||
records = db.session.query(OperationRecord, AttributeHistory).join(
|
records = db.session.query(OperationRecord, AttributeHistory).join(
|
||||||
AttributeHistory, OperationRecord.id == AttributeHistory.record_id)
|
AttributeHistory, OperationRecord.id == AttributeHistory.record_id)
|
||||||
|
@ -48,6 +48,9 @@ class AttributeHistoryManger(object):
|
||||||
if ci_id is not None:
|
if ci_id is not None:
|
||||||
records = records.filter(AttributeHistory.ci_id == ci_id)
|
records = records.filter(AttributeHistory.ci_id == ci_id)
|
||||||
|
|
||||||
|
if ci_ids and isinstance(ci_ids, list):
|
||||||
|
records = records.filter(AttributeHistory.ci_id.in_(ci_ids))
|
||||||
|
|
||||||
if attr_id is not None:
|
if attr_id is not None:
|
||||||
records = records.filter(AttributeHistory.attr_id == attr_id)
|
records = records.filter(AttributeHistory.attr_id == attr_id)
|
||||||
|
|
||||||
|
@ -62,6 +65,12 @@ class AttributeHistoryManger(object):
|
||||||
if attr_hist['attr']:
|
if attr_hist['attr']:
|
||||||
attr_hist['attr_name'] = attr_hist['attr'].name
|
attr_hist['attr_name'] = attr_hist['attr'].name
|
||||||
attr_hist['attr_alias'] = attr_hist['attr'].alias
|
attr_hist['attr_alias'] = attr_hist['attr'].alias
|
||||||
|
if more:
|
||||||
|
attr_hist['is_list'] = attr_hist['attr'].is_list
|
||||||
|
attr_hist['is_computed'] = attr_hist['attr'].is_computed
|
||||||
|
attr_hist['is_password'] = attr_hist['attr'].is_password
|
||||||
|
attr_hist['default'] = attr_hist['attr'].default
|
||||||
|
attr_hist['value_type'] = attr_hist['attr'].value_type
|
||||||
attr_hist.pop("attr")
|
attr_hist.pop("attr")
|
||||||
|
|
||||||
if record_id not in res:
|
if record_id not in res:
|
||||||
|
@ -161,6 +170,7 @@ class AttributeHistoryManger(object):
|
||||||
record = i.OperationRecord
|
record = i.OperationRecord
|
||||||
item = dict(attr_name=attr.name,
|
item = dict(attr_name=attr.name,
|
||||||
attr_alias=attr.alias,
|
attr_alias=attr.alias,
|
||||||
|
value_type=attr.value_type,
|
||||||
operate_type=hist.operate_type,
|
operate_type=hist.operate_type,
|
||||||
username=user and user.nickname,
|
username=user and user.nickname,
|
||||||
old=hist.old,
|
old=hist.old,
|
||||||
|
@ -271,7 +281,7 @@ class CITypeHistoryManager(object):
|
||||||
return numfound, result
|
return numfound, result
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def add(operate_type, type_id, attr_id=None, trigger_id=None, unique_constraint_id=None, change=None):
|
def add(operate_type, type_id, attr_id=None, trigger_id=None, unique_constraint_id=None, change=None, rc_id=None):
|
||||||
if type_id is None and attr_id is not None:
|
if type_id is None and attr_id is not None:
|
||||||
from api.models.cmdb import CITypeAttribute
|
from api.models.cmdb import CITypeAttribute
|
||||||
type_ids = [i.type_id for i in CITypeAttribute.get_by(attr_id=attr_id, to_dict=False)]
|
type_ids = [i.type_id for i in CITypeAttribute.get_by(attr_id=attr_id, to_dict=False)]
|
||||||
|
@ -284,6 +294,7 @@ class CITypeHistoryManager(object):
|
||||||
uid=current_user.uid,
|
uid=current_user.uid,
|
||||||
attr_id=attr_id,
|
attr_id=attr_id,
|
||||||
trigger_id=trigger_id,
|
trigger_id=trigger_id,
|
||||||
|
rc_id=rc_id,
|
||||||
unique_constraint_id=unique_constraint_id,
|
unique_constraint_id=unique_constraint_id,
|
||||||
change=change)
|
change=change)
|
||||||
|
|
||||||
|
|
|
@ -78,6 +78,8 @@ class ErrFormat(CommonErrFormat):
|
||||||
unique_constraint_invalid = _l("Uniquely constrained attributes cannot be JSON and multi-valued")
|
unique_constraint_invalid = _l("Uniquely constrained attributes cannot be JSON and multi-valued")
|
||||||
ci_type_trigger_duplicate = _l("Duplicated trigger") # 重复的触发器
|
ci_type_trigger_duplicate = _l("Duplicated trigger") # 重复的触发器
|
||||||
ci_type_trigger_not_found = _l("Trigger {} does not exist") # 触发器 {} 不存在
|
ci_type_trigger_not_found = _l("Trigger {} does not exist") # 触发器 {} 不存在
|
||||||
|
ci_type_reconciliation_duplicate = _l("Duplicated reconciliation rule") # 重复的校验规则
|
||||||
|
ci_type_reconciliation_not_found = _l("Reconciliation rule {} does not exist") # 规则 {} 不存在
|
||||||
|
|
||||||
record_not_found = _l("Operation record {} does not exist") # 操作记录 {} 不存在
|
record_not_found = _l("Operation record {} does not exist") # 操作记录 {} 不存在
|
||||||
cannot_delete_unique = _l("Unique identifier cannot be deleted") # 不能删除唯一标识
|
cannot_delete_unique = _l("Unique identifier cannot be deleted") # 不能删除唯一标识
|
||||||
|
|
|
@ -275,34 +275,27 @@ class AttributeValueManager(object):
|
||||||
if attr.is_list:
|
if attr.is_list:
|
||||||
existed_attrs = value_table.get_by(attr_id=attr.id, ci_id=ci.id, to_dict=False)
|
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]
|
existed_values = [i.value for i in existed_attrs]
|
||||||
|
added = set(value) - set(existed_values)
|
||||||
|
deleted = set(existed_values) - set(value)
|
||||||
|
for v in added:
|
||||||
|
value_table.create(ci_id=ci.id, attr_id=attr.id, value=v, flush=False, commit=False)
|
||||||
|
changed.append((ci.id, attr.id, OperateType.ADD, None, v, ci.type_id))
|
||||||
|
|
||||||
# Comparison array starts from which position changes
|
|
||||||
min_len = min(len(value), len(existed_values))
|
|
||||||
index = 0
|
|
||||||
while index < min_len:
|
|
||||||
if value[index] != existed_values[index]:
|
|
||||||
break
|
|
||||||
index += 1
|
|
||||||
added = value[index:]
|
|
||||||
deleted = existed_values[index:]
|
|
||||||
|
|
||||||
# Delete first and then add to ensure id sorting
|
|
||||||
for v in deleted:
|
for v in deleted:
|
||||||
existed_attr = existed_attrs[existed_values.index(v)]
|
existed_attr = existed_attrs[existed_values.index(v)]
|
||||||
existed_attr.delete(flush=False, commit=False)
|
existed_attr.delete(flush=False, commit=False)
|
||||||
changed.append((ci.id, attr.id, OperateType.DELETE, v, None, ci.type_id))
|
changed.append((ci.id, attr.id, OperateType.DELETE, v, None, ci.type_id))
|
||||||
for v in added:
|
|
||||||
value_table.create(ci_id=ci.id, attr_id=attr.id, value=v, flush=False, commit=False)
|
|
||||||
changed.append((ci.id, attr.id, OperateType.ADD, None, v, ci.type_id))
|
|
||||||
else:
|
else:
|
||||||
existed_attr = value_table.get_by(attr_id=attr.id, ci_id=ci.id, first=True, to_dict=False)
|
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
|
existed_value = existed_attr and existed_attr.value
|
||||||
|
existed_value = (ValueTypeMap.serialize[attr.value_type](existed_value) if
|
||||||
|
existed_value or existed_value == 0 else existed_value)
|
||||||
if existed_value is None and value is not None:
|
if existed_value is None and value is not None:
|
||||||
value_table.create(ci_id=ci.id, attr_id=attr.id, value=value, flush=False, commit=False)
|
value_table.create(ci_id=ci.id, attr_id=attr.id, value=value, flush=False, commit=False)
|
||||||
|
|
||||||
changed.append((ci.id, attr.id, OperateType.ADD, None, value, ci.type_id))
|
changed.append((ci.id, attr.id, OperateType.ADD, None, value, ci.type_id))
|
||||||
else:
|
else:
|
||||||
if existed_value != value:
|
if existed_value != value and existed_attr:
|
||||||
if value is None:
|
if value is None:
|
||||||
existed_attr.delete(flush=False, commit=False)
|
existed_attr.delete(flush=False, commit=False)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -224,16 +224,22 @@ class RoleRelationCache(object):
|
||||||
@classmethod
|
@classmethod
|
||||||
@flush_db
|
@flush_db
|
||||||
def rebuild(cls, rid, app_id):
|
def rebuild(cls, rid, app_id):
|
||||||
cls.clean(rid, app_id)
|
if app_id is None:
|
||||||
|
app_ids = [None] + [i.id for i in App.get_by(to_dict=False)]
|
||||||
cls.get_parent_ids(rid, app_id)
|
|
||||||
cls.get_child_ids(rid, app_id)
|
|
||||||
resources = cls.get_resources(rid, app_id)
|
|
||||||
if resources.get('id2perms') or resources.get('group2perms'):
|
|
||||||
HasResourceRoleCache.add(rid, app_id)
|
|
||||||
else:
|
else:
|
||||||
HasResourceRoleCache.remove(rid, app_id)
|
app_ids = [app_id]
|
||||||
cls.get_resources2(rid, app_id)
|
|
||||||
|
for _app_id in app_ids:
|
||||||
|
cls.clean(rid, _app_id)
|
||||||
|
|
||||||
|
cls.get_parent_ids(rid, _app_id)
|
||||||
|
cls.get_child_ids(rid, _app_id)
|
||||||
|
resources = cls.get_resources(rid, _app_id)
|
||||||
|
if resources.get('id2perms') or resources.get('group2perms'):
|
||||||
|
HasResourceRoleCache.add(rid, _app_id)
|
||||||
|
else:
|
||||||
|
HasResourceRoleCache.remove(rid, _app_id)
|
||||||
|
cls.get_resources2(rid, _app_id)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@flush_db
|
@flush_db
|
||||||
|
|
|
@ -274,12 +274,14 @@ class PermissionCRUD(object):
|
||||||
perm2resource.setdefault(_perm, []).append(resource_id)
|
perm2resource.setdefault(_perm, []).append(resource_id)
|
||||||
for _perm in perm2resource:
|
for _perm in perm2resource:
|
||||||
perm = PermissionCache.get(_perm, resource_type_id)
|
perm = PermissionCache.get(_perm, resource_type_id)
|
||||||
existeds = RolePermission.get_by(rid=rid,
|
if perm is None:
|
||||||
app_id=app_id,
|
continue
|
||||||
perm_id=perm.id,
|
exists = RolePermission.get_by(rid=rid,
|
||||||
__func_in___key_resource_id=perm2resource[_perm],
|
app_id=app_id,
|
||||||
to_dict=False)
|
perm_id=perm.id,
|
||||||
for existed in existeds:
|
__func_in___key_resource_id=perm2resource[_perm],
|
||||||
|
to_dict=False)
|
||||||
|
for existed in exists:
|
||||||
existed.deleted = True
|
existed.deleted = True
|
||||||
existed.deleted_at = datetime.datetime.now()
|
existed.deleted_at = datetime.datetime.now()
|
||||||
db.session.add(existed)
|
db.session.add(existed)
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
|
|
||||||
from flask import abort
|
from flask import abort
|
||||||
from flask import current_app
|
|
||||||
|
|
||||||
from api.extensions import db
|
from api.extensions import db
|
||||||
from api.lib.perm.acl.audit import AuditCRUD
|
from api.lib.perm.acl.audit import AuditCRUD
|
||||||
|
@ -127,11 +126,18 @@ class ResourceTypeCRUD(object):
|
||||||
existed_ids = [i.id for i in existed]
|
existed_ids = [i.id for i in existed]
|
||||||
current_ids = []
|
current_ids = []
|
||||||
|
|
||||||
|
rebuild_rids = set()
|
||||||
for i in existed:
|
for i in existed:
|
||||||
if i.name not in perms:
|
if i.name not in perms:
|
||||||
i.soft_delete()
|
i.soft_delete(commit=False)
|
||||||
|
for rp in RolePermission.get_by(perm_id=i.id, to_dict=False):
|
||||||
|
rp.soft_delete(commit=False)
|
||||||
|
rebuild_rids.add((rp.app_id, rp.rid))
|
||||||
else:
|
else:
|
||||||
current_ids.append(i.id)
|
current_ids.append(i.id)
|
||||||
|
db.session.commit()
|
||||||
|
for _app_id, _rid in rebuild_rids:
|
||||||
|
role_rebuild.apply_async(args=(_rid, _app_id), queue=ACL_QUEUE)
|
||||||
|
|
||||||
for i in perms:
|
for i in perms:
|
||||||
if i not in existed_names:
|
if i not in existed_names:
|
||||||
|
|
|
@ -3,12 +3,14 @@
|
||||||
|
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
import redis_lock
|
||||||
import six
|
import six
|
||||||
from flask import abort
|
from flask import abort
|
||||||
from flask import current_app
|
from flask import current_app
|
||||||
from sqlalchemy import or_
|
from sqlalchemy import or_
|
||||||
|
|
||||||
from api.extensions import db
|
from api.extensions import db
|
||||||
|
from api.extensions import rd
|
||||||
from api.lib.perm.acl.app import AppCRUD
|
from api.lib.perm.acl.app import AppCRUD
|
||||||
from api.lib.perm.acl.audit import AuditCRUD, AuditOperateType, AuditScope
|
from api.lib.perm.acl.audit import AuditCRUD, AuditOperateType, AuditScope
|
||||||
from api.lib.perm.acl.cache import AppCache
|
from api.lib.perm.acl.cache import AppCache
|
||||||
|
@ -62,7 +64,9 @@ class RoleRelationCRUD(object):
|
||||||
|
|
||||||
id2parents = {}
|
id2parents = {}
|
||||||
for i in res:
|
for i in res:
|
||||||
id2parents.setdefault(rid2uid.get(i.child_id, i.child_id), []).append(RoleCache.get(i.parent_id).to_dict())
|
parent = RoleCache.get(i.parent_id)
|
||||||
|
if parent:
|
||||||
|
id2parents.setdefault(rid2uid.get(i.child_id, i.child_id), []).append(parent.to_dict())
|
||||||
|
|
||||||
return id2parents
|
return id2parents
|
||||||
|
|
||||||
|
@ -141,24 +145,27 @@ class RoleRelationCRUD(object):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def add(cls, role, parent_id, child_ids, app_id):
|
def add(cls, role, parent_id, child_ids, app_id):
|
||||||
result = []
|
with redis_lock.Lock(rd.r, "ROLE_RELATION_ADD"):
|
||||||
for child_id in child_ids:
|
db.session.commit()
|
||||||
existed = RoleRelation.get_by(parent_id=parent_id, child_id=child_id, app_id=app_id)
|
|
||||||
if existed:
|
|
||||||
continue
|
|
||||||
|
|
||||||
RoleRelationCache.clean(parent_id, app_id)
|
result = []
|
||||||
RoleRelationCache.clean(child_id, app_id)
|
for child_id in child_ids:
|
||||||
|
existed = RoleRelation.get_by(parent_id=parent_id, child_id=child_id, app_id=app_id)
|
||||||
|
if existed:
|
||||||
|
continue
|
||||||
|
|
||||||
if parent_id in cls.recursive_child_ids(child_id, app_id):
|
RoleRelationCache.clean(parent_id, app_id)
|
||||||
return abort(400, ErrFormat.inheritance_dead_loop)
|
RoleRelationCache.clean(child_id, app_id)
|
||||||
|
|
||||||
if app_id is None:
|
if parent_id in cls.recursive_child_ids(child_id, app_id):
|
||||||
for app in AppCRUD.get_all():
|
return abort(400, ErrFormat.inheritance_dead_loop)
|
||||||
if app.name != "acl":
|
|
||||||
RoleRelationCache.clean(child_id, app.id)
|
|
||||||
|
|
||||||
result.append(RoleRelation.create(parent_id=parent_id, child_id=child_id, app_id=app_id).to_dict())
|
if app_id is None:
|
||||||
|
for app in AppCRUD.get_all():
|
||||||
|
if app.name != "acl":
|
||||||
|
RoleRelationCache.clean(child_id, app.id)
|
||||||
|
|
||||||
|
result.append(RoleRelation.create(parent_id=parent_id, child_id=child_id, app_id=app_id).to_dict())
|
||||||
|
|
||||||
AuditCRUD.add_role_log(app_id, AuditOperateType.role_relation_add,
|
AuditCRUD.add_role_log(app_id, AuditOperateType.role_relation_add,
|
||||||
AuditScope.role_relation, role.id, {}, {},
|
AuditScope.role_relation, role.id, {}, {},
|
||||||
|
|
|
@ -3,12 +3,13 @@
|
||||||
import json
|
import json
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from celery_once import QueueOnce
|
import redis_lock
|
||||||
from flask import current_app
|
from flask import current_app
|
||||||
from werkzeug.exceptions import BadRequest
|
from werkzeug.exceptions import BadRequest
|
||||||
from werkzeug.exceptions import NotFound
|
from werkzeug.exceptions import NotFound
|
||||||
|
|
||||||
from api.extensions import celery
|
from api.extensions import celery
|
||||||
|
from api.extensions import rd
|
||||||
from api.lib.decorator import flush_db
|
from api.lib.decorator import flush_db
|
||||||
from api.lib.decorator import reconnect_db
|
from api.lib.decorator import reconnect_db
|
||||||
from api.lib.perm.acl.audit import AuditCRUD
|
from api.lib.perm.acl.audit import AuditCRUD
|
||||||
|
@ -25,14 +26,14 @@ from api.models.acl import Role
|
||||||
from api.models.acl import Trigger
|
from api.models.acl import Trigger
|
||||||
|
|
||||||
|
|
||||||
@celery.task(name="acl.role_rebuild",
|
@celery.task(name="acl.role_rebuild", queue=ACL_QUEUE, )
|
||||||
queue=ACL_QUEUE,)
|
|
||||||
@flush_db
|
@flush_db
|
||||||
@reconnect_db
|
@reconnect_db
|
||||||
def role_rebuild(rids, app_id):
|
def role_rebuild(rids, app_id):
|
||||||
rids = rids if isinstance(rids, list) else [rids]
|
rids = rids if isinstance(rids, list) else [rids]
|
||||||
for rid in rids:
|
for rid in rids:
|
||||||
RoleRelationCache.rebuild(rid, app_id)
|
with redis_lock.Lock(rd.r, "ROLE_REBUILD_{}_{}".format(rid, app_id)):
|
||||||
|
RoleRelationCache.rebuild(rid, app_id)
|
||||||
|
|
||||||
current_app.logger.info("Role {0} App {1} rebuild..........".format(rids, app_id))
|
current_app.logger.info("Role {0} App {1} rebuild..........".format(rids, app_id))
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ from api.lib.cmdb.const import RetKey
|
||||||
from api.lib.cmdb.perms import has_perm_for_ci
|
from api.lib.cmdb.perms import has_perm_for_ci
|
||||||
from api.lib.cmdb.search import SearchError
|
from api.lib.cmdb.search import SearchError
|
||||||
from api.lib.cmdb.search.ci import search
|
from api.lib.cmdb.search.ci import search
|
||||||
|
from api.lib.decorator import args_required
|
||||||
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.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
|
||||||
|
@ -254,3 +255,23 @@ class CIPasswordView(APIView):
|
||||||
|
|
||||||
def post(self, ci_id, attr_id):
|
def post(self, ci_id, attr_id):
|
||||||
return self.get(ci_id, attr_id)
|
return self.get(ci_id, attr_id)
|
||||||
|
|
||||||
|
|
||||||
|
class CIBaselineView(APIView):
|
||||||
|
url_prefix = ("/ci/baseline", "/ci/<int:ci_id>/baseline/rollback")
|
||||||
|
|
||||||
|
@args_required("before_date")
|
||||||
|
def get(self):
|
||||||
|
ci_ids = handle_arg_list(request.values.get('ci_ids'))
|
||||||
|
before_date = request.values.get('before_date')
|
||||||
|
|
||||||
|
return self.jsonify(CIManager().baseline(list(map(int, ci_ids)), before_date))
|
||||||
|
|
||||||
|
@args_required("before_date")
|
||||||
|
def post(self, ci_id):
|
||||||
|
if 'rollback' in request.url:
|
||||||
|
before_date = request.values.get('before_date')
|
||||||
|
|
||||||
|
return self.jsonify(**CIManager().rollback(ci_id, before_date))
|
||||||
|
|
||||||
|
return self.get(ci_id)
|
||||||
|
|
|
@ -7,7 +7,6 @@ from io import BytesIO
|
||||||
from flask import abort
|
from flask import abort
|
||||||
from flask import current_app
|
from flask import current_app
|
||||||
from flask import request
|
from flask import request
|
||||||
from flask import session
|
|
||||||
|
|
||||||
from api.lib.cmdb.cache import AttributeCache
|
from api.lib.cmdb.cache import AttributeCache
|
||||||
from api.lib.cmdb.cache import CITypeCache
|
from api.lib.cmdb.cache import CITypeCache
|
||||||
|
@ -23,6 +22,8 @@ from api.lib.cmdb.const import PermEnum, ResourceTypeEnum, RoleEnum
|
||||||
from api.lib.cmdb.perms import CIFilterPermsCRUD
|
from api.lib.cmdb.perms import CIFilterPermsCRUD
|
||||||
from api.lib.cmdb.preference import PreferenceManager
|
from api.lib.cmdb.preference import PreferenceManager
|
||||||
from api.lib.cmdb.resp_format import ErrFormat
|
from api.lib.cmdb.resp_format import ErrFormat
|
||||||
|
from api.lib.common_setting.decorator import perms_role_required
|
||||||
|
from api.lib.common_setting.role_perm_base import CMDBApp
|
||||||
from api.lib.decorator import args_required
|
from api.lib.decorator import args_required
|
||||||
from api.lib.decorator import args_validate
|
from api.lib.decorator import args_validate
|
||||||
from api.lib.perm.acl.acl import ACLManager
|
from api.lib.perm.acl.acl import ACLManager
|
||||||
|
@ -36,6 +37,8 @@ from api.lib.perm.auth import auth_with_app_token
|
||||||
from api.lib.utils import handle_arg_list
|
from api.lib.utils import handle_arg_list
|
||||||
from api.resource import APIView
|
from api.resource import APIView
|
||||||
|
|
||||||
|
app_cli = CMDBApp()
|
||||||
|
|
||||||
|
|
||||||
class CITypeView(APIView):
|
class CITypeView(APIView):
|
||||||
url_prefix = ("/ci_types", "/ci_types/<int:type_id>", "/ci_types/<string:type_name>",
|
url_prefix = ("/ci_types", "/ci_types/<int:type_id>", "/ci_types/<string:type_name>",
|
||||||
|
@ -125,7 +128,8 @@ class CITypeGroupView(APIView):
|
||||||
|
|
||||||
return self.jsonify(CITypeGroupManager.get(need_other, config_required))
|
return self.jsonify(CITypeGroupManager.get(need_other, config_required))
|
||||||
|
|
||||||
@role_required(RoleEnum.CONFIG)
|
@perms_role_required(app_cli.app_name, app_cli.resource_type_name, app_cli.op.Model_Configuration,
|
||||||
|
app_cli.op.create_CIType_group, app_cli.admin_name)
|
||||||
@args_required("name")
|
@args_required("name")
|
||||||
@args_validate(CITypeGroupManager.cls)
|
@args_validate(CITypeGroupManager.cls)
|
||||||
def post(self):
|
def post(self):
|
||||||
|
@ -134,12 +138,11 @@ class CITypeGroupView(APIView):
|
||||||
|
|
||||||
return self.jsonify(group.to_dict())
|
return self.jsonify(group.to_dict())
|
||||||
|
|
||||||
|
@perms_role_required(app_cli.app_name, app_cli.resource_type_name, app_cli.op.Model_Configuration,
|
||||||
|
app_cli.op.update_CIType_group, app_cli.admin_name)
|
||||||
@args_validate(CITypeGroupManager.cls)
|
@args_validate(CITypeGroupManager.cls)
|
||||||
def put(self, gid=None):
|
def put(self, gid=None):
|
||||||
if "/order" in request.url:
|
if "/order" in request.url:
|
||||||
if RoleEnum.CONFIG not in session.get("acl", {}).get("parentRoles", []) and not is_app_admin("cmdb"):
|
|
||||||
return abort(403, ErrFormat.role_required.format(RoleEnum.CONFIG))
|
|
||||||
|
|
||||||
group_ids = request.values.get('group_ids')
|
group_ids = request.values.get('group_ids')
|
||||||
CITypeGroupManager.order(group_ids)
|
CITypeGroupManager.order(group_ids)
|
||||||
|
|
||||||
|
@ -152,7 +155,8 @@ class CITypeGroupView(APIView):
|
||||||
|
|
||||||
return self.jsonify(gid=gid)
|
return self.jsonify(gid=gid)
|
||||||
|
|
||||||
@role_required(RoleEnum.CONFIG)
|
@perms_role_required(app_cli.app_name, app_cli.resource_type_name, app_cli.op.Model_Configuration,
|
||||||
|
app_cli.op.delete_CIType_group, app_cli.admin_name)
|
||||||
def delete(self, gid):
|
def delete(self, gid):
|
||||||
type_ids = request.values.get("type_ids")
|
type_ids = request.values.get("type_ids")
|
||||||
CITypeGroupManager.delete(gid, type_ids)
|
CITypeGroupManager.delete(gid, type_ids)
|
||||||
|
@ -352,14 +356,16 @@ class CITypeAttributeGroupView(APIView):
|
||||||
class CITypeTemplateView(APIView):
|
class CITypeTemplateView(APIView):
|
||||||
url_prefix = ("/ci_types/template/import", "/ci_types/template/export", "/ci_types/<int:type_id>/template/export")
|
url_prefix = ("/ci_types/template/import", "/ci_types/template/export", "/ci_types/<int:type_id>/template/export")
|
||||||
|
|
||||||
@role_required(RoleEnum.CONFIG)
|
@perms_role_required(app_cli.app_name, app_cli.resource_type_name, app_cli.op.Model_Configuration,
|
||||||
|
app_cli.op.download_CIType, app_cli.admin_name)
|
||||||
def get(self, type_id=None): # export
|
def get(self, type_id=None): # export
|
||||||
if type_id is not None:
|
if type_id is not None:
|
||||||
return self.jsonify(dict(ci_type_template=CITypeTemplateManager.export_template_by_type(type_id)))
|
return self.jsonify(dict(ci_type_template=CITypeTemplateManager.export_template_by_type(type_id)))
|
||||||
|
|
||||||
return self.jsonify(dict(ci_type_template=CITypeTemplateManager.export_template()))
|
return self.jsonify(dict(ci_type_template=CITypeTemplateManager.export_template()))
|
||||||
|
|
||||||
@role_required(RoleEnum.CONFIG)
|
@perms_role_required(app_cli.app_name, app_cli.resource_type_name, app_cli.op.Model_Configuration,
|
||||||
|
app_cli.op.download_CIType, app_cli.admin_name)
|
||||||
def post(self): # import
|
def post(self): # import
|
||||||
tpt = request.values.get('ci_type_template') or {}
|
tpt = request.values.get('ci_type_template') or {}
|
||||||
|
|
||||||
|
@ -379,7 +385,8 @@ class CITypeCanDefineComputed(APIView):
|
||||||
class CITypeTemplateFileView(APIView):
|
class CITypeTemplateFileView(APIView):
|
||||||
url_prefix = ("/ci_types/template/import/file", "/ci_types/template/export/file")
|
url_prefix = ("/ci_types/template/import/file", "/ci_types/template/export/file")
|
||||||
|
|
||||||
@role_required(RoleEnum.CONFIG)
|
@perms_role_required(app_cli.app_name, app_cli.resource_type_name, app_cli.op.Model_Configuration,
|
||||||
|
app_cli.op.download_CIType, app_cli.admin_name)
|
||||||
def get(self): # export
|
def get(self): # export
|
||||||
tpt_json = CITypeTemplateManager.export_template()
|
tpt_json = CITypeTemplateManager.export_template()
|
||||||
tpt_json = dict(ci_type_template=tpt_json)
|
tpt_json = dict(ci_type_template=tpt_json)
|
||||||
|
@ -394,7 +401,8 @@ class CITypeTemplateFileView(APIView):
|
||||||
mimetype='application/json',
|
mimetype='application/json',
|
||||||
max_age=0)
|
max_age=0)
|
||||||
|
|
||||||
@role_required(RoleEnum.CONFIG)
|
@perms_role_required(app_cli.app_name, app_cli.resource_type_name, app_cli.op.Model_Configuration,
|
||||||
|
app_cli.op.download_CIType, app_cli.admin_name)
|
||||||
def post(self): # import
|
def post(self): # import
|
||||||
f = request.files.get('file')
|
f = request.files.get('file')
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,8 @@ from api.lib.cmdb.const import ResourceTypeEnum
|
||||||
from api.lib.cmdb.const import RoleEnum
|
from api.lib.cmdb.const import RoleEnum
|
||||||
from api.lib.cmdb.preference import PreferenceManager
|
from api.lib.cmdb.preference import PreferenceManager
|
||||||
from api.lib.cmdb.resp_format import ErrFormat
|
from api.lib.cmdb.resp_format import ErrFormat
|
||||||
|
from api.lib.common_setting.decorator import perms_role_required
|
||||||
|
from api.lib.common_setting.role_perm_base import CMDBApp
|
||||||
from api.lib.decorator import args_required
|
from api.lib.decorator import args_required
|
||||||
from api.lib.perm.acl.acl import ACLManager
|
from api.lib.perm.acl.acl import ACLManager
|
||||||
from api.lib.perm.acl.acl import has_perm_from_args
|
from api.lib.perm.acl.acl import has_perm_from_args
|
||||||
|
@ -18,6 +20,8 @@ from api.lib.perm.acl.acl import is_app_admin
|
||||||
from api.lib.perm.acl.acl import role_required
|
from api.lib.perm.acl.acl import role_required
|
||||||
from api.resource import APIView
|
from api.resource import APIView
|
||||||
|
|
||||||
|
app_cli = CMDBApp()
|
||||||
|
|
||||||
|
|
||||||
class GetChildrenView(APIView):
|
class GetChildrenView(APIView):
|
||||||
url_prefix = ("/ci_type_relations/<int:parent_id>/children",
|
url_prefix = ("/ci_type_relations/<int:parent_id>/children",
|
||||||
|
@ -41,7 +45,8 @@ class GetParentsView(APIView):
|
||||||
class CITypeRelationView(APIView):
|
class CITypeRelationView(APIView):
|
||||||
url_prefix = ("/ci_type_relations", "/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)
|
@perms_role_required(app_cli.app_name, app_cli.resource_type_name, app_cli.op.Service_Tree_Definition,
|
||||||
|
app_cli.op.read, app_cli.admin_name)
|
||||||
def get(self):
|
def get(self):
|
||||||
res, type2attributes = CITypeRelationManager.get()
|
res, type2attributes = CITypeRelationManager.get()
|
||||||
|
|
||||||
|
@ -69,7 +74,8 @@ class CITypeRelationView(APIView):
|
||||||
class CITypeRelationDelete2View(APIView):
|
class CITypeRelationDelete2View(APIView):
|
||||||
url_prefix = "/ci_type_relations/<int:ctr_id>"
|
url_prefix = "/ci_type_relations/<int:ctr_id>"
|
||||||
|
|
||||||
@role_required(RoleEnum.CONFIG)
|
@perms_role_required(app_cli.app_name, app_cli.resource_type_name, app_cli.op.Model_Relationships,
|
||||||
|
app_cli.op.read, app_cli.admin_name)
|
||||||
def delete(self, ctr_id):
|
def delete(self, ctr_id):
|
||||||
CITypeRelationManager.delete(ctr_id)
|
CITypeRelationManager.delete(ctr_id)
|
||||||
|
|
||||||
|
|
|
@ -3,14 +3,16 @@
|
||||||
|
|
||||||
from flask import request
|
from flask import request
|
||||||
|
|
||||||
from api.lib.cmdb.const import RoleEnum
|
|
||||||
from api.lib.cmdb.custom_dashboard import CustomDashboardManager
|
from api.lib.cmdb.custom_dashboard import CustomDashboardManager
|
||||||
from api.lib.cmdb.custom_dashboard import SystemConfigManager
|
from api.lib.cmdb.custom_dashboard import SystemConfigManager
|
||||||
|
from api.lib.common_setting.decorator import perms_role_required
|
||||||
|
from api.lib.common_setting.role_perm_base import CMDBApp
|
||||||
from api.lib.decorator import args_required
|
from api.lib.decorator import args_required
|
||||||
from api.lib.decorator import args_validate
|
from api.lib.decorator import args_validate
|
||||||
from api.lib.perm.acl.acl import role_required
|
|
||||||
from api.resource import APIView
|
from api.resource import APIView
|
||||||
|
|
||||||
|
app_cli = CMDBApp()
|
||||||
|
|
||||||
|
|
||||||
class CustomDashboardApiView(APIView):
|
class CustomDashboardApiView(APIView):
|
||||||
url_prefix = ("/custom_dashboard", "/custom_dashboard/<int:_id>", "/custom_dashboard/batch",
|
url_prefix = ("/custom_dashboard", "/custom_dashboard/<int:_id>", "/custom_dashboard/batch",
|
||||||
|
@ -19,7 +21,8 @@ class CustomDashboardApiView(APIView):
|
||||||
def get(self):
|
def get(self):
|
||||||
return self.jsonify(CustomDashboardManager.get())
|
return self.jsonify(CustomDashboardManager.get())
|
||||||
|
|
||||||
@role_required(RoleEnum.CONFIG)
|
@perms_role_required(app_cli.app_name, app_cli.resource_type_name, app_cli.op.Customized_Dashboard,
|
||||||
|
app_cli.op.read, app_cli.admin_name)
|
||||||
@args_validate(CustomDashboardManager.cls)
|
@args_validate(CustomDashboardManager.cls)
|
||||||
def post(self):
|
def post(self):
|
||||||
if request.url.endswith("/preview"):
|
if request.url.endswith("/preview"):
|
||||||
|
@ -32,7 +35,8 @@ class CustomDashboardApiView(APIView):
|
||||||
|
|
||||||
return self.jsonify(res)
|
return self.jsonify(res)
|
||||||
|
|
||||||
@role_required(RoleEnum.CONFIG)
|
@perms_role_required(app_cli.app_name, app_cli.resource_type_name, app_cli.op.Customized_Dashboard,
|
||||||
|
app_cli.op.read, app_cli.admin_name)
|
||||||
@args_validate(CustomDashboardManager.cls)
|
@args_validate(CustomDashboardManager.cls)
|
||||||
def put(self, _id=None):
|
def put(self, _id=None):
|
||||||
if _id is not None:
|
if _id is not None:
|
||||||
|
@ -47,7 +51,8 @@ class CustomDashboardApiView(APIView):
|
||||||
|
|
||||||
return self.jsonify(id2options=request.values.get('id2options'))
|
return self.jsonify(id2options=request.values.get('id2options'))
|
||||||
|
|
||||||
@role_required(RoleEnum.CONFIG)
|
@perms_role_required(app_cli.app_name, app_cli.resource_type_name, app_cli.op.Customized_Dashboard,
|
||||||
|
app_cli.op.read, app_cli.admin_name)
|
||||||
def delete(self, _id):
|
def delete(self, _id):
|
||||||
CustomDashboardManager.delete(_id)
|
CustomDashboardManager.delete(_id)
|
||||||
|
|
||||||
|
@ -57,12 +62,14 @@ class CustomDashboardApiView(APIView):
|
||||||
class SystemConfigApiView(APIView):
|
class SystemConfigApiView(APIView):
|
||||||
url_prefix = ("/system_config",)
|
url_prefix = ("/system_config",)
|
||||||
|
|
||||||
@role_required(RoleEnum.CONFIG)
|
@perms_role_required(app_cli.app_name, app_cli.resource_type_name, app_cli.op.Service_Tree_Definition,
|
||||||
|
app_cli.op.read, app_cli.admin_name)
|
||||||
@args_required("name", value_required=True)
|
@args_required("name", value_required=True)
|
||||||
def get(self):
|
def get(self):
|
||||||
return self.jsonify(SystemConfigManager.get(request.values['name']))
|
return self.jsonify(SystemConfigManager.get(request.values['name']))
|
||||||
|
|
||||||
@role_required(RoleEnum.CONFIG)
|
@perms_role_required(app_cli.app_name, app_cli.resource_type_name, app_cli.op.Service_Tree_Definition,
|
||||||
|
app_cli.op.read, app_cli.admin_name)
|
||||||
@args_validate(SystemConfigManager.cls)
|
@args_validate(SystemConfigManager.cls)
|
||||||
@args_required("name", value_required=True)
|
@args_required("name", value_required=True)
|
||||||
@args_required("option", value_required=True)
|
@args_required("option", value_required=True)
|
||||||
|
@ -74,7 +81,8 @@ class SystemConfigApiView(APIView):
|
||||||
def put(self, _id=None):
|
def put(self, _id=None):
|
||||||
return self.post()
|
return self.post()
|
||||||
|
|
||||||
@role_required(RoleEnum.CONFIG)
|
@perms_role_required(app_cli.app_name, app_cli.resource_type_name, app_cli.op.Service_Tree_Definition,
|
||||||
|
app_cli.op.read, app_cli.admin_name)
|
||||||
@args_required("name")
|
@args_required("name")
|
||||||
def delete(self):
|
def delete(self):
|
||||||
CustomDashboardManager.delete(request.values['name'])
|
CustomDashboardManager.delete(request.values['name'])
|
||||||
|
|
|
@ -5,28 +5,29 @@ import datetime
|
||||||
|
|
||||||
from flask import abort
|
from flask import abort
|
||||||
from flask import request
|
from flask import request
|
||||||
from flask import session
|
|
||||||
|
|
||||||
from api.lib.cmdb.ci import CIManager
|
from api.lib.cmdb.ci import CIManager
|
||||||
from api.lib.cmdb.const import PermEnum
|
from api.lib.cmdb.const import PermEnum
|
||||||
from api.lib.cmdb.const import ResourceTypeEnum
|
from api.lib.cmdb.const import ResourceTypeEnum
|
||||||
from api.lib.cmdb.const import RoleEnum
|
|
||||||
from api.lib.cmdb.history import AttributeHistoryManger
|
from api.lib.cmdb.history import AttributeHistoryManger
|
||||||
from api.lib.cmdb.history import CITriggerHistoryManager
|
from api.lib.cmdb.history import CITriggerHistoryManager
|
||||||
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
|
||||||
|
from api.lib.common_setting.decorator import perms_role_required
|
||||||
|
from api.lib.common_setting.role_perm_base import CMDBApp
|
||||||
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.acl.acl import is_app_admin
|
|
||||||
from api.lib.perm.acl.acl import role_required
|
|
||||||
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.resource import APIView
|
from api.resource import APIView
|
||||||
|
|
||||||
|
app_cli = CMDBApp()
|
||||||
|
|
||||||
|
|
||||||
class RecordView(APIView):
|
class RecordView(APIView):
|
||||||
url_prefix = ("/history/records/attribute", "/history/records/relation")
|
url_prefix = ("/history/records/attribute", "/history/records/relation")
|
||||||
|
|
||||||
@role_required(RoleEnum.CONFIG)
|
@perms_role_required(app_cli.app_name, app_cli.resource_type_name, app_cli.op.Operation_Audit,
|
||||||
|
app_cli.op.read, app_cli.admin_name)
|
||||||
def get(self):
|
def get(self):
|
||||||
page = get_page(request.values.get("page", 1))
|
page = get_page(request.values.get("page", 1))
|
||||||
page_size = get_page_size(request.values.get("page_size"))
|
page_size = get_page_size(request.values.get("page_size"))
|
||||||
|
@ -80,18 +81,21 @@ class CIHistoryView(APIView):
|
||||||
|
|
||||||
|
|
||||||
class CITriggerHistoryView(APIView):
|
class CITriggerHistoryView(APIView):
|
||||||
url_prefix = ("/history/ci_triggers/<int:ci_id>", "/history/ci_triggers")
|
url_prefix = ("/history/ci_triggers/<int:ci_id>",)
|
||||||
|
|
||||||
@has_perm_from_args("ci_id", ResourceTypeEnum.CI, PermEnum.READ, CIManager.get_type_name)
|
@has_perm_from_args("ci_id", ResourceTypeEnum.CI, PermEnum.READ, CIManager.get_type_name)
|
||||||
def get(self, ci_id=None):
|
def get(self, ci_id):
|
||||||
if ci_id is not None:
|
result = CITriggerHistoryManager.get_by_ci_id(ci_id)
|
||||||
result = CITriggerHistoryManager.get_by_ci_id(ci_id)
|
|
||||||
|
|
||||||
return self.jsonify(result)
|
return self.jsonify(result)
|
||||||
|
|
||||||
if RoleEnum.CONFIG not in session.get("acl", {}).get("parentRoles", []) and not is_app_admin("cmdb"):
|
|
||||||
return abort(403, ErrFormat.role_required.format(RoleEnum.CONFIG))
|
|
||||||
|
|
||||||
|
class CIsTriggerHistoryView(APIView):
|
||||||
|
url_prefix = ("/history/ci_triggers",)
|
||||||
|
|
||||||
|
@perms_role_required(app_cli.app_name, app_cli.resource_type_name, app_cli.op.Operation_Audit,
|
||||||
|
app_cli.op.read, app_cli.admin_name)
|
||||||
|
def get(self):
|
||||||
type_id = request.values.get("type_id")
|
type_id = request.values.get("type_id")
|
||||||
trigger_id = request.values.get("trigger_id")
|
trigger_id = request.values.get("trigger_id")
|
||||||
operate_type = request.values.get("operate_type")
|
operate_type = request.values.get("operate_type")
|
||||||
|
@ -115,7 +119,8 @@ class CITriggerHistoryView(APIView):
|
||||||
class CITypeHistoryView(APIView):
|
class CITypeHistoryView(APIView):
|
||||||
url_prefix = "/history/ci_types"
|
url_prefix = "/history/ci_types"
|
||||||
|
|
||||||
@role_required(RoleEnum.CONFIG)
|
@perms_role_required(app_cli.app_name, app_cli.resource_type_name, app_cli.op.Operation_Audit,
|
||||||
|
app_cli.op.read, app_cli.admin_name)
|
||||||
def get(self):
|
def get(self):
|
||||||
type_id = request.values.get("type_id")
|
type_id = request.values.get("type_id")
|
||||||
username = request.values.get("username")
|
username = request.values.get("username")
|
||||||
|
|
|
@ -8,20 +8,22 @@ from flask import request
|
||||||
from api.lib.cmdb.ci_type import CITypeManager
|
from api.lib.cmdb.ci_type import CITypeManager
|
||||||
from api.lib.cmdb.const import PermEnum
|
from api.lib.cmdb.const import PermEnum
|
||||||
from api.lib.cmdb.const import ResourceTypeEnum
|
from api.lib.cmdb.const import ResourceTypeEnum
|
||||||
from api.lib.cmdb.const import RoleEnum
|
|
||||||
from api.lib.cmdb.perms import CIFilterPermsCRUD
|
from api.lib.cmdb.perms import CIFilterPermsCRUD
|
||||||
from api.lib.cmdb.preference import PreferenceManager
|
from api.lib.cmdb.preference import PreferenceManager
|
||||||
from api.lib.cmdb.resp_format import ErrFormat
|
from api.lib.cmdb.resp_format import ErrFormat
|
||||||
|
from api.lib.common_setting.decorator import perms_role_required
|
||||||
|
from api.lib.common_setting.role_perm_base import CMDBApp
|
||||||
from api.lib.decorator import args_required
|
from api.lib.decorator import args_required
|
||||||
from api.lib.decorator import args_validate
|
from api.lib.decorator import args_validate
|
||||||
from api.lib.perm.acl.acl import ACLManager
|
from api.lib.perm.acl.acl import ACLManager
|
||||||
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.acl.acl import is_app_admin
|
from api.lib.perm.acl.acl import is_app_admin
|
||||||
from api.lib.perm.acl.acl import role_required
|
|
||||||
from api.lib.perm.acl.acl import validate_permission
|
from api.lib.perm.acl.acl import validate_permission
|
||||||
from api.lib.utils import handle_arg_list
|
from api.lib.utils import handle_arg_list
|
||||||
from api.resource import APIView
|
from api.resource import APIView
|
||||||
|
|
||||||
|
app_cli = CMDBApp()
|
||||||
|
|
||||||
|
|
||||||
class PreferenceShowCITypesView(APIView):
|
class PreferenceShowCITypesView(APIView):
|
||||||
url_prefix = ("/preference/ci_types", "/preference/ci_types2")
|
url_prefix = ("/preference/ci_types", "/preference/ci_types2")
|
||||||
|
@ -104,7 +106,8 @@ class PreferenceRelationApiView(APIView):
|
||||||
|
|
||||||
return self.jsonify(views=views, id2type=id2type, name2id=name2id)
|
return self.jsonify(views=views, id2type=id2type, name2id=name2id)
|
||||||
|
|
||||||
@role_required(RoleEnum.CONFIG)
|
@perms_role_required(app_cli.app_name, app_cli.resource_type_name, app_cli.op.Service_Tree_Definition,
|
||||||
|
app_cli.op.read, app_cli.admin_name)
|
||||||
@args_required("name")
|
@args_required("name")
|
||||||
@args_required("cr_ids")
|
@args_required("cr_ids")
|
||||||
@args_validate(PreferenceManager.pref_rel_cls)
|
@args_validate(PreferenceManager.pref_rel_cls)
|
||||||
|
@ -118,14 +121,16 @@ class PreferenceRelationApiView(APIView):
|
||||||
|
|
||||||
return self.jsonify(views=views, id2type=id2type, name2id=name2id)
|
return self.jsonify(views=views, id2type=id2type, name2id=name2id)
|
||||||
|
|
||||||
@role_required(RoleEnum.CONFIG)
|
@perms_role_required(app_cli.app_name, app_cli.resource_type_name, app_cli.op.Service_Tree_Definition,
|
||||||
|
app_cli.op.read, app_cli.admin_name)
|
||||||
@args_required("name")
|
@args_required("name")
|
||||||
def put(self, _id):
|
def put(self, _id):
|
||||||
views, id2type, name2id = PreferenceManager.create_or_update_relation_view(_id=_id, **request.values)
|
views, id2type, name2id = PreferenceManager.create_or_update_relation_view(_id=_id, **request.values)
|
||||||
|
|
||||||
return self.jsonify(views=views, id2type=id2type, name2id=name2id)
|
return self.jsonify(views=views, id2type=id2type, name2id=name2id)
|
||||||
|
|
||||||
@role_required(RoleEnum.CONFIG)
|
@perms_role_required(app_cli.app_name, app_cli.resource_type_name, app_cli.op.Service_Tree_Definition,
|
||||||
|
app_cli.op.read, app_cli.admin_name)
|
||||||
@args_required("name")
|
@args_required("name")
|
||||||
def delete(self):
|
def delete(self):
|
||||||
name = request.values.get("name")
|
name = request.values.get("name")
|
||||||
|
|
|
@ -4,14 +4,16 @@
|
||||||
from flask import abort
|
from flask import abort
|
||||||
from flask import request
|
from flask import request
|
||||||
|
|
||||||
from api.lib.cmdb.const import RoleEnum
|
|
||||||
from api.lib.cmdb.relation_type import RelationTypeManager
|
from api.lib.cmdb.relation_type import RelationTypeManager
|
||||||
from api.lib.cmdb.resp_format import ErrFormat
|
from api.lib.cmdb.resp_format import ErrFormat
|
||||||
|
from api.lib.common_setting.decorator import perms_role_required
|
||||||
|
from api.lib.common_setting.role_perm_base import CMDBApp
|
||||||
from api.lib.decorator import args_required
|
from api.lib.decorator import args_required
|
||||||
from api.lib.decorator import args_validate
|
from api.lib.decorator import args_validate
|
||||||
from api.lib.perm.acl.acl import role_required
|
|
||||||
from api.resource import APIView
|
from api.resource import APIView
|
||||||
|
|
||||||
|
app_cli = CMDBApp()
|
||||||
|
|
||||||
|
|
||||||
class RelationTypeView(APIView):
|
class RelationTypeView(APIView):
|
||||||
url_prefix = ("/relation_types", "/relation_types/<int:rel_id>")
|
url_prefix = ("/relation_types", "/relation_types/<int:rel_id>")
|
||||||
|
@ -19,7 +21,8 @@ class RelationTypeView(APIView):
|
||||||
def get(self):
|
def get(self):
|
||||||
return self.jsonify([i.to_dict() for i in RelationTypeManager.get_all()])
|
return self.jsonify([i.to_dict() for i in RelationTypeManager.get_all()])
|
||||||
|
|
||||||
@role_required(RoleEnum.CONFIG)
|
@perms_role_required(app_cli.app_name, app_cli.resource_type_name, app_cli.op.Relationship_Types,
|
||||||
|
app_cli.op.read, app_cli.admin_name)
|
||||||
@args_required("name")
|
@args_required("name")
|
||||||
@args_validate(RelationTypeManager.cls)
|
@args_validate(RelationTypeManager.cls)
|
||||||
def post(self):
|
def post(self):
|
||||||
|
@ -28,7 +31,8 @@ class RelationTypeView(APIView):
|
||||||
|
|
||||||
return self.jsonify(rel.to_dict())
|
return self.jsonify(rel.to_dict())
|
||||||
|
|
||||||
@role_required(RoleEnum.CONFIG)
|
@perms_role_required(app_cli.app_name, app_cli.resource_type_name, app_cli.op.Relationship_Types,
|
||||||
|
app_cli.op.read, app_cli.admin_name)
|
||||||
@args_required("name")
|
@args_required("name")
|
||||||
@args_validate(RelationTypeManager.cls)
|
@args_validate(RelationTypeManager.cls)
|
||||||
def put(self, rel_id):
|
def put(self, rel_id):
|
||||||
|
@ -37,7 +41,8 @@ class RelationTypeView(APIView):
|
||||||
|
|
||||||
return self.jsonify(rel.to_dict())
|
return self.jsonify(rel.to_dict())
|
||||||
|
|
||||||
@role_required(RoleEnum.CONFIG)
|
@perms_role_required(app_cli.app_name, app_cli.resource_type_name, app_cli.op.Relationship_Types,
|
||||||
|
app_cli.op.read, app_cli.admin_name)
|
||||||
def delete(self, rel_id):
|
def delete(self, rel_id):
|
||||||
RelationTypeManager.delete(rel_id)
|
RelationTypeManager.delete(rel_id)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue