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

Initial prototype of resources command #137

Merged
merged 6 commits into from
Oct 18, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Hide resources command from docs
  • Loading branch information
cmoog committed Oct 18, 2020
commit af2ac67ec59c81b1eb880fff57a476946c65147d
5 changes: 3 additions & 2 deletions ci/steps/gendocs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,16 @@ echo "Generating docs..."
cd "$(dirname "$0")"
cd ../../

rm -rf ./docs
mkdir ./docs
go run ./cmd/coder gen-docs ./docs

# remove cobra footer from each file
for filename in ./docs/*.md; do
trimmed=$(head -n -1 "$filename")
echo "$trimmed" > $filename
echo "$trimmed" >$filename
done


if [[ ${CI-} && $(git ls-files --other --modified --exclude-standard) ]]; then
echo "Documentation needs generation:"
git -c color.ui=always status | grep --color=no '\e\[31m'
Expand Down
6 changes: 3 additions & 3 deletions coder-sdk/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,9 @@ func (c Client) CreateEnvironment(ctx context.Context, orgID string, req CreateE
return &env, nil
}

// ListEnvironments lists environments returned by the given filter.
// TODO: add the filter options
func (c Client) ListEnvironments(ctx context.Context) ([]Environment, error) {
// Environments lists environments returned by the given filter.
// TODO: add the filter options, explore performance issues
func (c Client) Environments(ctx context.Context) ([]Environment, error) {
var envs []Environment
if err := c.requestBody(ctx, http.MethodGet, "/api/environments", nil, &envs); err != nil {
return nil, err
Expand Down
1 change: 0 additions & 1 deletion docs/coder.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ coder provides a CLI for working with an existing Coder Enterprise installation
* [coder envs](coder_envs.md) - Interact with Coder environments
* [coder login](coder_login.md) - Authenticate this client for future operations
* [coder logout](coder_logout.md) - Remove local authentication credentials if any exist
* [coder resources](coder_resources.md) - manager Coder resources with platform-level context (users, organizations, environments)
* [coder secrets](coder_secrets.md) - Interact with Coder Secrets
* [coder sh](coder_sh.md) - Open a shell and execute commands in a Coder environment
* [coder sync](coder_sync.md) - Establish a one way directory sync to a Coder environment
Expand Down
24 changes: 0 additions & 24 deletions docs/coder_resources.md

This file was deleted.

27 changes: 0 additions & 27 deletions docs/coder_resources_top.md

This file was deleted.

78 changes: 43 additions & 35 deletions internal/cmd/resourcemanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,21 @@ package cmd

import (
"fmt"
"io"
"os"
"sort"
"text/tabwriter"

"cdr.dev/coder-cli/coder-sdk"
"github.com/spf13/cobra"
"golang.org/x/xerrors"
)

func makeResourceCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "resources",
Short: "manager Coder resources with platform-level context (users, organizations, environments)",
Use: "resources",
Short: "manager Coder resources with platform-level context (users, organizations, environments)",
Hidden: true,
}
cmd.AddCommand(resourceTop())
return cmd
Expand All @@ -24,15 +27,16 @@ func resourceTop() *cobra.Command {
Use: "top",
RunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()

client, err := newClient()
if err != nil {
return err
}

envs, err := client.ListEnvironments(ctx)
// NOTE: it's not worth parrallelizing these calls yet given that this specific endpoint
// takes about 20x times longer than the other two
envs, err := client.Environments(ctx)
if err != nil {
return err
return xerrors.Errorf("get environments %w", err)
}

userEnvs := make(map[string][]coder.Environment)
Expand All @@ -42,51 +46,55 @@ func resourceTop() *cobra.Command {

users, err := client.Users(ctx)
if err != nil {
return err
return xerrors.Errorf("get users: %w", err)
}

orgs := make(map[string]coder.Organization)
orgIDMap := make(map[string]coder.Organization)
orglist, err := client.Organizations(ctx)
if err != nil {
return err
return xerrors.Errorf("get organizations: %w", err)
}
for _, o := range orglist {
orgs[o.ID] = o
}

tabwriter := tabwriter.NewWriter(os.Stdout, 0, 0, 4, ' ', 0)
var userResources []aggregatedUser
for _, u := range users {
// truncate user names to ensure tabwriter doesn't push our entire table too far
u.Name = truncate(u.Name, 20, "...")
userResources = append(userResources, aggregatedUser{User: u, resources: aggregateEnvResources(userEnvs[u.ID])})
}
sort.Slice(userResources, func(i, j int) bool {
return userResources[i].cpuAllocation > userResources[j].cpuAllocation
})

for _, u := range userResources {
_, _ = fmt.Fprintf(tabwriter, "%s\t(%s)\t%s", u.Name, u.Email, u.resources)
if verbose {
if len(userEnvs[u.ID]) > 0 {
_, _ = fmt.Fprintf(tabwriter, "\f")
}
for _, env := range userEnvs[u.ID] {
_, _ = fmt.Fprintf(tabwriter, "\t")
_, _ = fmt.Fprintln(tabwriter, fmtEnvResources(env, orgs))
}
}
fmt.Fprint(tabwriter, "\n")
orgIDMap[o.ID] = o
}
_ = tabwriter.Flush()

printResourceTop(os.Stdout, users, orgIDMap, userEnvs)
return nil
},
}

return cmd
}

func printResourceTop(writer io.Writer, users []coder.User, orgIDMap map[string]coder.Organization, userEnvs map[string][]coder.Environment) {
tabwriter := tabwriter.NewWriter(writer, 0, 0, 4, ' ', 0)
defer func() { _ = tabwriter.Flush() }()

var userResources []aggregatedUser
for _, u := range users {
// truncate user names to ensure tabwriter doesn't push our entire table too far
u.Name = truncate(u.Name, 20, "...")
userResources = append(userResources, aggregatedUser{User: u, resources: aggregateEnvResources(userEnvs[u.ID])})
}
sort.Slice(userResources, func(i, j int) bool {
return userResources[i].cpuAllocation > userResources[j].cpuAllocation
})

for _, u := range userResources {
_, _ = fmt.Fprintf(tabwriter, "%s\t(%s)\t%s", u.Name, u.Email, u.resources)
if verbose {
if len(userEnvs[u.ID]) > 0 {
_, _ = fmt.Fprintf(tabwriter, "\f")
}
for _, env := range userEnvs[u.ID] {
_, _ = fmt.Fprintf(tabwriter, "\t")
_, _ = fmt.Fprintln(tabwriter, fmtEnvResources(env, orgIDMap))
}
}
_, _ = fmt.Fprint(tabwriter, "\n")
}
}

type aggregatedUser struct {
coder.User
resources
Expand Down