Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
## v0.7.2
## v0.8.0

FEATURES:
- Added `meshstack_workspace` resource.
- Added `meshstack_workspace` data source.

FIXES:
- Allow `value_code` in `meshstack_building_block_v2` and `meshstack_building_block` resources.
Expand Down
2 changes: 2 additions & 0 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ type endpoints struct {
Projects *url.URL `json:"meshprojects"`
ProjectUserBindings *url.URL `json:"meshprojectuserbindings"`
ProjectGroupBindings *url.URL `json:"meshprojectgroupbindings"`
Workspaces *url.URL `json:"meshworkspaces"`
Tenants *url.URL `json:"meshtenants"`
TagDefinitions *url.URL `json:"meshtagdefinitions"`
}
Expand All @@ -63,6 +64,7 @@ func NewClient(rootUrl *url.URL, apiKey string, apiSecret string) (*MeshStackPro
Projects: rootUrl.JoinPath(apiMeshObjectsRoot, "meshprojects"),
ProjectUserBindings: rootUrl.JoinPath(apiMeshObjectsRoot, "meshprojectbindings", "userbindings"),
ProjectGroupBindings: rootUrl.JoinPath(apiMeshObjectsRoot, "meshprojectbindings", "groupbindings"),
Workspaces: rootUrl.JoinPath(apiMeshObjectsRoot, "meshworkspaces"),
Tenants: rootUrl.JoinPath(apiMeshObjectsRoot, "meshtenants"),
TagDefinitions: rootUrl.JoinPath(apiMeshObjectsRoot, "meshtagdefinitions"),
}
Expand Down
2 changes: 1 addition & 1 deletion client/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func (c *MeshStackProviderClient) ReadProject(workspace string, name string) (*M
return nil, err
}

if res.StatusCode == 404 {
if res.StatusCode == http.StatusNotFound {
return nil, nil
}

Expand Down
160 changes: 160 additions & 0 deletions client/workspace.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
package client

import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
)

const CONTENT_TYPE_WORKSPACE = "application/vnd.meshcloud.api.meshworkspace.v2.hal+json"

type MeshWorkspace struct {
ApiVersion string `json:"apiVersion" tfsdk:"api_version"`
Kind string `json:"kind" tfsdk:"kind"`
Metadata MeshWorkspaceMetadata `json:"metadata" tfsdk:"metadata"`
Spec MeshWorkspaceSpec `json:"spec" tfsdk:"spec"`
}

type MeshWorkspaceMetadata struct {
Name string `json:"name" tfsdk:"name"`
CreatedOn string `json:"createdOn" tfsdk:"created_on"`
DeletedOn *string `json:"deletedOn" tfsdk:"deleted_on"`
Tags map[string][]string `json:"tags" tfsdk:"tags"`
}

type MeshWorkspaceSpec struct {
DisplayName string `json:"displayName" tfsdk:"display_name"`
PlatformBuilderAccessEnabled *bool `json:"platformBuilderAccessEnabled,omitempty" tfsdk:"platform_builder_access_enabled"`
}

type MeshWorkspaceCreate struct {
ApiVersion string `json:"apiVersion" tfsdk:"api_version"`
Metadata MeshWorkspaceCreateMetadata `json:"metadata" tfsdk:"metadata"`
Spec MeshWorkspaceSpec `json:"spec" tfsdk:"spec"`
}
type MeshWorkspaceCreateMetadata struct {
Name string `json:"name" tfsdk:"name"`
Tags map[string][]string `json:"tags" tfsdk:"tags"`
}

func (c *MeshStackProviderClient) urlForWorkspace(name string) *url.URL {
return c.endpoints.Workspaces.JoinPath(name)
}

func (c *MeshStackProviderClient) ReadWorkspace(name string) (*MeshWorkspace, error) {
targetUrl := c.urlForWorkspace(name)
req, err := http.NewRequest("GET", targetUrl.String(), nil)
if err != nil {
return nil, err
}
req.Header.Set("Accept", CONTENT_TYPE_WORKSPACE)

res, err := c.doAuthenticatedRequest(req)
if err != nil {
return nil, err
}

defer res.Body.Close()

if res.StatusCode == http.StatusNotFound {
return nil, nil // Not found is not an error
}

data, err := io.ReadAll(res.Body)
if err != nil {
return nil, err
}

if !isSuccessHTTPStatus(res) {
return nil, fmt.Errorf("unexpected status code: %d, %s", res.StatusCode, data)
}

var workspace MeshWorkspace
err = json.Unmarshal(data, &workspace)
if err != nil {
return nil, err
}
return &workspace, nil
}

func (c *MeshStackProviderClient) CreateWorkspace(workspace *MeshWorkspaceCreate) (*MeshWorkspace, error) {
paylod, err := json.Marshal(workspace)
if err != nil {
return nil, err
}

req, err := http.NewRequest("POST", c.endpoints.Workspaces.String(), bytes.NewBuffer(paylod))
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", CONTENT_TYPE_WORKSPACE)
req.Header.Set("Accept", CONTENT_TYPE_WORKSPACE)

res, err := c.doAuthenticatedRequest(req)
if err != nil {
return nil, err
}
defer res.Body.Close()

data, err := io.ReadAll(res.Body)
if err != nil {
return nil, err
}

if !isSuccessHTTPStatus(res) {
return nil, fmt.Errorf("unexpected status code: %d, %s", res.StatusCode, data)
}

var createdWorkspace MeshWorkspace
err = json.Unmarshal(data, &createdWorkspace)
if err != nil {
return nil, err
}
return &createdWorkspace, nil
}

func (c *MeshStackProviderClient) UpdateWorkspace(name string, workspace *MeshWorkspaceCreate) (*MeshWorkspace, error) {
targetUrl := c.urlForWorkspace(name)

paylod, err := json.Marshal(workspace)
if err != nil {
return nil, err
}

req, err := http.NewRequest("PUT", targetUrl.String(), bytes.NewBuffer(paylod))
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", CONTENT_TYPE_WORKSPACE)
req.Header.Set("Accept", CONTENT_TYPE_WORKSPACE)

res, err := c.doAuthenticatedRequest(req)
if err != nil {
return nil, err
}
defer res.Body.Close()

data, err := io.ReadAll(res.Body)
if err != nil {
return nil, err
}

if !isSuccessHTTPStatus(res) {
return nil, fmt.Errorf("unexpected status code: %d, %s", res.StatusCode, data)
}

var updatedWorkspace MeshWorkspace
err = json.Unmarshal(data, &updatedWorkspace)
if err != nil {
return nil, err
}
return &updatedWorkspace, nil
}

func (c *MeshStackProviderClient) DeleteWorkspace(name string) error {
targetUrl := c.urlForWorkspace(name)
return c.deleteMeshObject(*targetUrl, 204)
}
2 changes: 1 addition & 1 deletion docs/data-sources/project.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ data "meshstack_project" "example" {
### Read-Only

- `api_version` (String) Project datatype version
- `kind` (String) meshObject type, always `meshBuildingBlock`.
- `kind` (String) meshObject type, always `meshProject`.
- `spec` (Attributes) Project specification. (see [below for nested schema](#nestedatt--spec))

<a id="nestedatt--metadata"></a>
Expand Down
56 changes: 56 additions & 0 deletions docs/data-sources/workspace.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "meshstack_workspace Data Source - terraform-provider-meshstack"
subcategory: ""
description: |-
Read a single workspace by identifier.
---

# meshstack_workspace (Data Source)

Read a single workspace by identifier.

## Example Usage

```terraform
data "meshstack_workspace" "example" {
metadata = {
name = "my-workspace-identifier"
}
}
```

<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `metadata` (Attributes) (see [below for nested schema](#nestedatt--metadata))

### Read-Only

- `api_version` (String) Workspace API version.
- `kind` (String) meshObject type, always `meshWorkspace`.
- `spec` (Attributes) (see [below for nested schema](#nestedatt--spec))

<a id="nestedatt--metadata"></a>
### Nested Schema for `metadata`

Required:

- `name` (String) Workspace identifier.

Read-Only:

- `created_on` (String) Creation date of the workspace.
- `deleted_on` (String) Deletion date of the workspace.
- `tags` (Map of List of String) Tags of the workspace.


<a id="nestedatt--spec"></a>
### Nested Schema for `spec`

Read-Only:

- `display_name` (String) Display name of the workspace.
- `platform_builder_access_enabled` (Boolean) Whether platform builder access is enabled for the workspace.
82 changes: 82 additions & 0 deletions docs/resources/workspace.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "meshstack_workspace Resource - terraform-provider-meshstack"
subcategory: ""
description: |-
Represents a meshStack workspace.
~> Note: Managing workspaces requires an API key with sufficient admin permissions.
---

# meshstack_workspace (Resource)

Represents a meshStack workspace.

~> **Note:** Managing workspaces requires an API key with sufficient admin permissions.

## Example Usage

```terraform
resource "meshstack_workspace" "example" {
metadata = {
name = "my-workspace-identifier"
tags = {
"cost-center" = [
"12345"
]
}
}
spec = {
display_name = "My Workspace's Display Name"
}
}
```

<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `metadata` (Attributes) (see [below for nested schema](#nestedatt--metadata))
- `spec` (Attributes) (see [below for nested schema](#nestedatt--spec))

### Read-Only

- `api_version` (String) Workspace datatype version
- `kind` (String) meshObject type, always `meshWorkspace`.

<a id="nestedatt--metadata"></a>
### Nested Schema for `metadata`

Required:

- `name` (String) Workspace identifier.

Optional:

- `tags` (Map of List of String) Tags of the workspace.

Read-Only:

- `created_on` (String) Creation date of the workspace.
- `deleted_on` (String) Deletion date of the workspace.


<a id="nestedatt--spec"></a>
### Nested Schema for `spec`

Required:

- `display_name` (String) Display name of the workspace.

Optional:

- `platform_builder_access_enabled` (Boolean) Whether platform builder access is enabled for the workspace.

## Import

Import is supported using the following syntax:

```shell
# import via workspace identifier
terraform import meshstack_workspace.example my-workspace-identifier
```
5 changes: 5 additions & 0 deletions examples/data-sources/meshstack_workspace/data-source.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
data "meshstack_workspace" "example" {
metadata = {
name = "my-workspace-identifier"
}
}
2 changes: 2 additions & 0 deletions examples/resources/meshstack_workspace/import.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# import via workspace identifier
terraform import meshstack_workspace.example my-workspace-identifier
13 changes: 13 additions & 0 deletions examples/resources/meshstack_workspace/resource.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
resource "meshstack_workspace" "example" {
metadata = {
name = "my-workspace-identifier"
tags = {
"cost-center" = [
"12345"
]
}
}
spec = {
display_name = "My Workspace's Display Name"
}
}
2 changes: 1 addition & 1 deletion internal/provider/project_data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func (d *projectDataSource) Schema(ctx context.Context, req datasource.SchemaReq
},

"kind": schema.StringAttribute{
MarkdownDescription: "meshObject type, always `meshBuildingBlock`.",
MarkdownDescription: "meshObject type, always `meshProject`.",
Computed: true,
Validators: []validator.String{
stringvalidator.OneOf([]string{"meshProject"}...),
Expand Down
2 changes: 2 additions & 0 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ func (p *MeshStackProvider) Resources(ctx context.Context) []func() resource.Res
NewTenantResource,
NewProjectUserBindingResource,
NewProjectGroupBindingResource,
NewWorkspaceResource,
NewBuildingBlockResource,
NewBuildingBlockV2Resource,
NewTagDefinitionResource,
Expand All @@ -121,6 +122,7 @@ func (p *MeshStackProvider) DataSources(ctx context.Context) []func() datasource
NewProjectsDataSource,
NewProjectUserBindingDataSource,
NewProjectGroupBindingDataSource,
NewWorkspaceDataSource,
NewTenantDataSource,
NewTagDefinitionDataSource,
NewTagDefinitionsDataSource,
Expand Down
Loading
Loading