-
-
Notifications
You must be signed in to change notification settings - Fork 997
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
feat: exec
, run
commands implementation
#3723
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm getting pulled onto other things, but I thought I see enough that warrants changes before continuing with the review (I'm only like 37/206 through this review...). Will come back to this soon, but wanted to give you feedback early while I'm not looking at it.
.golangci.yml
Outdated
@@ -79,6 +79,8 @@ linters: | |||
- nolintlint | |||
- wrapcheck | |||
- varnamelen | |||
- recvcheck |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are we disabling this check? Shouldn't we have all the receiver types be consistent? I don't know why we'd want to mix and match pointers and non-pointers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At that time, the latest version of golangci-lint
1.62.2 did not have this fix. I just updated golangci-lint
, now it has. I will enable recvcheck
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, no, it is still not fixed in golangci-lint
pkg/log/level.go:83:6: the methods of "Level" use pointer receiver and non-pointer receiver. (recvcheck)
// UnmarshalText implements encoding.TextUnmarshaler.
func (level *Level) UnmarshalText(text []byte) error {
I will add a comment on why this check is disabled.
Usage: "A key=value attribute to override in a provider block as part of the aws-provider-patch command. May be specified multiple times.", | ||
}, | ||
}), | ||
} | ||
} | ||
|
||
func NewCommand(opts *options.TerragruntOptions) *cli.Command { | ||
return &cli.Command{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we also hide this command? Who cares about it now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I only moved the code and I do not know the answer. Technically, of course, it can be hidden.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Feel free to ignore for now, but we should get rid of it or hide it before 1.0. it's a waste of space in the CLI API.
}, | ||
Flags: NewFlags(opts, cmdOpts).Sort(), | ||
ErrorOnUndefinedFlag: true, | ||
Hidden: true, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could I get confirmation on why we're hiding the command? Are we looking to dark launch it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mentioned it in the slack:
The new
exec
andrun
commands are temporarily hidden from help until we thoroughly test and document them in order not to delay the merge intomain
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should I add a comment or make them visible?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What I would recommend is marking them as experiments.
The danger with just marking them as hidden is that we're updating a lot of documentation, etc and we have to in order for them to be used right.
By marking them as experiments and making them visible, we document both that they're not ready for production usage, and explain how they're supposed to be used.
UsageText: "terragrunt run [options] -- <tofu/terraform command>", | ||
Description: "Run a command, passing arguments to a wrapped tofu/terraform binary.\n\nThis is the explicit, and most flexible form of running an IaC update with Terragrunt. Shortcuts can be found in \"terragrunt --help\" for common use-cases.", | ||
Examples: []string{ | ||
"# Run a plan\nterragrunt run -- plan\n# Shortcut:\n# terragrunt plan", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we already have this shortcut supported?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shortcut is what we have now terragrunt plan
, it is still supported, but with a deprecation warning. Should I disable the warning?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ya, see this:
#3723 (comment)
cli/commands/run/command.go
Outdated
Name: CommandName, | ||
Usage: "Run an OpenTofu/Terraform command. Shortcuts for common `run` commands are provided below.", | ||
UsageText: "terragrunt run [options] -- <tofu/terraform command>", | ||
Description: "Run a command, passing arguments to a wrapped tofu/terraform binary.\n\nThis is the explicit, and most flexible form of running an IaC update with Terragrunt. Shortcuts can be found in \"terragrunt --help\" for common use-cases.", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Description: "Run a command, passing arguments to a wrapped tofu/terraform binary.\n\nThis is the explicit, and most flexible form of running an IaC update with Terragrunt. Shortcuts can be found in \"terragrunt --help\" for common use-cases.", | |
Description: "Run a command, passing arguments to an orchestrated tofu/terraform binary.\n\nThis is the explicit, and most flexible form of running an IaC command with Terragrunt. Shortcuts can be found in \"terragrunt --help\" for common use-cases.", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we already support shortcuts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Responded here.
Description: "Run a command, passing arguments to a wrapped tofu/terraform binary.\n\nThis is the explicit, and most flexible form of running an IaC update with Terragrunt. Shortcuts can be found in \"terragrunt --help\" for common use-cases.", | ||
Examples: []string{ | ||
"# Run a plan\nterragrunt run -- plan\n# Shortcut:\n# terragrunt plan", | ||
"# Run output with -json flag\nterragrunt run -- output -json\n# Shortcut:\n# terragrunt output -json", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we already have this shortcut supported?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Responded here.
@@ -57,3 +57,12 @@ type MaxRetriesExceeded struct { | |||
func (err MaxRetriesExceeded) Error() string { | |||
return fmt.Sprintf("Exhausted retries (%v) for command %v %v", err.Opts.RetryMaxAttempts, err.Opts.TerraformPath, strings.Join(err.Opts.TerraformCliArgs, " ")) | |||
} | |||
|
|||
type RunAllDisabledErr struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's this for?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is moved code, not mine. I found the following
terragrunt/cli/commands/run-all/action.go
Lines 14 to 30 in 54a810f
// Known terraform commands that are explicitly not supported in run-all due to the nature of the command. This is | |
// tracked as a map that maps the terraform command to the reasoning behind disallowing the command in run-all. | |
var runAllDisabledCommands = map[string]string{ | |
terraform.CommandNameImport: "terraform import should only be run against a single state representation to avoid injecting the wrong object in the wrong state representation.", | |
terraform.CommandNameTaint: "terraform taint should only be run against a single state representation to avoid using the wrong state address.", | |
terraform.CommandNameUntaint: "terraform untaint should only be run against a single state representation to avoid using the wrong state address.", | |
terraform.CommandNameConsole: "terraform console requires stdin, which is shared across all instances of run-all when multiple modules run concurrently.", | |
terraform.CommandNameForceUnlock: "lock IDs are unique per state representation and thus should not be run with run-all.", | |
// MAINTAINER'S NOTE: There are a few other commands that might not make sense, but we deliberately allow it for | |
// certain use cases that are documented here: | |
// - state : Supporting `state` with run-all could be useful for a mass pull and push operation, which can | |
// be done en masse with the use of relative pathing. | |
// - login / logout : Supporting `login` with run-all could be useful when used in conjunction with mise and | |
// multi-terraform version setups, where multiple terraform versions need to be configured. | |
// - version : Supporting `version` with run-all could be useful for sanity checking a multi-version setup. | |
} |
cli/flags/deprecated_flag.go
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is the file called deprecated_flag
now? Not a big deal, just a little strange.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What would you like it to be called?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It used to be called deprecated_flags.go
cli/flags/deprecated_flag.go
Outdated
|
||
// BoolWithDeprecatedFlag adds deprecated names with strict mode control for the given flag. | ||
// If `oldNames` is not specified, names are taken from the given `flag` with adding `terragrunt-/TERRAGRUNT_` prefixes. | ||
func BoolWithDeprecatedFlag(opts *options.TerragruntOptions, flag *cli.BoolFlag, oldNames ...string) cli.Flag { //nolint:ireturn |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not return cli.BoolFlag
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because it returns *Flag
struct.
cannot use &Flag{…} (value of type *Flag) as *"github.com/gruntwork-io/terragrunt/internal/cli".BoolFlag value in return statement [IncompatibleAssign]
I will replace cli.Flag with *Flag
cli/flags/deprecated_flag.go
Outdated
DeprecatedFlagNamePrefix = "terragrunt-" | ||
) | ||
|
||
// BoolWithDeprecatedFlag adds deprecated names with strict mode control for the given flag. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// BoolWithDeprecatedFlag adds deprecated names with strict mode control for the given flag. | |
// BoolWithDeprecatedFlag adds deprecated names when strict mode is disabled for the given flag. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure, it adds deprecated names regardless of strict mode settings. Strict mode only affects behavior, prohibits or warns not to use these aliases(flags).
@@ -126,6 +130,10 @@ var StrictControls = Controls{ | |||
Error: errors.Errorf("The `%s` command is no longer supported. Use `terragrunt run-all validate` instead.", ValidateAll), | |||
Warning: fmt.Sprintf("The `%s` command is deprecated and will be removed in a future version. Use `terragrunt run-all validate` instead.", ValidateAll), | |||
}, | |||
DefaultCommand: { | |||
Error: errors.New("The default command is no longer supported. Use `terragrunt run` instead."), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Error: errors.New("The default command is no longer supported. Use `terragrunt run` instead."), | |
Error: errors.New("Terragrunt no longer has a default command. Use `terragrunt run` to explicitly pass commands to OpenTofu/Terraform instead. e.g. `terragrunt run -- plan`"), |
It might be too much, but I think it would be really nice if we could use the users incorrect command as a basis for this.
For example:
$ terragrunt foo
ERROR: The command `foo` is not a valid Terragrunt command. Use `terragrunt run` to explicitly pass commands to OpenTofu/Terraform instead. e.g. `terragrunt run -- foo`
@@ -142,6 +150,7 @@ var StrictControls = Controls{ | |||
Error: errors.Errorf("The `--%s` flag is no longer supported. Use `--terragrunt-log-format=json` instead.", TfLogJSON), | |||
Warning: fmt.Sprintf("The `--%s` flag is deprecated and will be removed in a future version. Use `--terragrunt-log-format=json` instead.", TfLogJSON), | |||
}, | |||
RenamedFlag: {}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- TODO: Populate this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RenamedFlag
is a strict control for multiple flags, meaning it returns a message with different names. The current implementation of the strict control can not allow to do it. Therefore the message builder is moved to here.
I was playing with this functionality locally, and noticed these two things: $ terragrunt exec ls
08:53:02.755 ERROR target command not specified
08:53:02.758 ERROR Unable to determine underlying exit code, so Terragrunt will exit with error code 1 That should work, given that At the very least, a better error message should be thrown if we can't make it so that a user doesn't need $ terragrunt exec -- ls
08:44:45.451 WARN Detected that init is needed, but Auto-Init is disabled. Continuing with further actions, but subsequent terraform commands may fail.
main.tf
terragrunt.hcl I'm also seeing issues with the $ terragrunt run --all plan
08:57:59.202 ERROR stat ./terragrunt.hcl: no such file or directory
08:57:59.202 ERROR Unable to determine underlying exit code, so Terragrunt will exit with error code 1 $ terragrunt run-all plan
08:58:02.838 INFO The stack at . will be processed in the following order for command plan:
Group 1
- Module ./live/storage/external/first-external
- Module ./live/storage/internal/first-internal
08:58:02.880 INFO [live/storage/external/first-external] tofu: Initializing the backend...
08:58:02.880 INFO [live/storage/external/first-external] tofu: Initializing provider plugins...
08:58:02.880 INFO [live/storage/external/first-external] tofu: OpenTofu has been successfully initialized!
08:58:02.880 INFO [live/storage/external/first-external] tofu:
08:58:02.880 INFO [live/storage/external/first-external] tofu: You may now begin working with OpenTofu. Try running "tofu plan" to see
08:58:02.880 INFO [live/storage/external/first-external] tofu: any changes that are required for your infrastructure. All OpenTofu commands
08:58:02.880 INFO [live/storage/external/first-external] tofu: should now work.
08:58:02.880 INFO [live/storage/external/first-external] tofu: If you ever set or change modules or backend configuration for OpenTofu,
08:58:02.880 INFO [live/storage/external/first-external] tofu: rerun this command to reinitialize your working directory. If you forget, other
08:58:02.880 INFO [live/storage/external/first-external] tofu: commands will detect it and remind you to do so if necessary.
08:58:02.880 INFO [live/storage/internal/first-internal] tofu: Initializing the backend...
08:58:02.880 INFO [live/storage/internal/first-internal] tofu: Initializing provider plugins...
08:58:02.880 INFO [live/storage/internal/first-internal] tofu: OpenTofu has been successfully initialized!
08:58:02.880 INFO [live/storage/internal/first-internal] tofu:
08:58:02.880 INFO [live/storage/internal/first-internal] tofu: You may now begin working with OpenTofu. Try running "tofu plan" to see
08:58:02.880 INFO [live/storage/internal/first-internal] tofu: any changes that are required for your infrastructure. All OpenTofu commands
08:58:02.880 INFO [live/storage/internal/first-internal] tofu: should now work.
08:58:02.880 INFO [live/storage/internal/first-internal] tofu: If you ever set or change modules or backend configuration for OpenTofu,
08:58:02.880 INFO [live/storage/internal/first-internal] tofu: rerun this command to reinitialize your working directory. If you forget, other
08:58:02.880 INFO [live/storage/internal/first-internal] tofu: commands will detect it and remind you to do so if necessary.
08:58:02.901 STDOUT [live/storage/external/first-external] tofu: No changes. Your infrastructure matches the configuration.
08:58:02.901 STDOUT [live/storage/external/first-external] tofu: OpenTofu has compared your real infrastructure against your configuration and
08:58:02.901 STDOUT [live/storage/external/first-external] tofu: found no differences, so no changes are needed.
08:58:02.901 STDOUT [live/storage/internal/first-internal] tofu: No changes. Your infrastructure matches the configuration.
08:58:02.901 STDOUT [live/storage/internal/first-internal] tofu: OpenTofu has compared your real infrastructure against your configuration and
08:58:02.901 STDOUT [live/storage/internal/first-internal] tofu: found no differences, so no changes are needed. |
Another thing I'm noticing is that the help for both $ terragrunt run --help
OpenTofu has no command named "run".
To see all of OpenTofu's top-level commands, run:
tofu -help
12:09:13.675 ERROR Failed to execute "tofu run -help" in
OpenTofu has no command named "run".
To see all of OpenTofu's top-level commands, run:
tofu -help
exit status 1 $ terragrunt exec --help
OpenTofu has no command named "exec".
To see all of OpenTofu's top-level commands, run:
tofu -help
12:09:44.576 ERROR Failed to execute "tofu exec -help" in
OpenTofu has no command named "exec".
To see all of OpenTofu's top-level commands, run:
tofu -help
exit status 1 |
it works:
|
Ok, it will work.
What text should be displayed for the
|
Something like the following:
In general, we should aim to always do the following with our errors in order of priority:
|
Description
exec
,run
commands implementation.Relates to #3445 .
TODOs
Read the Gruntwork contribution guidelines.
Release Notes (draft)
Added / Removed / Updated [X].
Migration Guide