diff --git a/ci/integration/integration_test.go b/ci/integration/integration_test.go index f92d733e..8654965a 100644 --- a/ci/integration/integration_test.go +++ b/ci/integration/integration_test.go @@ -53,15 +53,15 @@ func TestCoderCLI(t *testing.T) { headlessLogin(ctx, t, c) - c.Run(ctx, "coder envs").Assert(t, + c.Run(ctx, "coder workspaces").Assert(t, tcli.Success(), ) - c.Run(ctx, "coder envs ls").Assert(t, + c.Run(ctx, "coder workspaces ls").Assert(t, tcli.Success(), ) - c.Run(ctx, "coder envs ls -o json").Assert(t, + c.Run(ctx, "coder workspaces ls -o json").Assert(t, tcli.Success(), ) @@ -93,7 +93,7 @@ func TestCoderCLI(t *testing.T) { tcli.Success(), ) - c.Run(ctx, "coder envs ls").Assert(t, + c.Run(ctx, "coder workspaces ls").Assert(t, tcli.Error(), ) diff --git a/ci/integration/ssh_test.go b/ci/integration/ssh_test.go index 6a084a0d..5844ca93 100644 --- a/ci/integration/ssh_test.go +++ b/ci/integration/ssh_test.go @@ -13,17 +13,17 @@ func TestSSH(t *testing.T) { run(t, "ssh-coder-cli-tests", func(t *testing.T, ctx context.Context, c *tcli.ContainerRunner) { headlessLogin(ctx, t, c) - // TODO remove this once we can create an environment if there aren't any - var envs []coder.Environment - c.Run(ctx, "coder envs ls --output json").Assert(t, + // TODO remove this once we can create a workspace if there aren't any + var workspaces []coder.Workspace + c.Run(ctx, "coder workspaces ls --output json").Assert(t, tcli.Success(), - tcli.StdoutJSONUnmarshal(&envs), + tcli.StdoutJSONUnmarshal(&workspaces), ) assert := tcli.Success() - // if we don't have any environments, "coder config-ssh" will fail - if len(envs) == 0 { + // if we don't have any workspaces, "coder config-ssh" will fail + if len(workspaces) == 0 { assert = tcli.Error() } c.Run(ctx, "coder config-ssh").Assert(t, diff --git a/ci/integration/statictokens_test.go b/ci/integration/statictokens_test.go index d38dcd99..b1de474c 100644 --- a/ci/integration/statictokens_test.go +++ b/ci/integration/statictokens_test.go @@ -35,15 +35,15 @@ func TestStaticAuth(t *testing.T) { // make requests with token environment variable authentication cmd := exec.CommandContext(ctx, "sh", "-c", - fmt.Sprintf("export CODER_URL=%s && export CODER_TOKEN=$(cat) && coder envs ls", os.Getenv("CODER_URL")), + fmt.Sprintf("export CODER_URL=%s && export CODER_TOKEN=$(cat) && coder workspaces ls", os.Getenv("CODER_URL")), ) cmd.Stdin = strings.NewReader(string(result.Stdout)) c.RunCmd(cmd).Assert(t, tcli.Success(), ) - // should error when the environment variabels aren't set - c.Run(ctx, "coder envs ls").Assert(t, + // should error when the environment variables aren't set + c.Run(ctx, "coder workspaces ls").Assert(t, tcli.Error(), ) }) diff --git a/coder-sdk/activity.go b/coder-sdk/activity.go index c885f619..6d564efb 100644 --- a/coder-sdk/activity.go +++ b/coder-sdk/activity.go @@ -6,15 +6,15 @@ import ( ) type activityRequest struct { - Source string `json:"source"` - EnvironmentID string `json:"environment_id"` + Source string `json:"source"` + WorkspaceID string `json:"workspace_id"` } // PushActivity pushes CLI activity to Coder. -func (c *DefaultClient) PushActivity(ctx context.Context, source, envID string) error { +func (c *DefaultClient) PushActivity(ctx context.Context, source, workspaceID string) error { resp, err := c.request(ctx, http.MethodPost, "/api/private/metrics/usage/push", activityRequest{ - Source: source, - EnvironmentID: envID, + Source: source, + WorkspaceID: workspaceID, }) if err != nil { return err diff --git a/coder-sdk/activity_test.go b/coder-sdk/activity_test.go index 807b04f9..ff3083a3 100644 --- a/coder-sdk/activity_test.go +++ b/coder-sdk/activity_test.go @@ -17,14 +17,14 @@ func TestPushActivity(t *testing.T) { t.Parallel() const source = "test" - const envID = "602d377a-e6b8d763cae7561885c5f1b2" + const workspaceID = "602d377a-e6b8d763cae7561885c5f1b2" server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, "PushActivity is a POST", http.MethodPost, r.Method) assert.Equal(t, "URL matches", "/api/private/metrics/usage/push", r.URL.Path) expected := map[string]interface{}{ - "source": source, - "environment_id": envID, + "source": source, + "workspace_id": workspaceID, } var request map[string]interface{} err := json.NewDecoder(r.Body).Decode(&request) @@ -46,6 +46,6 @@ func TestPushActivity(t *testing.T) { }) assert.Success(t, "failed to create coder.Client", err) - err = client.PushActivity(context.Background(), source, envID) + err = client.PushActivity(context.Background(), source, workspaceID) assert.Success(t, "expected successful response from PushActivity", err) } diff --git a/coder-sdk/devurl.go b/coder-sdk/devurl.go index 27a18366..af6cf64f 100644 --- a/coder-sdk/devurl.go +++ b/coder-sdk/devurl.go @@ -17,38 +17,38 @@ type DevURL struct { } type delDevURLRequest struct { - EnvID string `json:"environment_id"` - DevURLID string `json:"url_id"` + WorkspaceID string `json:"workspace_id"` + DevURLID string `json:"url_id"` } // DeleteDevURL deletes the specified devurl. -func (c *DefaultClient) DeleteDevURL(ctx context.Context, envID, urlID string) error { - reqURL := fmt.Sprintf("/api/v0/environments/%s/devurls/%s", envID, urlID) +func (c *DefaultClient) DeleteDevURL(ctx context.Context, workspaceID, urlID string) error { + reqURL := fmt.Sprintf("/api/v0/workspaces/%s/devurls/%s", workspaceID, urlID) return c.requestBody(ctx, http.MethodDelete, reqURL, delDevURLRequest{ - EnvID: envID, - DevURLID: urlID, + WorkspaceID: workspaceID, + DevURLID: urlID, }, nil) } // CreateDevURLReq defines the request parameters for creating a new DevURL. type CreateDevURLReq struct { - EnvID string `json:"environment_id"` - Port int `json:"port"` - Access string `json:"access"` - Name string `json:"name"` - Scheme string `json:"scheme"` + WorkspaceID string `json:"workspace_id"` + Port int `json:"port"` + Access string `json:"access"` + Name string `json:"name"` + Scheme string `json:"scheme"` } // CreateDevURL inserts a new dev URL for the authenticated user. -func (c *DefaultClient) CreateDevURL(ctx context.Context, envID string, req CreateDevURLReq) error { - return c.requestBody(ctx, http.MethodPost, "/api/v0/environments/"+envID+"/devurls", req, nil) +func (c *DefaultClient) CreateDevURL(ctx context.Context, workspaceID string, req CreateDevURLReq) error { + return c.requestBody(ctx, http.MethodPost, "/api/v0/workspaces/"+workspaceID+"/devurls", req, nil) } -// DevURLs fetches the Dev URLs for a given environment. -func (c *DefaultClient) DevURLs(ctx context.Context, envID string) ([]DevURL, error) { +// DevURLs fetches the Dev URLs for a given workspace. +func (c *DefaultClient) DevURLs(ctx context.Context, workspaceID string) ([]DevURL, error) { var devurls []DevURL - if err := c.requestBody(ctx, http.MethodGet, "/api/v0/environments/"+envID+"/devurls", nil, &devurls); err != nil { + if err := c.requestBody(ctx, http.MethodGet, "/api/v0/workspaces/"+workspaceID+"/devurls", nil, &devurls); err != nil { return nil, err } return devurls, nil @@ -58,6 +58,6 @@ func (c *DefaultClient) DevURLs(ctx context.Context, envID string) ([]DevURL, er type PutDevURLReq CreateDevURLReq // PutDevURL updates an existing devurl for the authenticated user. -func (c *DefaultClient) PutDevURL(ctx context.Context, envID, urlID string, req PutDevURLReq) error { - return c.requestBody(ctx, http.MethodPut, "/api/v0/environments/"+envID+"/devurls/"+urlID, req, nil) +func (c *DefaultClient) PutDevURL(ctx context.Context, workspaceID, urlID string, req PutDevURLReq) error { + return c.requestBody(ctx, http.MethodPut, "/api/v0/workspaces/"+workspaceID+"/devurls/"+urlID, req, nil) } diff --git a/coder-sdk/interface.go b/coder-sdk/interface.go index 42c34d2c..47ed28c3 100644 --- a/coder-sdk/interface.go +++ b/coder-sdk/interface.go @@ -12,7 +12,7 @@ import ( // This is an interface to allow for mocking of coder-sdk client usage. type Client interface { // PushActivity pushes CLI activity to Coder. - PushActivity(ctx context.Context, source, envID string) error + PushActivity(ctx context.Context, source, workspaceID string) error // Me gets the details of the authenticated user. Me(ctx context.Context) (*User, error) @@ -66,75 +66,75 @@ type Client interface { SiteConfigWorkspaces(ctx context.Context) (*ConfigWorkspaces, error) // DeleteDevURL deletes the specified devurl. - DeleteDevURL(ctx context.Context, envID, urlID string) error + DeleteDevURL(ctx context.Context, workspaceID, urlID string) error // CreateDevURL inserts a new devurl for the authenticated user. - CreateDevURL(ctx context.Context, envID string, req CreateDevURLReq) error + CreateDevURL(ctx context.Context, workspaceID string, req CreateDevURLReq) error - // DevURLs fetches the Dev URLs for a given environment. - DevURLs(ctx context.Context, envID string) ([]DevURL, error) + // DevURLs fetches the Dev URLs for a given workspace. + DevURLs(ctx context.Context, workspaceID string) ([]DevURL, error) // PutDevURL updates an existing devurl for the authenticated user. - PutDevURL(ctx context.Context, envID, urlID string, req PutDevURLReq) error + PutDevURL(ctx context.Context, workspaceID, urlID string, req PutDevURLReq) error - // CreateEnvironment sends a request to create an environment. - CreateEnvironment(ctx context.Context, req CreateEnvironmentRequest) (*Environment, error) + // CreateWorkspace sends a request to create a workspace. + CreateWorkspace(ctx context.Context, req CreateWorkspaceRequest) (*Workspace, error) // ParseTemplate parses a template config. It support both remote repositories and local files. // If a local file is specified then all other values in the request are ignored. ParseTemplate(ctx context.Context, req ParseTemplateRequest) (*TemplateVersion, error) - // CreateEnvironmentFromRepo sends a request to create an environment from a repository. - CreateEnvironmentFromRepo(ctx context.Context, orgID string, req TemplateVersion) (*Environment, error) + // CreateWorkspaceFromRepo sends a request to create a workspace from a repository. + CreateWorkspaceFromRepo(ctx context.Context, orgID string, req TemplateVersion) (*Workspace, error) - // Environments lists environments returned by the given filter. - Environments(ctx context.Context) ([]Environment, error) + // Workspaces lists workspaces returned by the given filter. + Workspaces(ctx context.Context) ([]Workspace, error) - // UserEnvironmentsByOrganization gets the list of environments owned by the given user. - UserEnvironmentsByOrganization(ctx context.Context, userID, orgID string) ([]Environment, error) + // UserWorkspacesByOrganization gets the list of workspaces owned by the given user. + UserWorkspacesByOrganization(ctx context.Context, userID, orgID string) ([]Workspace, error) - // DeleteEnvironment deletes the environment. - DeleteEnvironment(ctx context.Context, envID string) error + // DeleteWorkspace deletes the workspace. + DeleteWorkspace(ctx context.Context, workspaceID string) error - // StopEnvironment stops the environment. - StopEnvironment(ctx context.Context, envID string) error + // StopWorkspace stops the workspace. + StopWorkspace(ctx context.Context, workspaceID string) error - // RebuildEnvironment requests that the given envID is rebuilt with no changes to its specification. - RebuildEnvironment(ctx context.Context, envID string) error + // RebuildWorkspace requests that the given workspaceID is rebuilt with no changes to its specification. + RebuildWorkspace(ctx context.Context, workspaceID string) error - // EditEnvironment modifies the environment specification and initiates a rebuild. - EditEnvironment(ctx context.Context, envID string, req UpdateEnvironmentReq) error + // EditWorkspace modifies the workspace specification and initiates a rebuild. + EditWorkspace(ctx context.Context, workspaceID string, req UpdateWorkspaceReq) error - // DialWsep dials an environments command execution interface + // DialWsep dials a workspace's command execution interface // See https://github.com/cdr/wsep for details. - DialWsep(ctx context.Context, baseURL *url.URL, envID string) (*websocket.Conn, error) + DialWsep(ctx context.Context, baseURL *url.URL, workspaceID string) (*websocket.Conn, error) - // DialExecutor gives a remote execution interface for performing commands inside an environment. - DialExecutor(ctx context.Context, baseURL *url.URL, envID string) (wsep.Execer, error) + // DialExecutor gives a remote execution interface for performing commands inside a workspace. + DialExecutor(ctx context.Context, baseURL *url.URL, workspaceID string) (wsep.Execer, error) - // DialIDEStatus opens a websocket connection for cpu load metrics on the environment. - DialIDEStatus(ctx context.Context, baseURL *url.URL, envID string) (*websocket.Conn, error) + // DialIDEStatus opens a websocket connection for cpu load metrics on the workspace. + DialIDEStatus(ctx context.Context, baseURL *url.URL, workspaceID string) (*websocket.Conn, error) - // DialEnvironmentBuildLog opens a websocket connection for the environment build log messages. - DialEnvironmentBuildLog(ctx context.Context, envID string) (*websocket.Conn, error) + // DialWorkspaceBuildLog opens a websocket connection for the workspace build log messages. + DialWorkspaceBuildLog(ctx context.Context, workspaceID string) (*websocket.Conn, error) - // FollowEnvironmentBuildLog trails the build log of a Coder environment. - FollowEnvironmentBuildLog(ctx context.Context, envID string) (<-chan BuildLogFollowMsg, error) + // FollowWorkspaceBuildLog trails the build log of a Coder workspace. + FollowWorkspaceBuildLog(ctx context.Context, workspaceID string) (<-chan BuildLogFollowMsg, error) - // DialEnvironmentStats opens a websocket connection for environment stats. - DialEnvironmentStats(ctx context.Context, envID string) (*websocket.Conn, error) + // DialWorkspaceStats opens a websocket connection for workspace stats. + DialWorkspaceStats(ctx context.Context, workspaceID string) (*websocket.Conn, error) - // DialResourceLoad opens a websocket connection for cpu load metrics on the environment. - DialResourceLoad(ctx context.Context, envID string) (*websocket.Conn, error) + // DialResourceLoad opens a websocket connection for cpu load metrics on the workspace. + DialResourceLoad(ctx context.Context, workspaceID string) (*websocket.Conn, error) - // WaitForEnvironmentReady will watch the build log and return when done. - WaitForEnvironmentReady(ctx context.Context, envID string) error + // WaitForWorkspaceReady will watch the build log and return when done. + WaitForWorkspaceReady(ctx context.Context, workspaceID string) error - // EnvironmentByID get the details of an environment by its id. - EnvironmentByID(ctx context.Context, id string) (*Environment, error) + // WorkspaceByID get the details of a workspace by its id. + WorkspaceByID(ctx context.Context, id string) (*Workspace, error) - // EnvironmentsByWorkspaceProvider returns environments that belong to a particular workspace provider. - EnvironmentsByWorkspaceProvider(ctx context.Context, wpID string) ([]Environment, error) + // WorkspacesByWorkspaceProvider returns workspaces that belong to a particular workspace provider. + WorkspacesByWorkspaceProvider(ctx context.Context, wpID string) ([]Workspace, error) // ImportImage creates a new image and optionally a new registry. ImportImage(ctx context.Context, req ImportImageReq) (*Image, error) diff --git a/coder-sdk/org.go b/coder-sdk/org.go index 92718dcd..0922d229 100644 --- a/coder-sdk/org.go +++ b/coder-sdk/org.go @@ -13,7 +13,7 @@ type Organization struct { Description string `json:"description"` Default bool `json:"default"` Members []OrganizationUser `json:"members"` - EnvironmentCount int `json:"environment_count"` + WorkspaceCount int `json:"workspace_count"` ResourceNamespace string `json:"resource_namespace"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` diff --git a/coder-sdk/tags.go b/coder-sdk/tags.go index 7e4563a9..9a3c941f 100644 --- a/coder-sdk/tags.go +++ b/coder-sdk/tags.go @@ -8,14 +8,14 @@ import ( // ImageTag is a Docker image tag. type ImageTag struct { - ImageID string `json:"image_id" table:"-"` - Tag string `json:"tag" table:"Tag"` - LatestHash string `json:"latest_hash" table:"-"` - HashLastUpdatedAt time.Time `json:"hash_last_updated_at" table:"-"` - OSRelease *OSRelease `json:"os_release" table:"OS"` - Environments []*Environment `json:"environments" table:"-"` - UpdatedAt time.Time `json:"updated_at" table:"UpdatedAt"` - CreatedAt time.Time `json:"created_at" table:"-"` + ImageID string `json:"image_id" table:"-"` + Tag string `json:"tag" table:"Tag"` + LatestHash string `json:"latest_hash" table:"-"` + HashLastUpdatedAt time.Time `json:"hash_last_updated_at" table:"-"` + OSRelease *OSRelease `json:"os_release" table:"OS"` + Workspaces []*Workspace `json:"workspaces" table:"-"` + UpdatedAt time.Time `json:"updated_at" table:"UpdatedAt"` + CreatedAt time.Time `json:"created_at" table:"-"` } func (i ImageTag) String() string { diff --git a/coder-sdk/env.go b/coder-sdk/workspace.go similarity index 52% rename from coder-sdk/env.go rename to coder-sdk/workspace.go index e807b219..fca61dcd 100644 --- a/coder-sdk/env.go +++ b/coder-sdk/workspace.go @@ -13,8 +13,8 @@ import ( "nhooyr.io/websocket/wsjson" ) -// Environment describes a Coder environment. -type Environment struct { +// Workspace describes a Coder workspace. +type Workspace struct { ID string `json:"id" table:"-"` Name string `json:"name" table:"Name"` ImageID string `json:"image_id" table:"-"` @@ -27,7 +27,7 @@ type Environment struct { DiskGB int `json:"disk_gb" table:"DiskGB"` GPUs int `json:"gpus" table:"-"` Updating bool `json:"updating" table:"-"` - LatestStat EnvironmentStat `json:"latest_stat" table:"Status"` + LatestStat WorkspaceStat `json:"latest_stat" table:"Status"` RebuildMessages []RebuildMessage `json:"rebuild_messages" table:"-"` CreatedAt time.Time `json:"created_at" table:"-"` UpdatedAt time.Time `json:"updated_at" table:"-"` @@ -38,42 +38,42 @@ type Environment struct { ResourcePoolID string `json:"resource_pool_id" table:"-"` } -// RebuildMessage defines the message shown when an Environment requires a rebuild for it can be accessed. +// RebuildMessage defines the message shown when a Workspace requires a rebuild for it can be accessed. type RebuildMessage struct { Text string `json:"text"` Required bool `json:"required"` AutoOffThreshold Duration `json:"auto_off_threshold"` } -// EnvironmentStat represents the state of an environment. -type EnvironmentStat struct { - Time time.Time `json:"time"` - LastOnline time.Time `json:"last_online"` - ContainerStatus EnvironmentStatus `json:"container_status"` - StatError string `json:"stat_error"` - CPUUsage float32 `json:"cpu_usage"` - MemoryTotal int64 `json:"memory_total"` - MemoryUsage float32 `json:"memory_usage"` - DiskTotal int64 `json:"disk_total"` - DiskUsed int64 `json:"disk_used"` +// WorkspaceStat represents the state of a workspace. +type WorkspaceStat struct { + Time time.Time `json:"time"` + LastOnline time.Time `json:"last_online"` + ContainerStatus WorkspaceStatus `json:"container_status"` + StatError string `json:"stat_error"` + CPUUsage float32 `json:"cpu_usage"` + MemoryTotal int64 `json:"memory_total"` + MemoryUsage float32 `json:"memory_usage"` + DiskTotal int64 `json:"disk_total"` + DiskUsed int64 `json:"disk_used"` } -func (e EnvironmentStat) String() string { return string(e.ContainerStatus) } +func (e WorkspaceStat) String() string { return string(e.ContainerStatus) } -// EnvironmentStatus refers to the states of an environment. -type EnvironmentStatus string +// WorkspaceStatus refers to the states of a workspace. +type WorkspaceStatus string -// The following represent the possible environment container states. +// The following represent the possible workspace container states. const ( - EnvironmentCreating EnvironmentStatus = "CREATING" - EnvironmentOff EnvironmentStatus = "OFF" - EnvironmentOn EnvironmentStatus = "ON" - EnvironmentFailed EnvironmentStatus = "FAILED" - EnvironmentUnknown EnvironmentStatus = "UNKNOWN" + WorkspaceCreating WorkspaceStatus = "CREATING" + WorkspaceOff WorkspaceStatus = "OFF" + WorkspaceOn WorkspaceStatus = "ON" + WorkspaceFailed WorkspaceStatus = "FAILED" + WorkspaceUnknown WorkspaceStatus = "UNKNOWN" ) -// CreateEnvironmentRequest is used to configure a new environment. -type CreateEnvironmentRequest struct { +// CreateWorkspaceRequest is used to configure a new workspace. +type CreateWorkspaceRequest struct { Name string `json:"name"` ImageID string `json:"image_id"` OrgID string `json:"org_id"` @@ -91,13 +91,13 @@ type CreateEnvironmentRequest struct { TemplateID string `json:"template_id,omitempty"` } -// CreateEnvironment sends a request to create an environment. -func (c *DefaultClient) CreateEnvironment(ctx context.Context, req CreateEnvironmentRequest) (*Environment, error) { - var env Environment - if err := c.requestBody(ctx, http.MethodPost, "/api/v0/environments", req, &env); err != nil { +// CreateWorkspace sends a request to create a workspace. +func (c *DefaultClient) CreateWorkspace(ctx context.Context, req CreateWorkspaceRequest) (*Workspace, error) { + var workspace Workspace + if err := c.requestBody(ctx, http.MethodPost, "/api/v0/workspaces", req, &workspace); err != nil { return nil, err } - return &env, nil + return &workspace, nil } // ParseTemplateRequest parses a template. If Local is a non-nil reader @@ -112,7 +112,7 @@ type ParseTemplateRequest struct { // TemplateVersion is a Workspaces As Code (WAC) template. // For now, let's not interpret it on the CLI level. We just need -// to forward this as part of the create env request. +// to forward this as part of the create workspace request. type TemplateVersion struct { ID string `json:"id"` TemplateID string `json:"template_id"` @@ -127,7 +127,7 @@ type TemplateVersion struct { // ParseTemplate parses a template config. It support both remote repositories and local files. // If a local file is specified then all other values in the request are ignored. func (c *DefaultClient) ParseTemplate(ctx context.Context, req ParseTemplateRequest) (*TemplateVersion, error) { - const path = "/api/private/environments/template/parse" + const path = "/api/private/workspaces/template/parse" var ( tpl TemplateVersion opts []requestOption @@ -157,54 +157,54 @@ func (c *DefaultClient) ParseTemplate(ctx context.Context, req ParseTemplateRequ return &tpl, nil } -// CreateEnvironmentFromRepo sends a request to create an environment from a repository. -func (c *DefaultClient) CreateEnvironmentFromRepo(ctx context.Context, orgID string, req TemplateVersion) (*Environment, error) { - var env Environment - if err := c.requestBody(ctx, http.MethodPost, "/api/private/orgs/"+orgID+"/environments/from-repo", req, &env); err != nil { +// CreateWorkspaceFromRepo sends a request to create a workspace from a repository. +func (c *DefaultClient) CreateWorkspaceFromRepo(ctx context.Context, orgID string, req TemplateVersion) (*Workspace, error) { + var workspace Workspace + if err := c.requestBody(ctx, http.MethodPost, "/api/private/orgs/"+orgID+"/workspaces/from-repo", req, &workspace); err != nil { return nil, err } - return &env, nil + return &workspace, nil } -// Environments lists environments returned by the given filter. +// Workspaces lists workspaces returned by the given filter. // TODO: add the filter options, explore performance issue. -func (c *DefaultClient) Environments(ctx context.Context) ([]Environment, error) { - var envs []Environment - if err := c.requestBody(ctx, http.MethodGet, "/api/v0/environments", nil, &envs); err != nil { +func (c *DefaultClient) Workspaces(ctx context.Context) ([]Workspace, error) { + var workspaces []Workspace + if err := c.requestBody(ctx, http.MethodGet, "/api/v0/workspaces", nil, &workspaces); err != nil { return nil, err } - return envs, nil + return workspaces, nil } -// UserEnvironmentsByOrganization gets the list of environments owned by the given user. -func (c *DefaultClient) UserEnvironmentsByOrganization(ctx context.Context, userID, orgID string) ([]Environment, error) { +// UserWorkspacesByOrganization gets the list of workspaces owned by the given user. +func (c *DefaultClient) UserWorkspacesByOrganization(ctx context.Context, userID, orgID string) ([]Workspace, error) { var ( - envs []Environment - query = url.Values{} + workspaces []Workspace + query = url.Values{} ) query.Add("orgs", orgID) query.Add("users", userID) - if err := c.requestBody(ctx, http.MethodGet, "/api/v0/environments", nil, &envs, withQueryParams(query)); err != nil { + if err := c.requestBody(ctx, http.MethodGet, "/api/v0/workspaces", nil, &workspaces, withQueryParams(query)); err != nil { return nil, err } - return envs, nil + return workspaces, nil } -// DeleteEnvironment deletes the environment. -func (c *DefaultClient) DeleteEnvironment(ctx context.Context, envID string) error { - return c.requestBody(ctx, http.MethodDelete, "/api/v0/environments/"+envID, nil, nil) +// DeleteWorkspace deletes the workspace. +func (c *DefaultClient) DeleteWorkspace(ctx context.Context, workspaceID string) error { + return c.requestBody(ctx, http.MethodDelete, "/api/v0/workspaces/"+workspaceID, nil, nil) } -// StopEnvironment stops the environment. -func (c *DefaultClient) StopEnvironment(ctx context.Context, envID string) error { - return c.requestBody(ctx, http.MethodPut, "/api/v0/environments/"+envID+"/stop", nil, nil) +// StopWorkspace stops the workspace. +func (c *DefaultClient) StopWorkspace(ctx context.Context, workspaceID string) error { + return c.requestBody(ctx, http.MethodPut, "/api/v0/workspaces/"+workspaceID+"/stop", nil, nil) } -// UpdateEnvironmentReq defines the update operation, only setting +// UpdateWorkspaceReq defines the update operation, only setting // nil-fields. -type UpdateEnvironmentReq struct { +type UpdateWorkspaceReq struct { ImageID *string `json:"image_id"` ImageTag *string `json:"image_tag"` CPUCores *float32 `json:"cpu_cores"` @@ -213,45 +213,46 @@ type UpdateEnvironmentReq struct { GPUs *int `json:"gpus"` } -// RebuildEnvironment requests that the given envID is rebuilt with no changes to its specification. -func (c *DefaultClient) RebuildEnvironment(ctx context.Context, envID string) error { - return c.requestBody(ctx, http.MethodPatch, "/api/v0/environments/"+envID, UpdateEnvironmentReq{}, nil) +// RebuildWorkspace requests that the given workspaceID is rebuilt with no changes to its specification. +func (c *DefaultClient) RebuildWorkspace(ctx context.Context, workspaceID string) error { + return c.requestBody(ctx, http.MethodPatch, "/api/v0/workspaces/"+workspaceID, UpdateWorkspaceReq{}, nil) } -// EditEnvironment modifies the environment specification and initiates a rebuild. -func (c *DefaultClient) EditEnvironment(ctx context.Context, envID string, req UpdateEnvironmentReq) error { - return c.requestBody(ctx, http.MethodPatch, "/api/v0/environments/"+envID, req, nil) +// EditWorkspace modifies the workspace specification and initiates a rebuild. +func (c *DefaultClient) EditWorkspace(ctx context.Context, workspaceID string, req UpdateWorkspaceReq) error { + return c.requestBody(ctx, http.MethodPatch, "/api/v0/workspaces/"+workspaceID, req, nil) } -// DialWsep dials an environments command execution interface +// DialWsep dials a workspace's command execution interface // See https://github.com/cdr/wsep for details. -func (c *DefaultClient) DialWsep(ctx context.Context, baseURL *url.URL, envID string) (*websocket.Conn, error) { - return c.dialWebsocket(ctx, "/proxy/environments/"+envID+"/wsep", withBaseURL(baseURL)) +func (c *DefaultClient) DialWsep(ctx context.Context, baseURL *url.URL, workspaceID string) (*websocket.Conn, error) { + return c.dialWebsocket(ctx, "/proxy/workspaces/"+workspaceID+"/wsep", withBaseURL(baseURL)) } -// DialExecutor gives a remote execution interface for performing commands inside an environment. -func (c *DefaultClient) DialExecutor(ctx context.Context, baseURL *url.URL, envID string) (wsep.Execer, error) { - ws, err := c.DialWsep(ctx, baseURL, envID) +// DialExecutor gives a remote execution interface for performing commands +// inside a workspace. +func (c *DefaultClient) DialExecutor(ctx context.Context, baseURL *url.URL, workspaceID string) (wsep.Execer, error) { + ws, err := c.DialWsep(ctx, baseURL, workspaceID) if err != nil { return nil, err } return wsep.RemoteExecer(ws), nil } -// DialIDEStatus opens a websocket connection for cpu load metrics on the environment. -func (c *DefaultClient) DialIDEStatus(ctx context.Context, baseURL *url.URL, envID string) (*websocket.Conn, error) { - return c.dialWebsocket(ctx, "/proxy/environments/"+envID+"/ide/api/status", withBaseURL(baseURL)) +// DialIDEStatus opens a websocket connection for cpu load metrics on the workspace. +func (c *DefaultClient) DialIDEStatus(ctx context.Context, baseURL *url.URL, workspaceID string) (*websocket.Conn, error) { + return c.dialWebsocket(ctx, "/proxy/workspaces/"+workspaceID+"/ide/api/status", withBaseURL(baseURL)) } -// DialEnvironmentBuildLog opens a websocket connection for the environment build log messages. -func (c *DefaultClient) DialEnvironmentBuildLog(ctx context.Context, envID string) (*websocket.Conn, error) { - return c.dialWebsocket(ctx, "/api/private/environments/"+envID+"/watch-update") +// DialWorkspaceBuildLog opens a websocket connection for the workspace build log messages. +func (c *DefaultClient) DialWorkspaceBuildLog(ctx context.Context, workspaceID string) (*websocket.Conn, error) { + return c.dialWebsocket(ctx, "/api/private/workspaces/"+workspaceID+"/watch-update") } -// BuildLog defines a build log record for a Coder environment. +// BuildLog defines a build log record for a Coder workspace. type BuildLog struct { - ID string `db:"id" json:"id"` - EnvironmentID string `db:"environment_id" json:"environment_id"` + ID string `db:"id" json:"id"` + WorkspaceID string `db:"workspace_id" json:"workspace_id"` // BuildID allows the frontend to separate the logs from the old build with the logs from the new. BuildID string `db:"build_id" json:"build_id"` Time time.Time `db:"time" json:"time"` @@ -266,10 +267,10 @@ type BuildLogFollowMsg struct { Err error } -// FollowEnvironmentBuildLog trails the build log of a Coder environment. -func (c *DefaultClient) FollowEnvironmentBuildLog(ctx context.Context, envID string) (<-chan BuildLogFollowMsg, error) { +// FollowWorkspaceBuildLog trails the build log of a Coder workspace. +func (c *DefaultClient) FollowWorkspaceBuildLog(ctx context.Context, workspaceID string) (<-chan BuildLogFollowMsg, error) { ch := make(chan BuildLogFollowMsg) - ws, err := c.DialEnvironmentBuildLog(ctx, envID) + ws, err := c.DialWorkspaceBuildLog(ctx, workspaceID) if err != nil { return nil, err } @@ -291,14 +292,14 @@ func (c *DefaultClient) FollowEnvironmentBuildLog(ctx context.Context, envID str return ch, nil } -// DialEnvironmentStats opens a websocket connection for environment stats. -func (c *DefaultClient) DialEnvironmentStats(ctx context.Context, envID string) (*websocket.Conn, error) { - return c.dialWebsocket(ctx, "/api/private/environments/"+envID+"/watch-stats") +// DialWorkspaceStats opens a websocket connection for workspace stats. +func (c *DefaultClient) DialWorkspaceStats(ctx context.Context, workspaceID string) (*websocket.Conn, error) { + return c.dialWebsocket(ctx, "/api/private/workspaces/"+workspaceID+"/watch-stats") } -// DialResourceLoad opens a websocket connection for cpu load metrics on the environment. -func (c *DefaultClient) DialResourceLoad(ctx context.Context, envID string) (*websocket.Conn, error) { - return c.dialWebsocket(ctx, "/api/private/environments/"+envID+"/watch-resource-load") +// DialResourceLoad opens a websocket connection for cpu load metrics on the workspace. +func (c *DefaultClient) DialResourceLoad(ctx context.Context, workspaceID string) (*websocket.Conn, error) { + return c.dialWebsocket(ctx, "/api/private/workspaces/"+workspaceID+"/watch-resource-load") } // BuildLogType describes the type of an event. @@ -307,8 +308,8 @@ type BuildLogType string const ( // BuildLogTypeStart signals that a new build log has begun. BuildLogTypeStart BuildLogType = "start" - // BuildLogTypeStage is a stage-level event for an environment. - // It can be thought of as a major step in the environment's + // BuildLogTypeStage is a stage-level event for a workspace. + // It can be thought of as a major step in the workspace's // lifecycle. BuildLogTypeStage BuildLogType = "stage" // BuildLogTypeError describes an error that has occurred. @@ -325,18 +326,18 @@ type buildLogMsg struct { Type BuildLogType `json:"type"` } -// WaitForEnvironmentReady will watch the build log and return when done. -func (c *DefaultClient) WaitForEnvironmentReady(ctx context.Context, envID string) error { - conn, err := c.DialEnvironmentBuildLog(ctx, envID) +// WaitForWorkspaceReady will watch the build log and return when done. +func (c *DefaultClient) WaitForWorkspaceReady(ctx context.Context, workspaceID string) error { + conn, err := c.DialWorkspaceBuildLog(ctx, workspaceID) if err != nil { - return xerrors.Errorf("%s: dial build log: %w", envID, err) + return xerrors.Errorf("%s: dial build log: %w", workspaceID, err) } for { msg := buildLogMsg{} err := wsjson.Read(ctx, conn, &msg) if err != nil { - return xerrors.Errorf("%s: reading build log msg: %w", envID, err) + return xerrors.Errorf("%s: reading build log msg: %w", workspaceID, err) } if msg.Type == BuildLogTypeDone { @@ -345,20 +346,20 @@ func (c *DefaultClient) WaitForEnvironmentReady(ctx context.Context, envID strin } } -// EnvironmentByID get the details of an environment by its id. -func (c *DefaultClient) EnvironmentByID(ctx context.Context, id string) (*Environment, error) { - var env Environment - if err := c.requestBody(ctx, http.MethodGet, "/api/v0/environments/"+id, nil, &env); err != nil { +// WorkspaceByID get the details of a workspace by its id. +func (c *DefaultClient) WorkspaceByID(ctx context.Context, id string) (*Workspace, error) { + var workspace Workspace + if err := c.requestBody(ctx, http.MethodGet, "/api/v0/workspaces/"+id, nil, &workspace); err != nil { return nil, err } - return &env, nil + return &workspace, nil } -// EnvironmentsByWorkspaceProvider returns all environments that belong to a particular workspace provider. -func (c *DefaultClient) EnvironmentsByWorkspaceProvider(ctx context.Context, wpID string) ([]Environment, error) { - var envs []Environment - if err := c.requestBody(ctx, http.MethodGet, "/api/private/resource-pools/"+wpID+"/environments", nil, &envs); err != nil { +// WorkspacesByWorkspaceProvider returns all workspaces that belong to a particular workspace provider. +func (c *DefaultClient) WorkspacesByWorkspaceProvider(ctx context.Context, wpID string) ([]Workspace, error) { + var workspaces []Workspace + if err := c.requestBody(ctx, http.MethodGet, "/api/private/resource-pools/"+wpID+"/workspaces", nil, &workspaces); err != nil { return nil, err } - return envs, nil + return workspaces, nil } diff --git a/coder-sdk/workspace_providers.go b/coder-sdk/workspace_providers.go index 28710867..1ed0589c 100644 --- a/coder-sdk/workspace_providers.go +++ b/coder-sdk/workspace_providers.go @@ -10,7 +10,7 @@ type WorkspaceProviders struct { Kubernetes []KubernetesProvider `json:"kubernetes"` } -// KubernetesProvider defines an entity capable of deploying and acting as an ingress for Coder environments. +// KubernetesProvider defines an entity capable of deploying and acting as an ingress for Coder workspaces. type KubernetesProvider struct { ID string `json:"id" table:"-"` Name string `json:"name" table:"Name"` diff --git a/docs/coder.md b/docs/coder.md index bd37b0bd..ab6254e8 100644 --- a/docs/coder.md +++ b/docs/coder.md @@ -12,14 +12,14 @@ coder provides a CLI for working with an existing Coder installation ### SEE ALSO * [coder completion](coder_completion.md) - Generate completion script -* [coder config-ssh](coder_config-ssh.md) - Configure SSH to access Coder environments -* [coder envs](coder_envs.md) - Interact with Coder environments +* [coder config-ssh](coder_config-ssh.md) - Configure SSH to access Coder workspaces * [coder images](coder_images.md) - Manage Coder images * [coder login](coder_login.md) - Authenticate this client for future operations * [coder logout](coder_logout.md) - Remove local authentication credentials if any exist -* [coder ssh](coder_ssh.md) - Enter a shell of execute a command over SSH into a Coder environment -* [coder sync](coder_sync.md) - Establish a one way directory sync to a Coder environment +* [coder ssh](coder_ssh.md) - Enter a shell of execute a command over SSH into a Coder workspace +* [coder sync](coder_sync.md) - Establish a one way directory sync to a Coder workspace * [coder tokens](coder_tokens.md) - manage Coder API tokens for the active user -* [coder urls](coder_urls.md) - Interact with environment DevURLs +* [coder urls](coder_urls.md) - Interact with workspace DevURLs * [coder users](coder_users.md) - Interact with Coder user accounts +* [coder workspaces](coder_workspaces.md) - Interact with Coder workspaces diff --git a/docs/coder_completion.md b/docs/coder_completion.md index 7478c155..143dcac7 100644 --- a/docs/coder_completion.md +++ b/docs/coder_completion.md @@ -18,7 +18,7 @@ MacOS: Zsh: -If shell completion is not already enabled in your environment you will need +If shell completion is not already enabled in your workspace you will need to enable it. You can execute the following once: $ echo "autoload -U compinit; compinit" >> ~/.zshrc diff --git a/docs/coder_config-ssh.md b/docs/coder_config-ssh.md index 7aba039f..c16d087b 100644 --- a/docs/coder_config-ssh.md +++ b/docs/coder_config-ssh.md @@ -1,6 +1,6 @@ ## coder config-ssh -Configure SSH to access Coder environments +Configure SSH to access Coder workspaces ### Synopsis diff --git a/docs/coder_envs.md b/docs/coder_envs.md deleted file mode 100644 index 623c5e83..00000000 --- a/docs/coder_envs.md +++ /dev/null @@ -1,32 +0,0 @@ -## coder envs - -Interact with Coder environments - -### Synopsis - -Perform operations on the Coder environments owned by the active user. - -### Options - -``` - -h, --help help for envs -``` - -### Options inherited from parent commands - -``` - -v, --verbose show verbose output -``` - -### SEE ALSO - -* [coder](coder.md) - coder provides a CLI for working with an existing Coder installation -* [coder envs create](coder_envs_create.md) - create a new environment. -* [coder envs create-from-config](coder_envs_create-from-config.md) - create a new environment from a template -* [coder envs edit](coder_envs_edit.md) - edit an existing environment and initiate a rebuild. -* [coder envs ls](coder_envs_ls.md) - list all environments owned by the active user -* [coder envs rebuild](coder_envs_rebuild.md) - rebuild a Coder environment -* [coder envs rm](coder_envs_rm.md) - remove Coder environments by name -* [coder envs stop](coder_envs_stop.md) - stop Coder environments by name -* [coder envs watch-build](coder_envs_watch-build.md) - trail the build log of a Coder environment - diff --git a/docs/coder_envs_create-from-config.md b/docs/coder_envs_create-from-config.md deleted file mode 100644 index e90e7bfe..00000000 --- a/docs/coder_envs_create-from-config.md +++ /dev/null @@ -1,43 +0,0 @@ -## coder envs create-from-config - -create a new environment from a template - -### Synopsis - -Create a new Coder environment using a Workspaces As Code template. - -``` -coder envs create-from-config [flags] -``` - -### Examples - -``` -# create a new environment from git repository -coder envs create-from-config --name="dev-env" --repo-url https://github.com/cdr/m --ref my-branch -coder envs create-from-config --name="dev-env" -f coder.yaml -``` - -### Options - -``` - -f, --filepath string path to local template file. - --follow follow buildlog after initiating rebuild - -h, --help help for create-from-config - --name string name of the environment to be created - -o, --org string name of the organization the environment should be created under. - --provider string name of Workspace Provider with which to create the environment - --ref string git reference to pull template from. May be a branch, tag, or commit hash. (default "master") - -r, --repo-url string URL of the git repository to pull the config from. Config file must live in '.coder/coder.yaml'. -``` - -### Options inherited from parent commands - -``` - -v, --verbose show verbose output -``` - -### SEE ALSO - -* [coder envs](coder_envs.md) - Interact with Coder environments - diff --git a/docs/coder_envs_create.md b/docs/coder_envs_create.md deleted file mode 100644 index bc1f6517..00000000 --- a/docs/coder_envs_create.md +++ /dev/null @@ -1,47 +0,0 @@ -## coder envs create - -create a new environment. - -### Synopsis - -Create a new Coder environment. - -``` -coder envs create [environment_name] [flags] -``` - -### Examples - -``` -# create a new environment using default resource amounts -coder envs create my-new-env --image ubuntu -coder envs create my-new-powerful-env --cpu 12 --disk 100 --memory 16 --image ubuntu -``` - -### Options - -``` - --container-based-vm deploy the environment as a Container-based VM - -c, --cpu float32 number of cpu cores the environment should be provisioned with. - -d, --disk int GB of disk storage an environment should be provisioned with. - --enable-autostart automatically start this environment at your preferred time. - --follow follow buildlog after initiating rebuild - -g, --gpus int number GPUs an environment should be provisioned with. - -h, --help help for create - -i, --image string name of the image to base the environment off of. - -m, --memory float32 GB of RAM an environment should be provisioned with. - -o, --org string name of the organization the environment should be created under. - --provider string name of Workspace Provider with which to create the environment - -t, --tag string tag of the image the environment will be based off of. (default "latest") -``` - -### Options inherited from parent commands - -``` - -v, --verbose show verbose output -``` - -### SEE ALSO - -* [coder envs](coder_envs.md) - Interact with Coder environments - diff --git a/docs/coder_envs_edit.md b/docs/coder_envs_edit.md deleted file mode 100644 index a8cc2551..00000000 --- a/docs/coder_envs_edit.md +++ /dev/null @@ -1,46 +0,0 @@ -## coder envs edit - -edit an existing environment and initiate a rebuild. - -### Synopsis - -Edit an existing environment and initate a rebuild. - -``` -coder envs edit [flags] -``` - -### Examples - -``` -coder envs edit back-end-env --cpu 4 - -coder envs edit back-end-env --disk 20 -``` - -### Options - -``` - -c, --cpu float32 The number of cpu cores the environment should be provisioned with. - -d, --disk int The amount of disk storage an environment should be provisioned with. - --follow follow buildlog after initiating rebuild - --force force rebuild without showing a confirmation prompt - -g, --gpu int The amount of disk storage to provision the environment with. - -h, --help help for edit - -i, --image string name of the image you want the environment to be based off of. - -m, --memory float32 The amount of RAM an environment should be provisioned with. - -o, --org string name of the organization the environment should be created under. - -t, --tag string image tag of the image you want to base the environment off of. (default "latest") - --user string Specify the user whose resources to target (default "me") -``` - -### Options inherited from parent commands - -``` - -v, --verbose show verbose output -``` - -### SEE ALSO - -* [coder envs](coder_envs.md) - Interact with Coder environments - diff --git a/docs/coder_envs_rm.md b/docs/coder_envs_rm.md deleted file mode 100644 index e39acffd..00000000 --- a/docs/coder_envs_rm.md +++ /dev/null @@ -1,26 +0,0 @@ -## coder envs rm - -remove Coder environments by name - -``` -coder envs rm [...environment_names] [flags] -``` - -### Options - -``` - -f, --force force remove the specified environments without prompting first - -h, --help help for rm - --user string Specify the user whose resources to target (default "me") -``` - -### Options inherited from parent commands - -``` - -v, --verbose show verbose output -``` - -### SEE ALSO - -* [coder envs](coder_envs.md) - Interact with Coder environments - diff --git a/docs/coder_envs_stop.md b/docs/coder_envs_stop.md deleted file mode 100644 index 4fd38db2..00000000 --- a/docs/coder_envs_stop.md +++ /dev/null @@ -1,44 +0,0 @@ -## coder envs stop - -stop Coder environments by name - -### Synopsis - -Stop Coder environments by name - -``` -coder envs stop [...environment_names] [flags] -``` - -### Examples - -``` -coder envs stop front-end-env -coder envs stop front-end-env backend-env - -# stop all of your environments -coder envs ls -o json | jq -c '.[].name' | xargs coder envs stop - -# stop all environments for a given user -coder envs --user charlie@coder.com ls -o json \ - | jq -c '.[].name' \ - | xargs coder envs --user charlie@coder.com stop -``` - -### Options - -``` - -h, --help help for stop - --user string Specify the user whose resources to target (default "me") -``` - -### Options inherited from parent commands - -``` - -v, --verbose show verbose output -``` - -### SEE ALSO - -* [coder envs](coder_envs.md) - Interact with Coder environments - diff --git a/docs/coder_ssh.md b/docs/coder_ssh.md index 656b66fd..d57ac50e 100644 --- a/docs/coder_ssh.md +++ b/docs/coder_ssh.md @@ -1,9 +1,9 @@ ## coder ssh -Enter a shell of execute a command over SSH into a Coder environment +Enter a shell of execute a command over SSH into a Coder workspace ``` -coder ssh [environment_name] [] +coder ssh [workspace_name] [] ``` ### Examples diff --git a/docs/coder_sync.md b/docs/coder_sync.md index b872fab4..516f3160 100644 --- a/docs/coder_sync.md +++ b/docs/coder_sync.md @@ -1,9 +1,9 @@ ## coder sync -Establish a one way directory sync to a Coder environment +Establish a one way directory sync to a Coder workspace ``` -coder sync [local directory] [:] [flags] +coder sync [local directory] [:] [flags] ``` ### Options diff --git a/docs/coder_tokens.md b/docs/coder_tokens.md index 62bf7511..7b884e5b 100644 --- a/docs/coder_tokens.md +++ b/docs/coder_tokens.md @@ -5,7 +5,7 @@ manage Coder API tokens for the active user ### Synopsis Create and manage API Tokens for authenticating the CLI. -Statically authenticate using the token value with the `CODER_TOKEN` and `CODER_URL` environment variables. +Statically authenticate using the token value with the `CODER_TOKEN` and `CODER_URL` workspace variables. ### Options diff --git a/docs/coder_urls.md b/docs/coder_urls.md index efe016d1..2bb3e393 100644 --- a/docs/coder_urls.md +++ b/docs/coder_urls.md @@ -1,6 +1,6 @@ ## coder urls -Interact with environment DevURLs +Interact with workspace DevURLs ### Options @@ -18,6 +18,6 @@ Interact with environment DevURLs * [coder](coder.md) - coder provides a CLI for working with an existing Coder installation * [coder urls create](coder_urls_create.md) - Create a new dev URL for a workspace -* [coder urls ls](coder_urls_ls.md) - List all DevURLs for an environment +* [coder urls ls](coder_urls_ls.md) - List all DevURLs for a workspace * [coder urls rm](coder_urls_rm.md) - Remove a dev url diff --git a/docs/coder_urls_create.md b/docs/coder_urls_create.md index 81228aaa..eb3ed6fa 100644 --- a/docs/coder_urls_create.md +++ b/docs/coder_urls_create.md @@ -29,5 +29,5 @@ coder urls create my-workspace 8080 --name my-dev-url ### SEE ALSO -* [coder urls](coder_urls.md) - Interact with environment DevURLs +* [coder urls](coder_urls.md) - Interact with workspace DevURLs diff --git a/docs/coder_urls_ls.md b/docs/coder_urls_ls.md index 67d3fc2c..79048d9e 100644 --- a/docs/coder_urls_ls.md +++ b/docs/coder_urls_ls.md @@ -1,9 +1,9 @@ ## coder urls ls -List all DevURLs for an environment +List all DevURLs for a workspace ``` -coder urls ls [environment_name] [flags] +coder urls ls [workspace_name] [flags] ``` ### Options @@ -21,5 +21,5 @@ coder urls ls [environment_name] [flags] ### SEE ALSO -* [coder urls](coder_urls.md) - Interact with environment DevURLs +* [coder urls](coder_urls.md) - Interact with workspace DevURLs diff --git a/docs/coder_urls_rm.md b/docs/coder_urls_rm.md index be1f8e3c..5a25a3bf 100644 --- a/docs/coder_urls_rm.md +++ b/docs/coder_urls_rm.md @@ -3,7 +3,7 @@ Remove a dev url ``` -coder urls rm [environment_name] [port] [flags] +coder urls rm [workspace_name] [port] [flags] ``` ### Options @@ -20,5 +20,5 @@ coder urls rm [environment_name] [port] [flags] ### SEE ALSO -* [coder urls](coder_urls.md) - Interact with environment DevURLs +* [coder urls](coder_urls.md) - Interact with workspace DevURLs diff --git a/docs/coder_workspaces.md b/docs/coder_workspaces.md new file mode 100644 index 00000000..bb29bcf5 --- /dev/null +++ b/docs/coder_workspaces.md @@ -0,0 +1,32 @@ +## coder workspaces + +Interact with Coder workspaces + +### Synopsis + +Perform operations on the Coder workspaces owned by the active user. + +### Options + +``` + -h, --help help for workspaces +``` + +### Options inherited from parent commands + +``` + -v, --verbose show verbose output +``` + +### SEE ALSO + +* [coder](coder.md) - coder provides a CLI for working with an existing Coder installation +* [coder workspaces create](coder_workspaces_create.md) - create a new workspace. +* [coder workspaces create-from-config](coder_workspaces_create-from-config.md) - create a new workspace from a template +* [coder workspaces edit](coder_workspaces_edit.md) - edit an existing workspace and initiate a rebuild. +* [coder workspaces ls](coder_workspaces_ls.md) - list all workspaces owned by the active user +* [coder workspaces rebuild](coder_workspaces_rebuild.md) - rebuild a Coder workspace +* [coder workspaces rm](coder_workspaces_rm.md) - remove Coder workspaces by name +* [coder workspaces stop](coder_workspaces_stop.md) - stop Coder workspaces by name +* [coder workspaces watch-build](coder_workspaces_watch-build.md) - trail the build log of a Coder workspace + diff --git a/docs/coder_workspaces_create-from-config.md b/docs/coder_workspaces_create-from-config.md new file mode 100644 index 00000000..3ad6c2ae --- /dev/null +++ b/docs/coder_workspaces_create-from-config.md @@ -0,0 +1,43 @@ +## coder workspaces create-from-config + +create a new workspace from a template + +### Synopsis + +Create a new Coder workspace using a Workspaces As Code template. + +``` +coder workspaces create-from-config [flags] +``` + +### Examples + +``` +# create a new workspace from git repository +coder workspaces create-from-config --name="dev-workspace" --repo-url https://github.com/cdr/m --ref my-branch +coder workspaces create-from-config --name="dev-workspace" -f coder.yaml +``` + +### Options + +``` + -f, --filepath string path to local template file. + --follow follow buildlog after initiating rebuild + -h, --help help for create-from-config + --name string name of the workspace to be created + -o, --org string name of the organization the workspace should be created under. + --provider string name of Workspace Provider with which to create the workspace + --ref string git reference to pull template from. May be a branch, tag, or commit hash. (default "master") + -r, --repo-url string URL of the git repository to pull the config from. Config file must live in '.coder/coder.yaml'. +``` + +### Options inherited from parent commands + +``` + -v, --verbose show verbose output +``` + +### SEE ALSO + +* [coder workspaces](coder_workspaces.md) - Interact with Coder workspaces + diff --git a/docs/coder_workspaces_create.md b/docs/coder_workspaces_create.md new file mode 100644 index 00000000..56732f89 --- /dev/null +++ b/docs/coder_workspaces_create.md @@ -0,0 +1,47 @@ +## coder workspaces create + +create a new workspace. + +### Synopsis + +Create a new Coder workspace. + +``` +coder workspaces create [workspace_name] [flags] +``` + +### Examples + +``` +# create a new workspace using default resource amounts +coder workspaces create my-new-workspace --image ubuntu +coder workspaces create my-new-powerful-workspace --cpu 12 --disk 100 --memory 16 --image ubuntu +``` + +### Options + +``` + --container-based-vm deploy the workspace as a Container-based VM + -c, --cpu float32 number of cpu cores the workspace should be provisioned with. + -d, --disk int GB of disk storage a workspace should be provisioned with. + --enable-autostart automatically start this workspace at your preferred time. + --follow follow buildlog after initiating rebuild + -g, --gpus int number GPUs a workspace should be provisioned with. + -h, --help help for create + -i, --image string name of the image to base the workspace off of. + -m, --memory float32 GB of RAM a workspace should be provisioned with. + -o, --org string name of the organization the workspace should be created under. + --provider string name of Workspace Provider with which to create the workspace + -t, --tag string tag of the image the workspace will be based off of. (default "latest") +``` + +### Options inherited from parent commands + +``` + -v, --verbose show verbose output +``` + +### SEE ALSO + +* [coder workspaces](coder_workspaces.md) - Interact with Coder workspaces + diff --git a/docs/coder_workspaces_edit.md b/docs/coder_workspaces_edit.md new file mode 100644 index 00000000..2d214cb4 --- /dev/null +++ b/docs/coder_workspaces_edit.md @@ -0,0 +1,46 @@ +## coder workspaces edit + +edit an existing workspace and initiate a rebuild. + +### Synopsis + +Edit an existing workspace and initate a rebuild. + +``` +coder workspaces edit [flags] +``` + +### Examples + +``` +coder workspaces edit back-end-workspace --cpu 4 + +coder workspaces edit back-end-workspace --disk 20 +``` + +### Options + +``` + -c, --cpu float32 The number of cpu cores the workspace should be provisioned with. + -d, --disk int The amount of disk storage a workspace should be provisioned with. + --follow follow buildlog after initiating rebuild + --force force rebuild without showing a confirmation prompt + -g, --gpu int The amount of disk storage to provision the workspace with. + -h, --help help for edit + -i, --image string name of the image you want the workspace to be based off of. + -m, --memory float32 The amount of RAM a workspace should be provisioned with. + -o, --org string name of the organization the workspace should be created under. + -t, --tag string image tag of the image you want to base the workspace off of. (default "latest") + --user string Specify the user whose resources to target (default "me") +``` + +### Options inherited from parent commands + +``` + -v, --verbose show verbose output +``` + +### SEE ALSO + +* [coder workspaces](coder_workspaces.md) - Interact with Coder workspaces + diff --git a/docs/coder_envs_ls.md b/docs/coder_workspaces_ls.md similarity index 51% rename from docs/coder_envs_ls.md rename to docs/coder_workspaces_ls.md index e43aec24..cd940e2b 100644 --- a/docs/coder_envs_ls.md +++ b/docs/coder_workspaces_ls.md @@ -1,13 +1,13 @@ -## coder envs ls +## coder workspaces ls -list all environments owned by the active user +list all workspaces owned by the active user ### Synopsis -List all Coder environments owned by the active user. +List all Coder workspaces owned by the active user. ``` -coder envs ls [flags] +coder workspaces ls [flags] ``` ### Options @@ -15,7 +15,7 @@ coder envs ls [flags] ``` -h, --help help for ls -o, --output string human | json (default "human") - -p, --provider string Filter environments by a particular workspace provider name. + -p, --provider string Filter workspaces by a particular workspace provider name. --user string Specify the user whose resources to target (default "me") ``` @@ -27,5 +27,5 @@ coder envs ls [flags] ### SEE ALSO -* [coder envs](coder_envs.md) - Interact with Coder environments +* [coder workspaces](coder_workspaces.md) - Interact with Coder workspaces diff --git a/docs/coder_envs_rebuild.md b/docs/coder_workspaces_rebuild.md similarity index 59% rename from docs/coder_envs_rebuild.md rename to docs/coder_workspaces_rebuild.md index a18d279e..8e928852 100644 --- a/docs/coder_envs_rebuild.md +++ b/docs/coder_workspaces_rebuild.md @@ -1,16 +1,16 @@ -## coder envs rebuild +## coder workspaces rebuild -rebuild a Coder environment +rebuild a Coder workspace ``` -coder envs rebuild [environment_name] [flags] +coder workspaces rebuild [workspace_name] [flags] ``` ### Examples ``` -coder envs rebuild front-end-env --follow -coder envs rebuild backend-env --force +coder workspaces rebuild front-end-workspace --follow +coder workspaces rebuild backend-workspace --force ``` ### Options @@ -30,5 +30,5 @@ coder envs rebuild backend-env --force ### SEE ALSO -* [coder envs](coder_envs.md) - Interact with Coder environments +* [coder workspaces](coder_workspaces.md) - Interact with Coder workspaces diff --git a/docs/coder_workspaces_rm.md b/docs/coder_workspaces_rm.md new file mode 100644 index 00000000..b19ece2d --- /dev/null +++ b/docs/coder_workspaces_rm.md @@ -0,0 +1,26 @@ +## coder workspaces rm + +remove Coder workspaces by name + +``` +coder workspaces rm [...workspace_names] [flags] +``` + +### Options + +``` + -f, --force force remove the specified workspaces without prompting first + -h, --help help for rm + --user string Specify the user whose resources to target (default "me") +``` + +### Options inherited from parent commands + +``` + -v, --verbose show verbose output +``` + +### SEE ALSO + +* [coder workspaces](coder_workspaces.md) - Interact with Coder workspaces + diff --git a/docs/coder_workspaces_stop.md b/docs/coder_workspaces_stop.md new file mode 100644 index 00000000..0e00ecef --- /dev/null +++ b/docs/coder_workspaces_stop.md @@ -0,0 +1,44 @@ +## coder workspaces stop + +stop Coder workspaces by name + +### Synopsis + +Stop Coder workspaces by name + +``` +coder workspaces stop [...workspace_names] [flags] +``` + +### Examples + +``` +coder workspaces stop front-end-workspace +coder workspaces stop front-end-workspace backend-workspace + +# stop all of your workspaces +coder workspaces ls -o json | jq -c '.[].name' | xargs coder workspaces stop + +# stop all workspaces for a given user +coder workspaces --user charlie@coder.com ls -o json \ + | jq -c '.[].name' \ + | xargs coder workspaces --user charlie@coder.com stop +``` + +### Options + +``` + -h, --help help for stop + --user string Specify the user whose resources to target (default "me") +``` + +### Options inherited from parent commands + +``` + -v, --verbose show verbose output +``` + +### SEE ALSO + +* [coder workspaces](coder_workspaces.md) - Interact with Coder workspaces + diff --git a/docs/coder_envs_watch-build.md b/docs/coder_workspaces_watch-build.md similarity index 53% rename from docs/coder_envs_watch-build.md rename to docs/coder_workspaces_watch-build.md index 19901fc5..8af34e82 100644 --- a/docs/coder_envs_watch-build.md +++ b/docs/coder_workspaces_watch-build.md @@ -1,15 +1,15 @@ -## coder envs watch-build +## coder workspaces watch-build -trail the build log of a Coder environment +trail the build log of a Coder workspace ``` -coder envs watch-build [environment_name] [flags] +coder workspaces watch-build [workspace_name] [flags] ``` ### Examples ``` -coder envs watch-build front-end-env +coder workspaces watch-build front-end-workspace ``` ### Options @@ -27,5 +27,5 @@ coder envs watch-build front-end-env ### SEE ALSO -* [coder envs](coder_envs.md) - Interact with Coder environments +* [coder workspaces](coder_workspaces.md) - Interact with Coder workspaces diff --git a/internal/activity/pusher.go b/internal/activity/pusher.go index f59630a1..f432c72e 100644 --- a/internal/activity/pusher.go +++ b/internal/activity/pusher.go @@ -16,19 +16,19 @@ const pushInterval = time.Minute // Pusher pushes activity metrics no more than once per pushInterval. Pushes // within the same interval are a no-op. type Pusher struct { - envID string - source string + workspaceID string + source string client coder.Client rate *rate.Limiter // Use a rate limiter to control the sampling rate. } // NewPusher instantiates a new instance of Pusher. -func NewPusher(c coder.Client, envID, source string) *Pusher { +func NewPusher(c coder.Client, workspaceID, source string) *Pusher { return &Pusher{ - envID: envID, - source: source, - client: c, + workspaceID: workspaceID, + source: source, + client: c, // Sample only 1 per interval to avoid spamming the api. rate: rate.NewLimiter(rate.Every(pushInterval), 1), } @@ -41,7 +41,7 @@ func (p *Pusher) Push(ctx context.Context) { return } - if err := p.client.PushActivity(ctx, p.source, p.envID); err != nil { + if err := p.client.PushActivity(ctx, p.source, p.workspaceID); err != nil { clog.Log(clog.Error(fmt.Sprintf("push activity: %s", err))) } } diff --git a/internal/cmd/ceapi.go b/internal/cmd/ceapi.go index 2e7b031d..c58b8161 100644 --- a/internal/cmd/ceapi.go +++ b/internal/cmd/ceapi.go @@ -32,8 +32,8 @@ func lookupUserOrgs(user *coder.User, orgs []coder.Organization) []coder.Organiz return userOrgs } -// getEnvs returns all environments for the user. -func getEnvs(ctx context.Context, client coder.Client, email string) ([]coder.Environment, error) { +// getWorkspaces returns all workspaces for the user. +func getWorkspaces(ctx context.Context, client coder.Client, email string) ([]coder.Workspace, error) { user, err := client.UserByEmail(ctx, email) if err != nil { return nil, xerrors.Errorf("get user: %w", err) @@ -46,51 +46,51 @@ func getEnvs(ctx context.Context, client coder.Client, email string) ([]coder.En orgs = lookupUserOrgs(user, orgs) - // NOTE: We don't know in advance how many envs we have so we can't pre-alloc. - var allEnvs []coder.Environment + // NOTE: We don't know in advance how many workspaces we have so we can't pre-alloc. + var allWorkspaces []coder.Workspace for _, org := range orgs { - envs, err := client.UserEnvironmentsByOrganization(ctx, user.ID, org.ID) + workspaces, err := client.UserWorkspacesByOrganization(ctx, user.ID, org.ID) if err != nil { - return nil, xerrors.Errorf("get envs for %s: %w", org.Name, err) + return nil, xerrors.Errorf("get workspaces for %s: %w", org.Name, err) } - allEnvs = append(allEnvs, envs...) + allWorkspaces = append(allWorkspaces, workspaces...) } - return allEnvs, nil + return allWorkspaces, nil } -// searchForEnv searches a user's environments to find the specified envName. If none is found, the haystack of -// environment names is returned. -func searchForEnv(ctx context.Context, client coder.Client, envName, userEmail string) (_ *coder.Environment, haystack []string, _ error) { - envs, err := getEnvs(ctx, client, userEmail) +// searchForWorkspace searches a user's workspaces to find the specified workspaceName. If none is found, the haystack of +// workspace names is returned. +func searchForWorkspace(ctx context.Context, client coder.Client, workspaceName, userEmail string) (_ *coder.Workspace, haystack []string, _ error) { + workspaces, err := getWorkspaces(ctx, client, userEmail) if err != nil { - return nil, nil, xerrors.Errorf("get environments: %w", err) + return nil, nil, xerrors.Errorf("get workspaces: %w", err) } - // NOTE: We don't know in advance where we will find the env, so we can't pre-alloc. - for _, env := range envs { - if env.Name == envName { - return &env, nil, nil + // NOTE: We don't know in advance where we will find the workspace, so we can't pre-alloc. + for _, workspace := range workspaces { + if workspace.Name == workspaceName { + return &workspace, nil, nil } // Keep track of what we found for the logs. - haystack = append(haystack, env.Name) + haystack = append(haystack, workspace.Name) } return nil, haystack, coder.ErrNotFound } -// findEnv returns a single environment by name (if it exists.). -func findEnv(ctx context.Context, client coder.Client, envName, userEmail string) (*coder.Environment, error) { - env, haystack, err := searchForEnv(ctx, client, envName, userEmail) +// findWorkspace returns a single workspace by name (if it exists.). +func findWorkspace(ctx context.Context, client coder.Client, workspaceName, userEmail string) (*coder.Workspace, error) { + workspace, haystack, err := searchForWorkspace(ctx, client, workspaceName, userEmail) if err != nil { return nil, clog.Fatal( - "failed to find environment", - fmt.Sprintf("environment %q not found in %q", envName, haystack), + "failed to find workspace", + fmt.Sprintf("workspace %q not found in %q", workspaceName, haystack), clog.BlankLine, - clog.Tipf("run \"coder envs ls\" to view your environments"), + clog.Tipf("run \"coder workspaces ls\" to view your workspaces"), ) } - return env, nil + return workspace, nil } type findImgConf struct { @@ -204,35 +204,35 @@ 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, userEmail string) ([]coder.Environment, error) { +func getWorkspacesByProvider(ctx context.Context, client coder.Client, wpName, userEmail string) ([]coder.Workspace, error) { wp, err := coderutil.ProviderByName(ctx, client, wpName) if err != nil { return nil, err } - envs, err := client.EnvironmentsByWorkspaceProvider(ctx, wp.ID) + workspaces, err := client.WorkspacesByWorkspaceProvider(ctx, wp.ID) if err != nil { return nil, err } - envs, err = filterEnvsByUser(ctx, client, userEmail, envs) + workspaces, err = filterWorkspacesByUser(ctx, client, userEmail, workspaces) if err != nil { return nil, err } - return envs, nil + return workspaces, nil } -func filterEnvsByUser(ctx context.Context, client coder.Client, userEmail string, envs []coder.Environment) ([]coder.Environment, error) { +func filterWorkspacesByUser(ctx context.Context, client coder.Client, userEmail string, workspaces []coder.Workspace) ([]coder.Workspace, 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) + var filteredWorkspaces []coder.Workspace + for _, workspace := range workspaces { + if workspace.UserID == user.ID { + filteredWorkspaces = append(filteredWorkspaces, workspace) } } - return filteredEnvs, nil + return filteredWorkspaces, nil } diff --git a/internal/cmd/cmd.go b/internal/cmd/cmd.go index be7b8f9e..38e5ae4f 100644 --- a/internal/cmd/cmd.go +++ b/internal/cmd/cmd.go @@ -28,7 +28,8 @@ func Make() *cobra.Command { usersCmd(), tagsCmd(), configSSHCmd(), - envsCmd(), + envCmd(), // DEPRECATED. + workspacesCmd(), syncCmd(), urlCmd(), tokensCmd(), @@ -83,7 +84,7 @@ MacOS: Zsh: -If shell completion is not already enabled in your environment you will need +If shell completion is not already enabled in your workspace you will need to enable it. You can execute the following once: $ echo "autoload -U compinit; compinit" >> ~/.zshrc diff --git a/internal/cmd/configssh.go b/internal/cmd/configssh.go index ee493660..9417c514 100644 --- a/internal/cmd/configssh.go +++ b/internal/cmd/configssh.go @@ -22,7 +22,7 @@ import ( const sshStartToken = "# ------------START-CODER-ENTERPRISE-----------" const sshStartMessage = `# The following has been auto-generated by "coder config-ssh" -# to make accessing your Coder environments easier. +# to make accessing your Coder workspaces easier. # # To remove this blob, run: # @@ -40,7 +40,7 @@ func configSSHCmd() *cobra.Command { cmd := &cobra.Command{ Use: "config-ssh", - Short: "Configure SSH to access Coder environments", + Short: "Configure SSH to access Coder workspaces", Long: "Inject the proper OpenSSH configuration into your local SSH config file.", RunE: configSSH(&configpath, &remove, &next), } @@ -98,21 +98,21 @@ func configSSH(configpath *string, remove *bool, next *bool) func(cmd *cobra.Com return xerrors.Errorf("fetch username: %w", err) } - envs, err := getEnvs(ctx, client, coder.Me) + workspaces, err := getWorkspaces(ctx, client, coder.Me) if err != nil { return err } - if len(envs) < 1 { - return xerrors.New("no environments found") + if len(workspaces) < 1 { + return xerrors.New("no workspaces found") } - envsWithProviders, err := coderutil.EnvsWithProvider(ctx, client, envs) + workspacesWithProviders, err := coderutil.WorkspacesWithProvider(ctx, client, workspaces) if err != nil { - return xerrors.Errorf("resolve env workspace providers: %w", err) + return xerrors.Errorf("resolve workspace workspace providers: %w", err) } - if !sshAvailable(envsWithProviders) { - return xerrors.New("SSH is disabled or not available for any environments in your Coder deployment.") + if !sshAvailable(workspacesWithProviders) { + return xerrors.New("SSH is disabled or not available for any workspaces in your Coder deployment.") } wconf, err := client.SiteConfigWorkspaces(ctx) @@ -132,7 +132,7 @@ func configSSH(configpath *string, remove *bool, next *bool) func(cmd *cobra.Com } } - newConfig := makeNewConfigs(user.Username, envsWithProviders, privateKeyFilepath, p2p) + newConfig := makeNewConfigs(user.Username, workspacesWithProviders, privateKeyFilepath, p2p) err = os.MkdirAll(filepath.Dir(*configpath), os.ModePerm) if err != nil { @@ -152,10 +152,10 @@ func configSSH(configpath *string, remove *bool, next *bool) func(cmd *cobra.Com fmt.Printf("Your private ssh key was written to \"%s\"\n", privateKeyFilepath) } - writeSSHUXState(ctx, client, user.ID, envs) + writeSSHUXState(ctx, client, user.ID, workspaces) fmt.Printf("An auto-generated ssh config was written to \"%s\"\n", *configpath) - fmt.Println("You should now be able to ssh into your environment") - fmt.Printf("For example, try running\n\n\t$ ssh coder.%s\n\n", envs[0].Name) + fmt.Println("You should now be able to ssh into your workspace") + fmt.Printf("For example, try running\n\n\t$ ssh coder.%s\n\n", workspaces[0].Name) return nil } } @@ -175,10 +175,10 @@ func removeOldConfig(config string) (string, bool) { return config[:startIndex-1] + config[endIndex+len(sshEndToken)+1:], true } -// sshAvailable returns true if SSH is available for at least one environment. -func sshAvailable(envs []coderutil.EnvWithWorkspaceProvider) bool { - for _, env := range envs { - if env.WorkspaceProvider.SSHEnabled { +// sshAvailable returns true if SSH is available for at least one workspace. +func sshAvailable(workspaces []coderutil.WorkspaceWithWorkspaceProvider) bool { + for _, workspace := range workspaces { + if workspace.WorkspaceProvider.SSHEnabled { return true } } @@ -193,34 +193,34 @@ func writeSSHKey(ctx context.Context, client coder.Client, privateKeyPath string return ioutil.WriteFile(privateKeyPath, []byte(key.PrivateKey), 0600) } -func makeNewConfigs(userName string, envs []coderutil.EnvWithWorkspaceProvider, privateKeyFilepath string, p2p bool) string { +func makeNewConfigs(userName string, workspaces []coderutil.WorkspaceWithWorkspaceProvider, privateKeyFilepath string, p2p bool) string { newConfig := fmt.Sprintf("\n%s\n%s\n\n", sshStartToken, sshStartMessage) - sort.Slice(envs, func(i, j int) bool { return envs[i].Env.Name < envs[j].Env.Name }) + sort.Slice(workspaces, func(i, j int) bool { return workspaces[i].Workspace.Name < workspaces[j].Workspace.Name }) - for _, env := range envs { - if !env.WorkspaceProvider.SSHEnabled { - clog.LogWarn(fmt.Sprintf("SSH is not enabled for workspace provider %q", env.WorkspaceProvider.Name), + for _, workspace := range workspaces { + if !workspace.WorkspaceProvider.SSHEnabled { + clog.LogWarn(fmt.Sprintf("SSH is not enabled for workspace provider %q", workspace.WorkspaceProvider.Name), clog.BlankLine, clog.Tipf("ask an infrastructure administrator to enable SSH for this workspace provider"), ) continue } - u, err := url.Parse(env.WorkspaceProvider.EnvproxyAccessURL) + u, err := url.Parse(workspace.WorkspaceProvider.EnvproxyAccessURL) if err != nil { - clog.LogWarn("invalid access url", clog.Causef("malformed url: %q", env.WorkspaceProvider.EnvproxyAccessURL)) + clog.LogWarn("invalid access url", clog.Causef("malformed url: %q", workspace.WorkspaceProvider.EnvproxyAccessURL)) continue } - useTunnel := env.WorkspaceProvider.BuiltIn && p2p - newConfig += makeSSHConfig(u.Host, userName, env.Env.Name, privateKeyFilepath, useTunnel) + useTunnel := workspace.WorkspaceProvider.BuiltIn && p2p + newConfig += makeSSHConfig(u.Host, userName, workspace.Workspace.Name, privateKeyFilepath, useTunnel) } newConfig += fmt.Sprintf("\n%s\n", sshEndToken) return newConfig } -func makeSSHConfig(host, userName, envName, privateKeyFilepath string, tunnel bool) string { +func makeSSHConfig(host, userName, workspaceName, privateKeyFilepath string, tunnel bool) string { if tunnel { return fmt.Sprintf( `Host coder.%s @@ -232,7 +232,7 @@ func makeSSHConfig(host, userName, envName, privateKeyFilepath string, tunnel bo IdentityFile="%s" ServerAliveInterval 60 ServerAliveCountMax 3 -`, envName, envName, envName, privateKeyFilepath) +`, workspaceName, workspaceName, workspaceName, privateKeyFilepath) } return fmt.Sprintf( @@ -245,7 +245,7 @@ func makeSSHConfig(host, userName, envName, privateKeyFilepath string, tunnel bo IdentityFile="%s" ServerAliveInterval 60 ServerAliveCountMax 3 -`, envName, host, userName, envName, privateKeyFilepath) +`, workspaceName, host, userName, workspaceName, privateKeyFilepath) } func writeStr(filename, data string) error { @@ -260,12 +260,12 @@ func readStr(filename string) (string, error) { return string(contents), nil } -func writeSSHUXState(ctx context.Context, client coder.Client, userID string, envs []coder.Environment) { - // Create a map of env.ID -> true to indicate to the web client that all - // current environments have SSH configured +func writeSSHUXState(ctx context.Context, client coder.Client, userID string, workspaces []coder.Workspace) { + // Create a map of workspace.ID -> true to indicate to the web client that all + // current workspaces have SSH configured cliSSHConfigured := make(map[string]bool) - for _, env := range envs { - cliSSHConfigured[env.ID] = true + for _, workspace := range workspaces { + cliSSHConfigured[workspace.ID] = true } // Update UXState that coder config-ssh has been run by the currently // authenticated user diff --git a/internal/cmd/login.go b/internal/cmd/login.go index a23cabfd..a706259c 100644 --- a/internal/cmd/login.go +++ b/internal/cmd/login.go @@ -47,11 +47,11 @@ func loginCmd() *cobra.Command { } } -// storeConfig writes the env URL and session token to the local config directory. +// storeConfig writes the workspace URL and session token to the local config directory. // The config lib will handle the local config path lookup and creation. -func storeConfig(envURL *url.URL, sessionToken string, urlCfg, sessionCfg config.File) error { - if err := urlCfg.Write(envURL.String()); err != nil { - return xerrors.Errorf("store env url: %w", err) +func storeConfig(workspaceURL *url.URL, sessionToken string, urlCfg, sessionCfg config.File) error { + if err := urlCfg.Write(workspaceURL.String()); err != nil { + return xerrors.Errorf("store workspace url: %w", err) } if err := sessionCfg.Write(sessionToken); err != nil { return xerrors.Errorf("store session token: %w", err) @@ -59,9 +59,9 @@ func storeConfig(envURL *url.URL, sessionToken string, urlCfg, sessionCfg config return nil } -func login(cmd *cobra.Command, envURL *url.URL) error { - authURL := *envURL - authURL.Path = envURL.Path + "/internal-auth" +func login(cmd *cobra.Command, workspaceURL *url.URL) error { + authURL := *workspaceURL + authURL.Path = workspaceURL.Path + "/internal-auth" q := authURL.Query() q.Add("show_token", "true") authURL.RawQuery = q.Encode() @@ -81,10 +81,10 @@ func login(cmd *cobra.Command, envURL *url.URL) error { return xerrors.Errorf("reading standard input: %w", err) } - if err := pingAPI(cmd.Context(), envURL, token); err != nil { + if err := pingAPI(cmd.Context(), workspaceURL, token); err != nil { return xerrors.Errorf("ping API with credentials: %w", err) } - if err := storeConfig(envURL, token, config.URL, config.Session); err != nil { + if err := storeConfig(workspaceURL, token, config.URL, config.Session); err != nil { return xerrors.Errorf("store auth: %w", err) } clog.LogSuccess("logged in") @@ -93,9 +93,9 @@ func login(cmd *cobra.Command, envURL *url.URL) error { // pingAPI creates a client from the given url/token and try to exec an api call. // Not using the SDK as we want to verify the url/token pair before storing the config files. -func pingAPI(ctx context.Context, envURL *url.URL, token string) error { +func pingAPI(ctx context.Context, workspaceURL *url.URL, token string) error { client, err := coder.NewClient(coder.ClientOptions{ - BaseURL: envURL, + BaseURL: workspaceURL, Token: token, }) if err != nil { diff --git a/internal/cmd/rebuild.go b/internal/cmd/rebuild.go index 4df7d8e9..80a4521c 100644 --- a/internal/cmd/rebuild.go +++ b/internal/cmd/rebuild.go @@ -17,30 +17,30 @@ import ( "cdr.dev/coder-cli/pkg/clog" ) -func rebuildEnvCommand() *cobra.Command { +func rebuildWorkspaceCommand() *cobra.Command { var follow bool var force bool var user string cmd := &cobra.Command{ - Use: "rebuild [environment_name]", - Short: "rebuild a Coder environment", + Use: "rebuild [workspace_name]", + Short: "rebuild a Coder workspace", Args: xcobra.ExactArgs(1), - Example: `coder envs rebuild front-end-env --follow -coder envs rebuild backend-env --force`, + Example: `coder workspaces rebuild front-end-workspace --follow +coder workspaces rebuild backend-workspace --force`, RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() client, err := newClient(ctx, true) if err != nil { return err } - env, err := findEnv(ctx, client, args[0], user) + workspace, err := findWorkspace(ctx, client, args[0], user) if err != nil { return err } - if !force && env.LatestStat.ContainerStatus == coder.EnvironmentOn { + if !force && workspace.LatestStat.ContainerStatus == coder.WorkspaceOn { _, err = (&promptui.Prompt{ - Label: fmt.Sprintf("Rebuild environment %q? (will destroy any work outside of your home directory)", env.Name), + Label: fmt.Sprintf("Rebuild workspace %q? (will destroy any work outside of your home directory)", workspace.Name), IsConfirm: true, }).Run() if err != nil { @@ -51,17 +51,17 @@ coder envs rebuild backend-env --force`, } } - if err = client.RebuildEnvironment(ctx, env.ID); err != nil { + if err = client.RebuildWorkspace(ctx, workspace.ID); err != nil { return err } if follow { - if err = trailBuildLogs(ctx, client, env.ID); err != nil { + if err = trailBuildLogs(ctx, client, workspace.ID); err != nil { return err } } else { clog.LogSuccess( "successfully started rebuild", - clog.Tipf("run \"coder envs watch-build %s\" to follow the build logs", env.Name), + clog.Tipf("run \"coder workspaces watch-build %s\" to follow the build logs", workspace.Name), ) } return nil @@ -74,9 +74,9 @@ coder envs rebuild backend-env --force`, return cmd } -// trailBuildLogs follows the build log for a given environment and prints the staged +// trailBuildLogs follows the build log for a given workspace and prints the staged // output with loaders and success/failure indicators for each stage. -func trailBuildLogs(ctx context.Context, client coder.Client, envID string) error { +func trailBuildLogs(ctx context.Context, client coder.Client, workspaceID string) error { const check = "✅" const failure = "❌" @@ -85,7 +85,7 @@ func trailBuildLogs(ctx context.Context, client coder.Client, envID string) erro // this tells us whether to show dynamic loaders when printing output isTerminal := showInteractiveOutput - logs, err := client.FollowEnvironmentBuildLog(ctx, envID) + logs, err := client.FollowWorkspaceBuildLog(ctx, workspaceID) if err != nil { return err } @@ -160,9 +160,9 @@ func trailBuildLogs(ctx context.Context, client coder.Client, envID string) erro func watchBuildLogCommand() *cobra.Command { var user string cmd := &cobra.Command{ - Use: "watch-build [environment_name]", - Example: "coder envs watch-build front-end-env", - Short: "trail the build log of a Coder environment", + Use: "watch-build [workspace_name]", + Example: "coder workspaces watch-build front-end-workspace", + Short: "trail the build log of a Coder workspace", Args: xcobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() @@ -170,12 +170,12 @@ func watchBuildLogCommand() *cobra.Command { if err != nil { return err } - env, err := findEnv(ctx, client, args[0], user) + workspace, err := findWorkspace(ctx, client, args[0], user) if err != nil { return err } - if err = trailBuildLogs(ctx, client, env.ID); err != nil { + if err = trailBuildLogs(ctx, client, workspace.ID); err != nil { return err } return nil diff --git a/internal/cmd/resourcemanager.go b/internal/cmd/resourcemanager.go index 85d39c98..5be08d24 100644 --- a/internal/cmd/resourcemanager.go +++ b/internal/cmd/resourcemanager.go @@ -19,7 +19,7 @@ import ( func resourceCmd() *cobra.Command { cmd := &cobra.Command{ Use: "resources", - Short: "manage Coder resources with platform-level context (users, organizations, environments)", + Short: "manage Coder resources with platform-level context (users, organizations, workspaces)", Hidden: true, } cmd.AddCommand(resourceTop()) @@ -53,8 +53,8 @@ coder resources top --sort-by memory --show-empty`, 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") + cmd.Flags().StringVar(&options.sortBy, "sort-by", "cpu", "field to sort aggregate groups and workspaces by (cpu|memory)") + cmd.Flags().BoolVar(&options.showEmptyGroups, "show-empty", false, "show groups with zero active workspaces") return cmd } @@ -69,15 +69,15 @@ func runResourceTop(options *resourceTopOptions) func(cmd *cobra.Command, args [ // NOTE: it's not worth parrallelizing these calls yet given that this specific endpoint // takes about 20x times longer than the other two - allEnvs, err := client.Environments(ctx) + allWorkspaces, err := client.Workspaces(ctx) if err != nil { - return xerrors.Errorf("get environments %w", err) + return xerrors.Errorf("get workspaces %w", err) } - // only include environments whose last status was "ON" - envs := make([]coder.Environment, 0) - for _, e := range allEnvs { - if e.LatestStat.ContainerStatus == coder.EnvironmentOn { - envs = append(envs, e) + // only include workspaces whose last status was "ON" + workspaces := make([]coder.Workspace, 0) + for _, e := range allWorkspaces { + if e.LatestStat.ContainerStatus == coder.WorkspaceOn { + workspaces = append(workspaces, e) } } @@ -85,7 +85,7 @@ func runResourceTop(options *resourceTopOptions) func(cmd *cobra.Command, args [ if err != nil { return xerrors.Errorf("get users: %w", err) } - images, err := coderutil.MakeImageMap(ctx, client, envs) + images, err := coderutil.MakeImageMap(ctx, client, workspaces) if err != nil { return xerrors.Errorf("get images: %w", err) } @@ -100,11 +100,11 @@ func runResourceTop(options *resourceTopOptions) func(cmd *cobra.Command, args [ return xerrors.Errorf("get workspace providers: %w", err) } data := entities{ - providers: providers.Kubernetes, - users: users, - orgs: orgs, - envs: envs, - images: images, + providers: providers.Kubernetes, + users: users, + orgs: orgs, + workspaces: workspaces, + images: images, } return presentEntites(cmd.OutOrStdout(), data, *options) } @@ -113,7 +113,7 @@ func runResourceTop(options *resourceTopOptions) func(cmd *cobra.Command, args [ func presentEntites(w io.Writer, data entities, options resourceTopOptions) error { var ( groups []groupable - labeler envLabeler + labeler workspaceLabeler ) switch options.group { case "user": @@ -130,32 +130,32 @@ func presentEntites(w io.Writer, data entities, options resourceTopOptions) erro } type entities struct { - providers []coder.KubernetesProvider - users []coder.User - orgs []coder.Organization - envs []coder.Environment - images map[string]*coder.Image + providers []coder.KubernetesProvider + users []coder.User + orgs []coder.Organization + workspaces []coder.Workspace + images map[string]*coder.Image } -func aggregateByUser(data entities, options resourceTopOptions) ([]groupable, envLabeler) { +func aggregateByUser(data entities, options resourceTopOptions) ([]groupable, workspaceLabeler) { var groups []groupable providerIDMap := providerIDs(data.providers) orgIDMap := make(map[string]coder.Organization) for _, o := range data.orgs { orgIDMap[o.ID] = o } - userEnvs := make(map[string][]coder.Environment, len(data.users)) - for _, e := range data.envs { + userWorkspaces := make(map[string][]coder.Workspace, len(data.users)) + for _, e := range data.workspaces { if options.org != "" && orgIDMap[e.OrganizationID].Name != options.org { continue } - userEnvs[e.UserID] = append(userEnvs[e.UserID], e) + userWorkspaces[e.UserID] = append(userWorkspaces[e.UserID], e) } for _, u := range data.users { if options.user != "" && u.Email != options.user { continue } - groups = append(groups, userGrouping{user: u, envs: userEnvs[u.ID]}) + groups = append(groups, userGrouping{user: u, userWorkspaces: userWorkspaces[u.ID]}) } return groups, labelAll(imgLabeler(data.images), providerLabeler(providerIDMap), orgLabeler(orgIDMap)) } @@ -168,22 +168,22 @@ func userIDs(users []coder.User) map[string]coder.User { return userIDMap } -func aggregateByOrg(data entities, options resourceTopOptions) ([]groupable, envLabeler) { +func aggregateByOrg(data entities, options resourceTopOptions) ([]groupable, workspaceLabeler) { var groups []groupable providerIDMap := providerIDs(data.providers) - orgEnvs := make(map[string][]coder.Environment, len(data.orgs)) + orgWorkspaces := make(map[string][]coder.Workspace, len(data.orgs)) userIDMap := userIDs(data.users) - for _, e := range data.envs { + for _, e := range data.workspaces { if options.user != "" && userIDMap[e.UserID].Email != options.user { continue } - orgEnvs[e.OrganizationID] = append(orgEnvs[e.OrganizationID], e) + orgWorkspaces[e.OrganizationID] = append(orgWorkspaces[e.OrganizationID], e) } for _, o := range data.orgs { if options.org != "" && o.Name != options.org { continue } - groups = append(groups, orgGrouping{org: o, envs: orgEnvs[o.ID]}) + groups = append(groups, orgGrouping{org: o, orgWorkspaces: orgWorkspaces[o.ID]}) } return groups, labelAll(imgLabeler(data.images), userLabeler(userIDMap), providerLabeler(providerIDMap)) } @@ -196,39 +196,39 @@ func providerIDs(providers []coder.KubernetesProvider) map[string]coder.Kubernet return providerIDMap } -func aggregateByProvider(data entities, options resourceTopOptions) ([]groupable, envLabeler) { +func aggregateByProvider(data entities, options resourceTopOptions) ([]groupable, workspaceLabeler) { var groups []groupable providerIDMap := providerIDs(data.providers) userIDMap := userIDs(data.users) - providerEnvs := make(map[string][]coder.Environment, len(data.providers)) - for _, e := range data.envs { + providerWorkspaces := make(map[string][]coder.Workspace, len(data.providers)) + for _, e := range data.workspaces { if options.provider != "" && providerIDMap[e.ResourcePoolID].Name != options.provider { continue } - providerEnvs[e.ResourcePoolID] = append(providerEnvs[e.ResourcePoolID], e) + providerWorkspaces[e.ResourcePoolID] = append(providerWorkspaces[e.ResourcePoolID], e) } for _, p := range data.providers { if options.provider != "" && p.Name != options.provider { continue } - groups = append(groups, providerGrouping{provider: p, envs: providerEnvs[p.ID]}) + groups = append(groups, providerGrouping{provider: p, providerWorkspaces: providerWorkspaces[p.ID]}) } return groups, labelAll(imgLabeler(data.images), userLabeler(userIDMap)) // TODO: consider adding an org label here } -// groupable specifies a structure capable of being an aggregation group of environments (user, org, all). +// groupable specifies a structure capable of being an aggregation group of workspaces (user, org, all). type groupable interface { header() string - environments() []coder.Environment + workspaces() []coder.Workspace } type userGrouping struct { - user coder.User - envs []coder.Environment + user coder.User + userWorkspaces []coder.Workspace } -func (u userGrouping) environments() []coder.Environment { - return u.envs +func (u userGrouping) workspaces() []coder.Workspace { + return u.userWorkspaces } func (u userGrouping) header() string { @@ -236,12 +236,12 @@ func (u userGrouping) header() string { } type orgGrouping struct { - org coder.Organization - envs []coder.Environment + org coder.Organization + orgWorkspaces []coder.Workspace } -func (o orgGrouping) environments() []coder.Environment { - return o.envs +func (o orgGrouping) workspaces() []coder.Workspace { + return o.orgWorkspaces } func (o orgGrouping) header() string { @@ -253,29 +253,29 @@ func (o orgGrouping) header() string { } type providerGrouping struct { - provider coder.KubernetesProvider - envs []coder.Environment + provider coder.KubernetesProvider + providerWorkspaces []coder.Workspace } -func (p providerGrouping) environments() []coder.Environment { - return p.envs +func (p providerGrouping) workspaces() []coder.Workspace { + return p.providerWorkspaces } func (p providerGrouping) header() string { return fmt.Sprintf("%s\t", truncate(p.provider.Name, 20, "...")) } -func printResourceTop(writer io.Writer, groups []groupable, labeler envLabeler, showEmptyGroups bool, sortBy string) error { +func printResourceTop(writer io.Writer, groups []groupable, labeler workspaceLabeler, showEmptyGroups bool, sortBy string) error { tabwriter := tabwriter.NewWriter(writer, 0, 0, 4, ' ', 0) defer func() { _ = tabwriter.Flush() }() var userResources []aggregatedResources for _, group := range groups { - if !showEmptyGroups && len(group.environments()) < 1 { + if !showEmptyGroups && len(group.workspaces()) < 1 { continue } userResources = append(userResources, aggregatedResources{ - groupable: group, resources: aggregateEnvResources(group.environments()), + groupable: group, resources: aggregateWorkspaceResources(group.workspaces()), }) } @@ -287,19 +287,19 @@ func printResourceTop(writer io.Writer, groups []groupable, labeler envLabeler, for _, u := range userResources { _, _ = fmt.Fprintf(tabwriter, "%s\t%s", u.header(), u.resources) if verbose { - if len(u.environments()) > 0 { + if len(u.workspaces()) > 0 { _, _ = fmt.Fprintf(tabwriter, "\f") } - for _, env := range u.environments() { + for _, workspace := range u.workspaces() { _, _ = fmt.Fprintf(tabwriter, "\t") - _, _ = fmt.Fprintln(tabwriter, fmtEnvResources(env, labeler)) + _, _ = fmt.Fprintln(tabwriter, fmtWorkspaceResources(workspace, labeler)) } } _, _ = fmt.Fprint(tabwriter, "\n") } if len(userResources) == 0 { clog.LogInfo( - "no groups for the given filters exist with active environments", + "no groups for the given filters exist with active workspaces", clog.Tipf("run \"--show-empty\" to see groups with no resources."), ) } @@ -322,12 +322,12 @@ func sortAggregatedResources(resources []aggregatedResources, sortBy string) err return xerrors.Errorf("unknown --sort-by value of \"%s\"", sortBy) } for _, group := range resources { - envs := group.environments() + workspaces := group.workspaces() switch sortBy { case cpu: - sort.Slice(envs, func(i, j int) bool { return envs[i].CPUCores > envs[j].CPUCores }) + sort.Slice(workspaces, func(i, j int) bool { return workspaces[i].CPUCores > workspaces[j].CPUCores }) case memory: - sort.Slice(envs, func(i, j int) bool { return envs[i].MemoryGB > envs[j].MemoryGB }) + sort.Slice(workspaces, func(i, j int) bool { return workspaces[i].MemoryGB > workspaces[j].MemoryGB }) default: return xerrors.Errorf("unknown --sort-by value of \"%s\"", sortBy) } @@ -340,28 +340,28 @@ type aggregatedResources struct { resources } -func resourcesFromEnv(env coder.Environment) resources { +func resourcesFromWorkspace(workspace coder.Workspace) resources { return resources{ - cpuAllocation: env.CPUCores, - cpuUtilization: env.LatestStat.CPUUsage, - memAllocation: env.MemoryGB, - memUtilization: env.LatestStat.MemoryUsage, + cpuAllocation: workspace.CPUCores, + cpuUtilization: workspace.LatestStat.CPUUsage, + memAllocation: workspace.MemoryGB, + memUtilization: workspace.LatestStat.MemoryUsage, } } -func fmtEnvResources(env coder.Environment, labeler envLabeler) string { - return fmt.Sprintf("%s\t%s\t%s", truncate(env.Name, 20, "..."), resourcesFromEnv(env), labeler.label(env)) +func fmtWorkspaceResources(workspace coder.Workspace, labeler workspaceLabeler) string { + return fmt.Sprintf("%s\t%s\t%s", truncate(workspace.Name, 20, "..."), resourcesFromWorkspace(workspace), labeler.label(workspace)) } -type envLabeler interface { - label(coder.Environment) string +type workspaceLabeler interface { + label(coder.Workspace) string } -func labelAll(labels ...envLabeler) envLabeler { return multiLabeler(labels) } +func labelAll(labels ...workspaceLabeler) workspaceLabeler { return multiLabeler(labels) } -type multiLabeler []envLabeler +type multiLabeler []workspaceLabeler -func (m multiLabeler) label(e coder.Environment) string { +func (m multiLabeler) label(e coder.Workspace) string { var str strings.Builder for i, labeler := range m { if i != 0 { @@ -374,31 +374,31 @@ func (m multiLabeler) label(e coder.Environment) string { type orgLabeler map[string]coder.Organization -func (o orgLabeler) label(e coder.Environment) string { +func (o orgLabeler) label(e coder.Workspace) string { return fmt.Sprintf("[org: %s]", o[e.OrganizationID].Name) } type imgLabeler map[string]*coder.Image -func (i imgLabeler) label(e coder.Environment) string { +func (i imgLabeler) label(e coder.Workspace) string { return fmt.Sprintf("[img: %s:%s]", i[e.ImageID].Repository, e.ImageTag) } type userLabeler map[string]coder.User -func (u userLabeler) label(e coder.Environment) string { +func (u userLabeler) label(e coder.Workspace) string { return fmt.Sprintf("[user: %s]", u[e.UserID].Email) } type providerLabeler map[string]coder.KubernetesProvider -func (p providerLabeler) label(e coder.Environment) string { +func (p providerLabeler) label(e coder.Workspace) string { return fmt.Sprintf("[provider: %s]", p[e.ResourcePoolID].Name) } -func aggregateEnvResources(envs []coder.Environment) resources { +func aggregateWorkspaceResources(workspaces []coder.Workspace) resources { var aggregate resources - for _, e := range envs { + for _, e := range workspaces { aggregate.cpuAllocation += e.CPUCores aggregate.cpuUtilization += e.LatestStat.CPUUsage aggregate.memAllocation += e.MemoryGB diff --git a/internal/cmd/resourcemanager_test.go b/internal/cmd/resourcemanager_test.go index 50c9156c..ffe3dbb9 100644 --- a/internal/cmd/resourcemanager_test.go +++ b/internal/cmd/resourcemanager_test.go @@ -85,7 +85,7 @@ func mockResourceTopEntities() entities { imageIDs := [...]string{randString(10), randString(10), randString(10)} providerIDs := [...]string{randString(10), randString(10), randString(10)} userIDs := [...]string{randString(10), randString(10), randString(10)} - envIDs := [...]string{randString(10), randString(10), randString(10), randString(10)} + workspaceIDs := [...]string{randString(10), randString(10), randString(10), randString(10)} return entities{ providers: []coder.KubernetesProvider{ @@ -126,47 +126,47 @@ func mockResourceTopEntities() entities { Members: []coder.OrganizationUser{{}, {}}, }, }, - envs: []coder.Environment{ + workspaces: []coder.Workspace{ { - ID: envIDs[0], + ID: workspaceIDs[0], ResourcePoolID: providerIDs[0], ImageID: imageIDs[0], OrganizationID: orgIDs[0], UserID: userIDs[0], - Name: "dev-env", + Name: "dev-workspace", ImageTag: "20.04", CPUCores: 12.2, MemoryGB: 64.4, - LatestStat: coder.EnvironmentStat{ - ContainerStatus: coder.EnvironmentOn, + LatestStat: coder.WorkspaceStat{ + ContainerStatus: coder.WorkspaceOn, }, }, { - ID: envIDs[1], + ID: workspaceIDs[1], ResourcePoolID: providerIDs[1], ImageID: imageIDs[1], OrganizationID: orgIDs[1], UserID: userIDs[1], - Name: "another-env", + Name: "another-workspace", ImageTag: "10.2", CPUCores: 4, MemoryGB: 16, - LatestStat: coder.EnvironmentStat{ - ContainerStatus: coder.EnvironmentOn, + LatestStat: coder.WorkspaceStat{ + ContainerStatus: coder.WorkspaceOn, }, }, { - ID: envIDs[2], + ID: workspaceIDs[2], ResourcePoolID: providerIDs[1], ImageID: imageIDs[1], OrganizationID: orgIDs[1], UserID: userIDs[1], - Name: "yet-another-env", + Name: "yet-another-workspace", ImageTag: "10.2", CPUCores: 100, MemoryGB: 2, - LatestStat: coder.EnvironmentStat{ - ContainerStatus: coder.EnvironmentOn, + LatestStat: coder.WorkspaceStat{ + ContainerStatus: coder.WorkspaceOn, }, }, }, diff --git a/internal/cmd/resourcemanager_test.golden b/internal/cmd/resourcemanager_test.golden index 0707bd1a..0bed13ee 100755 --- a/internal/cmd/resourcemanager_test.golden +++ b/internal/cmd/resourcemanager_test.golden @@ -1,32 +1,32 @@ === TEST: By User Second Random (second-random@coder.com) [cpu: 104.0] [mem: 18.0 GB] - yet-another-env [cpu: 100.0] [mem: 2.0 GB] [img: archlinux:10.2] [provider: underground] [org: NotSoSpecialOrg] - another-env [cpu: 4.0] [mem: 16.0 GB] [img: archlinux:10.2] [provider: underground] [org: NotSoSpecialOrg] + yet-another-workspace... [cpu: 100.0] [mem: 2.0 GB] [img: archlinux:10.2] [provider: underground] [org: NotSoSpecialOrg] + another-workspace [cpu: 4.0] [mem: 16.0 GB] [img: archlinux:10.2] [provider: underground] [org: NotSoSpecialOrg] Random (random@coder.com) [cpu: 12.2] [mem: 64.4 GB] - dev-env [cpu: 12.2] [mem: 64.4 GB] [img: ubuntu:20.04] [provider: mars] [org: SpecialOrg] + dev-workspace [cpu: 12.2] [mem: 64.4 GB] [img: ubuntu:20.04] [provider: mars] [org: SpecialOrg] === TEST: By Org NotSoSpecialOrg (2 members) [cpu: 104.0] [mem: 18.0 GB] - yet-another-env [cpu: 100.0] [mem: 2.0 GB] [img: archlinux:10.2] [user: second-random@coder.com] [provider: underground] - another-env [cpu: 4.0] [mem: 16.0 GB] [img: archlinux:10.2] [user: second-random@coder.com] [provider: underground] + yet-another-workspace... [cpu: 100.0] [mem: 2.0 GB] [img: archlinux:10.2] [user: second-random@coder.com] [provider: underground] + another-workspace [cpu: 4.0] [mem: 16.0 GB] [img: archlinux:10.2] [user: second-random@coder.com] [provider: underground] SpecialOrg (2 members) [cpu: 12.2] [mem: 64.4 GB] - dev-env [cpu: 12.2] [mem: 64.4 GB] [img: ubuntu:20.04] [user: random@coder.com] [provider: mars] + dev-workspace [cpu: 12.2] [mem: 64.4 GB] [img: ubuntu:20.04] [user: random@coder.com] [provider: mars] === TEST: By Provider underground [cpu: 104.0] [mem: 18.0 GB] - yet-another-env [cpu: 100.0] [mem: 2.0 GB] [img: archlinux:10.2] [user: second-random@coder.com] - another-env [cpu: 4.0] [mem: 16.0 GB] [img: archlinux:10.2] [user: second-random@coder.com] + yet-another-workspace... [cpu: 100.0] [mem: 2.0 GB] [img: archlinux:10.2] [user: second-random@coder.com] + another-workspace [cpu: 4.0] [mem: 16.0 GB] [img: archlinux:10.2] [user: second-random@coder.com] mars [cpu: 12.2] [mem: 64.4 GB] - dev-env [cpu: 12.2] [mem: 64.4 GB] [img: ubuntu:20.04] [user: random@coder.com] + dev-workspace [cpu: 12.2] [mem: 64.4 GB] [img: ubuntu:20.04] [user: random@coder.com] === TEST: Sort By Memory Random (random@coder.com) [cpu: 12.2] [mem: 64.4 GB] - dev-env [cpu: 12.2] [mem: 64.4 GB] [img: ubuntu:20.04] [provider: mars] [org: SpecialOrg] + dev-workspace [cpu: 12.2] [mem: 64.4 GB] [img: ubuntu:20.04] [provider: mars] [org: SpecialOrg] Second Random (second-random@coder.com) [cpu: 104.0] [mem: 18.0 GB] - another-env [cpu: 4.0] [mem: 16.0 GB] [img: archlinux:10.2] [provider: underground] [org: NotSoSpecialOrg] - yet-another-env [cpu: 100.0] [mem: 2.0 GB] [img: archlinux:10.2] [provider: underground] [org: NotSoSpecialOrg] + another-workspace [cpu: 4.0] [mem: 16.0 GB] [img: archlinux:10.2] [provider: underground] [org: NotSoSpecialOrg] + yet-another-workspace... [cpu: 100.0] [mem: 2.0 GB] [img: archlinux:10.2] [provider: underground] [org: NotSoSpecialOrg] diff --git a/internal/cmd/ssh.go b/internal/cmd/ssh.go index 34478e0a..cec588a6 100644 --- a/internal/cmd/ssh.go +++ b/internal/cmd/ssh.go @@ -22,8 +22,8 @@ var ( func sshCmd() *cobra.Command { cmd := cobra.Command{ - Use: "ssh [environment_name] []", - Short: "Enter a shell of execute a command over SSH into a Coder environment", + Use: "ssh [workspace_name] []", + Short: "Enter a shell of execute a command over SSH into a Coder workspace", Args: shValidArgs, Example: `coder ssh my-dev coder ssh my-dev pwd`, @@ -45,18 +45,18 @@ func shell(cmd *cobra.Command, args []string) error { if err != nil { return err } - env, err := findEnv(ctx, client, args[0], coder.Me) + workspace, err := findWorkspace(ctx, client, args[0], coder.Me) if err != nil { return err } - if env.LatestStat.ContainerStatus != coder.EnvironmentOn { - return clog.Error("environment not available", - fmt.Sprintf("current status: \"%s\"", env.LatestStat.ContainerStatus), + if workspace.LatestStat.ContainerStatus != coder.WorkspaceOn { + return clog.Error("workspace not available", + fmt.Sprintf("current status: \"%s\"", workspace.LatestStat.ContainerStatus), clog.BlankLine, - clog.Tipf("use \"coder envs rebuild %s\" to rebuild this environment", env.Name), + clog.Tipf("use \"coder workspaces rebuild %s\" to rebuild this workspace", workspace.Name), ) } - wp, err := client.WorkspaceProviderByID(ctx, env.ResourcePoolID) + wp, err := client.WorkspaceProviderByID(ctx, workspace.ResourcePoolID) if err != nil { return err } @@ -77,7 +77,7 @@ func shell(cmd *cobra.Command, args []string) error { } ssh := exec.CommandContext(ctx, "ssh", "-i"+privateKeyFilepath, - fmt.Sprintf("%s-%s@%s", me.Username, env.Name, u.Hostname()), + fmt.Sprintf("%s-%s@%s", me.Username, workspace.Name, u.Hostname()), ) if len(args) > 1 { ssh.Args = append(ssh.Args, args[1:]...) @@ -101,17 +101,17 @@ func shValidArgs(cmd *cobra.Command, args []string) error { if err != nil { client, err := newClient(ctx, true) if err != nil { - return clog.Error("missing [environment_name] argument") + return clog.Error("missing [workspace_name] argument") } - _, haystack, err := searchForEnv(ctx, client, "", coder.Me) + _, haystack, err := searchForWorkspace(ctx, client, "", coder.Me) if err != nil { - return clog.Error("missing [environment_name] argument", + return clog.Error("missing [workspace_name] argument", fmt.Sprintf("specify one of %q", haystack), clog.BlankLine, - clog.Tipf("run \"coder envs ls\" to view your environments"), + clog.Tipf("run \"coder workspaces ls\" to view your workspaces"), ) } - return clog.Error("missing [environment_name] argument") + return clog.Error("missing [workspace_name] argument") } return nil } diff --git a/internal/cmd/sync.go b/internal/cmd/sync.go index 922f2679..eadb3853 100644 --- a/internal/cmd/sync.go +++ b/internal/cmd/sync.go @@ -20,8 +20,8 @@ import ( func syncCmd() *cobra.Command { var init bool cmd := &cobra.Command{ - Use: "sync [local directory] [:]", - Short: "Establish a one way directory sync to a Coder environment", + Use: "sync [local directory] [:]", + Short: "Establish a one way directory sync to a Coder workspace", Args: xcobra.ExactArgs(2), RunE: makeRunSync(&init), } @@ -64,11 +64,11 @@ func makeRunSync(init *bool) func(cmd *cobra.Command, args []string) error { return xerrors.New("remote malformatted") } var ( - envName = remoteTokens[0] - remoteDir = remoteTokens[1] + workspaceName = remoteTokens[0] + remoteDir = remoteTokens[1] ) - env, err := findEnv(ctx, client, envName, coder.Me) + workspace, err := findWorkspace(ctx, client, workspaceName, coder.Me) if err != nil { return err } @@ -78,7 +78,7 @@ func makeRunSync(init *bool) func(cmd *cobra.Command, args []string) error { return err } if info.Mode().IsRegular() { - return sync.SingleFile(ctx, local, remoteDir, env, client) + return sync.SingleFile(ctx, local, remoteDir, workspace, client) } if !info.IsDir() { return xerrors.Errorf("local path must lead to a regular file or directory: %w", err) @@ -91,7 +91,7 @@ func makeRunSync(init *bool) func(cmd *cobra.Command, args []string) error { s := sync.Sync{ Init: *init, - Env: *env, + Workspace: *workspace, RemoteDir: remoteDir, LocalDir: absLocal, Client: client, diff --git a/internal/cmd/tags.go b/internal/cmd/tags.go index 201133b0..24a7affa 100644 --- a/internal/cmd/tags.go +++ b/internal/cmd/tags.go @@ -36,7 +36,7 @@ func tagsCreateCmd() *cobra.Command { cmd := &cobra.Command{ Use: "create [tag]", Short: "add an image tag", - Long: "allow users to create environments with this image tag", + Long: "allow users to create workspaces with this image tag", Example: `coder tags create latest --image ubuntu --org default`, Args: xcobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { diff --git a/internal/cmd/tokens.go b/internal/cmd/tokens.go index 0763a5b0..a014f546 100644 --- a/internal/cmd/tokens.go +++ b/internal/cmd/tokens.go @@ -17,7 +17,7 @@ func tokensCmd() *cobra.Command { Use: "tokens", Short: "manage Coder API tokens for the active user", Long: "Create and manage API Tokens for authenticating the CLI.\n" + - "Statically authenticate using the token value with the " + "`" + "CODER_TOKEN" + "`" + " and " + "`" + "CODER_URL" + "`" + " environment variables.", + "Statically authenticate using the token value with the " + "`" + "CODER_TOKEN" + "`" + " and " + "`" + "CODER_URL" + "`" + " workspace variables.", } cmd.AddCommand( lsTokensCmd(), diff --git a/internal/cmd/tunnel.go b/internal/cmd/tunnel.go index 09463589..ae7fe14c 100644 --- a/internal/cmd/tunnel.go +++ b/internal/cmd/tunnel.go @@ -55,19 +55,19 @@ coder tunnel my-dev 3000 3000 } baseURL := sdk.BaseURL() - envs, err := getEnvs(ctx, sdk, coder.Me) + workspaces, err := getWorkspaces(ctx, sdk, coder.Me) if err != nil { return xerrors.Errorf("get workspaces: %w", err) } - var envID string - for _, env := range envs { - if env.Name == args[0] { - envID = env.ID + var workspaceID string + for _, workspace := range workspaces { + if workspace.Name == args[0] { + workspaceID = workspace.ID break } } - if envID == "" { + if workspaceID == "" { return xerrors.Errorf("No workspace found by name '%s'", args[0]) } @@ -75,7 +75,7 @@ coder tunnel my-dev 3000 3000 log: log, brokerAddr: &baseURL, token: sdk.Token(), - workspaceID: envID, + workspaceID: workspaceID, stdio: args[2] == "stdio", localPort: uint16(localPort), remotePort: uint16(remotePort), diff --git a/internal/cmd/urls.go b/internal/cmd/urls.go index 64836229..b6730d34 100644 --- a/internal/cmd/urls.go +++ b/internal/cmd/urls.go @@ -21,18 +21,18 @@ func urlCmd() *cobra.Command { var outputFmt string cmd := &cobra.Command{ Use: "urls", - Short: "Interact with environment DevURLs", + Short: "Interact with workspace DevURLs", } lsCmd := &cobra.Command{ - Use: "ls [environment_name]", - Short: "List all DevURLs for an environment", + Use: "ls [workspace_name]", + Short: "List all DevURLs for a workspace", Args: xcobra.ExactArgs(1), RunE: listDevURLsCmd(&outputFmt), } lsCmd.Flags().StringVarP(&outputFmt, "output", "o", humanOutput, "human|json") rmCmd := &cobra.Command{ - Use: "rm [environment_name] [port]", + Use: "rm [workspace_name] [port]", Args: cobra.ExactArgs(2), Short: "Remove a dev url", RunE: removeDevURL, @@ -77,7 +77,7 @@ func accessLevelIsValid(level string) bool { } // Run gets the list of active devURLs from the cemanager for the -// specified environment and outputs info to stdout. +// specified workspace and outputs info to stdout. func listDevURLsCmd(outputFmt *string) func(cmd *cobra.Command, args []string) error { return func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() @@ -85,9 +85,9 @@ func listDevURLsCmd(outputFmt *string) func(cmd *cobra.Command, args []string) e if err != nil { return err } - envName := args[0] + workspaceName := args[0] - devURLs, err := urlList(ctx, client, envName) + devURLs, err := urlList(ctx, client, workspaceName) if err != nil { return err } @@ -95,7 +95,7 @@ func listDevURLsCmd(outputFmt *string) func(cmd *cobra.Command, args []string) e switch *outputFmt { case humanOutput: if len(devURLs) < 1 { - clog.LogInfo(fmt.Sprintf("no devURLs found for environment %q", envName)) + clog.LogInfo(fmt.Sprintf("no devURLs found for workspace %q", workspaceName)) return nil } err := tablewriter.WriteTable(cmd.OutOrStdout(), len(devURLs), func(i int) interface{} { @@ -129,9 +129,9 @@ func createDevURLCmd() *cobra.Command { Example: `coder urls create my-workspace 8080 --name my-dev-url`, RunE: func(cmd *cobra.Command, args []string) error { var ( - envName = args[0] - port = args[1] - ctx = cmd.Context() + workspaceName = args[0] + port = args[1] + ctx = cmd.Context() ) portNum, err := validatePort(port) @@ -152,36 +152,36 @@ func createDevURLCmd() *cobra.Command { return err } - env, err := findEnv(ctx, client, envName, coder.Me) + workspace, err := findWorkspace(ctx, client, workspaceName, coder.Me) if err != nil { return err } - urls, err := urlList(ctx, client, envName) + urls, err := urlList(ctx, client, workspaceName) if err != nil { return err } urlID, found := devURLID(portNum, urls) if found { - err := client.PutDevURL(ctx, env.ID, urlID, coder.PutDevURLReq{ - Port: portNum, - Name: urlname, - Access: access, - EnvID: env.ID, - Scheme: scheme, + err := client.PutDevURL(ctx, workspace.ID, urlID, coder.PutDevURLReq{ + Port: portNum, + Name: urlname, + Access: access, + WorkspaceID: workspace.ID, + Scheme: scheme, }) if err != nil { return xerrors.Errorf("update DevURL: %w", err) } clog.LogSuccess(fmt.Sprintf("patched devurl for port %s", port)) } else { - err := client.CreateDevURL(ctx, env.ID, coder.CreateDevURLReq{ - Port: portNum, - Name: urlname, - Access: access, - EnvID: env.ID, - Scheme: scheme, + err := client.CreateDevURL(ctx, workspace.ID, coder.CreateDevURLReq{ + Port: portNum, + Name: urlname, + Access: access, + WorkspaceID: workspace.ID, + Scheme: scheme, }) if err != nil { return xerrors.Errorf("insert DevURL: %w", err) @@ -203,7 +203,7 @@ func createDevURLCmd() *cobra.Command { // consist solely of letters and digits, with a max length of 64 chars. var devURLNameValidRx = regexp.MustCompile("^[a-zA-Z][a-zA-Z0-9]{0,63}$") -// devURLID returns the ID of a devURL, given the env name and port +// devURLID returns the ID of a devURL, given the workspace name and port // from a list of DevURL records. // ("", false) is returned if no match is found. func devURLID(port int, urls []coder.DevURL) (string, bool) { @@ -215,12 +215,12 @@ func devURLID(port int, urls []coder.DevURL) (string, bool) { return "", false } -// Run deletes a devURL, specified by env ID and port, from the cemanager. +// Run deletes a devURL, specified by workspace ID and port, from the cemanager. func removeDevURL(cmd *cobra.Command, args []string) error { var ( - envName = args[0] - port = args[1] - ctx = cmd.Context() + workspaceName = args[0] + port = args[1] + ctx = cmd.Context() ) portNum, err := validatePort(port) @@ -232,12 +232,12 @@ func removeDevURL(cmd *cobra.Command, args []string) error { if err != nil { return err } - env, err := findEnv(ctx, client, envName, coder.Me) + workspace, err := findWorkspace(ctx, client, workspaceName, coder.Me) if err != nil { return err } - urls, err := urlList(ctx, client, envName) + urls, err := urlList(ctx, client, workspaceName) if err != nil { return err } @@ -249,17 +249,17 @@ func removeDevURL(cmd *cobra.Command, args []string) error { return xerrors.Errorf("No devurl found for port %v", port) } - if err := client.DeleteDevURL(ctx, env.ID, urlID); err != nil { + if err := client.DeleteDevURL(ctx, workspace.ID, urlID); err != nil { return xerrors.Errorf("delete DevURL: %w", err) } return nil } // urlList returns the list of active devURLs from the cemanager. -func urlList(ctx context.Context, client coder.Client, envName string) ([]coder.DevURL, error) { - env, err := findEnv(ctx, client, envName, coder.Me) +func urlList(ctx context.Context, client coder.Client, workspaceName string) ([]coder.DevURL, error) { + workspace, err := findWorkspace(ctx, client, workspaceName, coder.Me) if err != nil { return nil, err } - return client.DevURLs(ctx, env.ID) + return client.DevURLs(ctx, workspace.ID) } diff --git a/internal/cmd/envs.go b/internal/cmd/workspaces.go similarity index 60% rename from internal/cmd/envs.go rename to internal/cmd/workspaces.go index 352b2567..2660dc3e 100644 --- a/internal/cmd/envs.go +++ b/internal/cmd/workspaces.go @@ -21,22 +21,31 @@ import ( const defaultImgTag = "latest" -func envsCmd() *cobra.Command { +func envCmd() *cobra.Command { + cmd := workspacesCmd() + cmd.Use = "envs" + cmd.Deprecated = "use \"workspaces\" instead" + cmd.Aliases = []string{} + return cmd +} + +func workspacesCmd() *cobra.Command { cmd := &cobra.Command{ - Use: "envs", - Short: "Interact with Coder environments", - Long: "Perform operations on the Coder environments owned by the active user.", + Use: "workspaces", + Short: "Interact with Coder workspaces", + Long: "Perform operations on the Coder workspaces owned by the active user.", + Aliases: []string{"ws"}, } cmd.AddCommand( - lsEnvsCommand(), - stopEnvsCmd(), - rmEnvsCmd(), + lsWorkspacesCommand(), + stopWorkspacesCmd(), + rmWorkspacesCmd(), watchBuildLogCommand(), - rebuildEnvCommand(), - createEnvCmd(), - createEnvFromConfigCmd(), - editEnvCmd(), + rebuildWorkspaceCommand(), + createWorkspaceCmd(), + createWorkspaceFromConfigCmd(), + editWorkspaceCmd(), ) return cmd } @@ -46,7 +55,7 @@ const ( jsonOutput = "json" ) -func lsEnvsCommand() *cobra.Command { +func lsWorkspacesCommand() *cobra.Command { var ( outputFmt string user string @@ -55,45 +64,45 @@ func lsEnvsCommand() *cobra.Command { cmd := &cobra.Command{ Use: "ls", - Short: "list all environments owned by the active user", - Long: "List all Coder environments owned by the active user.", + Short: "list all workspaces owned by the active user", + Long: "List all Coder workspaces owned by the active user.", RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() client, err := newClient(ctx, true) if err != nil { return err } - envs, err := getEnvs(ctx, client, user) + workspaces, err := getWorkspaces(ctx, client, user) if err != nil { return err } if provider != "" { - envs, err = getEnvsByProvider(ctx, client, provider, user) + workspaces, err = getWorkspacesByProvider(ctx, client, provider, user) if err != nil { return err } } - if len(envs) < 1 { - clog.LogInfo("no environments found") - envs = []coder.Environment{} // ensures that json output still marshals + if len(workspaces) < 1 { + clog.LogInfo("no workspaces found") + workspaces = []coder.Workspace{} // ensures that json output still marshals } switch outputFmt { case humanOutput: - envs, err := coderutil.EnvsHumanTable(ctx, client, envs) + workspaces, err := coderutil.WorkspacesHumanTable(ctx, client, workspaces) if err != nil { return err } - err = tablewriter.WriteTable(cmd.OutOrStdout(), len(envs), func(i int) interface{} { - return envs[i] + err = tablewriter.WriteTable(cmd.OutOrStdout(), len(workspaces), func(i int) interface{} { + return workspaces[i] }) if err != nil { return xerrors.Errorf("write table: %w", err) } case jsonOutput: - err := json.NewEncoder(cmd.OutOrStdout()).Encode(envs) + err := json.NewEncoder(cmd.OutOrStdout()).Encode(workspaces) if err != nil { - return xerrors.Errorf("write environments as JSON: %w", err) + return xerrors.Errorf("write workspaces as JSON: %w", err) } default: return xerrors.Errorf("unknown --output value %q", outputFmt) @@ -104,27 +113,27 @@ func lsEnvsCommand() *cobra.Command { cmd.Flags().StringVar(&user, "user", coder.Me, "Specify the user whose resources to target") cmd.Flags().StringVarP(&outputFmt, "output", "o", humanOutput, "human | json") - cmd.Flags().StringVarP(&provider, "provider", "p", "", "Filter environments by a particular workspace provider name.") + cmd.Flags().StringVarP(&provider, "provider", "p", "", "Filter workspaces by a particular workspace provider name.") return cmd } -func stopEnvsCmd() *cobra.Command { +func stopWorkspacesCmd() *cobra.Command { var user string cmd := &cobra.Command{ - Use: "stop [...environment_names]", - Short: "stop Coder environments by name", - Long: "Stop Coder environments by name", - Example: `coder envs stop front-end-env -coder envs stop front-end-env backend-env + Use: "stop [...workspace_names]", + Short: "stop Coder workspaces by name", + Long: "Stop Coder workspaces by name", + Example: `coder workspaces stop front-end-workspace +coder workspaces stop front-end-workspace backend-workspace -# stop all of your environments -coder envs ls -o json | jq -c '.[].name' | xargs coder envs stop +# stop all of your workspaces +coder workspaces ls -o json | jq -c '.[].name' | xargs coder workspaces stop -# stop all environments for a given user -coder envs --user charlie@coder.com ls -o json \ +# stop all workspaces for a given user +coder workspaces --user charlie@coder.com ls -o json \ | jq -c '.[].name' \ - | xargs coder envs --user charlie@coder.com stop`, + | xargs coder workspaces --user charlie@coder.com stop`, Args: cobra.MinimumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() @@ -134,21 +143,21 @@ coder envs --user charlie@coder.com ls -o json \ } egroup := clog.LoggedErrGroup() - for _, envName := range args { - envName := envName + for _, workspaceName := range args { + workspaceName := workspaceName egroup.Go(func() error { - env, err := findEnv(ctx, client, envName, user) + workspace, err := findWorkspace(ctx, client, workspaceName, user) if err != nil { return err } - if err = client.StopEnvironment(ctx, env.ID); err != nil { - return clog.Error(fmt.Sprintf("stop environment %q", env.Name), + if err = client.StopWorkspace(ctx, workspace.ID); err != nil { + return clog.Error(fmt.Sprintf("stop workspace %q", workspace.Name), clog.Causef(err.Error()), clog.BlankLine, - clog.Hintf("current environment status is %q", env.LatestStat.ContainerStatus), + clog.Hintf("current workspace status is %q", workspace.LatestStat.ContainerStatus), ) } - clog.LogSuccess(fmt.Sprintf("successfully stopped environment %q", envName)) + clog.LogSuccess(fmt.Sprintf("successfully stopped workspace %q", workspaceName)) return nil }) } @@ -160,7 +169,7 @@ coder envs --user charlie@coder.com ls -o json \ return cmd } -func createEnvCmd() *cobra.Command { +func createWorkspaceCmd() *cobra.Command { var ( org string cpu float32 @@ -176,13 +185,13 @@ func createEnvCmd() *cobra.Command { ) cmd := &cobra.Command{ - Use: "create [environment_name]", - Short: "create a new environment.", + Use: "create [workspace_name]", + Short: "create a new workspace.", Args: xcobra.ExactArgs(1), - Long: "Create a new Coder environment.", - Example: `# create a new environment using default resource amounts -coder envs create my-new-env --image ubuntu -coder envs create my-new-powerful-env --cpu 12 --disk 100 --memory 16 --image ubuntu`, + Long: "Create a new Coder workspace.", + Example: `# create a new workspace using default resource amounts +coder workspaces create my-new-workspace --image ubuntu +coder workspaces create my-new-powerful-workspace --cpu 12 --disk 100 --memory 16 --image ubuntu`, RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() if img == "" { @@ -225,7 +234,7 @@ coder envs create my-new-powerful-env --cpu 12 --disk 100 --memory 16 --image ub } // ExactArgs(1) ensures our name value can't panic on an out of bounds. - createReq := &coder.CreateEnvironmentRequest{ + createReq := &coder.CreateWorkspaceRequest{ Name: args[0], ImageID: importedImg.ID, OrgID: importedImg.OrganizationID, @@ -252,66 +261,66 @@ coder envs create my-new-powerful-env --cpu 12 --disk 100 --memory 16 --image ub createReq.DiskGB = importedImg.DefaultDiskGB } - env, err := client.CreateEnvironment(ctx, *createReq) + workspace, err := client.CreateWorkspace(ctx, *createReq) if err != nil { - return xerrors.Errorf("create environment: %w", err) + return xerrors.Errorf("create workspace: %w", err) } if follow { - clog.LogSuccess("creating environment...") - if err := trailBuildLogs(ctx, client, env.ID); err != nil { + clog.LogSuccess("creating workspace...") + if err := trailBuildLogs(ctx, client, workspace.ID); err != nil { return err } return nil } - clog.LogSuccess("creating environment...", + clog.LogSuccess("creating workspace...", clog.BlankLine, - clog.Tipf(`run "coder envs watch-build %s" to trail the build logs`, env.Name), + clog.Tipf(`run "coder workspaces watch-build %s" to trail the build logs`, workspace.Name), ) return nil }, } - cmd.Flags().StringVarP(&org, "org", "o", "", "name of the organization the environment should be created under.") - cmd.Flags().StringVarP(&tag, "tag", "t", defaultImgTag, "tag of the image the environment will be based off of.") - cmd.Flags().Float32VarP(&cpu, "cpu", "c", 0, "number of cpu cores the environment should be provisioned with.") - cmd.Flags().Float32VarP(&memory, "memory", "m", 0, "GB of RAM an environment should be provisioned with.") - cmd.Flags().IntVarP(&disk, "disk", "d", 0, "GB of disk storage an environment should be provisioned with.") - cmd.Flags().IntVarP(&gpus, "gpus", "g", 0, "number GPUs an environment should be provisioned with.") - cmd.Flags().StringVarP(&img, "image", "i", "", "name of the image to base the environment off of.") - cmd.Flags().StringVar(&providerName, "provider", "", "name of Workspace Provider with which to create the environment") + cmd.Flags().StringVarP(&org, "org", "o", "", "name of the organization the workspace should be created under.") + cmd.Flags().StringVarP(&tag, "tag", "t", defaultImgTag, "tag of the image the workspace will be based off of.") + cmd.Flags().Float32VarP(&cpu, "cpu", "c", 0, "number of cpu cores the workspace should be provisioned with.") + cmd.Flags().Float32VarP(&memory, "memory", "m", 0, "GB of RAM a workspace should be provisioned with.") + cmd.Flags().IntVarP(&disk, "disk", "d", 0, "GB of disk storage a workspace should be provisioned with.") + cmd.Flags().IntVarP(&gpus, "gpus", "g", 0, "number GPUs a workspace should be provisioned with.") + cmd.Flags().StringVarP(&img, "image", "i", "", "name of the image to base the workspace off of.") + cmd.Flags().StringVar(&providerName, "provider", "", "name of Workspace Provider with which to create the workspace") cmd.Flags().BoolVar(&follow, "follow", false, "follow buildlog after initiating rebuild") - cmd.Flags().BoolVar(&useCVM, "container-based-vm", false, "deploy the environment as a Container-based VM") - cmd.Flags().BoolVar(&enableAutostart, "enable-autostart", false, "automatically start this environment at your preferred time.") + cmd.Flags().BoolVar(&useCVM, "container-based-vm", false, "deploy the workspace as a Container-based VM") + cmd.Flags().BoolVar(&enableAutostart, "enable-autostart", false, "automatically start this workspace at your preferred time.") _ = cmd.MarkFlagRequired("image") return cmd } -func createEnvFromConfigCmd() *cobra.Command { +func createWorkspaceFromConfigCmd() *cobra.Command { var ( - ref string - repo string - follow bool - filepath string - org string - providerName string - envName string + ref string + repo string + follow bool + filepath string + org string + providerName string + workspaceName string ) cmd := &cobra.Command{ Use: "create-from-config", - Short: "create a new environment from a template", - Long: "Create a new Coder environment using a Workspaces As Code template.", - Example: `# create a new environment from git repository -coder envs create-from-config --name="dev-env" --repo-url https://github.com/cdr/m --ref my-branch -coder envs create-from-config --name="dev-env" -f coder.yaml`, + Short: "create a new workspace from a template", + Long: "Create a new Coder workspace using a Workspaces As Code template.", + Example: `# create a new workspace from git repository +coder workspaces create-from-config --name="dev-workspace" --repo-url https://github.com/cdr/m --ref my-branch +coder workspaces create-from-config --name="dev-workspace" -f coder.yaml`, RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() - if envName == "" { - return clog.Error("Must provide a environment name.", + if workspaceName == "" { + return clog.Error("Must provide a workspace name.", clog.BlankLine, - clog.Tipf("Use --name= to name your environment"), + clog.Tipf("Use --name= to name your workspace"), ) } @@ -378,43 +387,43 @@ coder envs create-from-config --name="dev-env" -f coder.yaml`, return xerrors.Errorf("default workspace provider: %w", err) } - env, err := client.CreateEnvironment(ctx, coder.CreateEnvironmentRequest{ + workspace, err := client.CreateWorkspace(ctx, coder.CreateWorkspaceRequest{ OrgID: userOrg.ID, TemplateID: version.TemplateID, ResourcePoolID: provider.ID, Namespace: provider.DefaultNamespace, - Name: envName, + Name: workspaceName, }) if err != nil { return handleAPIError(err) } if follow { - clog.LogSuccess("creating environment...") - if err := trailBuildLogs(ctx, client, env.ID); err != nil { + clog.LogSuccess("creating workspace...") + if err := trailBuildLogs(ctx, client, workspace.ID); err != nil { return err } return nil } - clog.LogSuccess("creating environment...", + clog.LogSuccess("creating workspace...", clog.BlankLine, - clog.Tipf(`run "coder envs watch-build %s" to trail the build logs`, env.Name), + clog.Tipf(`run "coder workspaces watch-build %s" to trail the build logs`, workspace.Name), ) return nil }, } - cmd.Flags().StringVarP(&org, "org", "o", "", "name of the organization the environment should be created under.") + cmd.Flags().StringVarP(&org, "org", "o", "", "name of the organization the workspace should be created under.") cmd.Flags().StringVarP(&filepath, "filepath", "f", "", "path to local template file.") cmd.Flags().StringVarP(&ref, "ref", "", "master", "git reference to pull template from. May be a branch, tag, or commit hash.") cmd.Flags().StringVarP(&repo, "repo-url", "r", "", "URL of the git repository to pull the config from. Config file must live in '.coder/coder.yaml'.") cmd.Flags().BoolVar(&follow, "follow", false, "follow buildlog after initiating rebuild") - cmd.Flags().StringVar(&providerName, "provider", "", "name of Workspace Provider with which to create the environment") - cmd.Flags().StringVar(&envName, "name", "", "name of the environment to be created") + cmd.Flags().StringVar(&providerName, "provider", "", "name of Workspace Provider with which to create the workspace") + cmd.Flags().StringVar(&workspaceName, "name", "", "name of the workspace to be created") return cmd } -func editEnvCmd() *cobra.Command { +func editWorkspaceCmd() *cobra.Command { var ( org string img string @@ -430,12 +439,12 @@ func editEnvCmd() *cobra.Command { cmd := &cobra.Command{ Use: "edit", - Short: "edit an existing environment and initiate a rebuild.", + Short: "edit an existing workspace and initiate a rebuild.", Args: xcobra.ExactArgs(1), - Long: "Edit an existing environment and initate a rebuild.", - Example: `coder envs edit back-end-env --cpu 4 + Long: "Edit an existing workspace and initate a rebuild.", + Example: `coder workspaces edit back-end-workspace --cpu 4 -coder envs edit back-end-env --disk 20`, +coder workspaces edit back-end-workspace --disk 20`, RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() client, err := newClient(ctx, true) @@ -443,9 +452,9 @@ coder envs edit back-end-env --disk 20`, return err } - envName := args[0] + workspaceName := args[0] - env, err := findEnv(ctx, client, envName, user) + workspace, err := findWorkspace(ctx, client, workspaceName, user) if err != nil { return err } @@ -461,23 +470,23 @@ coder envs edit back-end-env --disk 20`, } req, err := buildUpdateReq(ctx, client, updateConf{ - cpu: cpu, - memGB: memory, - diskGB: disk, - gpus: gpus, - environment: env, - user: user, - image: img, - imageTag: tag, - orgName: org, + cpu: cpu, + memGB: memory, + diskGB: disk, + gpus: gpus, + workspace: workspace, + user: user, + image: img, + imageTag: tag, + orgName: org, }) if err != nil { return err } - if !force && env.LatestStat.ContainerStatus == coder.EnvironmentOn { + if !force && workspace.LatestStat.ContainerStatus == coder.WorkspaceOn { _, err = (&promptui.Prompt{ - Label: fmt.Sprintf("Rebuild environment %q? (will destroy any work outside of your home directory)", env.Name), + Label: fmt.Sprintf("Rebuild workspace %q? (will destroy any work outside of your home directory)", workspace.Name), IsConfirm: true, }).Run() if err != nil { @@ -488,47 +497,47 @@ coder envs edit back-end-env --disk 20`, } } - if err := client.EditEnvironment(ctx, env.ID, *req); err != nil { - return xerrors.Errorf("failed to apply changes to environment %q: %w", envName, err) + if err := client.EditWorkspace(ctx, workspace.ID, *req); err != nil { + return xerrors.Errorf("failed to apply changes to workspace %q: %w", workspaceName, err) } if follow { - clog.LogSuccess("applied changes to the environment, rebuilding...") - if err := trailBuildLogs(ctx, client, env.ID); err != nil { + clog.LogSuccess("applied changes to the workspace, rebuilding...") + if err := trailBuildLogs(ctx, client, workspace.ID); err != nil { return err } return nil } - clog.LogSuccess("applied changes to the environment, rebuilding...", + clog.LogSuccess("applied changes to the workspace, rebuilding...", clog.BlankLine, - clog.Tipf(`run "coder envs watch-build %s" to trail the build logs`, envName), + clog.Tipf(`run "coder workspaces watch-build %s" to trail the build logs`, workspaceName), ) return nil }, } - cmd.Flags().StringVarP(&org, "org", "o", "", "name of the organization the environment should be created under.") - cmd.Flags().StringVarP(&img, "image", "i", "", "name of the image you want the environment to be based off of.") - cmd.Flags().StringVarP(&tag, "tag", "t", "latest", "image tag of the image you want to base the environment off of.") - cmd.Flags().Float32VarP(&cpu, "cpu", "c", 0, "The number of cpu cores the environment should be provisioned with.") - cmd.Flags().Float32VarP(&memory, "memory", "m", 0, "The amount of RAM an environment should be provisioned with.") - cmd.Flags().IntVarP(&disk, "disk", "d", 0, "The amount of disk storage an environment should be provisioned with.") - cmd.Flags().IntVarP(&gpus, "gpu", "g", 0, "The amount of disk storage to provision the environment with.") + cmd.Flags().StringVarP(&org, "org", "o", "", "name of the organization the workspace should be created under.") + cmd.Flags().StringVarP(&img, "image", "i", "", "name of the image you want the workspace to be based off of.") + cmd.Flags().StringVarP(&tag, "tag", "t", "latest", "image tag of the image you want to base the workspace off of.") + cmd.Flags().Float32VarP(&cpu, "cpu", "c", 0, "The number of cpu cores the workspace should be provisioned with.") + cmd.Flags().Float32VarP(&memory, "memory", "m", 0, "The amount of RAM a workspace should be provisioned with.") + cmd.Flags().IntVarP(&disk, "disk", "d", 0, "The amount of disk storage a workspace should be provisioned with.") + cmd.Flags().IntVarP(&gpus, "gpu", "g", 0, "The amount of disk storage to provision the workspace with.") cmd.Flags().BoolVar(&follow, "follow", false, "follow buildlog after initiating rebuild") cmd.Flags().StringVar(&user, "user", coder.Me, "Specify the user whose resources to target") cmd.Flags().BoolVar(&force, "force", false, "force rebuild without showing a confirmation prompt") return cmd } -func rmEnvsCmd() *cobra.Command { +func rmWorkspacesCmd() *cobra.Command { var ( force bool user string ) cmd := &cobra.Command{ - Use: "rm [...environment_names]", - Short: "remove Coder environments by name", + Use: "rm [...workspace_names]", + Short: "remove Coder workspaces by name", Args: cobra.MinimumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() @@ -538,7 +547,7 @@ func rmEnvsCmd() *cobra.Command { } if !force { confirm := promptui.Prompt{ - Label: fmt.Sprintf("Delete environments %q? (all data will be lost)", args), + Label: fmt.Sprintf("Delete workspaces %q? (all data will be lost)", args), IsConfirm: true, } if _, err := confirm.Run(); err != nil { @@ -550,52 +559,52 @@ func rmEnvsCmd() *cobra.Command { } egroup := clog.LoggedErrGroup() - for _, envName := range args { - envName := envName + for _, workspaceName := range args { + workspaceName := workspaceName egroup.Go(func() error { - env, err := findEnv(ctx, client, envName, user) + workspace, err := findWorkspace(ctx, client, workspaceName, user) if err != nil { return err } - if err = client.DeleteEnvironment(ctx, env.ID); err != nil { + if err = client.DeleteWorkspace(ctx, workspace.ID); err != nil { return clog.Error( - fmt.Sprintf(`failed to delete environment "%s"`, env.Name), + fmt.Sprintf(`failed to delete workspace "%s"`, workspace.Name), clog.Causef(err.Error()), ) } - clog.LogSuccess(fmt.Sprintf("deleted environment %q", env.Name)) + clog.LogSuccess(fmt.Sprintf("deleted workspace %q", workspace.Name)) return nil }) } return egroup.Wait() }, } - cmd.Flags().BoolVarP(&force, "force", "f", false, "force remove the specified environments without prompting first") + cmd.Flags().BoolVarP(&force, "force", "f", false, "force remove the specified workspaces without prompting first") cmd.Flags().StringVar(&user, "user", coder.Me, "Specify the user whose resources to target") return cmd } type updateConf struct { - cpu float32 - memGB float32 - diskGB int - gpus int - environment *coder.Environment - user string - image string - imageTag string - orgName string + cpu float32 + memGB float32 + diskGB int + gpus int + workspace *coder.Workspace + user string + image string + imageTag string + orgName string } -func buildUpdateReq(ctx context.Context, client coder.Client, conf updateConf) (*coder.UpdateEnvironmentReq, error) { +func buildUpdateReq(ctx context.Context, client coder.Client, conf updateConf) (*coder.UpdateWorkspaceReq, error) { var ( - updateReq coder.UpdateEnvironmentReq + updateReq coder.UpdateWorkspaceReq defaultCPUCores float32 defaultMemGB float32 defaultDiskGB int ) - // If this is not empty it means the user is requesting to change the environment image. + // If this is not empty it means the user is requesting to change the workspace image. if conf.image != "" { importedImg, err := findImg(ctx, client, findImgConf{ email: conf.user, @@ -607,12 +616,12 @@ func buildUpdateReq(ctx context.Context, client coder.Client, conf updateConf) ( } // If the user passes an image arg of the image that - // the environment is already using, it was most likely a mistake. + // the workspace is already using, it was most likely a mistake. if conf.image != importedImg.Repository { - return nil, xerrors.Errorf("environment is already using image %q", conf.image) + return nil, xerrors.Errorf("workspace is already using image %q", conf.image) } - // Since the environment image is being changed, + // Since the workspace image is being changed, // the resource amount defaults should be changed to // reflect that of the default resource amounts of the new image. defaultCPUCores = importedImg.DefaultCPUCores @@ -620,17 +629,17 @@ func buildUpdateReq(ctx context.Context, client coder.Client, conf updateConf) ( defaultDiskGB = importedImg.DefaultDiskGB updateReq.ImageID = &importedImg.ID } else { - // if the environment image is not being changed, the default + // if the workspace image is not being changed, the default // resource amounts should reflect the default resource amounts - // of the image the environment is already using. - defaultCPUCores = conf.environment.CPUCores - defaultMemGB = conf.environment.MemoryGB - defaultDiskGB = conf.environment.DiskGB - updateReq.ImageID = &conf.environment.ImageID + // of the image the workspace is already using. + defaultCPUCores = conf.workspace.CPUCores + defaultMemGB = conf.workspace.MemoryGB + defaultDiskGB = conf.workspace.DiskGB + updateReq.ImageID = &conf.workspace.ImageID } // The following logic checks to see if the user specified - // any resource amounts for the environment that need to be changed. + // any resource amounts for the workspace that need to be changed. // If they did not, then we will get the zero value back // and should set the resource amount to the default. @@ -652,14 +661,14 @@ func buildUpdateReq(ctx context.Context, client coder.Client, conf updateConf) ( updateReq.DiskGB = &conf.diskGB } - // Environment disks can not be shrink so we have to overwrite this + // Workspace disks can not be shrink so we have to overwrite this // if the user accidentally requests it or if the default diskGB value for a - // newly requested image is smaller than the current amount the environment is using. - if *updateReq.DiskGB < conf.environment.DiskGB { + // newly requested image is smaller than the current amount the workspace is using. + if *updateReq.DiskGB < conf.workspace.DiskGB { clog.LogWarn("disk can not be shrunk", - fmt.Sprintf("keeping environment disk at %d GB", conf.environment.DiskGB), + fmt.Sprintf("keeping workspace disk at %d GB", conf.workspace.DiskGB), ) - updateReq.DiskGB = &conf.environment.DiskGB + updateReq.DiskGB = &conf.workspace.DiskGB } if conf.gpus != 0 { diff --git a/internal/cmd/envs_test.go b/internal/cmd/workspaces_test.go similarity index 61% rename from internal/cmd/envs_test.go rename to internal/cmd/workspaces_test.go index b28ea6c7..a8c1d6cd 100644 --- a/internal/cmd/envs_test.go +++ b/internal/cmd/workspaces_test.go @@ -17,19 +17,19 @@ import ( "cdr.dev/coder-cli/coder-sdk" ) -func Test_envs_ls(t *testing.T) { +func Test_workspaces_ls(t *testing.T) { skipIfNoAuth(t) - res := execute(t, nil, "envs", "ls") + res := execute(t, nil, "workspaces", "ls") res.success(t) - res = execute(t, nil, "envs", "ls", "--output=json") + res = execute(t, nil, "workspaces", "ls", "--output=json") res.success(t) - var envs []coder.Environment - res.stdoutUnmarshals(t, &envs) + var workspaces []coder.Workspace + res.stdoutUnmarshals(t, &workspaces) } -func Test_envs_ls_by_provider(t *testing.T) { +func Test_workspaces_ls_by_provider(t *testing.T) { skipIfNoAuth(t) for _, test := range []struct { name string @@ -38,15 +38,15 @@ func Test_envs_ls_by_provider(t *testing.T) { }{ { name: "simple list", - command: []string{"envs", "ls", "--provider", "built-in"}, + command: []string{"workspaces", "ls", "--provider", "built-in"}, assert: func(r result) { r.success(t) }, }, { name: "list as json", - command: []string{"envs", "ls", "--provider", "built-in", "--output", "json"}, + command: []string{"workspaces", "ls", "--provider", "built-in", "--output", "json"}, assert: func(r result) { - var envs []coder.Environment - r.stdoutUnmarshals(t, &envs) + var workspaces []coder.Workspace + r.stdoutUnmarshals(t, &workspaces) }, }, } { @@ -57,27 +57,27 @@ func Test_envs_ls_by_provider(t *testing.T) { } } -func Test_env_create(t *testing.T) { +func Test_workspace_create(t *testing.T) { skipIfNoAuth(t) ctx := context.Background() // Minimum args not received. - res := execute(t, nil, "envs", "create") + res := execute(t, nil, "workspaces", "create") res.error(t) res.stderrContains(t, "accepts 1 arg(s), received 0") // Successfully output help. - res = execute(t, nil, "envs", "create", "--help") + res = execute(t, nil, "workspaces", "create", "--help") res.success(t) - res.stdoutContains(t, "Create a new Coder environment.") + res.stdoutContains(t, "Create a new Coder workspace.") // Image unset - res = execute(t, nil, "envs", "create", "test-env") + res = execute(t, nil, "workspaces", "create", "test-workspace") res.error(t) res.stderrContains(t, "fatal: required flag(s) \"image\" not set") // Image not imported - res = execute(t, nil, "envs", "create", "test-env", "--image=doestexist") + res = execute(t, nil, "workspaces", "create", "test-workspace", "--image=doestexist") res.error(t) res.stderrContains(t, "fatal: image not found - did you forget to import this image?") @@ -86,49 +86,49 @@ func Test_env_create(t *testing.T) { name := randString(10) cpu := 2.3 - // attempt to remove the environment on cleanup - t.Cleanup(func() { _ = execute(t, nil, "envs", "rm", name, "--force") }) + // attempt to remove the workspace on cleanup + t.Cleanup(func() { _ = execute(t, nil, "workspaces", "rm", name, "--force") }) - res = execute(t, nil, "envs", "create", name, "--image=ubuntu", fmt.Sprintf("--cpu=%f", cpu)) + res = execute(t, nil, "workspaces", "create", name, "--image=ubuntu", fmt.Sprintf("--cpu=%f", cpu)) res.success(t) - res = execute(t, nil, "envs", "ls") + res = execute(t, nil, "workspaces", "ls") res.success(t) res.stdoutContains(t, name) - var envs []coder.Environment - res = execute(t, nil, "envs", "ls", "--output=json") + var workspaces []coder.Workspace + res = execute(t, nil, "workspaces", "ls", "--output=json") res.success(t) - res.stdoutUnmarshals(t, &envs) - env := assertEnv(t, name, envs) - assert.Equal(t, "env cpu", cpu, float64(env.CPUCores), floatComparer) + res.stdoutUnmarshals(t, &workspaces) + workspace := assertWorkspace(t, name, workspaces) + assert.Equal(t, "workspace cpu", cpu, float64(workspace.CPUCores), floatComparer) - res = execute(t, nil, "envs", "watch-build", name) + res = execute(t, nil, "workspaces", "watch-build", name) res.success(t) - // edit the CPU of the environment + // edit the CPU of the workspace cpu = 2.1 - res = execute(t, nil, "envs", "edit", name, fmt.Sprintf("--cpu=%f", cpu), "--follow", "--force") + res = execute(t, nil, "workspaces", "edit", name, fmt.Sprintf("--cpu=%f", cpu), "--follow", "--force") res.success(t) // assert that the CPU actually did change after edit - res = execute(t, nil, "envs", "ls", "--output=json") + res = execute(t, nil, "workspaces", "ls", "--output=json") res.success(t) - res.stdoutUnmarshals(t, &envs) - env = assertEnv(t, name, envs) - assert.Equal(t, "env cpu", cpu, float64(env.CPUCores), floatComparer) + res.stdoutUnmarshals(t, &workspaces) + workspace = assertWorkspace(t, name, workspaces) + assert.Equal(t, "workspace cpu", cpu, float64(workspace.CPUCores), floatComparer) - res = execute(t, nil, "envs", "rm", name, "--force") + res = execute(t, nil, "workspaces", "rm", name, "--force") res.success(t) } -func assertEnv(t *testing.T, name string, envs []coder.Environment) *coder.Environment { - for _, e := range envs { +func assertWorkspace(t *testing.T, name string, workspaces []coder.Workspace) *coder.Workspace { + for _, e := range workspaces { if name == e.Name { return &e } } - slogtest.Fatal(t, "env not found", slog.F("name", name), slog.F("envs", envs)) + slogtest.Fatal(t, "workspace not found", slog.F("name", name), slog.F("workspaces", workspaces)) return nil } diff --git a/internal/coderutil/env.go b/internal/coderutil/workspace.go similarity index 54% rename from internal/coderutil/env.go rename to internal/coderutil/workspace.go index 9485347f..b81ad964 100644 --- a/internal/coderutil/env.go +++ b/internal/coderutil/workspace.go @@ -13,34 +13,34 @@ import ( "cdr.dev/coder-cli/pkg/clog" ) -// DialEnvWsep dials the executor endpoint using the https://github.com/cdr/wsep message protocol. +// DialWorkspaceWsep dials the executor endpoint using the https://github.com/cdr/wsep message protocol. // The proper workspace provider envproxy access URL is used. -func DialEnvWsep(ctx context.Context, client coder.Client, env *coder.Environment) (*websocket.Conn, error) { - workspaceProvider, err := client.WorkspaceProviderByID(ctx, env.ResourcePoolID) +func DialWorkspaceWsep(ctx context.Context, client coder.Client, workspace *coder.Workspace) (*websocket.Conn, error) { + workspaceProvider, err := client.WorkspaceProviderByID(ctx, workspace.ResourcePoolID) if err != nil { - return nil, xerrors.Errorf("get env workspace provider: %w", err) + return nil, xerrors.Errorf("get workspace workspace provider: %w", err) } accessURL, err := url.Parse(workspaceProvider.EnvproxyAccessURL) if err != nil { return nil, xerrors.Errorf("invalid workspace provider envproxy access url: %w", err) } - conn, err := client.DialWsep(ctx, accessURL, env.ID) + conn, err := client.DialWsep(ctx, accessURL, workspace.ID) if err != nil { return nil, xerrors.Errorf("dial websocket: %w", err) } return conn, nil } -// EnvWithWorkspaceProvider composes an Environment entity with its associated WorkspaceProvider. -type EnvWithWorkspaceProvider struct { - Env coder.Environment +// WorkspaceWithWorkspaceProvider composes an Workspace entity with its associated WorkspaceProvider. +type WorkspaceWithWorkspaceProvider struct { + Workspace coder.Workspace WorkspaceProvider coder.KubernetesProvider } -// EnvsWithProvider performs the composition of each Environment with its associated WorkspaceProvider. -func EnvsWithProvider(ctx context.Context, client coder.Client, envs []coder.Environment) ([]EnvWithWorkspaceProvider, error) { - pooledEnvs := make([]EnvWithWorkspaceProvider, 0, len(envs)) +// WorkspacesWithProvider performs the composition of each Workspace with its associated WorkspaceProvider. +func WorkspacesWithProvider(ctx context.Context, client coder.Client, workspaces []coder.Workspace) ([]WorkspaceWithWorkspaceProvider, error) { + pooledWorkspaces := make([]WorkspaceWithWorkspaceProvider, 0, len(workspaces)) providers, err := client.WorkspaceProviders(ctx) if err != nil { return nil, err @@ -49,20 +49,20 @@ func EnvsWithProvider(ctx context.Context, client coder.Client, envs []coder.Env for _, p := range providers.Kubernetes { providerMap[p.ID] = p } - for _, e := range envs { - envProvider, ok := providerMap[e.ResourcePoolID] + for _, e := range workspaces { + workspaceProvider, ok := providerMap[e.ResourcePoolID] if !ok { - return nil, xerrors.Errorf("fetch env workspace provider: %w", coder.ErrNotFound) + return nil, xerrors.Errorf("fetch workspace workspace provider: %w", coder.ErrNotFound) } - pooledEnvs = append(pooledEnvs, EnvWithWorkspaceProvider{ - Env: e, - WorkspaceProvider: envProvider, + pooledWorkspaces = append(pooledWorkspaces, WorkspaceWithWorkspaceProvider{ + Workspace: e, + WorkspaceProvider: workspaceProvider, }) } - return pooledEnvs, nil + return pooledWorkspaces, nil } -// DefaultWorkspaceProvider returns the default provider with which to create environments. +// DefaultWorkspaceProvider returns the default provider with which to create workspaces. func DefaultWorkspaceProvider(ctx context.Context, c coder.Client) (*coder.KubernetesProvider, error) { provider, err := c.WorkspaceProviders(ctx) if err != nil { @@ -76,9 +76,9 @@ 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 +// WorkspaceTable defines an Workspace-like structure with associated entities composed in a human // readable form. -type EnvTable struct { +type WorkspaceTable struct { Name string `table:"Name"` Image string `table:"Image"` CPU float32 `table:"vCPU"` @@ -89,14 +89,14 @@ type EnvTable struct { 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) +// WorkspacesHumanTable performs the composition of each Workspace with its associated ProviderName and ImageRepo. +func WorkspacesHumanTable(ctx context.Context, client coder.Client, workspaces []coder.Workspace) ([]WorkspaceTable, error) { + imageMap, err := MakeImageMap(ctx, client, workspaces) if err != nil { return nil, err } - pooledEnvs := make([]EnvTable, 0, len(envs)) + pooledWorkspaces := make([]WorkspaceTable, 0, len(workspaces)) providers, err := client.WorkspaceProviders(ctx) if err != nil { return nil, err @@ -105,33 +105,33 @@ func EnvsHumanTable(ctx context.Context, client coder.Client, envs []coder.Envir for _, p := range providers.Kubernetes { providerMap[p.ID] = p } - for _, e := range envs { - envProvider, ok := providerMap[e.ResourcePoolID] + for _, e := range workspaces { + workspaceProvider, ok := providerMap[e.ResourcePoolID] if !ok { - return nil, xerrors.Errorf("fetch env workspace provider: %w", coder.ErrNotFound) + return nil, xerrors.Errorf("fetch workspace workspace provider: %w", coder.ErrNotFound) } - pooledEnvs = append(pooledEnvs, EnvTable{ + pooledWorkspaces = append(pooledWorkspaces, WorkspaceTable{ 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, + Provider: workspaceProvider.Name, CVM: e.UseContainerVM, }) } - return pooledEnvs, nil + return pooledWorkspaces, nil } -// MakeImageMap fetches all image entities specified in the slice of environments, then places them into an ID map. -func MakeImageMap(ctx context.Context, client coder.Client, envs []coder.Environment) (map[string]*coder.Image, error) { +// MakeImageMap fetches all image entities specified in the slice of workspaces, then places them into an ID map. +func MakeImageMap(ctx context.Context, client coder.Client, workspaces []coder.Workspace) (map[string]*coder.Image, error) { var ( mu sync.Mutex egroup = clog.LoggedErrGroup() ) imageMap := make(map[string]*coder.Image) - for _, e := range envs { + for _, e := range workspaces { // put all the image IDs into a map to remove duplicates imageMap[e.ImageID] = nil } diff --git a/internal/sync/singlefile.go b/internal/sync/singlefile.go index 0e15e354..adf8c290 100644 --- a/internal/sync/singlefile.go +++ b/internal/sync/singlefile.go @@ -17,9 +17,9 @@ import ( "cdr.dev/coder-cli/internal/coderutil" ) -// SingleFile copies the given file into the remote dir or remote path of the given coder.Environment. -func SingleFile(ctx context.Context, local, remoteDir string, env *coder.Environment, client coder.Client) error { - conn, err := coderutil.DialEnvWsep(ctx, client, env) +// SingleFile copies the given file into the remote dir or remote path of the given coder.Workspace. +func SingleFile(ctx context.Context, local, remoteDir string, workspace *coder.Workspace, client coder.Client) error { + conn, err := coderutil.DialWorkspaceWsep(ctx, client, workspace) if err != nil { return xerrors.Errorf("dial remote execer: %w", err) } diff --git a/internal/sync/sync.go b/internal/sync/sync.go index 1d356f0f..dd90cf7a 100644 --- a/internal/sync/sync.go +++ b/internal/sync/sync.go @@ -1,4 +1,4 @@ -// Package sync contains logic for establishing a file sync between a local machine and a Coder environment. +// Package sync contains logic for establishing a file sync between a local machine and a Coder workspace. package sync import ( @@ -41,7 +41,7 @@ type Sync struct { // DisableMetrics disables activity metric pushing. DisableMetrics bool - Env coder.Environment + Workspace coder.Workspace Client coder.Client OutW io.Writer ErrW io.Writer @@ -61,7 +61,7 @@ func (s Sync) syncPaths(delete bool, local, remote string) error { args := []string{"-zz", "-a", "--delete", - "-e", self + " sh", local, s.Env.Name + ":" + remote, + "-e", self + " sh", local, s.Workspace.Name + ":" + remote, } if delete { args = append([]string{"--delete"}, args...) @@ -95,7 +95,7 @@ func (s Sync) syncPaths(delete bool, local, remote string) error { } func (s Sync) remoteCmd(ctx context.Context, prog string, args ...string) error { - conn, err := coderutil.DialEnvWsep(ctx, s.Client, &s.Env) + conn, err := coderutil.DialWorkspaceWsep(ctx, s.Client, &s.Workspace) if err != nil { return xerrors.Errorf("dial executor: %w", err) } @@ -276,9 +276,9 @@ func (s Sync) Version() (string, error) { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() - conn, err := coderutil.DialEnvWsep(ctx, s.Client, &s.Env) + conn, err := coderutil.DialWorkspaceWsep(ctx, s.Client, &s.Workspace) if err != nil { - return "", xerrors.Errorf("dial env executor: %w", err) + return "", xerrors.Errorf("dial workspace executor: %w", err) } defer func() { _ = conn.Close(websocket.CloseNormalClosure, "") }() // Best effort. @@ -327,7 +327,7 @@ func (s Sync) Run() error { return xerrors.Errorf("create remote directory: %w", err) } - ap := activity.NewPusher(s.Client, s.Env.ID, activityName) + ap := activity.NewPusher(s.Client, s.Workspace.ID, activityName) ap.Push(ctx) setConsoleTitle("⏳ syncing project", s.IsInteractiveOutput) diff --git a/pkg/clog/errgroup.go b/pkg/clog/errgroup.go index e3a16fd4..a96d6449 100644 --- a/pkg/clog/errgroup.go +++ b/pkg/clog/errgroup.go @@ -10,7 +10,7 @@ import ( // ErrGroup wraps the /x/sync/errgroup.(Group) and adds clog logging and rich error propagation. // -// Take for example, a case in which we are concurrently stopping a slice of environments. +// Take for example, a case in which we are concurrently stopping a slice of workspaces. // In this case, we want to log errors as they happen, not pass them through the callstack as errors. // When the operations complete, we want to log how many, if any, failed. The caller is still expected // to handle success and info logging.