github.com/adamar/terraform@v0.2.2-0.20141016210445-2e703afdad0e/command/refresh.go (about)

     1  package command
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"os"
     7  	"strings"
     8  
     9  	"github.com/hashicorp/terraform/terraform"
    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  	var statePath, stateOutPath, backupPath string
    20  
    21  	args = c.Meta.process(args, true)
    22  
    23  	cmdFlags := c.Meta.flagSet("refresh")
    24  	cmdFlags.StringVar(&statePath, "state", DefaultStateFilename, "path")
    25  	cmdFlags.StringVar(&stateOutPath, "state-out", "", "path")
    26  	cmdFlags.StringVar(&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 apply command expacts 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  	// If we don't specify an output path, default to out normal state
    49  	// path.
    50  	if stateOutPath == "" {
    51  		stateOutPath = statePath
    52  	}
    53  
    54  	// If we don't specify a backup path, default to state out with
    55  	// the extension
    56  	if backupPath == "" {
    57  		backupPath = stateOutPath + DefaultBackupExtention
    58  	}
    59  
    60  	// Verify that the state path exists. The "ContextArg" function below
    61  	// will actually do this, but we want to provide a richer error message
    62  	// if possible.
    63  	if _, err := os.Stat(statePath); err != nil {
    64  		if os.IsNotExist(err) {
    65  			c.Ui.Error(fmt.Sprintf(
    66  				"The Terraform state file for your infrastructure does not\n"+
    67  					"exist. The 'refresh' command only works and only makes sense\n"+
    68  					"when there is existing state that Terraform is managing. Please\n"+
    69  					"double-check the value given below and try again. If you\n"+
    70  					"haven't created infrastructure with Terraform yet, use the\n"+
    71  					"'terraform apply' command.\n\n"+
    72  					"Path: %s",
    73  				statePath))
    74  			return 1
    75  		}
    76  
    77  		c.Ui.Error(fmt.Sprintf(
    78  			"There was an error reading the Terraform state that is needed\n"+
    79  				"for refreshing. The path and error are shown below.\n\n"+
    80  				"Path: %s\n\nError: %s",
    81  			statePath,
    82  			err))
    83  		return 1
    84  	}
    85  
    86  	// Build the context based on the arguments given
    87  	ctx, _, err := c.Context(contextOpts{
    88  		Path:      configPath,
    89  		StatePath: statePath,
    90  	})
    91  	if err != nil {
    92  		c.Ui.Error(err.Error())
    93  		return 1
    94  	}
    95  	if err := ctx.Input(c.InputMode()); err != nil {
    96  		c.Ui.Error(fmt.Sprintf("Error configuring: %s", err))
    97  		return 1
    98  	}
    99  	if !validateContext(ctx, c.Ui) {
   100  		return 1
   101  	}
   102  
   103  	// Create a backup of the state before updating
   104  	if backupPath != "-" && c.state != nil {
   105  		log.Printf("[INFO] Writing backup state to: %s", backupPath)
   106  		f, err := os.Create(backupPath)
   107  		if err == nil {
   108  			err = terraform.WriteState(c.state, f)
   109  			f.Close()
   110  		}
   111  		if err != nil {
   112  			c.Ui.Error(fmt.Sprintf("Error writing backup state file: %s", err))
   113  			return 1
   114  		}
   115  	}
   116  
   117  	state, err := ctx.Refresh()
   118  	if err != nil {
   119  		c.Ui.Error(fmt.Sprintf("Error refreshing state: %s", err))
   120  		return 1
   121  	}
   122  
   123  	log.Printf("[INFO] Writing state output to: %s", stateOutPath)
   124  	f, err := os.Create(stateOutPath)
   125  	if err == nil {
   126  		defer f.Close()
   127  		err = terraform.WriteState(state, f)
   128  	}
   129  	if err != nil {
   130  		c.Ui.Error(fmt.Sprintf("Error writing state file: %s", err))
   131  		return 1
   132  	}
   133  
   134  	return 0
   135  }
   136  
   137  func (c *RefreshCommand) Help() string {
   138  	helpText := `
   139  Usage: terraform refresh [options] [dir]
   140  
   141    Update the state file of your infrastructure with metadata that matches
   142    the physical resources they are tracking.
   143  
   144    This will not modify your infrastructure, but it can modify your
   145    state file to update metadata. This metadata might cause new changes
   146    to occur when you generate a plan or call apply next.
   147  
   148  Options:
   149  
   150    -backup=path        Path to backup the existing state file before
   151                        modifying. Defaults to the "-state-out" path with
   152                        ".backup" extension. Set to "-" to disable backup.
   153  
   154    -input=true         Ask for input for variables if not directly set.
   155  
   156    -no-color           If specified, output won't contain any color.
   157  
   158    -state=path         Path to read and save state (unless state-out
   159                        is specified). Defaults to "terraform.tfstate".
   160  
   161    -state-out=path     Path to write updated state file. By default, the
   162                        "-state" path will be used.
   163  
   164    -var 'foo=bar'      Set a variable in the Terraform configuration. This
   165                        flag can be set multiple times.
   166  
   167    -var-file=foo       Set variables in the Terraform configuration from
   168                        a file. If "terraform.tfvars" is present, it will be
   169                        automatically loaded if this flag is not specified.
   170  
   171  `
   172  	return strings.TrimSpace(helpText)
   173  }
   174  
   175  func (c *RefreshCommand) Synopsis() string {
   176  	return "Update local state file against real resources"
   177  }