github.com/chalford/terraform@v0.3.7-0.20150113080010-a78c69a8c81f/command/refresh.go (about)

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