func AppLogs(ws *websocket.Conn) *httperr.Error { app := mux.Vars(ws.Request())["app"] a, err := models.GetApp(app) if awsError(err) == "ValidationError" { return httperr.Errorf(404, "no such app: %s", app) } if err != nil { return httperr.Server(err) } logs := make(chan []byte) done := make(chan bool) a.SubscribeLogs(logs, done) go signalWsClose(ws, done) for data := range logs { ws.Write(data) } return nil }
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) } // proxy to docker container logs // https://docs.docker.com/reference/api/docker_remote_api_v1.19/#get-container-logs client, err := docker.NewClient("unix:///var/run/docker.sock") 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) }
func ProcessExecAttached(ws *websocket.Conn) *httperr.Error { vars := mux.Vars(ws.Request()) app := vars["app"] pid := vars["pid"] command := ws.Request().Header.Get("Command") a, err := models.GetApp(app) if awsError(err) == "ValidationError" { return httperr.Errorf(404, "no such app: %s", app) } if err != nil { return httperr.Server(err) } return httperr.Server(a.ExecAttached(pid, command, ws)) }
func ServiceLogs(ws *websocket.Conn) *httperr.Error { service := mux.Vars(ws.Request())["service"] s, err := models.GetService(service) if err != nil { return httperr.Server(err) } logs := make(chan []byte) done := make(chan bool) s.SubscribeLogs(logs, done) go signalWsClose(ws, done) for data := range logs { ws.Write(data) } return nil }
func ProcessRunAttached(ws *websocket.Conn) *httperr.Error { vars := mux.Vars(ws.Request()) header := ws.Request().Header app := vars["app"] process := vars["process"] command := header.Get("Command") height, _ := strconv.Atoi(header.Get("Height")) width, _ := strconv.Atoi(header.Get("Width")) a, err := models.GetApp(app) if awsError(err) == "ValidationError" { return httperr.Errorf(404, "no such app: %s", app) } if err != nil { return httperr.Server(err) } return httperr.Server(a.RunAttached(process, command, height, width, ws)) }
func InstanceSSH(ws *websocket.Conn) *httperr.Error { vars := mux.Vars(ws.Request()) id := vars["id"] cmd := ws.Request().Header.Get("Command") term := ws.Request().Header.Get("Terminal") var height, width int var err error if term != "" { height, err = strconv.Atoi(ws.Request().Header.Get("Height")) if err != nil { return httperr.Server(err) } width, err = strconv.Atoi(ws.Request().Header.Get("Width")) if err != nil { return httperr.Server(err) } } return httperr.Server(models.InstanceSSH(id, cmd, term, height, width, ws)) }
func Proxy(ws *websocket.Conn) *httperr.Error { vars := mux.Vars(ws.Request()) host := vars["host"] port := vars["port"] conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%s", host, port), 3*time.Second) if neterr, ok := err.(net.Error); ok && neterr.Timeout() { return httperr.Errorf(403, "timeout") } if err != nil { return httperr.Server(err) } var wg sync.WaitGroup wg.Add(2) go copyAsync(ws, conn, &wg) go copyAsync(conn, ws, &wg) wg.Wait() return nil }
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) }