discovery-patterns
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseDiscovery Patterns for ServiceNow
ServiceNow Discovery 模式
Discovery automatically populates the CMDB by scanning networks and systems.
Discovery通过扫描网络和系统自动填充CMDB。
Discovery Architecture
Discovery 架构
Discovery Schedule
↓
MID Server
↓
Probes (collect data)
↓
Sensors (process data)
↓
Identification Rules (match/create CIs)
↓
CMDB PopulationDiscovery 调度任务
↓
MID Server
↓
探针(收集数据)
↓
传感器(处理数据)
↓
识别规则(匹配/创建CI)
↓
填充CMDBKey Tables
核心表
| Table | Purpose |
|---|---|
| Discovery schedules |
| Discovery credentials |
| IP ranges to scan |
| CI identification |
| MID Server records |
| Discovery run status |
| 表名 | 用途 |
|---|---|
| Discovery调度任务 |
| Discovery凭证 |
| 待扫描IP范围 |
| CI识别规则 |
| MID Server记录 |
| Discovery运行状态 |
Discovery Schedules (ES5)
Discovery 调度任务(ES5)
Create Discovery Schedule
创建Discovery调度任务
javascript
// Create discovery schedule (ES5 ONLY!)
var schedule = new GlideRecord('discovery_schedule');
schedule.initialize();
// Basic info
schedule.setValue('name', 'Data Center Discovery');
schedule.setValue('description', 'Weekly discovery of data center infrastructure');
// Type
schedule.setValue('discover', 'IP'); // IP, CI, Cloud Resources
// Schedule
schedule.setValue('run_type', 'weekly');
schedule.setValue('run_dayofweek', 'sunday');
schedule.setValue('run_time', '02:00:00');
// MID Server
schedule.setValue('mid_server', getMIDServerSysId('DataCenterMID'));
// Enable
schedule.setValue('active', true);
var scheduleSysId = schedule.insert();
// Add IP range
addDiscoveryRange(scheduleSysId, '10.0.0.0', '10.0.255.255', 'Data Center Network');javascript
// 创建Discovery调度任务(仅支持ES5!)
var schedule = new GlideRecord('discovery_schedule');
schedule.initialize();
// 基本信息
schedule.setValue('name', '数据中心Discovery');
schedule.setValue('description', '每周扫描数据中心基础设施');
// 类型
schedule.setValue('discover', 'IP'); // IP、CI、云资源
// 调度设置
schedule.setValue('run_type', 'weekly');
schedule.setValue('run_dayofweek', 'sunday');
schedule.setValue('run_time', '02:00:00');
// MID Server
schedule.setValue('mid_server', getMIDServerSysId('DataCenterMID'));
// 启用
schedule.setValue('active', true);
var scheduleSysId = schedule.insert();
// 添加IP范围
addDiscoveryRange(scheduleSysId, '10.0.0.0', '10.0.255.255', '数据中心网络');Add Discovery Range
添加扫描范围
javascript
// Add IP range to discovery schedule (ES5 ONLY!)
function addDiscoveryRange(scheduleSysId, startIP, endIP, name) {
var range = new GlideRecord('discovery_range');
range.initialize();
range.setValue('schedule', scheduleSysId);
range.setValue('name', name);
range.setValue('type', 'range');
range.setValue('range_start', startIP);
range.setValue('range_end', endIP);
range.setValue('active', true);
return range.insert();
}
// Add CIDR range
function addDiscoveryCIDR(scheduleSysId, cidr, name) {
var range = new GlideRecord('discovery_range');
range.initialize();
range.setValue('schedule', scheduleSysId);
range.setValue('name', name);
range.setValue('type', 'cidr');
range.setValue('range', cidr); // e.g., '10.0.0.0/24'
range.setValue('active', true);
return range.insert();
}javascript
// 为Discovery调度任务添加IP范围(仅支持ES5!)
function addDiscoveryRange(scheduleSysId, startIP, endIP, name) {
var range = new GlideRecord('discovery_range');
range.initialize();
range.setValue('schedule', scheduleSysId);
range.setValue('name', name);
range.setValue('type', 'range');
range.setValue('range_start', startIP);
range.setValue('range_end', endIP);
range.setValue('active', true);
return range.insert();
}
// 添加CIDR范围
function addDiscoveryCIDR(scheduleSysId, cidr, name) {
var range = new GlideRecord('discovery_range');
range.initialize();
range.setValue('schedule', scheduleSysId);
range.setValue('name', name);
range.setValue('type', 'cidr');
range.setValue('range', cidr); // 例如:'10.0.0.0/24'
range.setValue('active', true);
return range.insert();
}Discovery Credentials (ES5)
Discovery 凭证(ES5)
Create Credentials
创建凭证
javascript
// Create Windows credential (ES5 ONLY!)
var cred = new GlideRecord('discovery_credentials');
cred.initialize();
cred.setValue('name', 'Windows Domain Admin');
cred.setValue('type', 'windows');
cred.setValue('user_name', 'domain\\admin');
cred.setValue('password', ''); // Set via secure method
cred.setValue('active', true);
// Credential order
cred.setValue('order', 100);
// Assign to credential affinity
cred.setValue('credential_alias', credentialAliasSysId);
cred.insert();javascript
// 创建Windows凭证(仅支持ES5!)
var cred = new GlideRecord('discovery_credentials');
cred.initialize();
cred.setValue('name', 'Windows域管理员');
cred.setValue('type', 'windows');
cred.setValue('user_name', 'domain\\admin');
cred.setValue('password', ''); // 通过安全方式设置
cred.setValue('active', true);
// 凭证优先级
cred.setValue('order', 100);
// 关联凭证亲和性
cred.setValue('credential_alias', credentialAliasSysId);
cred.insert();Credential Affinity
凭证亲和性
javascript
// Create credential affinity (map credentials to IP ranges) (ES5 ONLY!)
var affinity = new GlideRecord('dscy_credentials_affinity');
affinity.initialize();
affinity.setValue('credential', credentialSysId);
affinity.setValue('range', discoveryRangeSysId);
affinity.setValue('order', 100);
affinity.insert();javascript
// 创建凭证亲和性(将凭证映射到IP范围)(仅支持ES5!)
var affinity = new GlideRecord('dscy_credentials_affinity');
affinity.initialize();
affinity.setValue('credential', credentialSysId);
affinity.setValue('range', discoveryRangeSysId);
affinity.setValue('order', 100);
affinity.insert();Custom Probes and Sensors (ES5)
自定义探针与传感器(ES5)
Custom Probe
自定义探针
javascript
// Create custom probe script (ES5 ONLY!)
// Probes run on MID Server to collect data
// Table: discovery_probes_script
var probe = new GlideRecord('discovery_probes_script');
probe.initialize();
probe.setValue('name', 'Custom Application Version');
probe.setValue('active', true);
// Probe script (runs on MID Server - ES5 ONLY!)
probe.setValue('script',
'var output = {};\n' +
'\n' +
'// Command to run\n' +
'var cmd = "cat /opt/myapp/version.txt";\n' +
'\n' +
'try {\n' +
' var result = Packages.com.service_now.mid.probe.tpcon.OperatingSystemCommand.execute(cmd);\n' +
' output.app_version = result.getOutput().trim();\n' +
' output.success = true;\n' +
'} catch (e) {\n' +
' output.success = false;\n' +
' output.error = e.message;\n' +
'}\n' +
'\n' +
'output;'
);
probe.insert();javascript
// 创建自定义探针脚本(仅支持ES5!)
// 探针在MID Server上运行以收集数据
// 表:discovery_probes_script
var probe = new GlideRecord('discovery_probes_script');
probe.initialize();
probe.setValue('name', '自定义应用版本探针');
probe.setValue('active', true);
// 探针脚本(在MID Server上运行 - 仅支持ES5!)
probe.setValue('script',
'var output = {};\n' +
'\n' +
'// 要执行的命令\n' +
'var cmd = "cat /opt/myapp/version.txt";\n' +
'\n' +
'try {\n' +
' var result = Packages.com.service_now.mid.probe.tpcon.OperatingSystemCommand.execute(cmd);\n' +
' output.app_version = result.getOutput().trim();\n' +
' output.success = true;\n' +
'} catch (e) {\n' +
' output.success = false;\n' +
' output.error = e.message;\n' +
'}\n' +
'\n' +
'output;'
);
probe.insert();Custom Sensor
自定义传感器
javascript
// Create custom sensor (ES5 ONLY!)
// Sensors run on ServiceNow instance to process probe results
// Table: discovery_sensors_script
var sensor = new GlideRecord('discovery_sensors_script');
sensor.initialize();
sensor.setValue('name', 'Process Custom Application Version');
sensor.setValue('active', true);
sensor.setValue('probe', probeSysId);
// Sensor script (runs on instance - ES5 ONLY!)
sensor.setValue('script',
'(function process(result, source) {\n' +
' var output = JSON.parse(result.output);\n' +
' \n' +
' if (!output.success) {\n' +
' gs.warn("Custom app discovery failed: " + output.error);\n' +
' return;\n' +
' }\n' +
' \n' +
' // Find or create CI\n' +
' var ci = source.getDeviceRecord();\n' +
' if (ci) {\n' +
' ci.u_custom_app_version = output.app_version;\n' +
' ci.update();\n' +
' gs.info("Updated CI with app version: " + output.app_version);\n' +
' }\n' +
'})(result, source);'
);
sensor.insert();javascript
// 创建自定义传感器(仅支持ES5!)
// 传感器在ServiceNow实例上运行以处理探针结果
// 表:discovery_sensors_script
var sensor = new GlideRecord('discovery_sensors_script');
sensor.initialize();
sensor.setValue('name', '处理自定义应用版本');
sensor.setValue('active', true);
sensor.setValue('probe', probeSysId);
// 传感器脚本(在实例上运行 - 仅支持ES5!)
sensor.setValue('script',
'(function process(result, source) {\n' +
' var output = JSON.parse(result.output);\n' +
' \n' +
' if (!output.success) {\n' +
' gs.warn("自定义应用发现失败: " + output.error);\n' +
' return;\n' +
' }\n' +
' \n' +
' // 查找或创建CI\n' +
' var ci = source.getDeviceRecord();\n' +
' if (ci) {\n' +
' ci.u_custom_app_version = output.app_version;\n' +
' ci.update();\n' +
' gs.info("已更新CI应用版本: " + output.app_version);\n' +
' }\n' +
'})(result, source);'
);
sensor.insert();Identification Rules (ES5)
识别规则(ES5)
CI Identification Rule
CI识别规则
javascript
// Create identification rule (ES5 ONLY!)
var rule = new GlideRecord('cmdb_identifier');
rule.initialize();
rule.setValue('name', 'Server Identification');
rule.setValue('table', 'cmdb_ci_server');
rule.setValue('active', true);
// Priority (lower = higher priority)
rule.setValue('order', 100);
// Identification entries (criteria)
rule.insert();
// Add identification criteria
var entry = new GlideRecord('cmdb_identifier_entry');
entry.initialize();
entry.setValue('identifier', rule.getUniqueValue());
entry.setValue('criterion_attributes', 'serial_number'); // Match by serial
entry.setValue('search_type', 'equals');
entry.setValue('active', true);
entry.insert();javascript
// 创建识别规则(仅支持ES5!)
var rule = new GlideRecord('cmdb_identifier');
rule.initialize();
rule.setValue('name', '服务器识别规则');
rule.setValue('table', 'cmdb_ci_server');
rule.setValue('active', true);
// 优先级(数值越小优先级越高)
rule.setValue('order', 100);
// 识别条目(匹配条件)
rule.insert();
// 添加识别条件
var entry = new GlideRecord('cmdb_identifier_entry');
entry.initialize();
entry.setValue('identifier', rule.getUniqueValue());
entry.setValue('criterion_attributes', 'serial_number'); // 通过序列号匹配
entry.setValue('search_type', 'equals');
entry.setValue('active', true);
entry.insert();Custom Identification Script
自定义识别脚本
javascript
// Identification script for complex matching (ES5 ONLY!)
// Table: cmdb_identifier_script
var script = new GlideRecord('cmdb_identifier_script');
script.initialize();
script.setValue('name', 'Custom Server Match');
script.setValue('table', 'cmdb_ci_server');
script.setValue('active', true);
script.setValue('script',
'(function identify(source) {\n' +
' var serial = source.getValue("serial_number");\n' +
' var hostname = source.getValue("name");\n' +
' \n' +
' // Try serial match first\n' +
' var gr = new GlideRecord("cmdb_ci_server");\n' +
' if (serial) {\n' +
' gr.addQuery("serial_number", serial);\n' +
' gr.query();\n' +
' if (gr.next()) {\n' +
' return gr.getUniqueValue();\n' +
' }\n' +
' }\n' +
' \n' +
' // Try hostname + IP match\n' +
' gr = new GlideRecord("cmdb_ci_server");\n' +
' gr.addQuery("name", hostname);\n' +
' gr.addQuery("ip_address", source.getValue("ip_address"));\n' +
' gr.query();\n' +
' if (gr.next()) {\n' +
' return gr.getUniqueValue();\n' +
' }\n' +
' \n' +
' // No match - return null to create new CI\n' +
' return null;\n' +
'})(source);'
);
script.insert();javascript
// 用于复杂匹配的识别脚本(仅支持ES5!)
// 表:cmdb_identifier_script
var script = new GlideRecord('cmdb_identifier_script');
script.initialize();
script.setValue('name', '自定义服务器匹配');
script.setValue('table', 'cmdb_ci_server');
script.setValue('active', true);
script.setValue('script',
'(function identify(source) {\n' +
' var serial = source.getValue("serial_number");\n' +
' var hostname = source.getValue("name");\n' +
' \n' +
' // 优先尝试序列号匹配\n' +
' var gr = new GlideRecord("cmdb_ci_server");\n' +
' if (serial) {\n' +
' gr.addQuery("serial_number", serial);\n' +
' gr.query();\n' +
' if (gr.next()) {\n' +
' return gr.getUniqueValue();\n' +
' }\n' +
' }\n' +
' \n' +
' // 尝试主机名+IP匹配\n' +
' gr = new GlideRecord("cmdb_ci_server");\n' +
' gr.addQuery("name", hostname);\n' +
' gr.addQuery("ip_address", source.getValue("ip_address"));\n' +
' gr.query();\n' +
' if (gr.next()) {\n' +
' return gr.getUniqueValue();\n' +
' }\n' +
' \n' +
' // 无匹配项 - 返回null以创建新CI\n' +
' return null;\n' +
'})(source);'
);
script.insert();Discovery Status (ES5)
Discovery 状态(ES5)
Monitor Discovery Status
监控Discovery运行状态
javascript
// Check discovery run status (ES5 ONLY!)
function getDiscoveryStatus(scheduleSysId) {
var status = new GlideRecord('discovery_status');
status.addQuery('dscheduler', scheduleSysId);
status.orderByDesc('sys_created_on');
status.setLimit(1);
status.query();
if (status.next()) {
return {
state: status.state.getDisplayValue(),
started: status.getValue('started'),
completed: status.getValue('completed'),
devices_found: status.getValue('devices_found'),
devices_completed: status.getValue('devices_completed'),
errors: status.getValue('error_count')
};
}
return null;
}javascript
// 检查Discovery运行状态(仅支持ES5!)
function getDiscoveryStatus(scheduleSysId) {
var status = new GlideRecord('discovery_status');
status.addQuery('dscheduler', scheduleSysId);
status.orderByDesc('sys_created_on');
status.setLimit(1);
status.query();
if (status.next()) {
return {
state: status.state.getDisplayValue(),
started: status.getValue('started'),
completed: status.getValue('completed'),
devices_found: status.getValue('devices_found'),
devices_completed: status.getValue('devices_completed'),
errors: status.getValue('error_count')
};
}
return null;
}Discovery Device Results
Discovery 设备扫描结果
javascript
// Get discovered devices from a run (ES5 ONLY!)
function getDiscoveredDevices(statusSysId) {
var devices = [];
var device = new GlideRecord('discovery_device_history');
device.addQuery('status', statusSysId);
device.query();
while (device.next()) {
devices.push({
ip_address: device.getValue('source'),
ci: device.cmdb_ci.getDisplayValue(),
ci_class: device.getValue('ci_type'),
state: device.state.getDisplayValue(),
issues: device.getValue('issue_count')
});
}
return devices;
}javascript
// 获取某次扫描的设备结果(仅支持ES5!)
function getDiscoveredDevices(statusSysId) {
var devices = [];
var device = new GlideRecord('discovery_device_history');
device.addQuery('status', statusSysId);
device.query();
while (device.next()) {
devices.push({
ip_address: device.getValue('source'),
ci: device.cmdb_ci.getDisplayValue(),
ci_class: device.getValue('ci_type'),
state: device.state.getDisplayValue(),
issues: device.getValue('issue_count')
});
}
return devices;
}MCP Tool Integration
MCP 工具集成
Available Tools
可用工具
| Tool | Purpose |
|---|---|
| Query discovery tables |
| Find discovery configs |
| Test discovery scripts |
| Search discovered CIs |
| 工具 | 用途 |
|---|---|
| 查询Discovery相关表 |
| 查找Discovery配置项 |
| 测试Discovery脚本 |
| 搜索已发现的CI |
Example Workflow
示例工作流
javascript
// 1. Query active schedules
await snow_query_table({
table: 'discovery_schedule',
query: 'active=true',
fields: 'name,discover,run_type,mid_server'
});
// 2. Check recent discovery status
await snow_execute_script_with_output({
script: `
var status = getDiscoveryStatus('schedule_sys_id');
gs.info(JSON.stringify(status));
`
});
// 3. Find discovery errors
await snow_query_table({
table: 'discovery_log',
query: 'level=error^sys_created_on>=javascript:gs.daysAgo(1)',
fields: 'message,source,sys_created_on'
});javascript
// 1. 查询活跃的调度任务
await snow_query_table({
table: 'discovery_schedule',
query: 'active=true',
fields: 'name,discover,run_type,mid_server'
});
// 2. 检查最近的Discovery运行状态
await snow_execute_script_with_output({
script: `
var status = getDiscoveryStatus('schedule_sys_id');
gs.info(JSON.stringify(status));
`
});
// 3. 查找Discovery错误日志
await snow_query_table({
table: 'discovery_log',
query: 'level=error^sys_created_on>=javascript:gs.daysAgo(1)',
fields: 'message,source,sys_created_on'
});Best Practices
最佳实践
- Credential Security - Use credential vault
- Schedule Off-Peak - Minimize network impact
- Range Management - Organize by network segment
- MID Server - Proper placement and sizing
- Identification - Clear matching criteria
- Reconciliation - Regular CMDB validation
- Monitoring - Track discovery health
- ES5 Only - No modern JavaScript syntax
- 凭证安全 - 使用凭证保险箱
- 非高峰时段调度 - 降低对网络的影响
- 扫描范围管理 - 按网络网段划分
- MID Server - 合理部署与规划规模
- 识别规则 - 明确匹配条件
- 数据对账 - 定期验证CMDB
- 监控 - 跟踪Discovery运行状态
- 仅支持ES5 - 不使用现代JavaScript语法