@@ -4,11 +4,15 @@ import (
4
4
"context"
5
5
"database/sql"
6
6
"errors"
7
+ "fmt"
7
8
"net/http"
9
+ "strings"
8
10
9
11
"github.com/coder/coder/coderd/database"
10
12
"github.com/coder/coder/coderd/httpapi"
11
13
"github.com/coder/coder/codersdk"
14
+ "github.com/go-chi/chi/v5"
15
+ "github.com/google/uuid"
12
16
)
13
17
14
18
type workspaceParamContextKey struct {}
@@ -48,3 +52,106 @@ func ExtractWorkspaceParam(db database.Store) func(http.Handler) http.Handler {
48
52
})
49
53
}
50
54
}
55
+
56
+ // ExtractWorkspaceAndAgentParam grabs a workspace and an agent from the
57
+ // "workspacename_and_agent" URL parameter. `ExtractUserParam` must be called
58
+ // before this.
59
+ // This can be in the form of:
60
+ // - "<workspace-name>.[workspace-agent]" : If multiple agents exist
61
+ // - "<workspace-name>" : If one agent exists
62
+ func ExtractWorkspaceAndAgentParam (db database.Store ) func (http.Handler ) http.Handler {
63
+ return func (next http.Handler ) http.Handler {
64
+ return http .HandlerFunc (func (rw http.ResponseWriter , r * http.Request ) {
65
+ user := UserParam (r )
66
+ workspaceWithAgent := chi .URLParam (r , "workspacename_and_agent" )
67
+ workspaceParts := strings .Split (workspaceWithAgent , "." )
68
+
69
+ workspace , err := db .GetWorkspaceByOwnerIDAndName (r .Context (), database.GetWorkspaceByOwnerIDAndNameParams {
70
+ OwnerID : user .ID ,
71
+ Name : workspaceParts [0 ],
72
+ })
73
+ if err != nil {
74
+ if errors .Is (err , sql .ErrNoRows ) {
75
+ httpapi .ResourceNotFound (rw )
76
+ return
77
+ }
78
+ httpapi .Write (rw , http .StatusInternalServerError , codersdk.Response {
79
+ Message : "Internal error fetching workspace." ,
80
+ Detail : err .Error (),
81
+ })
82
+ return
83
+ }
84
+
85
+ build , err := db .GetLatestWorkspaceBuildByWorkspaceID (r .Context (), workspace .ID )
86
+ if err != nil {
87
+ httpapi .Write (rw , http .StatusInternalServerError , codersdk.Response {
88
+ Message : "Internal error fetching workspace build." ,
89
+ Detail : err .Error (),
90
+ })
91
+ return
92
+ }
93
+
94
+ resources , err := db .GetWorkspaceResourcesByJobID (r .Context (), build .JobID )
95
+ if err != nil {
96
+ httpapi .Write (rw , http .StatusInternalServerError , codersdk.Response {
97
+ Message : "Internal error fetching workspace resources." ,
98
+ Detail : err .Error (),
99
+ })
100
+ return
101
+ }
102
+ resourceIDs := make ([]uuid.UUID , 0 )
103
+ for _ , resource := range resources {
104
+ resourceIDs = append (resourceIDs , resource .ID )
105
+ }
106
+
107
+ agents , err := db .GetWorkspaceAgentsByResourceIDs (r .Context (), resourceIDs )
108
+ if err != nil {
109
+ httpapi .Write (rw , http .StatusInternalServerError , codersdk.Response {
110
+ Message : "Internal error fetching workspace agents." ,
111
+ Detail : err .Error (),
112
+ })
113
+ return
114
+ }
115
+
116
+ if len (agents ) == 0 {
117
+ httpapi .Write (rw , http .StatusBadRequest , codersdk.Response {
118
+ Message : "No agents exist for this workspace" ,
119
+ })
120
+ return
121
+ }
122
+
123
+ // If we have more than 1 workspace agent, we need to specify which one to use.
124
+ if len (agents ) > 1 && len (workspaceParts ) <= 1 {
125
+ httpapi .Write (rw , http .StatusBadRequest , codersdk.Response {
126
+ Message : "More than one agent exists, but no agent specified." ,
127
+ })
128
+ return
129
+ }
130
+
131
+ // If we have more than 1 workspace agent, we need to specify which one to use.
132
+ var agent database.WorkspaceAgent
133
+ var found bool
134
+ if len (agents ) > 1 {
135
+ for _ , otherAgent := range agents {
136
+ if otherAgent .Name == workspaceParts [1 ] {
137
+ agent = otherAgent
138
+ found = true
139
+ break
140
+ }
141
+ }
142
+ if ! found {
143
+ httpapi .Write (rw , http .StatusBadRequest , codersdk.Response {
144
+ Message : fmt .Sprintf ("No agent exists with the name %s" , workspaceParts [1 ]),
145
+ })
146
+ return
147
+ }
148
+ } else {
149
+ agent = agents [0 ]
150
+ }
151
+
152
+ ctx := context .WithValue (r .Context (), workspaceParamContextKey {}, workspace )
153
+ ctx = context .WithValue (r .Context (), workspaceAgentContextKey {}, agent )
154
+ next .ServeHTTP (rw , r .WithContext (ctx ))
155
+ })
156
+ }
157
+ }
0 commit comments