Skip to content
This repository was archived by the owner on Aug 30, 2024. It is now read-only.

Commit 349f90d

Browse files
committed
Add resource sorting by CPU
1 parent 3c27cab commit 349f90d

File tree

2 files changed

+82
-48
lines changed

2 files changed

+82
-48
lines changed

internal/cmd/cmd.go

+4
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ import (
77
"github.com/spf13/cobra/doc"
88
)
99

10+
// verbose is a global flag for specifying that a command should give verbose output
11+
var verbose bool = false
12+
1013
// Make constructs the "coder" root command
1114
func Make() *cobra.Command {
1215
app := &cobra.Command{
@@ -28,6 +31,7 @@ func Make() *cobra.Command {
2831
completionCmd,
2932
genDocs(app),
3033
)
34+
app.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "show verbose output")
3135
return app
3236
}
3337

internal/cmd/resourcemanager.go

+78-48
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package cmd
33
import (
44
"fmt"
55
"os"
6+
"sort"
67
"text/tabwriter"
78

89
"cdr.dev/coder-cli/coder-sdk"
@@ -14,60 +15,81 @@ func makeResourceCmd() *cobra.Command {
1415
Use: "resources",
1516
Short: "manager Coder resources with platform-level context (users, organizations, environments)",
1617
}
17-
cmd.AddCommand(resourceTop)
18+
cmd.AddCommand(resourceTop())
1819
return cmd
1920
}
2021

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
6036
}
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)
6441
}
65-
fmt.Fprint(tabwriter, "\n")
66-
}
67-
_ = tabwriter.Flush()
6842

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
7193
}
7294

7395
func resourcesFromEnv(env coder.Environment) resources {
@@ -104,3 +126,11 @@ type resources struct {
104126
func (a resources) String() string {
105127
return fmt.Sprintf("[cpu: alloc=%.1fvCPU, util=%.1f]\t[mem: alloc=%.1fGB, util=%.1f]", a.cpuAllocation, a.cpuUtilization, a.memAllocation, a.memUtilization)
106128
}
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

Comments
 (0)