Skip to content

Commit

Permalink
internal/controller: use hcl pkg to generate atlas.hcl for versioned …
Browse files Browse the repository at this point in the history
…flow (#241)
  • Loading branch information
datdao authored Dec 11, 2024
1 parent e4482e2 commit 7110c6d
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 121 deletions.
55 changes: 54 additions & 1 deletion internal/controller/atlasmigration_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ import (
"ariga.io/atlas/sql/migrate"
dbv1alpha1 "github.com/ariga/atlas-operator/api/v1alpha1"
"github.com/ariga/atlas-operator/internal/controller/watch"
"github.com/hashicorp/hcl/v2/hclwrite"
"github.com/zclconf/go-cty/cty"
)

//+kubebuilder:rbac:groups=core,resources=configmaps;secrets,verbs=create;update;delete;get;list;watch
Expand Down Expand Up @@ -562,7 +564,15 @@ func (d *migrationData) render(w io.Writer) error {
default:
return errors.New("migration directory is empty")
}
return tmpl.ExecuteTemplate(w, "atlas_migration.tmpl", d)
f := hclwrite.NewFile()
fBody := f.Body()
for _, b := range d.asBlocks() {
fBody.AppendBlock(b)
}
if _, err := f.WriteTo(w); err != nil {
return err
}
return nil
}

// hasRemoteDir returns true if the given migration data has a remote directory
Expand All @@ -573,6 +583,49 @@ func (c *migrationData) hasRemoteDir() bool {
return c.RemoteDir != nil && c.RemoteDir.Name != ""
}

// asBlocks returns the HCL blocks for the given migration data
func (d *migrationData) asBlocks() []*hclwrite.Block {
var blocks []*hclwrite.Block
if d.Cloud != nil {
atlas := hclwrite.NewBlock("atlas", nil)
cloud := atlas.Body().AppendNewBlock("cloud", nil).Body()
if d.Cloud.Token != "" {
cloud.SetAttributeValue("token", cty.StringVal(d.Cloud.Token))
}
if d.Cloud.URL != "" {
cloud.SetAttributeValue("url", cty.StringVal(d.Cloud.URL))
}
if d.Cloud.Repo != "" {
cloud.SetAttributeValue("project", cty.StringVal(d.Cloud.Repo))
}
blocks = append(blocks, atlas)
}
env := hclwrite.NewBlock("env", []string{d.EnvName})
blocks = append(blocks, env)
envBody := env.Body()
if d.URL != nil {
envBody.SetAttributeValue("url", cty.StringVal(d.URL.String()))
}
if d.DevURL != "" {
envBody.SetAttributeValue("dev", cty.StringVal(d.DevURL))
}
migration := hclwrite.NewBlock("migration", nil)
envBody.AppendBlock(migration)
// env.migration
migrationBody := migration.Body()
migrationBody.SetAttributeValue("dir", cty.StringVal(d.DirURL()))
if d.ExecOrder != "" {
migrationBody.SetAttributeValue("exec_order", cty.StringVal(d.ExecOrder))
}
if d.Baseline != "" {
migrationBody.SetAttributeValue("baseline", cty.StringVal(d.Baseline))
}
if d.RevisionsSchema != "" {
migrationBody.SetAttributeValue("revisions_schema", cty.StringVal(d.RevisionsSchema))
}
return blocks
}

func makeKeyLatest(resName string) string {
// Inspired by the helm chart key format
const storageKey = "io.atlasgo.db.v1"
Expand Down
52 changes: 26 additions & 26 deletions internal/controller/atlasmigration_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -990,50 +990,51 @@ func TestWatcher_enabled(t *testing.T) {

func TestDefaultTemplate(t *testing.T) {
migrate := &migrationData{
URL: must(url.Parse("sqlite://file2/?mode=memory")),
DevURL: "sqlite://dev/?mode=memory",
EnvName: defaultEnvName,
URL: must(url.Parse("sqlite://file2/?mode=memory")),
DevURL: "sqlite://dev/?mode=memory",
Dir: must(memDir(map[string]string{
"1.sql": "CREATE TABLE foo (id INT PRIMARY KEY);",
})),
}
var fileContent bytes.Buffer
require.NoError(t, migrate.render(&fileContent))
require.EqualValues(t, `
env {
name = atlas.env
url = "sqlite://file2/?mode=memory"
dev = "sqlite://dev/?mode=memory"
require.EqualValues(t, `env "kubernetes" {
url = "sqlite://file2/?mode=memory"
dev = "sqlite://dev/?mode=memory"
migration {
dir = "file://migrations"
}
}`, fileContent.String())
}
`, fileContent.String())
}

func TestBaselineTemplate(t *testing.T) {
migrate := &migrationData{
EnvName: defaultEnvName,
URL: must(url.Parse("sqlite://file2/?mode=memory")),
DevURL: "sqlite://dev/?mode=memory",
Dir: must(memDir(map[string]string{})),
Baseline: "20230412003626",
}
var fileContent bytes.Buffer
require.NoError(t, migrate.render(&fileContent))
require.EqualValues(t, `
env {
name = atlas.env
url = "sqlite://file2/?mode=memory"
dev = "sqlite://dev/?mode=memory"
require.EqualValues(t, `env "kubernetes" {
url = "sqlite://file2/?mode=memory"
dev = "sqlite://dev/?mode=memory"
migration {
dir = "file://migrations"
dir = "file://migrations"
baseline = "20230412003626"
}
}`, fileContent.String())
}
`, fileContent.String())
}

func TestCloudTemplate(t *testing.T) {
migrate := &migrationData{
URL: must(url.Parse("sqlite://file2/?mode=memory")),
DevURL: "sqlite://dev/?mode=memory",
EnvName: defaultEnvName,
URL: must(url.Parse("sqlite://file2/?mode=memory")),
DevURL: "sqlite://dev/?mode=memory",
Cloud: &Cloud{
URL: "https://atlasgo.io/",
Repo: "my-project",
Expand All @@ -1046,22 +1047,21 @@ func TestCloudTemplate(t *testing.T) {
}
var fileContent bytes.Buffer
require.NoError(t, migrate.render(&fileContent))
require.EqualValues(t, `
atlas {
require.EqualValues(t, `atlas {
cloud {
token = "my-token"
url = "https://atlasgo.io/"
token = "my-token"
url = "https://atlasgo.io/"
project = "my-project"
}
}
env {
name = atlas.env
url = "sqlite://file2/?mode=memory"
dev = "sqlite://dev/?mode=memory"
env "kubernetes" {
url = "sqlite://file2/?mode=memory"
dev = "sqlite://dev/?mode=memory"
migration {
dir = "atlas://my-remote-dir?tag=my-remote-tag"
}
}`, fileContent.String())
}
`, fileContent.String())
}

func TestMigrationWithDeploymentContext(t *testing.T) {
Expand Down
26 changes: 0 additions & 26 deletions internal/controller/atlasschema_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -453,32 +453,6 @@ func TestConfigTemplate(t *testing.T) {
require.EqualValues(t, expected, buf.String())
}

func TestTemplate_Func_RemoveSpecialChars(t *testing.T) {
var buf bytes.Buffer
tmpl, err := tmpl.New("specialChars").Parse(`
{{- removeSpecialChars .Text -}}
{{- removeSpecialChars .URL -}}
`)
require.NoError(t, err)
var textWithSpecialChars = "a\tb\rc\n"
err = tmpl.ExecuteTemplate(&buf, `specialChars`, struct {
Text string
URL *url.URL
}{
Text: textWithSpecialChars,
URL: &url.URL{},
})
require.NoError(t, err)
require.EqualValues(t, "abc", buf.String())
// invalid data type
err = tmpl.ExecuteTemplate(&buf, `specialChars`, struct {
Text int
}{
Text: 0,
})
require.ErrorContains(t, err, "unsupported type int")
}

func conditionReconciling() *dbv1alpha1.AtlasSchema {
return &dbv1alpha1.AtlasSchema{
ObjectMeta: objmeta(),
Expand Down
38 changes: 0 additions & 38 deletions internal/controller/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,10 @@ package controller

import (
"context"
"embed"
"errors"
"fmt"
"regexp"
"strings"
"text/template"
"time"

"ariga.io/atlas-go-sdk/atlasexec"
Expand Down Expand Up @@ -96,42 +94,6 @@ func NewAtlasExec(dir string, c *Cloud) (AtlasExec, error) {
}

var (
//go:embed templates
tmpls embed.FS
tmpl = template.Must(template.New("operator").
Funcs(template.FuncMap{
"hclValue": func(s string) string {
if s == "" {
return s
}
return strings.ReplaceAll(strings.ToUpper(s), "-", "_")
},
"slides": func(s []string) string {
b := &strings.Builder{}
b.WriteRune('[')
for i, v := range s {
if i > 0 {
b.WriteRune(',')
}
fmt.Fprintf(b, "%q", v)
}
b.WriteRune(']')
return b.String()
},
"removeSpecialChars": func(s interface{}) (string, error) {
r := regexp.MustCompile("[\t\r\n]")
switch s := s.(type) {
case string:
return r.ReplaceAllString(s, ""), nil
case fmt.Stringer:
return r.ReplaceAllString(s.String(), ""), nil
default:
return "", fmt.Errorf("unsupported type %T", s)
}
},
}).
ParseFS(tmpls, "templates/*.tmpl"),
)
sqlErrRegex = regexp.MustCompile(`sql/migrate: (execute: )?executing statement`)
)

Expand Down
30 changes: 0 additions & 30 deletions internal/controller/templates/atlas_migration.tmpl

This file was deleted.

0 comments on commit 7110c6d

Please sign in to comment.