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

Commit 166ed14

Browse files
committed
Initial prototype of resources command
1 parent b7cd44f commit 166ed14

File tree

4 files changed

+142
-2
lines changed

4 files changed

+142
-2
lines changed

coder-sdk/env.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ type Environment struct {
2121
UserID string `json:"user_id" tab:"-"`
2222
LastBuiltAt time.Time `json:"last_built_at" tab:"-"`
2323
CPUCores float32 `json:"cpu_cores" tab:"CPUCores"`
24-
MemoryGB int `json:"memory_gb" tab:"MemoryGB"`
24+
MemoryGB float32 `json:"memory_gb" tab:"MemoryGB"`
2525
DiskGB int `json:"disk_gb" tab:"DiskGB"`
2626
GPUs int `json:"gpus" tab:"GPUs"`
2727
Updating bool `json:"updating" tab:"Updating"`
@@ -93,6 +93,16 @@ func (c Client) CreateEnvironment(ctx context.Context, orgID string, req CreateE
9393
return &env, nil
9494
}
9595

96+
// ListEnvironments lists environments returned by the given filter.
97+
// TODO: add the filter options
98+
func (c Client) ListEnvironments(ctx context.Context) ([]Environment, error) {
99+
var envs []Environment
100+
if err := c.requestBody(ctx, http.MethodGet, "/api/environments", nil, &envs); err != nil {
101+
return nil, err
102+
}
103+
return envs, nil
104+
}
105+
96106
// EnvironmentsByOrganization gets the list of environments owned by the given user.
97107
func (c Client) EnvironmentsByOrganization(ctx context.Context, userID, orgID string) ([]Environment, error) {
98108
var envs []Environment

coder-sdk/org.go

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,30 @@ package coder
33
import (
44
"context"
55
"net/http"
6+
"time"
67
)
78

89
// Org describes an Organization in Coder
910
type Org struct {
1011
ID string `json:"id"`
1112
Name string `json:"name"`
12-
Members []User `json:"members"`
13+
Members []OrganizationUser `json:"members"`
1314
}
1415

16+
type OrganizationUser struct {
17+
User
18+
OrganizationRoles []Role `json:"organization_roles"`
19+
RolesUpdatedAt time.Time `json:"roles_updated_at"`
20+
}
21+
22+
type Role string
23+
24+
const (
25+
RoleOrgMember Role = "organization-member"
26+
RoleOrgAdmin Role = "organization-admin"
27+
RoleOrgManager Role = "organization-manager"
28+
)
29+
1530
// Orgs gets all Organizations
1631
func (c Client) Orgs(ctx context.Context) ([]Org, error) {
1732
var orgs []Org
@@ -20,3 +35,11 @@ func (c Client) Orgs(ctx context.Context) ([]Org, error) {
2035
}
2136
return orgs, nil
2237
}
38+
39+
func (c Client) OrgMembers(ctx context.Context, orgID string) ([]OrganizationUser, error) {
40+
var members []OrganizationUser
41+
if err := c.requestBody(ctx, http.MethodGet, "/api/orgs/"+orgID+"/members", nil, &members); err != nil {
42+
return nil, err
43+
}
44+
return members, nil
45+
}

internal/cmd/cmd.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ func Make() *cobra.Command {
2424
makeEnvsCommand(),
2525
makeSyncCmd(),
2626
makeURLCmd(),
27+
makeResourceCmd(),
2728
completionCmd,
2829
genDocs(app),
2930
)

internal/cmd/resourcemanager.go

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"text/tabwriter"
7+
8+
"cdr.dev/coder-cli/coder-sdk"
9+
"github.com/spf13/cobra"
10+
)
11+
12+
func makeResourceCmd() *cobra.Command {
13+
cmd := &cobra.Command{
14+
Use: "resources",
15+
Short: "manager Coder resources with platform-level context (users, organizations, environments)",
16+
}
17+
cmd.AddCommand(resourceTop)
18+
return cmd
19+
}
20+
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.Org)
47+
orglist, err := client.Orgs(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")
60+
}
61+
for _, env := range userEnvs[u.ID] {
62+
_, _ = fmt.Fprintf(tabwriter, "\t")
63+
_, _ = fmt.Fprintln(tabwriter, fmtEnvResources(env, orgs))
64+
}
65+
fmt.Fprint(tabwriter, "\n")
66+
}
67+
_ = tabwriter.Flush()
68+
69+
return nil
70+
},
71+
}
72+
73+
func resourcesFromEnv(env coder.Environment) resources {
74+
return resources{
75+
cpuAllocation: env.CPUCores,
76+
cpuUtilization: env.LatestStat.CPUUsage,
77+
memAllocation: env.MemoryGB,
78+
memUtilization: env.LatestStat.MemoryUsage,
79+
}
80+
}
81+
82+
func fmtEnvResources(env coder.Environment, orgs map[string]coder.Org) string {
83+
return fmt.Sprintf("%s\t%s\t[org: %s]", env.Name, resourcesFromEnv(env), orgs[env.OrganizationID].Name)
84+
}
85+
86+
func aggregateEnvResources(envs []coder.Environment) (resources) {
87+
var aggregate resources
88+
for _, e := range envs {
89+
aggregate.cpuAllocation += e.CPUCores
90+
aggregate.cpuUtilization += e.LatestStat.CPUUsage
91+
aggregate.memAllocation += e.MemoryGB
92+
aggregate.memUtilization += e.LatestStat.MemoryUsage
93+
}
94+
return aggregate
95+
}
96+
97+
type resources struct {
98+
cpuAllocation float32
99+
cpuUtilization float32
100+
memAllocation float32
101+
memUtilization float32
102+
}
103+
104+
func (a resources) String() string {
105+
return fmt.Sprintf("[cpu: alloc=%.1fvCPU, util=%.1f]\t[mem: alloc=%.1fGB, util=%.1f]", a.cpuAllocation, a.cpuUtilization, a.memAllocation, a.memUtilization)
106+
}

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