github.com/kevholditch/terraform@v0.9.7-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 }