From 5386f91b74819c70538c0a902e36c7f506674366 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Samin?= Date: Fri, 3 Apr 2020 11:34:58 +0200 Subject: [PATCH] fix(api): fix hooks with empty UUID (#5098) Signed-off-by: francois samin --- engine/api/api.go | 4 ++ engine/api/migrate/clean_duplicate_hooks.go | 77 +++++++++++++++++++++ 2 files changed, 81 insertions(+) diff --git a/engine/api/api.go b/engine/api/api.go index f116130a65..3f5440957e 100644 --- a/engine/api/api.go +++ b/engine/api/api.go @@ -707,6 +707,10 @@ func (a *API) Serve(ctx context.Context) error { return migrate.CleanDuplicateHooks(ctx, a.DBConnectionFactory.GetDBMap(), a.Cache, false) }}) + migrate.Add(ctx, sdk.Migration{Name: "FixEmptyUUIDHooks", Release: "0.44.0", Blocker: false, Automatic: false, ExecFunc: func(ctx context.Context) error { + return migrate.FixEmptyUUIDHooks(ctx, a.DBConnectionFactory.GetDBMap(), a.Cache) + }}) + isFreshInstall, errF := version.IsFreshInstall(a.mustDB()) if errF != nil { return sdk.WrapError(errF, "Unable to check if it's a fresh installation of CDS") diff --git a/engine/api/migrate/clean_duplicate_hooks.go b/engine/api/migrate/clean_duplicate_hooks.go index ef168e2b65..9e88af2682 100644 --- a/engine/api/migrate/clean_duplicate_hooks.go +++ b/engine/api/migrate/clean_duplicate_hooks.go @@ -135,3 +135,80 @@ func cleanDuplicateHooks(ctx context.Context, db *gorp.DbMap, store cache.Store, return nil } + +func FixEmptyUUIDHooks(ctx context.Context, db *gorp.DbMap, store cache.Store) error { + q := "select distinct(workflow.id) from w_node_hook join w_node on w_node.id = w_node_hook.node_id join workflow on workflow.id = w_node.workflow_id where uuid = ''" + var ids []int64 + + if _, err := db.Select(&ids, q); err != nil { + return sdk.WrapError(err, "unable to select workflow") + } + + var mError = new(sdk.MultiError) + for _, id := range ids { + if err := fixEmptyUUIDHooks(ctx, db, store, id); err != nil { + mError.Append(err) + log.Error(ctx, "migrate.FixEmptyUUIDHooks> unable to clean workflow %d: %v", id, err) + } + } + + if mError.IsEmpty() { + return nil + } + return mError +} + +func fixEmptyUUIDHooks(ctx context.Context, db *gorp.DbMap, store cache.Store, workflowID int64) error { + tx, err := db.Begin() + if err != nil { + return sdk.WithStack(err) + } + + defer tx.Rollback() // nolint + + projectID, err := tx.SelectInt("SELECT project_id FROM workflow WHERE id = $1", workflowID) + if err != nil { + if err == sql.ErrNoRows { + return nil + } + return sdk.WithStack(err) + } + + if projectID == 0 { + return nil + } + + proj, err := project.LoadByID(tx, store, projectID, + project.LoadOptions.WithApplicationWithDeploymentStrategies, + project.LoadOptions.WithPipelines, + project.LoadOptions.WithEnvironments, + project.LoadOptions.WithIntegrations) + if err != nil { + return sdk.WrapError(err, "unable to load project %d", projectID) + } + + w, err := workflow.LoadAndLockByID(ctx, tx, store, *proj, workflowID, workflow.LoadOptions{}) + if err != nil { + if sdk.ErrorIs(err, sdk.ErrNotFound) { + return nil + } + return err + } + + for i, h := range w.WorkflowData.Node.Hooks { + if h.UUID == "" { + w.WorkflowData.Node.Hooks[i].UUID = sdk.UUID() + } + } + + if err := workflow.Update(ctx, tx, store, *proj, w, workflow.UpdateOptions{}); err != nil { + return err + } + + if err := tx.Commit(); err != nil { + return err + } + log.Info(ctx, "migrate.fixEmptyUUIDHooks> workflow %s/%s (%d) has been cleaned", proj.Name, w.Name, w.ID) + + return nil +}