@@ -79,14 +79,15 @@ func DefaultWorkspaceProvider(ctx context.Context, c coder.Client) (*coder.Kuber
79
79
// WorkspaceTable defines an Workspace-like structure with associated entities composed in a human
80
80
// readable form.
81
81
type WorkspaceTable struct {
82
- Name string `table:"Name"`
83
- Image string `table:"Image"`
84
- CPU float32 `table:"vCPU"`
85
- MemoryGB float32 `table:"MemoryGB"`
86
- DiskGB int `table:"DiskGB"`
87
- Status string `table:"Status"`
88
- Provider string `table:"Provider"`
89
- CVM bool `table:"CVM"`
82
+ Name string `table:"Name" json:"name"`
83
+ Image string `table:"Image" json:"image"`
84
+ CPU float32 `table:"vCPU" json:"cpu"`
85
+ MemoryGB float32 `table:"MemoryGB" json:"memory_gb"`
86
+ DiskGB int `table:"DiskGB" json:"disk_gb"`
87
+ Status string `table:"Status" json:"status"`
88
+ Provider string `table:"Provider" json:"provider"`
89
+ CVM bool `table:"CVM" json:"cvm"`
90
+ Username string `table:"Username" json:"username"`
90
91
}
91
92
92
93
// WorkspacesHumanTable performs the composition of each Workspace with its associated ProviderName and ImageRepo.
@@ -96,6 +97,11 @@ func WorkspacesHumanTable(ctx context.Context, client coder.Client, workspaces [
96
97
return nil ,err
97
98
}
98
99
100
+ userMap ,err := MakeUserMap (ctx ,client ,workspaces )
101
+ if err != nil {
102
+ return nil ,err
103
+ }
104
+
99
105
pooledWorkspaces := make ([]WorkspaceTable ,0 ,len (workspaces ))
100
106
providers ,err := client .WorkspaceProviders (ctx )
101
107
if err != nil {
@@ -105,25 +111,66 @@ func WorkspacesHumanTable(ctx context.Context, client coder.Client, workspaces [
105
111
for _ ,p := range providers .Kubernetes {
106
112
providerMap [p .ID ]= p
107
113
}
108
- for _ ,e := range workspaces {
109
- workspaceProvider ,ok := providerMap [e .ResourcePoolID ]
114
+ for _ ,ws := range workspaces {
115
+ workspaceProvider ,ok := providerMap [ws .ResourcePoolID ]
110
116
if ! ok {
111
117
return nil ,xerrors .Errorf ("fetch workspace workspace provider: %w" ,coder .ErrNotFound )
112
118
}
113
119
pooledWorkspaces = append (pooledWorkspaces ,WorkspaceTable {
114
- Name :e .Name ,
115
- Image :fmt .Sprintf ("%s:%s" ,imageMap [e .ImageID ].Repository ,e .ImageTag ),
116
- CPU :e .CPUCores ,
117
- MemoryGB :e .MemoryGB ,
118
- DiskGB :e .DiskGB ,
119
- Status :string (e .LatestStat .ContainerStatus ),
120
+ Name :ws .Name ,
121
+ Image :fmt .Sprintf ("%s:%s" ,imageMap [ws .ImageID ].Repository ,ws .ImageTag ),
122
+ CPU :ws .CPUCores ,
123
+ MemoryGB :ws .MemoryGB ,
124
+ DiskGB :ws .DiskGB ,
125
+ Status :string (ws .LatestStat .ContainerStatus ),
120
126
Provider :workspaceProvider .Name ,
121
- CVM :e .UseContainerVM ,
127
+ CVM :ws .UseContainerVM ,
128
+ Username :userMap [ws .UserID ].Username ,
122
129
})
123
130
}
124
131
return pooledWorkspaces ,nil
125
132
}
126
133
134
+ func MakeUserMap (ctx context.Context ,client coder.Client ,workspaces []coder.Workspace ) (map [string ]* coder.User ,error ) {
135
+ var (
136
+ mu sync.Mutex
137
+ egroup = clog .LoggedErrGroup ()
138
+ )
139
+
140
+ userMap := map [string ]* coder.User {}
141
+
142
+ // Iterate over all the workspaces to get a list of unique User IDs.
143
+ for _ ,ws := range workspaces {
144
+ userMap [ws .UserID ]= nil
145
+ }
146
+
147
+ fetchIds := make ([]string ,0 ,len (userMap ))
148
+ for id := range userMap {
149
+ fetchIds = append (fetchIds ,id )
150
+ }
151
+
152
+ for _ ,id := range fetchIds {
153
+ id := id
154
+ egroup .Go (func ()error {
155
+ user ,err := client .UserByID (ctx ,id )
156
+ if err != nil {
157
+ return xerrors .Errorf ("get user by id: %w" ,err )
158
+ }
159
+ mu .Lock ()
160
+ defer mu .Unlock ()
161
+
162
+ userMap [id ]= user
163
+ return nil
164
+ })
165
+ }
166
+
167
+ if err := egroup .Wait ();err != nil {
168
+ return nil ,xerrors .Errorf ("fetch all workspace users: %w" ,err )
169
+ }
170
+
171
+ return userMap ,nil
172
+ }
173
+
127
174
// MakeImageMap fetches all image entities specified in the slice of workspaces, then places them into an ID map.
128
175
func MakeImageMap (ctx context.Context ,client coder.Client ,workspaces []coder.Workspace ) (map [string ]* coder.Image ,error ) {
129
176
var (