Skip to content

Commit e9fdd86

Browse files
committed
Merge branch 'jjs/presets' of github.com:/coder/coder into dk/prebuilds
2 parents 9df08f7 + a737087 commit e9fdd86

File tree

88 files changed

+2786
-551
lines changed

Some content is hidden

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

88 files changed

+2786
-551
lines changed

.github/workflows/docs-ci.yaml

+3
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ on:
1515
- "**.md"
1616
- ".github/workflows/docs-ci.yaml"
1717

18+
permissions:
19+
contents: read
20+
1821
jobs:
1922
docs:
2023
runs-on: ubuntu-latest

agent/agent.go

+45-23
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,18 @@ import (
4141
"github.com/coder/coder/v2/agent/agentscripts"
4242
"github.com/coder/coder/v2/agent/agentssh"
4343
"github.com/coder/coder/v2/agent/proto"
44+
"github.com/coder/coder/v2/agent/proto/resourcesmonitor"
4445
"github.com/coder/coder/v2/agent/reconnectingpty"
4546
"github.com/coder/coder/v2/buildinfo"
47+
"github.com/coder/coder/v2/cli/clistat"
4648
"github.com/coder/coder/v2/cli/gitauth"
4749
"github.com/coder/coder/v2/coderd/database/dbtime"
4850
"github.com/coder/coder/v2/codersdk"
4951
"github.com/coder/coder/v2/codersdk/agentsdk"
5052
"github.com/coder/coder/v2/codersdk/workspacesdk"
5153
"github.com/coder/coder/v2/tailnet"
5254
tailnetproto "github.com/coder/coder/v2/tailnet/proto"
55+
"github.com/coder/quartz"
5356
)
5457

5558
const (
@@ -89,8 +92,8 @@ type Options struct {
8992
}
9093

9194
type Client interface {
92-
ConnectRPC23(ctx context.Context) (
93-
proto.DRPCAgentClient23, tailnetproto.DRPCTailnetClient23, error,
95+
ConnectRPC24(ctx context.Context) (
96+
proto.DRPCAgentClient24, tailnetproto.DRPCTailnetClient24, error,
9497
)
9598
RewriteDERPMap(derpMap *tailcfg.DERPMap)
9699
}
@@ -410,7 +413,7 @@ func (t *trySingleflight) Do(key string, fn func()) {
410413
fn()
411414
}
412415

413-
func (a *agent) reportMetadata(ctx context.Context, aAPI proto.DRPCAgentClient23) error {
416+
func (a *agent) reportMetadata(ctx context.Context, aAPI proto.DRPCAgentClient24) error {
414417
tickerDone := make(chan struct{})
415418
collectDone := make(chan struct{})
416419
ctx, cancel := context.WithCancel(ctx)
@@ -626,7 +629,7 @@ func (a *agent) reportMetadata(ctx context.Context, aAPI proto.DRPCAgentClient23
626629

627630
// reportLifecycle reports the current lifecycle state once. All state
628631
// changes are reported in order.
629-
func (a *agent) reportLifecycle(ctx context.Context, aAPI proto.DRPCAgentClient23) error {
632+
func (a *agent) reportLifecycle(ctx context.Context, aAPI proto.DRPCAgentClient24) error {
630633
for {
631634
select {
632635
case <-a.lifecycleUpdate:
@@ -708,7 +711,7 @@ func (a *agent) setLifecycle(state codersdk.WorkspaceAgentLifecycle) {
708711
// fetchServiceBannerLoop fetches the service banner on an interval. It will
709712
// not be fetched immediately; the expectation is that it is primed elsewhere
710713
// (and must be done before the session actually starts).
711-
func (a *agent) fetchServiceBannerLoop(ctx context.Context, aAPI proto.DRPCAgentClient23) error {
714+
func (a *agent) fetchServiceBannerLoop(ctx context.Context, aAPI proto.DRPCAgentClient24) error {
712715
ticker := time.NewTicker(a.announcementBannersRefreshInterval)
713716
defer ticker.Stop()
714717
for {
@@ -744,7 +747,7 @@ func (a *agent) run() (retErr error) {
744747
a.sessionToken.Store(&sessionToken)
745748

746749
// ConnectRPC returns the dRPC connection we use for the Agent and Tailnet v2+ APIs
747-
aAPI, tAPI, err := a.client.ConnectRPC23(a.hardCtx)
750+
aAPI, tAPI, err := a.client.ConnectRPC24(a.hardCtx)
748751
if err != nil {
749752
return err
750753
}
@@ -761,7 +764,7 @@ func (a *agent) run() (retErr error) {
761764
connMan := newAPIConnRoutineManager(a.gracefulCtx, a.hardCtx, a.logger, aAPI, tAPI)
762765

763766
connMan.startAgentAPI("init notification banners", gracefulShutdownBehaviorStop,
764-
func(ctx context.Context, aAPI proto.DRPCAgentClient23) error {
767+
func(ctx context.Context, aAPI proto.DRPCAgentClient24) error {
765768
bannersProto, err := aAPI.GetAnnouncementBanners(ctx, &proto.GetAnnouncementBannersRequest{})
766769
if err != nil {
767770
return xerrors.Errorf("fetch service banner: %w", err)
@@ -778,7 +781,7 @@ func (a *agent) run() (retErr error) {
778781
// sending logs gets gracefulShutdownBehaviorRemain because we want to send logs generated by
779782
// shutdown scripts.
780783
connMan.startAgentAPI("send logs", gracefulShutdownBehaviorRemain,
781-
func(ctx context.Context, aAPI proto.DRPCAgentClient23) error {
784+
func(ctx context.Context, aAPI proto.DRPCAgentClient24) error {
782785
err := a.logSender.SendLoop(ctx, aAPI)
783786
if xerrors.Is(err, agentsdk.LogLimitExceededError) {
784787
// we don't want this error to tear down the API connection and propagate to the
@@ -796,6 +799,25 @@ func (a *agent) run() (retErr error) {
796799
// metadata reporting can cease as soon as we start gracefully shutting down
797800
connMan.startAgentAPI("report metadata", gracefulShutdownBehaviorStop, a.reportMetadata)
798801

802+
// resources monitor can cease as soon as we start gracefully shutting down.
803+
connMan.startAgentAPI("resources monitor", gracefulShutdownBehaviorStop, func(ctx context.Context, aAPI proto.DRPCAgentClient24) error {
804+
logger := a.logger.Named("resources_monitor")
805+
clk := quartz.NewReal()
806+
config, err := aAPI.GetResourcesMonitoringConfiguration(ctx, &proto.GetResourcesMonitoringConfigurationRequest{})
807+
if err != nil {
808+
return xerrors.Errorf("failed to get resources monitoring configuration: %w", err)
809+
}
810+
811+
statfetcher, err := clistat.New()
812+
if err != nil {
813+
return xerrors.Errorf("failed to create resources fetcher: %w", err)
814+
}
815+
resourcesFetcher := resourcesmonitor.NewFetcher(statfetcher)
816+
817+
resourcesmonitor := resourcesmonitor.NewResourcesMonitor(logger, clk, config, resourcesFetcher, aAPI)
818+
return resourcesmonitor.Start(ctx)
819+
})
820+
799821
// channels to sync goroutines below
800822
// handle manifest
801823
// |
@@ -818,7 +840,7 @@ func (a *agent) run() (retErr error) {
818840
connMan.startAgentAPI("handle manifest", gracefulShutdownBehaviorStop, a.handleManifest(manifestOK))
819841

820842
connMan.startAgentAPI("app health reporter", gracefulShutdownBehaviorStop,
821-
func(ctx context.Context, aAPI proto.DRPCAgentClient23) error {
843+
func(ctx context.Context, aAPI proto.DRPCAgentClient24) error {
822844
if err := manifestOK.wait(ctx); err != nil {
823845
return xerrors.Errorf("no manifest: %w", err)
824846
}
@@ -833,7 +855,7 @@ func (a *agent) run() (retErr error) {
833855
a.createOrUpdateNetwork(manifestOK, networkOK))
834856

835857
connMan.startTailnetAPI("coordination", gracefulShutdownBehaviorStop,
836-
func(ctx context.Context, tAPI tailnetproto.DRPCTailnetClient23) error {
858+
func(ctx context.Context, tAPI tailnetproto.DRPCTailnetClient24) error {
837859
if err := networkOK.wait(ctx); err != nil {
838860
return xerrors.Errorf("no network: %w", err)
839861
}
@@ -842,7 +864,7 @@ func (a *agent) run() (retErr error) {
842864
)
843865

844866
connMan.startTailnetAPI("derp map subscriber", gracefulShutdownBehaviorStop,
845-
func(ctx context.Context, tAPI tailnetproto.DRPCTailnetClient23) error {
867+
func(ctx context.Context, tAPI tailnetproto.DRPCTailnetClient24) error {
846868
if err := networkOK.wait(ctx); err != nil {
847869
return xerrors.Errorf("no network: %w", err)
848870
}
@@ -851,7 +873,7 @@ func (a *agent) run() (retErr error) {
851873

852874
connMan.startAgentAPI("fetch service banner loop", gracefulShutdownBehaviorStop, a.fetchServiceBannerLoop)
853875

854-
connMan.startAgentAPI("stats report loop", gracefulShutdownBehaviorStop, func(ctx context.Context, aAPI proto.DRPCAgentClient23) error {
876+
connMan.startAgentAPI("stats report loop", gracefulShutdownBehaviorStop, func(ctx context.Context, aAPI proto.DRPCAgentClient24) error {
855877
if err := networkOK.wait(ctx); err != nil {
856878
return xerrors.Errorf("no network: %w", err)
857879
}
@@ -864,8 +886,8 @@ func (a *agent) run() (retErr error) {
864886
}
865887

866888
// handleManifest returns a function that fetches and processes the manifest
867-
func (a *agent) handleManifest(manifestOK *checkpoint) func(ctx context.Context, aAPI proto.DRPCAgentClient23) error {
868-
return func(ctx context.Context, aAPI proto.DRPCAgentClient23) error {
889+
func (a *agent) handleManifest(manifestOK *checkpoint) func(ctx context.Context, aAPI proto.DRPCAgentClient24) error {
890+
return func(ctx context.Context, aAPI proto.DRPCAgentClient24) error {
869891
var (
870892
sentResult = false
871893
err error
@@ -974,8 +996,8 @@ func (a *agent) handleManifest(manifestOK *checkpoint) func(ctx context.Context,
974996

975997
// createOrUpdateNetwork waits for the manifest to be set using manifestOK, then creates or updates
976998
// the tailnet using the information in the manifest
977-
func (a *agent) createOrUpdateNetwork(manifestOK, networkOK *checkpoint) func(context.Context, proto.DRPCAgentClient23) error {
978-
return func(ctx context.Context, _ proto.DRPCAgentClient23) (retErr error) {
999+
func (a *agent) createOrUpdateNetwork(manifestOK, networkOK *checkpoint) func(context.Context, proto.DRPCAgentClient24) error {
1000+
return func(ctx context.Context, _ proto.DRPCAgentClient24) (retErr error) {
9791001
if err := manifestOK.wait(ctx); err != nil {
9801002
return xerrors.Errorf("no manifest: %w", err)
9811003
}
@@ -1279,7 +1301,7 @@ func (a *agent) createTailnet(ctx context.Context, agentID uuid.UUID, derpMap *t
12791301

12801302
// runCoordinator runs a coordinator and returns whether a reconnect
12811303
// should occur.
1282-
func (a *agent) runCoordinator(ctx context.Context, tClient tailnetproto.DRPCTailnetClient23, network *tailnet.Conn) error {
1304+
func (a *agent) runCoordinator(ctx context.Context, tClient tailnetproto.DRPCTailnetClient24, network *tailnet.Conn) error {
12831305
defer a.logger.Debug(ctx, "disconnected from coordination RPC")
12841306
// we run the RPC on the hardCtx so that we have a chance to send the disconnect message if we
12851307
// gracefully shut down.
@@ -1326,7 +1348,7 @@ func (a *agent) runCoordinator(ctx context.Context, tClient tailnetproto.DRPCTai
13261348
}
13271349

13281350
// runDERPMapSubscriber runs a coordinator and returns if a reconnect should occur.
1329-
func (a *agent) runDERPMapSubscriber(ctx context.Context, tClient tailnetproto.DRPCTailnetClient23, network *tailnet.Conn) error {
1351+
func (a *agent) runDERPMapSubscriber(ctx context.Context, tClient tailnetproto.DRPCTailnetClient24, network *tailnet.Conn) error {
13301352
defer a.logger.Debug(ctx, "disconnected from derp map RPC")
13311353
ctx, cancel := context.WithCancel(ctx)
13321354
defer cancel()
@@ -1696,16 +1718,16 @@ const (
16961718

16971719
type apiConnRoutineManager struct {
16981720
logger slog.Logger
1699-
aAPI proto.DRPCAgentClient23
1700-
tAPI tailnetproto.DRPCTailnetClient23
1721+
aAPI proto.DRPCAgentClient24
1722+
tAPI tailnetproto.DRPCTailnetClient24
17011723
eg *errgroup.Group
17021724
stopCtx context.Context
17031725
remainCtx context.Context
17041726
}
17051727

17061728
func newAPIConnRoutineManager(
17071729
gracefulCtx, hardCtx context.Context, logger slog.Logger,
1708-
aAPI proto.DRPCAgentClient23, tAPI tailnetproto.DRPCTailnetClient23,
1730+
aAPI proto.DRPCAgentClient24, tAPI tailnetproto.DRPCTailnetClient24,
17091731
) *apiConnRoutineManager {
17101732
// routines that remain in operation during graceful shutdown use the remainCtx. They'll still
17111733
// exit if the errgroup hits an error, which usually means a problem with the conn.
@@ -1738,7 +1760,7 @@ func newAPIConnRoutineManager(
17381760
// but for Tailnet.
17391761
func (a *apiConnRoutineManager) startAgentAPI(
17401762
name string, behavior gracefulShutdownBehavior,
1741-
f func(context.Context, proto.DRPCAgentClient23) error,
1763+
f func(context.Context, proto.DRPCAgentClient24) error,
17421764
) {
17431765
logger := a.logger.With(slog.F("name", name))
17441766
var ctx context.Context
@@ -1775,7 +1797,7 @@ func (a *apiConnRoutineManager) startAgentAPI(
17751797
// but for the Agent API.
17761798
func (a *apiConnRoutineManager) startTailnetAPI(
17771799
name string, behavior gracefulShutdownBehavior,
1778-
f func(context.Context, tailnetproto.DRPCTailnetClient23) error,
1800+
f func(context.Context, tailnetproto.DRPCTailnetClient24) error,
17791801
) {
17801802
logger := a.logger.With(slog.F("name", name))
17811803
var ctx context.Context

agent/agenttest/client.go

+32-3
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,8 @@ func (c *Client) Close() {
9797
c.derpMapOnce.Do(func() { close(c.derpMapUpdates) })
9898
}
9999

100-
func (c *Client) ConnectRPC23(ctx context.Context) (
101-
agentproto.DRPCAgentClient23, proto.DRPCTailnetClient23, error,
100+
func (c *Client) ConnectRPC24(ctx context.Context) (
101+
agentproto.DRPCAgentClient24, proto.DRPCTailnetClient24, error,
102102
) {
103103
conn, lis := drpcsdk.MemTransportPipe()
104104
c.LastWorkspaceAgent = func() {
@@ -172,7 +172,9 @@ type FakeAgentAPI struct {
172172
metadata map[string]agentsdk.Metadata
173173
timings []*agentproto.Timing
174174

175-
getAnnouncementBannersFunc func() ([]codersdk.BannerConfig, error)
175+
getAnnouncementBannersFunc func() ([]codersdk.BannerConfig, error)
176+
getResourcesMonitoringConfigurationFunc func() (*agentproto.GetResourcesMonitoringConfigurationResponse, error)
177+
pushResourcesMonitoringUsageFunc func(*agentproto.PushResourcesMonitoringUsageRequest) (*agentproto.PushResourcesMonitoringUsageResponse, error)
176178
}
177179

178180
func (f *FakeAgentAPI) GetManifest(context.Context, *agentproto.GetManifestRequest) (*agentproto.Manifest, error) {
@@ -213,6 +215,33 @@ func (f *FakeAgentAPI) GetAnnouncementBanners(context.Context, *agentproto.GetAn
213215
return &agentproto.GetAnnouncementBannersResponse{AnnouncementBanners: bannersProto}, nil
214216
}
215217

218+
func (f *FakeAgentAPI) GetResourcesMonitoringConfiguration(_ context.Context, _ *agentproto.GetResourcesMonitoringConfigurationRequest) (*agentproto.GetResourcesMonitoringConfigurationResponse, error) {
219+
f.Lock()
220+
defer f.Unlock()
221+
222+
if f.getResourcesMonitoringConfigurationFunc == nil {
223+
return &agentproto.GetResourcesMonitoringConfigurationResponse{
224+
Config: &agentproto.GetResourcesMonitoringConfigurationResponse_Config{
225+
CollectionIntervalSeconds: 10,
226+
NumDatapoints: 20,
227+
},
228+
}, nil
229+
}
230+
231+
return f.getResourcesMonitoringConfigurationFunc()
232+
}
233+
234+
func (f *FakeAgentAPI) PushResourcesMonitoringUsage(_ context.Context, req *agentproto.PushResourcesMonitoringUsageRequest) (*agentproto.PushResourcesMonitoringUsageResponse, error) {
235+
f.Lock()
236+
defer f.Unlock()
237+
238+
if f.pushResourcesMonitoringUsageFunc == nil {
239+
return &agentproto.PushResourcesMonitoringUsageResponse{}, nil
240+
}
241+
242+
return f.pushResourcesMonitoringUsageFunc(req)
243+
}
244+
216245
func (f *FakeAgentAPI) UpdateStats(ctx context.Context, req *agentproto.UpdateStatsRequest) (*agentproto.UpdateStatsResponse, error) {
217246
f.logger.Debug(ctx, "update stats called", slog.F("req", req))
218247
// empty request is sent to get the interval; but our tests don't want empty stats requests

0 commit comments

Comments
 (0)