Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions mcp-server/release-prepare/cmd/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package main

import (
"encoding/json"
"fmt"
"os"
"qiniu1024-mcp-server/release-prepare/internal/orchestrator"
)

func main() {
issue := orchestrator.RunReleasePreparation("user-service", "v1.1.0")

// 序列化成 JSON
out, err := json.MarshalIndent(issue, "", " ")
if err != nil {
fmt.Println("json marshal error:", err)
return
}

// 写入文件
err = os.WriteFile("issue.json", out, 0644)
if err != nil {
fmt.Println("write file error:", err)
return
}

fmt.Println("JSON 数据已写入 issue.json")
}
16 changes: 16 additions & 0 deletions mcp-server/release-prepare/internal/issue/issue.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package issue

import (
"qiniu1024-mcp-server/pkg/models"
"time"
)

func GenerateIssue(service, candidate string, steps []models.StepResult) map[string]interface{} {
return map[string]interface{}{
"title": "Release Preparation - " + service + " " + candidate,
"service": service,
"candidate": candidate,
"steps": steps,
"created_at": time.Now().Format(time.RFC3339),
}
}
37 changes: 37 additions & 0 deletions mcp-server/release-prepare/internal/metrics/metrics.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package metrics

import (
"fmt"
"qiniu1024-mcp-server/pkg/models"
)

// 指标模板
var metricTemplates = map[string][]string{
"CPU": {"%s_service_cpu_user_seconds_total", "%s_service_cpu_system_seconds_total"},
"Memory": {"%s_service_memory_used_bytes", "%s_service_memory_active_bytes"},
"Error Rate": {"%s_service_errors_total"},
}

// BuildMetricsForService 根据服务名和指标模板拼接各问题对应的Prometheus指标列表
func BuildMetricsForService(service string) []map[string]interface{} {
metrics := []map[string]interface{}{}
for name, templates := range metricTemplates {
candidates := []string{}
for _, tpl := range templates {
candidates = append(candidates, fmt.Sprintf(tpl, service))
}
metrics = append(metrics, map[string]interface{}{
"name": name,
"candidates": candidates,
})
}
return metrics
}

func GenerateMetricList(service string) models.StepResult {
details := map[string]interface{}{
"service": service,
"metrics": BuildMetricsForService(service),
}
return models.NewStepResult("MetricAnalysis", fmt.Sprintf("%d group metrics identified", len(metricTemplates)), details)
}
23 changes: 23 additions & 0 deletions mcp-server/release-prepare/internal/orchestrator/orchestrator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package orchestrator

import (
"qiniu1024-mcp-server/pkg/models"
"qiniu1024-mcp-server/release-prepare/internal/issue"
"qiniu1024-mcp-server/release-prepare/internal/metrics"
"qiniu1024-mcp-server/release-prepare/internal/planner"
"qiniu1024-mcp-server/release-prepare/internal/risk"
"qiniu1024-mcp-server/release-prepare/internal/version"
)

func RunReleasePreparation(service, candidate string) map[string]interface{} {
steps := []models.StepResult{}

// 依次记录版本冲突、待监测指标列表、灰度策略和风险预案
steps = append(steps, version.CheckVersion(service, candidate))
steps = append(steps, metrics.GenerateMetricList(service))
steps = append(steps, planner.ReleasePlan(service))
steps = append(steps, risk.PredictRisk(service))

// 根据记录结果生成发布issue
return issue.GenerateIssue(service, candidate, steps)
}
38 changes: 38 additions & 0 deletions mcp-server/release-prepare/internal/planner/planner.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package planner

import (
"qiniu1024-mcp-server/pkg/models"
)

func ReleasePlan(service string) models.StepResult {
details := map[string]interface{}{
"service": service,
"gray_strategy": map[string]interface{}{
"batches": []map[string]interface{}{
{
"batch_id": 1,
"nodes": []map[string]interface{}{
{"node_id": "bj1-node-001", "host_id": "127.0.0.1"},
},
},
{
"batch_id": 2,
"nodes": []map[string]interface{}{
{"node_id": "sh1-node-001", "host_id": "192.168.1.11"},
{"node_id": "sh2-node-001", "host_id": "192.168.2.11"},
},
},
{
"batch_id": 3,
"nodes": []map[string]interface{}{
{"node_id": "sh1-node-002", "host_id": "192.168.1.12"},
{"node_id": "sh1-node-003", "host_id": "192.168.1.13"},
{"node_id": "sh2-node-002", "host_id": "192.168.2.12"},
{"node_id": "sh2-node-003", "host_id": "192.168.2.13"},
},
},
},
},
}
return models.NewStepResult("ReleasePlan", "2 batches created", details)
}
14 changes: 14 additions & 0 deletions mcp-server/release-prepare/internal/risk/risk.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package risk

import "qiniu1024-mcp-server/pkg/models"

func PredictRisk(service string) models.StepResult {
details := map[string]interface{}{
"service": service,
"risks": []map[string]interface{}{
{"type": "memory_leak", "mitigation": "restart"},
{"type": "cpu_spike", "mitigation": "rollback"},
},
}
return models.NewStepResult("RiskPrediction", "2 risks identified", details)
}
15 changes: 15 additions & 0 deletions mcp-server/release-prepare/internal/version/version.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package version

import "qiniu1024-mcp-server/pkg/models"

func CheckVersion(service, candidate string) models.StepResult {
details := map[string]interface{}{
"service": service,
"current": "v1.0.0",
"candidate": candidate,
"has_conflict": false,
"conflict_reason": "",
}
summary := "No conflict detected"
return models.NewStepResult("VersionCheck", summary, details)
}
127 changes: 127 additions & 0 deletions mcp-server/release-prepare/issue.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
{
"candidate": "v1.1.0",
"created_at": "2025-08-25T16:17:24+08:00",
"service": "user-service",
"steps": [
{
"step_name": "VersionCheck",
"status": "success",
"summary": "No conflict detected",
"details": {
"candidate": "v1.1.0",
"conflict_reason": "",
"current": "v1.0.0",
"has_conflict": false,
"service": "user-service"
},
"timestamp": "2025-08-25T16:17:24+08:00"
},
{
"step_name": "MetricAnalysis",
"status": "success",
"summary": "3 group metrics identified",
"details": {
"metrics": [
{
"candidates": [
"user-service_service_cpu_user_seconds_total",
"user-service_service_cpu_system_seconds_total"
],
"name": "CPU"
},
{
"candidates": [
"user-service_service_memory_used_bytes",
"user-service_service_memory_active_bytes"
],
"name": "Memory"
},
{
"candidates": [
"user-service_service_errors_total"
],
"name": "Error Rate"
}
],
"service": "user-service"
},
"timestamp": "2025-08-25T16:17:24+08:00"
},
{
"step_name": "ReleasePlan",
"status": "success",
"summary": "2 batches created",
"details": {
"gray_strategy": {
"batches": [
{
"batch_id": 1,
"nodes": [
{
"host_id": "127.0.0.1",
"node_id": "bj1-node-001"
}
]
},
{
"batch_id": 2,
"nodes": [
{
"host_id": "192.168.1.11",
"node_id": "sh1-node-001"
},
{
"host_id": "192.168.2.11",
"node_id": "sh2-node-001"
}
]
},
{
"batch_id": 3,
"nodes": [
{
"host_id": "192.168.1.12",
"node_id": "sh1-node-002"
},
{
"host_id": "192.168.1.13",
"node_id": "sh1-node-003"
},
{
"host_id": "192.168.2.12",
"node_id": "sh2-node-002"
},
{
"host_id": "192.168.2.13",
"node_id": "sh2-node-003"
}
]
}
]
},
"service": "user-service"
},
"timestamp": "2025-08-25T16:17:24+08:00"
},
{
"step_name": "RiskPrediction",
"status": "success",
"summary": "2 risks identified",
"details": {
"risks": [
{
"mitigation": "restart",
"type": "memory_leak"
},
{
"mitigation": "rollback",
"type": "cpu_spike"
}
],
"service": "user-service"
},
"timestamp": "2025-08-25T16:17:24+08:00"
}
],
"title": "Release Preparation - user-service v1.1.0"
}