@@ -2,6 +2,7 @@ package config
2
2
3
3
import (
4
4
"fmt"
5
+ "github.com/mitchellh/mapstructure"
5
6
"os"
6
7
"path/filepath"
7
8
"reflect"
@@ -40,6 +41,8 @@ type TerragruntConfig struct {
40
41
TerragruntDependencies []Dependency
41
42
GenerateConfigs map [string ]codegen.GenerateConfig
42
43
RetryableErrors []string
44
+ RetryMaxAttempts * int
45
+ RetrySleepIntervalSec * int
43
46
44
47
// Indicates whether or not this is the result of a partial evaluation
45
48
IsPartial bool
@@ -52,21 +55,57 @@ func (conf *TerragruntConfig) String() string {
52
55
// terragruntConfigFile represents the configuration supported in a Terragrunt configuration file (i.e.
53
56
// terragrunt.hcl)
54
57
type terragruntConfigFile struct {
55
- Terraform * TerraformConfig `hcl:"terraform,block"`
56
- TerraformBinary * string `hcl:"terraform_binary,attr"`
57
- TerraformVersionConstraint * string `hcl:"terraform_version_constraint,attr"`
58
- TerragruntVersionConstraint * string `hcl:"terragrunt_version_constraint,attr"`
59
- Inputs * cty.Value `hcl:"inputs,attr"`
60
- Include * IncludeConfig `hcl:"include,block"`
61
- RemoteState * remoteStateConfigFile `hcl:"remote_state,block"`
62
- Dependencies * ModuleDependencies `hcl:"dependencies,block"`
63
- DownloadDir * string `hcl:"download_dir,attr"`
64
- PreventDestroy * bool `hcl:"prevent_destroy,attr"`
65
- Skip * bool `hcl:"skip,attr"`
66
- IamRole * string `hcl:"iam_role,attr"`
67
- TerragruntDependencies []Dependency `hcl:"dependency,block"`
68
- GenerateBlocks []terragruntGenerateBlock `hcl:"generate,block"`
69
- RetryableErrors []string `hcl:"retryable_errors,optional"`
58
+ Terraform * TerraformConfig `hcl:"terraform,block"`
59
+ TerraformBinary * string `hcl:"terraform_binary,attr"`
60
+ TerraformVersionConstraint * string `hcl:"terraform_version_constraint,attr"`
61
+ TerragruntVersionConstraint * string `hcl:"terragrunt_version_constraint,attr"`
62
+ Inputs * cty.Value `hcl:"inputs,attr"`
63
+ Include * IncludeConfig `hcl:"include,block"`
64
+
65
+ // We allow users to configure remote state (backend) via blocks:
66
+ //
67
+ // remote_state {
68
+ // backend = "s3"
69
+ // config = { ... }
70
+ // }
71
+ //
72
+ // Or as attributes:
73
+ //
74
+ // remote_state = {
75
+ // backend = "s3"
76
+ // config = { ... }
77
+ // }
78
+ RemoteState * remoteStateConfigFile `hcl:"remote_state,block"`
79
+ RemoteStateAttr * cty.Value `hcl:"remote_state,optional"`
80
+
81
+ Dependencies * ModuleDependencies `hcl:"dependencies,block"`
82
+ DownloadDir * string `hcl:"download_dir,attr"`
83
+ PreventDestroy * bool `hcl:"prevent_destroy,attr"`
84
+ Skip * bool `hcl:"skip,attr"`
85
+ IamRole * string `hcl:"iam_role,attr"`
86
+ TerragruntDependencies []Dependency `hcl:"dependency,block"`
87
+
88
+ // We allow users to configure code generation via blocks:
89
+ //
90
+ // generate "example" {
91
+ // path = "example.tf"
92
+ // contents = "example"
93
+ // }
94
+ //
95
+ // Or via attributes:
96
+ //
97
+ // generate = {
98
+ // example = {
99
+ // path = "example.tf"
100
+ // contents = "example"
101
+ // }
102
+ // }
103
+ GenerateAttrs * cty.Value `hcl:"generate,optional"`
104
+ GenerateBlocks []terragruntGenerateBlock `hcl:"generate,block"`
105
+
106
+ RetryableErrors []string `hcl:"retryable_errors,optional"`
107
+ RetryMaxAttempts * int `hcl:"retry_max_attempts,optional"`
108
+ RetrySleepIntervalSec * int `hcl:"retry_sleep_interval_sec,optional"`
70
109
71
110
// This struct is used for validating and parsing the entire terragrunt config. Since locals are evaluated in a
72
111
// completely separate cycle, it should not be evaluated here. Otherwise, we can't support self referencing other
@@ -135,11 +174,11 @@ type remoteStateConfigGenerate struct {
135
174
// through the codegen routine.
136
175
type terragruntGenerateBlock struct {
137
176
Name string `hcl:",label"`
138
- Path string `hcl:"path,attr"`
139
- IfExists string `hcl:"if_exists,attr"`
140
- CommentPrefix * string `hcl:"comment_prefix,attr"`
141
- Contents string `hcl:"contents,attr"`
142
- DisableSignature * bool `hcl:"disable_signature,attr"`
177
+ Path string `hcl:"path,attr" mapstructure:"path" `
178
+ IfExists string `hcl:"if_exists,attr" mapstructure:"if_exists" `
179
+ CommentPrefix * string `hcl:"comment_prefix,attr" mapstructure:"comment_prefix" `
180
+ Contents string `hcl:"contents,attr" mapstructure:"contents" `
181
+ DisableSignature * bool `hcl:"disable_signature,attr" mapstructure:"disable_signature" `
143
182
}
144
183
145
184
// IncludeConfig represents the configuration settings for a parent Terragrunt configuration file that you can
@@ -566,6 +605,14 @@ func mergeConfigWithIncludedConfig(config *TerragruntConfig, includedConfig *Ter
566
605
includedConfig .RetryableErrors = config .RetryableErrors
567
606
}
568
607
608
+ if config .RetryMaxAttempts != nil {
609
+ includedConfig .RetryMaxAttempts = config .RetryMaxAttempts
610
+ }
611
+
612
+ if config .RetrySleepIntervalSec != nil {
613
+ includedConfig .RetrySleepIntervalSec = config .RetrySleepIntervalSec
614
+ }
615
+
569
616
if config .TerragruntVersionConstraint != "" {
570
617
includedConfig .TerragruntVersionConstraint = config .TerragruntVersionConstraint
571
618
}
@@ -717,6 +764,20 @@ func convertToTerragruntConfig(
717
764
terragruntConfig .RemoteState = remoteState
718
765
}
719
766
767
+ if terragruntConfigFromFile .RemoteStateAttr != nil {
768
+ remoteStateMap , err := parseCtyValueToMap (* terragruntConfigFromFile .RemoteStateAttr )
769
+ if err != nil {
770
+ return nil , err
771
+ }
772
+
773
+ var remoteState * remote.RemoteState
774
+ if err := mapstructure .Decode (remoteStateMap , & remoteState ); err != nil {
775
+ return nil , err
776
+ }
777
+
778
+ terragruntConfig .RemoteState = remoteState
779
+ }
780
+
720
781
if err := terragruntConfigFromFile .Terraform .ValidateHooks (); err != nil {
721
782
return nil , err
722
783
}
@@ -733,6 +794,14 @@ func convertToTerragruntConfig(
733
794
terragruntConfig .RetryableErrors = terragruntConfigFromFile .RetryableErrors
734
795
}
735
796
797
+ if terragruntConfigFromFile .RetryMaxAttempts != nil {
798
+ terragruntConfig .RetryMaxAttempts = terragruntConfigFromFile .RetryMaxAttempts
799
+ }
800
+
801
+ if terragruntConfigFromFile .RetrySleepIntervalSec != nil {
802
+ terragruntConfig .RetrySleepIntervalSec = terragruntConfigFromFile .RetrySleepIntervalSec
803
+ }
804
+
736
805
if terragruntConfigFromFile .DownloadDir != nil {
737
806
terragruntConfig .DownloadDir = * terragruntConfigFromFile .DownloadDir
738
807
}
@@ -757,7 +826,26 @@ func convertToTerragruntConfig(
757
826
terragruntConfig .IamRole = * terragruntConfigFromFile .IamRole
758
827
}
759
828
760
- for _ , block := range terragruntConfigFromFile .GenerateBlocks {
829
+ generateBlocks := []terragruntGenerateBlock {}
830
+ generateBlocks = append (generateBlocks , terragruntConfigFromFile .GenerateBlocks ... )
831
+
832
+ if terragruntConfigFromFile .GenerateAttrs != nil {
833
+ generateMap , err := parseCtyValueToMap (* terragruntConfigFromFile .GenerateAttrs )
834
+ if err != nil {
835
+ return nil , err
836
+ }
837
+
838
+ for name , block := range generateMap {
839
+ var generateBlock terragruntGenerateBlock
840
+ if err := mapstructure .Decode (block , & generateBlock ); err != nil {
841
+ return nil , err
842
+ }
843
+ generateBlock .Name = name
844
+ generateBlocks = append (generateBlocks , generateBlock )
845
+ }
846
+ }
847
+
848
+ for _ , block := range generateBlocks {
761
849
ifExists , err := codegen .GenerateConfigExistsFromString (block .IfExists )
762
850
if err != nil {
763
851
return nil , err
0 commit comments