mcpField
C
change-management

change-management

github.com/serac-labs云与 DevOps7767 次安装9 周前更新
代码仓库

关于 change-management

面向 ServiceNow 变更管理的技能,涵盖变更请求、审批、任务和状态流转,并提供相应的 MCP 工具流程参考。适合需要规范基础设施变更操作的团队。

主要功能

  1. 01区分标准、普通和紧急变更
  2. 02创建变更请求与任务
  3. 03关联受影响的 CI
  4. 04检查审批与排期冲突
  5. 05管理变更状态流转

适用场景

  1. 01创建服务器补丁变更计划
  2. 02为变更添加实施任务与 CI
  3. 03跟踪审批并推进变更状态

MCP 相关

文档列出用于创建、查询、更新变更及安排 CAB 的 MCP 工具,并示范变更工作流。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/serac-labs/serac --skill change-management

安装后在 Claude Code 中输入/change-management确认已加载。

详细介绍

ServiceNow 的变更管理

变更管理通过标准化流程和审批,确保对 IT 基础设施进行受控修改。

变更类型

类型审批风险示例
标准预先批准低密码重置模板
普通CAB 审批中等服务器修补
紧急实施后审批高生产中断修复

变更请求结构

Change Request: CHG0010001
├── Risk Assessment
│   ├── Impact: Medium
│   ├── Risk: Low
│   └── Conflict Status: Clear
├── Schedule
│   ├── Planned Start: 2024-03-15 22:00
│   └── Planned End: 2024-03-15 23:00
├── Approvals
│   ├── Manager Approval: Approved
│   └── CAB Approval: Pending
├── Change Tasks
│   ├── Task 1: Backup current config
│   ├── Task 2: Apply patches
│   └── Task 3: Verify functionality
└── Affected CIs
    ├── PROD-WEB-001
    └── PROD-DB-001

创建变更

普通变更(ES5)
// Create normal change request
var change = new GlideRecord("change_request")
change.initialize()

// Basic info
change.setValue("short_description", "Apply security patches to web servers")
change.setValue("description", "Monthly security patch deployment for production web tier")
change.setValue("type", "normal") // normal, standard, emergency

// Classification
change.setValue("category", "Software")
change.setValue("priority", 3)

// Risk assessment
change.setValue("risk", "low") // high, moderate, low
change.setValue("impact", 2) // 1-High, 2-Medium, 3-Low

// Schedule
var startDate = new GlideDateTime()
startDate.addDaysLocalTime(7)
startDate.setValue("2024-03-15 22:00:00")
change.setValue("start_date", startDate)

var endDate = new GlideDateTime(startDate)
endDate.addSeconds(3600) // 1 hour
change.setValue("end_date", endDate)

// Assignment
change.setValue("assignment_group", getGroupSysId("Change Management"))
change.setValue("assigned_to", getOnCallUser())

// Implementation plan
change.setValue(
  "implementation_plan",
  "1. Take backup of current configuration\\n" +
    "2. Stop web services\\n" +
    "3. Apply security patches\\n" +
    "4. Restart services\\n" +
    "5. Verify functionality",
)

change.setValue(
  "backout_plan",
  "1. Stop web services\\n" + "2. Restore from backup\\n" + "3. Restart services\\n" + "4. Verify rollback successful",
)

change.setValue(
  "test_plan",
  "1. Check web server response\\n" + "2. Verify all pages load\\n" + "3. Run automated health checks",
)

var changeSysId = change.insert()
紧急变更(ES5)
// Create emergency change
var emergencyChange = new GlideRecord("change_request")
emergencyChange.initialize()

emergencyChange.setValue("short_description", "Emergency: Fix production database connection leak")
emergencyChange.setValue("type", "emergency")
emergencyChange.setValue("priority", 1)
emergencyChange.setValue("risk", "high")
emergencyChange.setValue("impact", 1)

// Emergency justification
emergencyChange.setValue(
  "justification",
  "Production database connections exhausted causing service outage. " + "Immediate fix required to restore service.",
)

// Immediate start
emergencyChange.setValue("start_date", new GlideDateTime())

var endDate = new GlideDateTime()
endDate.addSeconds(7200) // 2 hours
emergencyChange.setValue("end_date", endDate)

emergencyChange.insert()

// Emergency changes bypass normal CAB
gs.eventQueue("change.emergency.created", emergencyChange)
标准变更(ES5)
// Create from standard change template
function createStandardChange(templateName, variables) {
  // Find template
  var template = new GlideRecord("std_change_producer")
  template.addQuery("name", templateName)
  template.query()

  if (!template.next()) {
    gs.error("Standard change template not found: " + templateName)
    return null
  }

  // Create change from template
  var change = new GlideRecord("change_request")
  change.initialize()

  // Copy template values
  change.setValue("short_description", template.getValue("short_description"))
  change.setValue("description", template.getValue("description"))
  change.setValue("type", "standard")
  change.setValue("std_change_producer", template.getUniqueValue())

  // Apply variables
  for (var key in variables) {
    if (variables.hasOwnProperty(key) && change.isValidField(key)) {
      change.setValue(key, variables[key])
    }
  }

  return change.insert()
}

// Usage
createStandardChange("Password Reset", {
  requested_by: userSysId,
  cmdb_ci: applicationSysId,
})

变更任务

创建变更任务(ES5)
// Add tasks to change
function addChangeTask(changeSysId, taskConfig) {
  var task = new GlideRecord("change_task")
  task.initialize()
  task.setValue("change_request", changeSysId)
  task.setValue("short_description", taskConfig.description)
  task.setValue("order", taskConfig.order)
  task.setValue("assignment_group", taskConfig.group)
  task.setValue("planned_start_date", taskConfig.start)
  task.setValue("planned_end_date", taskConfig.end)
  return task.insert()
}

// Create implementation tasks
var tasks = [
  { description: "Pre-implementation backup", order: 100, group: "Database Team" },
  { description: "Apply patches", order: 200, group: "Server Team" },
  { description: "Verify functionality", order: 300, group: "QA Team" },
  { description: "Update documentation", order: 400, group: "Change Management" },
]

for (var i = 0; i < tasks.length; i++) {
  addChangeTask(changeSysId, tasks[i])
}

受影响的 CI

将 CI 关联到变更(ES5)
// Add affected CIs
function addAffectedCI(changeSysId, ciSysId) {
  var task = new GlideRecord("task_ci")
  task.initialize()
  task.setValue("task", changeSysId)
  task.setValue("ci_item", ciSysId)
  return task.insert()
}

// Add all affected servers
var servers = ["server1_sys_id", "server2_sys_id", "db_sys_id"]
for (var i = 0; i < servers.length; i++) {
  addAffectedCI(changeSysId, servers[i])
}

审批

检查审批状态(ES5)
// Get approval status
function getApprovalStatus(changeSysId) {
  var approvals = []

  var approval = new GlideRecord("sysapproval_approver")
  approval.addQuery("sysapproval", changeSysId)
  approval.query()

  while (approval.next()) {
    approvals.push({
      approver: approval.approver.getDisplayValue(),
      state: approval.state.getDisplayValue(),
      comments: approval.getValue("comments"),
      sys_updated_on: approval.getValue("sys_updated_on"),
    })
  }

  return approvals
}
请求审批(ES5)
// Add approval request
function requestApproval(changeSysId, approverSysId) {
  var approval = new GlideRecord("sysapproval_approver")
  approval.initialize()
  approval.setValue("sysapproval", changeSysId)
  approval.setValue("approver", approverSysId)
  approval.setValue("state", "requested")
  return approval.insert()
}

变更冲突检测

检查冲突(ES5)
// Check for scheduling conflicts
function checkChangeConflicts(changeSysId) {
  var change = new GlideRecord("change_request")
  if (!change.get(changeSysId)) return []

  var conflicts = []
  var startDate = change.getValue("start_date")
  var endDate = change.getValue("end_date")

  // Find overlapping changes on same CIs
  var affected = new GlideAggregate("task_ci")
  affected.addQuery("task", changeSysId)
  affected.groupBy("ci_item")
  affected.query()

  while (affected.next()) {
    var ciSysId = affected.ci_item.toString()

    // Find other changes affecting this CI
    var otherChanges = new GlideRecord("change_request")
    otherChanges.addQuery("sys_id", "!=", changeSysId)
    otherChanges.addQuery("state", "NOT IN", "closed,cancelled")
    otherChanges.addQuery("start_date", "<=", endDate)
    otherChanges.addQuery("end_date", ">=", startDate)

    // Join to task_ci
    otherChanges.addJoinQuery("task_ci", "sys_id", "task").addCondition("ci_item", ciSysId)

    otherChanges.query()

    while (otherChanges.next()) {
      conflicts.push({
        change: otherChanges.getValue("number"),
        ci: ciSysId,
        start: otherChanges.getValue("start_date"),
        end: otherChanges.getValue("end_date"),
      })
    }
  }

  return conflicts
}

状态转换

变更状态
状态后续状态条件
新建评估已提交
评估授权、已取消评估完成
授权已安排、已取消审批完成
已安排实施、已取消在维护窗口内
实施审查、已取消任务已完成
审查已关闭PIR 已完成
已关闭-最终状态
转换变更(ES5)
// Move change to next state
function transitionChange(changeSysId, newState, notes) {
  var change = new GlideRecord("change_request")
  if (!change.get(changeSysId)) {
    gs.error("Change not found: " + changeSysId)
    return false
  }

  // Validate transition
  var currentState = change.getValue("state")
  var validTransitions = {
    "-5": ["-4", "4"], // New -> Assess or Cancelled
    "-4": ["-3", "4"], // Assess -> Authorize or Cancelled
    "-3": ["-2", "4"], // Authorize -> Scheduled or Cancelled
    "-2": ["-1", "4"], // Scheduled -> Implement or Cancelled
    "-1": ["0", "4"], // Implement -> Review or Cancelled
    0: ["3"], // Review -> Closed
  }

  if (!validTransitions[currentState] || validTransitions[currentState].indexOf(newState) === -1) {
    gs.error("Invalid state transition: " + currentState + " -> " + newState)
    return false
  }

  change.setValue("state", newState)
  if (notes) {
    change.work_notes = notes
  }
  change.update()

  return true
}

MCP 工具集成

可用的变更工具
工具用途
snow_change_manage (action='create')创建变更
snow_change_manage (action='create_task')添加任务
snow_change_query (action='get')获取详情
snow_change_manage (action='update_state')转换状态
snow_change_query (action='search')查找变更
snow_change_manage (action='schedule_cab')安排 CAB
示例工作流
// 1. Create change (scheduling happens later via action: "update_state" -> "scheduled")
var changeId = await snow_change_manage({
  action: "create",
  short_description: "Database upgrade",
  type: "normal",
  risk: "medium",
})

// 2. Add tasks
await snow_change_manage({
  action: "create_task",
  sys_id: changeId,
  short_description: "Backup database",
})

// 3. Check conflicts: search for overlapping open changes in the same window
// (see checkChangeConflicts above for per-CI conflict detection)
var conflicts = await snow_change_query({
  action: "search",
  query: "stateNOT INclosed,cancelled^start_date<=2024-03-21 02:00:00^end_date>=2024-03-20 22:00:00",
})

// 4. Submit for approval
await snow_change_manage({
  action: "update_state",
  sys_id: changeId,
  state: "assess",
})

最佳实践

  1. 完整文档 - 实施、回退和测试计划
  2. 风险评估 - 准确评估风险和影响
  3. CI 关联 - 附加所有受影响的 CI
  4. 合理安排时间 - 在维护窗口内进行
  5. 任务拆分 - 明确实施步骤
  6. 审批流程 - 完成所有必需的审批
  7. 冲突检查 - 确认不存在重叠的变更
  8. PIR - 实施后审查,总结经验教训

评论

支持 Markdown