github.com/erriapo/terraform@v0.6.12-0.20160203182612-0340ea72354f/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 }