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