| 1060 | } |
| 1061 | |
| 1062 | func (a *agent) run() (retErr error) { |
| 1063 | // This allows the agent to refresh its token if necessary. |
| 1064 | // For instance identity this is required, since the instance |
| 1065 | // may not have re-provisioned, but a new agent ID was created. |
| 1066 | err := a.client.RefreshToken(a.hardCtx) |
| 1067 | if err != nil { |
| 1068 | return xerrors.Errorf("refresh token: %w", err) |
| 1069 | } |
| 1070 | |
| 1071 | // ConnectRPC returns the dRPC connection we use for the Agent and Tailnet v2+ APIs. |
| 1072 | // We pass role "agent" to enable connection monitoring on the server, which tracks |
| 1073 | // the agent's connectivity state (first_connected_at, last_connected_at, disconnected_at). |
| 1074 | aAPI, tAPI, err := a.client.ConnectRPC29WithRole(a.hardCtx, "agent") |
| 1075 | if err != nil { |
| 1076 | return err |
| 1077 | } |
| 1078 | defer func() { |
| 1079 | cErr := aAPI.DRPCConn().Close() |
| 1080 | if cErr != nil { |
| 1081 | a.logger.Debug(a.hardCtx, "error closing drpc connection", slog.Error(cErr)) |
| 1082 | } |
| 1083 | }() |
| 1084 | |
| 1085 | // The socket server accepts requests from processes running inside the workspace and forwards |
| 1086 | // some of the requests to Coderd over the DRPC connection. |
| 1087 | if a.socketServer != nil { |
| 1088 | a.socketServer.SetAgentAPI(aAPI) |
| 1089 | defer a.socketServer.ClearAgentAPI() |
| 1090 | } |
| 1091 | |
| 1092 | // A lot of routines need the agent API / tailnet API connection. We run them in their own |
| 1093 | // goroutines in parallel, but errors in any routine will cause them all to exit so we can |
| 1094 | // redial the coder server and retry. |
| 1095 | connMan := newAPIConnRoutineManager(a.gracefulCtx, a.hardCtx, a.logger, aAPI, tAPI) |
| 1096 | |
| 1097 | connMan.startAgentAPI("init notification banners", gracefulShutdownBehaviorStop, |
| 1098 | func(ctx context.Context, aAPI proto.DRPCAgentClient28) error { |
| 1099 | bannersProto, err := aAPI.GetAnnouncementBanners(ctx, &proto.GetAnnouncementBannersRequest{}) |
| 1100 | if err != nil { |
| 1101 | return xerrors.Errorf("fetch service banner: %w", err) |
| 1102 | } |
| 1103 | banners := make([]codersdk.BannerConfig, 0, len(bannersProto.AnnouncementBanners)) |
| 1104 | for _, bannerProto := range bannersProto.AnnouncementBanners { |
| 1105 | banners = append(banners, agentsdk.BannerConfigFromProto(bannerProto)) |
| 1106 | } |
| 1107 | a.announcementBanners.Store(&banners) |
| 1108 | return nil |
| 1109 | }, |
| 1110 | ) |
| 1111 | |
| 1112 | // sending logs gets gracefulShutdownBehaviorRemain because we want to send logs generated by |
| 1113 | // shutdown scripts. |
| 1114 | connMan.startAgentAPI("send logs", gracefulShutdownBehaviorRemain, |
| 1115 | func(ctx context.Context, aAPI proto.DRPCAgentClient28) error { |
| 1116 | err := a.logSender.SendLoop(ctx, aAPI) |
| 1117 | if xerrors.Is(err, agentsdk.ErrLogLimitExceeded) { |
| 1118 | // we don't want this error to tear down the API connection and propagate to the |
| 1119 | // other routines that use the API. The LogSender has already dropped a warning |