github.com/wangzhucn/terraform@v0.6.7-0.20151109233120-4eea011b56b3/command/init.go (about)

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