-
Notifications
You must be signed in to change notification settings - Fork 118
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add StateShow #205
Add StateShow #205
Conversation
64c0d6b
to
166e583
Compare
166e583
to
f05c8b8
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @micahkemp
Thank you for the PR.
We tend to keep terraform-exec focused on automation use cases (rather than aiming for 100% coverage of all Terraform CLI commands).
With that in mind could you share your use case for this command in the context of automation?
Keep in mind that this command (unlike most others we integrated) does not provide machine-readable (JSON) output and AFAIK therefore doesn't provide any compatibility guarantees for the output format.
If we have a use case though we could propose enhancement of Terraform CLI so that it does offer JSON output - this would then make the integration much easier here.
This PR (as well as #206) was indeed crafted in the name of automation. I'm working on enabling In support of that, my pipeline aims to:
There's certainly a lot more to it (dynamically created workspaces for feature branches, checking if the defined imports are still valid before merging the next PR, etc.), but these two PRs add vital functionality which will make my automated CI/CD much simpler when written in Go than in Shell. As for potential enhancement requests to have the CLI output JSON that could help, I'm not sure how much help that would be. |
Thank you for the added context - this is useful! I think we are all aiming for a long-term goal where Terraform is capable of seamlessly importing a resource without additional human interaction 😄 Unfortunately this isn't how Terraform works today - yet - as you already noticed.
I'm afraid that is a false assumption. It only happens to look like HCL and in many/most cases it is valid HCL, but it's not a design goal and it is certainly not guaranteed that command will always output valid HCL. You can also review how the output is assembled here which also shows a number of annotations such as Upcoming I assume that would address your use case, wouldn't it? I'd be happy to review a PR for the It's fair to say that users with lots of resources (probably your case?) will want to employ some automation around this process. I would however apply some caution because the resulting config (even the one generated by In other words I understand why you want to automate this, but I'm not sure I fully understand why you wish to do it in a CI pipeline (as opposed to a standalone script human runs). What would the output or next step from that pipeline be? |
This is acceptable to us. We aren't looking for the automation to take the result of
This looks very promising! I will spend some more time looking into this, but it looks like a replacement for
This is likely a longer topic than can truly be expressed here, but the CI/CD pipeline for import is largely intended to prevent engineers from configuring the remote state (and other) credentials that would permit them to run terraform commands locally. When multiple engineers are working on code and configuration it becomes more important for everything to go through review and automation to be deployed, and avoid as much manual running as possible. Specifically it would permit the use of existing automation to assist the building of .tf content and validation that said content is a net-zero change from what is already deployed (outside of terraform). The steps generally look like: Feature branch:
Default branch:
Our existing process is manual, and dependent on being run by just one or two terraform experts, who are (hopefully) less likely to make a mistake to the default workspace or deployed infrastructure. But we'd like to avoid this bottleneck, while also not promoting every engineer to run terraform commands locally, due to the risk of state not matching committed/merged configurations, or having orphaned remote resources from working on local state or manually created workspaces. |
Thank you for the added detailed description of your CI/CD use case - this is very insightful. I appreciate that the lack of compatibility guarantees is acceptable for you but as maintainers we also need to keep in mind this library is used by folks who have certain expectations which may not necessarily match with yours. I'm just in the process of planning work on another project which will also require programmatic access to state and so I will likely have a use case for this either way. If we do add it though I'd really prefer consuming machine-readable (JSON) output, rather than the human-readable one. I will try to propose JSON output flag for the two subcommands ( Thank you for your patience and understanding. |
For this PR, I think it can be closed and potentially replaced by one for I believe I'll close this PR assuming you agree, or you can feel free to close it. |
I would probably prefer to keep it open for a little bit longer if you don't mind. As mentioned I have a potential use case for I should have some time to work on that in coming weeks hopefully. 🤞🏻 |
After discussing this in more detail with the Core team and also outlining some use potential cases of our own in hashicorp/vscode-terraform#734 we came to conclusion that the discussed import use case along with the one linked can be addressed with existing functionality.
Given a previously package main
import (
"context"
"fmt"
"log"
"os"
"os/exec"
"github.com/hashicorp/terraform-exec/tfexec"
tfjson "github.com/hashicorp/terraform-json"
)
func main() {
workDir, err := os.Getwd()
if err != nil {
log.Fatal(err)
}
execPath, err := exec.LookPath("terraform")
if err != nil {
log.Fatal(err)
}
tf, err := tfexec.NewTerraform(workDir, execPath)
if err != nil {
log.Fatal(err)
}
ctx := context.Background()
state, err := tf.Show(ctx)
if err != nil {
log.Fatal(err)
}
for _, resource := range state.Values.RootModule.Resources {
if resource.Address == "random_pet.adam" {
switch resource.Mode {
case tfjson.ManagedResourceMode:
fmt.Printf("resource ")
case tfjson.DataResourceMode:
fmt.Printf("data ")
}
fmt.Printf("%q ", resource.Type)
fmt.Printf("%q {\n", resource.Name)
for key, value := range resource.AttributeValues {
if value != nil {
fmt.Printf(" %s = %q\n", key, value)
}
}
fmt.Printf("}\n")
}
}
} $ go run main.go
resource "random_pet" "adam" {
id = "quality-firefly"
length = "2"
separator = "-"
} which produces equivalent output to $ terraform state show random_pet.adam
# random_pet.adam:
resource "random_pet" "adam" {
id = "quality-firefly"
length = 2
separator = "-"
} Thank you for your patience and understanding. I hope that helps. |
Included in this PR is the addition of the StateShow method.
This method returns the stdout of the executed terraform command, or an error if encountered.