Skip to content

Commit dc154b2

Browse files
authored
Merge pull request #149 from fajpunk/output-all
Output all
2 parents 727b311 + 41fecb5 commit dc154b2

25 files changed

Lines changed: 241 additions & 67 deletions

README.md

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ The solution is to use the following features of Terragrunt:
362362
* Find parent helper
363363
* Relative path helper
364364
* Overriding included settings
365-
* The `spin-up` and `tear-down` commands
365+
* The `apply-all`, `destroy-all`, and `output-all` commands
366366
* Dependencies between modules
367367

368368
### Includes
@@ -646,7 +646,7 @@ terragrunt= {
646646
}
647647
```
648648

649-
### The spin-up and tear-down commands
649+
### The apply-all, destroy-all, and output-all commands
650650

651651
Let's say you have a single environment (e.g. `stage` or `prod`) that has a number of Terraform modules within it:
652652

@@ -678,21 +678,28 @@ There is one module to deploy a frontend-app, another to deploy a backend-app, a
678678
on. To deploy such an environment, you'd have to manually run `terragrunt apply` in each of the subfolders. How do you
679679
avoid this tedious and time-consuming process?
680680

681-
The answer is that you can use the `spin-up` command:
681+
The answer is that you can use the `apply-all` command:
682682

683683
```
684684
cd my-terraform-repo/stage
685-
terragrunt spin-up
685+
terragrunt apply-all
686686
```
687687

688688
When you run this command, Terragrunt will find all `terraform.tfvars` files in the subfolders of the current working
689-
directory that contain `terragrunt = { ... }` blocks, and run `terragrunt apply` in each one concurrently.
689+
directory that contain `terragrunt = { ... }` blocks, and run `terragrunt apply` in each one concurrently.
690690

691-
Similarly, to undeploy all the Terraform modules, you can use the `tear-down` command:
691+
Similarly, to undeploy all the Terraform modules, you can use the `destroy-all` command:
692692

693693
```
694694
cd my-terraform-repo/stage
695-
terragrunt tear-down
695+
terragrunt destroy-all
696+
```
697+
698+
Finally, to see the currently applied outputs of all of the subfolders, you can use the `output-all` command:
699+
700+
```
701+
cd my-terraform-repo/stage
702+
terragrunt output-all
696703
```
697704

698705
Of course, if your modules have dependencies between them—for example, you can't deploy the backend-app until the MySQL
@@ -762,17 +769,17 @@ terragrunt = {
762769
}
763770
```
764771

765-
Once you've specified the depenedencies in each `terraform.tfvars` file, when you run the `terragrunt spin-up` and
766-
`terragrunt tear-down`, Terragrunt will ensure that the dependencies are applied or destroyed, respectively, in the
767-
correct order. For the example at the start of this section, the order for the `spin-up` command would be:
772+
Once you've specified the depenedencies in each `terraform.tfvars` file, when you run the `terragrunt apply-all` and
773+
`terragrunt destroy-all`, Terragrunt will ensure that the dependencies are applied or destroyed, respectively, in the
774+
correct order. For the example at the start of this section, the order for the `apply-all` command would be:
768775

769776
1. Deploy the VPC
770777
1. Deploy MySQL and Redis in parallel
771778
1. Deploy the backend-app
772779
1. Deploy the frontend-app and search-app in parallel
773780

774781
If any of the modules fail to deploy, then Terragrunt will not attempt to deploy the modules that depend on them. Once
775-
you've fixed the error, it's usually safe to re-run the `spin-up` or `tear-down` command again, since it'll be a noop
782+
you've fixed the error, it's usually safe to re-run the `apply-all` or `destroy-all` command again, since it'll be a noop
776783
for the modules that already deployed successfully, and should only affect the ones that had an error the last time
777784
around.
778785

@@ -939,7 +946,7 @@ prefix `--terragrunt-`. The currently available options are:
939946
* `--terragrunt-non-interactive`: Don't show interactive user prompts. This will default the answer for all prompts to
940947
'yes'. Useful if you need to run Terragrunt in an automated setting (e.g. from a script).
941948
* `--terragrunt-working-dir`: Set the directory where Terragrunt should execute the `terraform` command. Default is the
942-
current working directory. Note that for the `spin-up` and `tear-down` directories, this parameter has a different
949+
current working directory. Note that for the `apply-all` and `destroy-all` directories, this parameter has a different
943950
meaning: Terragrunt will apply or destroy all the Terraform modules in the subfolders of the
944951
`terragrunt-working-dir`, running `terraform` in the root of each module it finds.
945952
* `--terragrunt-source`: Download Terraform configurations from the specified source into a temporary folder, and run

cli/args.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,15 @@ import (
1414

1515
// Parse command line options that are passed in for Terragrunt
1616
func ParseTerragruntOptions(cliContext *cli.Context) (*options.TerragruntOptions, error) {
17-
return parseTerragruntOptionsFromArgs(cliContext.Args())
17+
terragruntOptions, err := parseTerragruntOptionsFromArgs(cliContext.Args())
18+
if err != nil {
19+
return nil, err
20+
}
21+
22+
terragruntOptions.Writer = cliContext.App.Writer
23+
terragruntOptions.ErrWriter = cliContext.App.ErrWriter
24+
25+
return terragruntOptions, nil
1826
}
1927

2028
// TODO: replace the urfave CLI library with something else.

cli/args_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,8 @@ func TestFilterTerragruntArgs(t *testing.T) {
153153
{[]string{"foo", "--terragrunt-config", fmt.Sprintf("/some/path/%s", config.DefaultTerragruntConfigPath)}, []string{"foo"}},
154154
{[]string{"foo", "--terragrunt-non-interactive"}, []string{"foo"}},
155155
{[]string{"foo", "--terragrunt-non-interactive", "--bar", "--terragrunt-working-dir", "/some/path", "--baz", "--terragrunt-config", fmt.Sprintf("/some/path/%s", config.DefaultTerragruntConfigPath)}, []string{"foo", "--bar", "--baz"}},
156-
{[]string{"spin-up", "foo", "bar"}, []string{"foo", "bar"}},
157-
{[]string{"foo", "tear-down", "--foo", "--bar"}, []string{"foo", "--foo", "--bar"}},
156+
{[]string{"apply-all", "foo", "bar"}, []string{"foo", "bar"}},
157+
{[]string{"foo", "destroy-all", "--foo", "--bar"}, []string{"foo", "--foo", "--bar"}},
158158
}
159159

160160
for _, testCase := range testCases {

cli/cli_app.go

Lines changed: 72 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@ import (
55
"regexp"
66

77
"github.com/gruntwork-io/terragrunt/config"
8+
"github.com/gruntwork-io/terragrunt/configstack"
89
"github.com/gruntwork-io/terragrunt/errors"
910
"github.com/gruntwork-io/terragrunt/locks"
1011
"github.com/gruntwork-io/terragrunt/options"
1112
"github.com/gruntwork-io/terragrunt/remote"
1213
"github.com/gruntwork-io/terragrunt/shell"
13-
"github.com/gruntwork-io/terragrunt/spin"
1414
"github.com/gruntwork-io/terragrunt/util"
1515
"github.com/urfave/cli"
16+
"io"
1617
)
1718

1819
const OPT_TERRAGRUNT_CONFIG = "terragrunt-config"
@@ -27,10 +28,24 @@ var ALL_TERRAGRUNT_STRING_OPTS = []string{OPT_TERRAGRUNT_CONFIG, OPT_TERRAGRUNT_
2728

2829
const CMD_ACQUIRE_LOCK = "acquire-lock"
2930
const CMD_RELEASE_LOCK = "release-lock"
31+
32+
const CMD_APPLY_ALL = "apply-all"
33+
const CMD_DESTROY_ALL = "destroy-all"
34+
const CMD_OUTPUT_ALL = "output-all"
35+
36+
// CMD_SPIN_UP is deprecated.
3037
const CMD_SPIN_UP = "spin-up"
38+
39+
// CMD_TEAR_DOWN is deprecated.
3140
const CMD_TEAR_DOWN = "tear-down"
3241

33-
var MULTI_MODULE_COMMANDS = []string{CMD_SPIN_UP, CMD_TEAR_DOWN}
42+
var MULTI_MODULE_COMMANDS = []string{CMD_APPLY_ALL, CMD_DESTROY_ALL, CMD_OUTPUT_ALL}
43+
44+
// DEPRECATED_COMMANDS is a map of deprecated commands to the commands that replace them.
45+
var DEPRECATED_COMMANDS = map[string]string{
46+
CMD_SPIN_UP: CMD_APPLY_ALL,
47+
CMD_TEAR_DOWN: CMD_DESTROY_ALL,
48+
}
3449

3550
// Since Terragrunt is just a thin wrapper for Terraform, and we don't want to repeat every single Terraform command
3651
// in its definition, we don't quite fit into the model of any Go CLI library. Fortunately, urfave/cli allows us to
@@ -53,8 +68,9 @@ COMMANDS:
5368
remote push Acquire a lock and run 'terraform remote push'
5469
acquire-lock Acquire a long-term lock for these templates
5570
release-lock Release a long-term lock or a lock that failed to clean up
56-
spin-up Spin up a 'stack' by running 'terragrunt apply' in each subfolder
57-
tear-down Tear down a 'stack' by running 'terragrunt destroy' in each subfolder
71+
apply-all Apply a 'stack' by running 'terragrunt apply' in each subfolder
72+
output-all Display the outputs of a 'stack' by running 'terragrunt output' in each subfolder
73+
destroy-all Destroy a 'stack' by running 'terragrunt destroy' in each subfolder
5874
* Terragrunt forwards all other commands directly to Terraform
5975
6076
GLOBAL OPTIONS:
@@ -78,7 +94,7 @@ var MODULE_REGEX = regexp.MustCompile(`module ".+"`)
7894
const TERRAFORM_EXTENSION_GLOB = "*.tf"
7995

8096
// Create the Terragrunt CLI App
81-
func CreateTerragruntCli(version string) *cli.App {
97+
func CreateTerragruntCli(version string, writer io.Writer, errwriter io.Writer) *cli.App {
8298
cli.OsExiter = func(exitCode int) {
8399
// Do nothing. We just need to override this function, as the default value calls os.Exit, which
84100
// kills the app (or any automated test) dead in its tracks.
@@ -93,6 +109,8 @@ func CreateTerragruntCli(version string) *cli.App {
93109
app.Version = version
94110
app.Action = runApp
95111
app.Usage = "terragrunt <COMMAND>"
112+
app.Writer = writer
113+
app.ErrWriter = errwriter
96114
app.UsageText = fmt.Sprintf(`Terragrunt is a thin wrapper for [Terraform](https://www.terraform.io/) that supports locking
97115
via Amazon's DynamoDB and enforces best practices. Terragrunt forwards almost all commands, arguments, and options
98116
directly to Terraform, using whatever version of Terraform you already have installed. However, before running
@@ -119,11 +137,28 @@ func runApp(cliContext *cli.Context) (finalErr error) {
119137
return err
120138
}
121139

122-
if isMultiModuleCommand(cliContext.Args().First()) {
123-
return runMultiModuleCommand(cliContext.Args().First(), terragruntOptions)
124-
} else {
125-
return runTerragrunt(terragruntOptions)
140+
givenCommand := cliContext.Args().First()
141+
command := checkDeprecated(givenCommand)
142+
return runCommand(command, terragruntOptions)
143+
}
144+
145+
// checkDeprecated checks if the given command is deprecated. If so: prints a message and returns the new command.
146+
func checkDeprecated(command string) string {
147+
newCommand, deprecated := DEPRECATED_COMMANDS[command]
148+
if deprecated {
149+
fmt.Printf("%v is deprecated; running %v instead.\n", command, newCommand)
150+
return newCommand
151+
}
152+
return command
153+
}
154+
155+
// runCommand runs one or many terraform commands based on the type of
156+
// terragrunt command
157+
func runCommand(command string, terragruntOptions *options.TerragruntOptions) (finalEff error) {
158+
if isMultiModuleCommand(command) {
159+
return runMultiModuleCommand(command, terragruntOptions)
126160
}
161+
return runTerragrunt(terragruntOptions)
127162
}
128163

129164
// Run Terragrunt with the given options and CLI args. This will forward all the args directly to Terraform, enforcing
@@ -163,18 +198,20 @@ func runTerragrunt(terragruntOptions *options.TerragruntOptions) error {
163198
}
164199

165200
// Returns true if the command the user wants to execute is supposed to affect multiple Terraform modules, such as the
166-
// spin-up or tear-down command.
201+
// apply-all or destroy-all command.
167202
func isMultiModuleCommand(command string) bool {
168203
return util.ListContainsElement(MULTI_MODULE_COMMANDS, command)
169204
}
170205

171-
// Execute a command that affects multiple Terraform modules, such as the spin-up or tear-down command.
206+
// Execute a command that affects multiple Terraform modules, such as the apply-all or destroy-all command.
172207
func runMultiModuleCommand(command string, terragruntOptions *options.TerragruntOptions) error {
173208
switch command {
174-
case CMD_SPIN_UP:
175-
return spinUp(terragruntOptions)
176-
case CMD_TEAR_DOWN:
177-
return tearDown(terragruntOptions)
209+
case CMD_APPLY_ALL:
210+
return applyAll(terragruntOptions)
211+
case CMD_DESTROY_ALL:
212+
return destroyAll(terragruntOptions)
213+
case CMD_OUTPUT_ALL:
214+
return outputAll(terragruntOptions)
178215
default:
179216
return errors.WithStackTrace(UnrecognizedCommand(command))
180217
}
@@ -253,19 +290,19 @@ func runTerraformCommandWithLock(lock locks.Lock, terragruntOptions *options.Ter
253290

254291
// Spin up an entire "stack" by running 'terragrunt apply' in each subfolder, processing them in the right order based
255292
// on terraform_remote_state dependencies.
256-
func spinUp(terragruntOptions *options.TerragruntOptions) error {
257-
stack, err := spin.FindStackInSubfolders(terragruntOptions)
293+
func applyAll(terragruntOptions *options.TerragruntOptions) error {
294+
stack, err := configstack.FindStackInSubfolders(terragruntOptions)
258295
if err != nil {
259296
return err
260297
}
261298

262299
terragruntOptions.Logger.Printf("%s", stack.String())
263-
shouldSpinUp, err := shell.PromptUserForYesNo("Are you sure you want to run 'terragrunt apply' in each folder of the stack described above?", terragruntOptions)
300+
shouldApplyAll, err := shell.PromptUserForYesNo("Are you sure you want to run 'terragrunt apply' in each folder of the stack described above?", terragruntOptions)
264301
if err != nil {
265302
return err
266303
}
267304

268-
if shouldSpinUp {
305+
if shouldApplyAll {
269306
return stack.Apply(terragruntOptions)
270307
}
271308

@@ -274,25 +311,37 @@ func spinUp(terragruntOptions *options.TerragruntOptions) error {
274311

275312
// Tear down an entire "stack" by running 'terragrunt destroy' in each subfolder, processing them in the right order
276313
// based on terraform_remote_state dependencies.
277-
func tearDown(terragruntOptions *options.TerragruntOptions) error {
278-
stack, err := spin.FindStackInSubfolders(terragruntOptions)
314+
func destroyAll(terragruntOptions *options.TerragruntOptions) error {
315+
stack, err := configstack.FindStackInSubfolders(terragruntOptions)
279316
if err != nil {
280317
return err
281318
}
282319

283320
terragruntOptions.Logger.Printf("%s", stack.String())
284-
shouldTearDown, err := shell.PromptUserForYesNo("WARNING: Are you sure you want to run `terragrunt destroy` in each folder of the stack described above? There is no undo!", terragruntOptions)
321+
shouldDestroyAll, err := shell.PromptUserForYesNo("WARNING: Are you sure you want to run `terragrunt destroy` in each folder of the stack described above? There is no undo!", terragruntOptions)
285322
if err != nil {
286323
return err
287324
}
288325

289-
if shouldTearDown {
326+
if shouldDestroyAll {
290327
return stack.Destroy(terragruntOptions)
291328
}
292329

293330
return nil
294331
}
295332

333+
// outputAll prints the outputs from all configuration in a stack, in the order
334+
// specified in the terraform_remote_state dependencies
335+
func outputAll(terragruntOptions *options.TerragruntOptions) error {
336+
stack, err := configstack.FindStackInSubfolders(terragruntOptions)
337+
if err != nil {
338+
return err
339+
}
340+
341+
terragruntOptions.Logger.Printf("%s", stack.String())
342+
return stack.Output(terragruntOptions)
343+
}
344+
296345
// Acquire a lock. This can be useful for locking down a deploy for a long time, such as during a major deployment.
297346
func acquireLock(lock locks.Lock, terragruntOptions *options.TerragruntOptions) error {
298347
shouldAcquireLock, err := shell.PromptUserForYesNo("Are you sure you want to acquire a long-term lock?", terragruntOptions)

spin/graph.go renamed to configstack/graph.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package spin
1+
package configstack
22

33
import (
44
"github.com/gruntwork-io/terragrunt/errors"
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package spin
1+
package configstack
22

33
import (
44
"github.com/gruntwork-io/terragrunt/errors"

spin/module.go renamed to configstack/module.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package spin
1+
package configstack
22

33
import (
44
"fmt"
@@ -89,7 +89,7 @@ func resolveTerraformModule(terragruntConfigPath string, terragruntOptions *opti
8989
// Look through the dependencies of the modules in the given map and resolve the "external" dependency paths listed in
9090
// each modules config (i.e. those dependencies not in the given list of Terragrunt config canonical file paths).
9191
// These external dependencies are outside of the current working directory, which means they may not be part of the
92-
// environment the user is trying to spin-up or tear down. Therefore, this method also confirms whether the user wants
92+
// environment the user is trying to apply-all or destroy-all. Therefore, this method also confirms whether the user wants
9393
// to actually apply those dependencies or just assume they are already applied. Note that this method will NOT fill in
9494
// the Dependencies field of the TerraformModule struct (see the crosslinkDependencies method for that).
9595
func resolveExternalDependenciesForModules(canonicalTerragruntConfigPaths []string, moduleMap map[string]*TerraformModule, terragruntOptions *options.TerragruntOptions) (map[string]*TerraformModule, error) {
@@ -122,7 +122,7 @@ func resolveExternalDependenciesForModules(canonicalTerragruntConfigPaths []stri
122122
// Look through the dependencies of the given module and resolve the "external" dependency paths listed in the module's
123123
// config (i.e. those dependencies not in the given list of Terragrunt config canonical file paths). These external
124124
// dependencies are outside of the current working directory, which means they may not be part of the environment the
125-
// user is trying to spin-up or tear down. Note that this method will NOT fill in the Dependencies field of the
125+
// user is trying to apply-all or destroy-all. Note that this method will NOT fill in the Dependencies field of the
126126
// TerraformModule struct (see the crosslinkDependencies method for that).
127127
func resolveExternalDependenciesForModule(module *TerraformModule, canonicalTerragruntConfigPaths []string, terragruntOptions *options.TerragruntOptions) (map[string]*TerraformModule, error) {
128128
if module.Config.Dependencies == nil || len(module.Config.Dependencies.Paths) == 0 {
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package spin
1+
package configstack
22

33
import (
44
"github.com/gruntwork-io/terragrunt/config"
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package spin
1+
package configstack
22

33
import (
44
"fmt"
@@ -7,7 +7,7 @@ import (
77
"sync"
88
)
99

10-
// Represents the status of a module that we are trying to apply as part of the spin-up or tear-down command
10+
// Represents the status of a module that we are trying to apply as part of the apply-all or destroy-all command
1111
type ModuleStatus int
1212

1313
const (
@@ -16,7 +16,7 @@ const (
1616
Finished
1717
)
1818

19-
// Represents a module we are trying to "run" (i.e. apply or destroy) as part of the spin-up or tear-down command
19+
// Represents a module we are trying to "run" (i.e. apply or destroy) as part of the apply-all or destroy-all command
2020
type runningModule struct {
2121
Module *TerraformModule
2222
Status ModuleStatus
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package spin
1+
package configstack
22

33
import (
44
"fmt"

0 commit comments

Comments
 (0)