github.com/skyscape-cloud-services/terraform@v0.9.2-0.20170609144644-7ece028a1747/command/clistate/state.go (about)

     1  // Package state exposes common helpers for working with state from the CLI.
     2  //
     3  // This is a separate package so that backends can use this for consistent
     4  // messaging without creating a circular reference to the command package.
     5  package clistate
     6  
     7  import (
     8  	"context"
     9  	"fmt"
    10  	"strings"
    11  	"time"
    12  
    13  	"github.com/hashicorp/errwrap"
    14  	"github.com/hashicorp/terraform/helper/slowmessage"
    15  	"github.com/hashicorp/terraform/state"
    16  	"github.com/mitchellh/cli"
    17  	"github.com/mitchellh/colorstring"
    18  )
    19  
    20  const (
    21  	LockThreshold    = 400 * time.Millisecond
    22  	LockMessage      = "Acquiring state lock. This may take a few moments..."
    23  	LockErrorMessage = `Error acquiring the state lock: {{err}}
    24  
    25  Terraform acquires a state lock to protect the state from being written
    26  by multiple users at the same time. Please resolve the issue above and try
    27  again. For most commands, you can disable locking with the "-lock=false"
    28  flag, but this is not recommended.`
    29  
    30  	UnlockMessage      = "Releasing state lock. This may take a few moments..."
    31  	UnlockErrorMessage = `
    32  [reset][bold][red]Error releasing the state lock![reset][red]
    33  
    34  Error message: %s
    35  
    36  Terraform acquires a lock when accessing your state to prevent others
    37  running Terraform to potentially modify the state at the same time. An
    38  error occurred while releasing this lock. This could mean that the lock
    39  did or did not release properly. If the lock didn't release properly,
    40  Terraform may not be able to run future commands since it'll appear as if
    41  the lock is held.
    42  
    43  In this scenario, please call the "force-unlock" command to unlock the
    44  state manually. This is a very dangerous operation since if it is done
    45  erroneously it could result in two people modifying state at the same time.
    46  Only call this command if you're certain that the unlock above failed and
    47  that no one else is holding a lock.
    48  `
    49  )
    50  
    51  // Lock locks the given state and outputs to the user if locking
    52  // is taking longer than the threshold.  The lock is retried until the context
    53  // is cancelled.
    54  func Lock(ctx context.Context, s state.State, info *state.LockInfo, ui cli.Ui, color *colorstring.Colorize) (string, error) {
    55  	var lockID string
    56  
    57  	err := slowmessage.Do(LockThreshold, func() error {
    58  		id, err := state.LockWithContext(ctx, s, info)
    59  		lockID = id
    60  		return err
    61  	}, func() {
    62  		if ui != nil {
    63  			ui.Output(color.Color(LockMessage))
    64  		}
    65  	})
    66  
    67  	if err != nil {
    68  		err = errwrap.Wrapf(strings.TrimSpace(LockErrorMessage), err)
    69  	}
    70  
    71  	return lockID, err
    72  }
    73  
    74  // Unlock unlocks the given state and outputs to the user if the
    75  // unlock fails what can be done.
    76  func Unlock(s state.State, id string, ui cli.Ui, color *colorstring.Colorize) error {
    77  	err := slowmessage.Do(LockThreshold, func() error {
    78  		return s.Unlock(id)
    79  	}, func() {
    80  		if ui != nil {
    81  			ui.Output(color.Color(UnlockMessage))
    82  		}
    83  	})
    84  
    85  	if err != nil {
    86  		ui.Output(color.Color(fmt.Sprintf(
    87  			"\n"+strings.TrimSpace(UnlockErrorMessage)+"\n", err)))
    88  
    89  		err = fmt.Errorf(
    90  			"Error releasing the state lock. Please see the longer error message above.")
    91  	}
    92  
    93  	return err
    94  }