docs/architecture/deployment-execution/import.md
(importing-resources)=
There are a number of scenarios in which it is necessary to import existing resources for management by Pulumi:
pulumi state move
is not sufficient.Pulumi offers two approaches for importing resources: the import resource
option and the pulumi import command. At a minimum, importing a resource
involves adding the resource's state to the destination stack's
state. Once the resource has been added to the stack, the
Pulumi CLI is able to manage the resource like any other.
import resource optionThe import resource
option accepts the
ID of an existing resource whose state should be
and imported into the stack.
Importing a resource using the import resource option requires that the
desired state described by the Pulumi program for a resource being imported
matches the actual state of the resource as returned by the provider. More
precisely, given a resource R of type T with import ID X and set of inputs
(as specified in the program) Iₚ, the engine performs the following sequence
of operations:
Iₐ and state Sₐ for the resource of type T
with ID X from its provider by calling the provider's
method. If the provider does not return a
value for Iₐ, the provider does not support importing resources and the
import fails.ignoreChanges resource
option by
copying the value for any ignored input property from Iₐ to Iₚ.Iₚ and Iₐ to the provider's method.
Let Iₖ be the checked inputs; these inputs form the resource's desired
state.Iₖ and Sₐ by calling the provider's
method. If the provider reports any
differences, the import either succeeds with a warning (in the case of a
preview) or fails with an error (in the case of an update).If all of these steps succeed, the user is left with a definition for R in
their Pulumi program that matches that in the stack's state exactly.
:caption: Importing a resource using the `import` resource option
:zoom:
sequenceDiagram
participant LH as Language host
box Engine
participant RM as Resource monitor
participant SG as Step generator
participant SE as Step executor
end
participant P as Provider
LH->>+RM: RegisterResourceRequest(type, name, inputs, options)
RM->>+SG: RegisterResourceEvent(type, name, inputs, options)
SG->>+SE: ImportStep(inputs, options)
SE->>+P: ReadRequest(type, id)
P->>-SE: ReadResponse(current inputs, current state)
SE->>+P: CheckRequest(type, inputs, current inputs)
P->>-SE: CheckResponse(inputs', failures)
SE->>+P: DiffRequest(type, inputs', current state, options)
P->>-SE: DiffResponse(diff)
SE->>-RM: Done(current state)
RM->>-LH: RegisterResourceResponse(URN, ID, current state)
pulumi importpulumi import is a
newer method of importing resources into a stack that also generates program
code for imported resources. pulumi import accepts a list of import specs,
where each spec comprises at minimum a type token, name, and
ID, but may also specify a parent URN, provider reference, and
package version. Unlike the import resource option, pulumi import does not
insist that the desired state of the resource in the Pulumi program matches the
actual state of the resource as returned by the provider, since it is capable of
generating code to match the actual state. Given a resource R of type T with
import ID X and an (initially empty) set of input properties Iₚ, the engine
performs the following sequence of operations:
Iₐ and state Sₐ for the resource of type T
with ID X from its provider by calling the provider's
method. If the provider does not return a
value for Iₐ, the provider does not support importing resources and the
import fails.T from the provider. If the provider
is not schematized or if T has no schema, the import fails.T
from Iₐ to Iₚ.Iₚ and Iₐ to the provider's method.
Let Iₖ be the checked inputs; these inputs form the resource's desired
state.Iₖ and Sₐ by calling the provider's
method. If the provider reports any
differences, the values of the differing properties are copied from Sₐ to
Iₚ. This is intended to produce the smallest valid set of inputs necessary
to avoid diffs. This does not use a fixed-point algorithm because there is no
guarantee that the values copied from Sₐ are in fact valid (state and
inputs with the same property paths may have different types and validation
rules) and there is no guarantee that such an algorithm would terminate (
bridged Terraform providers, for example, have had bugs that cause persistent
diffs, which can only be worked around with ignoreChanges).If all of these steps succeed, the user is left with a definition for R in
their state. The Pulumi CLI then passes the inputs Iₚ stored in the state to
the import code generator. The import code generator converts the values present
in Iₚ into an equivalent PCL representation of R's desired state,
then passes the PCL to a language-specific code generator to emit a
representation of R's desired state in the language used by the destination
stack's Pulumi program. The user can then copy the generated definition into
their Pulumi program.
:caption: Importing a resource using the `pulumi import` CLI
:zoom:
sequenceDiagram
participant PI as pulumi import
participant CV as PCL converter
participant LH as Language host
box Engine
participant ID as Import driver
participant SE as Step executor
end
participant P as Provider
PI->>+ID: Import(specs)
ID->>+SE: ImportStep(inputs, options)
SE->>+P: ReadRequest(type, id)
P->>-SE: ReadResponse(current inputs, current state)
SE->>+P: CheckRequest(type, inputs, current inputs)
P->>-SE: CheckResponse(inputs', failures)
SE->>+P: DiffRequest(type, inputs', current state, options)
P->>-SE: DiffResponse(diff)
SE->>-ID: Done(current state)
ID->>-PI: Done(current state)
PI->>+CV: Convert(current state)
CV->>-PI: Done(PCL definitions)
PI->>+LH: GenerateProgram(PCL definitions)
LH->>-PI: Done(generated resource definitions)
The primary challenge in generating appropriate code for pulumi import lies in
determining exactly what the input values for a particular resource should be.
In many providers, it is not necessarily possible to accurately recover a
resource's inputs from its state. This observation led to the diff-oriented
approach described above, where the importer begins with an extremely minimal
set of inputs and attempts to derive the actual inputs from the results of a
call to the provider's method.
Unfortunately, the results are not always satisfactory, and the relatively small
set of inputs present in the generated code can make it difficult for users to
determine what inputs they actually need to pass to the resource to describe
its current state.
A few other approaches might be:
It is likely that some mix of approaches is necessary in order to arrive at a satisfactory solution, as none of the above solutions seems universally "correct".
When using pulumi import --file=..., the engine runs a preview before making
any changes. If errors are detected during the preview (e.g. a resource is not
found), the command fails before writing anything to state. When --skip-preview
is specified, the engine instead imports as many resources as possible, writing
successful imports to state immediately and collecting any errors for display in
the final output.
Both approaches are safe to retry: importing a resource that already exists in state is a no-op. However, it is possible to accidentally import the same physical resource under two different logical names, which creates an implicit aliasing situation where the stack tracks the same underlying resource twice.