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

Commit 1f60e71

Browse files
committed
Add resource sorting by CPU allocation
1 parent d138de8 commit 1f60e71

File tree

2 files changed

+82
-48
lines changed

2 files changed

+82
-48
lines changed

internal/cmd/cmd.go

Lines changed: 4 additions & 0 deletions
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

Lines changed: 78 additions & 48 deletions
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy