// WaitForNetworkWithTimeout waits for a network connection to become available within a timeout func WaitForNetworkWithTimeout(name string, host string, timeout time.Duration) { waitDone := make(chan bool, 1) go func() { log.Info("Waiting for %s to become available (%s)", name, host) for { select { case <-time.After(5 * time.Second): } _, err := net.DialTimeout("tcp", host, 10*time.Second) if err != nil { continue } waitDone <- true } }() WaitLoop: for { select { case <-waitDone: log.Info("Connected to %s", name) break WaitLoop case <-time.After(timeout): log.Fatalf("Unable to connect to %s %s", name, "Is Docker running?") } } return }
// DockerClient creates a docker client from environment func DockerClient() *dockerclient.Client { client, err := dockerclient.NewClientFromEnv() if err != nil { log.Fatalf("Unabled to create a Docker Client: Is Docker Machine installed and running?") } client.SkipServerVersionCheck = true return client }
// Configure sets up this plugin with initial state func (c *DockerCompose) Configure(pc *parity.PluginConfig) { log.Debug("Configuring 'Docker Machine' 'Run\\Build\\Shell' plugin") c.pluginConfig = pc var err error if c.project, err = c.GetProject(); err != nil { log.Fatalf("Unable to create Compose Project: %s", err.Error()) } }
// CreateTemplateTempFile resurrects a go-bindata asset and execute the template (if any) it contains. // return a reference to the temporary file func CreateTemplateTempFile(data func() ([]byte, error), perms os.FileMode, templateData interface{}) *os.File { daemon, err := data() if err != nil { log.Fatalf("Template failed:", err.Error()) } tmpl, err := template.New("template file").Parse(string(daemon)) if err != nil { log.Fatalf("Template failed:", err.Error()) } file, _ := ioutil.TempFile("/tmp", "parity") file.Chmod(perms) err = tmpl.Execute(file, templateData) if err != nil { panic(err) } return file }
// LoadPlugins loads all plugins referenced in the parity.yml file // from those registered at runtime func (p *Parity) LoadPlugins() { log.Debug("loading plugins") var err error var confLoader *plugo.ConfigLoader c := &config.RootConfig{} if p.config.ConfigFile != "" { confLoader = &plugo.ConfigLoader{} err = confLoader.LoadFromFile(p.config.ConfigFile, &c) if err != nil { log.Fatalf("Unable to read configuration file: %s", err.Error()) } } else { log.Fatalf("No configuration file provided. Please create a 'parity.yml' file.") } log.SetLevel(log.LogLevel(c.LogLevel)) // Load all plugins p.pluginConfig = &PluginConfig{Ui: p.config.Ui} // Set project name p.pluginConfig.ProjectName = c.Name p.pluginConfig.ProjectNameSafe = strings.Replace(strings.ToLower(c.Name), " ", "", -1) // Sync plugins p.SyncPlugins = make([]Sync, len(c.Sync)) syncPlugins := plugo.LoadPluginsWithConfig(confLoader, c.Sync) for i, pl := range syncPlugins { log.Debug("Loading Sync Plugin\t" + log.Colorize(log.YELLOW, c.Sync[i].Name)) p.SyncPlugins[i] = pl.(Sync) p.SyncPlugins[i].Configure(p.pluginConfig) p.plugins = append(p.plugins, p.SyncPlugins[i]) } // Run plugins p.RunPlugins = make([]Run, len(c.Run)) runPlugins := plugo.LoadPluginsWithConfig(confLoader, c.Run) for i, pl := range runPlugins { log.Debug("Loading Run Plugin\t" + log.Colorize(log.YELLOW, c.Run[i].Name)) p.RunPlugins[i] = pl.(Run) p.RunPlugins[i].Configure(p.pluginConfig) p.plugins = append(p.plugins, p.RunPlugins[i]) } // Build plugins p.BuildPlugins = make([]Builder, len(c.Build)) buildPlugins := plugo.LoadPluginsWithConfig(confLoader, c.Build) for i, pl := range buildPlugins { log.Debug("Loading Build Plugin\t" + log.Colorize(log.YELLOW, c.Build[i].Name)) p.BuildPlugins[i] = pl.(Builder) p.BuildPlugins[i].Configure(p.pluginConfig) p.plugins = append(p.plugins, p.BuildPlugins[i]) } // Shell plugins p.ShellPlugins = make([]Shell, len(c.Shell)) shellPlugins := plugo.LoadPluginsWithConfig(confLoader, c.Shell) for i, pl := range shellPlugins { log.Debug("Loading Shell Plugin\t" + log.Colorize(log.YELLOW, c.Shell[i].Name)) p.ShellPlugins[i] = pl.(Shell) p.ShellPlugins[i].Configure(p.pluginConfig) p.plugins = append(p.plugins, p.ShellPlugins[i]) } }
// InstallParity installs Parity into the running Docker Machine func InstallParity(config InstallConfig) { log.Stage("Install Parity") if config.DevHost == "" { config.DevHost = "parity.local" } // Create DNS entry if config.Dns { hostname := strings.Split(utils.DockerHost(), ":")[0] log.Step("Creating host entry: %s -> %s", hostname, config.DevHost) var hosts goodhosts.Hosts var err error if hosts, err = goodhosts.NewHosts(); err == nil { hosts.Add(hostname, config.DevHost) } else { log.Error("Unable to create DNS Entry: %s", err.Error()) } if err = hosts.Flush(); err != nil { log.Error("Unable to create DNS Entry: %s", err.Error()) } } // Check - is there a Docker Machine created? // -> If so, use the currently selected machine // -> If not, create another machine // -> Persist these settings in ~/.parityrc? // Wrap the local Docker command so that we don't have to use Docker Machine all of the time! type FileTemplate struct { Version string } templateData := FileTemplate{Version: version.Version} // Create the install mirror daemon template file := utils.CreateTemplateTempFile(templatesBootlocalShBytes, 0655, templateData) session, err := utils.SSHSession(utils.DockerHost()) if err != nil { log.Fatalf("Unable to connect to Docker utils.DockerHost(). Is Docker running? (%v)", err.Error()) } log.Step("Installing bootlocal.sh on Docker Host") remoteTmpFile := fmt.Sprintf("/tmp/%s", filepath.Base(file.Name())) err = scp.CopyPath(file.Name(), remoteTmpFile, session) utils.RunCommandWithDefaults(utils.DockerHost(), fmt.Sprintf("sudo cp %s %s", remoteTmpFile, "/var/lib/boot2docker/bootlocal.sh")) session.Close() file = utils.CreateTemplateTempFile(templatesMirrorDaemonShBytes, 0655, templateData) session, err = utils.SSHSession(utils.DockerHost()) if err != nil { log.Fatalf("Unable to connect to Docker utils.DockerHost(). Is Docker running? (%v)", err.Error()) } log.Step("Installing mirror-daemon.sh on Docker Host") remoteTmpFile = fmt.Sprintf("/tmp/%s", filepath.Base(file.Name())) err = scp.CopyPath(file.Name(), remoteTmpFile, session) utils.RunCommandWithDefaults(utils.DockerHost(), fmt.Sprintf("sudo cp %s %s", remoteTmpFile, "/var/lib/boot2docker/mirror-daemon.sh")) session.Close() log.Step("Downloading file sync utility (mirror)") utils.RunCommandWithDefaults(utils.DockerHost(), fmt.Sprintf("sudo chmod +x /var/lib/boot2docker/*.sh")) utils.RunCommandWithDefaults(utils.DockerHost(), fmt.Sprintf(" /var/lib/boot2docker/*.sh")) utils.RunCommandWithDefaults(utils.DockerHost(), fmt.Sprintf("sudo /var/lib/boot2docker/bootlocal.sh start")) log.Step("Restarting Docker") utils.RunCommandWithDefaults(utils.DockerHost(), "sudo shutdown -r now") utils.WaitForNetwork("docker", utils.DockerHost()) utils.WaitForNetwork("mirror", utils.MirrorHost()) // Removing shared folders if utils.CheckSharedFolders() { log.Step("Unmounting Virtualbox shared folders") utils.UnmountSharedFolders() } log.Stage("Install Parity : Complete") }