mirror of
https://github.com/coder/coder.git
synced 2025-07-09 11:45:56 +00:00
feat: add support for coder_script
(#9584)
* Add basic migrations * Improve schema * Refactor agent scripts into it's own package * Support legacy start and stop script format * Pipe the scripts! * Finish the piping * Fix context usage * It works! * Fix sql query * Fix SQL query * Rename `LogSourceID` -> `SourceID` * Fix the FE * fmt * Rename migrations * Fix log tests * Fix lint err * Fix gen * Fix story type * Rename source to script * Fix schema jank * Uncomment test * Rename proto to TimeoutSeconds * Fix comments * Fix comments * Fix legacy endpoint without specified log_source * Fix non-blocking by default in agent * Fix resources tests * Fix dbfake * Fix resources * Fix linting I think * Add fixtures * fmt * Fix startup script behavior * Fix comments * Fix context * Fix cancel * Fix SQL tests * Fix e2e tests * Interrupt on Windows * Fix agent leaking script process * Fix migrations * Fix stories * Fix duplicate logs appearing * Gen * Fix log location * Fix tests * Fix tests * Fix log output * Show display name in output * Fix print * Return timeout on start context * Gen * Fix fixture * Fix the agent status * Fix startup timeout msg * Fix command using shared context * Fix timeout draining * Change signal type * Add deterministic colors to startup script logs --------- Co-authored-by: Muhammad Atif Ali <atif@coder.com>
This commit is contained in:
@ -23,6 +23,13 @@ import (
|
||||
"github.com/coder/retry"
|
||||
)
|
||||
|
||||
// ExternalLogSourceID is the statically-defined ID of a log-source that
|
||||
// appears as "External" in the dashboard.
|
||||
//
|
||||
// This is to support legacy API-consumers that do not create their own
|
||||
// log-source. This should be removed in the future.
|
||||
var ExternalLogSourceID = uuid.MustParse("3b579bf4-1ed8-4b99-87a8-e9a1e3410410")
|
||||
|
||||
// New returns a client that is used to interact with the
|
||||
// Coder API from a workspace agent.
|
||||
func New(serverURL *url.URL) *Client {
|
||||
@ -91,14 +98,21 @@ type Manifest struct {
|
||||
DERPMap *tailcfg.DERPMap `json:"derpmap"`
|
||||
DERPForceWebSockets bool `json:"derp_force_websockets"`
|
||||
EnvironmentVariables map[string]string `json:"environment_variables"`
|
||||
StartupScript string `json:"startup_script"`
|
||||
StartupScriptTimeout time.Duration `json:"startup_script_timeout"`
|
||||
Directory string `json:"directory"`
|
||||
MOTDFile string `json:"motd_file"`
|
||||
ShutdownScript string `json:"shutdown_script"`
|
||||
ShutdownScriptTimeout time.Duration `json:"shutdown_script_timeout"`
|
||||
DisableDirectConnections bool `json:"disable_direct_connections"`
|
||||
Metadata []codersdk.WorkspaceAgentMetadataDescription `json:"metadata"`
|
||||
Scripts []codersdk.WorkspaceAgentScript `json:"scripts"`
|
||||
}
|
||||
|
||||
type LogSource struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
DisplayName string `json:"display_name"`
|
||||
Icon string `json:"icon"`
|
||||
}
|
||||
|
||||
type Script struct {
|
||||
Script string `json:"script"`
|
||||
}
|
||||
|
||||
// Manifest fetches manifest for the currently authenticated workspace agent.
|
||||
@ -631,14 +645,14 @@ func (c *Client) PostStartup(ctx context.Context, req PostStartupRequest) error
|
||||
}
|
||||
|
||||
type Log struct {
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
Output string `json:"output"`
|
||||
Level codersdk.LogLevel `json:"level"`
|
||||
Source codersdk.WorkspaceAgentLogSource `json:"source"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
Output string `json:"output"`
|
||||
Level codersdk.LogLevel `json:"level"`
|
||||
}
|
||||
|
||||
type PatchLogs struct {
|
||||
Logs []Log `json:"logs"`
|
||||
LogSourceID uuid.UUID `json:"log_source_id"`
|
||||
Logs []Log `json:"logs"`
|
||||
}
|
||||
|
||||
// PatchLogs writes log messages to the agent startup script.
|
||||
@ -655,6 +669,29 @@ func (c *Client) PatchLogs(ctx context.Context, req PatchLogs) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type PostLogSource struct {
|
||||
// ID is a unique identifier for the log source.
|
||||
// It is scoped to a workspace agent, and can be statically
|
||||
// defined inside code to prevent duplicate sources from being
|
||||
// created for the same agent.
|
||||
ID uuid.UUID `json:"id"`
|
||||
DisplayName string `json:"display_name"`
|
||||
Icon string `json:"icon"`
|
||||
}
|
||||
|
||||
func (c *Client) PostLogSource(ctx context.Context, req PostLogSource) (codersdk.WorkspaceAgentLogSource, error) {
|
||||
res, err := c.SDK.Request(ctx, http.MethodPost, "/api/v2/workspaceagents/me/log-source", req)
|
||||
if err != nil {
|
||||
return codersdk.WorkspaceAgentLogSource{}, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
if res.StatusCode != http.StatusCreated {
|
||||
return codersdk.WorkspaceAgentLogSource{}, codersdk.ReadBodyAsError(res)
|
||||
}
|
||||
var logSource codersdk.WorkspaceAgentLogSource
|
||||
return logSource, json.NewDecoder(res.Body).Decode(&logSource)
|
||||
}
|
||||
|
||||
// GetServiceBanner relays the service banner config.
|
||||
func (c *Client) GetServiceBanner(ctx context.Context) (codersdk.ServiceBannerConfig, error) {
|
||||
res, err := c.SDK.Request(ctx, http.MethodGet, "/api/v2/appearance", nil)
|
||||
|
@ -10,6 +10,8 @@ import (
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
||||
"cdr.dev/slog"
|
||||
"github.com/coder/coder/v2/codersdk"
|
||||
"github.com/coder/retry"
|
||||
@ -20,7 +22,7 @@ type startupLogsWriter struct {
|
||||
ctx context.Context
|
||||
send func(ctx context.Context, log ...Log) error
|
||||
level codersdk.LogLevel
|
||||
source codersdk.WorkspaceAgentLogSource
|
||||
source uuid.UUID
|
||||
}
|
||||
|
||||
func (w *startupLogsWriter) Write(p []byte) (int, error) {
|
||||
@ -44,7 +46,6 @@ func (w *startupLogsWriter) Write(p []byte) (int, error) {
|
||||
CreatedAt: time.Now().UTC(), // UTC, like dbtime.Now().
|
||||
Level: w.level,
|
||||
Output: string(partial) + string(p[:nl-cr]),
|
||||
Source: w.source,
|
||||
})
|
||||
if err != nil {
|
||||
return n - len(p), err
|
||||
@ -67,24 +68,20 @@ func (w *startupLogsWriter) Close() error {
|
||||
CreatedAt: time.Now().UTC(), // UTC, like dbtime.Now().
|
||||
Level: w.level,
|
||||
Output: w.buf.String(),
|
||||
Source: w.source,
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// StartupLogsWriter returns an io.WriteCloser that sends logs via the
|
||||
// LogsWriter returns an io.WriteCloser that sends logs via the
|
||||
// provided sender. The sender is expected to be non-blocking. Calling
|
||||
// Close flushes any remaining partially written log lines but is
|
||||
// otherwise no-op. If the context passed to StartupLogsWriter is
|
||||
// otherwise no-op. If the context passed to LogsWriter is
|
||||
// canceled, any remaining logs will be discarded.
|
||||
//
|
||||
// Neither Write nor Close is safe for concurrent use and must be used
|
||||
// by a single goroutine.
|
||||
func StartupLogsWriter(ctx context.Context, sender func(ctx context.Context, log ...Log) error, source codersdk.WorkspaceAgentLogSource, level codersdk.LogLevel) io.WriteCloser {
|
||||
if source == "" {
|
||||
source = codersdk.WorkspaceAgentLogSourceExternal
|
||||
}
|
||||
func LogsWriter(ctx context.Context, sender func(ctx context.Context, log ...Log) error, source uuid.UUID, level codersdk.LogLevel) io.WriteCloser {
|
||||
return &startupLogsWriter{
|
||||
ctx: ctx,
|
||||
send: sender,
|
||||
@ -98,7 +95,7 @@ func StartupLogsWriter(ctx context.Context, sender func(ctx context.Context, log
|
||||
// has been called. Calling sendLog concurrently is not supported. If
|
||||
// the context passed to flushAndClose is canceled, any remaining logs
|
||||
// will be discarded.
|
||||
func LogsSender(patchLogs func(ctx context.Context, req PatchLogs) error, logger slog.Logger) (sendLog func(ctx context.Context, log ...Log) error, flushAndClose func(context.Context) error) {
|
||||
func LogsSender(sourceID uuid.UUID, patchLogs func(ctx context.Context, req PatchLogs) error, logger slog.Logger) (sendLog func(ctx context.Context, log ...Log) error, flushAndClose func(context.Context) error) {
|
||||
// The main context is used to close the sender goroutine and cancel
|
||||
// any outbound requests to the API. The shutdown context is used to
|
||||
// signal the sender goroutine to flush logs and then exit.
|
||||
@ -158,7 +155,8 @@ func LogsSender(patchLogs func(ctx context.Context, req PatchLogs) error, logger
|
||||
// shutdown.
|
||||
for r := retry.New(time.Second, 5*time.Second); r.Wait(ctx); {
|
||||
err := patchLogs(ctx, PatchLogs{
|
||||
Logs: backlog,
|
||||
Logs: backlog,
|
||||
LogSourceID: sourceID,
|
||||
})
|
||||
if err == nil {
|
||||
break
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/exp/slices"
|
||||
@ -39,12 +40,10 @@ func TestStartupLogsWriter_Write(t *testing.T) {
|
||||
ctx: context.Background(),
|
||||
level: codersdk.LogLevelInfo,
|
||||
writes: []string{"hello world\n"},
|
||||
source: codersdk.WorkspaceAgentLogSourceShutdownScript,
|
||||
want: []agentsdk.Log{
|
||||
{
|
||||
Level: codersdk.LogLevelInfo,
|
||||
Output: "hello world",
|
||||
Source: codersdk.WorkspaceAgentLogSourceShutdownScript,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -57,12 +56,10 @@ func TestStartupLogsWriter_Write(t *testing.T) {
|
||||
{
|
||||
Level: codersdk.LogLevelInfo,
|
||||
Output: "hello world",
|
||||
Source: codersdk.WorkspaceAgentLogSourceExternal,
|
||||
},
|
||||
{
|
||||
Level: codersdk.LogLevelInfo,
|
||||
Output: "goodbye world",
|
||||
Source: codersdk.WorkspaceAgentLogSourceExternal,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -75,32 +72,26 @@ func TestStartupLogsWriter_Write(t *testing.T) {
|
||||
{
|
||||
Level: codersdk.LogLevelInfo,
|
||||
Output: "",
|
||||
Source: codersdk.WorkspaceAgentLogSourceExternal,
|
||||
},
|
||||
{
|
||||
Level: codersdk.LogLevelInfo,
|
||||
Output: "",
|
||||
Source: codersdk.WorkspaceAgentLogSourceExternal,
|
||||
},
|
||||
{
|
||||
Level: codersdk.LogLevelInfo,
|
||||
Output: "hello world",
|
||||
Source: codersdk.WorkspaceAgentLogSourceExternal,
|
||||
},
|
||||
{
|
||||
Level: codersdk.LogLevelInfo,
|
||||
Output: "",
|
||||
Source: codersdk.WorkspaceAgentLogSourceExternal,
|
||||
},
|
||||
{
|
||||
Level: codersdk.LogLevelInfo,
|
||||
Output: "",
|
||||
Source: codersdk.WorkspaceAgentLogSourceExternal,
|
||||
},
|
||||
{
|
||||
Level: codersdk.LogLevelInfo,
|
||||
Output: "goodbye world",
|
||||
Source: codersdk.WorkspaceAgentLogSourceExternal,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -113,7 +104,6 @@ func TestStartupLogsWriter_Write(t *testing.T) {
|
||||
{
|
||||
Level: codersdk.LogLevelInfo,
|
||||
Output: "hello world",
|
||||
Source: codersdk.WorkspaceAgentLogSourceExternal,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -127,12 +117,10 @@ func TestStartupLogsWriter_Write(t *testing.T) {
|
||||
{
|
||||
Level: codersdk.LogLevelInfo,
|
||||
Output: "hello world",
|
||||
Source: codersdk.WorkspaceAgentLogSourceExternal,
|
||||
},
|
||||
{
|
||||
Level: codersdk.LogLevelInfo,
|
||||
Output: "goodbye world",
|
||||
Source: codersdk.WorkspaceAgentLogSourceExternal,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -145,12 +133,10 @@ func TestStartupLogsWriter_Write(t *testing.T) {
|
||||
{
|
||||
Level: codersdk.LogLevelInfo,
|
||||
Output: "hello world",
|
||||
Source: codersdk.WorkspaceAgentLogSourceExternal,
|
||||
},
|
||||
{
|
||||
Level: codersdk.LogLevelInfo,
|
||||
Output: "goodbye world",
|
||||
Source: codersdk.WorkspaceAgentLogSourceExternal,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -163,17 +149,14 @@ func TestStartupLogsWriter_Write(t *testing.T) {
|
||||
{
|
||||
Level: codersdk.LogLevelInfo,
|
||||
Output: "hello world",
|
||||
Source: codersdk.WorkspaceAgentLogSourceExternal,
|
||||
},
|
||||
{
|
||||
Level: codersdk.LogLevelInfo,
|
||||
Output: "\r",
|
||||
Source: codersdk.WorkspaceAgentLogSourceExternal,
|
||||
},
|
||||
{
|
||||
Level: codersdk.LogLevelInfo,
|
||||
Output: "goodbye world",
|
||||
Source: codersdk.WorkspaceAgentLogSourceExternal,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -201,7 +184,7 @@ func TestStartupLogsWriter_Write(t *testing.T) {
|
||||
got = append(got, log...)
|
||||
return nil
|
||||
}
|
||||
w := agentsdk.StartupLogsWriter(tt.ctx, send, tt.source, tt.level)
|
||||
w := agentsdk.LogsWriter(tt.ctx, send, uuid.New(), tt.level)
|
||||
for _, s := range tt.writes {
|
||||
_, err := w.Write([]byte(s))
|
||||
if err != nil {
|
||||
@ -291,7 +274,7 @@ func TestStartupLogsSender(t *testing.T) {
|
||||
return nil
|
||||
}
|
||||
|
||||
sendLog, flushAndClose := agentsdk.LogsSender(patchLogs, slogtest.Make(t, nil).Leveled(slog.LevelDebug))
|
||||
sendLog, flushAndClose := agentsdk.LogsSender(uuid.New(), patchLogs, slogtest.Make(t, nil).Leveled(slog.LevelDebug))
|
||||
defer func() {
|
||||
err := flushAndClose(ctx)
|
||||
require.NoError(t, err)
|
||||
@ -330,7 +313,7 @@ func TestStartupLogsSender(t *testing.T) {
|
||||
return nil
|
||||
}
|
||||
|
||||
sendLog, flushAndClose := agentsdk.LogsSender(patchLogs, slogtest.Make(t, nil).Leveled(slog.LevelDebug))
|
||||
sendLog, flushAndClose := agentsdk.LogsSender(uuid.New(), patchLogs, slogtest.Make(t, nil).Leveled(slog.LevelDebug))
|
||||
defer func() {
|
||||
_ = flushAndClose(ctx)
|
||||
}()
|
||||
@ -361,7 +344,7 @@ func TestStartupLogsSender(t *testing.T) {
|
||||
return nil
|
||||
}
|
||||
|
||||
sendLog, flushAndClose := agentsdk.LogsSender(patchLogs, slogtest.Make(t, nil).Leveled(slog.LevelDebug))
|
||||
sendLog, flushAndClose := agentsdk.LogsSender(uuid.New(), patchLogs, slogtest.Make(t, nil).Leveled(slog.LevelDebug))
|
||||
defer func() {
|
||||
_ = flushAndClose(ctx)
|
||||
}()
|
||||
|
@ -58,7 +58,7 @@ const (
|
||||
// Starting returns true if the agent is in the process of starting.
|
||||
func (l WorkspaceAgentLifecycle) Starting() bool {
|
||||
switch l {
|
||||
case WorkspaceAgentLifecycleCreated, WorkspaceAgentLifecycleStarting, WorkspaceAgentLifecycleStartTimeout:
|
||||
case WorkspaceAgentLifecycleCreated, WorkspaceAgentLifecycleStarting:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
@ -101,6 +101,7 @@ var WorkspaceAgentLifecycleOrder = []WorkspaceAgentLifecycle{
|
||||
// ready (can be overridden).
|
||||
//
|
||||
// Presently, non-blocking is the default, but this may change in the future.
|
||||
// Deprecated: `coder_script` allows configuration on a per-script basis.
|
||||
type WorkspaceAgentStartupScriptBehavior string
|
||||
|
||||
const (
|
||||
@ -144,42 +145,61 @@ const (
|
||||
)
|
||||
|
||||
type WorkspaceAgent struct {
|
||||
ID uuid.UUID `json:"id" format:"uuid"`
|
||||
CreatedAt time.Time `json:"created_at" format:"date-time"`
|
||||
UpdatedAt time.Time `json:"updated_at" format:"date-time"`
|
||||
FirstConnectedAt *time.Time `json:"first_connected_at,omitempty" format:"date-time"`
|
||||
LastConnectedAt *time.Time `json:"last_connected_at,omitempty" format:"date-time"`
|
||||
DisconnectedAt *time.Time `json:"disconnected_at,omitempty" format:"date-time"`
|
||||
StartedAt *time.Time `json:"started_at,omitempty" format:"date-time"`
|
||||
ReadyAt *time.Time `json:"ready_at,omitempty" format:"date-time"`
|
||||
Status WorkspaceAgentStatus `json:"status"`
|
||||
LifecycleState WorkspaceAgentLifecycle `json:"lifecycle_state"`
|
||||
Name string `json:"name"`
|
||||
ResourceID uuid.UUID `json:"resource_id" format:"uuid"`
|
||||
InstanceID string `json:"instance_id,omitempty"`
|
||||
Architecture string `json:"architecture"`
|
||||
EnvironmentVariables map[string]string `json:"environment_variables"`
|
||||
OperatingSystem string `json:"operating_system"`
|
||||
StartupScript string `json:"startup_script,omitempty"`
|
||||
StartupScriptBehavior WorkspaceAgentStartupScriptBehavior `json:"startup_script_behavior"`
|
||||
StartupScriptTimeoutSeconds int32 `json:"startup_script_timeout_seconds"` // StartupScriptTimeoutSeconds is the number of seconds to wait for the startup script to complete. If the script does not complete within this time, the agent lifecycle will be marked as start_timeout.
|
||||
LogsLength int32 `json:"logs_length"`
|
||||
LogsOverflowed bool `json:"logs_overflowed"`
|
||||
Directory string `json:"directory,omitempty"`
|
||||
ExpandedDirectory string `json:"expanded_directory,omitempty"`
|
||||
Version string `json:"version"`
|
||||
Apps []WorkspaceApp `json:"apps"`
|
||||
ID uuid.UUID `json:"id" format:"uuid"`
|
||||
CreatedAt time.Time `json:"created_at" format:"date-time"`
|
||||
UpdatedAt time.Time `json:"updated_at" format:"date-time"`
|
||||
FirstConnectedAt *time.Time `json:"first_connected_at,omitempty" format:"date-time"`
|
||||
LastConnectedAt *time.Time `json:"last_connected_at,omitempty" format:"date-time"`
|
||||
DisconnectedAt *time.Time `json:"disconnected_at,omitempty" format:"date-time"`
|
||||
StartedAt *time.Time `json:"started_at,omitempty" format:"date-time"`
|
||||
ReadyAt *time.Time `json:"ready_at,omitempty" format:"date-time"`
|
||||
Status WorkspaceAgentStatus `json:"status"`
|
||||
LifecycleState WorkspaceAgentLifecycle `json:"lifecycle_state"`
|
||||
Name string `json:"name"`
|
||||
ResourceID uuid.UUID `json:"resource_id" format:"uuid"`
|
||||
InstanceID string `json:"instance_id,omitempty"`
|
||||
Architecture string `json:"architecture"`
|
||||
EnvironmentVariables map[string]string `json:"environment_variables"`
|
||||
OperatingSystem string `json:"operating_system"`
|
||||
LogsLength int32 `json:"logs_length"`
|
||||
LogsOverflowed bool `json:"logs_overflowed"`
|
||||
Directory string `json:"directory,omitempty"`
|
||||
ExpandedDirectory string `json:"expanded_directory,omitempty"`
|
||||
Version string `json:"version"`
|
||||
Apps []WorkspaceApp `json:"apps"`
|
||||
// DERPLatency is mapped by region name (e.g. "New York City", "Seattle").
|
||||
DERPLatency map[string]DERPRegion `json:"latency,omitempty"`
|
||||
ConnectionTimeoutSeconds int32 `json:"connection_timeout_seconds"`
|
||||
TroubleshootingURL string `json:"troubleshooting_url"`
|
||||
// Deprecated: Use StartupScriptBehavior instead.
|
||||
LoginBeforeReady bool `json:"login_before_ready"`
|
||||
ShutdownScript string `json:"shutdown_script,omitempty"`
|
||||
ShutdownScriptTimeoutSeconds int32 `json:"shutdown_script_timeout_seconds"`
|
||||
Subsystems []AgentSubsystem `json:"subsystems"`
|
||||
Health WorkspaceAgentHealth `json:"health"` // Health reports the health of the agent.
|
||||
DisplayApps []DisplayApp `json:"display_apps"`
|
||||
DERPLatency map[string]DERPRegion `json:"latency,omitempty"`
|
||||
ConnectionTimeoutSeconds int32 `json:"connection_timeout_seconds"`
|
||||
TroubleshootingURL string `json:"troubleshooting_url"`
|
||||
Subsystems []AgentSubsystem `json:"subsystems"`
|
||||
Health WorkspaceAgentHealth `json:"health"` // Health reports the health of the agent.
|
||||
DisplayApps []DisplayApp `json:"display_apps"`
|
||||
LogSources []WorkspaceAgentLogSource `json:"log_sources"`
|
||||
Scripts []WorkspaceAgentScript `json:"scripts"`
|
||||
|
||||
// StartupScriptBehavior is a legacy field that is deprecated in favor
|
||||
// of the `coder_script` resource. It's only referenced by old clients.
|
||||
// Deprecated: Remove in the future!
|
||||
StartupScriptBehavior WorkspaceAgentStartupScriptBehavior `json:"startup_script_behavior"`
|
||||
}
|
||||
|
||||
type WorkspaceAgentLogSource struct {
|
||||
WorkspaceAgentID uuid.UUID `json:"workspace_agent_id" format:"uuid"`
|
||||
ID uuid.UUID `json:"id" format:"uuid"`
|
||||
CreatedAt time.Time `json:"created_at" format:"date-time"`
|
||||
DisplayName string `json:"display_name"`
|
||||
Icon string `json:"icon"`
|
||||
}
|
||||
|
||||
type WorkspaceAgentScript struct {
|
||||
LogSourceID uuid.UUID `json:"log_source_id" format:"uuid"`
|
||||
LogPath string `json:"log_path"`
|
||||
Script string `json:"script"`
|
||||
Cron string `json:"cron"`
|
||||
RunOnStart bool `json:"run_on_start"`
|
||||
RunOnStop bool `json:"run_on_stop"`
|
||||
StartBlocksLogin bool `json:"start_blocks_login"`
|
||||
Timeout time.Duration `json:"timeout"`
|
||||
}
|
||||
|
||||
type WorkspaceAgentHealth struct {
|
||||
@ -530,13 +550,6 @@ func (c *Client) WorkspaceAgent(ctx context.Context, id uuid.UUID) (WorkspaceAge
|
||||
if err != nil {
|
||||
return WorkspaceAgent{}, err
|
||||
}
|
||||
// Backwards compatibility for cases where the API is older then the client.
|
||||
if workspaceAgent.StartupScriptBehavior == "" {
|
||||
workspaceAgent.StartupScriptBehavior = WorkspaceAgentStartupScriptBehaviorNonBlocking
|
||||
if !workspaceAgent.LoginBeforeReady {
|
||||
workspaceAgent.StartupScriptBehavior = WorkspaceAgentStartupScriptBehaviorBlocking
|
||||
}
|
||||
}
|
||||
return workspaceAgent, nil
|
||||
}
|
||||
|
||||
@ -762,6 +775,7 @@ type WorkspaceAgentLog struct {
|
||||
CreatedAt time.Time `json:"created_at" format:"date-time"`
|
||||
Output string `json:"output"`
|
||||
Level LogLevel `json:"level"`
|
||||
SourceID uuid.UUID `json:"source_id" format:"uuid"`
|
||||
}
|
||||
|
||||
type AgentSubsystem string
|
||||
@ -780,14 +794,3 @@ func (s AgentSubsystem) Valid() bool {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
type WorkspaceAgentLogSource string
|
||||
|
||||
const (
|
||||
WorkspaceAgentLogSourceStartupScript WorkspaceAgentLogSource = "startup_script"
|
||||
WorkspaceAgentLogSourceShutdownScript WorkspaceAgentLogSource = "shutdown_script"
|
||||
WorkspaceAgentLogSourceKubernetes WorkspaceAgentLogSource = "kubernetes"
|
||||
WorkspaceAgentLogSourceEnvbox WorkspaceAgentLogSource = "envbox"
|
||||
WorkspaceAgentLogSourceEnvbuilder WorkspaceAgentLogSource = "envbuilder"
|
||||
WorkspaceAgentLogSourceExternal WorkspaceAgentLogSource = "external"
|
||||
)
|
||||
|
Reference in New Issue
Block a user