7
7
"errors"
8
8
"fmt"
9
9
"net/http"
10
+ "slices"
10
11
"strconv"
11
12
"time"
12
13
@@ -15,6 +16,7 @@ import (
15
16
"golang.org/x/xerrors"
16
17
17
18
"cdr.dev/slog"
19
+ "github.com/coder/coder/v2/agent/proto"
18
20
"github.com/coder/coder/v2/coderd/audit"
19
21
"github.com/coder/coder/v2/coderd/database"
20
22
"github.com/coder/coder/v2/coderd/database/db2sdk"
@@ -1106,6 +1108,7 @@ func (api *API) putExtendWorkspace(rw http.ResponseWriter, r *http.Request) {
1106
1108
// @Security CoderSessionToken
1107
1109
// @Tags Workspaces
1108
1110
// @Param workspace path string true "Workspace ID" format(uuid)
1111
+ // @Param request body codersdk.PostWorkspaceUsageRequest false "Post workspace usage request"
1109
1112
// @Success 204
1110
1113
// @Router /workspaces/{workspace}/usage [post]
1111
1114
func (api * API ) postWorkspaceUsage (rw http.ResponseWriter , r * http.Request ) {
@@ -1116,6 +1119,93 @@ func (api *API) postWorkspaceUsage(rw http.ResponseWriter, r *http.Request) {
1116
1119
}
1117
1120
1118
1121
api .statsReporter .TrackUsage (workspace .ID )
1122
+
1123
+ if ! api .Experiments .Enabled (codersdk .ExperimentWorkspaceUsage ) {
1124
+ // Continue previous behavior if the experiment is not enabled.
1125
+ rw .WriteHeader (http .StatusNoContent )
1126
+ return
1127
+ }
1128
+
1129
+ ctx := r .Context ()
1130
+ var req codersdk.PostWorkspaceUsageRequest
1131
+ if ! httpapi .Read (ctx , rw , r , & req ) {
1132
+ return
1133
+ }
1134
+
1135
+ if req .AgentID == uuid .Nil && req .AppName == "" {
1136
+ // Continue previous behavior if body is empty.
1137
+ rw .WriteHeader (http .StatusNoContent )
1138
+ return
1139
+ }
1140
+ if req .AgentID == uuid .Nil {
1141
+ httpapi .Write (ctx , rw , http .StatusBadRequest , codersdk.Response {
1142
+ Message : "Invalid request" ,
1143
+ Validations : []codersdk.ValidationError {{
1144
+ Field : "agent_id" ,
1145
+ Detail : "must be set when app_name is set" ,
1146
+ }},
1147
+ })
1148
+ return
1149
+ }
1150
+ if req .AppName == "" {
1151
+ httpapi .Write (ctx , rw , http .StatusBadRequest , codersdk.Response {
1152
+ Message : "Invalid request" ,
1153
+ Validations : []codersdk.ValidationError {{
1154
+ Field : "app_name" ,
1155
+ Detail : "must be set when agent_id is set" ,
1156
+ }},
1157
+ })
1158
+ return
1159
+ }
1160
+ if ! slices .Contains (codersdk .AllowedAppNames , req .AppName ) {
1161
+ httpapi .Write (ctx , rw , http .StatusBadRequest , codersdk.Response {
1162
+ Message : "Invalid request" ,
1163
+ Validations : []codersdk.ValidationError {{
1164
+ Field : "app_name" ,
1165
+ Detail : fmt .Sprintf ("must be one of %v" , codersdk .AllowedAppNames ),
1166
+ }},
1167
+ })
1168
+ return
1169
+ }
1170
+
1171
+ stat := & proto.Stats {}
1172
+ switch req .AppName {
1173
+ case codersdk .UsageAppNameVscode :
1174
+ stat .SessionCountVscode = 1
1175
+ case codersdk .UsageAppNameJetbrains :
1176
+ stat .SessionCountJetbrains = 1
1177
+ case codersdk .UsageAppNameReconnectingPty :
1178
+ stat .SessionCountReconnectingPty = 1
1179
+ case codersdk .UsageAppNameSsh :
1180
+ stat .SessionCountSsh = 1
1181
+ default :
1182
+ // This means the app_name is not in the list of allowed app names.
1183
+ httpapi .InternalServerError (rw , xerrors .Errorf ("unknown app_name %q" , req .AppName ))
1184
+ return
1185
+ }
1186
+
1187
+ agent , err := api .Database .GetWorkspaceAgentByID (ctx , req .AgentID )
1188
+ if err != nil {
1189
+ if httpapi .Is404Error (err ) {
1190
+ httpapi .ResourceNotFound (rw )
1191
+ return
1192
+ }
1193
+ httpapi .InternalServerError (rw , err )
1194
+ return
1195
+ }
1196
+
1197
+ template , err := api .Database .GetTemplateByID (ctx , workspace .TemplateID )
1198
+ if err != nil {
1199
+ httpapi .InternalServerError (rw , err )
1200
+ return
1201
+ }
1202
+
1203
+ err = api .statsReporter .ReportAgentStats (ctx , dbtime .Now (), workspace , agent , template .Name , stat )
1204
+ if err != nil {
1205
+ httpapi .InternalServerError (rw , err )
1206
+ return
1207
+ }
1208
+
1119
1209
rw .WriteHeader (http .StatusNoContent )
1120
1210
}
1121
1211
0 commit comments