mirror of
https://github.com/veops/cmdb.git
synced 2025-08-25 04:41:45 +08:00
feat(api): multi-value attribute handling in relation building
This commit is contained in:
@@ -360,16 +360,28 @@ class CIManager(object):
|
||||
_sync=False,
|
||||
**ci_dict):
|
||||
"""
|
||||
add ci
|
||||
:param ci_type_name:
|
||||
:param exist_policy: replace or reject or need
|
||||
:param _no_attribute_policy: ignore or reject
|
||||
:param is_auto_discovery: default is False
|
||||
:param _is_admin: default is False
|
||||
:param ticket_id:
|
||||
:param _sync:
|
||||
:param ci_dict:
|
||||
:return:
|
||||
Create a new Configuration Item (CI) or update existing based on unique constraints.
|
||||
|
||||
Handles complete CI creation workflow including validation, uniqueness checks,
|
||||
password encryption, computed attributes, relationship creation, and caching.
|
||||
|
||||
Args:
|
||||
ci_type_name (str): Name of the CI type to create
|
||||
exist_policy (ExistPolicy): How to handle existing CIs (REPLACE/REJECT/NEED)
|
||||
_no_attribute_policy (ExistPolicy): How to handle unknown attributes (IGNORE/REJECT)
|
||||
is_auto_discovery (bool): Whether CI is created by auto-discovery process
|
||||
_is_admin (bool): Whether to skip permission checks
|
||||
ticket_id (int, optional): Associated ticket ID for audit trail
|
||||
_sync (bool): Whether to execute cache/relation tasks synchronously
|
||||
**ci_dict: CI attribute values as key-value pairs
|
||||
|
||||
Returns:
|
||||
int: ID of the created or updated CI
|
||||
|
||||
Raises:
|
||||
400: If unique constraints violated, required attributes missing, or validation fails
|
||||
403: If user lacks permissions for restricted attributes
|
||||
404: If CI type not found or referenced CI not exists
|
||||
"""
|
||||
now = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||
ci_type = CITypeManager.check_is_existed(ci_type_name)
|
||||
@@ -512,6 +524,24 @@ class CIManager(object):
|
||||
return ci.id
|
||||
|
||||
def update(self, ci_id, _is_admin=False, ticket_id=None, _sync=False, **ci_dict):
|
||||
"""
|
||||
Update an existing Configuration Item with new attribute values.
|
||||
|
||||
Performs comprehensive CI update including validation, constraint checks,
|
||||
password handling, computed attributes processing, and change tracking.
|
||||
|
||||
Args:
|
||||
ci_id (int): ID of the CI to update
|
||||
_is_admin (bool): Whether to skip permission checks
|
||||
ticket_id (int, optional): Associated ticket ID for audit trail
|
||||
_sync (bool): Whether to execute cache/relation tasks synchronously
|
||||
**ci_dict: CI attribute values to update as key-value pairs
|
||||
|
||||
Raises:
|
||||
400: If unique constraints violated or validation fails
|
||||
403: If user lacks permissions for restricted attributes
|
||||
404: If CI not found
|
||||
"""
|
||||
now = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||
ci = self.confirm_ci_existed(ci_id)
|
||||
ci_type = ci.ci_type
|
||||
@@ -1420,12 +1450,29 @@ class CIRelationManager(object):
|
||||
parent_attr = AttributeCache.get(parent_attr_id)
|
||||
child_attr = AttributeCache.get(child_attr_id)
|
||||
attr_value = ci_dict.get(parent_attr.name)
|
||||
if attr_value != 0 and not attr_value:
|
||||
continue
|
||||
value_table = TableMap(attr=child_attr).table
|
||||
for child in value_table.get_by(attr_id=child_attr.id, value=attr_value, only_query=True).join(
|
||||
CI, CI.id == value_table.ci_id).filter(CI.type_id == item.child_id):
|
||||
_relations.add((ci_dict['_id'], child.ci_id))
|
||||
attr_value_list = [attr_value] if not isinstance(attr_value, list) else attr_value
|
||||
|
||||
matching_cis = value_table.get_by(
|
||||
attr_id=child_attr.id,
|
||||
only_query=True
|
||||
).join(
|
||||
CI, CI.id == value_table.ci_id
|
||||
).filter(
|
||||
CI.type_id == item.child_id,
|
||||
value_table.value.in_(attr_value_list)
|
||||
).all()
|
||||
|
||||
for ci in matching_cis:
|
||||
_relations.add((ci_dict['_id'], ci.ci_id))
|
||||
|
||||
if relations is None:
|
||||
relations = _relations
|
||||
else:
|
||||
if item.constraint == ConstraintEnum.Many2Many:
|
||||
relations |= _relations
|
||||
else:
|
||||
relations &= _relations
|
||||
|
||||
@@ -1447,12 +1494,29 @@ class CIRelationManager(object):
|
||||
parent_attr = AttributeCache.get(parent_attr_id)
|
||||
child_attr = AttributeCache.get(child_attr_id)
|
||||
attr_value = ci_dict.get(child_attr.name)
|
||||
if attr_value != 0 and not attr_value:
|
||||
continue
|
||||
value_table = TableMap(attr=parent_attr).table
|
||||
for parent in value_table.get_by(attr_id=parent_attr.id, value=attr_value, only_query=True).join(
|
||||
CI, CI.id == value_table.ci_id).filter(CI.type_id == item.parent_id):
|
||||
_relations.add((parent.ci_id, ci_dict['_id']))
|
||||
attr_value_list = [attr_value] if not isinstance(attr_value, list) else attr_value
|
||||
|
||||
matching_cis = value_table.get_by(
|
||||
attr_id=parent_attr.id,
|
||||
only_query=True
|
||||
).join(
|
||||
CI, CI.id == value_table.ci_id
|
||||
).filter(
|
||||
CI.type_id == item.parent_id,
|
||||
value_table.value.in_(attr_value_list)
|
||||
).all()
|
||||
|
||||
for ci in matching_cis:
|
||||
_relations.add((ci.ci_id, ci_dict['_id']))
|
||||
|
||||
if relations is None:
|
||||
relations = _relations
|
||||
else:
|
||||
if item.constraint == ConstraintEnum.Many2Many:
|
||||
relations |= _relations
|
||||
else:
|
||||
relations &= _relations
|
||||
|
||||
|
@@ -92,7 +92,8 @@ class IpAddressManager(object):
|
||||
else:
|
||||
return abort(400, ErrFormat.ipam_address_model_not_found)
|
||||
|
||||
with (redis_lock.Lock(rd.r, "IPAM_ASSIGN_ADDRESS_{}".format(subnet_id), expire=10)):
|
||||
with (redis_lock.Lock(rd.r, "IPAM_ASSIGN_ADDRESS_{}".format(subnet_id),
|
||||
expire=60, auto_renewal=True)):
|
||||
cis = self._get_cis(subnet_id, ips)
|
||||
ip2ci = {ci[IPAddressBuiltinAttributes.IP]: ci for ci in cis}
|
||||
|
||||
|
Reference in New Issue
Block a user