github.com/opentofu/opentofu@v1.7.1/internal/command/output.go (about) 1 // Copyright (c) The OpenTofu Authors 2 // SPDX-License-Identifier: MPL-2.0 3 // Copyright (c) 2023 HashiCorp, Inc. 4 // SPDX-License-Identifier: MPL-2.0 5 6 package command 7 8 import ( 9 "fmt" 10 "strings" 11 12 "github.com/opentofu/opentofu/internal/command/arguments" 13 "github.com/opentofu/opentofu/internal/command/views" 14 "github.com/opentofu/opentofu/internal/encryption" 15 "github.com/opentofu/opentofu/internal/states" 16 "github.com/opentofu/opentofu/internal/tfdiags" 17 ) 18 19 // OutputCommand is a Command implementation that reads an output 20 // from a OpenTofu state and prints it. 21 type OutputCommand struct { 22 Meta 23 } 24 25 func (c *OutputCommand) Run(rawArgs []string) int { 26 // Parse and apply global view arguments 27 common, rawArgs := arguments.ParseView(rawArgs) 28 c.View.Configure(common) 29 30 // Parse and validate flags 31 args, diags := arguments.ParseOutput(rawArgs) 32 if diags.HasErrors() { 33 c.View.Diagnostics(diags) 34 c.View.HelpPrompt("output") 35 return 1 36 } 37 38 view := views.NewOutput(args.ViewType, c.View) 39 40 // Load the encryption configuration 41 enc, encDiags := c.Encryption() 42 diags = diags.Append(encDiags) 43 if encDiags.HasErrors() { 44 c.View.Diagnostics(diags) 45 return 1 46 } 47 48 // Fetch data from state 49 outputs, diags := c.Outputs(args.StatePath, enc) 50 if diags.HasErrors() { 51 view.Diagnostics(diags) 52 return 1 53 } 54 55 // Render the view 56 viewDiags := view.Output(args.Name, outputs) 57 diags = diags.Append(viewDiags) 58 59 view.Diagnostics(diags) 60 61 if diags.HasErrors() { 62 return 1 63 } 64 65 return 0 66 } 67 68 func (c *OutputCommand) Outputs(statePath string, enc encryption.Encryption) (map[string]*states.OutputValue, tfdiags.Diagnostics) { 69 var diags tfdiags.Diagnostics 70 71 // Allow state path override 72 if statePath != "" { 73 c.Meta.statePath = statePath 74 } 75 76 // Load the backend 77 b, backendDiags := c.Backend(nil, enc.State()) 78 diags = diags.Append(backendDiags) 79 if diags.HasErrors() { 80 return nil, diags 81 } 82 83 // This is a read-only command 84 c.ignoreRemoteVersionConflict(b) 85 86 env, err := c.Workspace() 87 if err != nil { 88 diags = diags.Append(fmt.Errorf("Error selecting workspace: %w", err)) 89 return nil, diags 90 } 91 92 // Get the state 93 stateStore, err := b.StateMgr(env) 94 if err != nil { 95 diags = diags.Append(fmt.Errorf("Failed to load state: %w", err)) 96 return nil, diags 97 } 98 99 output, err := stateStore.GetRootOutputValues() 100 if err != nil { 101 return nil, diags.Append(err) 102 } 103 104 return output, diags 105 } 106 107 func (c *OutputCommand) Help() string { 108 helpText := ` 109 Usage: tofu [global options] output [options] [NAME] 110 111 Reads an output variable from a OpenTofu state file and prints 112 the value. With no additional arguments, output will display all 113 the outputs for the root module. If NAME is not specified, all 114 outputs are printed. 115 116 Options: 117 118 -state=path Path to the state file to read. Defaults to 119 "terraform.tfstate". Ignored when remote 120 state is used. 121 122 -no-color If specified, output won't contain any color. 123 124 -json If specified, machine readable output will be 125 printed in JSON format. 126 127 -raw For value types that can be automatically 128 converted to a string, will print the raw 129 string directly, rather than a human-oriented 130 representation of the value. 131 ` 132 return strings.TrimSpace(helpText) 133 } 134 135 func (c *OutputCommand) Synopsis() string { 136 return "Show output values from your root module" 137 }