github.com/greysond/terraform@v0.8.5-0.20170124173113-439b5507bbe9/command/refresh.go (about)

     1  package command
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"os"
     7  	"strings"
     8  
     9  	"github.com/hashicorp/go-multierror"
    10  	"github.com/hashicorp/terraform/terraform"
    11  )
    12  
    13  // RefreshCommand is a cli.Command implementation that refreshes the state
    14  // file.
    15  type RefreshCommand struct {
    16  	Meta
    17  }
    18  
    19  func (c *RefreshCommand) Run(args []string) int {
    20  	args = c.Meta.process(args, true)
    21  
    22  	cmdFlags := c.Meta.flagSet("refresh")
    23  	cmdFlags.StringVar(&c.Meta.statePath, "state", DefaultStateFilename, "path")
    24  	cmdFlags.IntVar(&c.Meta.parallelism, "parallelism", 0, "parallelism")
    25  	cmdFlags.StringVar(&c.Meta.stateOutPath, "state-out", "", "path")
    26  	cmdFlags.StringVar(&c.Meta.backupPath, "backup", "", "path")
    27  	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
    28  	if err := cmdFlags.Parse(args); err != nil {
    29  		return 1
    30  	}
    31  
    32  	var configPath string
    33  	args = cmdFlags.Args()
    34  	if len(args) > 1 {
    35  		c.Ui.Error("The refresh command expects at most one argument.")
    36  		cmdFlags.Usage()
    37  		return 1
    38  	} else if len(args) == 1 {
    39  		configPath = args[0]
    40  	} else {
    41  		var err error
    42  		configPath, err = os.Getwd()
    43  		if err != nil {
    44  			c.Ui.Error(fmt.Sprintf("Error getting pwd: %s", err))
    45  		}
    46  	}
    47  
    48  	// Check if remote state is enabled
    49  	state, err := c.State()
    50  	if err != nil {
    51  		c.Ui.Error(fmt.Sprintf("Failed to load state: %s", err))
    52  		return 1
    53  	}
    54  
    55  	// Verify that the state path exists. The "ContextArg" function below
    56  	// will actually do this, but we want to provide a richer error message
    57  	// if possible.
    58  	if !state.State().IsRemote() {
    59  		if _, err := os.Stat(c.Meta.statePath); err != nil {
    60  			if os.IsNotExist(err) {
    61  				c.Ui.Error(fmt.Sprintf(
    62  					"The Terraform state file for your infrastructure does not\n"+
    63  						"exist. The 'refresh' command only works and only makes sense\n"+
    64  						"when there is existing state that Terraform is managing. Please\n"+
    65  						"double-check the value given below and try again. If you\n"+
    66  						"haven't created infrastructure with Terraform yet, use the\n"+
    67  						"'terraform apply' command.\n\n"+
    68  						"Path: %s",
    69  					c.Meta.statePath))
    70  				return 1
    71  			}
    72  
    73  			c.Ui.Error(fmt.Sprintf(
    74  				"There was an error reading the Terraform state that is needed\n"+
    75  					"for refreshing. The path and error are shown below.\n\n"+
    76  					"Path: %s\n\nError: %s",
    77  				c.Meta.statePath,
    78  				err))
    79  			return 1
    80  		}
    81  	}
    82  
    83  	// This is going to keep track of shadow errors
    84  	var shadowErr error
    85  
    86  	// Build the context based on the arguments given
    87  	ctx, _, err := c.Context(contextOpts{
    88  		Path:        configPath,
    89  		StatePath:   c.Meta.statePath,
    90  		Parallelism: c.Meta.parallelism,
    91  	})
    92  	if err != nil {
    93  		c.Ui.Error(err.Error())
    94  		return 1
    95  	}
    96  
    97  	if err := ctx.Input(c.InputMode()); err != nil {
    98  		c.Ui.Error(fmt.Sprintf("Error configuring: %s", err))
    99  		return 1
   100  	}
   101  
   102  	// Record any shadow errors for later
   103  	if err := ctx.ShadowError(); err != nil {
   104  		shadowErr = multierror.Append(shadowErr, multierror.Prefix(
   105  			err, "input operation:"))
   106  	}
   107  
   108  	if !validateContext(ctx, c.Ui) {
   109  		return 1
   110  	}
   111  
   112  	newState, err := ctx.Refresh()
   113  	if err != nil {
   114  		c.Ui.Error(fmt.Sprintf("Error refreshing state: %s", err))
   115  		return 1
   116  	}
   117  
   118  	log.Printf("[INFO] Writing state output to: %s", c.Meta.StateOutPath())
   119  	if err := c.Meta.PersistState(newState); err != nil {
   120  		c.Ui.Error(fmt.Sprintf("Error writing state file: %s", err))
   121  		return 1
   122  	}
   123  
   124  	if outputs := outputsAsString(newState, terraform.RootModulePath, ctx.Module().Config().Outputs, true); outputs != "" {
   125  		c.Ui.Output(c.Colorize().Color(outputs))
   126  	}
   127  
   128  	// Record any shadow errors for later
   129  	if err := ctx.ShadowError(); err != nil {
   130  		shadowErr = multierror.Append(shadowErr, multierror.Prefix(
   131  			err, "refresh operation:"))
   132  	}
   133  
   134  	// If we have an error in the shadow graph, let the user know.
   135  	c.outputShadowError(shadowErr, true)
   136  
   137  	return 0
   138  }
   139  
   140  func (c *RefreshCommand) Help() string {
   141  	helpText := `
   142  Usage: terraform refresh [options] [dir]
   143  
   144    Update the state file of your infrastructure with metadata that matches
   145    the physical resources they are tracking.
   146  
   147    This will not modify your infrastructure, but it can modify your
   148    state file to update metadata. This metadata might cause new changes
   149    to occur when you generate a plan or call apply next.
   150  
   151  Options:
   152  
   153    -backup=path        Path to backup the existing state file before
   154                        modifying. Defaults to the "-state-out" path with
   155                        ".backup" extension. Set to "-" to disable backup.
   156  
   157    -input=true         Ask for input for variables if not directly set.
   158  
   159    -no-color           If specified, output won't contain any color.
   160  
   161    -state=path         Path to read and save state (unless state-out
   162                        is specified). Defaults to "terraform.tfstate".
   163  
   164    -state-out=path     Path to write updated state file. By default, the
   165                        "-state" path will be used.
   166  
   167    -target=resource    Resource to target. Operation will be limited to this
   168                        resource and its dependencies. This flag can be used
   169                        multiple times.
   170  
   171    -var 'foo=bar'      Set a variable in the Terraform configuration. This
   172                        flag can be set multiple times.
   173  
   174    -var-file=foo       Set variables in the Terraform configuration from
   175                        a file. If "terraform.tfvars" is present, it will be
   176                        automatically loaded if this flag is not specified.
   177  
   178  `
   179  	return strings.TrimSpace(helpText)
   180  }
   181  
   182  func (c *RefreshCommand) Synopsis() string {
   183  	return "Update local state file against real resources"
   184  }