refactor: Generalize log ownership to allow for scratch jobs (#182)

* refactor: Generalize log ownership to allow for scratch jobs

Importing may fail when creating a project. We don't want to lose this output,
but we don't want to allow users to create a failing project.

This generalizes logs to soon enable one-off situations where a user can upload
their archive, create a project, and watch the output parse to completion.

* Improve file table schema by using hash

* Fix racey test by allowing logs before

* Add debug logging for PostgreSQL insert
This commit is contained in:
Kyle Carberry
2022-02-07 15:32:37 -06:00
committed by GitHub
parent bde732f2ef
commit ed705f6af2
26 changed files with 892 additions and 935 deletions
-74
View File
@@ -5,9 +5,6 @@ import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"strconv"
"time"
"github.com/coder/coder/coderd"
)
@@ -134,74 +131,3 @@ func (c *Client) CreateWorkspaceHistory(ctx context.Context, owner, workspace st
var workspaceHistory coderd.WorkspaceHistory
return workspaceHistory, json.NewDecoder(res.Body).Decode(&workspaceHistory)
}
// WorkspaceHistoryLogs returns all logs for workspace history.
// To stream logs, use the FollowWorkspaceHistoryLogs function.
func (c *Client) WorkspaceHistoryLogs(ctx context.Context, owner, workspace, history string) ([]coderd.WorkspaceHistoryLog, error) {
return c.WorkspaceHistoryLogsBetween(ctx, owner, workspace, history, time.Time{}, time.Time{})
}
// WorkspaceHistoryLogsBetween returns logs between a specific time.
func (c *Client) WorkspaceHistoryLogsBetween(ctx context.Context, owner, workspace, history string, after, before time.Time) ([]coderd.WorkspaceHistoryLog, error) {
if owner == "" {
owner = "me"
}
values := url.Values{}
if !after.IsZero() {
values["after"] = []string{strconv.FormatInt(after.UTC().UnixMilli(), 10)}
}
if !before.IsZero() {
values["before"] = []string{strconv.FormatInt(before.UTC().UnixMilli(), 10)}
}
res, err := c.request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/workspaces/%s/%s/version/%s/logs?%s", owner, workspace, history, values.Encode()), nil)
if err != nil {
return nil, err
}
if res.StatusCode != http.StatusOK {
defer res.Body.Close()
return nil, readBodyAsError(res)
}
var logs []coderd.WorkspaceHistoryLog
return logs, json.NewDecoder(res.Body).Decode(&logs)
}
// FollowWorkspaceHistoryLogsAfter returns a stream of workspace history logs.
// The channel will close when the workspace history job is no longer active.
func (c *Client) FollowWorkspaceHistoryLogsAfter(ctx context.Context, owner, workspace, history string, after time.Time) (<-chan coderd.WorkspaceHistoryLog, error) {
afterQuery := ""
if !after.IsZero() {
afterQuery = fmt.Sprintf("&after=%d", after.UTC().UnixMilli())
}
if owner == "" {
owner = "me"
}
res, err := c.request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/workspaces/%s/%s/version/%s/logs?follow%s", owner, workspace, history, afterQuery), nil)
if err != nil {
return nil, err
}
if res.StatusCode != http.StatusOK {
defer res.Body.Close()
return nil, readBodyAsError(res)
}
logs := make(chan coderd.WorkspaceHistoryLog)
decoder := json.NewDecoder(res.Body)
go func() {
defer close(logs)
var log coderd.WorkspaceHistoryLog
for {
err = decoder.Decode(&log)
if err != nil {
return
}
select {
case <-ctx.Done():
return
case logs <- log:
}
}
}()
return logs, nil
}