func keepAlive(ws *websocket.Conn, quit chan bool) { c := time.Tick(5 * time.Second) b := []byte{} for { select { case <-c: ws.Write(b) case <-quit: return } } }
func BuildLogs(ws *websocket.Conn) { defer ws.Close() log := buildsLogger("logs").Start() vars := mux.Vars(ws.Request()) id := vars["build"] log.Success("step=upgrade build=%q", id) defer ws.Close() // 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 { helpers.Error(log, err) ws.Write([]byte(fmt.Sprintf("error: %s\n", err))) return } 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", id), Follow: true, Stdout: true, Stderr: true, Tail: "all", RawTerminal: false, OutputStream: w, ErrorStream: w, }) quit <- true if err != nil { helpers.Error(log, err) ws.Write([]byte(fmt.Sprintf("error: %s\n", err))) return } }
func scanLines(r io.Reader, ws *websocket.Conn) { scanner := bufio.NewScanner(r) for scanner.Scan() { parts := strings.SplitN(scanner.Text(), "|", 2) if len(parts) < 2 { ws.Write([]byte(parts[0] + "\n")) continue } switch parts[0] { case "manifest": case "error": ws.Write([]byte(parts[1] + "\n")) default: ws.Write([]byte(parts[1] + "\n")) } } }
func ProcessRunAttached(ws *websocket.Conn) { defer ws.Close() log := processesLogger("run.attached").Start() vars := mux.Vars(ws.Request()) app := vars["app"] process := vars["process"] command := ws.Request().Header.Get("Command") ps, err := models.GetProcess(app, process) if err != nil { helpers.Error(log, err) ws.Write([]byte(fmt.Sprintf("error: %s\n", err))) return } log.Success("step=upgrade app=%q", ps.App) defer ws.Close() err = ps.RunAttached(command, ws) if err != nil { helpers.Error(log, err) ws.Write([]byte(fmt.Sprintf("error: %s\n", err))) return } log.Success("step=ended app=%q", ps.App) }