github.com/vtorhonen/terraform@v0.9.0-beta2.0.20170307220345-5d894e4ffda7/command/console.go (about) 1 package command 2 3 import ( 4 "bufio" 5 "fmt" 6 "strings" 7 8 "github.com/hashicorp/terraform/backend" 9 "github.com/hashicorp/terraform/helper/wrappedstreams" 10 "github.com/hashicorp/terraform/repl" 11 12 "github.com/mitchellh/cli" 13 ) 14 15 // ConsoleCommand is a Command implementation that applies a Terraform 16 // configuration and actually builds or changes infrastructure. 17 type ConsoleCommand struct { 18 Meta 19 20 // When this channel is closed, the apply will be cancelled. 21 ShutdownCh <-chan struct{} 22 } 23 24 func (c *ConsoleCommand) Run(args []string) int { 25 args = c.Meta.process(args, true) 26 cmdFlags := c.Meta.flagSet("console") 27 cmdFlags.StringVar(&c.Meta.statePath, "state", DefaultStateFilename, "path") 28 cmdFlags.Usage = func() { c.Ui.Error(c.Help()) } 29 if err := cmdFlags.Parse(args); err != nil { 30 return 1 31 } 32 33 configPath, err := ModulePath(cmdFlags.Args()) 34 if err != nil { 35 c.Ui.Error(err.Error()) 36 return 1 37 } 38 39 // Load the module 40 mod, err := c.Module(configPath) 41 if err != nil { 42 c.Ui.Error(fmt.Sprintf("Failed to load root config module: %s", err)) 43 return 1 44 } 45 46 // Load the backend 47 b, err := c.Backend(&BackendOpts{ConfigPath: configPath}) 48 if err != nil { 49 c.Ui.Error(fmt.Sprintf("Failed to load backend: %s", err)) 50 return 1 51 } 52 53 // We require a local backend 54 local, ok := b.(backend.Local) 55 if !ok { 56 c.Ui.Error(ErrUnsupportedLocalOp) 57 return 1 58 } 59 60 // Build the operation 61 opReq := c.Operation() 62 opReq.Module = mod 63 64 // Get the context 65 ctx, _, err := local.Context(opReq) 66 if err != nil { 67 c.Ui.Error(err.Error()) 68 return 1 69 } 70 71 // Setup the UI so we can output directly to stdout 72 ui := &cli.BasicUi{ 73 Writer: wrappedstreams.Stdout(), 74 ErrorWriter: wrappedstreams.Stderr(), 75 } 76 77 // IO Loop 78 session := &repl.Session{ 79 Interpolater: ctx.Interpolater(), 80 } 81 82 // Determine if stdin is a pipe. If so, we evaluate directly. 83 if c.StdinPiped() { 84 return c.modePiped(session, ui) 85 } 86 87 return c.modeInteractive(session, ui) 88 } 89 90 func (c *ConsoleCommand) modePiped(session *repl.Session, ui cli.Ui) int { 91 var lastResult string 92 scanner := bufio.NewScanner(wrappedstreams.Stdin()) 93 for scanner.Scan() { 94 // Handle it. If there is an error exit immediately 95 result, err := session.Handle(strings.TrimSpace(scanner.Text())) 96 if err != nil { 97 ui.Error(err.Error()) 98 return 1 99 } 100 101 // Store the last result 102 lastResult = result 103 } 104 105 // Output the final result 106 ui.Output(lastResult) 107 108 return 0 109 } 110 111 func (c *ConsoleCommand) Help() string { 112 helpText := ` 113 Usage: terraform console [options] [DIR] 114 115 Starts an interactive console for experimenting with Terraform 116 interpolations. 117 118 This will open an interactive console that you can use to type 119 interpolations into and inspect their values. This command loads the 120 current state. This lets you explore and test interpolations before 121 using them in future configurations. 122 123 This command will never modify your state. 124 125 DIR can be set to a directory with a Terraform state to load. By 126 default, this will default to the current working directory. 127 128 Options: 129 130 -state=path Path to read state. Defaults to "terraform.tfstate" 131 132 -var 'foo=bar' Set a variable in the Terraform configuration. This 133 flag can be set multiple times. 134 135 -var-file=foo Set variables in the Terraform configuration from 136 a file. If "terraform.tfvars" is present, it will be 137 automatically loaded if this flag is not specified. 138 139 140 ` 141 return strings.TrimSpace(helpText) 142 } 143 144 func (c *ConsoleCommand) Synopsis() string { 145 return "Interactive console for Terraform interpolations" 146 }