github.com/jd3nn1s/terraform@v0.9.6-0.20170906225847-13878347b7a1/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, 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 lockCtx, cancel := context.WithTimeout(context.Background(), c.stateLockTimeout) 118 defer cancel() 119 120 // Lock the state if we can 121 lockInfo := state.NewLockInfo() 122 lockInfo.Operation = "workspace new" 123 lockID, err := clistate.Lock(lockCtx, sMgr, lockInfo, c.Ui, c.Colorize()) 124 if err != nil { 125 c.Ui.Error(fmt.Sprintf("Error locking state: %s", err)) 126 return 1 127 } 128 defer clistate.Unlock(sMgr, lockID, c.Ui, c.Colorize()) 129 } 130 131 // read the existing state file 132 stateFile, err := os.Open(statePath) 133 if err != nil { 134 c.Ui.Error(err.Error()) 135 return 1 136 } 137 138 s, err := terraform.ReadState(stateFile) 139 if err != nil { 140 c.Ui.Error(err.Error()) 141 return 1 142 } 143 144 // save the existing state in the new Backend. 145 err = sMgr.WriteState(s) 146 if err != nil { 147 c.Ui.Error(err.Error()) 148 return 1 149 } 150 err = sMgr.PersistState() 151 if err != nil { 152 c.Ui.Error(err.Error()) 153 return 1 154 } 155 156 return 0 157 } 158 159 func (c *WorkspaceNewCommand) Help() string { 160 helpText := ` 161 Usage: terraform workspace new [OPTIONS] NAME [DIR] 162 163 Create a new Terraform workspace. 164 165 166 Options: 167 168 -state=path Copy an existing state file into the new workspace. 169 ` 170 return strings.TrimSpace(helpText) 171 } 172 173 func (c *WorkspaceNewCommand) Synopsis() string { 174 return "Create a new workspace" 175 }