Terraform: state mv should update provider references

Created on 9 Apr 2018  ยท  3Comments  ยท  Source: hashicorp/terraform

When moving modules, the state mv command should update provider references to match the new paths.

This isn't usually a problem, as a new apply will update the provider reference, but it could lead to circumstances where multiple changes leave orphaned resource that can't locate a suitable provider for removal.

bug cli v0.11

Most helpful comment

I've found a solid workaround in case anybody else comes across this before it's fixed. I've used it on a few modules and resources and it's working for me.

I've also published the script as a runnable gist, so if you have comments on the script specifically you can make them there to not clutter this issue (I'll keep the version in this comment up to date with any changes).

# Pull a copy of the current state. 
terraform pull > terraform.tfstate

# (Optional) If you want to move from a separate state
#  - Also replace the "-state=" in the next command with "old.tfstate"
(cd somewhere_else; terraform pull > old.tfstate) && mv somewhere_else/old.tfstate .

# Move resources and modules into a temporary state
#   - You will need to run this once per module/resource
#     - modules will move all children with them
terraform state mv \
  -state=terraform.tfstate \
  -state-out=temp.tfstate \
  old.module some.temp.name

# Rename the provider using jq
#  - the "from" and "to" args are the provider aliases (or 'aws' for the root provider)
jq --arg from aws --arg to aws.foo -f <(cat<<'EOF'
# This is only necessary with jq<1.6rc1
def walk(f):
  . as $in
  | if type == "object" then
      reduce keys_unsorted[] as $key
        ( {}; . + { ($key):  ($in[$key] | walk(f)) } ) | f
  elif type == "array" then map( walk(f) ) | f
  else f
  end;
###

walk(
  if type == "object" and
  has("provider") and
  .provider == "provider.\($from)"
  then .provider = "provider.\($to)" else . end
)
EOF
) temp.tfstate > updated.tfstate

# Move the resource(s) to the new state file
terraform state mv \
  -state=updated.tfstate \
  -state-out=terraform.tfstate \
  some.temp.name the.final.name

# Push your new state
terraform push -state=terraform.tfstate

The jq script above defines a walk function that's available in [email protected]. Most package managers don't have it yet, but when they do, you can just remove the def block. You can also save that to a file and then call it with jq -f rename_provider.jq ...

All 3 comments

I've found a solid workaround in case anybody else comes across this before it's fixed. I've used it on a few modules and resources and it's working for me.

I've also published the script as a runnable gist, so if you have comments on the script specifically you can make them there to not clutter this issue (I'll keep the version in this comment up to date with any changes).

# Pull a copy of the current state. 
terraform pull > terraform.tfstate

# (Optional) If you want to move from a separate state
#  - Also replace the "-state=" in the next command with "old.tfstate"
(cd somewhere_else; terraform pull > old.tfstate) && mv somewhere_else/old.tfstate .

# Move resources and modules into a temporary state
#   - You will need to run this once per module/resource
#     - modules will move all children with them
terraform state mv \
  -state=terraform.tfstate \
  -state-out=temp.tfstate \
  old.module some.temp.name

# Rename the provider using jq
#  - the "from" and "to" args are the provider aliases (or 'aws' for the root provider)
jq --arg from aws --arg to aws.foo -f <(cat<<'EOF'
# This is only necessary with jq<1.6rc1
def walk(f):
  . as $in
  | if type == "object" then
      reduce keys_unsorted[] as $key
        ( {}; . + { ($key):  ($in[$key] | walk(f)) } ) | f
  elif type == "array" then map( walk(f) ) | f
  else f
  end;
###

walk(
  if type == "object" and
  has("provider") and
  .provider == "provider.\($from)"
  then .provider = "provider.\($to)" else . end
)
EOF
) temp.tfstate > updated.tfstate

# Move the resource(s) to the new state file
terraform state mv \
  -state=updated.tfstate \
  -state-out=terraform.tfstate \
  some.temp.name the.final.name

# Push your new state
terraform push -state=terraform.tfstate

The jq script above defines a walk function that's available in [email protected]. Most package managers don't have it yet, but when they do, you can just remove the def block. You can also save that to a file and then call it with jq -f rename_provider.jq ...

This is no longer needed, since provider references are absolute.

I'm going to lock this issue because it has been closed for _30 days_ โณ. This helps our maintainers find and focus on the active issues.

If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

rjinski picture rjinski  ยท  3Comments

pawelsawicz picture pawelsawicz  ยท  3Comments

rjinski picture rjinski  ยท  3Comments

rnowosielski picture rnowosielski  ยท  3Comments

thebenwaters picture thebenwaters  ยท  3Comments