Пример #1
0
func DeleteBuild(c *gin.Context) {
	engine_ := context.Engine(c)
	repo := session.Repo(c)

	// parse the build number and job sequence number from
	// the repquest parameter.
	num, _ := strconv.Atoi(c.Params.ByName("number"))
	seq, _ := strconv.Atoi(c.Params.ByName("job"))

	build, err := store.GetBuildNumber(c, repo, num)
	if err != nil {
		c.AbortWithError(404, err)
		return
	}

	job, err := store.GetJobNumber(c, build, seq)
	if err != nil {
		c.AbortWithError(404, err)
		return
	}
	node, err := store.GetNode(c, job.NodeID)
	if err != nil {
		c.AbortWithError(404, err)
		return
	}
	engine_.Cancel(build.ID, job.ID, node)
}
Пример #2
0
func GetStream(c *gin.Context) {

	repo := session.Repo(c)
	buildn, _ := strconv.Atoi(c.Param("build"))
	jobn, _ := strconv.Atoi(c.Param("number"))

	c.Writer.Header().Set("Content-Type", "text/event-stream")

	build, err := store.GetBuildNumber(c, repo, buildn)
	if err != nil {
		log.Debugln("stream cannot get build number.", err)
		c.AbortWithError(404, err)
		return
	}
	job, err := store.GetJobNumber(c, build, jobn)
	if err != nil {
		log.Debugln("stream cannot get job number.", err)
		c.AbortWithError(404, err)
		return
	}

	rc, err := stream.Reader(c, stream.ToKey(job.ID))
	if err != nil {
		c.AbortWithError(404, err)
		return
	}

	go func() {
		<-c.Writer.CloseNotify()
		rc.Close()
	}()

	var line int
	var scanner = bufio.NewScanner(rc)
	for scanner.Scan() {
		line++
		var err = sse.Encode(c.Writer, sse.Event{
			Id:    strconv.Itoa(line),
			Event: "message",
			Data:  scanner.Text(),
		})
		if err != nil {
			break
		}
		c.Writer.Flush()
	}

	log.Debugf("Closed stream %s#%d", repo.FullName, build.Number)
}
Пример #3
0
func GetStream(c *gin.Context) {

	engine_ := context.Engine(c)
	repo := session.Repo(c)
	buildn, _ := strconv.Atoi(c.Param("build"))
	jobn, _ := strconv.Atoi(c.Param("number"))

	c.Writer.Header().Set("Content-Type", "text/event-stream")

	build, err := store.GetBuildNumber(c, repo, buildn)
	if err != nil {
		log.Debugln("stream cannot get build number.", err)
		c.AbortWithError(404, err)
		return
	}
	job, err := store.GetJobNumber(c, build, jobn)
	if err != nil {
		log.Debugln("stream cannot get job number.", err)
		c.AbortWithError(404, err)
		return
	}
	node, err := store.GetNode(c, job.NodeID)
	if err != nil {
		log.Debugln("stream cannot get node.", err)
		c.AbortWithError(404, err)
		return
	}

	rc, err := engine_.Stream(build.ID, job.ID, node)
	if err != nil {
		c.AbortWithError(404, err)
		return
	}

	defer func() {
		rc.Close()
	}()

	go func() {
		<-c.Writer.CloseNotify()
		rc.Close()
	}()

	rw := &StreamWriter{c.Writer, 0}

	stdcopy.StdCopy(rw, rw, rc)
}
Пример #4
0
func DeleteBuild(c *gin.Context) {
	repo := session.Repo(c)

	// parse the build number and job sequence number from
	// the repquest parameter.
	num, _ := strconv.Atoi(c.Params.ByName("number"))
	seq, _ := strconv.Atoi(c.Params.ByName("job"))

	build, err := store.GetBuildNumber(c, repo, num)
	if err != nil {
		c.AbortWithError(404, err)
		return
	}

	job, err := store.GetJobNumber(c, build, seq)
	if err != nil {
		c.AbortWithError(404, err)
		return
	}

	if job.Status != model.StatusRunning {
		c.String(400, "Cannot cancel a non-running build")
		return
	}

	job.Status = model.StatusKilled
	job.Finished = time.Now().Unix()
	if job.Started == 0 {
		job.Started = job.Finished
	}
	job.ExitCode = 137
	store.UpdateBuildJob(c, build, job)

	client := stomp.MustFromContext(c)
	client.SendJSON("/topic/cancel", model.Event{
		Type:  model.Cancelled,
		Repo:  *repo,
		Build: *build,
		Job:   *job,
	}, stomp.WithHeader("job-id", strconv.FormatInt(job.ID, 10)))

	c.String(204, "")
}
Пример #5
0
func GetBuildLogs(c *gin.Context) {
	repo := session.Repo(c)

	// the user may specify to stream the full logs,
	// or partial logs, capped at 2MB.
	full, _ := strconv.ParseBool(c.DefaultQuery("full", "false"))

	// parse the build number and job sequence number from
	// the repquest parameter.
	num, _ := strconv.Atoi(c.Params.ByName("number"))
	seq, _ := strconv.Atoi(c.Params.ByName("job"))

	build, err := store.GetBuildNumber(c, repo, num)
	if err != nil {
		c.AbortWithError(404, err)
		return
	}

	job, err := store.GetJobNumber(c, build, seq)
	if err != nil {
		c.AbortWithError(404, err)
		return
	}

	r, err := store.ReadLog(c, job)
	if err != nil {
		c.AbortWithError(404, err)
		return
	}

	defer r.Close()
	if full {
		// TODO implement limited streaming to avoid crashing the browser
	}

	c.Header("Content-Type", "application/json")
	stream.Copy(c.Writer, r)
}
Пример #6
0
func DeleteBuild(c *gin.Context) {
	repo := session.Repo(c)

	// parse the build number and job sequence number from
	// the repquest parameter.
	num, _ := strconv.Atoi(c.Params.ByName("number"))
	seq, _ := strconv.Atoi(c.Params.ByName("job"))

	build, err := store.GetBuildNumber(c, repo, num)
	if err != nil {
		c.AbortWithError(404, err)
		return
	}

	job, err := store.GetJobNumber(c, build, seq)
	if err != nil {
		c.AbortWithError(404, err)
		return
	}

	bus.Publish(c, bus.NewEvent(bus.Cancelled, repo, build, job))
	c.String(204, "")
}
Пример #7
0
func GetBuildLogs(c *gin.Context) {
	repo := session.Repo(c)

	// the user may specify to stream the full logs,
	// or partial logs, capped at 2MB.
	full, _ := strconv.ParseBool(c.Params.ByName("full"))

	// parse the build number and job sequence number from
	// the repquest parameter.
	num, _ := strconv.Atoi(c.Params.ByName("number"))
	seq, _ := strconv.Atoi(c.Params.ByName("job"))

	build, err := store.GetBuildNumber(c, repo, num)
	if err != nil {
		c.AbortWithError(404, err)
		return
	}

	job, err := store.GetJobNumber(c, build, seq)
	if err != nil {
		c.AbortWithError(404, err)
		return
	}

	r, err := store.ReadLog(c, job)
	if err != nil {
		c.AbortWithError(404, err)
		return
	}

	defer r.Close()
	if full {
		io.Copy(c.Writer, r)
	} else {
		io.Copy(c.Writer, io.LimitReader(r, 2000000))
	}
}
Пример #8
0
func DeleteBuild(c *gin.Context) {
	repo := session.Repo(c)

	// parse the build number and job sequence number from
	// the repquest parameter.
	num, _ := strconv.Atoi(c.Params.ByName("number"))
	seq, _ := strconv.Atoi(c.Params.ByName("job"))

	build, err := store.GetBuildNumber(c, repo, num)
	if err != nil {
		c.AbortWithError(404, err)
		return
	}

	job, err := store.GetJobNumber(c, build, seq)
	if err != nil {
		c.AbortWithError(404, err)
		return
	}

	if job.Status != model.StatusRunning {
		c.String(400, "Cannot cancel a non-running build")
		return
	}

	job.Status = model.StatusKilled
	job.Finished = time.Now().Unix()
	if job.Started == 0 {
		job.Started = job.Finished
	}
	job.ExitCode = 137
	store.UpdateBuildJob(c, build, job)

	bus.Publish(c, bus.NewEvent(bus.Cancelled, repo, build, job))
	c.String(204, "")
}
Пример #9
0
// LogStream streams the build log output to the client.
func LogStream(c *gin.Context) {
	repo := session.Repo(c)
	buildn, _ := strconv.Atoi(c.Param("build"))
	jobn, _ := strconv.Atoi(c.Param("number"))

	c.Writer.Header().Set("Content-Type", "text/event-stream")

	build, err := store.GetBuildNumber(c, repo, buildn)
	if err != nil {
		logrus.Debugln("stream cannot get build number.", err)
		c.AbortWithError(404, err)
		return
	}
	job, err := store.GetJobNumber(c, build, jobn)
	if err != nil {
		logrus.Debugln("stream cannot get job number.", err)
		c.AbortWithError(404, err)
		return
	}
	if job.Status != model.StatusRunning {
		logrus.Debugln("stream not found.")
		c.AbortWithStatus(404)
		return
	}

	ws, err := upgrader.Upgrade(c.Writer, c.Request, nil)
	if err != nil {
		if _, ok := err.(websocket.HandshakeError); !ok {
			logrus.Errorf("Cannot upgrade websocket. %s", err)
		}
		return
	}
	logrus.Debugf("Successfull upgraded websocket")

	ticker := time.NewTicker(pingPeriod)
	defer ticker.Stop()

	logs := make(chan []byte)
	done := make(chan bool)
	dest := fmt.Sprintf("/topic/logs.%d", job.ID)
	client, _ := stomp.FromContext(c)
	sub, err := client.Subscribe(dest, stomp.HandlerFunc(func(m *stomp.Message) {
		if m.Header.GetBool("eof") {
			done <- true
		} else {
			logs <- m.Body
		}
		m.Release()
	}))
	if err != nil {
		logrus.Errorf("Unable to read logs from broker. %s", err)
		return
	}
	defer func() {
		client.Unsubscribe(sub)
		close(done)
		close(logs)
	}()

	for {
		select {
		case buf := <-logs:
			ws.SetWriteDeadline(time.Now().Add(writeWait))
			ws.WriteMessage(websocket.TextMessage, buf)
		case <-done:
			return
		case <-ticker.C:
			err := ws.WriteControl(websocket.PingMessage, []byte{}, time.Now().Add(writeWait))
			if err != nil {
				return
			}
		}
	}
}