feat(delivery): delete CloudDM datasource when instance is removed

This commit is contained in:
2026-07-30 18:05:51 +08:00
parent a72567a84a
commit 80d4f9ce60
3 changed files with 89 additions and 0 deletions
+1
View File
@@ -67,6 +67,7 @@ DELIVERY_MYSQL_INSPECT_TIMEOUT_SECONDS=90
DELIVERY_ROLLBACK_TEMPLATE_ID=0
DELIVERY_SERVICE_TOKEN=
CLOUDDM_REGISTER_URL=
CLOUDDM_DELETE_URL=
CLOUDDM_API_TOKEN=
JWT_SECRET=change-this-secret
+2
View File
@@ -62,6 +62,7 @@ type Config struct {
CloudDMAdminUsername string
CloudDMAdminPassword string
CloudDMRegisterURL string
CloudDMDeleteURL string
CloudDMAPIToken string
AWXBaseURL string
AWXToken string
@@ -147,6 +148,7 @@ func Load() Config {
CloudDMAdminUsername: env("CLOUDDM_ADMIN_USERNAME", ""),
CloudDMAdminPassword: env("CLOUDDM_ADMIN_PASSWORD", ""),
CloudDMRegisterURL: trimURL(env("CLOUDDM_REGISTER_URL", "")),
CloudDMDeleteURL: trimURL(env("CLOUDDM_DELETE_URL", "")),
CloudDMAPIToken: env("CLOUDDM_API_TOKEN", ""),
AWXBaseURL: trimURL(env("AWX_BASE_URL", "")),
AWXToken: env("AWX_TOKEN", ""),
+86
View File
@@ -1215,6 +1215,25 @@ func (s *DeliveryService) applyMySQLInspectResults(ctx context.Context, results
Updates(map[string]any{"status": "released", "released_at": now, "updated_at": now}).Error; err != nil {
return err
}
dataSourceID, deleteStatus := cloudDMDeleteInfo(meta)
if dataSourceID > 0 && deleteStatus != "deleted" {
if err := s.deleteCloudDMDataSource(ctx, current); err != nil {
meta = updateCloudDMDeleteMetadata(meta, "failed", err.Error(), "")
if updateErr := s.db.WithContext(ctx).Model(&model.DeploymentResult{}).
Where("id = ?", result.ID).
Update("metadata", string(mustJSON(meta))).Error; updateErr != nil {
return updateErr
}
return err
}
meta = updateCloudDMDeleteMetadata(meta, "deleted", "", now.Format(time.RFC3339))
if err := s.db.WithContext(ctx).Model(&model.DeploymentResult{}).
Where("id = ?", result.ID).
Update("metadata", string(mustJSON(meta))).Error; err != nil {
return err
}
}
}
}
return nil
@@ -2384,6 +2403,12 @@ type cloudDMRegisterRequest struct {
DataSource cloudDMDataSource `json:"dataSource"`
}
type cloudDMDeleteRequest struct {
SourceSystem string `json:"sourceSystem"`
ResourceType string `json:"resourceType"`
ExternalResourceID string `json:"externalResourceId"`
}
type cloudDMDataSource struct {
InstanceName string `json:"instanceName"`
InstanceDesc string `json:"instanceDesc"`
@@ -2463,6 +2488,36 @@ func cloudDMMetadata(existing map[string]any, instance model.DeploymentResult, d
return meta
}
func buildCloudDMDeleteRequest(instance model.DeploymentResult) cloudDMDeleteRequest {
return cloudDMDeleteRequest{
SourceSystem: "xinfra",
ResourceType: "MYSQL_INSTANCE",
ExternalResourceID: cloudDMExternalResourceID(instance.ID),
}
}
func cloudDMDeleteInfo(meta map[string]any) (uint64, string) {
clouddm, ok := meta["clouddm"].(map[string]any)
if !ok {
return 0, ""
}
dataSourceID, _ := cloudDMDataSourceIDFromValue(clouddm["data_source_id"])
deleteStatus := strings.ToLower(strings.TrimSpace(stringValue(clouddm["delete_status"])))
return dataSourceID, deleteStatus
}
func updateCloudDMDeleteMetadata(meta map[string]any, deleteStatus, deleteError, deletedAt string) map[string]any {
clouddm, ok := meta["clouddm"].(map[string]any)
if !ok {
clouddm = map[string]any{}
}
clouddm["delete_status"] = deleteStatus
clouddm["delete_error"] = deleteError
clouddm["deleted_at"] = deletedAt
meta["clouddm"] = clouddm
return meta
}
func buildCloudDMRegisterRequest(instance model.DeploymentResult, payload deliveryPayload, password string) cloudDMRegisterRequest {
description := strings.TrimSpace(payload.InstanceDesc)
if description == "" {
@@ -2498,6 +2553,37 @@ func buildCloudDMRegisterRequest(instance model.DeploymentResult, payload delive
}
}
func (s *DeliveryService) deleteCloudDMDataSource(ctx context.Context, instance model.DeploymentResult) error {
if strings.TrimSpace(s.cfg.CloudDMDeleteURL) == "" {
return fmt.Errorf("CloudDM deletion requires CLOUDDM_DELETE_URL to be configured")
}
if strings.TrimSpace(s.cfg.CloudDMAPIToken) == "" {
return fmt.Errorf("CloudDM deletion requires CLOUDDM_API_TOKEN to be configured")
}
body := buildCloudDMDeleteRequest(instance)
raw, err := json.Marshal(body)
if err != nil {
return fmt.Errorf("encode CloudDM deletion request: %w", err)
}
req, err := http.NewRequestWithContext(ctx, http.MethodPost, s.cfg.CloudDMDeleteURL, bytes.NewReader(raw))
if err != nil {
return err
}
req.Header.Set("Authorization", "Bearer "+strings.TrimSpace(s.cfg.CloudDMAPIToken))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Request-ID", randomUUID())
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
respBody, _ := io.ReadAll(resp.Body)
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
return fmt.Errorf("CloudDM deletion returned %s: %s", resp.Status, strings.TrimSpace(string(respBody)))
}
return nil
}
func (s *DeliveryService) RegisterCloudDM(ctx context.Context, taskID string) error {
if strings.TrimSpace(s.cfg.CloudDMRegisterURL) == "" {
return nil