| // Copyright IBM Corp. 2014, 2026 | |
| // SPDX-License-Identifier: BUSL-1.1 | |
| package command | |
| import ( | |
| "encoding/json" | |
| "fmt" | |
| "strings" | |
| "github.com/hashicorp/cli" | |
| "github.com/hashicorp/terraform/internal/addrs" | |
| "github.com/hashicorp/terraform/internal/command/arguments" | |
| "github.com/hashicorp/terraform/internal/states" | |
| ) | |
| // StateIdentitiesCommand is a Command implementation that lists the resource identities | |
| // within a state file. | |
| type StateIdentitiesCommand struct { | |
| Meta | |
| StateMeta | |
| } | |
| func (c *StateIdentitiesCommand) Run(args []string) int { | |
| args = c.Meta.process(args) | |
| var statePath string | |
| var jsonOutput bool | |
| cmdFlags := c.Meta.defaultFlagSet("state identities") | |
| cmdFlags.StringVar(&statePath, "state", "", "path") | |
| cmdFlags.BoolVar(&jsonOutput, "json", false, "produce JSON output") | |
| lookupId := cmdFlags.String("id", "", "Restrict output to paths with a resource having the specified ID.") | |
| if err := cmdFlags.Parse(args); err != nil { | |
| c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error())) | |
| return cli.RunResultHelp | |
| } | |
| args = cmdFlags.Args() | |
| if !jsonOutput { | |
| c.Ui.Error( | |
| "The `terraform state identities` command requires the `-json` flag.\n") | |
| cmdFlags.Usage() | |
| return 1 | |
| } | |
| view := arguments.ViewJSON // See above | |
| if statePath != "" { | |
| c.Meta.statePath = statePath | |
| } | |
| // Load the backend | |
| b, diags := c.backend(".", view) | |
| if diags.HasErrors() { | |
| c.showDiagnostics(diags) | |
| return 1 | |
| } | |
| // This is a read-only command | |
| c.ignoreRemoteVersionConflict(b) | |
| // Get the state | |
| env, err := c.Workspace() | |
| if err != nil { | |
| c.Ui.Error(fmt.Sprintf("Error selecting workspace: %s", err)) | |
| return 1 | |
| } | |
| stateMgr, sDiags := b.StateMgr(env) | |
| if sDiags.HasErrors() { | |
| c.Ui.Error(fmt.Sprintf(errStateLoadingState, sDiags.Err())) | |
| return 1 | |
| } | |
| if err := stateMgr.RefreshState(); err != nil { | |
| c.Ui.Error(fmt.Sprintf("Failed to load state: %s", err)) | |
| return 1 | |
| } | |
| state := stateMgr.State() | |
| if state == nil { | |
| c.Ui.Error(errStateNotFound) | |
| return 1 | |
| } | |
| var addrs []addrs.AbsResourceInstance | |
| if len(args) == 0 { | |
| addrs, diags = c.lookupAllResourceInstanceAddrs(state) | |
| } else { | |
| addrs, diags = c.lookupResourceInstanceAddrs(state, args...) | |
| } | |
| if diags.HasErrors() { | |
| c.showDiagnostics(diags) | |
| return 1 | |
| } | |
| output := make(map[string]any) | |
| for _, addr := range addrs { | |
| // If the resource exists but identity is nil, skip it, as it is not required to be present | |
| if is := state.ResourceInstance(addr); is != nil && is.Current.IdentityJSON != nil { | |
| if *lookupId == "" || *lookupId == states.LegacyInstanceObjectID(is.Current) { | |
| var rawIdentity map[string]any | |
| if err := json.Unmarshal(is.Current.IdentityJSON, &rawIdentity); err != nil { | |
| c.Ui.Error(fmt.Sprintf("Failed to unmarshal identity JSON: %s", err)) | |
| return 1 | |
| } | |
| output[addr.String()] = rawIdentity | |
| } | |
| } | |
| } | |
| outputJSON, err := json.MarshalIndent(output, "", " ") | |
| if err != nil { | |
| c.Ui.Error(fmt.Sprintf("Failed to marshal output JSON: %s", err)) | |
| return 1 | |
| } | |
| c.Ui.Output(string(outputJSON)) | |
| c.showDiagnostics(diags) | |
| return 0 | |
| } | |
| func (c *StateIdentitiesCommand) Help() string { | |
| helpText := ` | |
| Usage: terraform [global options] state identities [options] -json [address...] | |
| List the json format of the identities of resources in the Terraform state. | |
| This command lists the identities of resource instances in the Terraform state in json format. | |
| The address argument can be used to filter the instances by resource or module. If | |
| no pattern is given, identities for all resource instances are listed. | |
| The addresses must either be module addresses or absolute resource | |
| addresses, such as: | |
| aws_instance.example | |
| module.example | |
| module.example.module.child | |
| module.example.aws_instance.example | |
| An error will be returned if any of the resources or modules given as | |
| filter addresses do not exist in the state. | |
| Options: | |
| -state=statefile Path to a Terraform state file to use to look | |
| up Terraform-managed resources. By default, Terraform | |
| will consult the state of the currently-selected | |
| workspace. | |
| -id=ID Filters the results to include only instances whose | |
| resource types have an attribute named "id" whose value | |
| equals the given id string. | |
| ` | |
| return strings.TrimSpace(helpText) | |
| } | |
| func (c *StateIdentitiesCommand) Synopsis() string { | |
| return "List the identities of resources in the state" | |
| } |