diff --git a/internal/controller/devdb.go b/internal/controller/devdb.go index fc474ba..106ae82 100644 --- a/internal/controller/devdb.go +++ b/internal/controller/devdb.go @@ -20,6 +20,7 @@ import ( "errors" "fmt" "io" + "maps" "net/url" "os" "slices" @@ -42,9 +43,10 @@ import ( ) const ( - annoConnTmpl = "atlasgo.io/conntmpl" - labelEngine = "atlasgo.io/engine" - labelInstance = "app.kubernetes.io/instance" + annoConnTmpl = "atlasgo.io/conntmpl" + annoConnTmplGo = "atlasgo.io/conntmpl-go" + labelEngine = "atlasgo.io/engine" + labelInstance = "app.kubernetes.io/instance" ) type ( @@ -197,8 +199,7 @@ type devDB struct { SchemaBound bool } -// ConnTmpl returns a connection template for the devDB. -func (d *devDB) ConnTmpl() string { +func (d *devDB) connAnnotations() map[string]string { u := url.URL{ Scheme: d.Driver, User: url.UserPassword(d.User, d.Pass), @@ -216,11 +217,14 @@ func (d *devDB) ConnTmpl() string { } } u.RawQuery = q.Encode() - - return u.String() + s := u.String() + return map[string]string{ + annoConnTmpl: s, + annoConnTmplGo: strings.Replace(s, "localhost", "%s", 1), + } } -func (d *devDB) Render(w io.Writer) error { +func (d *devDB) render(w io.Writer) error { return tmpl.ExecuteTemplate(w, "devdb.tmpl", d) } @@ -253,15 +257,16 @@ func deploymentDevDB(name types.NamespacedName, drv string, schemaBound bool) (* return nil, fmt.Errorf("unsupported driver %q", v.Driver) } b := &bytes.Buffer{} - if err := v.Render(b); err != nil { + if err := v.render(b); err != nil { return nil, err } d := &appsv1.Deployment{} if err := yaml.NewYAMLToJSONDecoder(b).Decode(d); err != nil { return nil, err } + s := &d.Spec if drv == "sqlserver" { - c := &d.Spec.Template.Spec.Containers[0] + c := &s.Template.Spec.Containers[0] if v := os.Getenv("MSSQL_ACCEPT_EULA"); v != "" { c.Env = append(c.Env, corev1.EnvVar{ Name: "ACCEPT_EULA", @@ -275,6 +280,14 @@ func deploymentDevDB(name types.NamespacedName, drv string, schemaBound bool) (* }) } } + maps.Copy(s.Template.Labels, map[string]string{ + labelEngine: drv, + labelInstance: name.Name, + }) + s.Selector = &metav1.LabelSelector{ + MatchLabels: s.Template.Labels, + } + s.Template.Annotations = v.connAnnotations() return d, nil } diff --git a/internal/controller/templates/devdb.tmpl b/internal/controller/templates/devdb.tmpl index 8a99c78..b549cfa 100644 --- a/internal/controller/templates/devdb.tmpl +++ b/internal/controller/templates/devdb.tmpl @@ -4,13 +4,6 @@ metadata: name: {{ .Name }} namespace: {{ .Namespace }} spec: - selector: - matchLabels: - "app.kubernetes.io/name": "atlas-dev-db" - "app.kubernetes.io/instance": "{{ .Name }}" - "app.kubernetes.io/part-of": "atlas-operator" - "app.kubernetes.io/created-by": "controller-manager" - "atlasgo.io/engine": "{{ .Driver }}" replicas: 1 template: metadata: @@ -19,9 +12,6 @@ spec: "app.kubernetes.io/instance": "{{ .Name }}" "app.kubernetes.io/part-of": "atlas-operator" "app.kubernetes.io/created-by": "controller-manager" - "atlasgo.io/engine": "{{ .Driver }}" - annotations: - "atlasgo.io/conntmpl": "{{ .ConnTmpl }}" spec: {{- if ne .Driver "sqlserver" }} securityContext: @@ -64,4 +54,3 @@ spec: ports: - containerPort: {{ .Port }} name: {{ .Driver }} - diff --git a/test/e2e/e2e_test.go b/test/e2e/e2e_test.go index 5c34f2a..cf59d5e 100644 --- a/test/e2e/e2e_test.go +++ b/test/e2e/e2e_test.go @@ -76,12 +76,27 @@ func TestOperator(t *testing.T) { _, err = kind("kubectl", "rollout", "status", "-n", nsController, controller, "--timeout", "2m") require.NoError(t, err) + // Wait for the old pods to be deleted + _, err = kind("sleep", "5s") + require.NoError(t, err) + // Getting the controller-manager pod name + output, err := kind("kubectl", "wait", "pod", + "-n", nsController, + "-l", "control-plane=controller-manager", + "--for", "condition=Ready", + "-o", "go-template", + "--template", "{{.metadata.name}}", + ) + require.NoError(t, err) + pods := strings.Split(output, "\n") + require.Len(t, pods, 1, "expected one controller pod") // Running the test script testscript.Run(t, testscript.Params{ Dir: filepath.Join("testdata", "atlas-schema"), Setup: func(e *testscript.Env) (err error) { e.Setenv("CONTROLLER_NS", nsController) e.Setenv("CONTROLLER", controller) + e.Setenv("CONTROLLER_POD", pods[0]) // Sharing the atlas token with the test e.Setenv("ATLAS_TOKEN", os.Getenv("ATLAS_TOKEN")) // Ensure the test in running in the right kube context @@ -123,9 +138,7 @@ func TestOperator(t *testing.T) { }, // kubectl runs kubectl with the namespace set to the test namespace "kubectl": func(ts *testscript.TestScript, neg bool, args []string) { - err := ts.Exec("kubectl", append([]string{ - "--namespace", ts.Getenv("NAMESPACE"), - }, args...)...) + err := ts.Exec("kubectl", append([]string{"-n", ts.Getenv("NAMESPACE")}, args...)...) if !neg { ts.Check(err) } else if err == nil { @@ -157,6 +170,23 @@ func TestOperator(t *testing.T) { ts.Setenv(vals[0], ts.ReadFile(vals[1])) } }, + // devdb finds the devdb pod and prints the connection string + "devdb": func(ts *testscript.TestScript, neg bool, args []string) { + if neg { + ts.Fatalf("unsupported: ! devdb") + } + if len(args) != 1 { + ts.Fatalf("usage: devdb resource") + } + err := ts.Exec("kubectl", "get", "pods", + "-n", ts.Getenv("NAMESPACE"), + "-l", fmt.Sprintf("app.kubernetes.io/instance=%s-atlas-dev-db", args[0]), + "--field-selector", "status.phase=Running", + "-o", "go-template", + "--template", `{{with (index .items 0)}}{{printf (index .metadata.annotations "atlasgo.io/conntmpl-go") .status.podIP}}{{end}}`, + ) + ts.Check(err) + }, }, }) }