Skip to content

Commit

Permalink
support using atlas hcl file in monitor action
Browse files Browse the repository at this point in the history
  • Loading branch information
ronenlu committed Jan 9, 2025
1 parent 9fa6bcb commit 2cd0dcd
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 20 deletions.
8 changes: 7 additions & 1 deletion .github/workflows/ci-go.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -444,9 +444,15 @@ jobs:
- run: go install ./cmd/atlas-action
env:
CGO_ENABLED: 0
- id: sanity
- id: sanity using url
uses: ./monitor/schema
with:
cloud-token: ${{ secrets.ATLAS_AGENT_TOKEN }}
url: 'mysql://root:pass@localhost:3306/dev'
slug: 'github-action'
- id: sanity using config
uses: ./monitor/schema
with:
cloud-token: ${{ secrets.ATLAS_AGENT_TOKEN }}
config: 'file://monitor/schema/atlas.hcl'
env: 'dev'
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,10 @@ Can be used periodically to [monitor](https://atlasgo.io/monitoring) changes in

* `cloud-token` - (required) The Atlas Cloud token to use for authentication. To create
a cloud token see the [docs](https://atlasgo.io/cloud/bots).
* `url` - (required) The URL of the database to monitor. For example: `mysql://root:pass@localhost:3306/prod`.
* `url` - (optional) The URL of the database to monitor. For example: `mysql://root:pass@localhost:3306/prod` (mutually exclusive with `config` and `env`).
* `config` - (optional) The URL of the Atlas configuration file. By default, Atlas will look for a file
named `atlas.hcl` in the current directory. For example, `file://config/atlas.hcl` (mutually exclusive with `url`).
* `env` - (optional) The environment to use from the Atlas configuration file. For example, `dev` (mutually exclusive with `url`).
* `slug` - (optional) Unique identifier for the database server.
* `schemas` - (optional) List of database schemas to include (by default includes all schemas). see: https://atlasgo.io/declarative/inspect#inspect-multiple-schemas.
* `exclude` - (optional) List of exclude patterns from inspection. see: https://atlasgo.io/declarative/inspect#exclude-schemas.
Expand Down
43 changes: 30 additions & 13 deletions atlasaction/action.go
Original file line number Diff line number Diff line change
Expand Up @@ -820,6 +820,13 @@ func (a *Actions) MonitorSchema(ctx context.Context) error {
if err != nil {
return err
}
var (
config = a.GetInput("config")
env = a.GetInput("env")
)
if (config != "" || env != "") && db.String() != "" {
return errors.New("only one of the inputs 'config' or 'url' should be provided")
}
var (
id = cloud.ScopeIdent{
URL: db.Redacted(),
Expand All @@ -833,15 +840,30 @@ func (a *Actions) MonitorSchema(ctx context.Context) error {
}); err != nil {
return fmt.Errorf("failed to login to Atlas Cloud: %w", err)
}
res, err := a.Atlas.SchemaInspect(ctx, &atlasexec.SchemaInspectParams{
URL: db.String(),
params := &atlasexec.SchemaInspectParams{
Schema: id.Schemas,
Exclude: id.Schemas,
Format: `{{ printf "# %s\n%s" .Hash .MarshalHCL }}`,
})
Format: `{{ printf "# %s\n%s\n%s" .Hash .MarshalHCL .RedactedURL }}`,
}
if db.String() != "" {
params.URL = db.String()
}
if config != "" {
params.ConfigURL = config
params.Env = env
}
res, err := a.Atlas.SchemaInspect(ctx, params)
if err != nil {
return fmt.Errorf("failed to inspect the schema: %w", err)
}
var (
parts = strings.SplitN(res, "\n", 3)
hash = strings.TrimPrefix(parts[0], "# ")
hcl = parts[1]
)
if id.URL == "" {
id.URL = parts[2] // Get the URL from the inspect output.
}
cc, err := a.cloudClient(ctx, "cloud-token")
if err != nil {
return err
Expand All @@ -850,15 +872,10 @@ func (a *Actions) MonitorSchema(ctx context.Context) error {
if err != nil {
return fmt.Errorf("failed to get the schema snapshot hash: %w", err)
}
var (
parts = strings.SplitN(res, "\n", 2)
hash = strings.TrimPrefix(parts[0], "# ")
hcl = parts[1]
input = &cloud.PushSnapshotInput{
ScopeIdent: id,
HashMatch: strings.HasPrefix(h, "h1:") && OldAgentHash(hcl) == h || hash == h,
}
)
input := &cloud.PushSnapshotInput{
ScopeIdent: id,
HashMatch: strings.HasPrefix(h, "h1:") && OldAgentHash(hcl) == h || hash == h,
}
if !input.HashMatch {
input.Snapshot = &cloud.SnapshotInput{Hash: hash, HCL: hcl}
}
Expand Down
29 changes: 26 additions & 3 deletions atlasaction/action_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -555,11 +555,12 @@ func TestMonitorSchema(t *testing.T) {
ctx = context.Background()
)
for _, tt := range []struct {
name, url, slug string
name, url, slug, config string
schemas, exclude []string
latestHash, newHash, hcl string
exSnapshot *cloud.SnapshotInput
exMatch bool
wantErr bool
}{
{
name: "no latest hash",
Expand Down Expand Up @@ -628,6 +629,22 @@ func TestMonitorSchema(t *testing.T) {
exclude: []string{"foo.*", "bar.*.*"},
exMatch: true,
},
{
name: "url and config should rerurn error",
url: u,
config: "config",
wantErr: true,
},
{
name: "hash match old hash func, using config",
config: "file:/atlas.hcl",
latestHash: atlasaction.OldAgentHash("hcl"),
newHash: "hash",
hcl: "hcl",
schemas: []string{},
exclude: []string{},
exMatch: true,
},
} {
t.Run(tt.name, func(t *testing.T) {
var (
Expand All @@ -637,6 +654,7 @@ func TestMonitorSchema(t *testing.T) {
"cloud-token": "token",
"url": tt.url,
"slug": tt.slug,
"config": tt.config,
"schemas": strings.Join(tt.schemas, "\n"),
"exclude": strings.Join(tt.exclude, "\n"),
},
Expand All @@ -647,7 +665,7 @@ func TestMonitorSchema(t *testing.T) {
return nil
},
schemaInspect: func(_ context.Context, p *atlasexec.SchemaInspectParams) (string, error) {
return fmt.Sprintf("# %s\n%s", tt.newHash, tt.hcl), nil
return fmt.Sprintf("# %s\n%s\n%s", tt.newHash, tt.hcl, ""), nil
},
}
cc = &mockCloudClient{hash: tt.latestHash}
Expand All @@ -660,7 +678,12 @@ func TestMonitorSchema(t *testing.T) {
)
)
require.NoError(t, err)
require.NoError(t, as.MonitorSchema(ctx))
err = as.MonitorSchema(ctx)
if tt.wantErr {
require.Error(t, err)
return
}
require.NoError(t, err)
require.Equal(t, &cloud.PushSnapshotInput{
ScopeIdent: cloud.ScopeIdent{
URL: must(url.Parse(tt.url)).Redacted(),
Expand Down
12 changes: 10 additions & 2 deletions monitor/schema/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,16 @@ inputs:
description: 'The token that is used to connect to Atlas Cloud (should be passed as a secret).'
required: true
url:
description: 'URL of the database to sync.'
required: true
description: 'URL of the database to sync (mutually exclusive with `config` and `env`).'
required: false
config:
description: 'The URL of the Atlas configuration file (mutually exclusive with `url`).
For example, `file://config/atlas.hcl`, learn more about [Atlas configuration files](https://atlasgo.io/atlas-schema/projects).'
required: false
env:
description: 'The environment to use from the Atlas configuration file. For example, `dev`
(mutually exclusive with `url`).'
required: false
slug:
description: 'Optional unique identifier for the database server.'
required: false
Expand Down
4 changes: 4 additions & 0 deletions monitor/schema/atlas.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# used in monitor github action for integration tests
env "dev" {
url = "mysql://root:pass@localhost:3306/dev"
}

0 comments on commit 2cd0dcd

Please sign in to comment.