scottwinkler / terraform-provider-shell

Terraform provider for executing shell commands and saving output to state file
Mozilla Public License 2.0
279 stars 60 forks source link

Clarification on update lifecycle #75

Closed rucciva closed 3 years ago

rucciva commented 3 years ago

hi! thanks for making this provider. Just have a bit of question.

i've specified update lifecycle_commands but when i change a value in environment, sensitive_environment or triggers, terraform need to destroy and create new resource, as such:

$ terraform apply
shell_script.github_repository: Refreshing state... [id=bu7d4dr3gcl4s8t7ks70]

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
-/+ destroy and then create replacement

Terraform will perform the following actions:

  # shell_script.github_repository must be replaced
-/+ resource "shell_script" "github_repository" {
        dirty                 = false
      ~ environment           = { # forces replacement
          ~ "DESCRIPTION" = "description" -> "description1"
            "NAME"        = "hello-world"
        }
      ~ id                    = "bu7d4dr3gcl4s8t7ks70" -> (known after apply)
      ~ output                = {
          - "description" = "description"
          - "name"        = "hello-world"
        } -> (known after apply)
        sensitive_environment = (sensitive value)
        triggers              = {
            "when_value_changed" = "test"
        }
        working_directory     = "."

        lifecycle_commands {
            create = "echo '{\"name\":\"'$NAME'\", \"description\": \"'$DESCRIPTION'\"}' > tmp"
            delete = "rm tmp"
            read   = "cat tmp"
            update = <<~EOT
                cat > previous
                echo '{"name":"'$NAME'", "description": "'$DESCRIPTION'"}' > tmp
            EOT
        }
    }

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

change are indeed triggered but only if the actual state is changing or if there are any change in the script it self, as such:

$ terraform apply   # after manually modifying "tmp" files
shell_script.github_repository: Refreshing state... [id=bu7d4dr3gcl4s8t7ks70]

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  # shell_script.github_repository will be updated in-place
  ~ resource "shell_script" "github_repository" {
      ~ dirty                 = true -> false
        environment           = {
            "DESCRIPTION" = "description"
            "NAME"        = "hello-world"
        }
        id                    = "bu7d4dr3gcl4s8t7ks70"
        output                = {
            "description" = "description"
            "name"        = "hello-world"
        }
        sensitive_environment = (sensitive value)
        triggers              = {
            "when_value_changed" = "test"
        }
        working_directory     = "."

        lifecycle_commands {
            create = "echo '{\"name\":\"'$NAME'\", \"description\": \"'$DESCRIPTION'\"}' > tmp"
            delete = "rm tmp"
            read   = "cat tmp"
            update = <<~EOT
                cat > previous
                echo '{"name":"'$NAME'", "description": "'$DESCRIPTION'"}' > tmp
            EOT
        }
    }

Plan: 0 to add, 1 to change, 0 to destroy.
$ terraform apply
shell_script.github_repository: Refreshing state... [id=bu7d4dr3gcl4s8t7ks70]

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  # shell_script.github_repository will be updated in-place
  ~ resource "shell_script" "github_repository" {
        dirty                 = false
        environment           = {
            "DESCRIPTION" = "description"
            "NAME"        = "hello-world"
        }
        id                    = "bu7d4dr3gcl4s8t7ks70"
        output                = {
            "description" = "description"
            "name"        = "hello-world"
        }
        sensitive_environment = (sensitive value)
        triggers              = {
            "when_value_changed" = "test"
        }
        working_directory     = "."

      ~ lifecycle_commands {
            create = "echo '{\"name\":\"'$NAME'\", \"description\": \"'$DESCRIPTION'\"}' > tmp"
          ~ delete = <<~EOT
                rm tmp
              + echo
            EOT
            read   = "cat tmp"
            update = <<~EOT
                cat > previous
                echo '{"name":"'$NAME'", "description": "'$DESCRIPTION'"}' > tmp
            EOT
        }
    }

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

is this expected? if so, what is the recommended way to pass or update metadata to script (such as connection information) without triggering destroy lifecycle (which might actually destroy unrecoverable data).

scottwinkler commented 3 years ago

Hi @rucciva . There was a bug with the environment variables, they should have not been force new. I just released this in 1.7.4 patch. The recommended way to pass metadata to script is using an environment/sensitive_environment variable block, either on the resource in question, or on the provider configuration. Let me know if this answers your question, or else I will close this issue.

rucciva commented 3 years ago

Hi, this answer the question, thanks