Skip to content

Commit

Permalink
feat: projects data source
Browse files Browse the repository at this point in the history
  • Loading branch information
malhussan committed Jun 17, 2024
1 parent 1d328ef commit 09eb81b
Show file tree
Hide file tree
Showing 5 changed files with 298 additions and 0 deletions.
72 changes: 72 additions & 0 deletions docs/data-sources/projects.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "meshstack_projects Data Source - terraform-provider-meshstack"
subcategory: ""
description: |-
Projects in a workspace.
---

# meshstack_projects (Data Source)

Projects in a workspace.

## Example Usage

```terraform
data "meshstack_projects" "example_all_projects_in_workspace" {
workspace_identifier = "my-workspace-identifier"
}
data "meshstack_projects" "example_all_projects_in_workspace_with_payment_method" {
workspace_identifier = "my-workspace-identifier"
# use empty string "" for listing projects without a payment method, omit for all projects
payment_method_identifier = "my-payment-method-identifier"
}
```

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

### Required

- `workspace_identifier` (String) Workspace identifier

### Optional

- `payment_method_identifier` (String) Payment method identifier

### Read-Only

- `projects` (Attributes List) List of projects (see [below for nested schema](#nestedatt--projects))

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

Read-Only:

- `api_version` (String) API version
- `kind` (String) Kind of project
- `metadata` (Attributes) Metadata of the project (see [below for nested schema](#nestedatt--projects--metadata))
- `spec` (Attributes) Specifications of the project (see [below for nested schema](#nestedatt--projects--spec))

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

Read-Only:

- `created_on` (String) Creation date of the project
- `deleted_on` (String) Deletion date of the project
- `name` (String) Name of the project
- `owned_by_workspace` (String) Workspace that owns the project


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

Read-Only:

- `display_name` (String) Display name of the project
- `payment_method_identifier` (String) Payment method identifier
- `substitute_payment_method_identifier` (String) Substitute payment method identifier
- `tags` (Map of List of String) Tags associated with the project
10 changes: 10 additions & 0 deletions examples/data-sources/meshstack_projects/data-source.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
data "meshstack_projects" "example_all_projects_in_workspace" {
workspace_identifier = "my-workspace-identifier"
}

data "meshstack_projects" "example_all_projects_in_workspace_with_payment_method" {
workspace_identifier = "my-workspace-identifier"

# use empty string "" for listing projects without a payment method, omit for all projects
payment_method_identifier = "my-payment-method-identifier"
}
69 changes: 69 additions & 0 deletions internal/provider/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,75 @@ func (c *MeshStackProviderClient) ReadProject(workspace string, name string) (*M
return &project, nil
}

func (c *MeshStackProviderClient) ReadProjects(workspaceIdentifier string, paymentMethodIdentifier *string) (*[]MeshProject, error) {
var allProjects []MeshProject

pageNumber := 0
targetUrl := c.endpoints.Projects
query := targetUrl.Query()
query.Set("workspaceIdentifier", workspaceIdentifier)
if paymentMethodIdentifier != nil {
query.Set("paymentIdentifier", *paymentMethodIdentifier)
}

for {
query.Set("page", fmt.Sprintf("%d", pageNumber))

targetUrl.RawQuery = query.Encode()

req, err := http.NewRequest("GET", targetUrl.String(), nil)
if err != nil {
return nil, err
}

req.Header.Set("Accept", CONTENT_TYPE_PROJECT)

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, fmt.Errorf("failed to read response body: %w", err)
}

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

var response struct {
Embedded struct {
MeshProjects []MeshProject `json:"meshProjects"`
} `json:"_embedded"`
Page struct {
Size int `json:"size"`
TotalElements int `json:"totalElements"`
TotalPages int `json:"totalPages"`
Number int `json:"number"`
} `json:"page"`
}

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

allProjects = append(allProjects, response.Embedded.MeshProjects...)

// Check if there are more pages
if response.Page.Number >= response.Page.TotalPages-1 {
break
}

pageNumber++
}

return &allProjects, nil
}

func (c *MeshStackProviderClient) CreateProject(project *MeshProjectCreate) (*MeshProject, error) {
payload, err := json.Marshal(project)
if err != nil {
Expand Down
146 changes: 146 additions & 0 deletions internal/provider/projects_data_source.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
package provider

import (
"context"
"fmt"

"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/types"
)

// Ensure provider defined types fully satisfy framework interfaces.
var (
_ datasource.DataSource = &projectsDataSource{}
_ datasource.DataSourceWithConfigure = &projectsDataSource{}
)

func NewProjectsDataSource() datasource.DataSource {
return &projectsDataSource{}
}

type projectsDataSource struct {
client *MeshStackProviderClient
}

func (d *projectsDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_projects"
}

func (d *projectsDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{
MarkdownDescription: "Projects in a workspace.",

Attributes: map[string]schema.Attribute{
"workspace_identifier": schema.StringAttribute{
MarkdownDescription: "Workspace identifier",
Required: true,
},
"payment_method_identifier": schema.StringAttribute{
MarkdownDescription: "Payment method identifier",
Optional: true,
},
"projects": schema.ListNestedAttribute{
MarkdownDescription: "List of projects",
Computed: true,
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
"api_version": schema.StringAttribute{
MarkdownDescription: "API version",
Computed: true,
},
"kind": schema.StringAttribute{
MarkdownDescription: "Kind of project",
Computed: true,
},
"metadata": schema.SingleNestedAttribute{
MarkdownDescription: "Metadata of the project",
Computed: true,
Attributes: map[string]schema.Attribute{
"name": schema.StringAttribute{
MarkdownDescription: "Name of the project",
Computed: true,
},
"owned_by_workspace": schema.StringAttribute{
MarkdownDescription: "Workspace that owns the project",
Computed: true,
},
"created_on": schema.StringAttribute{
MarkdownDescription: "Creation date of the project",
Computed: true,
},
"deleted_on": schema.StringAttribute{
MarkdownDescription: "Deletion date of the project",
Computed: true,
},
},
},
"spec": schema.SingleNestedAttribute{
MarkdownDescription: "Specifications of the project",
Computed: true,
Attributes: map[string]schema.Attribute{
"display_name": schema.StringAttribute{
MarkdownDescription: "Display name of the project",
Computed: true,
},
"tags": schema.MapAttribute{
MarkdownDescription: "Tags associated with the project",
Computed: true,
ElementType: types.ListType{ElemType: types.StringType},
},
"payment_method_identifier": schema.StringAttribute{
MarkdownDescription: "Payment method identifier",
Computed: true,
},
"substitute_payment_method_identifier": schema.StringAttribute{
MarkdownDescription: "Substitute payment method identifier",
Computed: true,
},
},
},
},
},
},
},
}
}

func (d *projectsDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
if req.ProviderData == nil {
return
}

client, ok := req.ProviderData.(*MeshStackProviderClient)

if !ok {
resp.Diagnostics.AddError(
"Unexpected Data Source Configure Type",
fmt.Sprintf("Expected *MeshStackProviderClient, got: %T. Please report this issue to the provider developers.", req.ProviderData),
)

return
}

d.client = client
}

func (d *projectsDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
var workspaceIdentifier string
var paymentMethodIdentifier *string

resp.Diagnostics.Append(req.Config.GetAttribute(ctx, path.Root("workspace_identifier"), &workspaceIdentifier)...)
resp.Diagnostics.Append(req.Config.GetAttribute(ctx, path.Root("payment_method_identifier"), &paymentMethodIdentifier)...)

if resp.Diagnostics.HasError() {
return
}

projects, err := d.client.ReadProjects(workspaceIdentifier, paymentMethodIdentifier)
if err != nil {
resp.Diagnostics.AddError("Unable to read projects", err.Error())
return
}

resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("projects"), &projects)...)
}
1 change: 1 addition & 0 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ func (p *MeshStackProvider) DataSources(ctx context.Context) []func() datasource
return []func() datasource.DataSource{
NewBuildingBlockDataSource,
NewProjectDataSource,
NewProjectsDataSource,
NewTenantDataSource,
}
}
Expand Down

0 comments on commit 09eb81b

Please sign in to comment.