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