def _process_components(self, instance_info): """ Gets SNOW components name, external_id and other identifiers :param instance_info: :return: """ collected_components = self._batch_collect(self._batch_collect_components, instance_info) for component in collected_components: data = {} component = self._filter_empty_metadata(component) identifiers = [] comp_name = component.get('name') comp_type = component.get('sys_class_name') external_id = component.get('sys_id') if component.get('fqdn'): identifiers.append(Identifiers.create_host_identifier(to_string(component['fqdn']))) if component.get('host_name'): identifiers.append(Identifiers.create_host_identifier(to_string(component['host_name']))) else: identifiers.append(Identifiers.create_host_identifier(to_string(comp_name))) identifiers.append(external_id) identifiers = Identifiers.append_lowercase_identifiers(identifiers) data.update(component) data.update({"identifiers": identifiers, "tags": instance_info.instance_tags}) self.component(external_id, comp_type, data)
def _process_components(self, instance_info): """ Gets SNOW components name, external_id and other identifiers :param instance_info: :return: None """ collected_components = self._batch_collect( self._batch_collect_components, instance_info) for component in collected_components: try: config_item = ConfigurationItem(component, strict=False) config_item.validate() except DataError as e: self.log.warning( "Error while processing properties of CI {} having sys_id {} - {}" .format(config_item.sys_id.value, config_item.name.value, e)) continue data = {} component = self.select_metadata_field( component, instance_info.component_display_value_list) identifiers = [] comp_name = config_item.name.value comp_type = config_item.sys_class_name.value external_id = config_item.sys_id.value if config_item.fqdn.value: identifiers.append( Identifiers.create_host_identifier( to_string(config_item.fqdn.value))) if config_item.host_name.value: identifiers.append( Identifiers.create_host_identifier( to_string(config_item.host_name.value))) else: identifiers.append( Identifiers.create_host_identifier(to_string(comp_name))) identifiers.append(external_id) identifiers = Identifiers.append_lowercase_identifiers(identifiers) data.update(component) tags = instance_info.instance_tags sys_tags = config_item.sys_tags.display_value if sys_tags: sys_tags = list(map(lambda x: x.strip(), sys_tags.split(","))) tags = tags + sys_tags data.update({"identifiers": identifiers, "tags": tags}) self.component(external_id, comp_type, data)
def select_metadata_field(data, display_value_list): """ Retrieve the proper attribute either `display_value` or `value` from data :param data: metadata from servicenow :param display_value_list: list of attributes for which `display_value` to be extracted :return: metadata with applied field """ result = {} if isinstance(data, dict): for k, v in data.items(): # since display_param_value always returns dictionary for all keys if isinstance(v, dict): if k in display_value_list: if v.get("display_value"): result[k] = to_string(v.get("display_value")) continue result[k] = to_string(v.get("value")) return result
def _filter_empty_metadata(data): """ Filter the empty key:value in metadata dictionary and fix utf-8 encoding problems :param data: metadata from servicenow :return: filtered metadata """ result = {} if isinstance(data, dict): for k, v in data.items(): if v: result[k] = to_string(v) return result
def test_custom_cmdb_ci_field(self): """ Read from the custom field. """ custom_field_instance = { 'url': "https://instance.service-now.com", 'user': '******', 'password': '******', 'custom_cmdb_ci_field': 'u_configuration_item' } check = ServicenowCheck('servicenow', {}, {}, [custom_field_instance]) check._collect_relation_types = mock_collect_process check._batch_collect_components = mock_collect_process check._batch_collect_relations = mock_collect_process check._collect_change_requests = mock.MagicMock() response = self._read_data('CHG0000003.json') self.assertEqual( to_string('Sales © Force Automation'), to_string(response['result'][0]['u_configuration_item'] ['display_value'])) self.assertEqual( to_string( 'Service Management Tools Portal - AXA WINTERTHUR - Production - Standard' ), response['result'][0]['cmdb_ci']['display_value']) check._collect_change_requests.return_value = response check.run() topology_events = telemetry._topology_events service_checks = aggregator.service_checks( 'servicenow.cmdb.topology_information') self.assertEqual(AgentCheck.OK, service_checks[0].status) self.assertEqual(1, len(topology_events)) self.assertEqual(to_string('CHG0000003: Rollback Oracle ® Version'), topology_events[0]['msg_title']) host_identifier = [ e for e in topology_events[0]['context']['element_identifiers'] if 'urn:host:/' in e ][0] self.assertEqual(to_string('urn:host:/Sales © Force Automation'), host_identifier) self.check.commit_state(None)
def _create_event_from_change_request(self, change_request): host = Identifiers.create_host_identifier( to_string(change_request.custom_cmdb_ci.display_value)) identifiers = [change_request.custom_cmdb_ci.value, host] identifiers = Identifiers.append_lowercase_identifiers(identifiers) timestamp = (change_request.sys_updated_on.value - datetime.datetime.utcfromtimestamp(0)).total_seconds() msg_title = '%s: %s' % (change_request.number.display_value, change_request.short_description.display_value) tags = [ 'number:%s' % change_request.number.display_value, 'priority:%s' % change_request.priority.display_value, 'risk:%s' % change_request.risk.display_value, 'state:%s' % change_request.state.display_value, 'category:%s' % change_request.category.display_value, 'conflict_status:%s' % change_request.conflict_status.display_value, 'assigned_to:%s' % change_request.assigned_to.display_value, ] event_type = 'Change Request %s' % change_request.type.display_value self.log.debug('Creating event from CR %s', change_request.number.display_value) self.event({ 'timestamp': timestamp, 'event_type': event_type, 'msg_title': msg_title, 'msg_text': change_request.description.display_value, 'context': { 'source': 'servicenow', 'category': 'change_request', 'element_identifiers': identifiers, 'source_links': [], 'data': { 'impact': change_request.impact.display_value, 'requested_by': change_request.requested_by.display_value, 'conflict_last_run': change_request.conflict_last_run.display_value, 'assignment_group': change_request.assignment_group.display_value, 'service_offering': change_request.service_offering.display_value, }, }, 'tags': tags })
def test_creating_event_from_change_request(self): """ Test creating event from SNOW Change Request """ self.check._collect_relation_types = mock_collect_process self.check._batch_collect_components = mock_collect_process self.check._batch_collect_relations = mock_collect_process self.check._collect_change_requests = mock.MagicMock() self.check._collect_change_requests.return_value = self._read_data( 'CHG0000001.json') self.check.run() topology_events = telemetry._topology_events service_checks = aggregator.service_checks( 'servicenow.cmdb.topology_information') self.assertEqual(AgentCheck.OK, service_checks[0].status) self.assertEqual(1, len(topology_events)) self.assertEqual(to_string('CHG0000001: Rollback Oracle ® Version'), topology_events[0]['msg_title']) self.check.commit_state(None)
def _create_event_from_change_request(self, change_request): """ StackState topology event is created from ServiceNow Change Request (CR). Time of event is based on when the CR was last time updated. :param change_request: ChangeRequest object :return: None """ host = Identifiers.create_host_identifier( to_string(change_request.custom_cmdb_ci.display_value)) identifiers = [change_request.custom_cmdb_ci.value, host] identifiers = Identifiers.append_lowercase_identifiers(identifiers) timestamp = (change_request.sys_updated_on.value - datetime.datetime.utcfromtimestamp(0)).total_seconds() msg_title = '%s: %s' % (change_request.number.display_value, change_request.short_description.display_value or 'No short description') msg_txt = change_request.description.display_value or 'No description' tags = [ 'number:%s' % change_request.number.display_value, 'priority:%s' % change_request.priority.display_value, 'risk:%s' % change_request.risk.display_value, 'impact:%s' % change_request.impact.display_value, 'state:%s' % change_request.state.display_value, 'category:%s' % change_request.category.display_value, ] event_type = 'Change Request %s' % change_request.type.display_value self.log.debug('Creating STS topology event from SNOW CR %s', change_request.number.display_value) self.event({ 'timestamp': timestamp, 'event_type': event_type, 'msg_title': msg_title, 'msg_text': msg_txt, 'context': { 'source': 'servicenow', 'category': 'change_request', 'element_identifiers': identifiers, 'source_links': [], 'data': { 'requested_by': change_request.requested_by.display_value, 'assignment_group': change_request.assignment_group.display_value, 'assigned_to': change_request.assigned_to.display_value, 'conflict_status': change_request.conflict_status.display_value, 'conflict_last_run': change_request.conflict_last_run.display_value, 'service_offering': change_request.service_offering.display_value, 'start_date': change_request.custom_planned_start_date.display_value, 'end_date': change_request.custom_planned_end_date.display_value, }, }, 'tags': tags })