github.com/jonasi/terraform@v0.6.10-0.20160125170522-e865c342cc1f/command/init.go (about)

     1  package command
     2  
     3  import (
     4  	"flag"
     5  	"fmt"
     6  	"os"
     7  	"path/filepath"
     8  	"strings"
     9  
    10  	"github.com/hashicorp/go-getter"
    11  	"github.com/hashicorp/terraform/config"
    12  	"github.com/hashicorp/terraform/config/module"
    13  	"github.com/hashicorp/terraform/terraform"
    14  )
    15  
    16  // InitCommand is a Command implementation that takes a Terraform
    17  // module and clones it to the working directory.
    18  type InitCommand struct {
    19  	Meta
    20  }
    21  
    22  func (c *InitCommand) Run(args []string) int {
    23  	var remoteBackend string
    24  	args = c.Meta.process(args, false)
    25  	remoteConfig := make(map[string]string)
    26  	cmdFlags := flag.NewFlagSet("init", flag.ContinueOnError)
    27  	cmdFlags.StringVar(&remoteBackend, "backend", "", "")
    28  	cmdFlags.Var((*FlagKV)(&remoteConfig), "backend-config", "config")
    29  	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
    30  	if err := cmdFlags.Parse(args); err != nil {
    31  		return 1
    32  	}
    33  
    34  	var path string
    35  	args = cmdFlags.Args()
    36  	if len(args) > 2 {
    37  		c.Ui.Error("The init command expects at most two arguments.\n")
    38  		cmdFlags.Usage()
    39  		return 1
    40  	} else if len(args) < 1 {
    41  		c.Ui.Error("The init command expects at least one arguments.\n")
    42  		cmdFlags.Usage()
    43  		return 1
    44  	}
    45  
    46  	if len(args) == 2 {
    47  		path = args[1]
    48  	} else {
    49  		var err error
    50  		path, err = os.Getwd()
    51  		if err != nil {
    52  			c.Ui.Error(fmt.Sprintf("Error getting pwd: %s", err))
    53  		}
    54  	}
    55  
    56  	// Set the state out path to be the path requested for the module
    57  	// to be copied. This ensures any remote states gets setup in the
    58  	// proper directory.
    59  	c.Meta.dataDir = filepath.Join(path, DefaultDataDirectory)
    60  
    61  	source := args[0]
    62  
    63  	// Get our pwd since we need it
    64  	pwd, err := os.Getwd()
    65  	if err != nil {
    66  		c.Ui.Error(fmt.Sprintf(
    67  			"Error reading working directory: %s", err))
    68  		return 1
    69  	}
    70  
    71  	// Verify the directory is empty
    72  	if empty, err := config.IsEmptyDir(path); err != nil {
    73  		c.Ui.Error(fmt.Sprintf(
    74  			"Error checking on destination path: %s", err))
    75  		return 1
    76  	} else if !empty {
    77  		c.Ui.Error(
    78  			"The destination path has Terraform configuration files. The\n" +
    79  				"init command can only be used on a directory without existing Terraform\n" +
    80  				"files.")
    81  		return 1
    82  	}
    83  
    84  	// Detect
    85  	source, err = getter.Detect(source, pwd, getter.Detectors)
    86  	if err != nil {
    87  		c.Ui.Error(fmt.Sprintf(
    88  			"Error with module source: %s", err))
    89  		return 1
    90  	}
    91  
    92  	// Get it!
    93  	if err := module.GetCopy(path, source); err != nil {
    94  		c.Ui.Error(err.Error())
    95  		return 1
    96  	}
    97  
    98  	// Handle remote state if configured
    99  	if remoteBackend != "" {
   100  		var remoteConf terraform.RemoteState
   101  		remoteConf.Type = remoteBackend
   102  		remoteConf.Config = remoteConfig
   103  
   104  		state, err := c.State()
   105  		if err != nil {
   106  			c.Ui.Error(fmt.Sprintf("Error checking for state: %s", err))
   107  			return 1
   108  		}
   109  		if state != nil {
   110  			s := state.State()
   111  			if !s.Empty() {
   112  				c.Ui.Error(fmt.Sprintf(
   113  					"State file already exists and is not empty! Please remove this\n" +
   114  						"state file before initializing. Note that removing the state file\n" +
   115  						"may result in a loss of information since Terraform uses this\n" +
   116  						"to track your infrastructure."))
   117  				return 1
   118  			}
   119  			if s.IsRemote() {
   120  				c.Ui.Error(fmt.Sprintf(
   121  					"State file already exists with remote state enabled! Please remove this\n" +
   122  						"state file before initializing. Note that removing the state file\n" +
   123  						"may result in a loss of information since Terraform uses this\n" +
   124  						"to track your infrastructure."))
   125  				return 1
   126  			}
   127  		}
   128  
   129  		// Initialize a blank state file with remote enabled
   130  		remoteCmd := &RemoteConfigCommand{
   131  			Meta:       c.Meta,
   132  			remoteConf: remoteConf,
   133  		}
   134  		return remoteCmd.initBlankState()
   135  	}
   136  	return 0
   137  }
   138  
   139  func (c *InitCommand) Help() string {
   140  	helpText := `
   141  Usage: terraform init [options] SOURCE [PATH]
   142  
   143    Downloads the module given by SOURCE into the PATH. The PATH defaults
   144    to the working directory. PATH must be empty of any Terraform files.
   145    Any conflicting non-Terraform files will be overwritten.
   146  
   147    The module downloaded is a copy. If you're downloading a module from
   148    Git, it will not preserve the Git history, it will only copy the
   149    latest files.
   150  
   151  Options:
   152  
   153    -backend=atlas         Specifies the type of remote backend. If not
   154                           specified, local storage will be used.
   155  
   156    -backend-config="k=v"  Specifies configuration for the remote storage
   157                           backend. This can be specified multiple times.
   158  
   159    -no-color           If specified, output won't contain any color.
   160  
   161  `
   162  	return strings.TrimSpace(helpText)
   163  }
   164  
   165  func (c *InitCommand) Synopsis() string {
   166  	return "Initializes Terraform configuration from a module"
   167  }