Skip to content

Commit

Permalink
website: plannable import docs (#33266)
Browse files Browse the repository at this point in the history
* website: plannable import docs

* website: config gen docs

* Update website/docs/cli/commands/plan.mdx

Co-authored-by: Rose M Koron <[email protected]>

* Update website/docs/cli/import/index.mdx

Co-authored-by: Rose M Koron <[email protected]>

* Update website/docs/language/import/index.mdx

Co-authored-by: Rose M Koron <[email protected]>

* Update website/docs/language/import/index.mdx

Co-authored-by: Rose M Koron <[email protected]>

* Apply suggestions from code review

Co-authored-by: Rose M Koron <[email protected]>

* fix docs rendering

* Apply suggestions from code review

Co-authored-by: Rose M Koron <[email protected]>

* link again to import blocks

* fix genconfig example plan output

* Update website/docs/language/import/index.mdx

Co-authored-by: Rose M Koron <[email protected]>

* add import resource config example

* Apply suggestions from code review

Co-authored-by: Rose M Koron <[email protected]>

* attempt to fix nav

* more explicit

* fix build?

* remove pseudo tutorial

* add advice on when to gen

* add note on idempotency

* Apply suggestions from code review

Co-authored-by: Rose M Koron <[email protected]>
Co-authored-by: Alan Szlosek Jr <[email protected]>

* refer to cli cmd in usual way

* more explanation for genconfig

* remove unnecessary sentence

* add heading

* update help text

* Apply suggestions from code review

Co-authored-by: Rose M Koron <[email protected]>

* update link

* add import ID section

* Apply suggestions from code review

Co-authored-by: rita <[email protected]>
Co-authored-by: Rose M Koron <[email protected]>

* Apply suggestions from code review

Co-authored-by: rita <[email protected]>
Co-authored-by: Rose M Koron <[email protected]>

* dial back didacticism

* clarify genconfig instructions

* explicit explanation of arg conflict

* Apply suggestions from code review

Co-authored-by: rita <[email protected]>
Co-authored-by: Rose M Koron <[email protected]>

* clarify import block required for genconfig

---------

Co-authored-by: Rose M Koron <[email protected]>
Co-authored-by: Alan Szlosek Jr <[email protected]>
Co-authored-by: rita <[email protected]>
  • Loading branch information
4 people authored Jun 9, 2023
1 parent 46e47e0 commit 991d6f3
Show file tree
Hide file tree
Showing 6 changed files with 299 additions and 4 deletions.
10 changes: 10 additions & 0 deletions website/data/language-nav-data.json
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,16 @@
]
},
{ "title": "Checks", "path": "checks" },
{
"title": "Import",
"routes": [
{ "title": "Overview", "path": "import" },
{
"title": "Generating Configuration",
"path": "import/generating-configuration"
}
]
},
{
"title": "Expressions",
"routes": [
Expand Down
2 changes: 2 additions & 0 deletions website/docs/cli/commands/plan.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,8 @@ The available options are:
* 1 = Error
* 2 = Succeeded with non-empty diff (changes present)

- `-generate-config-out=PATH` - (Experimental) If `import` blocks are present in configuration, instructs Terraform to generate HCL for any imported resources not already present. The configuration is written to a new file at PATH, which must not already exist, or Terraform will error. If the plan fails for another reason, Terraform may still attempt to write configuration.

* `-input=false` - Disables Terraform's default behavior of prompting for
input for root module input variables that have not otherwise been assigned
a value. This option is particularly useful when running Terraform in
Expand Down
6 changes: 4 additions & 2 deletions website/docs/cli/import/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ description: >-
Terraform can import existing infrastructure resources. This functionality lets you bring existing resources under Terraform management.

~> **Warning:** Terraform expects that each remote object is bound to only one resource address. You should import each remote object to only one Terraform resource address. If you import the same object multiple times, Terraform may exhibit unwanted behavior. Refer to [State](/terraform/language/state) for more details.
-> **Note:** Terraform v1.5.0 and later supports `import` blocks. Unlike the `terraform import` command, you can use `import` blocks to import more than one resource at a time, and you can review imports as part of your normal plan and apply workflow. [Learn more about `import` blocks](/terraform/language/import).

## State Only

Terraform import can only import resources into the [state](/terraform/language/state). Importing does not generate configuration.
~> **Warning:** Terraform expects that each remote object is bound to a _single_ resource address. You should import each remote object to _one_ Terraform resource address. If you import the same object multiple times, Terraform may exhibit unwanted behavior. See [State](/terraform/language/state) for more details.

The `terraform import` CLI command can only import resources into the [state](/terraform/language/state). Importing via the CLI does _not_ generate configuration. If you want to generate the accompanying configuration for imported resources, [use the `import` block instead](/terraform/language/import).

Before you run `terraform import` you must manually write a `resource` configuration block for the resource. The resource block describes where Terraform should map the imported object.

Expand Down
146 changes: 146 additions & 0 deletions website/docs/language/import/generating-configuration.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
---
page_title: Import - Generating Configuration
description: >-
Generate configuration and manage existing resources with Terraform using configuration-driven import.
---

# Generating configuration

~> **Experimental:** Configuration generation is available in Terraform v1.5 as an experimental feature. Later minor versions may contain changes to the formatting of generated configuration and behavior of the `terraform plan` command using the `-generate-config-out` flag.

Terraform can generate code for the resources you define in [`import` blocks](/terraform/language/import) that do not already exist in your configuration. Terraform produces HCL to act as a template that contains Terraform's best guess at the appropriate value for each resource argument.

Starting with Terraform's generated HCL, we recommend iterating to find your ideal configuration by removing some attributes, adjusting the value of others, and rearranging `resource` blocks into files and modules as appropriate.

To generate configuration, run `terraform plan` with the `-generate-config-out` flag and supply a new file path. Do not supply a path to an existing file, or Terraform throws an error.

```shell
$ terraform plan -generate-config-out=generated_resources.tf
```

If any resources targeted by an `import` block do not exist in your configuration, Terraform then generates and writes configuration for those resources in `generated_resources.tf`.

## Workflow

The workflow for generating configuration is similar to the [`import` block workflow](/terraform/language/import#plan-and-apply-an-import), with the extra step of generating configuration during the planning stage. You can then review and modify the generated configuration before applying.

### 1. Add the `import` block

Add an `import` block to your configuration. This `import` block can be in a separate file (e.g., `import.tf`) or an existing configuration file.

```hcl
import {
to = aws_iot_thing.bar
id = "foo"
}
```

The import block's `to` argument points to the address a `resource` will have in your state file. If a resource address in your state matches an `import` block's `to` argument, Terraform attempts to import into that resource. In future planning, Terraform knows it doesn't need to generate configuration for resources that already exist in your state.

The import block's `id` argument uses that resource's [import ID](/terraform/language/import#import-id).

If your configuration does not contain other resources for your selected provider, you must add a `provider` block to inform Terraform which provider it should use to generate configuration. Otherwise, Terraform displays an error if it can not determine which provider to use.
If you add a new `provider` block to your configuration, you must run `terraform init` again.

### 2. Plan and generate configuration

To instruct Terraform to generate configuration for the `import` blocks you defined, run `terraform plan` with the `-generate-config-out=` flag and a new file path. Terraform displays its plan for importing your resource and the file where Terraform generated configuration based on this plan.

```shell
$ terraform plan -generate-config-out=generated.tf

aws_iot_thing.bar: Preparing import... [id=foo]
aws_iot_thing.bar: Refreshing state... [id=foo]

Terraform will perform the following actions:

# aws_iot_thing.bar will be imported
# (config will be generated)
resource "aws_iot_thing" "bar" {
arn = "arn:aws:iot:eu-west-1:1234567890:thing/foo"
attributes = {}
default_client_id = "foo"
id = "foo"
name = "foo"
version = 1
}

Plan: 1 to import, 0 to add, 0 to change, 0 to destroy.

│ Warning: Config generation is experimental
│ Generating configuration during import is currently experimental, and the generated configuration format may change in future versions.

──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Terraform has generated configuration and written it to generated.tf. Please review the configuration and edit it as necessary before adding it to version control.
```

### 3. Review generated configuration

The example above instructs Terraform to generate configuration in a file named `generated.tf`. The below code is an example of a `generated.tf` file.

```hcl
resource aws_iot_thing "bar" {
name = "foo"
}
```

Review the generated configuration and update it as needed. You may wish to move the generated configuration to another file, add or remove resource arguments, or update it to reference input variables or other resources in your configuration.

### 4. Apply

Run `terraform apply` to import your infrastructure.

```shell
$ terraform apply

aws_iot_thing.bar: Preparing import... [id=foo]
aws_iot_thing.bar: Refreshing state... [id=foo]

Terraform will perform the following actions:

# aws_iot_thing.bar will be imported
resource "aws_iot_thing" "bar" {
arn = "arn:aws:iot:eu-west-1:1234567890:thing/foo"
attributes = {}
default_client_id = "foo"
id = "foo"
name = "foo"
version = 1
}

Plan: 1 to import, 0 to add, 0 to change, 0 to destroy.
aws_iot_thing.bar: Importing... [id=foo]
aws_iot_thing.bar: Import complete [id=foo]

Apply complete! Resources: 1 imported, 0 added, 0 changed, 0 destroyed.

```

Commit your new resource configuration to your version control system.

## Limitations

### Conflicting resource arguments

Terraform generates configuration for importable resources during a plan by requesting values for resource attributes from the provider. For certain resources with complex schemas, Terraform may not be able to construct a valid configuration from these values.

Terraform will display an error like the one below if it does not receive values for resource attributes while generating configuration.

```shell
$ terraform plan -generate-config-out=generated.tf
│ Error: Conflicting configuration arguments
│ with aws_instance.ubuntu,
│ on g.tf line 20, in resource "aws_instance" "ubuntu":
│ 20: ipv6_address_count = 0
"ipv6_address_count": conflicts with ipv6_addresses
```

In the example above, Terraform still generates configuration and writes it to `generated.tf`. This error stems from a conflict between the `ipv6_address_count` and `ipv6_addresses` arguments. The resource supports both of these arguments, but you must choose only one when configuring the resource. You could fix the error by removing one of these two arguments, then running `terraform plan` again to check that there are no further issues.
136 changes: 136 additions & 0 deletions website/docs/language/import/index.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
---
page_title: Import - Configuration Language
description: >-
Import and manage existing resources with Terraform using configuration-driven import.
---

# Import

-> **Note:** Import blocks are only available in Terraform v1.5.0 and later.

~> **Experimental:** While we do not expect to make backwards-incompatible changes to syntax, the `-generate-config-out` flag and how Terraform processes imports during the plan stage and generates configuration may change in future releases.

Use the `import` block to import existing infrastructure resources into Terraform, bringing them under Terraform's management. Unlike the `terraform import` command, configuration-driven import using `import` blocks is predictable, works with CICD pipelines, and lets you preview an import operation before modifying state.

Once imported, Terraform tracks the resource in your state file. You can then manage the imported resource like any other, updating its attributes and destroying it as part of a standard resource lifecycle.

The `import` block records that Terraform imported the resource and did not create it. After importing, you can optionally remove import blocks from your configuration or leave them as a record of the resource's origin.

## Syntax

You can add an `import` block to any Terraform configuration file. A common pattern is to create an `imports.tf` file, or to place each `import` block beside the `resource` block it imports into.

```hcl
import {
to = aws_instance.example
id = "i-abcd1234"
}
resource "aws_instance" "example" {
name = "hashi"
# (other resource arguments...)
}
```

The above `import` block defines an import of the AWS instance with the ID "i-abcd1234" into the `aws_instance.example` resource in the root module.

The `import` block has the following arguments:
- `to` - The instance address this resource will have in your state file.
- `id` - A string with the [import ID](#import-id) of the resource.
- `provider` (optional) - An optional custom resource provider, see [The Resource provider Meta-Argument](/terraform/language/meta-arguments/resource-provider) for details.

If you do not set the `provider` argument, Terraform attempts to import from the default provider.

### Import ID

The import block requires you to provide the `id` argument with a literal string of your resource's import ID. Terraform needs this import ID to locate the resource you want to import.

The identifier you use for a resource's import ID is resource-specific. You can find the required ID in the [provider documentation](https://registry.terraform.io/browse/providers) for the resource you wish to import.

## Plan and apply an import

Terraform processes the `import` block during the plan stage. Once a plan is approved, Terraform imports the resource into its state during the subsequent apply stage.

To import a resource using `import` blocks, you must:
1. Define an `import` block for the resource(s).
1. Add a corresponding `resource` block to your configuration , or [generate configuration](/terraform/language/import/generating-configuration) for that resource.
1. Run `terraform plan` to review how Terraform will import the resource(s).
1. Apply the configuration to import the resources and update your Terraform state.

> **Hands-on:** Try the [State Import](/terraform/tutorials/state/state-import?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorial.
The `import` block is [_idempotent_](https://en.wikipedia.org/wiki/Idempotence), meaning that applying an import action and running another plan will not generate another import action as long as that resource remains in your state.

Terraform only needs to import a given resource once. Attempting to import a resource into the same address again is a harmless no-op. You can remove `import` blocks after completing the import or safely leave them in your configuration as a record of the resource's origin for future module maintainers. For more information on maintaining configurations over time, see [Refactoring](/terraform/language/modules/develop/refactoring).

## Resource configuration

Before importing, you must add configuration for every resource you want Terraform to import. Otherwise, Terraform throws an error during planning, insisting you add resource configuration before it can successfully import. You can create resource configuration manually or [generate it using Terraform](/terraform/language/import/generating-configuration).

We recommend writing a `resource` block if you know what most of the [resource's arguments](/terraform/language/resources/syntax#resource-arguments) will be. For example, your configuration may already contain a similar resource whose configuration you can copy and modify.

We recommend [generating configuration](/terraform/language/import/generating-configuration) when importing multiple resources or a single complex resource that you do not already have the configuration for.

### Add a `resource` block

Add a `resource` block for the resource to import. The resource address must match the import block's `to` argument.

```hcl
import {
to = aws_instance.example
id = "i-abcd1234"
}
resource "aws_instance" "example" {
name = "renderer"
}
```

### Generate configuration

Terraform can generate HCL for resources that do not already exist in configuration.
For more details, see [Generating Configuration](/terraform/language/import/generating-configuration).

## Examples

The following example demonstrates how to import into a module.

```hcl
import {

This comment has been minimized.

Copy link
@jkburges

jkburges Oct 17, 2023

Contributor

Hello @rkoron007, do you happen to know if it's possible when importing into a module to use a provider from the module?

I have a case where the provider datadog is used, and therefore declared, only in a certain module. I have tried the following with terraform v1.6.1, but it fails:

import {
  to       = module.logging.datadog_logs_index.main
  id       = "main"
  provider = module.logging.datadog
}

Output:

$ terraform init

Initializing the backend...
Initializing modules...
╷
│ Error: Invalid import provider argument
│ 
│   on main.tf line 75, in import:
│   75:   provider = module.logging.datadog
│ 
│ The provider argument can only be specified in import blocks that will generate
│ configuration.
│ 
│ Use the providers argument within the module block to configure providers for all resources
│ within a module, including imported resources.
╵

╷
│ Error: Invalid provider configuration reference
│ 
│   on main.tf line 75, in import:
│   75:   provider = module.logging.datadog
│ 
│ The provider argument requires a provider type name, optionally followed by a period and
│ then a configuration alias.
╵

I have got it to work by declaring the datadog provider at the root-level, but this seems redundant (but perhaps necessary).

#33474 may help with my situation in the long run, in any case.

Aside, import blocks are an amazing feature, thank you!

This comment has been minimized.

Copy link
@crw

crw Oct 17, 2023

Contributor

Hi @jkburges, @rkoron007 is no longer at HashiCorp. I would recommend asking this question in the community forum where there are more people ready to help. Most maintainers do not look at these types of commit comments.

This comment has been minimized.

Copy link
@jkburges

jkburges Oct 17, 2023

Contributor

Apologies, I'll ask over there. Thanks.

to = module.instances.aws_instance.example
id = "i-abcd1234"
}
```

The below example shows how to import a resource that includes [`count`](/terraform/language/meta-arguments/count).

```hcl
import {
to = aws_instance.example[0]
id = "i-abcd1234"
}
```


The below example shows how to import a resource that includes [`for_each`](/terraform/language/meta-arguments/for_each).
```hcl
import {
to = aws_instance.example["foo"]
id = "i-abcd1234"
}
```

Finally, the below example demonstrates how to import from a custom resource provider.

```hcl
provider "aws" {
alias = "europe"
region = "eu-west-1"
}
import {
provider = aws.europe
to = aws_instance.example["foo"]
id = "i-abcd1234"
}
```
3 changes: 1 addition & 2 deletions website/docs/language/state/import.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,4 @@ description: >-
Terraform is able to import existing infrastructure. This allows you to take
resources you have created by some other means and bring them under Terraform management.

To learn more about this, please visit the
[pages dedicated to import](/terraform/cli/import).
To learn more, see [Import](/terraform/language/import).

0 comments on commit 991d6f3

Please sign in to comment.