github.com/spirius/terraform@v0.10.0-beta2.0.20170714185654-87b2c0cf8fea/command/workspace_delete.go (about)

     1  package command
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"strings"
     7  
     8  	"github.com/hashicorp/terraform/command/clistate"
     9  	"github.com/hashicorp/terraform/state"
    10  	"github.com/mitchellh/cli"
    11  )
    12  
    13  type WorkspaceDeleteCommand struct {
    14  	Meta
    15  	LegacyName bool
    16  }
    17  
    18  func (c *WorkspaceDeleteCommand) Run(args []string) int {
    19  	args, err := c.Meta.process(args, true)
    20  	if err != nil {
    21  		return 1
    22  	}
    23  
    24  	envCommandShowWarning(c.Ui, c.LegacyName)
    25  
    26  	force := false
    27  	cmdFlags := c.Meta.flagSet("workspace")
    28  	cmdFlags.BoolVar(&force, "force", false, "force removal of a non-empty workspace")
    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 NAME.\n")
    36  		return cli.RunResultHelp
    37  	}
    38  
    39  	delEnv := args[0]
    40  
    41  	if !validWorkspaceName(delEnv) {
    42  		c.Ui.Error(fmt.Sprintf(envInvalidName, delEnv))
    43  		return 1
    44  	}
    45  
    46  	configPath, err := ModulePath(args[1:])
    47  	if err != nil {
    48  		c.Ui.Error(err.Error())
    49  		return 1
    50  	}
    51  
    52  	cfg, err := c.Config(configPath)
    53  	if err != nil {
    54  		c.Ui.Error(fmt.Sprintf("Failed to load root config module: %s", err))
    55  		return 1
    56  	}
    57  
    58  	// Load the backend
    59  	b, err := c.Backend(&BackendOpts{
    60  		Config: cfg,
    61  	})
    62  
    63  	if err != nil {
    64  		c.Ui.Error(fmt.Sprintf("Failed to load backend: %s", err))
    65  		return 1
    66  	}
    67  
    68  	states, err := b.States()
    69  	if err != nil {
    70  		c.Ui.Error(err.Error())
    71  		return 1
    72  	}
    73  
    74  	exists := false
    75  	for _, s := range states {
    76  		if delEnv == s {
    77  			exists = true
    78  			break
    79  		}
    80  	}
    81  
    82  	if !exists {
    83  		c.Ui.Error(fmt.Sprintf(strings.TrimSpace(envDoesNotExist), delEnv))
    84  		return 1
    85  	}
    86  
    87  	if delEnv == c.Workspace() {
    88  		c.Ui.Error(fmt.Sprintf(strings.TrimSpace(envDelCurrent), delEnv))
    89  		return 1
    90  	}
    91  
    92  	// we need the actual state to see if it's empty
    93  	sMgr, err := b.State(delEnv)
    94  	if err != nil {
    95  		c.Ui.Error(err.Error())
    96  		return 1
    97  	}
    98  
    99  	if err := sMgr.RefreshState(); err != nil {
   100  		c.Ui.Error(err.Error())
   101  		return 1
   102  	}
   103  
   104  	hasResources := sMgr.State().HasResources()
   105  
   106  	if hasResources && !force {
   107  		c.Ui.Error(fmt.Sprintf(strings.TrimSpace(envNotEmpty), delEnv))
   108  		return 1
   109  	}
   110  
   111  	// Honor the lock request, for consistency and one final safety check.
   112  	if c.stateLock {
   113  		lockCtx, cancel := context.WithTimeout(context.Background(), c.stateLockTimeout)
   114  		defer cancel()
   115  
   116  		// Lock the state if we can
   117  		lockInfo := state.NewLockInfo()
   118  		lockInfo.Operation = "workspace delete"
   119  		lockID, err := clistate.Lock(lockCtx, sMgr, lockInfo, c.Ui, c.Colorize())
   120  		if err != nil {
   121  			c.Ui.Error(fmt.Sprintf("Error locking state: %s", err))
   122  			return 1
   123  		}
   124  
   125  		// We need to release the lock just before deleting the state, in case
   126  		// the backend can't remove the resource while holding the lock. This
   127  		// is currently true for Windows local files.
   128  		//
   129  		// TODO: While there is little safety in locking while deleting the
   130  		// state, it might be nice to be able to coordinate processes around
   131  		// state deletion, i.e. in a CI environment. Adding Delete() as a
   132  		// required method of States would allow the removal of the resource to
   133  		// be delegated from the Backend to the State itself.
   134  		clistate.Unlock(sMgr, lockID, c.Ui, c.Colorize())
   135  	}
   136  
   137  	err = b.DeleteState(delEnv)
   138  	if err != nil {
   139  		c.Ui.Error(err.Error())
   140  		return 1
   141  	}
   142  
   143  	c.Ui.Output(
   144  		c.Colorize().Color(
   145  			fmt.Sprintf(envDeleted, delEnv),
   146  		),
   147  	)
   148  
   149  	if hasResources {
   150  		c.Ui.Output(
   151  			c.Colorize().Color(
   152  				fmt.Sprintf(envWarnNotEmpty, delEnv),
   153  			),
   154  		)
   155  	}
   156  
   157  	return 0
   158  }
   159  func (c *WorkspaceDeleteCommand) Help() string {
   160  	helpText := `
   161  Usage: terraform workspace delete [OPTIONS] NAME [DIR]
   162  
   163    Delete a Terraform workspace
   164  
   165  
   166  Options:
   167  
   168      -force    remove a non-empty workspace.
   169  `
   170  	return strings.TrimSpace(helpText)
   171  }
   172  
   173  func (c *WorkspaceDeleteCommand) Synopsis() string {
   174  	return "Delete a workspace"
   175  }