github.com/btobolaski/terraform@v0.6.4-0.20150928030114-0c3f2a915c02/command/refresh.go (about)

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