Skip to content

Instantly share code, notes, and snippets.

@ks2211
Last active July 30, 2024 20:06
Show Gist options
  • Save ks2211/816d531bff8935eb40dddbcc42a2b0e7 to your computer and use it in GitHub Desktop.
Save ks2211/816d531bff8935eb40dddbcc42a2b0e7 to your computer and use it in GitHub Desktop.
Using atlasexec (go SDK) to run migrations for multi tenants
variable "url" {
type = string
}
data "hcl_schema" "schema" {
path = "schema.hcl"
}
env {
name = atlas.env
url = var.url
src = data.hcl_schema.schema.url
diff {
skip {
drop_schema = true
drop_table = true
}
}
}
package main
import (
"context"
"embed"
"fmt"
"strings"
"log"
"ariga.io/atlas-go-sdk/atlasexec"
)
//go:embed schema.hcl
//go:embed atlas.hcl
var embedFS embed.FS
const (
atlasSchemaFile = "atlas.hcl"
schemaFileName = "schema.hcl"
)
func main() {
ctx := context.Background()
var dryRun bool // flag/env var
var dbURL string // flag/env var
var tenantIDs []string // fetch this from another source (e.g a file, another db, api, etc)
// create the atlas.hcl file
atlasSchema, err := embedFS.ReadFile(atlasSchemaFile)
if err != nil {
panic(err)
}
// Define the execution context, supplying a migration directory
// and potentially an `atlas.hcl` configuration file using `atlasexec.WithHCL`.
workdir, err := atlasexec.NewWorkingDir(
atlasexec.WithAtlasHCLString(string(atlasSchema)),
)
if err != nil {
panic(err)
}
// atlasexec works on a temporary directory, so we need to close it
defer workdir.Close()
// embed the migrations schema file
schemaFile, err := embedFS.ReadFile(schemaFileName)
if err != nil {
panic(err)
}
schemaFilePath, err := workdir.WriteFile(redshiftSchemaFile, schemaFileDat)
if err != nil {
panic(err)
}
client, err := atlasexec.NewClient(workdir.Path(), "atlas")
if err != nil {
panic(err)
}
// loop
for i := range tenantIDs {
// need to exclude the current tenant from the excludes so the migration runs on it
// also exclude public to avoid working against public schema
var excludes []string
excludes = append(excludes, companyIDs[:i]...)
excludes = append(excludes, companyIDs[i+1:]...)
excludes = append(excludes, "public")
resp, err := client.SchemaApply(ctx, &atlasexec.SchemaApplyParams{
URL: dbURL,
DryRun: dryRun,
Exclude: excludes,
Vars: atlasexec.Vars{
"tenant": tenantIDs[i],
"url": dbURL,
},
To: fmt.Sprintf("file://%s", schemaFilePath),
})
if err != nil {
log.Error("error doing migraton for tenant %v, error %v", tenantIDs[i], err)
continue
}
log.Debug("migrations for tenant %v response pending %v, applied %v", tenantIDs[i], strings.Join(resp.Changes.Pending, "\n"), strings.Join(resp.Changes.Applied, "\n"))
log.Info("completed migration for tenant %v", tenantIDs[i])
}
}
// schema.hcl
variable "tenant" {
type = string
description = "The schema we operate on"
}
schema "tenant" {
name = var.tenant
}
table "your_table" {
schema = schema.tenant
column "id" {
type = uuid
}
// other fields
primary_key {
columns = [column.id]
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment