diff --git a/cmd/atlas/internal/cmdapi/cmdapi_oss.go b/cmd/atlas/internal/cmdapi/cmdapi_oss.go index b193edd80a9..5594040ba81 100644 --- a/cmd/atlas/internal/cmdapi/cmdapi_oss.go +++ b/cmd/atlas/internal/cmdapi/cmdapi_oss.go @@ -16,7 +16,6 @@ import ( "text/template" "time" - "ariga.io/atlas/cmd/atlas/internal/cloudapi" "ariga.io/atlas/cmd/atlas/internal/cmdext" "ariga.io/atlas/cmd/atlas/internal/cmdlog" "ariga.io/atlas/cmd/atlas/internal/cmdstate" @@ -467,9 +466,8 @@ func promptApply(cmd *cobra.Command, flags schemaApplyFlags, diff *diff, client, return nil } -// withTokenContext allows attaching token to the context. -func withTokenContext(ctx context.Context, _ string, _ *cloudapi.Client) (context.Context, error) { - return ctx, nil // unimplemented. +func maySetLoginContext(*cobra.Command, *Project) error { + return nil } func setEnvs(context.Context, []*Env) {} diff --git a/cmd/atlas/internal/cmdapi/project.go b/cmd/atlas/internal/cmdapi/project.go index b312cfedbf8..b1434486b42 100644 --- a/cmd/atlas/internal/cmdapi/project.go +++ b/cmd/atlas/internal/cmdapi/project.go @@ -534,7 +534,7 @@ func EnvByName(cmd *cobra.Command, name string, vars map[string]cty.Value) (*Pro setEnvs(cmd.Context(), envs[name]) }() if p, e, ok := envsCache.load(GlobalFlags.ConfigURL, name, vars); ok { - return p, e, maySetTokenContext(cmd, p) + return p, e, maySetLoginContext(cmd, p) } u, err := url.Parse(GlobalFlags.ConfigURL) if err != nil { @@ -554,9 +554,9 @@ func EnvByName(cmd *cobra.Command, name string, vars map[string]cty.Value) (*Pro if err != nil { return nil, nil, err } - // The project token predates 'atlas login' command. If exists, + // The atlas.hcl token predates 'atlas login' command. If exists, // attach it to the context to indicate the user is authenticated. - if err := maySetTokenContext(cmd, project); err != nil { + if err := maySetLoginContext(cmd, project); err != nil { return nil, nil, err } if err := project.Lint.remainedLog(); err != nil { @@ -596,19 +596,6 @@ func EnvByName(cmd *cobra.Command, name string, vars map[string]cty.Value) (*Pro } } -// maySetTokenContext sets the token context and cloud client if -// defined in the project file. -func maySetTokenContext(cmd *cobra.Command, p *Project) error { - if p.cloud.Token != "" && p.cloud.Client != nil { - ctx, err := withTokenContext(cmd.Context(), p.cloud.Token, p.cloud.Client) - if err != nil { - return err - } - cmd.SetContext(ctx) - } - return nil -} - type ( envCacheK struct { path, env, vars string diff --git a/cmd/atlas/internal/cmdapi/schema.go b/cmd/atlas/internal/cmdapi/schema.go index 363296fd0cd..e25f540b3c1 100644 --- a/cmd/atlas/internal/cmdapi/schema.go +++ b/cmd/atlas/internal/cmdapi/schema.go @@ -381,12 +381,12 @@ flag. atlas schema inspect -u "mariadb://user:pass@localhost:3306/" --schema=schemaA,schemaB -s schemaC atlas schema inspect --url "postgres://user:pass@host:port/dbname?sslmode=disable" atlas schema inspect -u "sqlite://file:ex1.db?_fk=1"`, - PreRunE: func(cmd *cobra.Command, args []string) (err error) { + PreRunE: RunE(func(cmd *cobra.Command, args []string) (err error) { if env, err = selectEnv(cmd); err != nil { return err } return setSchemaEnvFlags(cmd, env) - }, + }), RunE: RunE(func(cmd *cobra.Command, args []string) error { return schemaInspectRun(cmd, args, flags, env) }), diff --git a/cmd/atlas/internal/cmdext/cmdext.go b/cmd/atlas/internal/cmdext/cmdext.go index 56bdac6e47a..fd2663ff8b6 100644 --- a/cmd/atlas/internal/cmdext/cmdext.go +++ b/cmd/atlas/internal/cmdext/cmdext.go @@ -17,7 +17,6 @@ import ( "os/exec" "path" "path/filepath" - "reflect" "text/template" "time" @@ -26,11 +25,9 @@ import ( "ariga.io/atlas/sql/migrate" "ariga.io/atlas/sql/schema" "ariga.io/atlas/sql/sqlclient" + "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/feature/rds/auth" - "golang.org/x/oauth2/google" - sqladmin "google.golang.org/api/sqladmin/v1beta4" - "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/gohcl" "github.com/hashicorp/hcl/v2/hclsyntax" @@ -44,6 +41,8 @@ import ( _ "gocloud.dev/runtimevar/gcpruntimeconfig" _ "gocloud.dev/runtimevar/gcpsecretmanager" _ "gocloud.dev/runtimevar/httpvar" + "golang.org/x/oauth2/google" + sqladmin "google.golang.org/api/sqladmin/v1beta4" ) // SpecOptions exposes the schema spec options like data-sources provided by this package. @@ -63,6 +62,16 @@ var SpecOptions = append( specOptions..., ) +// AtlasConfig exposes non-sensitive information returned by the "atlas" init-block. +// By invoking AtlasInitBlock() a new config is returned that is set by the init block +// defined and executed on schemahcl Eval functions. +type AtlasConfig struct { + Client *cloudapi.Client // Client attached to Atlas Cloud. + Token string // User token. + Org string // Organization to connect to. + Project string // Optional project. +} + // RuntimeVar exposes the gocloud.dev/runtimevar as a schemahcl datasource. // // data "runtimevar" "pass" { @@ -473,67 +482,6 @@ func TemplateDir(_ context.Context, ectx *hcl.EvalContext, block *hclsyntax.Bloc }), nil } -// AtlasConfig exposes non-sensitive information returned by the "atlas" init-block. -// By invoking AtlasInitBlock() a new config is returned that is set by the init block -// defined and executed on schemahcl Eval functions. -type AtlasConfig struct { - Client *cloudapi.Client // Client attached to Atlas Cloud. - Token string // User token. - Project string // Optional project. -} - -// InitBlock returns the handler for the "atlas" init block. -// -// atlas { -// cloud { -// token = data.runtimevar.token // User token. -// url = var.cloud_url // Optional URL. -// project = var.project // Optional project. Defaults to DefaultProjectName. -// } -// } -func (c *AtlasConfig) InitBlock() schemahcl.Option { - return schemahcl.WithInitBlock("atlas", func(_ context.Context, ectx *hcl.EvalContext, block *hclsyntax.Block) (cty.Value, error) { - atlasVal, diags := (&hclsyntax.ScopeTraversalExpr{ - Traversal: hcl.Traversal{hcl.TraverseRoot{Name: "atlas", SrcRange: block.Range()}}, - }).Value(ectx) - if diags.HasErrors() { - if len(diags) > 1 || diags[0].Summary != "Unknown variable" { - return cty.NilVal, fmt.Errorf("atlas.cloud: getting config: %v", diags) - } - // Create an empty object if the atlas object is not set. - atlasVal = cty.ObjectVal(map[string]cty.Value{}) - } - var args struct { - Cloud struct { - Token string `hcl:"token"` - URL string `hcl:"url,optional"` - Project string `hcl:"project,optional"` - } `hcl:"cloud,block"` - } - switch diags := gohcl.DecodeBody(block.Body, ectx, &args); { - case diags.HasErrors(): - return cty.NilVal, fmt.Errorf("atlas.cloud: decoding body: %v", diags) - case args.Cloud.Token == "": - return atlasVal, nil // If no token was set, the cloud is not initialized. - default: - if args.Cloud.Project == "" { - args.Cloud.Project = cloudapi.DefaultProjectName - } - c.Token = args.Cloud.Token - c.Project = args.Cloud.Project - c.Client = cloudapi.New(args.Cloud.URL, args.Cloud.Token) - m := atlasVal.AsValueMap() - m["cloud"] = cty.ObjectVal(map[string]cty.Value{ - "client": cty.CapsuleVal(clientType, c.Client), - "project": cty.StringVal(args.Cloud.Project), - }) - return cty.ObjectVal(m), nil - } - }) -} - -var clientType = cty.Capsule("client", reflect.TypeOf(cloudapi.Client{})) - // SchemaHCL is a data source that reads an Atlas HCL schema file(s), evaluates it // with the given variables and exposes its resulting schema as in-memory HCL file. func SchemaHCL(_ context.Context, ectx *hcl.EvalContext, block *hclsyntax.Block) (cty.Value, error) { diff --git a/cmd/atlas/internal/cmdext/cmdext_oss.go b/cmd/atlas/internal/cmdext/cmdext_oss.go index 8f2855583b7..0ec0b028b3f 100644 --- a/cmd/atlas/internal/cmdext/cmdext_oss.go +++ b/cmd/atlas/internal/cmdext/cmdext_oss.go @@ -46,3 +46,10 @@ func (l EntLoader) LoadState(context.Context, *StateReaderConfig) (*StateReadClo func (l EntLoader) MigrateDiff(context.Context, *MigrateDiffOptions) error { return fmt.Errorf("ent:// scheme is no longer supported by this release. See: https://atlasgo.io/getting-started") } + +// InitBlock returns the handler for the "atlas" init block. +func (c *AtlasConfig) InitBlock() schemahcl.Option { + return schemahcl.WithInitBlock("atlas", func(_ context.Context, ectx *hcl.EvalContext, block *hclsyntax.Block) (cty.Value, error) { + return cty.NilVal, fmt.Errorf("atlas block is not supported by this release. See: https://atlasgo.io/getting-started") + }) +} diff --git a/cmd/atlas/internal/cmdext/cmdext_test.go b/cmd/atlas/internal/cmdext/cmdext_test.go index da7edbe5871..5d51949ab37 100644 --- a/cmd/atlas/internal/cmdext/cmdext_test.go +++ b/cmd/atlas/internal/cmdext/cmdext_test.go @@ -16,7 +16,6 @@ import ( "strings" "testing" - "ariga.io/atlas/cmd/atlas/internal/cloudapi" "ariga.io/atlas/cmd/atlas/internal/cmdext" "ariga.io/atlas/schemahcl" "ariga.io/atlas/sql/migrate" @@ -475,86 +474,6 @@ output = local.dot_env.URL require.Equal(t, "https://example.com", v.Output) } -func TestAtlasConfig(t *testing.T) { - var ( - v struct { - Env string `spec:"env"` - HasClient bool `spec:"has_client"` - CloudKeys []string `spec:"cloud_keys"` - Atlas cty.Value `spec:"atlas"` - } - cfg = &cmdext.AtlasConfig{} - state = schemahcl.New(append(cmdext.SpecOptions, cfg.InitBlock(), schemahcl.WithVariables(map[string]cty.Value{ - "atlas": cty.ObjectVal(map[string]cty.Value{ - "env": cty.StringVal("dev"), - }), - }))...) - ) - require.Nil(t, cfg.Client) - require.Empty(t, cfg.Project) - err := state.EvalBytes([]byte(` -atlas { - cloud { - url = "url" - token = "token" - project = "atlasgo.io" - } -} - -env = atlas.env -has_client = atlas.cloud != null -cloud_keys = keys(atlas.cloud) -`), &v, map[string]cty.Value{}) - require.NoError(t, err) - require.Equal(t, "dev", v.Env) - require.True(t, v.HasClient) - require.Equal(t, []string{"client", "project"}, v.CloudKeys, "token and url should not be exported") - // Config options should be populated from the init block. - require.NotNil(t, cfg.Client) - require.Equal(t, "token", cfg.Token) - require.Equal(t, "atlasgo.io", cfg.Project) - - err = state.EvalBytes([]byte(` -atlas { - cloud { - url = "url" - token = "token" - } -} -`), &v, map[string]cty.Value{}) - require.NoError(t, err) - require.Equal(t, cloudapi.DefaultProjectName, cfg.Project) - - cfg = &cmdext.AtlasConfig{} - err = state.EvalBytes([]byte(` -atlas { - cloud { - url = "url" - token = "" - } -} -`), &v, map[string]cty.Value{}) - require.NoError(t, err) - require.Nil(t, cfg.Client) - require.Empty(t, cfg.Project) - - cfg = &cmdext.AtlasConfig{} - err = state.EvalBytes([]byte(` -atlas { - cloud { - url = "url" - token = "" - } -} -env { - name = atlas.env -} -`), &v, map[string]cty.Value{}) - require.NoError(t, err) - require.Nil(t, cfg.Client) - require.Empty(t, cfg.Project) -} - // backupEnv backs up the current value of an environment variable // and returns a function to restore it. func backupEnv(keys ...string) (restoreFunc func()) {