// try to find the docker host that's running a build // try a few times with a sleep func findBuildHost(build string) (string, error) { for i := 1; i < 5; i++ { pss, err := models.ListProcesses(os.Getenv("RACK")) if err != nil { return "", httperr.Server(err) } for _, ps := range pss { client, err := ps.Docker() if err != nil { return "", httperr.Server(err) } res, err := client.ListContainers(docker.ListContainersOptions{ All: true, Filters: map[string][]string{ "name": []string{fmt.Sprintf("build-%s", build)}, }, }) if len(res) > 0 { return fmt.Sprintf("http://%s:2376", ps.Host), nil } } time.Sleep(2 * time.Second) } return "", fmt.Errorf("could not find build host") }
func ProcessList(rw http.ResponseWriter, r *http.Request) *httperr.Error { app := mux.Vars(r)["app"] stats := r.URL.Query().Get("stats") == "true" _, err := models.GetApp(app) if awsError(err) == "ValidationError" { return httperr.Errorf(404, "no such app: %s", app) } processes, err := models.ListProcesses(app) if err != nil { return httperr.Server(err) } if stats { w := new(sync.WaitGroup) erch := make(chan error, len(processes)) for _, p := range processes { w.Add(1) go func(p *models.Process, w *sync.WaitGroup, erch chan error) { err := p.FetchStats() w.Done() if err != nil { erch <- err } }(p, w, erch) } w.Wait() select { case err := <-erch: return httperr.Server(err) default: // noop } } sort.Sort(models.Processes(processes)) return RenderJson(rw, processes) }
func ProcessList(rw http.ResponseWriter, r *http.Request) error { app := mux.Vars(r)["app"] _, err := models.GetApp(app) if awsError(err) == "ValidationError" { return RenderNotFound(rw, fmt.Sprintf("no such app: %s", app)) } processes, err := models.ListProcesses(app) if err != nil { return err } return RenderJson(rw, processes) }
func ProcessList(rw http.ResponseWriter, r *http.Request) *httperr.Error { app := mux.Vars(r)["app"] _, err := models.GetApp(app) if awsError(err) == "ValidationError" { return httperr.Errorf(404, "no such app: %s", app) } processes, err := models.ListProcesses(app) if err != nil { return httperr.Server(err) } final := models.Processes{} if r.URL.Query().Get("stats") != "false" { psch := make(chan models.Process) errch := make(chan error) for _, p := range processes { p := p go p.FetchStatsAsync(psch, errch) } for _, _ = range processes { err := <-errch if err != nil { return httperr.Server(err) } final = append(final, <-psch) } } else { final = processes } sort.Sort(final) return RenderJson(rw, final) }
func ProcessList(rw http.ResponseWriter, r *http.Request) error { app := mux.Vars(r)["app"] _, err := models.GetApp(app) if awsError(err) == "ValidationError" { return RenderNotFound(rw, fmt.Sprintf("no such app: %s", app)) } processes, err := models.ListProcesses(app) if err != nil { return err } final := models.Processes{} psch := make(chan models.Process) errch := make(chan error) for _, p := range processes { p := p go p.FetchStatsAsync(psch, errch) } for _, _ = range processes { err := <-errch if err != nil { return err } final = append(final, <-psch) } sort.Sort(final) return RenderJson(rw, final) }
func BuildLogs(ws *websocket.Conn) *httperr.Error { vars := mux.Vars(ws.Request()) app := vars["app"] build := vars["build"] _, err := models.GetApp(app) if awsError(err) == "ValidationError" { return httperr.Errorf(404, "no such app: %s", app) } _, err = models.GetBuild(app, build) if err != nil { return httperr.Server(err) } // default to local docker socket host := "unix:///var/run/docker.sock" // in production loop through docker hosts that the rack is running on // to find the build if os.Getenv("DEVELOPMENT") != "true" { pss, err := models.ListProcesses(os.Getenv("RACK")) if err != nil { return httperr.Server(err) } for _, ps := range pss { client, err := ps.Docker() if err != nil { return httperr.Server(err) } res, err := client.ListContainers(docker.ListContainersOptions{ All: true, Filters: map[string][]string{ "name": []string{fmt.Sprintf("build-%s", build)}, }, }) if len(res) > 0 { host = fmt.Sprintf("http://%s:2376", ps.Host) break } } } fmt.Printf("host %+v\n", host) // proxy to docker container logs // https://docs.docker.com/reference/api/docker_remote_api_v1.19/#get-container-logs client, err := docker.NewClient(host) if err != nil { return httperr.Server(err) } r, w := io.Pipe() quit := make(chan bool) go scanLines(r, ws) go keepAlive(ws, quit) err = client.Logs(docker.LogsOptions{ Container: fmt.Sprintf("build-%s", build), Follow: true, Stdout: true, Stderr: true, Tail: "all", RawTerminal: false, OutputStream: w, ErrorStream: w, }) quit <- true return httperr.Server(err) }