You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
179 lines
7.1 KiB
179 lines
7.1 KiB
# Copyright (C) 2005-2025 Splunk Inc. All Rights Reserved.
|
|
import sys
|
|
|
|
from itsi.content_packs.constants import ContentType, CONTENT_TYPE_WRITE_PRIORITY
|
|
from itsi.content_packs.itoa import (
|
|
get_itoa_object_class,
|
|
get_itoa_object_id,
|
|
get_itoa_object_title
|
|
)
|
|
from itsi.content_packs.journal import EntryType
|
|
from ITOA.setup_logging import InstrumentCall
|
|
|
|
|
|
class ItoaContentWriter(object):
|
|
"""
|
|
Handles the saving of content objects into ITSI.
|
|
"""
|
|
|
|
def __init__(self, logger, session_key, transaction_id=None):
|
|
"""
|
|
:param logger: a logger instance
|
|
:type logger: Logger
|
|
|
|
:param session_key: the session key
|
|
:type session_key: str
|
|
|
|
:param transaction_id: transaction info for tracking for debugging
|
|
:type transaction_id: basestring
|
|
"""
|
|
self.logger = logger
|
|
self.session_key = session_key
|
|
self._instrumentation = InstrumentCall(logger)
|
|
self.transaction_id = transaction_id
|
|
|
|
def write(self, content_objects, journal):
|
|
"""
|
|
Writes the given content objects to storage.
|
|
|
|
:param content_objects: the content objects data
|
|
:type content_objects: dict
|
|
|
|
:param journal: a journal instance
|
|
:type journal: TransactionJournal
|
|
|
|
:return: a dict of content objects data
|
|
:rtype: dict
|
|
"""
|
|
with self._instrumentation.track("ItoaContentWriter.write", transaction_id=self.transaction_id):
|
|
failed_parent_itsi_object_priority_order = sys.maxsize
|
|
failed_parent_itsi_object_type = ""
|
|
results = {}
|
|
|
|
content_types_with_priority = sorted(((content_type, CONTENT_TYPE_WRITE_PRIORITY[content_type]) for content_type in content_objects.keys()), key=lambda x: x[1])
|
|
|
|
for content_type, priority_order in content_types_with_priority:
|
|
|
|
objects = content_objects[content_type]
|
|
if not objects:
|
|
continue
|
|
|
|
if (failed_parent_itsi_object_type
|
|
and failed_parent_itsi_object_type not in (ContentType.GLASS_TABLE_ICON, ContentType.GLASS_TABLE_IMAGE)
|
|
and failed_parent_itsi_object_priority_order < priority_order):
|
|
error_message = f'tid={self.transaction_id} Skipping installation of {content_type} due to a failure while writing the parent ITSI Object Type: "{failed_parent_itsi_object_type}"'
|
|
self.logger.error(error_message)
|
|
journal.failure({
|
|
'error_message': error_message,
|
|
'type': EntryType.SKIPPING_INSTALLATION_WRITING + ' ' + failed_parent_itsi_object_type,
|
|
'content_type': content_type,
|
|
'ids': list({get_itoa_object_id(content_type, obj) for obj in objects}),
|
|
'titles': list({get_itoa_object_title(content_type, obj) for obj in objects})
|
|
})
|
|
else:
|
|
object_ids, failed_parent_itsi_object_type, failed_parent_itsi_object_priority_order = self.write_objects(content_type, objects, priority_order, journal=journal)
|
|
|
|
objects_data = self.construct_objects_data(content_type, object_ids, objects)
|
|
if objects_data:
|
|
results[content_type] = objects_data
|
|
|
|
return results
|
|
|
|
def write_objects(self, content_type, objects, priority_order, journal):
|
|
"""
|
|
Writes the given objects for a content type to storage.
|
|
|
|
:param content_type: the content type
|
|
:type content_type: str
|
|
|
|
:param objects: a list of objects data
|
|
:type objects: list
|
|
|
|
:param priority_order: priority order of ITSI Object
|
|
:type priority_order: int
|
|
|
|
:param journal: a journal instance
|
|
:type journal: TransactionJournal
|
|
|
|
:return: a tuple that will contain following items:
|
|
1. list of successfully written object ids
|
|
2. Name of ITSI Object Type that indicates that installation is skipped for dependent ITSI Objects Type
|
|
3. Priority Order of ITSI Object Type
|
|
:rtype: (list, string, int)
|
|
"""
|
|
with self._instrumentation.track(f"ItoaContentWriter.write_objects.{content_type}", transaction_id=self.transaction_id):
|
|
itoa_object_class = get_itoa_object_class(content_type)
|
|
if not itoa_object_class:
|
|
error_message = f'tid={self.transaction_id} Unexpected writing of unsupported content_type="{content_type}"'
|
|
self.logger.error(error_message)
|
|
|
|
journal.failure({
|
|
'error_message': error_message,
|
|
'type': EntryType.INVALID_CONTENT_TYPE,
|
|
'content_type': content_type,
|
|
'ids': list({get_itoa_object_id(content_type, obj) for obj in objects}),
|
|
'titles': list({get_itoa_object_title(content_type, obj) for obj in objects})
|
|
})
|
|
|
|
return [], content_type, priority_order
|
|
|
|
handler = itoa_object_class(self.session_key, 'nobody')
|
|
handler.skip_service_template_update = True
|
|
|
|
try:
|
|
object_ids = handler.save_batch(
|
|
'nobody',
|
|
objects,
|
|
validate_names=False,
|
|
transaction_id=self.transaction_id
|
|
)
|
|
self.logger.info(f'tid={self.transaction_id} Successfully created objects for content_type="{content_type}"')
|
|
except Exception as ex:
|
|
self.logger.error(f'tid={self.transaction_id} Failed to create objects for content_type="{content_type}"')
|
|
self.logger.exception(f'tid={self.transaction_id} {ex}')
|
|
|
|
journal.failure({
|
|
'error_message': str(ex),
|
|
'type': EntryType.ERROR_OBJECTS_SAVE,
|
|
'content_type': content_type,
|
|
'ids': list({get_itoa_object_id(content_type, obj) for obj in objects}),
|
|
'titles': list({get_itoa_object_title(content_type, obj) for obj in objects})
|
|
})
|
|
|
|
return [], content_type, priority_order
|
|
|
|
return object_ids, "", sys.maxsize
|
|
|
|
def construct_objects_data(self, content_type, object_ids, objects):
|
|
"""
|
|
Constructs the objects data for the given list of object ids.
|
|
|
|
:param content_type: the content type
|
|
:type content_type: str
|
|
|
|
:param object_ids: a list of object ids
|
|
:type object_ids: list
|
|
|
|
:param objects: a list of object data
|
|
:type objects: list
|
|
|
|
:return: a list of object data
|
|
:rtype: list
|
|
"""
|
|
lookup = { get_itoa_object_id(content_type, obj): obj for obj in objects }
|
|
|
|
objects_data = []
|
|
|
|
for object_id in object_ids:
|
|
if object_id not in lookup:
|
|
continue
|
|
|
|
data = lookup[object_id]
|
|
|
|
objects_data.append({
|
|
'id': object_id,
|
|
'title': get_itoa_object_title(content_type, data)
|
|
})
|
|
|
|
return objects_data
|