Esempio n. 1
0
// 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")
}
Esempio n. 2
0
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)
}
Esempio n. 3
0
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)
}
Esempio n. 4
0
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)
}
Esempio n. 5
0
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)
}
Esempio n. 6
0
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)
}