kubeform.dev/terraform-backend-sdk@v0.0.0-20220310143633-45f07fe731c5/command/state_show.go (about) 1 package command 2 3 import ( 4 "fmt" 5 "os" 6 "strings" 7 8 "kubeform.dev/terraform-backend-sdk/addrs" 9 "kubeform.dev/terraform-backend-sdk/backend" 10 "kubeform.dev/terraform-backend-sdk/command/format" 11 "kubeform.dev/terraform-backend-sdk/states" 12 "github.com/mitchellh/cli" 13 ) 14 15 // StateShowCommand is a Command implementation that shows a single resource. 16 type StateShowCommand struct { 17 Meta 18 StateMeta 19 } 20 21 func (c *StateShowCommand) Run(args []string) int { 22 args = c.Meta.process(args) 23 cmdFlags := c.Meta.defaultFlagSet("state show") 24 cmdFlags.StringVar(&c.Meta.statePath, "state", "", "path") 25 if err := cmdFlags.Parse(args); err != nil { 26 c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error())) 27 return 1 28 } 29 args = cmdFlags.Args() 30 if len(args) != 1 { 31 c.Ui.Error("Exactly one argument expected.\n") 32 return cli.RunResultHelp 33 } 34 35 // Check for user-supplied plugin path 36 var err error 37 if c.pluginPath, err = c.loadPluginPath(); err != nil { 38 c.Ui.Error(fmt.Sprintf("Error loading plugin path: %s", err)) 39 return 1 40 } 41 42 // Load the backend 43 b, backendDiags := c.Backend(nil) 44 if backendDiags.HasErrors() { 45 c.showDiagnostics(backendDiags) 46 return 1 47 } 48 49 // We require a local backend 50 local, ok := b.(backend.Local) 51 if !ok { 52 c.Ui.Error(ErrUnsupportedLocalOp) 53 return 1 54 } 55 56 // This is a read-only command 57 c.ignoreRemoteBackendVersionConflict(b) 58 59 // Check if the address can be parsed 60 addr, addrDiags := addrs.ParseAbsResourceInstanceStr(args[0]) 61 if addrDiags.HasErrors() { 62 c.Ui.Error(fmt.Sprintf(errParsingAddress, args[0])) 63 return 1 64 } 65 66 // We expect the config dir to always be the cwd 67 cwd, err := os.Getwd() 68 if err != nil { 69 c.Ui.Error(fmt.Sprintf("Error getting cwd: %s", err)) 70 return 1 71 } 72 73 // Build the operation (required to get the schemas) 74 opReq := c.Operation(b) 75 opReq.AllowUnsetVariables = true 76 opReq.ConfigDir = cwd 77 78 opReq.ConfigLoader, err = c.initConfigLoader() 79 if err != nil { 80 c.Ui.Error(fmt.Sprintf("Error initializing config loader: %s", err)) 81 return 1 82 } 83 84 // Get the context (required to get the schemas) 85 lr, _, ctxDiags := local.LocalRun(opReq) 86 if ctxDiags.HasErrors() { 87 c.showDiagnostics(ctxDiags) 88 return 1 89 } 90 91 // Get the schemas from the context 92 schemas, diags := lr.Core.Schemas(lr.Config, lr.InputState) 93 if diags.HasErrors() { 94 c.showDiagnostics(diags) 95 return 1 96 } 97 98 // Get the state 99 env, err := c.Workspace() 100 if err != nil { 101 c.Ui.Error(fmt.Sprintf("Error selecting workspace: %s", err)) 102 return 1 103 } 104 stateMgr, err := b.StateMgr(env) 105 if err != nil { 106 c.Ui.Error(fmt.Sprintf(errStateLoadingState, err)) 107 return 1 108 } 109 if err := stateMgr.RefreshState(); err != nil { 110 c.Ui.Error(fmt.Sprintf("Failed to refresh state: %s", err)) 111 return 1 112 } 113 114 state := stateMgr.State() 115 if state == nil { 116 c.Ui.Error(errStateNotFound) 117 return 1 118 } 119 120 is := state.ResourceInstance(addr) 121 if !is.HasCurrent() { 122 c.Ui.Error(errNoInstanceFound) 123 return 1 124 } 125 126 // check if the resource has a configured provider, otherwise this will use the default provider 127 rs := state.Resource(addr.ContainingResource()) 128 absPc := addrs.AbsProviderConfig{ 129 Provider: rs.ProviderConfig.Provider, 130 Alias: rs.ProviderConfig.Alias, 131 Module: addrs.RootModule, 132 } 133 singleInstance := states.NewState() 134 singleInstance.EnsureModule(addr.Module).SetResourceInstanceCurrent( 135 addr.Resource, 136 is.Current, 137 absPc, 138 ) 139 140 output := format.State(&format.StateOpts{ 141 State: singleInstance, 142 Color: c.Colorize(), 143 Schemas: schemas, 144 }) 145 c.Ui.Output(output[strings.Index(output, "#"):]) 146 147 return 0 148 } 149 150 func (c *StateShowCommand) Help() string { 151 helpText := ` 152 Usage: terraform [global options] state show [options] ADDRESS 153 154 Shows the attributes of a resource in the Terraform state. 155 156 This command shows the attributes of a single resource in the Terraform 157 state. The address argument must be used to specify a single resource. 158 You can view the list of available resources with "terraform state list". 159 160 Options: 161 162 -state=statefile Path to a Terraform state file to use to look 163 up Terraform-managed resources. By default it will 164 use the state "terraform.tfstate" if it exists. 165 166 ` 167 return strings.TrimSpace(helpText) 168 } 169 170 func (c *StateShowCommand) Synopsis() string { 171 return "Show a resource in the state" 172 } 173 174 const errNoInstanceFound = `No instance found for the given address! 175 176 This command requires that the address references one specific instance. 177 To view the available instances, use "terraform state list". Please modify 178 the address to reference a specific instance.` 179 180 const errParsingAddress = `Error parsing instance address: %s 181 182 This command requires that the address references one specific instance. 183 To view the available instances, use "terraform state list". Please modify 184 the address to reference a specific instance.`