From 2aa7416db1bb0c65e4835fb0b618605806523027 Mon Sep 17 00:00:00 2001 From: "Dat. Ba Dao" Date: Thu, 9 Nov 2023 22:22:27 +0700 Subject: [PATCH] controllers: add deployment context to migrate cmd (#102) --- api/v1alpha1/context.go | 32 ++++++++ controllers/atlasmigration_controller.go | 8 +- controllers/atlasmigration_controller_test.go | 73 +++++++++++++++++++ go.mod | 2 +- go.sum | 4 +- main.go | 4 + 6 files changed, 119 insertions(+), 4 deletions(-) create mode 100644 api/v1alpha1/context.go diff --git a/api/v1alpha1/context.go b/api/v1alpha1/context.go new file mode 100644 index 00000000..6d067abd --- /dev/null +++ b/api/v1alpha1/context.go @@ -0,0 +1,32 @@ +// Copyright 2023 The Atlas Operator Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package v1alpha1 + +import "context" + +type versionCtxKey struct{} + +// WithVersionContext returns a new context with the given verison. +func WithVersionContext(ctx context.Context, version string) context.Context { + return context.WithValue(ctx, versionCtxKey{}, version) +} + +// VersionFromContext returns the version from the given context. +func VersionFromContext(ctx context.Context) string { + if v := ctx.Value(versionCtxKey{}); v != nil { + return v.(string) + } + return "" +} diff --git a/controllers/atlasmigration_controller.go b/controllers/atlasmigration_controller.go index ff6268e8..e3611f24 100644 --- a/controllers/atlasmigration_controller.go +++ b/controllers/atlasmigration_controller.go @@ -238,7 +238,13 @@ func (r *AtlasMigrationReconciler) reconcile(ctx context.Context, dir, envName s }, nil } // Execute Atlas CLI migrate command - report, err := c.MigrateApply(ctx, &atlas.MigrateApplyParams{Env: envName}) + report, err := c.MigrateApply(ctx, &atlas.MigrateApplyParams{ + Env: envName, + Context: &atlas.DeployRunContext{ + TriggerType: atlas.TriggerTypeKubernetes, + TriggerVersion: dbv1alpha1.VersionFromContext(ctx), + }, + }) if err != nil { return nil, transient(err) } diff --git a/controllers/atlasmigration_controller_test.go b/controllers/atlasmigration_controller_test.go index 6ab69510..bf183559 100644 --- a/controllers/atlasmigration_controller_test.go +++ b/controllers/atlasmigration_controller_test.go @@ -17,11 +17,17 @@ package controllers import ( "bytes" "context" + "encoding/base64" + "encoding/json" "fmt" + "io" + "net/http" + "net/http/httptest" "net/url" "os" "os/exec" "path/filepath" + "strings" "testing" "time" @@ -758,6 +764,59 @@ env { }`, fileContent.String()) } +func TestMigrationWithDeploymentContext(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + type ( + RunContext struct { + TriggerType string `json:"triggerType,omitempty"` + TriggerVersion string `json:"triggerVersion,omitempty"` + } + graphQLQuery struct { + Query string `json:"query"` + Variables json.RawMessage `json:"variables"` + MigrateApplyReport struct { + Input struct { + Context *RunContext `json:"context,omitempty"` + } `json:"input"` + } + } + ) + var m graphQLQuery + require.NoError(t, json.NewDecoder(r.Body).Decode(&m)) + switch { + case strings.Contains(m.Query, "query"): + memdir := &migrate.MemDir{} + memdir.WriteFile("30230412003626.sql", []byte(`CREATE TABLE foo (id INT PRIMARY KEY)`)) + writeDir(t, memdir, w) + case strings.Contains(m.Query, "reportMigration"): + err := json.Unmarshal(m.Variables, &m.MigrateApplyReport) + require.NoError(t, err) + require.Equal(t, "my-version", m.MigrateApplyReport.Input.Context.TriggerVersion) + require.Equal(t, "KUBERNETES", m.MigrateApplyReport.Input.Context.TriggerType) + } + })) + defer srv.Close() + tt := migrationCliTest(t) + tt.initDefaultTokenSecret() + am := tt.getAtlasMigration() + am.Spec.Cloud.URL = srv.URL + am.Spec.Dir.Remote.Name = "my-remote-dir" + am.Spec.Cloud.Project = "my-project" + am.Spec.Cloud.TokenFrom = v1alpha1.TokenFrom{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "my-secret", + }, + Key: "token", + }, + } + tt.k8s.put(am) + ctx := dbv1alpha1.WithVersionContext(context.Background(), "my-version") + result, err := tt.r.Reconcile(ctx, migrationReq()) + require.NoError(tt, err) + require.EqualValues(tt, reconcile.Result{}, result) +} + func migrationObjmeta() metav1.ObjectMeta { return metav1.ObjectMeta{ Name: "atlas-migration", @@ -912,3 +971,17 @@ func (t *migrationTest) initDefaultTokenSecret() { func (t *migrationTest) events() []string { return events(t.r.recorder) } + +func writeDir(t *testing.T, dir migrate.Dir, w io.Writer) { + // Checksum before archiving. + hf, err := dir.Checksum() + require.NoError(t, err) + ht, err := hf.MarshalText() + require.NoError(t, err) + require.NoError(t, dir.WriteFile(migrate.HashFileName, ht)) + // Archive and send. + arc, err := migrate.ArchiveDir(dir) + require.NoError(t, err) + _, err = fmt.Fprintf(w, `{"data":{"dirState":{"content":%q}}}`, base64.StdEncoding.EncodeToString(arc)) + require.NoError(t, err) +} diff --git a/go.mod b/go.mod index 03791a06..da00d88b 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ toolchain go1.21.2 require ( ariga.io/atlas v0.14.3-0.20231010104048-0c071bfc9161 - ariga.io/atlas-go-sdk v0.1.1-0.20231029150106-1927c56b057b + ariga.io/atlas-go-sdk v0.1.1-0.20231102105853-9ab4fb4ddd54 github.com/stretchr/testify v1.8.4 golang.org/x/exp v0.0.0-20231006140011-7918f672742d golang.org/x/mod v0.13.0 diff --git a/go.sum b/go.sum index 268b78b5..8c96bf50 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ ariga.io/atlas v0.14.3-0.20231010104048-0c071bfc9161 h1:xZS2wAf1AzRNA/8iD2LTAXtIZuIDYDXsZRlYBAyBu0A= ariga.io/atlas v0.14.3-0.20231010104048-0c071bfc9161/go.mod h1:isZrlzJ5cpoCoKFoY9knZug7Lq4pP1cm8g3XciLZ0Pw= -ariga.io/atlas-go-sdk v0.1.1-0.20231029150106-1927c56b057b h1:pFSDzqE7YU7S8+fRnkiycFXCe39hpLALr2fgYhxjzAQ= -ariga.io/atlas-go-sdk v0.1.1-0.20231029150106-1927c56b057b/go.mod h1:owkEEXw6jqne5KPVDfKsYB7cwMiMk3jtOiAAeKxS/yU= +ariga.io/atlas-go-sdk v0.1.1-0.20231102105853-9ab4fb4ddd54 h1:/LzEDWzKDJH2e8vht7+kl2VO5hmkSC5SCyKAZtkLhiI= +ariga.io/atlas-go-sdk v0.1.1-0.20231102105853-9ab4fb4ddd54/go.mod h1:owkEEXw6jqne5KPVDfKsYB7cwMiMk3jtOiAAeKxS/yU= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= diff --git a/main.go b/main.go index 83f9a181..b8563cd0 100644 --- a/main.go +++ b/main.go @@ -16,6 +16,7 @@ package main import ( "bytes" + "context" "flag" "os" "strconv" @@ -89,6 +90,9 @@ func main() { LeaderElection: enableLeaderElection, LeaderElectionID: "5220c287.atlasgo.io", LeaderElectionReleaseOnCancel: true, + BaseContext: func() context.Context { + return dbv1alpha1.WithVersionContext(context.Background(), version) + }, }) if err != nil { setupLog.Error(err, "unable to start manager")