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