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

Commit 902d17f

Browse files
committed
Abstract env resource grouping and label properly
1 parent b3e8ec9 commit 902d17f

File tree

1 file changed

+104
-23
lines changed

1 file changed

+104
-23
lines changed

internal/cmd/resourcemanager.go

Lines changed: 104 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ func makeResourceCmd() *cobra.Command {
2323
}
2424

2525
func resourceTop() *cobra.Command {
26+
var group string
2627
cmd := &cobra.Command{
2728
Use: "top",
2829
RunE: func(cmd *cobra.Command, args []string) error {
@@ -39,64 +40,124 @@ func resourceTop() *cobra.Command {
3940
return xerrors.Errorf("get environments %w", err)
4041
}
4142

42-
userEnvs := make(map[string][]coder.Environment)
43-
for _, e := range envs {
44-
userEnvs[e.UserID] = append(userEnvs[e.UserID], e)
45-
}
46-
4743
users, err := client.Users(ctx)
4844
if err != nil {
4945
return xerrors.Errorf("get users: %w", err)
5046
}
5147

52-
orgIDMap := make(map[string]coder.Organization)
53-
orglist, err := client.Organizations(ctx)
48+
orgs, err := client.Organizations(ctx)
5449
if err != nil {
5550
return xerrors.Errorf("get organizations: %w", err)
5651
}
57-
for _, o := range orglist {
58-
orgIDMap[o.ID] = o
52+
53+
var groups []groupable
54+
var labeler envLabeler
55+
switch group {
56+
case "user":
57+
userEnvs := make(map[string][]coder.Environment, len(users))
58+
for _, e := range envs {
59+
userEnvs[e.UserID] = append(userEnvs[e.UserID], e)
60+
}
61+
for _, u := range users {
62+
groups = append(groups, userGrouping{user: u, envs: userEnvs[u.ID]})
63+
}
64+
orgIDMap := make(map[string]coder.Organization)
65+
for _, o := range orgs {
66+
orgIDMap[o.ID] = o
67+
}
68+
labeler = orgLabeler{orgIDMap}
69+
case "org":
70+
orgEnvs := make(map[string][]coder.Environment, len(orgs))
71+
for _, e := range envs {
72+
orgEnvs[e.OrganizationID] = append(orgEnvs[e.OrganizationID], e)
73+
}
74+
for _, o := range orgs {
75+
groups = append(groups, orgGrouping{org: o, envs: orgEnvs[o.ID]})
76+
}
77+
userIDMap := make(map[string]coder.User)
78+
for _, u := range users {
79+
userIDMap[u.ID] = u
80+
}
81+
labeler = userLabeler{userIDMap}
82+
default:
83+
return xerrors.Errorf("unknown --group %q", group)
5984
}
6085

61-
printResourceTop(os.Stdout, users, orgIDMap, userEnvs)
86+
printResourceTop(os.Stdout, groups, labeler)
6287
return nil
6388
},
6489
}
90+
cmd.Flags().StringVar(&group, "group", "user", "the grouping parameter (user|org|all)")
6591

6692
return cmd
6793
}
6894

69-
func printResourceTop(writer io.Writer, users []coder.User, orgIDMap map[string]coder.Organization, userEnvs map[string][]coder.Environment) {
95+
// groupable specifies a structure capable of being an aggregation group of environments (user, org, all)
96+
type groupable interface {
97+
header() string
98+
environments() []coder.Environment
99+
}
100+
101+
type userGrouping struct {
102+
user coder.User
103+
envs []coder.Environment
104+
}
105+
106+
func (u userGrouping) environments() []coder.Environment {
107+
return u.envs
108+
}
109+
110+
func (u userGrouping) header() string {
111+
return fmt.Sprintf("%s\t(%s)", truncate(u.user.Name, 20, "..."), u.user.Email)
112+
}
113+
114+
type orgGrouping struct {
115+
org coder.Organization
116+
envs []coder.Environment
117+
}
118+
119+
func (o orgGrouping) environments() []coder.Environment {
120+
return o.envs
121+
}
122+
123+
func (o orgGrouping) header() string {
124+
plural := "s"
125+
if len(o.org.Members) < 2 {
126+
plural = ""
127+
}
128+
return fmt.Sprintf("%s\t(%v member%s)", truncate(o.org.Name, 20, "..."), len(o.org.Members), plural)
129+
}
130+
131+
func printResourceTop(writer io.Writer, groups []groupable, labeler envLabeler) {
70132
tabwriter := tabwriter.NewWriter(writer, 0, 0, 4, ' ', 0)
71133
defer func() { _ = tabwriter.Flush() }()
72134

73-
var userResources []aggregatedUser
74-
for _, u := range users {
135+
var userResources []aggregatedResources
136+
for _, group := range groups {
75137
// truncate user names to ensure tabwriter doesn't push our entire table too far
76-
u.Name = truncate(u.Name, 20, "...")
77-
userResources = append(userResources, aggregatedUser{User: u, resources: aggregateEnvResources(userEnvs[u.ID])})
138+
userResources = append(userResources, aggregatedResources{groupable: group, resources: aggregateEnvResources(group.environments())})
78139
}
79140
sort.Slice(userResources, func(i, j int) bool {
80141
return userResources[i].cpuAllocation > userResources[j].cpuAllocation
81142
})
82143

83144
for _, u := range userResources {
84-
_, _ = fmt.Fprintf(tabwriter, "%s\t(%s)\t%s", u.Name, u.Email, u.resources)
145+
_, _ = fmt.Fprintf(tabwriter, "%s\t%s", u.header(), u.resources)
85146
if verbose {
86-
if len(userEnvs[u.ID]) > 0 {
147+
if len(u.environments()) > 0 {
87148
_, _ = fmt.Fprintf(tabwriter, "\f")
88149
}
89-
for _, env := range userEnvs[u.ID] {
150+
for _, env := range u.environments() {
90151
_, _ = fmt.Fprintf(tabwriter, "\t")
91-
_, _ = fmt.Fprintln(tabwriter, fmtEnvResources(env, orgIDMap))
152+
_, _ = fmt.Fprintln(tabwriter, fmtEnvResources(env, labeler))
92153
}
93154
}
94155
_, _ = fmt.Fprint(tabwriter, "\n")
95156
}
96157
}
97158

98-
type aggregatedUser struct {
99-
coder.User
159+
type aggregatedResources struct {
160+
groupable
100161
resources
101162
}
102163

@@ -109,8 +170,28 @@ func resourcesFromEnv(env coder.Environment) resources {
109170
}
110171
}
111172

112-
func fmtEnvResources(env coder.Environment, orgs map[string]coder.Organization) string {
113-
return fmt.Sprintf("%s\t%s\t[org: %s]", env.Name, resourcesFromEnv(env), orgs[env.OrganizationID].Name)
173+
func fmtEnvResources(env coder.Environment, labeler envLabeler) string {
174+
return fmt.Sprintf("%s\t%s\t%s", env.Name, resourcesFromEnv(env), labeler.label(env))
175+
}
176+
177+
type envLabeler interface {
178+
label(coder.Environment) string
179+
}
180+
181+
type orgLabeler struct {
182+
orgMap map[string]coder.Organization
183+
}
184+
185+
func (o orgLabeler) label(e coder.Environment) string {
186+
return fmt.Sprintf("[org: %s]", o.orgMap[e.OrganizationID].Name)
187+
}
188+
189+
type userLabeler struct {
190+
userMap map[string]coder.User
191+
}
192+
193+
func (u userLabeler) label(e coder.Environment) string {
194+
return fmt.Sprintf("[user: %s]", u.userMap[e.UserID].Email)
114195
}
115196

116197
func aggregateEnvResources(envs []coder.Environment) resources {

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