10000 chore: pull in cherry picks for v2.24 (#18674) · coder/coder@e5a74a7 · GitHub
[go: up one dir, main page]

Skip to content

Commit e5a74a7

Browse files
stirbydannykoppingEmyrkBrunoQuaresmaSasSwart
authored
chore: pull in cherry picks for v2.24 (#18674)
Co-authored-by: Danny Kopping <danny@coder.com> Co-authored-by: Steven Masley <Emyrk@users.noreply.github.com> Co-authored-by: Bruno Quaresma <bruno@coder.com> Co-authored-by: Sas Swart <sas.swart.cdk@gmail.com> Co-authored-by: Susana Ferreira <susana@coder.com> Co-authored-by: Danielle Maywood <danielle@themaywoods.com> Co-authored-by: Mathias Fredriksson <mafredri@gmail.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Asher <ash@coder.com> Co-authored-by: Hugo Dutka <hugo@coder.com>
1 parent de494d0 commit e5a74a7

File tree

115 files changed

+2208
-8867
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

115 files changed

+2208
-8867
lines changed

agent/agent.go

Lines changed: 92 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ type Options struct {
9191
Execer agentexec.Execer
9292
Devcontainers bool
9393
DevcontainerAPIOptions []agentcontainers.Option // Enable Devcontainers for these to be effective.
94+
Clock quartz.Clock
9495
}
9596

9697
type Client interface {
@@ -144,6 +145,9 @@ func New(options Options) Agent {
144145
if options.PortCacheDuration == 0 {
145146
options.PortCacheDuration = 1 * time.Second
146147
}
148+
if options.Clock == nil {
149+
options.Clock = quartz.NewReal()
150+
}
147151

148152
prometheusRegistry := options.PrometheusRegistry
149153
if prometheusRegistry == nil {
@@ -157,6 +161,7 @@ func New(options F438 Options) Agent {
157161
hardCtx, hardCancel := context.WithCancel(context.Background())
158162
gracefulCtx, gracefulCancel := context.WithCancel(hardCtx)
159163
a := &agent{
164+
clock: options.Clock,
160165
tailnetListenPort: options.TailnetListenPort,
161166
reconnectingPTYTimeout: options.ReconnectingPTYTimeout,
162167
logger: options.Logger,
@@ -204,6 +209,7 @@ func New(options Options) Agent {
204209
}
205210

206211
type agent struct {
212+
clock quartz.Clock
207213
logger slog.Logger
208214
client Client
209215
exchangeToken func(ctx context.Context) (string, error)
@@ -273,7 +279,7 @@ type agent struct {
273279

274280
devcontainers bool
275281
containerAPIOptions []agentcontainers.Option
276-
containerAPI atomic.Pointer[agentcontainers.API] // Set by apiHandler.
282+
containerAPI *agentcontainers.API
277283
}
278284

279285
func (a *agent) TailnetConn() *tailnet.Conn {
@@ -330,6 +336,19 @@ func (a *agent) init() {
330336
// will not report anywhere.
331337
a.scriptRunner.RegisterMetrics(a.prometheusRegistry)
332338

339+
if a.devcontainers {
340+
containerAPIOpts := []agentcontainers.Option{
341+
agentcontainers.WithExecer(a.execer),
342+
agentcontainers.WithCommandEnv(a.sshServer.CommandEnv),
343+
agentcontainers.WithScriptLogger(func(logSourceID uuid.UUID) agentcontainers.ScriptLogger {
344+
return a.logSender.GetScriptLogger(logSourceID)
345+
}),
346+
}
347+
containerAPIOpts = append(containerAPIOpts, a.containerAPIOptions...)
348+
349+
a.containerAPI = agentcontainers.NewAPI(a.logger.Named("containers"), containerAPIOpts...)
350+
}
351+
333352
a.reconnectingPTYServer = reconnectingpty.NewServer(
334353
a.logger.Named("reconnecting-pty"),
335354
a.sshServer,
@@ -1141,17 +1160,27 @@ func (a *agent) handleManifest(manifestOK *checkpoint) func(ctx context.Context,
11411160
}
11421161

11431162
var (
1144-
scripts = manifest.Scripts
1145-
scriptRunnerOpts []agentscripts.InitOption
1163+
scripts = manifest.Scripts
1164+
devcontainerScripts map[uuid.UUID]codersdk.WorkspaceAgentScript
11461165
)
1147-
if a.devcontainers {
1148-
var dcScripts []codersdk.WorkspaceAgentScript
1149-
scripts, dcScripts = agentcontainers.ExtractAndInitializeDevcontainerScripts(manifest.Devcontainers, scripts)
1150-
// See ExtractAndInitializeDevcontainerScripts for motivation
1151-
// behind running dcScripts as post start scripts.
1152-
scriptRunnerOpts = append(scriptRunnerOpts, agentscripts.WithPostStartScripts(dcScripts...))
1166+
if a.containerAPI != nil {
1167+
// Init the container API with the manifest and client so that
1168+
// we can start accepting requests. The final start of the API
1169+
// happens after the startup scripts have been executed to
1170+
// ensure the presence of required tools. This means we can
1171+
// return existing devcontainers but actual container detection
1172+
// and creation will be deferred.
1173+
a.containerAPI.Init(
1174+
agentcontainers.WithManifestInfo(manifest.OwnerName, manifest.WorkspaceName, manifest.AgentName),
1175+
agentcontainers.WithDevcontainers(manifest.Devcontainers, manifest.Scripts),
1176+
agentcontainers.WithSubAgentClient(agentcontainers.NewSubAgentClientFromAPI(a.logger, aAPI)),
1177+
)
1178+
1179+
// Since devcontainer are enabled, remove devcontainer scripts
1180+
// from the main scripts list to avoid showing an error.
1181+
scripts, devcontainerScripts = agentcontainers.ExtractDevcontainerScripts(manifest.Devcontainers, scripts)
11531182
}
1154-
err = a.scriptRunner.Init(scripts, aAPI.ScriptCompleted, scriptRunnerOpts...)
1183+
err = a.scriptRunner.Init(scripts, aAPI.ScriptCompleted)
11551184
if err != nil {
11561185
return xerrors.Errorf("init script runner: %w", err)
11571186
}
@@ -1168,7 +1197,18 @@ func (a *agent) handleManifest(manifestOK *checkpoint) func(ctx context.Context,
11681197
// finished (both start and post start). For instance, an
11691198
// autostarted devcontainer will be included in this time.
11701199
err := a.scriptRunner.Execute(a.gracefulCtx, agentscripts.ExecuteStartScripts)
1171-
err = errors.Join(err, a.scriptRunner.Execute(a.gracefulCtx, agentscripts.ExecutePostStartScripts))
1200+
1201+
if a.containerAPI != nil {
1202+
// Start the container API after the startup scripts have
1203+
// been executed to ensure that the required tools can be
1204+
// installed.
1205+
a.containerAPI.Start()
1206+
for _, dc := range manifest.Devcontainers {
1207+
cErr := a.createDevcontainer(ctx, aAPI, dc, devcontainerScripts[dc.ID])
1208+
err = errors.Join(err, cErr)
1209+
}
1210+
}
1211+
11721212
dur := time.Since(start).Seconds()
11731213
if err != nil {
11741214
a.logger.Warn(ctx, "startup script(s) failed", slog.Error(err))
@@ -1187,14 +1227,6 @@ func (a *agent) handleManifest(manifestOK *checkpoint) func(ctx context.Context,
11871227
}
11881228
a.metrics.startupScriptSeconds.WithLabelValues(label).Set(dur)
11891229
a.scriptRunner.StartCron()
1190-
1191-
// If the container API is enabled, trigger an immediate refresh
1192-
// for quick sub agent injection.
1193-
if cAPI := a.containerAPI.Load(); cAPI != nil {
1194-
if err := cAPI.RefreshContainers(ctx); err != nil {
1195-
a.logger.Error(ctx, "failed to refresh containers", slog.Error(err))
1196-
}
1197-
}
11981230
})
11991231
if err != nil {
12001232
return xerrors.Errorf("track conn goroutine: %w", err)
@@ -1204,6 +1236,38 @@ func (a *agent) handleManifest(manifestOK *checkpoint) func(ctx context.Context,
12041236
}
12051237
}
12061238

1239+
func (a *agent) createDevcontainer(
1240+
ctx context.Context,
1241+
aAPI proto.DRPCAgentClient26,
1242+
dc codersdk.WorkspaceAgentDevcontainer,
1243+
script codersdk.WorkspaceAgentScript,
1244+
) (err error) {
1245+
var (
1246+
exitCode = int32(0)
1247+
startTime = a.clock.Now()
1248+
status = proto.Timing_OK
1249+
)
1250+
if err = a.containerAPI.CreateDevcontainer(dc.WorkspaceFolder, dc.ConfigPath); err != nil {
1251+
exitCode = 1
1252+
status = proto.Timing_EXIT_FAILURE
1253+
}
1254+
endTime := a.clock.Now()
1255+
1256+
if _, scriptErr := aAPI.ScriptCompleted(ctx, &proto.WorkspaceAgentScriptCompletedRequest{
1257+
Timing: &proto.Timing{
1258+
ScriptId: script.ID[:],
1259+
Start: timestamppb.New(startTime),
1260+
End: timestamppb.New(endTime),
1261+
ExitCode: exitCode,
1262+
Stage: proto.Timing_START,
1263+
Status: status,
1264+
},
1265+
}); scriptErr != nil {
1266+
a.logger.Warn(ctx, "reporting script completed failed", slog.Error(scriptErr))
1267+
}
1268+
return err
1269+
}
1270+
12071271
// createOrUpdateNetwork waits for the manifest to be set using manifestOK, then creates or updates
12081272
// the tailnet using the information in the manifest
12091273
func (a *agent) createOrUpdateNetwork(manifestOK, networkOK *checkpoint) func(context.Context, proto.DRPCAgentClient26) error {
@@ -1227,7 +1291,6 @@ func (a *agent) createOrUpdateNetwork(manifestOK, networkOK *checkpoint) func(co
12271291
// agent API.
12281292
network, err = a.createTailnet(
12291293
a.gracefulCtx,
1230-
aAPI,
12311294
manifest.AgentID,
12321295
manifest.DERPMap,
12331296
manifest.DERPForceWebSockets,
@@ -1262,9 +1325,9 @@ func (a *agent) createOrUpdateNetwork(manifestOK, networkOK *checkpoint) func(co
12621325
network.SetBlockEndpoints(manifest.DisableDirectConnections)
12631326

12641327
// Update the subagent client if the container API is available.
1265-
if cAPI := a.containerAPI.Load(); cAPI != nil {
1328+
if a.containerAPI != nil {
12661329
client := agentcontainers.NewSubAgentClientFromAPI(a.logger, aAPI)
1267-
cAPI.UpdateSubAgentClient(client)
1330+
a.containerAPI.UpdateSubAgentClient(client)
12681331
}
12691332
}
12701333
return nil
@@ -1382,7 +1445,6 @@ func (a *agent) trackGoroutine(fn func()) error {
13821445

13831446
func (a *agent) createTailnet(
13841447
ctx context.Context,
1385-
aAPI proto.DRPCAgentClient26,
13861448
agentID uuid.UUID,
13871449
derpMap *tailcfg.DERPMap,
13881450
derpForceWebSockets, disableDirectConnections bool,
@@ -1515,10 +1577,7 @@ func (a *agent) createTailnet(
15151577
}()
15161578
if err = a.trackGoroutine(func() {
15171579
defer apiListener.Close()
1518-
apiHandler, closeAPIHAndler := a.apiHandler(aAPI)
1519-
defer func() {
1520-
_ = closeAPIHAndler()
1521-
}()
1580+
apiHandler := a.apiHandler()
15221581
server := &http.Server{
15231582
BaseContext: func(net.Listener) context.Context { return ctx },
15241583
Handler: apiHandler,
@@ -1532,7 +1591,6 @@ func (a *agent) createTailnet(
15321591
case <-ctx.Done():
15331592
case <-a.hardCtx.Done():
15341593
}
1535-
_ = closeAPIHAndler()
15361594
_ = server.Close()
15371595
}()
15381596

@@ -1871,6 +1929,12 @@ func (a *agent) Close() error {
18711929
a.logger.Error(a.hardCtx, "script runner close", slog.Error(err))
18721930
}
18731931

1932+
if a.containerAPI != nil {
1933+
if err := a.containerAPI.Close(); err != nil {
1934+
a.logger.Error(a.hardCtx, "container API close", slog.Error(err))
1935+
}
1936+
}
1937+
18741938
// Wait for the graceful shutdown to complete, but don't wait forever so
18751939
// that we don't break user expectations.
18761940
go func() {

0 commit comments

Comments
 (0)
0