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