func loadHost(store persist.Store, hostName string, storePath string) (*host.Host, error) { h, err := store.Load(hostName) if err != nil { return nil, fmt.Errorf("Loading host from store failed: %s", err) } d, err := driverfactory.NewDriver(h.DriverName, h.Name, storePath) if err != nil { return nil, err } err = json.Unmarshal(h.RawDriver, &d) if err != nil { return nil, err } h.Driver = d return h, nil }
// Usage: gattai provision func DoProvision(cli interface{}, args ...string) error { cmd := Cli.Subcmd("provision", []string{"PATTERNS"}, "Provision a set of machines. Patterns, e.g. machine-[1:10], are allowed.", false) provisionFilename := cmd.String( []string{"f", "-file"}, "provision.yml", "Name of the provision file") // TODO: EnvVar: "MACHINE_STORAGE_PATH" machineStoragePath := cmd.String( []string{"s", "-storge-path"}, utils.GetBaseDir(), "Configure Docker Machine's storage path") quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Do not list machines at the end of provisioning") cmd.ParseFlags(args, true) p, err := machine.ReadProvision(*provisionFilename) if err != nil { log.Debugf("err: %s", err) return err } // extract pattern // fmt.Printf("args: %s\n",args) machineList := p.GetMachineList(cmd.Args()...) log.Debugf("machines: %s", machineList) if len(machineList) == 0 { return errors.New("no machine in list") } // create libmachine's store log.Debugf("storage: %s", *machineStoragePath) certInfo := machine.GetCertInfo() authOptions := &auth.AuthOptions{ CertDir: filepath.Join(*machineStoragePath, "certs"), CaCertPath: certInfo.CaCertPath, CaPrivateKeyPath: certInfo.CaPrivateKeyPath, ClientCertPath: certInfo.ClientCertPath, ClientKeyPath: certInfo.ClientKeyPath, } // TODO authOptions := if err := cert.BootstrapCertificates(authOptions); err != nil { log.Fatalf("Error generating certificates: %s", err) } store := machine.GetDefaultStore(*machineStoragePath) spacing := len(machineList) > 1 // check each machine existing for _, name := range machineList { parts := strings.SplitN(name, "-", 2) group := parts[0] index := -1 if len(parts) > 1 { // node-master is not a group, but a machine name, for example. i, err := strconv.Atoi(parts[1]) if err != nil { group = name } else { index = i - 1 } } details := p.Machines[group] if details.BaseAddress != "" { ip, _, err := net.ParseCIDR(details.BaseAddress) if err != nil { return err } for i := details.BaseIndex; i <= index; i++ { utils.IncAddress(ip) } os.Setenv("MACHINE_IP", ip.String()) } if details.PreProvision != nil && len(details.PreProvision) > 0 { fmt.Println("Processing pre-provision commands...") for _, pre := range details.PreProvision { log.Debugf("pre-provision: %s", os.ExpandEnv(pre)) // if strings.HasPrefix(pre, "bash") { err := executeBash(strings.TrimSpace(os.ExpandEnv(pre))) if err != nil { log.Debug(err) } // } } } h, err := store.Load(name) if err != nil { if _, ok := err.(mcnerror.ErrHostDoesNotExist); ok { fmt.Printf("Machine '%s' not found, creating...\n", name) spacing = true // spew.Dump(hostOptions) driver, err := driverfactory.NewDriver(details.Driver, name, *machineStoragePath) if err != nil { log.Fatalf("Error trying to get driver: %s", err) } // TODO populate Env Vars from all hosts // to use with .SetConfigFromFlags h, err = store.NewHost(driver) if err != nil { log.Fatalf("Error getting new host: %s", err) } c := machine.Options(make(map[string]interface{})) for k, v := range details.Options { c[k] = v } hostOptions := &host.HostOptions{ AuthOptions: &auth.AuthOptions{ CertDir: utils.GetMachineCertDir(), CaCertPath: certInfo.CaCertPath, CaPrivateKeyPath: certInfo.CaPrivateKeyPath, ClientCertPath: certInfo.ClientCertPath, ClientKeyPath: certInfo.ClientKeyPath, ServerCertPath: filepath.Join(utils.GetMachineDir(), name, "server.pem"), ServerKeyPath: filepath.Join(utils.GetMachineDir(), name, "server-key.pem"), StorePath: filepath.Join(utils.GetMachineDir(), name), }, EngineOptions: &engine.EngineOptions{ ArbitraryFlags: c.StringSlice("engine-opt"), Env: c.StringSlice("engine-env"), InsecureRegistry: c.StringSlice("engine-insecure-registry"), Labels: c.StringSlice("engine-label"), RegistryMirror: c.StringSlice("engine-registry-mirror"), StorageDriver: c.String("engine-storage-driver"), TlsVerify: true, InstallURL: c.String("engine-install-url"), }, SwarmOptions: &swarm.SwarmOptions{ IsSwarm: c.Bool("swarm"), Image: c.String("swarm-image"), Master: c.Bool("swarm-master"), Discovery: c.String("swarm-discovery"), Address: c.String("swarm-addr"), Host: c.String("swarm-host"), Strategy: c.String("swarm-strategy"), ArbitraryFlags: c.StringSlice("swarm-opt"), }, } h.HostOptions = hostOptions if err := h.Driver.SetConfigFromFlags(details.Options); err != nil { log.Fatalf("Error setting machine configuration from flags provided: %s", err) } // make it compatible with RpcDriver driverData, err := json.Marshal(h.Driver) if err != nil { log.Fatal("Cannot marshal host driver") } h.RawDriver = driverData err = create(store, h, func(hh *host.Host) { c := machine.Options(make(map[string]interface{})) for k, v := range details.Options { c[k] = v } kvstoreName := details.NetworkKvstore log.Debug("Cluster store: " + kvstoreName) if kvstoreName != "" { kvstore, err := loadHost(store, kvstoreName, *machineStoragePath) if err != nil { panic(err) } c, url, err := configureClusterStore(h, kvstore, c) if err != nil { panic(err) } else { hh.HostOptions.EngineOptions.ArbitraryFlags = c.StringSlice("engine-opt") saveDiscoveryUrl(url + "/" + kvstoreName) } } }) if err != nil { log.Errorf("Error creating machine: %s", err) log.Fatal("You will want to check the provider to make sure the machine and associated resources were properly removed.") } // make it compatible with RpcDriver driverData, err = json.Marshal(h.Driver) if err != nil { log.Fatal("Cannot marshal host driver") } h.RawDriver = driverData err = store.Save(h) if err != nil { log.Fatalf("Error saving machine: %s", err) } } } else { fmt.Printf("Machine '%s' exists, starting...\n", name) h, err = loadHost(store, name, *machineStoragePath) // TODO reprovision h.Start() spacing = false } _ = removeAllContainers(h) // TODO delete all containers during re-provision? if details.PostProvision != nil && len(details.PostProvision) > 0 { fmt.Println("Processing post-provision commands...") for _, post := range details.PostProvision { log.Debugf("post-provision: %s", post) if strings.HasPrefix(post, "docker") { err := engineExecute(h, strings.TrimSpace(post[6:])) if err != nil { // if error, goes on log.Debug(err) } } } } if spacing { if len(machineList) > 1 { fmt.Println() } } } if !spacing { fmt.Println() } if *quiet == false { w := tabwriter.NewWriter(os.Stdout, 5, 1, 3, ' ', 0) fmt.Fprintln(w, "NAME\tURL\tSTATE") for _, machineName := range machineList { h, err := loadHost(store, machineName, utils.GetBaseDir()) items := getHostListItems([]*host.Host{h}) if err == nil { url, _ := h.GetURL() fmt.Fprintf(w, "%s\t%s\t%s\n", machineName, url, items[0].State) } } w.Flush() } return err }