Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

feat: add startup script logs to the ui#6558

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
kylecarbs merged 34 commits intomainfromstartuplogs
Mar 23, 2023
Merged
Show file tree
Hide file tree
Changes from1 commit
Commits
Show all changes
34 commits
Select commitHold shift + click to select a range
99d510c
Add startup script logs to the database
code-asherFeb 23, 2023
66c8ec3
Add coderd endpoints for startup script logs
code-asherFeb 23, 2023
1cc3e9d
Push startup script logs from agent
code-asherFeb 23, 2023
45d250f
Pull startup script logs on frontend
code-asherFeb 23, 2023
7fed360
Merge branch 'main' into startuplogs
kylecarbsMar 10, 2023
7ce73aa
Rename queries
kylecarbsMar 10, 2023
b86c400
Add constraint
kylecarbsMar 11, 2023
0c4d2c3
Start creating log sending loop
kylecarbsMar 13, 2023
1bb700f
Add log sending to the agent
kylecarbsMar 13, 2023
736705f
Add tests for streaming logs
kylecarbsMar 13, 2023
f741523
Shorten notify channel name
kylecarbsMar 14, 2023
54c30be
Add FE
kylecarbsMar 14, 2023
adb06ea
Improve bulk log performance
kylecarbsMar 15, 2023
4061b13
Finish UI display
kylecarbsMar 15, 2023
4c5b630
Fix startup log visibility
kylecarbsMar 15, 2023
05d536c
Add warning for overflow
kylecarbsMar 16, 2023
34fde1a
Fix agent queue logs overflow
kylecarbsMar 17, 2023
379f1f4
Display staartup logs in a virtual DOM for performance
kylecarbsMar 19, 2023
decde5c
Fix agent queue with loads of logs
kylecarbsMar 20, 2023
d74457c
Merge branch 'main' into startuplogs
kylecarbsMar 20, 2023
ac55f48
Fix authorize test
kylecarbsMar 20, 2023
8d75963
Remove faulty test
kylecarbsMar 20, 2023
cc715cd
Fix startup and shutdown reporting error
kylecarbsMar 20, 2023
e3a4b2c
Fix gen
kylecarbsMar 20, 2023
399dad7
Merge branch 'main' into startuplogs
kylecarbsMar 22, 2023
45c0aca
Fix comments
kylecarbsMar 22, 2023
5a0b15d
Periodically purge old database entries
kylecarbsMar 23, 2023
b1b3fcb
Add test fixture for migration
kylecarbsMar 23, 2023
6e1032c
Add Storybook
kylecarbsMar 23, 2023
3762e8d
Check if there are logs when displaying features
kylecarbsMar 23, 2023
f6b9fce
Fix startup component overflow gap
kylecarbsMar 23, 2023
c48658c
Fix startup log wrapping
kylecarbsMar 23, 2023
4ec1a0e
Merge branch 'main' into startuplogs
kylecarbsMar 23, 2023
b55b7a1
Merge branch 'main' into startuplogs
kylecarbsMar 23, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
PrevPrevious commit
NextNext commit
Add tests for streaming logs
  • Loading branch information
@kylecarbs
kylecarbs committedMar 13, 2023
commit736705f87068ded10740972bfdaeefb31e46f24c
32 changes: 7 additions & 25 deletionsagent/agent.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -88,7 +88,7 @@ type Client interface {
PostLifecycle(ctx context.Context, state agentsdk.PostLifecycleRequest) error
PostAppHealth(ctx context.Context, req agentsdk.PostAppHealthsRequest) error
PostStartup(ctx context.Context, req agentsdk.PostStartupRequest) error
AppendStartupLogs(ctx context.Context, req[]agentsdk.StartupLog) error
PatchStartupLogs(ctx context.Context, req agentsdk.PatchStartupLogs) error
}

func New(options Options) io.Closer {
Expand DownExpand Up@@ -202,19 +202,6 @@ func (a *agent) runLoop(ctx context.Context) {
}
}

func (a *agent) appendStartupLogsLoop(ctx context.Context, logs []agentsdk.StartupLog) {
for r := retry.New(time.Second, 15*time.Second); r.Wait(ctx); {
err := a.client.AppendStartupLogs(ctx, logs)
if err == nil {
return
}
if errors.Is(err, context.Canceled) || xerrors.Is(err, context.DeadlineExceeded) {
return
}
a.logger.Error(ctx, "failed to append startup logs", slog.Error(err))
}
}

// reportLifecycleLoop reports the current lifecycle state once.
// Only the latest state is reported, intermediate states may be
// lost if the agent can't communicate with the API.
Expand DownExpand Up@@ -680,25 +667,20 @@ func (a *agent) runScript(ctx context.Context, lifecycle, script string) error {
return
}
logsSending = true
toSend :=make([]agentsdk.StartupLog, len(queuedLogs))
copy(toSend, queuedLogs)
logsToSend := queuedLogs
queuedLogs = make([]agentsdk.StartupLog, 0)
logMutex.Unlock()
for r := retry.New(time.Second, 5*time.Second); r.Wait(ctx); {
err := a.client.AppendStartupLogs(ctx, toSend)
err := a.client.PatchStartupLogs(ctx, agentsdk.PatchStartupLogs{
Logs: logsToSend,
})
if err == nil {
break
}
a.logger.Error(ctx, "upload startup logs", slog.Error(err))
}
if ctx.Err() != nil {
logMutex.Lock()
logsSending = false
logMutex.Unlock()
return
a.logger.Error(ctx, "upload startup logs", slog.Error(err), slog.F("to_send", logsToSend))
}
logMutex.Lock()
logsSending = false
queuedLogs = queuedLogs[len(toSend):]
logMutex.Unlock()
}
queueLog := func(log agentsdk.StartupLog) {
Expand Down
4 changes: 2 additions & 2 deletionsagent/agent_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -1576,10 +1576,10 @@ func (c *client) getStartupLogs() []agentsdk.StartupLog {
return c.logs
}

func (c *client)AppendStartupLogs(_ context.Context, logs[]agentsdk.StartupLog) error {
func (c *client)PatchStartupLogs(_ context.Context, logs agentsdk.PatchStartupLogs) error {
c.mu.Lock()
defer c.mu.Unlock()
c.logs = append(c.logs, logs...)
c.logs = append(c.logs, logs.Logs...)
return nil
}

Expand Down
32 changes: 0 additions & 32 deletionscoderd/provisionerjobs_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -89,36 +89,4 @@ func TestProvisionerJobLogs(t *testing.T) {
}
}
})

t.Run("List", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
user := coderdtest.CreateFirstUser(t, client)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
Parse: echo.ParseComplete,
ProvisionApply: []*proto.Provision_Response{{
Type: &proto.Provision_Response_Log{
Log: &proto.Log{
Level: proto.LogLevel_INFO,
Output: "log-output",
},
},
}, {
Type: &proto.Provision_Response_Complete{
Complete: &proto.Provision_Complete{},
},
}},
})
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID)
coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID)

ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
defer cancel()

logs, err := client.WorkspaceBuildLogsBefore(ctx, workspace.LatestBuild.ID, 0)
require.NoError(t, err)
require.Greater(t, len(logs), 1)
})
}
8 changes: 4 additions & 4 deletionscoderd/workspaceagents.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -226,23 +226,23 @@ func (api *API) postWorkspaceAgentStartup(rw http.ResponseWriter, r *http.Reques
// @Accept json
// @Produce json
// @Tags Agents
// @Param request body[]agentsdk.StartupLog true "Startup logs"
// @Param request body agentsdk.PatchStartupLogs true "Startup logs"
// @Success 200
// @Router /workspaceagents/me/startup-logs [patch]
// @x-apidocgen {"skip": true}
func (api *API) patchWorkspaceAgentStartupLogs(rw http.ResponseWriter, r *http.Request) {
ctx := r.Context()
workspaceAgent := httpmw.WorkspaceAgent(r)

var req[]agentsdk.StartupLog
var req agentsdk.PatchStartupLogs
if !httpapi.Read(ctx, rw, r, &req) {
return
}

createdAt := make([]time.Time, 0)
output := make([]string, 0)
outputLength := 0
for _, log := range req {
for _, log := range req.Logs {
createdAt = append(createdAt, log.CreatedAt)
output = append(output, log.Output)
outputLength += len(log.Output)
Expand DownExpand Up@@ -311,7 +311,7 @@ func (api *API) workspaceAgentStartupLogs(rw http.ResponseWriter, r *http.Reques
// This mostly copies how provisioner job logs are streamed!
var (
ctx = r.Context()
agent = httpmw.WorkspaceAgent(r)
agent = httpmw.WorkspaceAgentParam(r)
logger = api.Logger.With(slog.F("workspace_agent_id", agent.ID))
follow = r.URL.Query().Has("follow")
afterRaw = r.URL.Query().Get("after")
Expand Down
59 changes: 59 additions & 0 deletionscoderd/workspaceagents_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -175,6 +175,65 @@ func TestWorkspaceAgent(t *testing.T) {
})
}

func TestWorkspaceAgentStartup(t *testing.T) {
t.Parallel()
ctx, cancelFunc := testutil.Context(t)
defer cancelFunc()
client := coderdtest.New(t, &coderdtest.Options{
IncludeProvisionerDaemon: true,
})
user := coderdtest.CreateFirstUser(t, client)
authToken := uuid.NewString()
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
Parse: echo.ParseComplete,
ProvisionPlan: echo.ProvisionComplete,
ProvisionApply: []*proto.Provision_Response{{
Type: &proto.Provision_Response_Complete{
Complete: &proto.Provision_Complete{
Resources: []*proto.Resource{{
Name: "example",
Type: "aws_instance",
Agents: []*proto.Agent{{
Id: uuid.NewString(),
Auth: &proto.Agent_Token{
Token: authToken,
},
}},
}},
},
},
}},
})
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID)
build := coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID)

agentClient := agentsdk.New(client.URL)
agentClient.SetSessionToken(authToken)
err := agentClient.PatchStartupLogs(ctx, agentsdk.PatchStartupLogs{
Logs: []agentsdk.StartupLog{{
CreatedAt: database.Now(),
Output: "testing",
}},
})
require.NoError(t, err)

logs, closer, err := client.WorkspaceAgentStartupLogsAfter(ctx, build.Resources[0].Agents[0].ID, 0)
require.NoError(t, err)
defer func() {
_ = closer.Close()
}()
var log codersdk.WorkspaceAgentStartupLog
select {
case <-ctx.Done():
case log = <-logs:
}
require.NoError(t, ctx.Err())
require.Equal(t, "testing", log.Output)
cancelFunc()
}

func TestWorkspaceAgentListen(t *testing.T) {
t.Parallel()

Expand Down
2 changes: 1 addition & 1 deletioncoderd/wsconncache/wsconncache_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -250,6 +250,6 @@ func (*client) PostStartup(_ context.Context, _ agentsdk.PostStartupRequest) err
return nil
}

func (*client)AppendStartupLogs(_ context.Context, _[]agentsdk.StartupLog) error {
func (*client)PatchStartupLogs(_ context.Context, _ agentsdk.PatchStartupLogs) error {
return nil
}
8 changes: 6 additions & 2 deletionscodersdk/agentsdk/agentsdk.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -521,9 +521,13 @@ type StartupLog struct {
Output string `json:"output"`
}

// AppendStartupLogs writes log messages to the agent startup script.
type PatchStartupLogs struct {
Logs []StartupLog `json:"logs"`
}

// PatchStartupLogs writes log messages to the agent startup script.
// Log messages are limited to 1MB in total.
func (c *Client)AppendStartupLogs(ctx context.Context, req[]StartupLog) error {
func (c *Client)PatchStartupLogs(ctx context.Context, reqPatchStartupLogs) error {
res, err := c.SDK.Request(ctx, http.MethodPatch, "/api/v2/workspaceagents/me/startup-logs", req)
if err != nil {
return err
Expand Down
23 changes: 0 additions & 23 deletionscodersdk/provisionerdaemons.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,8 +9,6 @@ import (
"net"
"net/http"
"net/http/cookiejar"
"net/url"
"strconv"
"time"

"github.com/google/uuid"
Expand DownExpand Up@@ -100,27 +98,6 @@ type ProvisionerJobLog struct {
Output string `json:"output"`
}

// provisionerJobLogsBefore provides log output that occurred before a time.
// This is abstracted from a specific job type to provide consistency between
// APIs. Logs is the only shared route between jobs.
func (c *Client) provisionerJobLogsBefore(ctx context.Context, path string, before int64) ([]ProvisionerJobLog, error) {
values := url.Values{}
if before != 0 {
values["before"] = []string{strconv.FormatInt(before, 10)}
}
res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("%s?%s", path, values.Encode()), nil)
if err != nil {
return nil, err
}
if res.StatusCode != http.StatusOK {
defer res.Body.Close()
return nil, ReadBodyAsError(res)
}

var logs []ProvisionerJobLog
return logs, json.NewDecoder(res.Body).Decode(&logs)
}

// provisionerJobLogsAfter streams logs that occurred after a specific time.
func (c *Client) provisionerJobLogsAfter(ctx context.Context, path string, after int64) (<-chan ProvisionerJobLog, io.Closer, error) {
afterQuery := ""
Expand Down
11 changes: 0 additions & 11 deletionscodersdk/templateversions.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -186,11 +186,6 @@ func (c *Client) TemplateVersionVariables(ctx context.Context, version uuid.UUID
return variables, json.NewDecoder(res.Body).Decode(&variables)
}

// TemplateVersionLogsBefore returns logs that occurred before a specific log ID.
func (c *Client) TemplateVersionLogsBefore(ctx context.Context, version uuid.UUID, before int64) ([]ProvisionerJobLog, error) {
return c.provisionerJobLogsBefore(ctx, fmt.Sprintf("/api/v2/templateversions/%s/logs", version), before)
}

// TemplateVersionLogsAfter streams logs for a template version that occurred after a specific log ID.
func (c *Client) TemplateVersionLogsAfter(ctx context.Context, version uuid.UUID, after int64) (<-chan ProvisionerJobLog, io.Closer, error) {
return c.provisionerJobLogsAfter(ctx, fmt.Sprintf("/api/v2/templateversions/%s/logs", version), after)
Expand DownExpand Up@@ -253,12 +248,6 @@ func (c *Client) TemplateVersionDryRunResources(ctx context.Context, version, jo
return resources, json.NewDecoder(res.Body).Decode(&resources)
}

// TemplateVersionDryRunLogsBefore returns logs for a template version dry-run
// that occurred before a specific log ID.
func (c *Client) TemplateVersionDryRunLogsBefore(ctx context.Context, version, job uuid.UUID, before int64) ([]ProvisionerJobLog, error) {
return c.provisionerJobLogsBefore(ctx, fmt.Sprintf("/api/v2/templateversions/%s/dry-run/%s/logs", version, job), before)
}

// TemplateVersionDryRunLogsAfter streams logs for a template version dry-run
// that occurred after a specific log ID.
func (c *Client) TemplateVersionDryRunLogsAfter(ctx context.Context, version, job uuid.UUID, after int64) (<-chan ProvisionerJobLog, io.Closer, error) {
Expand Down
60 changes: 60 additions & 0 deletionscodersdk/workspaceagents.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -5,6 +5,7 @@ import (
"encoding/json"
"errors"
"fmt"
"io"
"net"
"net/http"
"net/http/cookiejar"
Expand DownExpand Up@@ -314,6 +315,65 @@ func (c *Client) WorkspaceAgentListeningPorts(ctx context.Context, agentID uuid.
return listeningPorts, json.NewDecoder(res.Body).Decode(&listeningPorts)
}

func (c *Client) WorkspaceAgentStartupLogsAfter(ctx context.Context, agentID uuid.UUID, after int64) (<-chan WorkspaceAgentStartupLog, io.Closer, error) {
afterQuery := ""
if after != 0 {
afterQuery = fmt.Sprintf("&after=%d", after)
}
followURL, err := c.URL.Parse(fmt.Sprintf("/api/v2/workspaceagents/%s/startup-logs?follow%s", agentID, afterQuery))
if err != nil {
return nil, nil, err
}
jar, err := cookiejar.New(nil)
if err != nil {
return nil, nil, xerrors.Errorf("create cookie jar: %w", err)
}
jar.SetCookies(followURL, []*http.Cookie{{
Name: SessionTokenCookie,
Value: c.SessionToken(),
}})
httpClient := &http.Client{
Jar: jar,
Transport: c.HTTPClient.Transport,
}
conn, res, err := websocket.Dial(ctx, followURL.String(), &websocket.DialOptions{
HTTPClient: httpClient,
CompressionMode: websocket.CompressionDisabled,
})
if err != nil {
if res == nil {
return nil, nil, err
}
return nil, nil, ReadBodyAsError(res)
}
logs := make(chan WorkspaceAgentStartupLog)
closed := make(chan struct{})
ctx, wsNetConn := websocketNetConn(ctx, conn, websocket.MessageText)
decoder := json.NewDecoder(wsNetConn)
go func() {
defer close(closed)
defer close(logs)
defer conn.Close(websocket.StatusGoingAway, "")
var log WorkspaceAgentStartupLog
for {
err = decoder.Decode(&log)
if err != nil {
return
}
select {
case <-ctx.Done():
return
case logs <- log:
}
}
}()
return logs, closeFunc(func() error {
_ = wsNetConn.Close()
<-closed
return nil
}), nil
}

// GitProvider is a constant that represents the
// type of providers that are supported within Coder.
type GitProvider string
Expand Down
Loading

[8]ページ先頭

©2009-2025 Movatter.jp