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 - 教訓を得るための実装後レビュー

コメント