mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: add agent metadata (#6614)
This commit is contained in:
@@ -19,6 +19,7 @@ import (
|
||||
"tailscale.com/tailcfg"
|
||||
|
||||
"cdr.dev/slog"
|
||||
"github.com/coder/coder/coderd/tracing"
|
||||
"github.com/coder/coder/tailnet"
|
||||
"github.com/coder/retry"
|
||||
)
|
||||
@@ -75,6 +76,31 @@ var WorkspaceAgentLifecycleOrder = []WorkspaceAgentLifecycle{
|
||||
WorkspaceAgentLifecycleOff,
|
||||
}
|
||||
|
||||
type WorkspaceAgentMetadataResult struct {
|
||||
CollectedAt time.Time `json:"collected_at" format:"date-time"`
|
||||
// Age is the number of seconds since the metadata was collected.
|
||||
// It is provided in addition to CollectedAt to protect against clock skew.
|
||||
Age int64 `json:"age"`
|
||||
Value string `json:"value"`
|
||||
Error string `json:"error"`
|
||||
}
|
||||
|
||||
// WorkspaceAgentMetadataDescription is a description of dynamic metadata the agent should report
|
||||
// back to coderd. It is provided via the `metadata` list in the `coder_agent`
|
||||
// block.
|
||||
type WorkspaceAgentMetadataDescription struct {
|
||||
DisplayName string `json:"display_name"`
|
||||
Key string `json:"key"`
|
||||
Script string `json:"script"`
|
||||
Interval int64 `json:"interval"`
|
||||
Timeout int64 `json:"timeout"`
|
||||
}
|
||||
|
||||
type WorkspaceAgentMetadata struct {
|
||||
Result WorkspaceAgentMetadataResult `json:"result"`
|
||||
Description WorkspaceAgentMetadataDescription `json:"description"`
|
||||
}
|
||||
|
||||
type WorkspaceAgent struct {
|
||||
ID uuid.UUID `json:"id" format:"uuid"`
|
||||
CreatedAt time.Time `json:"created_at" format:"date-time"`
|
||||
@@ -258,6 +284,75 @@ func (c *Client) DialWorkspaceAgent(ctx context.Context, agentID uuid.UUID, opti
|
||||
return agentConn, nil
|
||||
}
|
||||
|
||||
// WatchWorkspaceAgentMetadata watches the metadata of a workspace agent.
|
||||
// The returned channel will be closed when the context is canceled. Exactly
|
||||
// one error will be sent on the error channel. The metadata channel is never closed.
|
||||
func (c *Client) WatchWorkspaceAgentMetadata(ctx context.Context, id uuid.UUID) (<-chan []WorkspaceAgentMetadata, <-chan error) {
|
||||
ctx, span := tracing.StartSpan(ctx)
|
||||
defer span.End()
|
||||
|
||||
metadataChan := make(chan []WorkspaceAgentMetadata, 256)
|
||||
|
||||
watch := func() error {
|
||||
res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/workspaceagents/%s/watch-metadata", id), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
return ReadBodyAsError(res)
|
||||
}
|
||||
|
||||
nextEvent := ServerSentEventReader(ctx, res.Body)
|
||||
defer res.Body.Close()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
sse, err := nextEvent()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b, ok := sse.Data.([]byte)
|
||||
if !ok {
|
||||
return xerrors.Errorf("unexpected data type: %T", sse.Data)
|
||||
}
|
||||
|
||||
switch sse.Type {
|
||||
case ServerSentEventTypeData:
|
||||
var met []WorkspaceAgentMetadata
|
||||
err = json.Unmarshal(b, &met)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("unmarshal metadata: %w", err)
|
||||
}
|
||||
metadataChan <- met
|
||||
case ServerSentEventTypeError:
|
||||
var r Response
|
||||
err = json.Unmarshal(b, &r)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("unmarshal error: %w", err)
|
||||
}
|
||||
return xerrors.Errorf("%+v", r)
|
||||
default:
|
||||
return xerrors.Errorf("unexpected event type: %s", sse.Type)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
errorChan := make(chan error, 1)
|
||||
go func() {
|
||||
defer close(errorChan)
|
||||
errorChan <- watch()
|
||||
}()
|
||||
|
||||
return metadataChan, errorChan
|
||||
}
|
||||
|
||||
// WorkspaceAgent returns an agent by ID.
|
||||
func (c *Client) WorkspaceAgent(ctx context.Context, id uuid.UUID) (WorkspaceAgent, error) {
|
||||
res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/workspaceagents/%s", id), nil)
|
||||
|
||||
Reference in New Issue
Block a user