Skip to content

Commit

Permalink
feat: prefect_workspace_access Resource (#75)
Browse files Browse the repository at this point in the history
* add workspace_access client

* add workspace_access resource logic

* final touches

* we must appease the linting lords

* add example

* oops
  • Loading branch information
parkedwards authored Oct 27, 2023
1 parent 7a2eaff commit 2f6d27f
Show file tree
Hide file tree
Showing 17 changed files with 650 additions and 32 deletions.
15 changes: 15 additions & 0 deletions examples/workspace_access.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
data "prefect_workspace_role" "developer" {
name = "Developer"
}
data "prefect_workspace" "prd" {
id = "<workspace uuid>"
}
resource "prefect_service_account" "bot" {
name = "a-cool-bot"
}
resource "prefect_workspace_access" "bot_access" {
accessor_type = "SERVICE_ACCOUNT"
accessor_id = prefect_service_account.bot.id
workspace_id = data.prefect_workspace.prd.id
workspace_role_id = data.prefect_workspace_role.developer.id
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ go 1.20
require (
github.com/google/uuid v1.3.1
github.com/hashicorp/terraform-plugin-framework v1.4.2
github.com/hashicorp/terraform-plugin-framework-validators v0.12.0
github.com/hashicorp/terraform-plugin-go v0.19.0
github.com/hashicorp/terraform-plugin-testing v1.5.1
)
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ github.com/hashicorp/terraform-json v0.17.1 h1:eMfvh/uWggKmY7Pmb3T85u86E2EQg6EQH
github.com/hashicorp/terraform-json v0.17.1/go.mod h1:Huy6zt6euxaY9knPAFKjUITn8QxUFIe9VuSzb4zn/0o=
github.com/hashicorp/terraform-plugin-framework v1.4.2 h1:P7a7VP1GZbjc4rv921Xy5OckzhoiO3ig6SGxwelD2sI=
github.com/hashicorp/terraform-plugin-framework v1.4.2/go.mod h1:GWl3InPFZi2wVQmdVnINPKys09s9mLmTZr95/ngLnbY=
github.com/hashicorp/terraform-plugin-framework-validators v0.12.0 h1:HOjBuMbOEzl7snOdOoUfE2Jgeto6JOjLVQ39Ls2nksc=
github.com/hashicorp/terraform-plugin-framework-validators v0.12.0/go.mod h1:jfHGE/gzjxYz6XoUwi/aYiiKrJDeutQNUtGQXkaHklg=
github.com/hashicorp/terraform-plugin-go v0.19.0 h1:BuZx/6Cp+lkmiG0cOBk6Zps0Cb2tmqQpDM3iAtnhDQU=
github.com/hashicorp/terraform-plugin-go v0.19.0/go.mod h1:EhRSkEPNoylLQntYsk5KrDHTZJh9HQoumZXbOGOXmec=
github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0=
Expand Down
1 change: 1 addition & 0 deletions internal/api/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import "github.com/google/uuid"
type PrefectClient interface {
Accounts() (AccountsClient, error)
Workspaces(accountID uuid.UUID) (WorkspacesClient, error)
WorkspaceAccess(accountID uuid.UUID, workspaceID uuid.UUID) (WorkspaceAccessClient, error)
WorkspaceRoles(accountID uuid.UUID) (WorkspaceRolesClient, error)
WorkPools(accountID uuid.UUID, workspaceID uuid.UUID) (WorkPoolsClient, error)
Variables(accountID uuid.UUID, workspaceID uuid.UUID) (VariablesClient, error)
Expand Down
40 changes: 40 additions & 0 deletions internal/api/workspace_access.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package api

import (
"context"

"github.com/google/uuid"
)

type WorkspaceAccessClient interface {
Upsert(ctx context.Context, accessorType string, accessorID uuid.UUID, roleID uuid.UUID) (*WorkspaceAccess, error)
Get(ctx context.Context, accessorType string, accessID uuid.UUID) (*WorkspaceAccess, error)
Delete(ctx context.Context, accessorType string, accessID uuid.UUID) error
}

// WorkspaceAccess is a representation of a workspace access.
// This is used for multiple accessor types (user, service account, team),
// which dictates the presence of the specific accessor's ID.
type WorkspaceAccess struct {
BaseModel
WorkspaceID uuid.UUID `json:"workspace_id"`
WorkspaceRoleID uuid.UUID `json:"workspace_role_id"`

ActorID *uuid.UUID `json:"actor_id"`
BotID *uuid.UUID `json:"bot_id"`
UserID *uuid.UUID `json:"user_id"`
}

// WorkspaceAccessUpsert defines the payload
// when upserting a workspace access request.
type WorkspaceAccessUpsert struct {
WorkspaceRoleID uuid.UUID `json:"workspace_role_id"`

// Only one of the follow IDs should be set on each call
// depending on the resource's AccessorType
// NOTE: omitempty normally excludes any zero value,
// for primitives, but complex types like structs
// and uuid.UUID require a pointer type to be omitted.
UserID *uuid.UUID `json:"user_id,omitempty"`
BotID *uuid.UUID `json:"bot_id,omitempty"`
}
13 changes: 10 additions & 3 deletions internal/client/accounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"

"github.com/google/uuid"
Expand Down Expand Up @@ -48,7 +49,9 @@ func (c *AccountsClient) Get(ctx context.Context, accountID uuid.UUID) (*api.Acc
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("status code %s", resp.Status)
errorBody, _ := io.ReadAll(resp.Body)

return nil, fmt.Errorf("status code %s, error=%s", resp.Status, errorBody)
}

var account api.AccountResponse
Expand Down Expand Up @@ -81,7 +84,9 @@ func (c *AccountsClient) Update(ctx context.Context, accountID uuid.UUID, data a
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusNoContent {
return fmt.Errorf("status code %s", resp.Status)
errorBody, _ := io.ReadAll(resp.Body)

return fmt.Errorf("status code %s, error=%s", resp.Status, errorBody)
}

return nil
Expand All @@ -104,7 +109,9 @@ func (c *AccountsClient) Delete(ctx context.Context, accountID uuid.UUID) error
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusNoContent {
return fmt.Errorf("status code %s", resp.Status)
errorBody, _ := io.ReadAll(resp.Body)

return fmt.Errorf("status code %s, error=%s", resp.Status, errorBody)
}

return nil
Expand Down
22 changes: 14 additions & 8 deletions internal/client/service_accounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,9 @@ func (sa *ServiceAccountsClient) Create(ctx context.Context, request api.Service
defer resp.Body.Close()

if resp.StatusCode != http.StatusCreated {
// Read the response body
bodyBytes, _ := io.ReadAll(resp.Body)
bodyString := string(bodyBytes)
errorBody, _ := io.ReadAll(resp.Body)

return nil, fmt.Errorf("status code: %s, response body: %s", resp.Status, bodyString)
return nil, fmt.Errorf("status code %s, error=%s", resp.Status, errorBody)
}

var response api.ServiceAccount
Expand Down Expand Up @@ -98,7 +96,9 @@ func (sa *ServiceAccountsClient) List(ctx context.Context, filter api.ServiceAcc
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("status code %s", resp.Status)
errorBody, _ := io.ReadAll(resp.Body)

return nil, fmt.Errorf("status code %s, error=%s", resp.Status, errorBody)
}

var serviceAccounts []*api.ServiceAccount
Expand Down Expand Up @@ -161,7 +161,9 @@ func (sa *ServiceAccountsClient) Update(ctx context.Context, botID string, reque
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusNoContent {
return fmt.Errorf("status code %s", resp.Status)
errorBody, _ := io.ReadAll(resp.Body)

return fmt.Errorf("status code %s, error=%s", resp.Status, errorBody)
}

return nil
Expand All @@ -181,7 +183,9 @@ func (sa *ServiceAccountsClient) Delete(ctx context.Context, botID string) error
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusNoContent {
return fmt.Errorf("status code %s", resp.Status)
errorBody, _ := io.ReadAll(resp.Body)

return fmt.Errorf("status code %s, error=%s", resp.Status, errorBody)
}

return nil
Expand All @@ -206,7 +210,9 @@ func (sa *ServiceAccountsClient) RotateKey(ctx context.Context, serviceAccountID
defer resp.Body.Close()

if resp.StatusCode != http.StatusCreated {
return nil, fmt.Errorf("status code %s", resp.Status)
errorBody, _ := io.ReadAll(resp.Body)

return nil, fmt.Errorf("status code %s, error=%s", resp.Status, errorBody)
}

var serviceAccount api.ServiceAccount
Expand Down
21 changes: 16 additions & 5 deletions internal/client/variables.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"

"github.com/google/uuid"
Expand Down Expand Up @@ -68,7 +69,9 @@ func (c *VariablesClient) Create(ctx context.Context, data api.VariableCreate) (
defer resp.Body.Close()

if resp.StatusCode != http.StatusCreated {
return nil, fmt.Errorf("status code %s", resp.Status)
errorBody, _ := io.ReadAll(resp.Body)

return nil, fmt.Errorf("status code %s, error=%s", resp.Status, errorBody)
}

var variable api.Variable
Expand Down Expand Up @@ -103,7 +106,9 @@ func (c *VariablesClient) Get(ctx context.Context, variableID uuid.UUID) (*api.V
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("status code %s", resp.Status)
errorBody, _ := io.ReadAll(resp.Body)

return nil, fmt.Errorf("status code %s, error=%s", resp.Status, errorBody)
}

var variable api.Variable
Expand All @@ -130,7 +135,9 @@ func (c *VariablesClient) GetByName(ctx context.Context, name string) (*api.Vari
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("status code %s", resp.Status)
errorBody, _ := io.ReadAll(resp.Body)

return nil, fmt.Errorf("status code %s, error=%s", resp.Status, errorBody)
}

var variable api.Variable
Expand Down Expand Up @@ -162,7 +169,9 @@ func (c *VariablesClient) Update(ctx context.Context, variableID uuid.UUID, data
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusNoContent {
return fmt.Errorf("status code %s", resp.Status)
errorBody, _ := io.ReadAll(resp.Body)

return fmt.Errorf("status code %s, error=%s", resp.Status, errorBody)
}

return nil
Expand All @@ -184,7 +193,9 @@ func (c *VariablesClient) Delete(ctx context.Context, variableID uuid.UUID) erro
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusNoContent {
return fmt.Errorf("status code %s", resp.Status)
errorBody, _ := io.ReadAll(resp.Body)

return fmt.Errorf("status code %s, error=%s", resp.Status, errorBody)
}

return nil
Expand Down
21 changes: 16 additions & 5 deletions internal/client/work_pools.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"

"github.com/google/uuid"
Expand Down Expand Up @@ -67,7 +68,9 @@ func (c *WorkPoolsClient) Create(ctx context.Context, data api.WorkPoolCreate) (
defer resp.Body.Close()

if resp.StatusCode != http.StatusCreated {
return nil, fmt.Errorf("status code %s", resp.Status)
errorBody, _ := io.ReadAll(resp.Body)

return nil, fmt.Errorf("status code %s, error=%s", resp.Status, errorBody)
}

var pool api.WorkPool
Expand Down Expand Up @@ -99,7 +102,9 @@ func (c *WorkPoolsClient) List(ctx context.Context, filter api.WorkPoolFilter) (
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("status code %s", resp.Status)
errorBody, _ := io.ReadAll(resp.Body)

return nil, fmt.Errorf("status code %s, error=%s", resp.Status, errorBody)
}

var pools []*api.WorkPool
Expand All @@ -126,7 +131,9 @@ func (c *WorkPoolsClient) Get(ctx context.Context, name string) (*api.WorkPool,
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("status code %s", resp.Status)
errorBody, _ := io.ReadAll(resp.Body)

return nil, fmt.Errorf("status code %s, error=%s", resp.Status, errorBody)
}

var pool api.WorkPool
Expand Down Expand Up @@ -158,7 +165,9 @@ func (c *WorkPoolsClient) Update(ctx context.Context, name string, data api.Work
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusNoContent {
return fmt.Errorf("status code %s", resp.Status)
errorBody, _ := io.ReadAll(resp.Body)

return fmt.Errorf("status code %s, error=%s", resp.Status, errorBody)
}

return nil
Expand All @@ -180,7 +189,9 @@ func (c *WorkPoolsClient) Delete(ctx context.Context, name string) error {
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusNoContent {
return fmt.Errorf("status code %s", resp.Status)
errorBody, _ := io.ReadAll(resp.Body)

return fmt.Errorf("status code %s, error=%s", resp.Status, errorBody)
}

return nil
Expand Down
Loading

0 comments on commit 2f6d27f

Please sign in to comment.