Skip to content

Commit 2166377

Browse files
committed
feat(部署): 重构部署任务管理功能
- 新增部署任务状态常量"error"表示失败状态 - 重构部署任务表结构,使用服务名和版本作为联合主键 - 实现部署适配器处理与deploy模块的交互 - 新增部署任务API支持服务名和版本作为路径参数 - 完善部署任务创建、更新、暂停、继续和回滚逻辑 - 新增配置模块支持数据库配置加载 - 更新SQL schema文件反映部署任务表结构变更 - 优化API分组注释和代码结构
1 parent 4555e06 commit 2166377

File tree

12 files changed

+580
-158
lines changed

12 files changed

+580
-158
lines changed

docs/service_manager/model/schema.sql

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,17 +44,21 @@ CREATE TABLE IF NOT EXISTS service_states (
4444

4545
-- 部署任务表 (deploy_tasks)
4646
CREATE TABLE IF NOT EXISTS deploy_tasks (
47-
id VARCHAR(32) PRIMARY KEY,
47+
service VARCHAR(255),
48+
version VARCHAR(255),
4849
start_time TIMESTAMP,
4950
end_time TIMESTAMP,
5051
target_ratio DOUBLE PRECISION,
5152
instances JSONB DEFAULT '[]'::jsonb,
52-
deploy_state VARCHAR(50)
53+
deploy_state VARCHAR(50),
54+
PRIMARY KEY (service, version),
55+
FOREIGN KEY (service) REFERENCES services(name) ON DELETE CASCADE
5356
);
5457

5558
-- 创建索引以提高查询性能
5659
CREATE INDEX IF NOT EXISTS idx_service_states_service ON service_states(service);
5760
CREATE INDEX IF NOT EXISTS idx_service_states_report_at ON service_states(service, report_at DESC);
61+
CREATE INDEX IF NOT EXISTS idx_deploy_tasks_service ON deploy_tasks(service);
5862
CREATE INDEX IF NOT EXISTS idx_deploy_tasks_state ON deploy_tasks(deploy_state);
5963
CREATE INDEX IF NOT EXISTS idx_service_instances_service ON service_instances(service);
6064

internal/deploy/config/config.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package config
2+
3+
import (
4+
"fmt"
5+
"os"
6+
7+
"gopkg.in/yaml.v3"
8+
)
9+
10+
// Config Deploy服务配置
11+
type Config struct {
12+
Database DatabaseConfig `yaml:"database"`
13+
}
14+
15+
// DatabaseConfig 数据库配置
16+
type DatabaseConfig struct {
17+
Host string `yaml:"host"`
18+
Port int `yaml:"port"`
19+
User string `yaml:"user"`
20+
Password string `yaml:"password"`
21+
DBName string `yaml:"dbname"`
22+
SSLMode string `yaml:"sslmode"`
23+
}
24+
25+
// GetDSN 获取PostgreSQL数据库连接字符串
26+
func (d *DatabaseConfig) GetDSN() string {
27+
return fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=%s",
28+
d.Host, d.Port, d.User, d.Password, d.DBName, d.SSLMode)
29+
}
30+
31+
// LoadConfig 加载配置文件
32+
func LoadConfig(configPath string) (*Config, error) {
33+
data, err := os.ReadFile(configPath)
34+
if err != nil {
35+
return nil, fmt.Errorf("failed to read config file: %w", err)
36+
}
37+
38+
var config Config
39+
if err := yaml.Unmarshal(data, &config); err != nil {
40+
return nil, fmt.Errorf("failed to parse config file: %w", err)
41+
}
42+
43+
return &config, nil
44+
}

internal/service_manager/api/deploy_api.go

Lines changed: 72 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,17 @@ func (api *Api) setupDeployRouters(router *fox.Engine) {
1515
// 部署任务基本操作
1616
router.POST("/v1/deployments", api.CreateDeployment)
1717
router.GET("/v1/deployments", api.GetDeployments)
18-
router.GET("/v1/deployments/:deployID", api.GetDeploymentByID)
19-
router.POST("/v1/deployments/:deployID", api.UpdateDeployment)
20-
router.DELETE("/v1/deployments/:deployID", api.DeleteDeployment)
18+
router.GET("/v1/deployments/:service/:version", api.GetDeploymentByServiceAndVersion)
19+
router.POST("/v1/deployments/:service/:version", api.UpdateDeployment)
20+
router.DELETE("/v1/deployments/:service/:version", api.DeleteDeployment)
2121

2222
// 部署任务控制操作
23-
router.POST("/v1/deployments/:deployID/pause", api.PauseDeployment)
24-
router.POST("/v1/deployments/:deployID/continue", api.ContinueDeployment)
25-
router.POST("/v1/deployments/:deployID/rollback", api.RollbackDeployment)
23+
router.POST("/v1/deployments/:service/:version/pause", api.PauseDeployment)
24+
router.POST("/v1/deployments/:service/:version/continue", api.ContinueDeployment)
25+
router.POST("/v1/deployments/:service/:version/rollback", api.RollbackDeployment)
2626
}
2727

28-
// ===== 部署管理相关API =====
28+
// ===== 部署任务基本操作 =====
2929

3030
// CreateDeployment 创建发布任务(POST /v1/deployments)
3131
func (api *Api) CreateDeployment(c *fox.Context) {
@@ -48,7 +48,7 @@ func (api *Api) CreateDeployment(c *fox.Context) {
4848
return
4949
}
5050

51-
deployID, err := api.service.CreateDeployment(ctx, &req)
51+
deployment, err := api.service.CreateDeployment(ctx, &req)
5252
if err != nil {
5353
if err == service.ErrServiceNotFound {
5454
c.JSON(http.StatusBadRequest, map[string]any{
@@ -75,26 +75,24 @@ func (api *Api) CreateDeployment(c *fox.Context) {
7575
return
7676
}
7777

78-
c.JSON(http.StatusCreated, map[string]any{
79-
"id": deployID,
80-
"message": "deployment created successfully",
81-
})
78+
c.JSON(http.StatusCreated, deployment)
8279
}
8380

84-
// GetDeploymentByID 获取发布任务详情(GET /v1/deployments/:deployID
85-
func (api *Api) GetDeploymentByID(c *fox.Context) {
81+
// GetDeploymentByServiceAndVersion 获取发布任务详情(GET /v1/deployments/:service/:version
82+
func (api *Api) GetDeploymentByServiceAndVersion(c *fox.Context) {
8683
ctx := c.Request.Context()
87-
deployID := c.Param("deployID")
84+
serviceName := c.Param("service")
85+
versionName := c.Param("version")
8886

89-
if deployID == "" {
87+
if serviceName == "" || versionName == "" {
9088
c.JSON(http.StatusBadRequest, map[string]any{
9189
"error": "bad request",
92-
"message": "deployment ID is required",
90+
"message": "service and version are required",
9391
})
9492
return
9593
}
9694

97-
deployment, err := api.service.GetDeploymentByID(ctx, deployID)
95+
deployment, err := api.service.GetDeploymentByServiceAndVersion(ctx, serviceName, versionName)
9896
if err != nil {
9997
if err == service.ErrDeploymentNotFound {
10098
c.JSON(http.StatusNotFound, map[string]any{
@@ -103,7 +101,7 @@ func (api *Api) GetDeploymentByID(c *fox.Context) {
103101
})
104102
return
105103
}
106-
log.Error().Err(err).Str("deployID", deployID).Msg("failed to get deployment")
104+
log.Error().Err(err).Str("service", serviceName).Str("version", versionName).Msg("failed to get deployment")
107105
c.JSON(http.StatusInternalServerError, map[string]any{
108106
"error": "internal server error",
109107
"message": "failed to get deployment",
@@ -145,15 +143,16 @@ func (api *Api) GetDeployments(c *fox.Context) {
145143
})
146144
}
147145

148-
// UpdateDeployment 修改发布任务(POST /v1/deployments/:deployID
146+
// UpdateDeployment 修改发布任务(POST /v1/deployments/:service/:version
149147
func (api *Api) UpdateDeployment(c *fox.Context) {
150148
ctx := c.Request.Context()
151-
deployID := c.Param("deployID")
149+
serviceName := c.Param("service")
150+
versionName := c.Param("version")
152151

153-
if deployID == "" {
152+
if serviceName == "" || versionName == "" {
154153
c.JSON(http.StatusBadRequest, map[string]any{
155154
"error": "bad request",
156-
"message": "deployment ID is required",
155+
"message": "service and version are required",
157156
})
158157
return
159158
}
@@ -167,7 +166,7 @@ func (api *Api) UpdateDeployment(c *fox.Context) {
167166
return
168167
}
169168

170-
err := api.service.UpdateDeployment(ctx, deployID, &req)
169+
err := api.service.UpdateDeployment(ctx, serviceName, versionName, &req)
171170
if err != nil {
172171
if err == service.ErrDeploymentNotFound {
173172
c.JSON(http.StatusNotFound, map[string]any{
@@ -183,7 +182,7 @@ func (api *Api) UpdateDeployment(c *fox.Context) {
183182
})
184183
return
185184
}
186-
log.Error().Err(err).Str("deployID", deployID).Msg("failed to update deployment")
185+
log.Error().Err(err).Str("service", serviceName).Str("version", versionName).Msg("failed to update deployment")
187186
c.JSON(http.StatusInternalServerError, map[string]any{
188187
"error": "internal server error",
189188
"message": "failed to update deployment",
@@ -196,20 +195,21 @@ func (api *Api) UpdateDeployment(c *fox.Context) {
196195
})
197196
}
198197

199-
// DeleteDeployment 删除发布任务(DELETE /v1/deployments/:deployID
198+
// DeleteDeployment 删除发布任务(DELETE /v1/deployments/:service/:version
200199
func (api *Api) DeleteDeployment(c *fox.Context) {
201200
ctx := c.Request.Context()
202-
deployID := c.Param("deployID")
201+
serviceName := c.Param("service")
202+
versionName := c.Param("version")
203203

204-
if deployID == "" {
204+
if serviceName == "" || versionName == "" {
205205
c.JSON(http.StatusBadRequest, map[string]any{
206206
"error": "bad request",
207-
"message": "deployment ID is required",
207+
"message": "service and version are required",
208208
})
209209
return
210210
}
211211

212-
err := api.service.DeleteDeployment(ctx, deployID)
212+
err := api.service.DeleteDeployment(ctx, serviceName, versionName)
213213
if err != nil {
214214
if err == service.ErrDeploymentNotFound {
215215
c.JSON(http.StatusNotFound, map[string]any{
@@ -225,7 +225,7 @@ func (api *Api) DeleteDeployment(c *fox.Context) {
225225
})
226226
return
227227
}
228-
log.Error().Err(err).Str("deployID", deployID).Msg("failed to delete deployment")
228+
log.Error().Err(err).Str("service", serviceName).Str("version", versionName).Msg("failed to delete deployment")
229229
c.JSON(http.StatusInternalServerError, map[string]any{
230230
"error": "internal server error",
231231
"message": "failed to delete deployment",
@@ -238,20 +238,23 @@ func (api *Api) DeleteDeployment(c *fox.Context) {
238238
})
239239
}
240240

241-
// PauseDeployment 暂停发布任务(POST /v1/deployments/:deployID/pause)
241+
// ===== 部署任务控制操作 =====
242+
243+
// PauseDeployment 暂停发布任务(POST /v1/deployments/:service/:version/pause)
242244
func (api *Api) PauseDeployment(c *fox.Context) {
243245
ctx := c.Request.Context()
244-
deployID := c.Param("deployID")
246+
serviceName := c.Param("service")
247+
versionName := c.Param("version")
245248

246-
if deployID == "" {
249+
if serviceName == "" || versionName == "" {
247250
c.JSON(http.StatusBadRequest, map[string]any{
248251
"error": "bad request",
249-
"message": "deployment ID is required",
252+
"message": "service and version are required",
250253
})
251254
return
252255
}
253256

254-
err := api.service.PauseDeployment(ctx, deployID)
257+
err := api.service.PauseDeployment(ctx, serviceName, versionName)
255258
if err != nil {
256259
if err == service.ErrDeploymentNotFound {
257260
c.JSON(http.StatusNotFound, map[string]any{
@@ -267,7 +270,7 @@ func (api *Api) PauseDeployment(c *fox.Context) {
267270
})
268271
return
269272
}
270-
log.Error().Err(err).Str("deployID", deployID).Msg("failed to pause deployment")
273+
log.Error().Err(err).Str("service", serviceName).Str("version", versionName).Msg("failed to pause deployment")
271274
c.JSON(http.StatusInternalServerError, map[string]any{
272275
"error": "internal server error",
273276
"message": "failed to pause deployment",
@@ -280,20 +283,21 @@ func (api *Api) PauseDeployment(c *fox.Context) {
280283
})
281284
}
282285

283-
// ContinueDeployment 继续发布任务(POST /v1/deployments/:deployID/continue)
286+
// ContinueDeployment 继续发布任务(POST /v1/deployments/:service/:version/continue)
284287
func (api *Api) ContinueDeployment(c *fox.Context) {
285288
ctx := c.Request.Context()
286-
deployID := c.Param("deployID")
289+
serviceName := c.Param("service")
290+
versionName := c.Param("version")
287291

288-
if deployID == "" {
292+
if serviceName == "" || versionName == "" {
289293
c.JSON(http.StatusBadRequest, map[string]any{
290294
"error": "bad request",
291-
"message": "deployment ID is required",
295+
"message": "service and version are required",
292296
})
293297
return
294298
}
295299

296-
err := api.service.ContinueDeployment(ctx, deployID)
300+
err := api.service.ContinueDeployment(ctx, serviceName, versionName)
297301
if err != nil {
298302
if err == service.ErrDeploymentNotFound {
299303
c.JSON(http.StatusNotFound, map[string]any{
@@ -309,7 +313,7 @@ func (api *Api) ContinueDeployment(c *fox.Context) {
309313
})
310314
return
311315
}
312-
log.Error().Err(err).Str("deployID", deployID).Msg("failed to continue deployment")
316+
log.Error().Err(err).Str("service", serviceName).Str("version", versionName).Msg("failed to continue deployment")
313317
c.JSON(http.StatusInternalServerError, map[string]any{
314318
"error": "internal server error",
315319
"message": "failed to continue deployment",
@@ -322,20 +326,38 @@ func (api *Api) ContinueDeployment(c *fox.Context) {
322326
})
323327
}
324328

325-
// RollbackDeployment 回滚发布任务(POST /v1/deployments/:deployID/rollback)
329+
// RollbackDeployment 回滚发布任务(POST /v1/deployments/:service/:version/rollback)
326330
func (api *Api) RollbackDeployment(c *fox.Context) {
327331
ctx := c.Request.Context()
328-
deployID := c.Param("deployID")
332+
serviceName := c.Param("service")
333+
versionName := c.Param("version")
334+
335+
if serviceName == "" || versionName == "" {
336+
c.JSON(http.StatusBadRequest, map[string]any{
337+
"error": "bad request",
338+
"message": "service and version are required",
339+
})
340+
return
341+
}
342+
343+
var req model.RollbackDeploymentRequest
344+
if err := c.ShouldBindJSON(&req); err != nil {
345+
c.JSON(http.StatusBadRequest, map[string]any{
346+
"error": "bad request",
347+
"message": "invalid request body: " + err.Error(),
348+
})
349+
return
350+
}
329351

330-
if deployID == "" {
352+
if req.TargetVersion == "" {
331353
c.JSON(http.StatusBadRequest, map[string]any{
332354
"error": "bad request",
333-
"message": "deployment ID is required",
355+
"message": "target version is required",
334356
})
335357
return
336358
}
337359

338-
err := api.service.RollbackDeployment(ctx, deployID)
360+
err := api.service.RollbackDeployment(ctx, serviceName, versionName, &req)
339361
if err != nil {
340362
if err == service.ErrDeploymentNotFound {
341363
c.JSON(http.StatusNotFound, map[string]any{
@@ -351,7 +373,7 @@ func (api *Api) RollbackDeployment(c *fox.Context) {
351373
})
352374
return
353375
}
354-
log.Error().Err(err).Str("deployID", deployID).Msg("failed to rollback deployment")
376+
log.Error().Err(err).Str("service", serviceName).Str("version", versionName).Msg("failed to rollback deployment")
355377
c.JSON(http.StatusInternalServerError, map[string]any{
356378
"error": "internal server error",
357379
"message": "failed to rollback deployment",
@@ -360,6 +382,6 @@ func (api *Api) RollbackDeployment(c *fox.Context) {
360382
}
361383

362384
c.JSON(http.StatusOK, map[string]any{
363-
"message": "deployment rolled back successfully",
385+
"message": "deployment rollback initiated successfully",
364386
})
365387
}

internal/service_manager/api/info_api.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ func (api *Api) setupInfoRouters(router *fox.Engine) {
2323
router.DELETE("/v1/services/:service", api.DeleteService)
2424
}
2525

26-
// ===== 服务信息相关API =====
26+
// ===== 服务信息查询API =====
2727

2828
// GetServices 获取所有服务列表(GET /v1/services)
2929
func (api *Api) GetServices(c *fox.Context) {
@@ -146,7 +146,7 @@ func (api *Api) GetServiceMetricTimeSeries(c *fox.Context) {
146146
c.JSON(http.StatusOK, response)
147147
}
148148

149-
// ===== 服务管理API(CRUD操作) =====
149+
// ===== 服务管理CRUD API =====
150150

151151
// CreateService 创建服务(POST /v1/services)
152152
func (api *Api) CreateService(c *fox.Context) {

0 commit comments

Comments
 (0)