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.
376 lines
16 KiB
376 lines
16 KiB
# Copyright (C) 2005-2024 Splunk Inc. All Rights Reserved.
|
|
|
|
from ITOA.setup_logging import setup_logging
|
|
from itsi.content_packs.journal import TransactionJournal
|
|
from itsi.content_packs.readers import ContentPackContentReader
|
|
from itsi.content_packs.retriever import retrieve_saved_search_consistency_status
|
|
from itsi.content_packs.entitlements_processor import ContentPackEntitlementsProcessor
|
|
from itsi.content_packs.itoa import get_itoa_object_class, get_itoa_object_title, get_itoa_object_id
|
|
from itsi.content_packs.constants import ContentType, ContentPackFields, \
|
|
CONTENT_PACK_SOURCE_VERSION_FIELD, CONTENT_PACK_SOURCE_FIELD, CONTENT_TYPE_TO_ITOA_TYPE
|
|
|
|
LOGGER = setup_logging(
|
|
logfile_name='itsi_content_packs_preview.log',
|
|
logger_name='itsi.content_packs.preview'
|
|
)
|
|
|
|
|
|
def preview(content_pack_id, version, session_key=None):
|
|
"""
|
|
Preview content pack objects based on the given content pack id and version
|
|
With installed field indicating whether objects have been installed
|
|
|
|
:param content_pack_id: the content pack id
|
|
:type content_pack_id: str
|
|
|
|
:param version: the content pack version
|
|
:type version: str
|
|
|
|
:param session_key: the session key
|
|
:type session_key: str
|
|
|
|
:return: a list of content packs objects with installed attribute
|
|
indicating whether content pack objects have been installed or not
|
|
:rtype: list
|
|
"""
|
|
previewer = ContentPackPreviewer(
|
|
logger=LOGGER,
|
|
session_key=session_key,
|
|
)
|
|
return previewer.preview(content_pack_id, version)
|
|
|
|
|
|
class ContentPackPreviewer(object):
|
|
"""This class is responsible for previewing content pack objects."""
|
|
|
|
def __init__(self, logger, session_key):
|
|
"""
|
|
:param logger: a logger instance
|
|
:type logger: Logger
|
|
|
|
:param session_key: the session key
|
|
:type session_key: str
|
|
"""
|
|
self.logger = logger
|
|
self.session_key = session_key
|
|
self.owner = 'nobody'
|
|
|
|
def get_content_objects(self, content_pack_id, version):
|
|
"""
|
|
Retrieve a dict of objects where key is the content type, value is a list of objects of the content type
|
|
|
|
:param content_pack_id: the content pack version id
|
|
:type content_pack_id: str
|
|
|
|
:param version: the content pack version
|
|
:type version: str
|
|
|
|
:return: content pack objects dict aggregated by content types
|
|
:rtype: dict
|
|
"""
|
|
journal = TransactionJournal()
|
|
entitlement_writer = ContentPackEntitlementsProcessor(
|
|
content_pack_id=content_pack_id,
|
|
logger=self.logger,
|
|
session_key=self.session_key
|
|
)
|
|
content_objects = ContentPackContentReader(
|
|
logger=self.logger,
|
|
session_key=self.session_key
|
|
).read(content_pack_id, version, journal=journal)
|
|
entitlement_writer.apply_object_type_level_entitlement(content_objects)
|
|
return content_objects
|
|
|
|
def get_content_info_from_json_files(self, content_objects):
|
|
"""
|
|
Retrieve a tuple where
|
|
the first item is a dict where key is content type, value is a list of content pack objects based on a
|
|
content_pack_id from content pack json files and
|
|
the second item is a list of correlation search keys of all content pack correlation searches in json files
|
|
|
|
:param content_objects: content pack objects dict aggregated by content types
|
|
:type content_objects: dict
|
|
|
|
:return: list of content pack objects with fields id, title, description,
|
|
list of content pack correlation search keys
|
|
:rtype: tuple
|
|
eg:
|
|
(
|
|
{
|
|
'glass_tables': [
|
|
{
|
|
'description': u"Throws an event when storefront isn't able to launch a resource",
|
|
'id': u'itsi-citrix-storefront-no-resources',
|
|
'title': u'Storefront No Resources'
|
|
}
|
|
]
|
|
},
|
|
[
|
|
'Windows Event Logs',
|
|
'Database Events'
|
|
]
|
|
)
|
|
|
|
"""
|
|
content_objects_info = {}
|
|
correlation_search_keys = []
|
|
|
|
for content_type, objects in content_objects.items():
|
|
if content_type == ContentType.GLASS_TABLE_IMAGE:
|
|
continue
|
|
elif content_type == ContentType.CORRELATION_SEARCH:
|
|
# The reason why we treat correlation searches as a special case is because correlation searches
|
|
# don't have source_itsi_da_version and source_itsi_da fields while other content pack objects have
|
|
# so that while we can pass source_itsi_da_version and source_itsi_da as filter to retrieve other
|
|
# content pack objects from KV Store, it doesn't work for correlation searches. The only way is to
|
|
# first get a list of names(the key of correlation searches) from json files and use that as a filter.
|
|
correlation_search_keys += [get_itoa_object_id(content_type, item) for item in objects]
|
|
content_pack_list = content_objects_info.get(content_type, [])
|
|
content_pack_list += [
|
|
{
|
|
ContentPackFields.ID: get_itoa_object_id(content_type, item),
|
|
ContentPackFields.TITLE: get_itoa_object_title(content_type, item),
|
|
ContentPackFields.DESCRIPTION: item.get(ContentPackFields.DESCRIPTION, ''),
|
|
ContentPackFields.ENTITLEMENT_STATUS: item.get(ContentPackFields.ENTITLEMENT_STATUS, False)
|
|
}
|
|
for item in objects]
|
|
content_objects_info[content_type] = content_pack_list
|
|
|
|
return content_objects_info, correlation_search_keys
|
|
|
|
def get_kvstore_content_objects_key(self, content_pack_id, correlation_search_keys):
|
|
"""
|
|
Retrieve a list of content pack objects of a content_pack_id from kvstore
|
|
|
|
:param content_pack_id: the content pack version id
|
|
:type content_pack_id: str
|
|
|
|
:param correlation_search_keys: list of content pack correlation search keys from json files
|
|
:type correlation_search_keys: list
|
|
|
|
:return: dict of content pack object keys separated by content types retrieved from KV Store
|
|
:rtype: dict
|
|
eg:
|
|
{
|
|
'correlation_searches':[
|
|
'Bidirectional Ticketing',
|
|
'Monitor Critical Services Based on Health Score',
|
|
'Normalized Correlation Search'
|
|
],
|
|
'deep_dives': [],
|
|
'entity_types': [],
|
|
'glass_tables': [],
|
|
'glass_table_icons': [],
|
|
'kpi_base_searches': [
|
|
'vmware-vmware-esxi',
|
|
'vmware-vmware-vcenter'
|
|
], 'kpi_threshold_templates': [],
|
|
'notable_event_aggregation_policies': [],
|
|
'service_analyzers': [],
|
|
'service_templates': [
|
|
'vmware-vmware-esxi-servers',
|
|
'vmware-vmware-vcenter',
|
|
'vmware-vmware-virtual-machines'
|
|
]
|
|
'services': [
|
|
'vmware-vmware-esxi-servers',
|
|
'vmware-vmware-virtual-machines',
|
|
'vmware-vmware-vsphere'
|
|
]
|
|
}
|
|
"""
|
|
content_types = [item for item in CONTENT_TYPE_TO_ITOA_TYPE.keys() if item != ContentType.GLASS_TABLE_IMAGE]
|
|
kvstore_content_objects_key = {content_type: [] for content_type in content_types}
|
|
|
|
for content_type in content_types:
|
|
if content_type == ContentType.CORRELATION_SEARCH:
|
|
correlation_search_key_query_list = [
|
|
{'name': key} for key in correlation_search_keys
|
|
]
|
|
filter_data = {'$or': correlation_search_key_query_list} if correlation_search_key_query_list else {}
|
|
else:
|
|
filter_data = {
|
|
'$and': [{CONTENT_PACK_SOURCE_FIELD: content_pack_id}]
|
|
}
|
|
itoa_object_class = get_itoa_object_class(content_type)
|
|
content_pack_objects_from_kvstore = itoa_object_class(
|
|
self.session_key,
|
|
self.owner
|
|
).get_bulk(owner=self.owner, filter_data=filter_data)
|
|
kvstore_content_objects_key[content_type] = [get_itoa_object_id(content_type, item) for item in
|
|
content_pack_objects_from_kvstore]
|
|
|
|
return kvstore_content_objects_key
|
|
|
|
@staticmethod
|
|
def add_fields_to_content_pack_objects(content_objects, content_objects_info, kvstore_content_objects_key):
|
|
"""
|
|
Add installed and has_dependency fields to content pack objects retrieved from json files
|
|
|
|
:param content_objects: content pack objects dict aggregated by content types
|
|
:type content_objects: dict
|
|
|
|
:param content_objects_info: list of content pack retrieved from json files
|
|
:type content_objects_info: list
|
|
|
|
:param kvstore_content_objects_key: dict of content pack object keys separated
|
|
by content types retrieved from KV Store
|
|
:type kvstore_content_objects_key: dict
|
|
|
|
:return: a dict where key is content type and value is a list of content pack objects with installed field
|
|
:rtype: dict
|
|
eg:
|
|
{
|
|
'glass_tables':
|
|
[
|
|
{
|
|
'description': u"Throws an event when storefront isn't able to launch a resource",
|
|
'id': u'itsi-citrix-storefront-no-resources',
|
|
'installed': False,
|
|
'has_dependency': False,
|
|
'title': u'Storefront No Resources'
|
|
}
|
|
]
|
|
}
|
|
"""
|
|
updated_content_pack_objects_dict_from_json = {}
|
|
for content_type, content_pack_object_list in content_objects_info.items():
|
|
content_pack_objects_preview_list = []
|
|
for content_pack_object in content_pack_object_list:
|
|
if content_pack_object[ContentPackFields.ID] in kvstore_content_objects_key[content_type]:
|
|
content_pack_object[ContentPackFields.INSTALLED] = True
|
|
else:
|
|
content_pack_object[ContentPackFields.INSTALLED] = False
|
|
content_pack_object['has_dependency'] = ContentPackPreviewer.identify_dependencies(
|
|
content_type,
|
|
content_pack_object[ContentPackFields.ID],
|
|
content_objects
|
|
)
|
|
content_pack_objects_preview_list.append(content_pack_object)
|
|
updated_content_pack_objects_dict_from_json[content_type] = content_pack_objects_preview_list
|
|
return updated_content_pack_objects_dict_from_json
|
|
|
|
@staticmethod
|
|
def identify_dependencies(content_type, object_id, content_objects):
|
|
"""
|
|
Identify has_dependency field of a content pack object by reviewing associated attributes of
|
|
other objects in this content pack
|
|
|
|
:param content_type: content type of object with object_id
|
|
:type content_type: str
|
|
|
|
:param object_id: object id of a content pack object
|
|
:type object_id: str
|
|
|
|
:param content_objects: content pack objects of this content pack id
|
|
:type content_objects: dict
|
|
|
|
:return: a boolean whether the object of this object_id has dependencies
|
|
:rtype: bool
|
|
"""
|
|
always_has_dependency_list = [
|
|
ContentType.CORRELATION_SEARCH,
|
|
ContentType.NOTABLE_EVENT_AGGREGATION_POLICY
|
|
]
|
|
services = content_objects.get(ContentType.SERVICE, [])
|
|
if content_type in always_has_dependency_list:
|
|
return True
|
|
elif content_type == ContentType.KPI_BASE_SEARCH:
|
|
for service in services:
|
|
for kpi in service.get('kpis', []):
|
|
if 'base_search_id' in kpi and kpi['base_search_id'] == object_id:
|
|
return True
|
|
elif content_type == ContentType.KPI_THRESHOLD_TEMPLATE:
|
|
for service in services:
|
|
for kpi in service.get('kpis', []):
|
|
if 'kpi_threshold_template_id' in kpi and kpi['kpi_threshold_template_id'] == object_id:
|
|
return True
|
|
elif content_type == ContentType.SERVICE_TEMPLATE:
|
|
for service in services:
|
|
if service.get('base_service_template_id') == object_id:
|
|
return True
|
|
elif content_type == ContentType.SERVICE:
|
|
for service in services:
|
|
if service['_key'] == object_id:
|
|
dependent_number = len(service['services_depends_on'])
|
|
depended_number = len(service['services_depending_on_me'])
|
|
if dependent_number > 0 or depended_number > 0 or service['base_service_template_id']:
|
|
return True
|
|
return False
|
|
|
|
def preview(self, content_pack_id, version):
|
|
"""
|
|
Get a list of content pack objects with field installed
|
|
indicating whether content pack objects have been installed or not
|
|
|
|
:param content_pack_id: the content pack version id
|
|
:type content_pack_id: str
|
|
|
|
:param version: the content pack version
|
|
:type version: str
|
|
|
|
:return: a dict where key is content type and value is a list of content pack objects with installed field
|
|
:rtype: dict
|
|
eg:
|
|
{
|
|
'glass_tables':
|
|
[
|
|
{
|
|
'description': u"Throws an event when storefront isn't able to launch a resource",
|
|
'id': u'itsi-citrix-storefront-no-resources',
|
|
'installed': False,
|
|
'title': u'Storefront No Resources'
|
|
}
|
|
]
|
|
}
|
|
"""
|
|
content_objects = self.get_content_objects(content_pack_id, version)
|
|
content_objects_info, correlation_search_keys = self.get_content_info_from_json_files(content_objects)
|
|
kvstore_content_objects_key = self.get_kvstore_content_objects_key(
|
|
content_pack_id,
|
|
correlation_search_keys
|
|
)
|
|
content_objects_preview = ContentPackPreviewer.add_fields_to_content_pack_objects(
|
|
content_objects,
|
|
content_objects_info,
|
|
kvstore_content_objects_key)
|
|
|
|
content_objects_preview["saved_searches"] = retrieve_saved_search_consistency_status(
|
|
session_key=self.session_key,
|
|
content_pack_id=content_pack_id,
|
|
)
|
|
return content_objects_preview
|
|
|
|
def format_preview_objects(self, content_pack_id, version):
|
|
"""
|
|
Get a formatted list of Content Pack Object IDs from preview.
|
|
|
|
:param content_pack_id: the content pack id
|
|
:type content_pack_id: str
|
|
|
|
:param version: the content pack version
|
|
:type version: str
|
|
|
|
:return: a dict where key is content type and value is a list of content pack object IDs.
|
|
:rtype: dict
|
|
eg:
|
|
{
|
|
'glass_tables': ['gt-id-1', 'gt-id-2'],
|
|
'entity_type': ['et-id-1', 'et-id-2']
|
|
}
|
|
"""
|
|
preview_objects = self.preview(content_pack_id, version)
|
|
content_filter_data = {}
|
|
for content_type in preview_objects:
|
|
try:
|
|
if content_type != ContentPackFields.SAVED_SEARCHES:
|
|
object_ids = []
|
|
for content_pack_object in preview_objects[content_type]:
|
|
object_ids.append(content_pack_object['id'])
|
|
content_filter_data[content_type] = object_ids
|
|
except Exception as ex:
|
|
LOGGER.error('Failed formating of object id="%s" content_pack_id="%s" version="%s"', content_pack_object['id'], content_pack_id, version)
|
|
LOGGER.exception(ex)
|
|
|
|
return content_filter_data
|