Terragrunt: Repo Structure V1

22 minute read

Description:

So recently I have been looking at using Terragrunt to manage my terraform code dynamically based on environment similar to my Data Lookup module. This post is a list of the steps taken to get my my initial (working!) version of my repo using Github Actions/Terragrunt.

Note: You can see the code for this post on my Github repo. Github Actions are here

To Resolve:

  1. First, for readers unaware, please see my subscription setup

    • To setup Terragrunt initially, you just start with a file structure that is completely up to you. I chose environment => subscription => region => application. This sets my file structure like the following as seen here:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    
    C:.
    │   global.hcl
    │   root.hcl
    │
    ├───nonprod
    │   │   env.hcl
    │   │
    │   ├───hub
    │   │   │   sub.hcl
    │   │   │
    │   │   ├───east
    │   │   │   │   region.hcl
    │   │   │   │
    │   │   │   └───deployment
    │   │   │           terragrunt.hcl
    │   │   │
    │   │   └───southcentral
    │   │       │   region.hcl
    │   │       │
    │   │       └───deployment
    │   │               terragrunt.hcl
    │   │
    │   └───spoke
    │       │   sub.hcl
    │       │
    │       ├───east
    │       │   │   region.hcl
    │       │   │
    │       │   └───deployment
    │       │           terragrunt.hcl
    │       │
    │       └───southcentral
    │           │   region.hcl
    │           │   
    │           └───deployment
    │                   terragrunt.hcl
    │
    └───prod
       │   env.hcl
       │
       ├───hub
       │   │   sub.hcl
       │   │
       │   ├───east
       │   │   │   region.hcl
       │   │   │
       │   │   └───deployment
       │   │           terragrunt.hcl
       │   │
       │   └───southcentral
       │       │   region.hcl
       │       │
       │       └───deployment
       │               terragrunt.hcl
       │
       └───spoke
          │   sub.hcl
          │
          ├───east
          │   │   region.hcl
          │   │
          │   └───deployment
          │           terragrunt.hcl
          │
          └───southcentral
                │   region.hcl
                │
                └───deployment
                      terragrunt.hcl
    
  2. So after creating the files, it is best to see what is happening by breaking them down by the directory level:

    • Level 1: global.hcl => Defines some local variables that will be inherited downwards to all subscriptions, environments, regions, ect. as well as imports environmental vars.

    • Level 1: root.hcl => currently only has a generate block which is a Terragrunt native command that dynamically generates a provider.tf at run time. I’m sure there is more to this, this just my initial version. We will import this file later in the file structure.

    • Level 2: env.hcl => These are placed in each sub folder and are environment level variables.

    • Level 3: sub.hcl => These are placed in each sub folder and are subscription level variables.

    • Level 4: region.hcl => These are placed in each sub folder and are region level variables.

    • Level 5: terragrunt.hcl => You will see this file placed 8 times - one for each environment, subscription, and region. The deployment is just an arbitrary name for an application deployment. I could have done weather.io, bob, or my-app if I wanted.

  3. So we have level 5 terragrunt.hcl files in 8 places with the same code in each, I thought the point was to be DRY (Don’t repeat yourself), sounds like you are! All I can say is “give me a break, I’m still learning! lol” But seriously, I think what is happening will reveal itself to be useful if we just continue on okay? UPDATE: This is fixed and covered in Terragrunt Repo Structure V2.

  4. OK, so let’s break down the sections in terragrunt.hcl.

    • First, it creates a dictionary of all the locals in the file system above it. This is incredibly powerful already because we can have 1, 2, or 23 levels of folders above and extract them locally! We can then mix and match to make our own custom locals.

    • Next, we include "root_config" to import that root hcl file that dynmically generates our provider.tf. Then we generate our own backend.tf.

    • Something really cool about this section is the path_relative_to_include() function for the blob location. This will actually create your state file based on your file system tree in your storage account! Really:

    • terragrunt-tree

    • Anyways, the next section is the most important: You call terraform with a source path and then you call inputs which is where you inject those locals to pass to the module.

  5. OK, so we are dynamically passing variables to modules, I want to see this in action! OK, let’s look at the build and see if we can dissect it:

    • First, we are using autero1/action-terragrunt@v1.1.0 to install terragrunt after terraform, cool.

    • Next, we are running its run-all plan to pass environmental variables to Terragrunt which will then pass them to terraform later on.

    • In that same command we are doing something that is real important for you to understand, we are passing a directory for the --terragrunt-working-dir. This is important because if you don’t pay attention here, you could run plans against all your subscriptions at the same time! Not a big deal since it is a plan but one of the main selling points of terragrunt. Let’s just run this once for now to see what happens…

    • NOTE: Unfortunately, I have to paste the logs here because Github deletes them, sorry, just scroll!

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    
    Prepare all required actions
    Getting action download info
    Download action repository 'actions/checkout@v3' (SHA:ac593985615ec2ede58e132d2e21d2b1cbd6127c)
    Download action repository 'hashicorp/setup-terraform@v2' (SHA:633666f66e0061ca3b725c73b2ec20cd13a8fdd1)
    Download action repository 'autero1/action-terragrunt@v1.1.0' (SHA:a99cd7d0443c46ba89b09d68a8db6bbcf8932ae0)
    Run ./.github/workflows/2023-01-04-terragrunt-repo-structure-v1/build
    Run actions/checkout@v3
    Syncing repository: gerryw1389/terraform-examples
    Getting Git version info
    Temporarily overriding HOME='/home/runner/work/_temp/15219c16-2bed-426f-9d25-2db8be9aa4cf' before making global git config changes
    Adding repository directory to the temporary git global config as a safe directory
    /usr/bin/git config --global --add safe.directory /home/runner/work/terraform-examples/terraform-examples
    /usr/bin/git config --local --get remote.origin.url
    https://github.com/gerryw1389/terraform-examples
    Removing previously created refs, to avoid conflicts
    Cleaning the repository
    Disabling automatic garbage collection
    Setting up auth
    Fetching the repository
    Determining the checkout info
    Checking out the ref
    /usr/bin/git log -1 --format='%H'
    '9811f927faa9adf513ab30272007fe68c70f3336'
    Run hashicorp/setup-terraform@v2
    /usr/bin/unzip -o -q /home/runner/work/_temp/aeca15f7-48be-4f9a-812f-61d0c68d91d9
    Run autero1/action-terragrunt@v1.1.0
    [INFO] TerragruntVersion: v0.42.7
    [INFO] Setting up Terragrunt version: 'v0.42.7'
    [INFO] Downloading from: 'https://github.com/gruntwork-io/terragrunt/releases/download/v0.42.7/terragrunt_linux_amd64'
    [INFO] Terragrunt version: 'v0.42.7' has been cached at /opt/hostedtoolcache/terragrunt/0.42.7/x64/terragrunt
    Warning: The `set-output` command is deprecated and will be disabled soon. Please upgrade to using Environment Files. For more information see: https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/
    Run cd 2023-01-04-terragrunt-repo-structure-v1
    time=2023-01-13T22:53:25Z level=info msg=The stack at infra-config/nonprod/hub/east/deployment will be processed in the following order for command plan:
    Group 1
    - Module /home/runner/work/terraform-examples/terraform-examples/2023-01-04-terragrunt-repo-structure-v1/infra-config/nonprod/hub/east/deployment
    
    
    time=2023-01-13T22:53:26Z level=warning msg=No double-slash (//) found in source URL /home/runner/work/terraform-examples/terraform-examples/2023-01-04-terragrunt-repo-structure-v1/infra. Relative paths in downloaded Terraform code may not work. prefix=[/home/runner/work/terraform-examples/terraform-examples/2023-01-04-terragrunt-repo-structure-v1/infra-config/nonprod/hub/east/deployment] 
    /home/runner/work/_temp/f5b30077-5be2-4d37-a73b-8dbd96e56e3c/terraform-bin init
    
    Initializing the backend...
    
    Successfully configured the backend "azurerm"! Terraform will automatically
    use this backend unless the backend configuration changes.
    
    Initializing provider plugins...
    - Finding hashicorp/azurerm versions matching "3.30.0"...
    - Installing hashicorp/azurerm v3.30.0...
    - Installed hashicorp/azurerm v3.30.0 (signed by HashiCorp)
    
    Terraform has created a lock file .terraform.lock.hcl to record the provider
    selections it made above. Include this file in your version control repository
    so that Terraform can guarantee to make the same selections by default when
    you run "terraform init" in the future.
    
    Terraform has been successfully initialized!
    
    You may now begin working with Terraform. Try running "terraform plan" to see
    any changes that are required for your infrastructure. All Terraform commands
    should now work.
    
    If you ever set or change modules or backend configuration for Terraform,
    rerun this command to reinitialize your working directory. If you forget, other
    commands will detect it and remind you to do so if necessary.
    /home/runner/work/_temp/f5b30077-5be2-4d37-a73b-8dbd96e56e3c/terraform-bin plan -input=false
    
    Terraform used the selected providers to generate the following execution
    plan. Resource actions are indicated with the following symbols:
    + create
    
    Terraform will perform the following actions:
    
    # azurerm_resource_group.rg will be created
    + resource "azurerm_resource_group" "rg" {
          + id       = (known after apply)
          + location = "eastus"
          + name     = "aa-dev-eus-mgmt-rg"
          + tags     = {
             + "App_Contact" = "gerry@automationadmin.com"
             + "CostCenter"  = "100"
             + "Description" = "Automation Admin Terraform POC"
             + "Environment" = "dev"
             + "Owner"       = "Automation Admin"
          }
       }
    
    Plan: 1 to add, 0 to change, 0 to destroy.
    
    ─────────────────────────────────────────────────────────────────────────────
    
    Note: You didn't use the -out option to save this plan, so Terraform can't
    guarantee to take exactly these actions if you run "terraform apply" now.
    -01-13T22:53:37Z level=info msg=[command]/home/runner/work/_temp/f5b30077-5be2-4d37-a73b-8dbd96e56e3c/terraform-bin init
    
    Initializing the backend...
    
    Successfully configured the backend "azurerm"! Terraform will automatically
    use this backend unless the backend configuration changes.
    
    Initializing provider plugins...
    - Finding hashicorp/azurerm versions matching "3.30.0"...
    - Installing hashicorp/azurerm v3.30.0...
    - Installed hashicorp/azurerm v3.30.0 (signed by HashiCorp)
    
    Terraform has created a lock file .terraform.lock.hcl to record the provider
    selections it made above. Include this file in your version control repository
    so that Terraform can guarantee to make the same selections by default when
    you run "terraform init" in the future.
    
    Terraform has been successfully initialized!
    
    You may now begin working with Terraform. Try running "terraform plan" to see
    any changes that are required for your infrastructure. All Terraform commands
    should now work.
    
    If you ever set or change modules or backend configuration for Terraform,
    rerun this command to reinitialize your working directory. If you forget, other
    commands will detect it and remind you to do so if necessary.
    
    
    • OK, success! It is going to build a Resource Group according to the inputs I passed it in infra-config/nonprod/hub/east/deployment. Lets look at its terragrunt.hcl

    • First, from the output, we can see it is creating a Resource Group called “aa-dev-eus-mgmt-rg”. Is this right?
    • According to main.tf the name expands "aa-${var.env_stage_abbr}-${var.region_abbr}-mgmt-rg"
    • Well var.env_stage_abbr is under the ./nonprod folder so it should be dev as we expect
    • Well var.region_abbr is under the ./east folder so it should be eus as we expect
    • OK so that is a lot of work for what it is, maybe not use Terragrunt?
  6. Well hold on, first let’s try a different environment/region and see what happens. Simply changing --terragrunt-working-dir infra-config/nonprod/hub/east/deployment to --terragrunt-working-dir infra-config/prod/hub/southcentral/deployment gives us "aa-prod-scus-mgmt-rg", wowza, that’s pretty cool!

  7. OK, so let’s talk about what will happen if we execute it from higher up? Well, let’s try. Changing --terragrunt-working-dir infra-config/prod/hub/southcentral/deployment to --terragrunt-working-dir infra-config/prod shows it will create 4 Resource Groups at the same time in each subscription! NOTE: Unfortunately, I have to paste the logs here because Github deletes them, sorry, just scroll!

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    
    Prepare all required actions
    Getting action download info
    Download action repository 'actions/checkout@v3' (SHA:ac593985615ec2ede58e132d2e21d2b1cbd6127c)
    Download action repository 'hashicorp/setup-terraform@v2' (SHA:633666f66e0061ca3b725c73b2ec20cd13a8fdd1)
    Download action repository 'autero1/action-terragrunt@v1.1.0' (SHA:a99cd7d0443c46ba89b09d68a8db6bbcf8932ae0)
    Run ./.github/workflows/2023-01-04-terragrunt-repo-structure-v1/build
    Run actions/checkout@v3
    Syncing repository: gerryw1389/terraform-examples
    Getting Git version info
    Temporarily overriding HOME='/home/runner/work/_temp/5e4c1666-90be-4607-81d3-ee6fba5d2f95' before making global git config changes
    Adding repository directory to the temporary git global config as a safe directory
    /usr/bin/git config --global --add safe.directory /home/runner/work/terraform-examples/terraform-examples
    /usr/bin/git config --local --get remote.origin.url
    https://github.com/gerryw1389/terraform-examples
    Removing previously created refs, to avoid conflicts
    Cleaning the repository
    Disabling automatic garbage collection
    Setting up auth
    Fetching the repository
    Determining the checkout info
    Checking out the ref
    /usr/bin/git log -1 --format='%H'
    '06e88633f924d9935a6c943810b95ddd43c05827'
    Run hashicorp/setup-terraform@v2
    /usr/bin/unzip -o -q /home/runner/work/_temp/c3831059-87ba-4596-8225-12dfd0aff9df
    Run autero1/action-terragrunt@v1.1.0
    [INFO] TerragruntVersion: v0.42.7
    [INFO] Setting up Terragrunt version: 'v0.42.7'
    [INFO] Downloading from: 'https://github.com/gruntwork-io/terragrunt/releases/download/v0.42.7/terragrunt_linux_amd64'
    [INFO] Terragrunt version: 'v0.42.7' has been cached at /opt/hostedtoolcache/terragrunt/0.42.7/x64/terragrunt
    Warning: The `set-output` command is deprecated and will be disabled soon. Please upgrade to using Environment Files. For more information see: https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/
    Run cd 2023-01-04-terragrunt-repo-structure-v1
    time=2023-01-14T00:25:31Z level=info msg=The stack at infra-config/prod will be processed in the following order for command plan:
    Group 1
    - Module /home/runner/work/terraform-examples/terraform-examples/2023-01-04-terragrunt-repo-structure-v1/infra-config/prod/hub/east/deployment
    - Module /home/runner/work/terraform-examples/terraform-examples/2023-01-04-terragrunt-repo-structure-v1/infra-config/prod/hub/southcentral/deployment
    - Module /home/runner/work/terraform-examples/terraform-examples/2023-01-04-terragrunt-repo-structure-v1/infra-config/prod/spoke/east/deployment
    - Module /home/runner/work/terraform-examples/terraform-examples/2023-01-04-terragrunt-repo-structure-v1/infra-config/prod/spoke/southcentral/deployment
    
    
    time=2023-01-14T00:25:33Z level=warning msg=No double-slash (//) found in source URL /home/runner/work/terraform-examples/terraform-examples/2023-01-04-terragrunt-repo-structure-v1/infra. Relative paths in downloaded Terraform code may not work. prefix=[/home/runner/work/terraform-examples/terraform-examples/2023-01-04-terragrunt-repo-structure-v1/infra-config/prod/spoke/southcentral/deployment] 
    time=2023-01-14T00:25:33Z level=warning msg=No double-slash (//) found in source URL /home/runner/work/terraform-examples/terraform-examples/2023-01-04-terragrunt-repo-structure-v1/infra. Relative paths in downloaded Terraform code may not work. prefix=[/home/runner/work/terraform-examples/terraform-examples/2023-01-04-terragrunt-repo-structure-v1/infra-config/prod/spoke/east/deployment] 
    time=2023-01-14T00:25:33Z level=warning msg=No double-slash (//) found in source URL /home/runner/work/terraform-examples/terraform-examples/2023-01-04-terragrunt-repo-structure-v1/infra. Relative paths in downloaded Terraform code may not work. prefix=[/home/runner/work/terraform-examples/terraform-examples/2023-01-04-terragrunt-repo-structure-v1/infra-config/prod/hub/southcentral/deployment] 
    /home/runner/work/_temp/c3c0f6cb-7901-4fd2-b79b-282c6a920406/terraform-bin init
    /home/runner/work/_temp/c3c0f6cb-7901-4fd2-b79b-282c6a920406/terraform-bin init
    time=2023-01-14T00:25:34Z level=warning msg=No double-slash (//) found in source URL /home/runner/work/terraform-examples/terraform-examples/2023-01-04-terragrunt-repo-structure-v1/infra. Relative paths in downloaded Terraform code may not work. prefix=[/home/runner/work/terraform-examples/terraform-examples/2023-01-04-terragrunt-repo-structure-v1/infra-config/prod/hub/east/deployment] 
    
    Initializing the backend...
    
    Initializing the backend...
    /home/runner/work/_temp/c3c0f6cb-7901-4fd2-b79b-282c6a920406/terraform-bin init
    /home/runner/work/_temp/c3c0f6cb-7901-4fd2-b79b-282c6a920406/terraform-bin init
    
    Initializing the backend...
    
    Initializing the backend...
    
    Successfully configured the backend "azurerm"! Terraform will automatically
    use this backend unless the backend configuration changes.
    
    Successfully configured the backend "azurerm"! Terraform will automatically
    use this backend unless the backend configuration changes.
    
    Successfully configured the backend "azurerm"! Terraform will automatically
    use this backend unless the backend configuration changes.
    
    Successfully configured the backend "azurerm"! Terraform will automatically
    use this backend unless the backend configuration changes.
    
    Initializing provider plugins...
    - Finding hashicorp/azurerm versions matching "3.30.0"...
    
    Initializing provider plugins...
    - Finding hashicorp/azurerm versions matching "3.30.0"...
    
    Initializing provider plugins...
    - Finding hashicorp/azurerm versions matching "3.30.0"...
    
    Initializing provider plugins...
    - Finding hashicorp/azurerm versions matching "3.30.0"...
    - Installing hashicorp/azurerm v3.30.0...
    - Installing hashicorp/azurerm v3.30.0...
    - Installing hashicorp/azurerm v3.30.0...
    - Installing hashicorp/azurerm v3.30.0...
    - Installed hashicorp/azurerm v3.30.0 (signed by HashiCorp)
    
    Terraform has created a lock file .terraform.lock.hcl to record the provider
    selections it made above. Include this file in your version control repository
    so that Terraform can guarantee to make the same selections by default when
    you run "terraform init" in the future.
    
    Terraform has been successfully initialized!
    
    You may now begin working with Terraform. Try running "terraform plan" to see
    any changes that are required for your infrastructure. All Terraform commands
    should now work.
    
    If you ever set or change modules or backend configuration for Terraform,
    rerun this command to reinitialize your working directory. If you forget, other
    commands will detect it and remind you to do so if necessary.
    - Installed hashicorp/azurerm v3.30.0 (signed by HashiCorp)
    
    Terraform has created a lock file .terraform.lock.hcl to record the provider
    selections it made above. Include this file in your version control repository
    so that Terraform can guarantee to make the same selections by default when
    you run "terraform init" in the future.
    
    Terraform has been successfully initialized!
    
    You may now begin working with Terraform. Try running "terraform plan" to see
    any changes that are required for your infrastructure. All Terraform commands
    should now work.
    
    If you ever set or change modules or backend configuration for Terraform,
    rerun this command to reinitialize your working directory. If you forget, other
    commands will detect it and remind you to do so if necessary.
    /home/runner/work/_temp/c3c0f6cb-7901-4fd2-b79b-282c6a920406/terraform-bin plan -input=false
    /home/runner/work/_temp/c3c0f6cb-7901-4fd2-b79b-282c6a920406/terraform-bin plan -input=false
    - Installed hashicorp/azurerm v3.30.0 (signed by HashiCorp)
    
    Terraform has created a lock file .terraform.lock.hcl to record the provider
    selections it made above. Include this file in your version control repository
    so that Terraform can guarantee to make the same selections by default when
    you run "terraform init" in the future.
    
    Terraform has been successfully initialized!
    
    You may now begin working with Terraform. Try running "terraform plan" to see
    any changes that are required for your infrastructure. All Terraform commands
    should now work.
    
    If you ever set or change modules or backend configuration for Terraform,
    rerun this command to reinitialize your working directory. If you forget, other
    commands will detect it and remind you to do so if necessary.
    - Installed hashicorp/azurerm v3.30.0 (signed by HashiCorp)
    
    Terraform has created a lock file .terraform.lock.hcl to record the provider
    selections it made above. Include this file in your version control repository
    so that Terraform can guarantee to make the same selections by default when
    you run "terraform init" in the future.
    
    Terraform has been successfully initialized!
    
    You may now begin working with Terraform. Try running "terraform plan" to see
    any changes that are required for your infrastructure. All Terraform commands
    should now work.
    
    If you ever set or change modules or backend configuration for Terraform,
    rerun this command to reinitialize your working directory. If you forget, other
    commands will detect it and remind you to do so if necessary.
    /home/runner/work/_temp/c3c0f6cb-7901-4fd2-b79b-282c6a920406/terraform-bin plan -input=false
    /home/runner/work/_temp/c3c0f6cb-7901-4fd2-b79b-282c6a920406/terraform-bin plan -input=false
    
    Terraform used the selected providers to generate the following execution
    plan. Resource actions are indicated with the following symbols:
    + create
    
    Terraform will perform the following actions:
    
    # azurerm_resource_group.rg will be created
    + resource "azurerm_resource_group" "rg" {
          + id       = (known after apply)
          + location = "eastus"
          + name     = "aa-prod-eus-mgmt-rg"
          + tags     = {
             + "App_Contact" = "gerry@automationadmin.com"
             + "CostCenter"  = "100"
             + "Description" = "Automation Admin Terraform POC"
             + "Environment" = "prod"
             + "Owner"       = "Automation Admin"
          }
       }
    
    Plan: 1 to add, 0 to change, 0 to destroy.
    
    ─────────────────────────────────────────────────────────────────────────────
    
    Note: You didn't use the -out option to save this plan, so Terraform can't
    guarantee to take exactly these actions if you run "terraform apply" now.
    
    Terraform used the selected providers to generate the following execution
    plan. Resource actions are indicated with the following symbols:
    + create
    
    Terraform will perform the following actions:
    
    # azurerm_resource_group.rg will be created
    + resource "azurerm_resource_group" "rg" {
          + id       = (known after apply)
          + location = "eastus"
          + name     = "aa-prod-eus-mgmt-rg"
          + tags     = {
             + "App_Contact" = "gerry@automationadmin.com"
             + "CostCenter"  = "100"
             + "Description" = "Automation Admin Terraform POC"
             + "Environment" = "prod"
             + "Owner"       = "Automation Admin"
          }
       }
    
    Plan: 1 to add, 0 to change, 0 to destroy.
    
    ─────────────────────────────────────────────────────────────────────────────
    
    Note: You didn't use the -out option to save this plan, so Terraform can't
    guarantee to take exactly these actions if you run "terraform apply" now.
    
    Terraform used the selected providers to generate the following execution
    plan. Resource actions are indicated with the following symbols:
    + create
    
    Terraform will perform the following actions:
    
    # azurerm_resource_group.rg will be created
    + resource "azurerm_resource_group" "rg" {
          + id       = (known after apply)
          + location = "southcentralus"
          + name     = "aa-prod-scus-mgmt-rg"
          + tags     = {
             + "App_Contact" = "gerry@automationadmin.com"
             + "CostCenter"  = "100"
             + "Description" = "Automation Admin Terraform POC"
             + "Environment" = "prod"
             + "Owner"       = "Automation Admin"
          }
       }
    
    Plan: 1 to add, 0 to change, 0 to destroy.
    
    ─────────────────────────────────────────────────────────────────────────────
    
    Note: You didn't use the -out option to save this plan, so Terraform can't
    guarantee to take exactly these actions if you run "terraform apply" now.
    
    Terraform used the selected providers to generate the following execution
    plan. Resource actions are indicated with the following symbols:
    + create
    
    Terraform will perform the following actions:
    
    # azurerm_resource_group.rg will be created
    + resource "azurerm_resource_group" "rg" {
          + id       = (known after apply)
          + location = "southcentralus"
          + name     = "aa-prod-scus-mgmt-rg"
          + tags     = {
             + "App_Contact" = "gerry@automationadmin.com"
             + "CostCenter"  = "100"
             + "Description" = "Automation Admin Terraform POC"
             + "Environment" = "prod"
             + "Owner"       = "Automation Admin"
          }
       }
    
    Plan: 1 to add, 0 to change, 0 to destroy.
    
    ─────────────────────────────────────────────────────────────────────────────
    
    Note: You didn't use the -out option to save this plan, so Terraform can't
    guarantee to take exactly these actions if you run "terraform apply" now.
    -01-14T00:25:54Z level=info msg=[command]/home/runner/work/_temp/c3c0f6cb-7901-4fd2-b79b-282c6a920406/terraform-bin init
    
    Initializing the backend...
    
    Successfully configured the backend "azurerm"! Terraform will automatically
    use this backend unless the backend configuration changes.
    
    Initializing provider plugins...
    - Finding hashicorp/azurerm versions matching "3.30.0"...
    - Installing hashicorp/azurerm v3.30.0...
    - Installed hashicorp/azurerm v3.30.0 (signed by HashiCorp)
    
    Terraform has created a lock file .terraform.lock.hcl to record the provider
    selections it made above. Include this file in your version control repository
    so that Terraform can guarantee to make the same selections by default when
    you run "terraform init" in the future.
    
    Terraform has been successfully initialized!
    
    You may now begin working with Terraform. Try running "terraform plan" to see
    any changes that are required for your infrastructure. All Terraform commands
    should now work.
    
    If you ever set or change modules or backend configuration for Terraform,
    rerun this command to reinitialize your working directory. If you forget, other
    commands will detect it and remind you to do so if necessary.
    
    -01-14T00:25:54Z level=info msg=[command]/home/runner/work/_temp/c3c0f6cb-7901-4fd2-b79b-282c6a920406/terraform-bin init
    
    Initializing the backend...
    
    Successfully configured the backend "azurerm"! Terraform will automatically
    use this backend unless the backend configuration changes.
    
    Initializing provider plugins...
    - Finding hashicorp/azurerm versions matching "3.30.0"...
    - Installing hashicorp/azurerm v3.30.0...
    - Installed hashicorp/azurerm v3.30.0 (signed by HashiCorp)
    
    Terraform has created a lock file .terraform.lock.hcl to record the provider
    selections it made above. Include this file in your version control repository
    so that Terraform can guarantee to make the same selections by default when
    you run "terraform init" in the future.
    
    Terraform has been successfully initialized!
    
    You may now begin working with Terraform. Try running "terraform plan" to see
    any changes that are required for your infrastructure. All Terraform commands
    should now work.
    
    If you ever set or change modules or backend configuration for Terraform,
    rerun this command to reinitialize your working directory. If you forget, other
    commands will detect it and remind you to do so if necessary.
    
    -01-14T00:25:54Z level=info msg=[command]/home/runner/work/_temp/c3c0f6cb-7901-4fd2-b79b-282c6a920406/terraform-bin init
    
    Initializing the backend...
    
    Successfully configured the backend "azurerm"! Terraform will automatically
    use this backend unless the backend configuration changes.
    
    Initializing provider plugins...
    - Finding hashicorp/azurerm versions matching "3.30.0"...
    - Installing hashicorp/azurerm v3.30.0...
    - Installed hashicorp/azurerm v3.30.0 (signed by HashiCorp)
    
    Terraform has created a lock file .terraform.lock.hcl to record the provider
    selections it made above. Include this file in your version control repository
    so that Terraform can guarantee to make the same selections by default when
    you run "terraform init" in the future.
    
    Terraform has been successfully initialized!
    
    You may now begin working with Terraform. Try running "terraform plan" to see
    any changes that are required for your infrastructure. All Terraform commands
    should now work.
    
    If you ever set or change modules or backend configuration for Terraform,
    rerun this command to reinitialize your working directory. If you forget, other
    commands will detect it and remind you to do so if necessary.
    
    -01-14T00:25:54Z level=info msg=[command]/home/runner/work/_temp/c3c0f6cb-7901-4fd2-b79b-282c6a920406/terraform-bin init
    
    Initializing the backend...
    
    Successfully configured the backend "azurerm"! Terraform will automatically
    use this backend unless the backend configuration changes.
    
    Initializing provider plugins...
    - Finding hashicorp/azurerm versions matching "3.30.0"...
    - Installing hashicorp/azurerm v3.30.0...
    - Installed hashicorp/azurerm v3.30.0 (signed by HashiCorp)
    
    Terraform has created a lock file .terraform.lock.hcl to record the provider
    selections it made above. Include this file in your version control repository
    so that Terraform can guarantee to make the same selections by default when
    you run "terraform init" in the future.
    
    Terraform has been successfully initialized!
    
    You may now begin working with Terraform. Try running "terraform plan" to see
    any changes that are required for your infrastructure. All Terraform commands
    should now work.
    
    If you ever set or change modules or backend configuration for Terraform,
    rerun this command to reinitialize your working directory. If you forget, other
    commands will detect it and remind you to do so if necessary.
    
    • This would of course fail because each of the two sets of Resource Groups have the same name because I wasn’t specific enough with my naming so they would get an error.

    • What’s happening, I think, is Terragrunt is going to that directory and recursively searching downwards and finding all four terragrunt.hcl files:

    • hub\east\deployment\terragrunt.hcl
    • hub\southcentral\deployment\terragrunt.hcl
    • spoke\east\deployment\terragrunt.hcl
    • spoke\southcentral\deployment\terragrunt.hcl

    • Then for each one, it is passing their customized locals as inputs to the terraform code that is up at the infra folder way way above it. This is because if you read their source for terraform, it says source = "${find_in_parent_folders("infra")}"
  8. But what if you wanted to have code in nonprod that is different than prod? Or east that is different from southcentralus?

    • You have two fixes, one is you set a bunch of flags as your input variables like includes_resource_group and if that is true, conditionally deploy that resource.
    • Second is you create separate folder under ./infra and point to that instead, like ./infa/nonprod and ./infa/prod then update your source like source = "${find_in_parent_folders("infra")}//nonprod" in your terragrunt.hcl. I cover this in Terragrunt Repo Structure V2.
  9. What if you don’t feel like copying that same terragrunt.hcl 8 times? Well I found the fix for this shortly after posting this, you just use includes and point higher up. I cover this in Terragrunt Repo Structure V2

  10. As a last example (for now), I wanted to show that you can mix your terragrunt and terraform code in the same structure and just reference terraform from terragrunt by using source = ./" in your terragrunt file and keeping them in the same folder structure. I cover this in Terragrunt Repo Structure V3. Keep in mind this is not recommended since you end up repeating alot which defeats the purpose of terragrunt.

  11. That’s it for now, will continue to post about Terragrunt in the future. Main reference I used was this repo to get started. Thanks to those contributors!