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.

294 lines
20 KiB

# Copyright (C) 2005-2025 Splunk Inc. All Rights Reserved.
from itsi.objects.model.itsi_model_validator import ItsiModelValidator
from migration.migration_precheck import MigrationPreCheck
class SIMigrationPreCheck(MigrationPreCheck):
"""
SI migration prechecks. The checks being performed are:
* Check for service templates that are not synced
* Check for service templates that have dangling linked service refs
* Check that a service template's linked services have a reciprocating base_service_template_id backref
* Check that a service's base_service_template_id has have a reciprocating linked_services backref
* Check for service objects that have dangling depends_on and/or depends_on_me service refs
* Check for KPIs that have dangling shared_base search refs
* Check for KPIs that have dangling kpi_threshold_template_id refs
"""
def __init__(self, session_key, logger, pre_checks, skip_pre_checks=[]):
MigrationPreCheck.__init__(self, session_key, logger, pre_checks, skip_pre_checks)
self.itsi_model_validator = ItsiModelValidator(session_key, logger)
@staticmethod
def collect_service_depends_info_strings(service_obj, services_depends_attr):
"""
Get a service's service dependency ids for the given service dependency attribute.
:param service_obj: the service object to get service dependency ids for
:param services_depends_attr: the service dependency attribute
:return: list of service dependency ids
"""
service_depends_info_strings = ["%s (%s)" % (services_depend_obj['identifying_name'], services_depend_obj['_key']) for
services_depend_obj in service_obj.get(services_depends_attr, [])]
return service_depends_info_strings
def precheck_SVC_SVCTMPL(self):
"""
* Check for service templates that are not synced
* Check for service templates that have dangling linked service refs
* Check that a service template's linked services have a reciprocating base_service_template_id backref
* Check that a service's base_service_template_id has have a reciprocating linked_services backref
* Check for service objects that have dangling depends_on and/or depends_on_me service refs
:return: None
"""
# Loop through all service templates
self.itsi_model_validator.check_service_templates()
# Loop through all services in chunks
self.itsi_model_validator.check_services()
ret_list = []
# service templates with bad sync_status
self.logger.info('Service templates with bad sync_status count: %s',
len(self.itsi_model_validator.service_template_bad_sync_status))
for service_template_obj in self.itsi_model_validator.service_template_bad_sync_status:
ret_list.append(self._make_result(False, "Service template: %s (%s) is not synced: %s" % (
service_template_obj.get('identifying_name', ''), service_template_obj['_key'],
service_template_obj['sync_status']), "Error"))
# service templates with dangling linked service ids
self.logger.info('Service templates with dangling linked_services count: %s',
len(self.itsi_model_validator.service_template_id_to_missing_linked_services_map))
for service_template_id in self.itsi_model_validator.service_template_id_to_missing_linked_services_map:
service_template_obj = self.itsi_model_validator.service_template_id_to_missing_linked_services_map[
service_template_id]
service_ids_missing = service_template_obj['linked_services']
ret_list.append(self._make_result(False, "Service template: %s (%s) has %s dangling linked_services" %
(
service_template_obj.get('identifying_name', ''),
service_template_obj['_key'], len(service_ids_missing)
), "Warn"))
self.logger.warn("Service template: %s (%s) has %s dangling linked_services: %s" % (
service_template_obj.get('identifying_name', ''), service_template_obj['_key'],
len(service_ids_missing), ','.join(service_ids_missing)))
# check that a service template's linked services have a reciprocating base_service_template_id backref
self.logger.info('Services with missing expected base_service_template_id count: %s',
len(self.itsi_model_validator.service_objects_missing_expected_service_template_id))
for service_object_missing_expected_service_template_id in \
self.itsi_model_validator.service_objects_missing_expected_service_template_id:
base_service_template_id = service_object_missing_expected_service_template_id.get(
'base_service_template_id', '')
base_service_template_expected = service_object_missing_expected_service_template_id[
'base_service_template_expected']
base_service_template_expected_id = base_service_template_expected['_key']
base_service_template_expected_name = base_service_template_expected['identifying_name']
ret_list.append(
self._make_result(
False,
"Service: %s (%s) is missing expected base service template: %s (%s)\
where actual base_service_template_id is: %s" % (
service_object_missing_expected_service_template_id.get(
'identifying_name', ''),
service_object_missing_expected_service_template_id['_key'],
base_service_template_expected_name, base_service_template_expected_id,
base_service_template_id), "Warn"))
# check that a service's base_service_template_id has have a reciprocating linked_services backref
self.logger.info('Service templates with missing expected linked_services count: %s',
len(self.itsi_model_validator.service_template_objects_missing_expected_linked_services_map))
for service_template_id in \
self.itsi_model_validator.service_template_objects_missing_expected_linked_services_map:
service_template_object_missing_expected_linked_services =\
self.itsi_model_validator.\
service_template_objects_missing_expected_linked_services_map[service_template_id]
missing_linked_services = service_template_object_missing_expected_linked_services['linked_services']
ret_list.append(
self._make_result(
False, "Service template: %s (%s) is missing %s expected linked_services" % (
service_template_object_missing_expected_linked_services.get(
'identifying_name', ''),
service_template_object_missing_expected_linked_services['_key'],
len(missing_linked_services)), "Warn"))
self.logger.warn("Service template: %s (%s) is missing %s expected linked_services: %s" % (
service_template_object_missing_expected_linked_services.get(
'identifying_name', ''),
service_template_object_missing_expected_linked_services['_key'],
len(missing_linked_services), ','.join(
["%s (%s)" % (missing_linked_service['identifying_name'], missing_linked_service['_key'])
for missing_linked_service in missing_linked_services])))
# services with dangling service template id
self.logger.info('Services with dangling base_service_template_id count: %s',
len(self.itsi_model_validator.service_objs_missing_service_template_id))
for service_obj_missing_service_template_id in \
self.itsi_model_validator.service_objs_missing_service_template_id:
ret_list.append(self._make_result(False, "Service: %s (%s) has a dangling base_service_template_id: %s" % (
service_obj_missing_service_template_id.get('identifying_name', ''),
service_obj_missing_service_template_id['_key'],
service_obj_missing_service_template_id['base_service_template_id']), "Warn"))
# Check service bidirectional dependencies for each service, lookup services using services_depends_on.
# For each of those services, ensure that services_depending_on_me contains the original service.
# Remove verified ids from services_depends_on and services_depending_on_me.
# Loop through services and for those that have non-empty services_depends_on or services_depending_on_me,
# mark as error because they are dangling references
self.logger.info('Services with dangling services_depends_on and/or services_depending_on_me count: %s',
len(self.itsi_model_validator.service_objects_with_dangling_service_refs))
for service_obj in self.itsi_model_validator.service_objects_with_dangling_service_refs:
services_depends_on_info_strings = set()
self.itsi_model_validator.collect_service_depends_service_ids(service_obj, 'services_depends_on',
services_depends_on_info_strings)
services_depending_on_me_info_strings = set()
self.itsi_model_validator.collect_service_depends_service_ids(service_obj, 'services_depending_on_me',
services_depending_on_me_info_strings)
if services_depends_on_info_strings:
ret_list.append(self._make_result(False, "Service: %s (%s) has %s dangling services_depends_on" % (
service_obj.get('identifying_name', ''), service_obj['_key'], len(services_depends_on_info_strings)), "Warn"))
self.logger.warn("Service: %s (%s) has %s dangling services_depends_on: %s" % (
service_obj.get('identifying_name', ''), service_obj['_key'], len(services_depends_on_info_strings),
','.join(services_depends_on_info_strings)))
if services_depending_on_me_info_strings:
ret_list.append(self._make_result(False,
"Service: %s (%s) has %s dangling services_depending_on_me" % (
service_obj.get('identifying_name', ''), service_obj['_key'],
len(services_depending_on_me_info_strings)), "Warn"))
self.logger.warn("Service: %s (%s) has %s dangling services_depending_on_me: %s" % (
service_obj.get('identifying_name', ''), service_obj['_key'],
len(services_depending_on_me_info_strings),
','.join(services_depending_on_me_info_strings)))
self.logger.info('Services with missing expected services_depends_on and/or services_depending_on_me count: %s',
len(self.itsi_model_validator.service_objects_with_missing_depends_service_refs_map))
for reverse_service_id in self.itsi_model_validator.service_objects_with_missing_depends_service_refs_map:
reverse_service_obj = self.itsi_model_validator.\
service_objects_with_missing_depends_service_refs_map[reverse_service_id]
services_depends_on_info_strings = self.collect_service_depends_info_strings(
reverse_service_obj, 'services_depends_on')
services_depending_on_me_info_strings = self.collect_service_depends_info_strings(
reverse_service_obj, 'services_depending_on_me')
if services_depends_on_info_strings:
ret_list.append(self._make_result(False, "Service: %s (%s) has %s missing services_depends_on" % (
reverse_service_obj.get('identifying_name', ''), reverse_service_obj['_key'],
len(services_depends_on_info_strings)), "Warn"))
self.logger.warn("Service: %s (%s) has %s missing services_depends_on: %s" % (
reverse_service_obj.get('identifying_name', ''), reverse_service_obj['_key'],
len(services_depends_on_info_strings), ','.join(services_depends_on_info_strings)))
if services_depending_on_me_info_strings:
ret_list.append(self._make_result(False,
"Service: %s (%s) had missing services_depending_on_me refs: %s" % (
reverse_service_obj.get('identifying_name', ''),
reverse_service_obj['_key'],
','.join(services_depending_on_me_info_strings)), "Warn"))
self.logger.warn("Service: %s (%s) has %s missing services_depending_on_me: %s" % (
reverse_service_obj.get('identifying_name', ''), reverse_service_obj['_key'],
len(services_depending_on_me_info_strings), ','.join(services_depending_on_me_info_strings)))
if ret_list:
return ret_list
return [self._make_result(True, "Services and service template ref checks passed", "Success")]
def _make_obj_with_corrupt_kpis_results(self, obj_with_corrupt_kpis):
"""
Make precheck failed results for object whose KPIs that have a mismatch of base_search_id and search_type.
:param obj_with_corrupt_kpis: object with list of KPIs with corrupt base search
:return: list of precheck results
"""
return [self._make_result(
False,
"%s: %s (%s) has KPI: %s that has mismatch of base_search_id: %s and search_type: %s" %
(
obj_with_corrupt_kpis['object_type'],
obj_with_corrupt_kpis.get('identifying_name', ''),
obj_with_corrupt_kpis['_key'],
kpi_object_corrupt_search.get('title', ''),
kpi_object_corrupt_search.get('base_search_id', ''),
kpi_object_corrupt_search.get('search_type', '')
), "Warn") for kpi_object_corrupt_search in obj_with_corrupt_kpis['kpis']]
def _make_obj_with_dangling_shared_base_search_kpis_results(self, obj_with_dangling_shared_base_search_kpis):
"""
Make precheck failed results for object with KPIs whose base search id is dangling.
:param obj_with_dangling_shared_base_search_kpis: object with list of KPIs with dangling base search ids
:return: list of precheck results
"""
return [self._make_result(False,
"%s: %s (%s) has KPI: %s that has a dangling base_search_id: %s" % (
obj_with_dangling_shared_base_search_kpis['object_type'],
obj_with_dangling_shared_base_search_kpis.get('identifying_name', ''),
obj_with_dangling_shared_base_search_kpis['_key'],
dangling_shared_base_search_kpi.get('title', ''),
dangling_shared_base_search_kpi.get('base_search_id', '')
), "Warn") for dangling_shared_base_search_kpi in
obj_with_dangling_shared_base_search_kpis['kpis']]
def _make_obj_with_dangling_kpi_threshold_templates_results(self, obj_with_dangling_kpi_threshold_templates):
"""
Make precheck failed results for object with KPIs whose KPI threshold template is dangling.
:param obj_with_dangling_kpi_threshold_templates: object with list of KPIs with dangling KPI threshold templates
:return: list of precheck results
"""
return [self._make_result(False,
"%s: %s (%s) has KPI: %s that has a dangling kpi_threshold_template_id: %s" % (
obj_with_dangling_kpi_threshold_templates['object_type'],
obj_with_dangling_kpi_threshold_templates.get('identifying_name', ''),
obj_with_dangling_kpi_threshold_templates['_key'],
dangling_kpi_threshold_template_kpi.get('title', ''),
dangling_kpi_threshold_template_kpi.get('kpi_threshold_template_id', '')
), "Warn") for dangling_kpi_threshold_template_kpi in
obj_with_dangling_kpi_threshold_templates['kpis']]
def precheck_KPI(self):
"""
* Check for KPIs that have dangling shared_base search refs
* Check for KPIs that have dangling kpi_threshold_template_id refs
* Check for KPIs with empty threshold field
:return: results of check
"""
self.itsi_model_validator.check_kpis_in_collections()
self.itsi_model_validator.get_kpi_with_empty_threshold_field()
ret_list = []
# KPI search type mismatch with base search id
self.logger.info('Objects with corrupt KPI searches count: %s',
len(self.itsi_model_validator.objs_with_corrupt_kpis))
ret_list.extend([result for obj_with_corrupt_kpis in
self.itsi_model_validator.objs_with_corrupt_kpis for result in
self._make_obj_with_corrupt_kpis_results(obj_with_corrupt_kpis)])
# KPIs missing base search object
self.logger.info('Objects with KPIs that have dangling base_search_id count: %s',
len(self.itsi_model_validator.objs_with_dangling_shared_base_search_kpis))
ret_list.extend(
[result for obj_with_dangling_shared_base_search_kpis in
self.itsi_model_validator.objs_with_dangling_shared_base_search_kpis for
result in
self._make_obj_with_dangling_shared_base_search_kpis_results(obj_with_dangling_shared_base_search_kpis)])
# KPIs missing kpi threshold template object
self.logger.info('Objects with KPIs that have dangling kpi_threshold_template_id count: %s',
len(self.itsi_model_validator.objs_with_dangling_kpi_threshold_templates))
ret_list.extend(
[result for obj_with_dangling_kpi_threshold_templates in
self.itsi_model_validator.objs_with_dangling_kpi_threshold_templates for
result in
self._make_obj_with_dangling_kpi_threshold_templates_results(obj_with_dangling_kpi_threshold_templates)])
# KPIs with empty threshold field
self.logger.info('Objects with KPIs that have empty threshold field count: %s',
len(self.itsi_model_validator.kpi_with_empty_threshold_field))
make_result_list = [self._make_result(
False, "KPI: %s (%s) of %s type in service %s (%s) has empty threshold field" % (
kpi_with_empty_threshold.get('title', ''),
kpi_with_empty_threshold.get('_key', ''),
kpi_with_empty_threshold.get('search_type', ''),
kpi_with_empty_threshold.get('service_title', ''),
kpi_with_empty_threshold.get('service_id', '')
), "Warn") for kpi_with_empty_threshold in
self.itsi_model_validator.kpi_with_empty_threshold_field]
ret_list.extend(make_result_list)
if ret_list:
return ret_list
return [self._make_result(True, "KPI checks passed", "Success")]