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

Add resource address to error message #60

Closed mrzor closed 4 years ago

mrzor commented 4 years ago

When having multiple shell_script resources sharing the same name (i.e. in a module instanciated several times), it's hard to know which one is yielding an error because Terraform displays the error at the end without context.

Current

Error: Error occurred during execution.
 Command: './redacted read' 
 Error: 'exit status 127' 
 StdOut: 

 StdErr: 
 /bin/sh: 1: ./redacted: not found

One can guess it is the last shell_script resources to be read in that case.

I imagine that with parallelism turned on, such guessing becomes even harder.

Suggested

Example:

Error: Error occurred during execution.
Resource: module.mymodule.shell_script.mything
 Command: './redacted read' 
 Error: 'exit status 127' 
 StdOut: 

 StdErr: 
 /bin/sh: 1: ./redacted: not found
scottwinkler commented 4 years ago

I think this is a great idea, and I spent some time looking into this but I really don't think its possible. Terraform providers operate in a sandbox and don't have very much information available to them except the minimum they need to be able to do their job. As such, you know the InstanceState of resources, which may include information such as you would find in the "instance" attribute of the state file, e.g.

{
          "schema_version": 0,
          "attributes": {
            "environment": null,
            "id": "bsehc7dgrkrh05uual20",
            "interpreter": null,
            "lifecycle_commands": [
              {
                "read": "echo \"{\\\"user\\\": \\\"$(whoami)\\\"}\"\n"
              }
            ],
            "output": {
              "user": "swinkler"
            },
            "sensitive_environment": null,
            "working_directory": "."
          }
        }

As you can see, the id in the instances is not the same as the resource address. Worse, it is only set after Create() has successfully completed, meaning that you could only print it in the error message for Read(), Update() and Delete(). I guess this could still be beneficial, but it could also be confusing and frustrating not to have the error message for Create(), which IMO is the most important.

There does not appear to be any way to the resource address, as far as I can tell. Resources only have schema.ResourceData available to them, which does contain a reference to State(), but again this is InstanceState and not the complete state file. ResourceAddress could be gleaned from InstanceInfo, but no reference to this struct is present via schema.ResourceData. Even if you were to do something janky like read the configuration code or state file through alternative means, you still wouldn't know exactly what the resource address is for the resource in question.

Might I suggest using a for_each on the shell resource/module instead? this might make it more clear where the error message is coming from. Resources in for_each are addressed as: module.shell_script.example["a"] where "a" is an element in the set used to instantiate the resources.

mrzor commented 4 years ago

I now understand the limitations the provider has to work under. I think an argument could be made to terraform devs to expand the context a bit for error messages - or they could provide the context when displaying the error - because Terraform displays the error, the provider merely formats it. That would be a proper fix.

Using for_each looks like a good workaround.

I thing the workaround has some downsides (I'll admit they're pretty weak):

... Which is why I've opened a PR with a pretty limited "error_tag" hack that addresses the issue with hopefully no side-effects or wide reaching concerns.

scottwinkler commented 4 years ago

i now print env in the output, which should be enough to be able to uniquely identify resources. i will favor this over an error tag for now. let me know what you think, i can always add error tag later