github.com/peterbale/terraform@v0.9.0-beta2.0.20170315142748-5723acd55547/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  }