CMDB Patterns for ServiceNow
The Configuration Management Database (CMDB) is the foundation of ServiceNow ITSM, tracking all Configuration Items (CIs) and their relationships.
CMDB Architecture
CI Class Hierarchy
cmdb (Base) └── cmdb_ci (Configuration Item) ├── cmdb_ci_computer │ ├── cmdb_ci_server │ │ ├── cmdb_ci_linux_server │ │ ├── cmdb_ci_win_server │ │ └── cmdb_ci_unix_server │ └── cmdb_ci_pc_hardware ├── cmdb_ci_service │ ├── cmdb_ci_service_auto │ └── cmdb_ci_service_discovered ├── cmdb_ci_appl │ ├── cmdb_ci_app_server │ └── cmdb_ci_db_instance └── cmdb_ci_network_gear ├── cmdb_ci_netgear └── cmdb_ci_lb
Key CI Tables
Table Purpose Key Fields
cmdb_ci
Base CI table name, sys_class_name, operational_status
cmdb_ci_server
Servers ip_address, os, cpu_count, ram
cmdb_ci_service
Business Services service_classification, busines_criticality
cmdb_ci_appl
Applications version, install_directory
cmdb_rel_ci
CI Relationships parent, child, type
Creating Configuration Items
Basic CI Creation (ES5)
// Create a new server CI var ci = new GlideRecord("cmdb_ci_server") ci.initialize() ci.setValue("name", "PROD-WEB-001") ci.setValue("ip_address", "10.0.1.100") ci.setValue("os", "Linux Red Hat") ci.setValue("os_version", "8.5") ci.setValue("cpu_count", 8) ci.setValue("ram", 32768) ci.setValue("operational_status", 1) // Operational ci.setValue("install_status", 1) // Installed ci.setValue("used_for", "Production") ci.setValue("owned_by", "sys_id_of_owner") ci.setValue("support_group", "sys_id_of_group") var sysId = ci.insert()
CI with Discovery Source
// CI from Discovery var ci = new GlideRecord("cmdb_ci_linux_server") ci.initialize() ci.setValue("name", "discovered-server-001") ci.setValue("discovery_source", "ServiceNow") ci.setValue("first_discovered", new GlideDateTime()) ci.setValue("last_discovered", new GlideDateTime()) ci.setValue("ip_address", "10.0.2.50")
// Set classification ci.setValue("classification", "Production") ci.setValue("environment", "Production")
ci.insert()
CI Relationships
Relationship Types
Type Parent → Child Example
Runs on::Runs
App → Server ERP runs on PROD-DB-01
Depends on::Used by
Service → App HR Service depends on SAP
Contains::Contained by
Cluster → Server Cluster contains Node1
Hosted on::Hosts
VM → Hypervisor VM01 hosted on ESX01
Members::Member of
CI → Group Server member of Pool
Creating Relationships (ES5)
// Create relationship between CIs function createCIRelationship(parentSysId, childSysId, relationType) { // Find relationship type var relType = new GlideRecord("cmdb_rel_type") relType.addQuery("name", relationType) relType.query()
if (!relType.next()) { gs.error("Relationship type not found: " + relationType) return null }
// Check if relationship already exists var existing = new GlideRecord("cmdb_rel_ci") existing.addQuery("parent", parentSysId) existing.addQuery("child", childSysId) existing.addQuery("type", relType.getUniqueValue()) existing.query()
if (existing.next()) { gs.info("Relationship already exists") return existing.getUniqueValue() }
// Create new relationship var rel = new GlideRecord("cmdb_rel_ci") rel.initialize() rel.setValue("parent", parentSysId) rel.setValue("child", childSysId) rel.setValue("type", relType.getUniqueValue()) return rel.insert() }
// Usage createCIRelationship(appSysId, serverSysId, "Runs on::Runs")
Querying Relationships
// Find all servers an application runs on function getAppServers(appSysId) { var servers = []
var rel = new GlideRecord("cmdb_rel_ci") rel.addQuery("parent", appSysId) rel.addQuery("type.name", "Runs on::Runs") rel.query()
while (rel.next()) { var server = rel.child.getRefRecord() servers.push({ sys_id: server.getUniqueValue(), name: server.getValue("name"), ip_address: server.getValue("ip_address"), }) }
return servers }
// Find all dependencies of a service function getServiceDependencies(serviceSysId) { var deps = []
var rel = new GlideRecord("cmdb_rel_ci") rel.addQuery("parent", serviceSysId) rel.addQuery("type.name", "Depends on::Used by") rel.query()
while (rel.next()) { deps.push({ sys_id: rel.child.getUniqueValue(), name: rel.child.getDisplayValue(), class: rel.child.sys_class_name.toString(), }) }
return deps }
Impact Analysis
Upstream/Downstream Analysis
// Get all CIs affected by a CI outage (downstream impact) function getDownstreamImpact(ciSysId, depth) { if (typeof depth === "undefined") depth = 3
var impacted = [] var processed = {}
function traverse(sysId, currentDepth) { if (currentDepth > depth || processed[sysId]) return processed[sysId] = true
var rel = new GlideRecord("cmdb_rel_ci")
rel.addQuery("child", sysId)
rel.query()
while (rel.next()) {
var parentId = rel.parent.toString()
if (!processed[parentId]) {
impacted.push({
sys_id: parentId,
name: rel.parent.getDisplayValue(),
depth: currentDepth,
})
traverse(parentId, currentDepth + 1)
}
}
}
traverse(ciSysId, 1) return impacted }
// Get all CIs this CI depends on (upstream dependencies) function getUpstreamDependencies(ciSysId, depth) { if (typeof depth === "undefined") depth = 3
var dependencies = [] var processed = {}
function traverse(sysId, currentDepth) { if (currentDepth > depth || processed[sysId]) return processed[sysId] = true
var rel = new GlideRecord("cmdb_rel_ci")
rel.addQuery("parent", sysId)
rel.query()
while (rel.next()) {
var childId = rel.child.toString()
if (!processed[childId]) {
dependencies.push({
sys_id: childId,
name: rel.child.getDisplayValue(),
depth: currentDepth,
})
traverse(childId, currentDepth + 1)
}
}
}
traverse(ciSysId, 1) return dependencies }
Business Service Impact
// Find all business services impacted by a CI function getImpactedServices(ciSysId) { var services = [] var processed = {}
function findServices(sysId) { if (processed[sysId]) return processed[sysId] = true
// Check if this CI is a service
var ci = new GlideRecord("cmdb_ci")
if (ci.get(sysId)) {
if (ci.sys_class_name.toString().indexOf("cmdb_ci_service") === 0) {
services.push({
sys_id: sysId,
name: ci.getValue("name"),
criticality: ci.getValue("busines_criticality"),
})
}
}
// Traverse upstream
var rel = new GlideRecord("cmdb_rel_ci")
rel.addQuery("child", sysId)
rel.query()
while (rel.next()) {
findServices(rel.parent.toString())
}
}
findServices(ciSysId) return services }
CMDB Health & Data Quality
Orphan CI Detection
// Find CIs without relationships function findOrphanCIs(ciClass) { var orphans = []
var ci = new GlideRecord(ciClass || "cmdb_ci") ci.addQuery("operational_status", 1) // Operational only ci.query()
while (ci.next()) { var sysId = ci.getUniqueValue()
// Check for any relationships
var rel = new GlideRecord("cmdb_rel_ci")
rel.addQuery("parent", sysId).addOrCondition("child", sysId)
rel.setLimit(1)
rel.query()
if (!rel.hasNext()) {
orphans.push({
sys_id: sysId,
name: ci.getValue("name"),
class: ci.getValue("sys_class_name"),
})
}
}
return orphans }
Stale CI Detection
// Find CIs not updated by discovery function findStaleCIs(daysOld) { if (typeof daysOld === "undefined") daysOld = 30
var stale = [] var cutoff = new GlideDateTime() cutoff.addDaysLocalTime(-daysOld)
var ci = new GlideRecord("cmdb_ci") ci.addQuery("operational_status", 1) ci.addQuery("last_discovered", "<", cutoff) ci.addNotNullQuery("last_discovered") ci.query()
while (ci.next()) { stale.push({ sys_id: ci.getUniqueValue(), name: ci.getValue("name"), last_discovered: ci.getValue("last_discovered"), }) }
return stale }
MCP Tool Integration
Available CMDB Tools
Tool Purpose
snow_create_ci
Create new CI with proper class
snow_cmdb_search
Search CIs with filters
snow_create_ci_relationship
Create CI relationships
snow_impact_analysis
Analyze CI impact
snow_get_ci_details
Get full CI information
snow_run_discovery
Trigger discovery
Example Workflow
// 1. Search for existing CI await snow_cmdb_search({ ci_class: "cmdb_ci_server", query: "name=PROD-WEB-001", include_relationships: true, })
// 2. Create new CI if not found await snow_create_ci({ ci_class: "cmdb_ci_linux_server", name: "PROD-WEB-002", ip_address: "10.0.1.101", operational_status: 1, })
// 3. Create relationship await snow_create_ci_relationship({ parent: appSysId, child: serverSysId, type: "Runs on::Runs", })
// 4. Impact analysis await snow_impact_analysis({ ci_sys_id: serverSysId, direction: "downstream", depth: 3, })
Best Practices
-
Use Correct CI Class - Always use most specific class (cmdb_ci_linux_server, not cmdb_ci)
-
Maintain Relationships - CIs without relationships have limited value
-
Discovery Alignment - Align manual CIs with discovery patterns
-
Operational Status - Keep status current (Operational, Retired, etc.)
-
Unique Identifiers - Use serial_number, asset_tag for uniqueness
-
Service Mapping - Connect CIs to business services
-
Regular Cleanup - Archive retired CIs, remove orphans