645 lines
20 KiB
Go
645 lines
20 KiB
Go
package tfe
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"net/url"
|
|
"time"
|
|
)
|
|
|
|
// Compile-time proof of interface implementation.
|
|
var _ Workspaces = (*workspaces)(nil)
|
|
|
|
// Workspaces describes all the workspace related methods that the Terraform
|
|
// Enterprise API supports.
|
|
//
|
|
// TFE API docs: https://www.terraform.io/docs/enterprise/api/workspaces.html
|
|
type Workspaces interface {
|
|
// List all the workspaces within an organization.
|
|
List(ctx context.Context, organization string, options WorkspaceListOptions) (*WorkspaceList, error)
|
|
|
|
// Create is used to create a new workspace.
|
|
Create(ctx context.Context, organization string, options WorkspaceCreateOptions) (*Workspace, error)
|
|
|
|
// Read a workspace by its name.
|
|
Read(ctx context.Context, organization string, workspace string) (*Workspace, error)
|
|
|
|
// ReadByID reads a workspace by its ID.
|
|
ReadByID(ctx context.Context, workspaceID string) (*Workspace, error)
|
|
|
|
// Update settings of an existing workspace.
|
|
Update(ctx context.Context, organization string, workspace string, options WorkspaceUpdateOptions) (*Workspace, error)
|
|
|
|
// UpdateByID updates the settings of an existing workspace.
|
|
UpdateByID(ctx context.Context, workspaceID string, options WorkspaceUpdateOptions) (*Workspace, error)
|
|
|
|
// Delete a workspace by its name.
|
|
Delete(ctx context.Context, organization string, workspace string) error
|
|
|
|
// DeleteByID deletes a workspace by its ID.
|
|
DeleteByID(ctx context.Context, workspaceID string) error
|
|
|
|
// RemoveVCSConnection from a workspace.
|
|
RemoveVCSConnection(ctx context.Context, organization, workspace string) (*Workspace, error)
|
|
|
|
// RemoveVCSConnectionByID removes a VCS connection from a workspace.
|
|
RemoveVCSConnectionByID(ctx context.Context, workspaceID string) (*Workspace, error)
|
|
|
|
// Lock a workspace by its ID.
|
|
Lock(ctx context.Context, workspaceID string, options WorkspaceLockOptions) (*Workspace, error)
|
|
|
|
// Unlock a workspace by its ID.
|
|
Unlock(ctx context.Context, workspaceID string) (*Workspace, error)
|
|
|
|
// ForceUnlock a workspace by its ID.
|
|
ForceUnlock(ctx context.Context, workspaceID string) (*Workspace, error)
|
|
|
|
// AssignSSHKey to a workspace.
|
|
AssignSSHKey(ctx context.Context, workspaceID string, options WorkspaceAssignSSHKeyOptions) (*Workspace, error)
|
|
|
|
// UnassignSSHKey from a workspace.
|
|
UnassignSSHKey(ctx context.Context, workspaceID string) (*Workspace, error)
|
|
}
|
|
|
|
// workspaces implements Workspaces.
|
|
type workspaces struct {
|
|
client *Client
|
|
}
|
|
|
|
// WorkspaceList represents a list of workspaces.
|
|
type WorkspaceList struct {
|
|
*Pagination
|
|
Items []*Workspace
|
|
}
|
|
|
|
// Workspace represents a Terraform Enterprise workspace.
|
|
type Workspace struct {
|
|
ID string `jsonapi:"primary,workspaces"`
|
|
Actions *WorkspaceActions `jsonapi:"attr,actions"`
|
|
AutoApply bool `jsonapi:"attr,auto-apply"`
|
|
CanQueueDestroyPlan bool `jsonapi:"attr,can-queue-destroy-plan"`
|
|
CreatedAt time.Time `jsonapi:"attr,created-at,iso8601"`
|
|
Environment string `jsonapi:"attr,environment"`
|
|
FileTriggersEnabled bool `jsonapi:"attr,file-triggers-enabled"`
|
|
Locked bool `jsonapi:"attr,locked"`
|
|
MigrationEnvironment string `jsonapi:"attr,migration-environment"`
|
|
Name string `jsonapi:"attr,name"`
|
|
Operations bool `jsonapi:"attr,operations"`
|
|
Permissions *WorkspacePermissions `jsonapi:"attr,permissions"`
|
|
QueueAllRuns bool `jsonapi:"attr,queue-all-runs"`
|
|
TerraformVersion string `jsonapi:"attr,terraform-version"`
|
|
TriggerPrefixes []string `jsonapi:"attr,trigger-prefixes"`
|
|
VCSRepo *VCSRepo `jsonapi:"attr,vcs-repo"`
|
|
WorkingDirectory string `jsonapi:"attr,working-directory"`
|
|
|
|
// Relations
|
|
CurrentRun *Run `jsonapi:"relation,current-run"`
|
|
Organization *Organization `jsonapi:"relation,organization"`
|
|
SSHKey *SSHKey `jsonapi:"relation,ssh-key"`
|
|
}
|
|
|
|
// VCSRepo contains the configuration of a VCS integration.
|
|
type VCSRepo struct {
|
|
Branch string `json:"branch"`
|
|
Identifier string `json:"identifier"`
|
|
IngressSubmodules bool `json:"ingress-submodules"`
|
|
OAuthTokenID string `json:"oauth-token-id"`
|
|
}
|
|
|
|
// WorkspaceActions represents the workspace actions.
|
|
type WorkspaceActions struct {
|
|
IsDestroyable bool `json:"is-destroyable"`
|
|
}
|
|
|
|
// WorkspacePermissions represents the workspace permissions.
|
|
type WorkspacePermissions struct {
|
|
CanDestroy bool `json:"can-destroy"`
|
|
CanForceUnlock bool `json:"can-force-unlock"`
|
|
CanLock bool `json:"can-lock"`
|
|
CanQueueApply bool `json:"can-queue-apply"`
|
|
CanQueueDestroy bool `json:"can-queue-destroy"`
|
|
CanQueueRun bool `json:"can-queue-run"`
|
|
CanReadSettings bool `json:"can-read-settings"`
|
|
CanUnlock bool `json:"can-unlock"`
|
|
CanUpdate bool `json:"can-update"`
|
|
CanUpdateVariable bool `json:"can-update-variable"`
|
|
}
|
|
|
|
// WorkspaceListOptions represents the options for listing workspaces.
|
|
type WorkspaceListOptions struct {
|
|
ListOptions
|
|
|
|
// A search string (partial workspace name) used to filter the results.
|
|
Search *string `url:"search[name],omitempty"`
|
|
}
|
|
|
|
// List all the workspaces within an organization.
|
|
func (s *workspaces) List(ctx context.Context, organization string, options WorkspaceListOptions) (*WorkspaceList, error) {
|
|
if !validStringID(&organization) {
|
|
return nil, errors.New("invalid value for organization")
|
|
}
|
|
|
|
u := fmt.Sprintf("organizations/%s/workspaces", url.QueryEscape(organization))
|
|
req, err := s.client.newRequest("GET", u, &options)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
wl := &WorkspaceList{}
|
|
err = s.client.do(ctx, req, wl)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return wl, nil
|
|
}
|
|
|
|
// WorkspaceCreateOptions represents the options for creating a new workspace.
|
|
type WorkspaceCreateOptions struct {
|
|
// For internal use only!
|
|
ID string `jsonapi:"primary,workspaces"`
|
|
|
|
// Whether to automatically apply changes when a Terraform plan is successful.
|
|
AutoApply *bool `jsonapi:"attr,auto-apply,omitempty"`
|
|
|
|
// Whether to filter runs based on the changed files in a VCS push. If
|
|
// enabled, the working directory and trigger prefixes describe a set of
|
|
// paths which must contain changes for a VCS push to trigger a run. If
|
|
// disabled, any push will trigger a run.
|
|
FileTriggersEnabled *bool `jsonapi:"attr,file-triggers-enabled,omitempty"`
|
|
|
|
// The legacy TFE environment to use as the source of the migration, in the
|
|
// form organization/environment. Omit this unless you are migrating a legacy
|
|
// environment.
|
|
MigrationEnvironment *string `jsonapi:"attr,migration-environment,omitempty"`
|
|
|
|
// The name of the workspace, which can only include letters, numbers, -,
|
|
// and _. This will be used as an identifier and must be unique in the
|
|
// organization.
|
|
Name *string `jsonapi:"attr,name"`
|
|
|
|
// Whether the workspace will use remote or local execution mode.
|
|
Operations *bool `jsonapi:"attr,operations,omitempty"`
|
|
|
|
// Whether to queue all runs. Unless this is set to true, runs triggered by
|
|
// a webhook will not be queued until at least one run is manually queued.
|
|
QueueAllRuns *bool `jsonapi:"attr,queue-all-runs,omitempty"`
|
|
|
|
// The version of Terraform to use for this workspace. Upon creating a
|
|
// workspace, the latest version is selected unless otherwise specified.
|
|
TerraformVersion *string `jsonapi:"attr,terraform-version,omitempty"`
|
|
|
|
// List of repository-root-relative paths which list all locations to be
|
|
// tracked for changes. See FileTriggersEnabled above for more details.
|
|
TriggerPrefixes []string `jsonapi:"attr,trigger-prefixes,omitempty"`
|
|
|
|
// Settings for the workspace's VCS repository. If omitted, the workspace is
|
|
// created without a VCS repo. If included, you must specify at least the
|
|
// oauth-token-id and identifier keys below.
|
|
VCSRepo *VCSRepoOptions `jsonapi:"attr,vcs-repo,omitempty"`
|
|
|
|
// A relative path that Terraform will execute within. This defaults to the
|
|
// root of your repository and is typically set to a subdirectory matching the
|
|
// environment when multiple environments exist within the same repository.
|
|
WorkingDirectory *string `jsonapi:"attr,working-directory,omitempty"`
|
|
}
|
|
|
|
// VCSRepoOptions represents the configuration options of a VCS integration.
|
|
type VCSRepoOptions struct {
|
|
Branch *string `json:"branch,omitempty"`
|
|
Identifier *string `json:"identifier,omitempty"`
|
|
IngressSubmodules *bool `json:"ingress-submodules,omitempty"`
|
|
OAuthTokenID *string `json:"oauth-token-id,omitempty"`
|
|
}
|
|
|
|
func (o WorkspaceCreateOptions) valid() error {
|
|
if !validString(o.Name) {
|
|
return errors.New("name is required")
|
|
}
|
|
if !validStringID(o.Name) {
|
|
return errors.New("invalid value for name")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Create is used to create a new workspace.
|
|
func (s *workspaces) Create(ctx context.Context, organization string, options WorkspaceCreateOptions) (*Workspace, error) {
|
|
if !validStringID(&organization) {
|
|
return nil, errors.New("invalid value for organization")
|
|
}
|
|
if err := options.valid(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Make sure we don't send a user provided ID.
|
|
options.ID = ""
|
|
|
|
u := fmt.Sprintf("organizations/%s/workspaces", url.QueryEscape(organization))
|
|
req, err := s.client.newRequest("POST", u, &options)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
w := &Workspace{}
|
|
err = s.client.do(ctx, req, w)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return w, nil
|
|
}
|
|
|
|
// Read a workspace by its name.
|
|
func (s *workspaces) Read(ctx context.Context, organization, workspace string) (*Workspace, error) {
|
|
if !validStringID(&organization) {
|
|
return nil, errors.New("invalid value for organization")
|
|
}
|
|
if !validStringID(&workspace) {
|
|
return nil, errors.New("invalid value for workspace")
|
|
}
|
|
|
|
u := fmt.Sprintf(
|
|
"organizations/%s/workspaces/%s",
|
|
url.QueryEscape(organization),
|
|
url.QueryEscape(workspace),
|
|
)
|
|
req, err := s.client.newRequest("GET", u, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
w := &Workspace{}
|
|
err = s.client.do(ctx, req, w)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return w, nil
|
|
}
|
|
|
|
// ReadByID reads a workspace by its ID.
|
|
func (s *workspaces) ReadByID(ctx context.Context, workspaceID string) (*Workspace, error) {
|
|
if !validStringID(&workspaceID) {
|
|
return nil, errors.New("invalid value for workspace ID")
|
|
}
|
|
|
|
u := fmt.Sprintf("workspaces/%s", url.QueryEscape(workspaceID))
|
|
req, err := s.client.newRequest("GET", u, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
w := &Workspace{}
|
|
err = s.client.do(ctx, req, w)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return w, nil
|
|
}
|
|
|
|
// WorkspaceUpdateOptions represents the options for updating a workspace.
|
|
type WorkspaceUpdateOptions struct {
|
|
// For internal use only!
|
|
ID string `jsonapi:"primary,workspaces"`
|
|
|
|
// Whether to automatically apply changes when a Terraform plan is successful.
|
|
AutoApply *bool `jsonapi:"attr,auto-apply,omitempty"`
|
|
|
|
// A new name for the workspace, which can only include letters, numbers, -,
|
|
// and _. This will be used as an identifier and must be unique in the
|
|
// organization. Warning: Changing a workspace's name changes its URL in the
|
|
// API and UI.
|
|
Name *string `jsonapi:"attr,name,omitempty"`
|
|
|
|
// Whether to filter runs based on the changed files in a VCS push. If
|
|
// enabled, the working directory and trigger prefixes describe a set of
|
|
// paths which must contain changes for a VCS push to trigger a run. If
|
|
// disabled, any push will trigger a run.
|
|
FileTriggersEnabled *bool `jsonapi:"attr,file-triggers-enabled,omitempty"`
|
|
|
|
// Whether the workspace will use remote or local execution mode.
|
|
Operations *bool `jsonapi:"attr,operations,omitempty"`
|
|
|
|
// Whether to queue all runs. Unless this is set to true, runs triggered by
|
|
// a webhook will not be queued until at least one run is manually queued.
|
|
QueueAllRuns *bool `jsonapi:"attr,queue-all-runs,omitempty"`
|
|
|
|
// The version of Terraform to use for this workspace.
|
|
TerraformVersion *string `jsonapi:"attr,terraform-version,omitempty"`
|
|
|
|
// List of repository-root-relative paths which list all locations to be
|
|
// tracked for changes. See FileTriggersEnabled above for more details.
|
|
TriggerPrefixes []string `jsonapi:"attr,trigger-prefixes,omitempty"`
|
|
|
|
// To delete a workspace's existing VCS repo, specify null instead of an
|
|
// object. To modify a workspace's existing VCS repo, include whichever of
|
|
// the keys below you wish to modify. To add a new VCS repo to a workspace
|
|
// that didn't previously have one, include at least the oauth-token-id and
|
|
// identifier keys.
|
|
VCSRepo *VCSRepoOptions `jsonapi:"attr,vcs-repo,omitempty"`
|
|
|
|
// A relative path that Terraform will execute within. This defaults to the
|
|
// root of your repository and is typically set to a subdirectory matching
|
|
// the environment when multiple environments exist within the same
|
|
// repository.
|
|
WorkingDirectory *string `jsonapi:"attr,working-directory,omitempty"`
|
|
}
|
|
|
|
// Update settings of an existing workspace.
|
|
func (s *workspaces) Update(ctx context.Context, organization, workspace string, options WorkspaceUpdateOptions) (*Workspace, error) {
|
|
if !validStringID(&organization) {
|
|
return nil, errors.New("invalid value for organization")
|
|
}
|
|
if !validStringID(&workspace) {
|
|
return nil, errors.New("invalid value for workspace")
|
|
}
|
|
|
|
// Make sure we don't send a user provided ID.
|
|
options.ID = ""
|
|
|
|
u := fmt.Sprintf(
|
|
"organizations/%s/workspaces/%s",
|
|
url.QueryEscape(organization),
|
|
url.QueryEscape(workspace),
|
|
)
|
|
req, err := s.client.newRequest("PATCH", u, &options)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
w := &Workspace{}
|
|
err = s.client.do(ctx, req, w)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return w, nil
|
|
}
|
|
|
|
// UpdateByID updates the settings of an existing workspace.
|
|
func (s *workspaces) UpdateByID(ctx context.Context, workspaceID string, options WorkspaceUpdateOptions) (*Workspace, error) {
|
|
if !validStringID(&workspaceID) {
|
|
return nil, errors.New("invalid value for workspace ID")
|
|
}
|
|
|
|
// Make sure we don't send a user provided ID.
|
|
options.ID = ""
|
|
|
|
u := fmt.Sprintf("workspaces/%s", url.QueryEscape(workspaceID))
|
|
req, err := s.client.newRequest("PATCH", u, &options)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
w := &Workspace{}
|
|
err = s.client.do(ctx, req, w)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return w, nil
|
|
}
|
|
|
|
// Delete a workspace by its name.
|
|
func (s *workspaces) Delete(ctx context.Context, organization, workspace string) error {
|
|
if !validStringID(&organization) {
|
|
return errors.New("invalid value for organization")
|
|
}
|
|
if !validStringID(&workspace) {
|
|
return errors.New("invalid value for workspace")
|
|
}
|
|
|
|
u := fmt.Sprintf(
|
|
"organizations/%s/workspaces/%s",
|
|
url.QueryEscape(organization),
|
|
url.QueryEscape(workspace),
|
|
)
|
|
req, err := s.client.newRequest("DELETE", u, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return s.client.do(ctx, req, nil)
|
|
}
|
|
|
|
// DeleteByID deletes a workspace by its ID.
|
|
func (s *workspaces) DeleteByID(ctx context.Context, workspaceID string) error {
|
|
if !validStringID(&workspaceID) {
|
|
return errors.New("invalid value for workspace ID")
|
|
}
|
|
|
|
u := fmt.Sprintf("workspaces/%s", url.QueryEscape(workspaceID))
|
|
req, err := s.client.newRequest("DELETE", u, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return s.client.do(ctx, req, nil)
|
|
}
|
|
|
|
// workspaceRemoveVCSConnectionOptions
|
|
type workspaceRemoveVCSConnectionOptions struct {
|
|
ID string `jsonapi:"primary,workspaces"`
|
|
VCSRepo *VCSRepoOptions `jsonapi:"attr,vcs-repo"`
|
|
}
|
|
|
|
// RemoveVCSConnection from a workspace.
|
|
func (s *workspaces) RemoveVCSConnection(ctx context.Context, organization, workspace string) (*Workspace, error) {
|
|
if !validStringID(&organization) {
|
|
return nil, errors.New("invalid value for organization")
|
|
}
|
|
if !validStringID(&workspace) {
|
|
return nil, errors.New("invalid value for workspace")
|
|
}
|
|
|
|
u := fmt.Sprintf(
|
|
"organizations/%s/workspaces/%s",
|
|
url.QueryEscape(organization),
|
|
url.QueryEscape(workspace),
|
|
)
|
|
|
|
req, err := s.client.newRequest("PATCH", u, &workspaceRemoveVCSConnectionOptions{})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
w := &Workspace{}
|
|
err = s.client.do(ctx, req, w)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return w, nil
|
|
}
|
|
|
|
// RemoveVCSConnectionByID removes a VCS connection from a workspace.
|
|
func (s *workspaces) RemoveVCSConnectionByID(ctx context.Context, workspaceID string) (*Workspace, error) {
|
|
if !validStringID(&workspaceID) {
|
|
return nil, errors.New("invalid value for workspace ID")
|
|
}
|
|
|
|
u := fmt.Sprintf("workspaces/%s", url.QueryEscape(workspaceID))
|
|
|
|
req, err := s.client.newRequest("PATCH", u, &workspaceRemoveVCSConnectionOptions{})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
w := &Workspace{}
|
|
err = s.client.do(ctx, req, w)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return w, nil
|
|
}
|
|
|
|
// WorkspaceLockOptions represents the options for locking a workspace.
|
|
type WorkspaceLockOptions struct {
|
|
// Specifies the reason for locking the workspace.
|
|
Reason *string `json:"reason,omitempty"`
|
|
}
|
|
|
|
// Lock a workspace by its ID.
|
|
func (s *workspaces) Lock(ctx context.Context, workspaceID string, options WorkspaceLockOptions) (*Workspace, error) {
|
|
if !validStringID(&workspaceID) {
|
|
return nil, errors.New("invalid value for workspace ID")
|
|
}
|
|
|
|
u := fmt.Sprintf("workspaces/%s/actions/lock", url.QueryEscape(workspaceID))
|
|
req, err := s.client.newRequest("POST", u, &options)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
w := &Workspace{}
|
|
err = s.client.do(ctx, req, w)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return w, nil
|
|
}
|
|
|
|
// Unlock a workspace by its ID.
|
|
func (s *workspaces) Unlock(ctx context.Context, workspaceID string) (*Workspace, error) {
|
|
if !validStringID(&workspaceID) {
|
|
return nil, errors.New("invalid value for workspace ID")
|
|
}
|
|
|
|
u := fmt.Sprintf("workspaces/%s/actions/unlock", url.QueryEscape(workspaceID))
|
|
req, err := s.client.newRequest("POST", u, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
w := &Workspace{}
|
|
err = s.client.do(ctx, req, w)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return w, nil
|
|
}
|
|
|
|
// ForceUnlock a workspace by its ID.
|
|
func (s *workspaces) ForceUnlock(ctx context.Context, workspaceID string) (*Workspace, error) {
|
|
if !validStringID(&workspaceID) {
|
|
return nil, errors.New("invalid value for workspace ID")
|
|
}
|
|
|
|
u := fmt.Sprintf("workspaces/%s/actions/force-unlock", url.QueryEscape(workspaceID))
|
|
req, err := s.client.newRequest("POST", u, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
w := &Workspace{}
|
|
err = s.client.do(ctx, req, w)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return w, nil
|
|
}
|
|
|
|
// WorkspaceAssignSSHKeyOptions represents the options to assign an SSH key to
|
|
// a workspace.
|
|
type WorkspaceAssignSSHKeyOptions struct {
|
|
// For internal use only!
|
|
ID string `jsonapi:"primary,workspaces"`
|
|
|
|
// The SSH key ID to assign.
|
|
SSHKeyID *string `jsonapi:"attr,id"`
|
|
}
|
|
|
|
func (o WorkspaceAssignSSHKeyOptions) valid() error {
|
|
if !validString(o.SSHKeyID) {
|
|
return errors.New("SSH key ID is required")
|
|
}
|
|
if !validStringID(o.SSHKeyID) {
|
|
return errors.New("invalid value for SSH key ID")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// AssignSSHKey to a workspace.
|
|
func (s *workspaces) AssignSSHKey(ctx context.Context, workspaceID string, options WorkspaceAssignSSHKeyOptions) (*Workspace, error) {
|
|
if !validStringID(&workspaceID) {
|
|
return nil, errors.New("invalid value for workspace ID")
|
|
}
|
|
if err := options.valid(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Make sure we don't send a user provided ID.
|
|
options.ID = ""
|
|
|
|
u := fmt.Sprintf("workspaces/%s/relationships/ssh-key", url.QueryEscape(workspaceID))
|
|
req, err := s.client.newRequest("PATCH", u, &options)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
w := &Workspace{}
|
|
err = s.client.do(ctx, req, w)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return w, nil
|
|
}
|
|
|
|
// workspaceUnassignSSHKeyOptions represents the options to unassign an SSH key
|
|
// to a workspace.
|
|
type workspaceUnassignSSHKeyOptions struct {
|
|
// For internal use only!
|
|
ID string `jsonapi:"primary,workspaces"`
|
|
|
|
// Must be nil to unset the currently assigned SSH key.
|
|
SSHKeyID *string `jsonapi:"attr,id"`
|
|
}
|
|
|
|
// UnassignSSHKey from a workspace.
|
|
func (s *workspaces) UnassignSSHKey(ctx context.Context, workspaceID string) (*Workspace, error) {
|
|
if !validStringID(&workspaceID) {
|
|
return nil, errors.New("invalid value for workspace ID")
|
|
}
|
|
|
|
u := fmt.Sprintf("workspaces/%s/relationships/ssh-key", url.QueryEscape(workspaceID))
|
|
req, err := s.client.newRequest("PATCH", u, &workspaceUnassignSSHKeyOptions{})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
w := &Workspace{}
|
|
err = s.client.do(ctx, req, w)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return w, nil
|
|
}
|