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

feat: add provider name and repo name to envs ls #286

Merged
merged 4 commits into from
Mar 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
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
4 changes: 2 additions & 2 deletions coder-sdk/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ type Environment struct {
CPUCores float32 `json:"cpu_cores" table:"CPUCores"`
MemoryGB float32 `json:"memory_gb" table:"MemoryGB"`
DiskGB int `json:"disk_gb" table:"DiskGB"`
GPUs int `json:"gpus" table:"GPUs"`
Updating bool `json:"updating" table:"Updating"`
GPUs int `json:"gpus" table:"-"`
Updating bool `json:"updating" table:"-"`
LatestStat EnvironmentStat `json:"latest_stat" table:"Status"`
RebuildMessages []RebuildMessage `json:"rebuild_messages" table:"-"`
CreatedAt time.Time `json:"created_at" table:"-"`
Expand Down
9 changes: 9 additions & 0 deletions coder-sdk/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,15 @@ func (c *DefaultClient) ImportImage(ctx context.Context, req ImportImageReq) (*I
return &img, nil
}

// ImageByID returns an image entity, fetched by its ID.
func (c *DefaultClient) ImageByID(ctx context.Context, id string) (*Image, error) {
var img Image
if err := c.requestBody(ctx, http.MethodGet, "/api/v0/images/"+id, nil, &img); err != nil {
return nil, err
}
return &img, nil
}

// OrganizationImages returns all of the images imported for orgID.
func (c *DefaultClient) OrganizationImages(ctx context.Context, orgID string) ([]Image, error) {
var (
Expand Down
3 changes: 3 additions & 0 deletions coder-sdk/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,9 @@ type Client interface {
// ImportImage creates a new image and optionally a new registry.
ImportImage(ctx context.Context, req ImportImageReq) (*Image, error)

// ImageByID returns an image entity, fetched by its ID.
ImageByID(ctx context.Context, id string) (*Image, error)

// OrganizationImages returns all of the images imported for orgID.
OrganizationImages(ctx context.Context, orgID string) ([]Image, error)

Expand Down
14 changes: 7 additions & 7 deletions coder-sdk/workspace_providers.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ type WorkspaceProviders struct {

// KubernetesProvider defines an entity capable of deploying and acting as an ingress for Coder environments.
type KubernetesProvider struct {
ID string `json:"id" table:"-"`
Name string `json:"name" table:"Name"`
Status WorkspaceProviderStatus `json:"status" table:"Status"`
BuiltIn bool `json:"built_in" table:"-"`
EnvproxyAccessURL string `json:"envproxy_access_url" validate:"required" table:"Access URL"`
DevurlHost string `json:"devurl_host" table:"Devurl Host"`
OrgWhitelist []string `json:"org_whitelist" table:"-"`
ID string `json:"id" table:"-"`
Name string `json:"name" table:"Name"`
Status WorkspaceProviderStatus `json:"status" table:"Status"`
BuiltIn bool `json:"built_in" table:"-"`
EnvproxyAccessURL string `json:"envproxy_access_url" table:"Access URL" validate:"required"`
DevurlHost string `json:"devurl_host" table:"Devurl Host"`
OrgWhitelist []string `json:"org_whitelist" table:"-"`
KubeProviderConfig `json:"config" table:"_"`
}

Expand Down
6 changes: 5 additions & 1 deletion internal/cmd/envs.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,11 @@ func lsEnvsCommand() *cobra.Command {

switch outputFmt {
case humanOutput:
err := tablewriter.WriteTable(cmd.OutOrStdout(), len(envs), func(i int) interface{} {
envs, err := coderutil.EnvsHumanTable(ctx, client, envs)
if err != nil {
return err
}
err = tablewriter.WriteTable(cmd.OutOrStdout(), len(envs), func(i int) interface{} {
return envs[i]
})
if err != nil {
Expand Down
87 changes: 87 additions & 0 deletions internal/coderutil/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@ package coderutil

import (
"context"
"fmt"
"net/url"
"sync"

"golang.org/x/xerrors"
"nhooyr.io/websocket"

"cdr.dev/coder-cli/coder-sdk"
"cdr.dev/coder-cli/pkg/clog"
)

// DialEnvWsep dials the executor endpoint using the https://github.com/cdr/wsep message protocol.
Expand Down Expand Up @@ -72,3 +75,87 @@ func DefaultWorkspaceProvider(ctx context.Context, c coder.Client) (*coder.Kuber
}
return nil, coder.ErrNotFound
}

// EnvTable defines an Environment-like structure with associated entities composed in a human
// readable form.
type EnvTable struct {
Name string `table:"Name"`
Image string `table:"Image"`
CPU float32 `table:"vCPU"`
MemoryGB float32 `table:"MemoryGB"`
DiskGB int `table:"DiskGB"`
Status string `table:"Status"`
Provider string `table:"Provider"`
CVM bool `table:"CVM"`
}

// EnvsHumanTable performs the composition of each Environment with its associated ProviderName and ImageRepo.
func EnvsHumanTable(ctx context.Context, client coder.Client, envs []coder.Environment) ([]EnvTable, error) {
imageMap, err := makeImageMap(ctx, client, envs)
if err != nil {
return nil, err
}

pooledEnvs := make([]EnvTable, 0, len(envs))
providers, err := client.WorkspaceProviders(ctx)
if err != nil {
return nil, err
}
providerMap := make(map[string]coder.KubernetesProvider, len(providers.Kubernetes))
for _, p := range providers.Kubernetes {
providerMap[p.ID] = p
}
for _, e := range envs {
envProvider, ok := providerMap[e.ResourcePoolID]
if !ok {
return nil, xerrors.Errorf("fetch env workspace provider: %w", coder.ErrNotFound)
}
pooledEnvs = append(pooledEnvs, EnvTable{
Name: e.Name,
Image: fmt.Sprintf("%s:%s", imageMap[e.ImageID].Repository, e.ImageTag),
CPU: e.CPUCores,
MemoryGB: e.MemoryGB,
DiskGB: e.DiskGB,
Status: string(e.LatestStat.ContainerStatus),
Provider: envProvider.Name,
CVM: e.UseContainerVM,
})
}
return pooledEnvs, nil
}

func makeImageMap(ctx context.Context, client coder.Client, envs []coder.Environment) (map[string]*coder.Image, error) {
var (
mu sync.Mutex
egroup = clog.LoggedErrGroup()
)
imageMap := make(map[string]*coder.Image)
for _, e := range envs {
// put all the image IDs into a map to remove duplicates
imageMap[e.ImageID] = nil
}
ids := make([]string, 0, len(imageMap))
for id := range imageMap {
// put the deduplicated back into a slice
// so we can write to the map while iterating
ids = append(ids, id)
}
for _, id := range ids {
id := id
egroup.Go(func() error {
img, err := client.ImageByID(ctx, id)
if err != nil {
return err
}
mu.Lock()
defer mu.Unlock()
imageMap[id] = img

return nil
})
}
if err := egroup.Wait(); err != nil {
return nil, err
}
return imageMap, nil
}