github.com/richardmarshall/terraform@v0.9.5-0.20170429023105-15704cc6ee35/command/env_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 EnvNewCommand struct { 16 Meta 17 } 18 19 func (c *EnvNewCommand) Run(args []string) int { 20 args = c.Meta.process(args, true) 21 22 statePath := "" 23 24 cmdFlags := c.Meta.flagSet("env new") 25 cmdFlags.StringVar(&statePath, "state", "", "terraform state file") 26 cmdFlags.Usage = func() { c.Ui.Error(c.Help()) } 27 if err := cmdFlags.Parse(args); err != nil { 28 return 1 29 } 30 args = cmdFlags.Args() 31 if len(args) == 0 { 32 c.Ui.Error("Expected a single argument: NAME.\n") 33 return cli.RunResultHelp 34 } 35 36 newEnv := args[0] 37 38 if !validEnvName(newEnv) { 39 c.Ui.Error(fmt.Sprintf(envInvalidName, newEnv)) 40 return 1 41 } 42 43 configPath, err := ModulePath(args[1:]) 44 if err != nil { 45 c.Ui.Error(err.Error()) 46 return 1 47 } 48 49 // Load the backend 50 b, err := c.Backend(&BackendOpts{ConfigPath: configPath}) 51 if err != nil { 52 c.Ui.Error(fmt.Sprintf("Failed to load backend: %s", err)) 53 return 1 54 } 55 56 states, err := b.States() 57 for _, s := range states { 58 if newEnv == s { 59 c.Ui.Error(fmt.Sprintf(envExists, newEnv)) 60 return 1 61 } 62 } 63 64 _, err = b.State(newEnv) 65 if err != nil { 66 c.Ui.Error(err.Error()) 67 return 1 68 } 69 70 // now save the current env locally 71 if err := c.SetEnv(newEnv); err != nil { 72 c.Ui.Error(fmt.Sprintf("error saving new environment name: %s", err)) 73 return 1 74 } 75 76 c.Ui.Output(c.Colorize().Color(fmt.Sprintf( 77 strings.TrimSpace(envCreated), newEnv))) 78 79 if statePath == "" { 80 // if we're not loading a state, then we're done 81 return 0 82 } 83 84 // load the new Backend state 85 sMgr, err := b.State(newEnv) 86 if err != nil { 87 c.Ui.Error(err.Error()) 88 return 1 89 } 90 91 if c.stateLock { 92 lockCtx, cancel := context.WithTimeout(context.Background(), c.stateLockTimeout) 93 defer cancel() 94 95 // Lock the state if we can 96 lockInfo := state.NewLockInfo() 97 lockInfo.Operation = "env new" 98 lockID, err := clistate.Lock(lockCtx, sMgr, lockInfo, c.Ui, c.Colorize()) 99 if err != nil { 100 c.Ui.Error(fmt.Sprintf("Error locking state: %s", err)) 101 return 1 102 } 103 defer clistate.Unlock(sMgr, lockID, c.Ui, c.Colorize()) 104 } 105 106 // read the existing state file 107 stateFile, err := os.Open(statePath) 108 if err != nil { 109 c.Ui.Error(err.Error()) 110 return 1 111 } 112 113 s, err := terraform.ReadState(stateFile) 114 if err != nil { 115 c.Ui.Error(err.Error()) 116 return 1 117 } 118 119 // save the existing state in the new Backend. 120 err = sMgr.WriteState(s) 121 if err != nil { 122 c.Ui.Error(err.Error()) 123 return 1 124 } 125 err = sMgr.PersistState() 126 if err != nil { 127 c.Ui.Error(err.Error()) 128 return 1 129 } 130 131 return 0 132 } 133 134 func (c *EnvNewCommand) Help() string { 135 helpText := ` 136 Usage: terraform env new [OPTIONS] NAME [DIR] 137 138 Create a new Terraform environment. 139 140 141 Options: 142 143 -state=path Copy an existing state file into the new environment. 144 ` 145 return strings.TrimSpace(helpText) 146 } 147 148 func (c *EnvNewCommand) Synopsis() string { 149 return "Create a new environment" 150 }