github.com/graywolf-at-work-2/terraform-vendor@v1.4.5/internal/command/workspace_new.go (about) 1 package command 2 3 import ( 4 "fmt" 5 "os" 6 "strings" 7 "time" 8 9 "github.com/hashicorp/terraform/internal/command/arguments" 10 "github.com/hashicorp/terraform/internal/command/clistate" 11 "github.com/hashicorp/terraform/internal/command/views" 12 "github.com/hashicorp/terraform/internal/states/statefile" 13 "github.com/hashicorp/terraform/internal/tfdiags" 14 "github.com/mitchellh/cli" 15 "github.com/posener/complete" 16 ) 17 18 type WorkspaceNewCommand struct { 19 Meta 20 LegacyName bool 21 } 22 23 func (c *WorkspaceNewCommand) Run(args []string) int { 24 args = c.Meta.process(args) 25 envCommandShowWarning(c.Ui, c.LegacyName) 26 27 var stateLock bool 28 var stateLockTimeout time.Duration 29 var statePath string 30 cmdFlags := c.Meta.defaultFlagSet("workspace new") 31 cmdFlags.BoolVar(&stateLock, "lock", true, "lock state") 32 cmdFlags.DurationVar(&stateLockTimeout, "lock-timeout", 0, "lock timeout") 33 cmdFlags.StringVar(&statePath, "state", "", "terraform state file") 34 cmdFlags.Usage = func() { c.Ui.Error(c.Help()) } 35 if err := cmdFlags.Parse(args); err != nil { 36 c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error())) 37 return 1 38 } 39 40 args = cmdFlags.Args() 41 if len(args) != 1 { 42 c.Ui.Error("Expected a single argument: NAME.\n") 43 return cli.RunResultHelp 44 } 45 46 workspace := args[0] 47 48 if !validWorkspaceName(workspace) { 49 c.Ui.Error(fmt.Sprintf(envInvalidName, workspace)) 50 return 1 51 } 52 53 // You can't ask to create a workspace when you're overriding the 54 // workspace name to be something different. 55 if current, isOverridden := c.WorkspaceOverridden(); current != workspace && isOverridden { 56 c.Ui.Error(envIsOverriddenNewError) 57 return 1 58 } 59 60 configPath, err := ModulePath(args[1:]) 61 if err != nil { 62 c.Ui.Error(err.Error()) 63 return 1 64 } 65 66 var diags tfdiags.Diagnostics 67 68 backendConfig, backendDiags := c.loadBackendConfig(configPath) 69 diags = diags.Append(backendDiags) 70 if diags.HasErrors() { 71 c.showDiagnostics(diags) 72 return 1 73 } 74 75 // Load the backend 76 b, backendDiags := c.Backend(&BackendOpts{ 77 Config: backendConfig, 78 }) 79 diags = diags.Append(backendDiags) 80 if backendDiags.HasErrors() { 81 c.showDiagnostics(diags) 82 return 1 83 } 84 85 // This command will not write state 86 c.ignoreRemoteVersionConflict(b) 87 88 workspaces, err := b.Workspaces() 89 if err != nil { 90 c.Ui.Error(fmt.Sprintf("Failed to get configured named states: %s", err)) 91 return 1 92 } 93 for _, ws := range workspaces { 94 if workspace == ws { 95 c.Ui.Error(fmt.Sprintf(envExists, workspace)) 96 return 1 97 } 98 } 99 100 _, err = b.StateMgr(workspace) 101 if err != nil { 102 c.Ui.Error(err.Error()) 103 return 1 104 } 105 106 // now set the current workspace locally 107 if err := c.SetWorkspace(workspace); err != nil { 108 c.Ui.Error(fmt.Sprintf("Error selecting new workspace: %s", err)) 109 return 1 110 } 111 112 c.Ui.Output(c.Colorize().Color(fmt.Sprintf( 113 strings.TrimSpace(envCreated), workspace))) 114 115 if statePath == "" { 116 // if we're not loading a state, then we're done 117 return 0 118 } 119 120 // load the new Backend state 121 stateMgr, err := b.StateMgr(workspace) 122 if err != nil { 123 c.Ui.Error(err.Error()) 124 return 1 125 } 126 127 if stateLock { 128 stateLocker := clistate.NewLocker(c.stateLockTimeout, views.NewStateLocker(arguments.ViewHuman, c.View)) 129 if diags := stateLocker.Lock(stateMgr, "workspace-new"); diags.HasErrors() { 130 c.showDiagnostics(diags) 131 return 1 132 } 133 defer func() { 134 if diags := stateLocker.Unlock(); diags.HasErrors() { 135 c.showDiagnostics(diags) 136 } 137 }() 138 } 139 140 // read the existing state file 141 f, err := os.Open(statePath) 142 if err != nil { 143 c.Ui.Error(err.Error()) 144 return 1 145 } 146 147 stateFile, err := statefile.Read(f) 148 if err != nil { 149 c.Ui.Error(err.Error()) 150 return 1 151 } 152 153 // save the existing state in the new Backend. 154 err = stateMgr.WriteState(stateFile.State) 155 if err != nil { 156 c.Ui.Error(err.Error()) 157 return 1 158 } 159 err = stateMgr.PersistState(nil) 160 if err != nil { 161 c.Ui.Error(err.Error()) 162 return 1 163 } 164 165 return 0 166 } 167 168 func (c *WorkspaceNewCommand) AutocompleteArgs() complete.Predictor { 169 return completePredictSequence{ 170 complete.PredictAnything, 171 complete.PredictDirs(""), 172 } 173 } 174 175 func (c *WorkspaceNewCommand) AutocompleteFlags() complete.Flags { 176 return complete.Flags{ 177 "-state": complete.PredictFiles("*.tfstate"), 178 } 179 } 180 181 func (c *WorkspaceNewCommand) Help() string { 182 helpText := ` 183 Usage: terraform [global options] workspace new [OPTIONS] NAME 184 185 Create a new Terraform workspace. 186 187 Options: 188 189 -lock=false Don't hold a state lock during the operation. This is 190 dangerous if others might concurrently run commands 191 against the same workspace. 192 193 -lock-timeout=0s Duration to retry a state lock. 194 195 -state=path Copy an existing state file into the new workspace. 196 197 ` 198 return strings.TrimSpace(helpText) 199 } 200 201 func (c *WorkspaceNewCommand) Synopsis() string { 202 return "Create a new workspace" 203 }