@@ -3,6 +3,7 @@ package cmd
3
3
import (
4
4
"fmt"
5
5
"os"
6
+ "sort"
6
7
"text/tabwriter"
7
8
8
9
"cdr.dev/coder-cli/coder-sdk"
@@ -14,60 +15,81 @@ func makeResourceCmd() *cobra.Command {
14
15
Use : "resources" ,
15
16
Short : "manager Coder resources with platform-level context (users, organizations, environments)" ,
16
17
}
17
- cmd .AddCommand (resourceTop )
18
+ cmd .AddCommand (resourceTop () )
18
19
return cmd
19
20
}
20
21
21
- var resourceTop = & cobra.Command {
22
- Use : "top" ,
23
- RunE : func (cmd * cobra.Command , args []string ) error {
24
- ctx := cmd .Context ()
25
-
26
- client , err := newClient ()
27
- if err != nil {
28
- return err
29
- }
30
-
31
- envs , err := client .ListEnvironments (ctx )
32
- if err != nil {
33
- return err
34
- }
35
-
36
- userEnvs := make (map [string ][]coder.Environment )
37
- for _ , e := range envs {
38
- userEnvs [e .UserID ] = append (userEnvs [e .UserID ], e )
39
- }
40
-
41
- users , err := client .Users (ctx )
42
- if err != nil {
43
- return err
44
- }
45
-
46
- orgs := make (map [string ]coder.Organization )
47
- orglist , err := client .Organizations (ctx )
48
- if err != nil {
49
- return err
50
- }
51
- for _ , o := range orglist {
52
- orgs [o .ID ] = o
53
- }
54
-
55
- tabwriter := tabwriter .NewWriter (os .Stdout , 0 , 0 , 4 , ' ' , 0 )
56
- for _ , u := range users {
57
- _ , _ = fmt .Fprintf (tabwriter , "%s\t (%s)\t %s" , u .Name , u .Email , aggregateEnvResources (userEnvs [u .ID ]))
58
- if len (userEnvs [u .ID ]) > 0 {
59
- _ , _ = fmt .Fprintf (tabwriter , "\f " )
22
+ func resourceTop () * cobra.Command {
23
+ cmd := & cobra.Command {
24
+ Use : "top" ,
25
+ RunE : func (cmd * cobra.Command , args []string ) error {
26
+ ctx := cmd .Context ()
27
+
28
+ client , err := newClient ()
29
+ if err != nil {
30
+ return err
31
+ }
32
+
33
+ envs , err := client .ListEnvironments (ctx )
34
+ if err != nil {
35
+ return err
60
36
}
61
- for _ , env := range userEnvs [u .ID ] {
62
- _ , _ = fmt .Fprintf (tabwriter , "\t " )
63
- _ , _ = fmt .Fprintln (tabwriter , fmtEnvResources (env , orgs ))
37
+
38
+ userEnvs := make (map [string ][]coder.Environment )
39
+ for _ , e := range envs {
40
+ userEnvs [e .UserID ] = append (userEnvs [e .UserID ], e )
64
41
}
65
- fmt .Fprint (tabwriter , "\n " )
66
- }
67
- _ = tabwriter .Flush ()
68
42
69
- return nil
70
- },
43
+ users , err := client .Users (ctx )
44
+ if err != nil {
45
+ return err
46
+ }
47
+
48
+ orgs := make (map [string ]coder.Organization )
49
+ orglist , err := client .Organizations (ctx )
50
+ if err != nil {
51
+ return err
52
+ }
53
+ for _ , o := range orglist {
54
+ orgs [o .ID ] = o
55
+ }
56
+
57
+ tabwriter := tabwriter .NewWriter (os .Stdout , 0 , 0 , 4 , ' ' , 0 )
58
+ var userResources []aggregatedUser
59
+ for _ , u := range users {
60
+ // truncate user names to ensure tabwriter doesn't push our entire table too far
61
+ u .Name = truncate (u .Name , 20 , "..." )
62
+ userResources = append (userResources , aggregatedUser {User : u , resources : aggregateEnvResources (userEnvs [u .ID ])})
63
+ }
64
+ sort .Slice (userResources , func (i , j int ) bool {
65
+ return userResources [i ].cpuAllocation > userResources [j ].cpuAllocation
66
+ })
67
+
68
+ for _ , u := range userResources {
69
+ _ , _ = fmt .Fprintf (tabwriter , "%s\t (%s)\t %s" , u .Name , u .Email , u .resources )
70
+ if verbose {
71
+ if len (userEnvs [u .ID ]) > 0 {
72
+ _ , _ = fmt .Fprintf (tabwriter , "\f " )
73
+ }
74
+ for _ , env := range userEnvs [u .ID ] {
75
+ _ , _ = fmt .Fprintf (tabwriter , "\t " )
76
+ _ , _ = fmt .Fprintln (tabwriter , fmtEnvResources (env , orgs ))
77
+ }
78
+ }
79
+ fmt .Fprint (tabwriter , "\n " )
80
+ }
81
+ _ = tabwriter .Flush ()
82
+
83
+ return nil
84
+ },
85
+ }
86
+
87
+ return cmd
88
+ }
89
+
90
+ type aggregatedUser struct {
91
+ coder.User
92
+ resources
71
93
}
72
94
73
95
func resourcesFromEnv (env coder.Environment ) resources {
@@ -104,3 +126,11 @@ type resources struct {
104
126
func (a resources ) String () string {
105
127
return fmt .Sprintf ("[cpu: alloc=%.1fvCPU, util=%.1f]\t [mem: alloc=%.1fGB, util=%.1f]" , a .cpuAllocation , a .cpuUtilization , a .memAllocation , a .memUtilization )
106
128
}
129
+
130
+ // truncate the given string and replace the removed chars with some replacement (ex: "...")
131
+ func truncate (str string , max int , replace string ) string {
132
+ if len (str ) <= max {
133
+ return str
134
+ }
135
+ return str [:max + 1 ] + replace
136
+ }
0 commit comments