-
Notifications
You must be signed in to change notification settings - Fork 216
Added bundle deployment bind and unbind command
#1131
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
ceb62c0
952d660
8075ae1
c65aa6c
d8fc45e
852e7bc
2cfee73
b318a42
7f795ec
4e8d030
637ceb3
b837d0b
4822806
1962a68
04071d6
6cbdde2
022ebc4
7f8e3b4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,105 @@ | ||
| package terraform | ||
|
|
||
| import ( | ||
| "bytes" | ||
| "context" | ||
| "fmt" | ||
|
|
||
| "github.com/databricks/cli/bundle" | ||
| "github.com/databricks/cli/libs/cmdio" | ||
| "github.com/hashicorp/terraform-exec/tfexec" | ||
| ) | ||
|
|
||
| type BindOptions struct { | ||
| AutoApprove bool | ||
| ResourceType string | ||
| ResourceKey string | ||
| ResourceId string | ||
| } | ||
|
|
||
| type importResource struct { | ||
| opts *BindOptions | ||
| } | ||
|
|
||
| // Apply implements bundle.Mutator. | ||
| func (m *importResource) Apply(ctx context.Context, b *bundle.Bundle) error { | ||
| tf := b.Terraform | ||
| if tf == nil { | ||
| return fmt.Errorf("terraform not initialized") | ||
| } | ||
|
|
||
| err := tf.Init(ctx, tfexec.Upgrade(true)) | ||
| if err != nil { | ||
| return fmt.Errorf("terraform init: %w", err) | ||
| } | ||
|
|
||
| err = tf.Import(ctx, fmt.Sprintf("%s.%s", m.opts.ResourceType, m.opts.ResourceKey), m.opts.ResourceId) | ||
| if err != nil { | ||
| return fmt.Errorf("terraform import: %w", err) | ||
| } | ||
|
|
||
| buf := bytes.NewBuffer(nil) | ||
| tf.SetStdout(buf) | ||
| changed, err := tf.Plan(ctx) | ||
|
andrewnester marked this conversation as resolved.
Outdated
andrewnester marked this conversation as resolved.
Outdated
|
||
| if err != nil { | ||
| return fmt.Errorf("terraform plan: %w", err) | ||
| } | ||
|
|
||
| if changed && !m.opts.AutoApprove { | ||
| cmdio.LogString(ctx, buf.String()) | ||
| ans, err := cmdio.AskYesOrNo(ctx, "Confirm import changes? Changes will be remotely only after running 'bundle deploy'.") | ||
|
andrewnester marked this conversation as resolved.
Outdated
andrewnester marked this conversation as resolved.
Outdated
|
||
| if err != nil { | ||
| return err | ||
|
andrewnester marked this conversation as resolved.
|
||
| } | ||
| if !ans { | ||
| err = tf.StateRm(ctx, fmt.Sprintf("%s.%s", m.opts.ResourceType, m.opts.ResourceKey)) | ||
|
andrewnester marked this conversation as resolved.
Outdated
|
||
| if err != nil { | ||
| return err | ||
| } | ||
| return fmt.Errorf("import aborted") | ||
| } | ||
| } | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| // Name implements bundle.Mutator. | ||
| func (*importResource) Name() string { | ||
| return "terraform.Import" | ||
| } | ||
|
|
||
| func Import(opts *BindOptions) bundle.Mutator { | ||
| return &importResource{opts: opts} | ||
| } | ||
|
|
||
| type unbind struct { | ||
| resourceType string | ||
| resourceKey string | ||
| } | ||
|
|
||
| func (m *unbind) Apply(ctx context.Context, b *bundle.Bundle) error { | ||
| tf := b.Terraform | ||
| if tf == nil { | ||
| return fmt.Errorf("terraform not initialized") | ||
| } | ||
|
|
||
| err := tf.Init(ctx, tfexec.Upgrade(true)) | ||
| if err != nil { | ||
| return fmt.Errorf("terraform init: %w", err) | ||
| } | ||
|
|
||
| err = tf.StateRm(ctx, fmt.Sprintf("%s.%s", m.resourceType, m.resourceKey)) | ||
| if err != nil { | ||
| return fmt.Errorf("terraform state rm: %w", err) | ||
| } | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| func (*unbind) Name() string { | ||
| return "terraform.Unbind" | ||
| } | ||
|
|
||
| func Unbind(resourceType string, resourceKey string) bundle.Mutator { | ||
| return &unbind{resourceType: resourceType, resourceKey: resourceKey} | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| package phases | ||
|
|
||
| import ( | ||
| "github.com/databricks/cli/bundle" | ||
| "github.com/databricks/cli/bundle/deploy/lock" | ||
| "github.com/databricks/cli/bundle/deploy/terraform" | ||
| ) | ||
|
|
||
| func Bind(opts *terraform.BindOptions) bundle.Mutator { | ||
| return newPhase( | ||
| "bind", | ||
| []bundle.Mutator{ | ||
| lock.Acquire(), | ||
| bundle.Defer( | ||
| bundle.Seq( | ||
| terraform.Interpolate(), | ||
| terraform.Write(), | ||
| terraform.StatePull(), | ||
| terraform.Import(opts), | ||
|
andrewnester marked this conversation as resolved.
|
||
| terraform.StatePush(), | ||
| ), | ||
| lock.Release(lock.GoalBind), | ||
| ), | ||
| }, | ||
| ) | ||
| } | ||
|
|
||
| func Unbind(resourceType string, resourceKey string) bundle.Mutator { | ||
| return newPhase( | ||
| "unbind", | ||
| []bundle.Mutator{ | ||
| lock.Acquire(), | ||
| bundle.Defer( | ||
| bundle.Seq( | ||
| terraform.Interpolate(), | ||
| terraform.Write(), | ||
| terraform.StatePull(), | ||
| terraform.Unbind(resourceType, resourceKey), | ||
| terraform.StatePush(), | ||
| ), | ||
| lock.Release(lock.GoalBind), | ||
|
andrewnester marked this conversation as resolved.
Outdated
|
||
| ), | ||
| }, | ||
| ) | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| package deployment | ||
|
|
||
| import ( | ||
| "fmt" | ||
|
|
||
| "github.com/databricks/cli/bundle" | ||
| "github.com/databricks/cli/bundle/deploy/terraform" | ||
| "github.com/databricks/cli/bundle/phases" | ||
| "github.com/databricks/cli/cmd/bundle/utils" | ||
| "github.com/databricks/cli/libs/cmdio" | ||
| "github.com/spf13/cobra" | ||
| ) | ||
|
|
||
| func newBindCommand() *cobra.Command { | ||
| cmd := &cobra.Command{ | ||
| Use: "bind KEY RESOURCE_ID", | ||
| Short: "Bind bundle-defined resources to existing resources", | ||
| Args: cobra.ExactArgs(2), | ||
| PreRunE: utils.ConfigureBundleWithVariables, | ||
| } | ||
|
|
||
| var autoApprove bool | ||
| var forceLock bool | ||
| cmd.Flags().BoolVar(&autoApprove, "auto-approve", false, "Automatically approve the binding") | ||
| cmd.Flags().BoolVar(&forceLock, "force-lock", false, "Force acquisition of deployment lock.") | ||
|
|
||
| cmd.RunE = func(cmd *cobra.Command, args []string) error { | ||
| b := bundle.Get(cmd.Context()) | ||
| r := b.Config.Resources | ||
| resource, err := r.FindResourceByConfigKey(args[0]) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| w := b.WorkspaceClient() | ||
| ctx := cmd.Context() | ||
| if !resource.Exists(ctx, w, args[1]) { | ||
| return fmt.Errorf("%s with an id '%s' is not found", resource.Type(), args[1]) | ||
| } | ||
|
|
||
| if !autoApprove { | ||
| answer, err := cmdio.AskYesOrNo(ctx, "Binding to existing resource means that the resource will be managed by the bundle which can lead to changes in the resource. Do you want to continue?") | ||
|
andrewnester marked this conversation as resolved.
Outdated
|
||
| if err != nil { | ||
| return err | ||
| } | ||
| if !answer { | ||
| return nil | ||
| } | ||
| } | ||
|
|
||
| b.Config.Bundle.Lock.Force = forceLock | ||
| return bundle.Apply(cmd.Context(), b, bundle.Seq( | ||
| phases.Initialize(), | ||
| phases.Bind(&terraform.BindOptions{ | ||
| ResourceType: resource.Type(), | ||
|
andrewnester marked this conversation as resolved.
Outdated
|
||
| ResourceKey: args[0], | ||
| ResourceId: args[1], | ||
| }), | ||
| )) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If this succeeds we should display a message (if in text output mode) to confirm it did. This can also include a call to action to hint at running a deploy next.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @juliacrawf-db Could you shine your light on how to best convey this?
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh no! I missed this ping! That string looks great. But wouldn't we want a similar error message in unbind.go if the unbinding fails? |
||
| } | ||
|
|
||
| return cmd | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| package deployment | ||
|
|
||
| import ( | ||
| "github.com/spf13/cobra" | ||
| ) | ||
|
|
||
| func NewDeploymentCommand() *cobra.Command { | ||
| cmd := &cobra.Command{ | ||
| Use: "deployment", | ||
| Short: "Deployment related commands", | ||
| Long: "Deployment related commands", | ||
| } | ||
|
|
||
| cmd.AddCommand(newBindCommand()) | ||
| cmd.AddCommand(newUnbindCommand()) | ||
| return cmd | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.