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