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

feature: support filtering by workspace provider when listing environ… #282

Merged
merged 6 commits into from
Mar 11, 2021
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
suggested changes
  • Loading branch information
Faris Huskovic committed Mar 11, 2021
commit e1d8cb54c9f8b45429cfb2456a62cc6b113091e7
22 changes: 21 additions & 1 deletion internal/cmd/ceapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ func getUserOrgs(ctx context.Context, client coder.Client, email string) ([]code
return lookupUserOrgs(u, orgs), nil
}

func getEnvsByProvider(ctx context.Context, client coder.Client, wpName string) ([]coder.Environment, error) {
func getEnvsByProvider(ctx context.Context, client coder.Client, wpName, userEmail string) ([]coder.Environment, error) {
wp, err := coderutil.ProviderByName(ctx, client, wpName)
if err != nil {
return nil, err
Expand All @@ -214,5 +214,25 @@ func getEnvsByProvider(ctx context.Context, client coder.Client, wpName string)
if err != nil {
return nil, err
}

envs, err = filterEnvsByUser(ctx, client, userEmail, envs)
if err != nil {
return nil, err
}
return envs, nil
}

func filterEnvsByUser(ctx context.Context, client coder.Client, userEmail string, envs []coder.Environment) ([]coder.Environment, error) {
user, err := client.UserByEmail(ctx, userEmail)
if err != nil {
return nil, xerrors.Errorf("get user: %w", err)
}

var filteredEnvs []coder.Environment
for _, env := range envs {
if env.UserID == user.ID {
filteredEnvs = append(filteredEnvs, env)
}
}
return filteredEnvs, nil
}
2 changes: 1 addition & 1 deletion internal/cmd/envs.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ func lsEnvsCommand() *cobra.Command {
return err
}
if provider != "" {
envs, err = getEnvsByProvider(ctx, client, provider)
envs, err = getEnvsByProvider(ctx, client, provider, user)
if err != nil {
return err
}
Expand Down
42 changes: 41 additions & 1 deletion internal/cmd/resourcemanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ type resourceTopOptions struct {
user string
org string
sortBy string
provider string
showEmptyGroups bool
}

Expand All @@ -41,11 +42,13 @@ func resourceTop() *cobra.Command {
Example: `coder resources top --group org
coder resources top --group org --verbose --org DevOps
coder resources top --group user --verbose --user [email protected]
coder resources top --group provider --verbose --provider myprovider
coder resources top --sort-by memory --show-empty`,
}
cmd.Flags().StringVar(&options.group, "group", "user", "the grouping parameter (user|org)")
cmd.Flags().StringVar(&options.group, "group", "user", "the grouping parameter (user|org|provider)")
cmd.Flags().StringVar(&options.user, "user", "", "filter by a user email")
cmd.Flags().StringVar(&options.org, "org", "", "filter by the name of an organization")
cmd.Flags().StringVar(&options.provider, "provider", "", "filter by the name of a workspace provider")
cmd.Flags().StringVar(&options.sortBy, "sort-by", "cpu", "field to sort aggregate groups and environments by (cpu|memory)")
cmd.Flags().BoolVar(&options.showEmptyGroups, "show-empty", false, "show groups with zero active environments")

Expand Down Expand Up @@ -84,13 +87,20 @@ func runResourceTop(options *resourceTopOptions) func(cmd *cobra.Command, args [
return xerrors.Errorf("get organizations: %w", err)
}

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

var groups []groupable
var labeler envLabeler
switch options.group {
case "user":
groups, labeler = aggregateByUser(users, orgs, envs, *options)
case "org":
groups, labeler = aggregateByOrg(users, orgs, envs, *options)
case "provider":
groups, labeler = aggregateByProvider(providers.Kubernetes, orgs, envs, *options)
default:
return xerrors.Errorf("unknown --group %q", options.group)
}
Expand Down Expand Up @@ -143,6 +153,28 @@ func aggregateByOrg(users []coder.User, orgs []coder.Organization, envs []coder.
return groups, userLabeler{userIDMap}
}

func aggregateByProvider(providers []coder.KubernetesProvider, orgs []coder.Organization, envs []coder.Environment, options resourceTopOptions) ([]groupable, envLabeler) {
var groups []groupable
providerIDMap := make(map[string]coder.KubernetesProvider)
for _, p := range providers {
providerIDMap[p.ID] = p
}
providerEnvs := make(map[string][]coder.Environment, len(orgs))
for _, e := range envs {
if options.user != "" && providerIDMap[e.ResourcePoolID].Name != options.provider {
continue
}
providerEnvs[e.OrganizationID] = append(providerEnvs[e.OrganizationID], e)
}
for _, o := range orgs {
if options.org != "" && o.Name != options.org {
continue
}
groups = append(groups, orgGrouping{org: o, envs: providerEnvs[o.ID]})
}
return groups, providerLabeler{providerIDMap}
}

// groupable specifies a structure capable of being an aggregation group of environments (user, org, all).
type groupable interface {
header() string
Expand Down Expand Up @@ -287,6 +319,14 @@ func (u userLabeler) label(e coder.Environment) string {
return fmt.Sprintf("[user: %s]", u.userMap[e.UserID].Email)
}

type providerLabeler struct {
providerMap map[string]coder.KubernetesProvider
}

func (p providerLabeler) label(e coder.Environment) string {
return fmt.Sprintf("[provider %s]", p.providerMap[e.ResourcePoolID].Name)
}

func aggregateEnvResources(envs []coder.Environment) resources {
var aggregate resources
for _, e := range envs {
Expand Down