terraform/repl/session.go

96 lines
2.3 KiB
Go

package repl
import (
"errors"
"fmt"
"strings"
"github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/terraform"
)
// ErrSessionExit is a special error result that should be checked for
// from Handle to signal a graceful exit.
var ErrSessionExit = errors.New("session exit")
// Session represents the state for a single REPL session.
type Session struct {
// Interpolater is used for calculating interpolations
Interpolater *terraform.Interpolater
}
// Handle handles a single line of input from the REPL.
//
// This is a stateful operation if a command is given (such as setting
// a variable). This function should not be called in parallel.
//
// The return value is the output and the error to show.
func (s *Session) Handle(line string) (string, error) {
switch {
case strings.TrimSpace(line) == "exit":
return "", ErrSessionExit
case strings.TrimSpace(line) == "help":
return s.handleHelp()
default:
return s.handleEval(line)
}
}
func (s *Session) handleEval(line string) (string, error) {
// Wrap the line to make it an interpolation.
line = fmt.Sprintf("${%s}", line)
// Parse the line
raw, err := config.NewRawConfig(map[string]interface{}{
"value": line,
})
if err != nil {
return "", err
}
// Set the value
raw.Key = "value"
// Get the values
vars, err := s.Interpolater.Values(&terraform.InterpolationScope{
Path: []string{"root"},
}, raw.Variables)
if err != nil {
return "", err
}
// Interpolate
if err := raw.Interpolate(vars); err != nil {
return "", err
}
// If we have any unknown keys, let the user know.
if ks := raw.UnknownKeys(); len(ks) > 0 {
return "", fmt.Errorf("unknown values referenced, can't compute value")
}
// Read the value
result, err := FormatResult(raw.Value())
if err != nil {
return "", err
}
return result, nil
}
func (s *Session) handleHelp() (string, error) {
text := `
The Terraform console allows you to experiment with Terraform interpolations.
You may access resources in the state (if you have one) just as you would
from a configuration. For example: "aws_instance.foo.id" would evaluate
to the ID of "aws_instance.foo" if it exists in your state.
Type in the interpolation to test and hit <enter> to see the result.
To exit the console, type "exit" and hit <enter>, or use Control-C or
Control-D.
`
return strings.TrimSpace(text), nil
}