// 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 }
// ReadComposeVolumes reads a docker-compose.yml and return a slice of // directories to sync into the Docker Host // // "." and "./." is converted to the current directory parity is running from. // Any volume starting with "/" will be treated as an absolute path. // All other volumes (e.g. starting with "./" or without a prefix "/") will be treated as // relative paths. func ReadComposeVolumes() []string { var volumes []string files := FindDockerComposeFiles() for i, file := range files { if _, err := os.Stat(file); err == nil { project, err := docker.NewProject(&docker.Context{ Context: project.Context{ ComposeFiles: []string{file}, ProjectName: fmt.Sprintf("parity-%d", i), }, }) if err != nil { log.Info("Could not parse compose file") } for _, c := range project.Configs { for _, v := range c.Volumes { v = strings.SplitN(v, ":", 2)[0] if v == "." || v == "./." { v, _ = os.Getwd() } else if strings.Index(v, "/") != 0 { cwd, _ := os.Getwd() v = fmt.Sprintf("%s/%s", cwd, v) } volumes = append(volumes, mutils.LinuxPath(v)) } } } } return volumes }
// XServerProxy creates a TCP proxy on port 6000 to a the Unix // socket that XQuartz is listening on. // // NOTE: this function does not start/install the XQuartz service func XServerProxy(port int) { if runtime.GOOS != "darwin" { log.Debug("Not running an OSX environment, skip run X Server Proxy") return } l, err := net.Listen("tcp", fmt.Sprintf(":%d", port)) if err != nil { log.Fatal(err) } defer l.Close() // Send all traffic back to unix $DISPLAY socket on a running XQuartz server addr, err := net.ResolveUnixAddr("unix", os.Getenv("DISPLAY")) if err != nil { log.Error("Error: ", err.Error()) } log.Info("X Service Proxy available on all network interfaces on port %d", port) if host, err := utils.DockerVMHost(); err == nil { log.Info("Parity has detected your Docker environment and recommends running 'export DISPLAY=%s:0' in your container to forward the X display", host) } for { xServerClient, err := net.DialUnix("unix", nil, addr) if err != nil { log.Error("Error: ", err.Error()) } defer xServerClient.Close() conn, err := l.Accept() log.Debug("X Service Proxy connected to client on: %s (remote: %s)", conn.LocalAddr(), conn.RemoteAddr()) if err != nil { log.Fatal(err) } go func(c net.Conn, s *net.UnixConn) { buf := make([]byte, 8092) io.CopyBuffer(s, c, buf) s.CloseWrite() }(conn, xServerClient) go func(c net.Conn, s *net.UnixConn) { buf := make([]byte, 8092) io.CopyBuffer(c, s, buf) c.Close() }(conn, xServerClient) } }
// Build will build all images in the Parity setup func (c *DockerCompose) Build() error { log.Stage("Bulding containers") base := "Dockerfile" cwd, _ := os.Getwd() baseVersion := c.generateContainerVersion(cwd, base) imageName := fmt.Sprintf("%s:%s", c.ImageName, baseVersion) client, _ := dockerclient2.NewEnvClient() log.Step("Checking if image %s exists locally", imageName) if images, err := client.ImageList(context.Background(), types.ImageListOptions{MatchName: imageName}); err == nil { for _, i := range images { log.Info("Found image: %s", i.ID) return nil } } log.Step("Image %s not found locally, pulling", imageName) client.ImagePull(context.Background(), types.ImagePullOptions{ImageID: imageName}, nil) log.Step("Image %s not found anywhere, building", imageName) ctx, err := c.CreateTar(".", "Dockerfile") if err != nil { return err } defer ctx.Close() var progBuff io.Writer = os.Stdout var buildBuff io.Writer = os.Stdout // Setup an upload progress bar progressOutput := streamformatter.NewStreamFormatter().NewProgressOutput(progBuff, true) var body io.Reader = progress.NewProgressReader(ctx, progressOutput, 0, "", "Sending build context to Docker daemon") logrus.Infof("Building %s...", imageName) outFd, isTerminalOut := term.GetFdInfo(os.Stdout) // Publish latest and specific version response, err := client.ImageBuild(context.Background(), types.ImageBuildOptions{ Context: body, Tags: []string{imageName, fmt.Sprintf("%s:latest", c.ImageName)}, NoCache: false, Remove: true, Dockerfile: "Dockerfile", }) if err != nil { log.Error(err.Error()) return err } err = jsonmessage.DisplayJSONMessagesStream(response.Body, buildBuff, outFd, isTerminalOut, nil) if err != nil { if jerr, ok := err.(*jsonmessage.JSONError); ok { // If no error code is set, default to 1 if jerr.Code == 0 { jerr.Code = 1 } fmt.Fprintf(os.Stderr, "%s%s", progBuff, buildBuff) return fmt.Errorf("Status: %s, Code: %d", jerr.Message, jerr.Code) } } return err }