Merge remote-tracking branch 'upstream/main' into feat/base-service-delivery

# Conflicts:
#	ansible/mysql-deploy.yml
#	frontend/src/api/delivery.ts
#	frontend/src/views/service/Catalog.vue
#	server/.env.example
#	server/internal/config/config.go
#	server/internal/handler/task_log.go
#	server/internal/service/delivery.go
This commit is contained in:
mac
2026-07-28 15:08:37 +08:00
15 changed files with 1145 additions and 345 deletions
+49
View File
@@ -242,6 +242,55 @@ func (h *DeliveryHandler) Cancel(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"ok": true})
}
// RetryRollback retries the compensating AWX job after a previous cleanup failure.
func (h *DeliveryHandler) RetryRollback(c *gin.Context) {
if !requirePlatformAdmin(c) {
return
}
if err := h.service.RetryRollback(c.Request.Context(), c.Param("id")); err != nil {
c.JSON(http.StatusConflict, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusAccepted, gin.H{"ok": true, "status": model.TaskRollbackPending})
}
// AcknowledgeRollbackRelease releases bookkeeping after an administrator has
// independently verified that no instance artifacts remain on the target host.
func (h *DeliveryHandler) AcknowledgeRollbackRelease(c *gin.Context) {
if !requirePlatformAdmin(c) {
return
}
if err := h.service.AcknowledgeRollbackRelease(c.Request.Context(), c.Param("id")); err != nil {
c.JSON(http.StatusConflict, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"ok": true, "status": model.TaskRollbackAck})
}
// RetryCloudDMRegistration retries only the CloudDM registration step for an
// already healthy and accounted-for MySQL instance.
func (h *DeliveryHandler) RetryCloudDMRegistration(c *gin.Context) {
claims, ok := CurrentClaims(c)
if !ok {
c.JSON(http.StatusUnauthorized, gin.H{"error": "missing current user"})
return
}
taskID := c.Param("id")
if _, _, err := h.service.GetTask(c.Request.Context(), taskID, claims.UserID, claims.IsAdmin); err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
c.JSON(http.StatusNotFound, gin.H{"error": "task not found"})
return
}
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
if err := h.service.RetryCloudDMRegistration(c.Request.Context(), taskID); err != nil {
c.JSON(http.StatusConflict, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusAccepted, gin.H{"ok": true, "status": model.TaskFinished})
}
// Targets 获取可用部署目标
// @Summary 获取可用部署目标
// @Description 从 AWX 动态返回可用 Job Template 及其 Inventory hosts