Skip to content

Commit 76d1c82

Browse files
committed
commit
1 parent 89fc568 commit 76d1c82

4 files changed

Lines changed: 104 additions & 0 deletions

File tree

platform-backend/cmd/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,7 @@ func main() {
414414
deployments.POST("/ha", middleware.RequirePermission("admin"), clusterDeployController.DeployHA)
415415
deployments.GET("", clusterDeployController.List)
416416
deployments.GET("/:id", clusterDeployController.GetDeploymentStatus)
417+
deployments.GET("/:id/plan", clusterDeployController.GetDeployPlan)
417418
deployments.DELETE("/:id", middleware.RequirePermission("admin"), clusterDeployController.Destroy)
418419
}
419420

platform-backend/internal/controllers/cluster_deploy_controller.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,18 @@ func (c *ClusterDeployController) DeployHA(ctx *gin.Context) {
118118
utils.SuccessResponse(ctx, response)
119119
}
120120

121+
func (c *ClusterDeployController) GetDeployPlan(ctx *gin.Context) {
122+
deploymentID := ctx.Param("id")
123+
124+
response, err := c.service.GetDeployPlan(ctx.Request.Context(), deploymentID)
125+
if err != nil {
126+
utils.NotFoundResponse(ctx, "Plan not found")
127+
return
128+
}
129+
130+
utils.SuccessResponse(ctx, response)
131+
}
132+
121133
func (c *ClusterDeployController) GetDeploymentStatus(ctx *gin.Context) {
122134
deploymentID := ctx.Param("id")
123135

platform-backend/internal/services/cluster_deploy_service.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1205,6 +1205,21 @@ func (s *ClusterDeployService) deployHAReplicaViaMasterAgent(ctx context.Context
12051205
})
12061206
}
12071207

1208+
func (s *ClusterDeployService) GetDeployPlan(ctx context.Context, deploymentID string) (*ClusterDeployPlan, error) {
1209+
dep, err := s.repo.GetByID(ctx, deploymentID)
1210+
if err != nil {
1211+
return nil, err
1212+
}
1213+
if dep.PlanJSON == "" {
1214+
return nil, fmt.Errorf("no plan found for deployment %s", deploymentID)
1215+
}
1216+
var plan ClusterDeployPlan
1217+
if err := json.Unmarshal([]byte(dep.PlanJSON), &plan); err != nil {
1218+
return nil, fmt.Errorf("failed to parse plan for deployment %s: %w", deploymentID, err)
1219+
}
1220+
return &plan, nil
1221+
}
1222+
12081223
func (s *ClusterDeployService) GetDeploymentStatus(ctx context.Context, deploymentID string) (*DeployResponse, error) {
12091224
dep, err := s.repo.GetByID(ctx, deploymentID)
12101225
if err != nil {

platform-backend/internal/services/universal_cluster_deploy_test.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package services
22

33
import (
44
"context"
5+
"encoding/json"
56
"testing"
67

78
"github.com/monkeycode/mysql-ops-platform/internal/models"
@@ -311,6 +312,81 @@ func TestExecuteClusterDeployPlan_RejectsRealMode(t *testing.T) {
311312
require.Contains(t, err.Error(), "only supports pseudo")
312313
}
313314

315+
func TestGetDeployPlan_ReturnsDeserializedPlan(t *testing.T) {
316+
ctx := context.Background()
317+
db := newTestDB()
318+
clusterRepo := repositories.NewClusterDeployRepository(db)
319+
service := NewClusterDeployService(clusterRepo, nil, nil, nil, nil, config.ClusterDefaults{})
320+
321+
// Create a deployment with plan_json populated
322+
plan := &ClusterDeployPlan{
323+
DeploymentID: "plan-test-001",
324+
ClusterType: "ha",
325+
Mode: "pseudo",
326+
Nodes: []PlanNode{
327+
{ID: "node-1", Host: "10.0.0.11", MySQLPort: 3306, Role: "master", AgentPort: 9090, ServerID: 1},
328+
{ID: "node-2", Host: "10.0.0.12", MySQLPort: 3307, Role: "replica", AgentPort: 9090, ServerID: 2},
329+
},
330+
Steps: []PlanStep{
331+
{ID: "step-1", Name: "validate_input", Type: "validate", TargetNode: ""},
332+
{ID: "step-2", Name: "deploy_master", Type: "bootstrap", TargetNode: "node-1"},
333+
{ID: "step-3", Name: "deploy_replica", Type: "join", TargetNode: "node-2"},
334+
{ID: "step-4", Name: "verify", Type: "verify", TargetNode: ""},
335+
},
336+
}
337+
planJSON := mustMarshalJSON(plan)
338+
339+
require.NoError(t, clusterRepo.Create(ctx, &models.ClusterDeployment{
340+
ID: "plan-test-001",
341+
ClusterType: "ha",
342+
Name: "plan-test-001",
343+
Status: "completed",
344+
PlanJSON: planJSON,
345+
}))
346+
347+
// Call GetDeployPlan
348+
result, err := service.GetDeployPlan(ctx, "plan-test-001")
349+
require.NoError(t, err)
350+
require.Equal(t, "plan-test-001", result.DeploymentID)
351+
require.Equal(t, "ha", result.ClusterType)
352+
require.Len(t, result.Nodes, 2)
353+
require.Equal(t, "10.0.0.11", result.Nodes[0].Host)
354+
require.Equal(t, "master", result.Nodes[0].Role)
355+
require.Equal(t, 1, result.Nodes[0].ServerID)
356+
require.Equal(t, "10.0.0.12", result.Nodes[1].Host)
357+
require.Equal(t, 2, result.Nodes[1].ServerID)
358+
require.Len(t, result.Steps, 4)
359+
require.Equal(t, "validate_input", result.Steps[0].Name)
360+
require.Equal(t, "deploy_master", result.Steps[1].Name)
361+
}
362+
363+
func TestGetDeployPlan_ReturnsErrorWhenEmpty(t *testing.T) {
364+
ctx := context.Background()
365+
db := newTestDB()
366+
clusterRepo := repositories.NewClusterDeployRepository(db)
367+
service := NewClusterDeployService(clusterRepo, nil, nil, nil, nil, config.ClusterDefaults{})
368+
369+
require.NoError(t, clusterRepo.Create(ctx, &models.ClusterDeployment{
370+
ID: "plan-test-empty",
371+
ClusterType: "ha",
372+
Name: "plan-test-empty",
373+
Status: "pending",
374+
PlanJSON: "",
375+
}))
376+
377+
_, err := service.GetDeployPlan(ctx, "plan-test-empty")
378+
require.Error(t, err)
379+
require.Contains(t, err.Error(), "no plan found")
380+
}
381+
382+
func mustMarshalJSON(v interface{}) string {
383+
data, err := json.Marshal(v)
384+
if err != nil {
385+
panic(err)
386+
}
387+
return string(data)
388+
}
389+
314390
func stepIDs(steps []PlanStep) []string {
315391
out := make([]string, 0, len(steps))
316392
for _, step := range steps {

0 commit comments

Comments
 (0)