github.com/paybyphone/terraform@v0.9.5-0.20170613192930-9706042ddd51/command/workspace_new.go (about)

     1  package command
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"os"
     7  	"strings"
     8  
     9  	"github.com/hashicorp/terraform/command/clistate"
    10  	"github.com/hashicorp/terraform/state"
    11  	"github.com/hashicorp/terraform/terraform"
    12  	"github.com/mitchellh/cli"
    13  )
    14  
    15  type WorkspaceNewCommand struct {
    16  	Meta
    17  	LegacyName bool
    18  }
    19  
    20  func (c *WorkspaceNewCommand) Run(args []string) int {
    21  	args = c.Meta.process(args, true)
    22  
    23  	envCommandShowWarning(c.Ui, c.LegacyName)
    24  
    25  	statePath := ""
    26  
    27  	cmdFlags := c.Meta.flagSet("workspace new")
    28  	cmdFlags.StringVar(&statePath, "state", "", "terraform state file")
    29  	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
    30  	if err := cmdFlags.Parse(args); err != nil {
    31  		return 1
    32  	}
    33  	args = cmdFlags.Args()
    34  	if len(args) == 0 {
    35  		c.Ui.Error("Expected a single argument: NAME.\n")
    36  		return cli.RunResultHelp
    37  	}
    38  
    39  	newEnv := args[0]
    40  
    41  	if !validWorkspaceName(newEnv) {
    42  		c.Ui.Error(fmt.Sprintf(envInvalidName, newEnv))
    43  		return 1
    44  	}
    45  
    46  	// You can't ask to create a workspace when you're overriding the
    47  	// workspace name to be something different.
    48  	if current, isOverridden := c.WorkspaceOverridden(); current != newEnv && isOverridden {
    49  		c.Ui.Error(envIsOverriddenNewError)
    50  		return 1
    51  	}
    52  
    53  	configPath, err := ModulePath(args[1:])
    54  	if err != nil {
    55  		c.Ui.Error(err.Error())
    56  		return 1
    57  	}
    58  
    59  	conf, err := c.Config(configPath)
    60  	if err != nil {
    61  		c.Ui.Error(fmt.Sprintf("Failed to load root config module: %s", err))
    62  	}
    63  
    64  	// Load the backend
    65  	b, err := c.Backend(&BackendOpts{
    66  		Config: conf,
    67  	})
    68  
    69  	if err != nil {
    70  		c.Ui.Error(fmt.Sprintf("Failed to load backend: %s", err))
    71  		return 1
    72  	}
    73  
    74  	states, err := b.States()
    75  	for _, s := range states {
    76  		if newEnv == s {
    77  			c.Ui.Error(fmt.Sprintf(envExists, newEnv))
    78  			return 1
    79  		}
    80  	}
    81  
    82  	_, err = b.State(newEnv)
    83  	if err != nil {
    84  		c.Ui.Error(err.Error())
    85  		return 1
    86  	}
    87  
    88  	// now set the current workspace locally
    89  	if err := c.SetWorkspace(newEnv); err != nil {
    90  		c.Ui.Error(fmt.Sprintf("Error selecting new workspace: %s", err))
    91  		return 1
    92  	}
    93  
    94  	c.Ui.Output(c.Colorize().Color(fmt.Sprintf(
    95  		strings.TrimSpace(envCreated), newEnv)))
    96  
    97  	if statePath == "" {
    98  		// if we're not loading a state, then we're done
    99  		return 0
   100  	}
   101  
   102  	// load the new Backend state
   103  	sMgr, err := b.State(newEnv)
   104  	if err != nil {
   105  		c.Ui.Error(err.Error())
   106  		return 1
   107  	}
   108  
   109  	if c.stateLock {
   110  		lockCtx, cancel := context.WithTimeout(context.Background(), c.stateLockTimeout)
   111  		defer cancel()
   112  
   113  		// Lock the state if we can
   114  		lockInfo := state.NewLockInfo()
   115  		lockInfo.Operation = "workspace new"
   116  		lockID, err := clistate.Lock(lockCtx, sMgr, lockInfo, c.Ui, c.Colorize())
   117  		if err != nil {
   118  			c.Ui.Error(fmt.Sprintf("Error locking state: %s", err))
   119  			return 1
   120  		}
   121  		defer clistate.Unlock(sMgr, lockID, c.Ui, c.Colorize())
   122  	}
   123  
   124  	// read the existing state file
   125  	stateFile, err := os.Open(statePath)
   126  	if err != nil {
   127  		c.Ui.Error(err.Error())
   128  		return 1
   129  	}
   130  
   131  	s, err := terraform.ReadState(stateFile)
   132  	if err != nil {
   133  		c.Ui.Error(err.Error())
   134  		return 1
   135  	}
   136  
   137  	// save the existing state in the new Backend.
   138  	err = sMgr.WriteState(s)
   139  	if err != nil {
   140  		c.Ui.Error(err.Error())
   141  		return 1
   142  	}
   143  	err = sMgr.PersistState()
   144  	if err != nil {
   145  		c.Ui.Error(err.Error())
   146  		return 1
   147  	}
   148  
   149  	return 0
   150  }
   151  
   152  func (c *WorkspaceNewCommand) Help() string {
   153  	helpText := `
   154  Usage: terraform workspace new [OPTIONS] NAME [DIR]
   155  
   156    Create a new Terraform workspace.
   157  
   158  
   159  Options:
   160  
   161      -state=path    Copy an existing state file into the new workspace.
   162  `
   163  	return strings.TrimSpace(helpText)
   164  }
   165  
   166  func (c *WorkspaceNewCommand) Synopsis() string {
   167  	return "Create a new workspace"
   168  }