Skip to main content

ServiceNow Integration

This guide covers the integration between NopeSight and ServiceNow, enabling seamless synchronization of configuration items, automated incident creation, and bidirectional data flow.

Overview

The NopeSight-ServiceNow integration provides:

  • Bidirectional CI Synchronization - Keep CMDB data in sync
  • Automated Incident Management - Create and update incidents
  • Change Request Integration - Link changes to CI relationships
  • Service Mapping Sync - Share service dependencies
  • Real-time Updates - Webhook-based synchronization

Architecture

Installation

1. Install NopeSight Integration App

  1. In ServiceNow, navigate to System Applications > Applications
  2. Search for "NopeSight Integration"
  3. Click Install
  4. Follow the installation wizard

2. Configure Integration User

// Create integration user in ServiceNow
var user = new GlideRecord('sys_user');
user.initialize();
user.user_name = 'nopesight_integration';
user.first_name = 'NopeSight';
user.last_name = 'Integration';
user.email = 'nopesight@company.com';
user.active = true;
user.insert();

// Assign roles
var role = new GlideRecord('sys_user_has_role');
role.initialize();
role.user = user.sys_id;
role.role = getRoleByName('itil');
role.insert();

role.initialize();
role.user = user.sys_id;
role.role = getRoleByName('import_admin');
role.insert();

3. Generate API Credentials

# In NopeSight
curl -X POST https://api.nopesight.com/v1/integrations/servicenow/setup \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"instance_url": "https://company.service-now.com",
"username": "nopesight_integration",
"password": "secure_password"
}'

Configuration

Connection Settings

# NopeSight configuration
integrations:
servicenow:
enabled: true
instance_url: https://company.service-now.com
auth:
method: oauth2
client_id: ${SERVICENOW_CLIENT_ID}
client_secret: ${SERVICENOW_CLIENT_SECRET}

sync:
interval: 300 # seconds
batch_size: 100

field_mapping:
ci:
name: name
serial_number: serial_number
ip_address: ip_address
os: os
location: location
department: u_department

webhook:
endpoint: /api/integrations/servicenow/webhook
secret: ${WEBHOOK_SECRET}

ServiceNow Business Rules

// Business rule for CI updates
(function executeRule(current, previous /*null when async*/) {

// Only sync if NopeSight flag is set
if (current.u_sync_to_nopesight != true) {
return;
}

var nopesight = new NopeSightIntegration();

// Prepare CI data
var ciData = {
sys_id: current.sys_id.toString(),
name: current.name.toString(),
sys_class_name: current.sys_class_name.toString(),
serial_number: current.serial_number.toString(),
ip_address: current.ip_address.toString(),
operational_status: current.operational_status.toString(),
attributes: {}
};

// Add class-specific attributes
if (current.sys_class_name == 'cmdb_ci_server') {
ciData.attributes.cpu_count = current.cpu_count.toString();
ciData.attributes.ram = current.ram.toString();
ciData.attributes.disk_space = current.disk_space.toString();
}

// Send to NopeSight
var response = nopesight.updateCI(ciData);

if (!response.success) {
gs.error('Failed to sync CI to NopeSight: ' + response.error);
}

})(current, previous);

Data Synchronization

CI Synchronization

# NopeSight sync script
import requests
from datetime import datetime

class ServiceNowSync:
def __init__(self, config):
self.snow_url = config['instance_url']
self.auth = (config['username'], config['password'])
self.headers = {
'Accept': 'application/json',
'Content-Type': 'application/json'
}

def sync_configuration_items(self):
"""Sync CIs from ServiceNow to NopeSight"""

# Get CIs modified in last sync interval
query = f"sys_updated_on>{self.last_sync_time}"

response = requests.get(
f"{self.snow_url}/api/now/table/cmdb_ci",
params={'sysparm_query': query},
auth=self.auth,
headers=self.headers
)

cis = response.json()['result']

for ci in cis:
# Transform ServiceNow CI to NopeSight format
nopesight_ci = self.transform_ci(ci)

# Check if CI exists in NopeSight
existing = self.get_ci_by_external_id(ci['sys_id'])

if existing:
self.update_ci(existing['id'], nopesight_ci)
else:
self.create_ci(nopesight_ci)

def transform_ci(self, snow_ci):
"""Transform ServiceNow CI to NopeSight format"""

# Map CI class to NopeSight type
type_mapping = {
'cmdb_ci_server': 'server',
'cmdb_ci_win_server': 'server',
'cmdb_ci_linux_server': 'server',
'cmdb_ci_app_server': 'application',
'cmdb_ci_database': 'database'
}

return {
'name': snow_ci['name'],
'type': type_mapping.get(snow_ci['sys_class_name'], 'other'),
'external_id': snow_ci['sys_id'],
'external_source': 'servicenow',
'attributes': {
'serial_number': snow_ci.get('serial_number', ''),
'ip_address': snow_ci.get('ip_address', ''),
'os': snow_ci.get('os', ''),
'location': snow_ci.get('location', {}).get('display_value', ''),
'operational_status': snow_ci.get('operational_status', '')
},
'custom_fields': {
'snow_class': snow_ci['sys_class_name'],
'snow_updated': snow_ci['sys_updated_on']
}
}

Incident Integration

// ServiceNow Script Include
var NopeSightIncidentIntegration = Class.create();
NopeSightIncidentIntegration.prototype = {
initialize: function() {
this.nopesightAPI = new NopeSightAPI();
},

createIncidentFromEvent: function(eventData) {
var incident = new GlideRecord('incident');
incident.initialize();

// Map event data to incident
incident.short_description = eventData.title;
incident.description = eventData.description;
incident.impact = this.mapSeverityToImpact(eventData.severity);
incident.urgency = this.mapSeverityToUrgency(eventData.severity);
incident.category = 'Infrastructure';
incident.subcategory = 'Server';

// Link to CI if available
if (eventData.affected_cis && eventData.affected_cis.length > 0) {
var ci = this.findCIByExternalId(eventData.affected_cis[0]);
if (ci) {
incident.cmdb_ci = ci.sys_id;
}
}

// Add NopeSight reference
incident.u_nopesight_event_id = eventData.id;
incident.u_source = 'NopeSight Discovery';

// Insert incident
var incidentId = incident.insert();

// Add work notes with AI analysis
if (eventData.ai_analysis) {
incident.work_notes = '[AI Analysis]\n' + eventData.ai_analysis;
incident.update();
}

return incidentId;
},

updateIncidentStatus: function(incidentSysId, status, notes) {
var incident = new GlideRecord('incident');
if (incident.get(incidentSysId)) {

// Map status
var stateMap = {
'resolved': 6,
'closed': 7,
'in_progress': 2
};

incident.state = stateMap[status] || incident.state;

if (notes) {
incident.work_notes = notes;
}

incident.update();

// Sync back to NopeSight if needed
if (incident.u_nopesight_event_id) {
this.nopesightAPI.updateEventStatus(
incident.u_nopesight_event_id,
status
);
}
}
},

mapSeverityToImpact: function(severity) {
var impactMap = {
'critical': 1, // High
'high': 2, // Medium
'medium': 3, // Low
'low': 3 // Low
};
return impactMap[severity] || 3;
},

mapSeverityToUrgency: function(severity) {
var urgencyMap = {
'critical': 1, // High
'high': 1, // High
'medium': 2, // Medium
'low': 3 // Low
};
return urgencyMap[severity] || 3;
}
};

Webhook Configuration

ServiceNow Webhook Setup

// Register webhook in ServiceNow
var webhook = new GlideRecord('sys_webhook');
webhook.initialize();
webhook.name = 'NopeSight CI Update';
webhook.url = 'https://api.nopesight.com/v1/webhooks/servicenow';
webhook.method = 'POST';
webhook.authentication_type = 'bearer_token';
webhook.bearer_token = gs.getProperty('nopesight.webhook.token');
webhook.content_type = 'application/json';
webhook.active = true;
webhook.insert();

// Create webhook subscription
var subscription = new GlideRecord('sys_webhook_subscription');
subscription.initialize();
subscription.webhook = webhook.sys_id;
subscription.table = 'cmdb_ci';
subscription.operation = 'insert_or_update';
subscription.condition = 'u_sync_to_nopesight=true';
subscription.active = true;
subscription.insert();

NopeSight Webhook Handler

from flask import Flask, request, jsonify
import hmac
import hashlib

app = Flask(__name__)

@app.route('/webhooks/servicenow', methods=['POST'])
def handle_servicenow_webhook():
# Verify webhook signature
signature = request.headers.get('X-ServiceNow-Signature')
if not verify_signature(request.data, signature):
return jsonify({'error': 'Invalid signature'}), 401

# Parse webhook data
data = request.json

# Route based on table
if data['table'] == 'cmdb_ci':
handle_ci_update(data)
elif data['table'] == 'incident':
handle_incident_update(data)
elif data['table'] == 'change_request':
handle_change_update(data)

return jsonify({'status': 'processed'}), 200

def verify_signature(payload, signature):
"""Verify ServiceNow webhook signature"""
secret = app.config['SERVICENOW_WEBHOOK_SECRET']
expected = hmac.new(
secret.encode(),
payload,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, signature)

def handle_ci_update(data):
"""Handle CI update from ServiceNow"""
ci_data = data['record']

# Transform and update in NopeSight
ci_service = CIService()
ci_service.sync_from_servicenow(ci_data)

Field Mapping

Standard Field Mappings

ServiceNow FieldNopeSight FieldNotes
sys_idexternal_idUnique identifier
namenameDisplay name
sys_class_nametypeMapped to NopeSight types
serial_numberattributes.serial_number
ip_addressattributes.ip_address
operational_statusstatusStatus mapping required
locationattributes.locationReference field
companycustom_fields.company
departmentcustom_fields.department

Custom Field Mapping

// ServiceNow Transform Map Script
(function transformEntry(source) {
var target = new GlideRecord('cmdb_ci_server');

// Standard mappings
target.name = source.name;
target.serial_number = source.serial_number;

// Custom field mappings
target.u_nopesight_id = source.nopesight_id;
target.u_last_discovered = source.last_scan_date;
target.u_discovery_source = 'NopeSight';

// Map NopeSight attributes to ServiceNow
if (source.attributes) {
target.cpu_count = source.attributes.cpu_cores;
target.ram = source.attributes.memory_gb * 1024; // Convert GB to MB
target.disk_space = source.attributes.disk_gb;
}

// Map status
var statusMap = {
'active': '1', // Operational
'inactive': '2', // Non-Operational
'maintenance': '3', // Repair in Progress
'retired': '6' // Retired
};
target.operational_status = statusMap[source.status] || '1';

return target;
})(source);

Advanced Features

Service Mapping Integration

def sync_service_dependencies():
"""Sync service dependencies between platforms"""

# Get NopeSight service map
services = nopesight_client.get('/services')

for service in services['data']:
# Get dependencies
deps = nopesight_client.get(f'/services/{service["id"]}/dependencies')

# Create or update in ServiceNow
snow_service = find_or_create_service(service)

# Map dependencies
for upstream in deps['dependencies']['upstream']:
create_service_relationship(
parent=upstream['service_id'],
child=snow_service['sys_id'],
type='depends_on'
)

def create_service_relationship(parent, child, type):
"""Create service relationship in ServiceNow"""

relationship = {
'parent': parent,
'child': child,
'type': {'value': type},
'u_discovered_by': 'NopeSight'
}

response = snow_client.post(
'/api/now/table/cmdb_rel_ci',
json=relationship
)

return response.json()

Change Management Integration

// Link changes to NopeSight discoveries
var ChangeNopeSightIntegration = Class.create();
ChangeNopeSightIntegration.prototype = {

linkChangeToDiscovery: function(changeId, discoveryData) {
var change = new GlideRecord('change_request');
if (change.get(changeId)) {

// Add relationship insights
var insights = this.getRelationshipInsights(
change.cmdb_ci.toString()
);

// Update change with impact analysis
change.u_nopesight_impact = JSON.stringify({
affected_services: insights.affected_services,
dependency_count: insights.total_dependencies,
risk_score: insights.risk_score,
ai_recommendations: insights.recommendations
});

change.update();

// Create relationship records
this.createImpactedCIRelationships(
changeId,
insights.impacted_cis
);
}
},

getRelationshipInsights: function(ciId) {
var nopesight = new NopeSightAPI();

// Get CI relationships from NopeSight
var relationships = nopesight.getCIRelationships(ciId);

// Get AI analysis
var analysis = nopesight.getImpactAnalysis(ciId);

return {
affected_services: analysis.affected_services,
total_dependencies: relationships.length,
risk_score: analysis.risk_score,
impacted_cis: relationships.map(function(rel) {
return rel.target_ci;
}),
recommendations: analysis.recommendations
};
}
};

Monitoring and Troubleshooting

Health Check Endpoint

@app.route('/integrations/servicenow/health', methods=['GET'])
def health_check():
"""ServiceNow integration health check"""

health = {
'status': 'healthy',
'checks': {}
}

# Check ServiceNow connectivity
try:
response = requests.get(
f"{SNOW_URL}/api/now/table/sys_properties",
auth=SNOW_AUTH,
timeout=5
)
health['checks']['servicenow_api'] = {
'status': 'ok' if response.status_code == 200 else 'error',
'response_time': response.elapsed.total_seconds()
}
except Exception as e:
health['checks']['servicenow_api'] = {
'status': 'error',
'error': str(e)
}
health['status'] = 'unhealthy'

# Check sync status
last_sync = get_last_sync_time()
health['checks']['sync_status'] = {
'last_sync': last_sync,
'sync_lag': (datetime.now() - last_sync).seconds,
'pending_items': get_sync_queue_size()
}

return jsonify(health)

Common Issues

troubleshooting:
authentication_errors:
symptom: "401 Unauthorized errors"
causes:
- Expired credentials
- Incorrect OAuth configuration
- User account locked
solutions:
- Regenerate OAuth tokens
- Verify client ID/secret
- Check user account status

sync_delays:
symptom: "Data not syncing timely"
causes:
- Large backlog
- Rate limiting
- Network issues
solutions:
- Increase batch size
- Implement queue prioritization
- Check network connectivity

field_mapping_issues:
symptom: "Missing or incorrect data"
causes:
- Field name changes
- Custom field not mapped
- Data type mismatch
solutions:
- Review field mappings
- Update transform scripts
- Add data validation

Best Practices

1. Data Governance

  • Define master data source for each CI type
  • Implement conflict resolution rules
  • Regular data quality audits

2. Performance

  • Use bulk APIs for large syncs
  • Implement intelligent caching
  • Monitor API rate limits

3. Security

  • Use OAuth 2.0 over basic auth
  • Encrypt sensitive field data
  • Audit all integration activities

4. Error Handling

  • Implement retry logic with backoff
  • Queue failed syncs for replay
  • Alert on critical failures