Skip to content

Commit

Permalink
Refactor/migrate region (#230)
Browse files Browse the repository at this point in the history
* refactor: rewrite datasource_projects with terraform-plugin-framework

* test: Added acctest for project resource

* fix: Use other test helper

* fix: Fixed acc failure

* fix: Fixed pre-commit

* fix: Fixed compile error

* fix: Fixed go fmt and goimports

* fix: Added UT for configure function

* feat: Added import for project resource

* refactor: rewrite datasource_projects with terraform-plugin-framework

* test: Added acctest for project resource

* fix: Use other test helper

* fix: Fixed acc failure

* fix: fixed typo

* fix: Fixed acc failure

* refactor: rewrite resource_region with terraform-plugin-framework

* refactor: rewrite datasource_region with terraform-plugin-framework

* fix: Fixed golint

* fix: Removed useless code

* fix: Updated name to biganimal_regions

* fix: Fixed datasource regions

* fix: Staticcheck S1011

https://staticcheck.io/docs/checks#S1011

S1011 - Use a single append to concatenate two slices

* feat: Further work on Region resource

* Reordered the file contents
* Use RegionClient for the CRUD operations
* Use schema instead of frameworkschema, there is only frameworkschema
  here in the end
* various pointer juggling, the code is not tested well

* style: whitespace cosmetics

* fix: Changed datasource region to regions for naming conversion

* feat: Added import for region resource

* fix: Add PlanModifiers for id attr

* fix: Keep datasource_region existing before releasing major version

* test: Added acctest for region datasource

* fix: Fixed comments

* fix: Fixed make docs

* docs: Add docs for regions data source.

* feat: Add import for biganimal_region resource.

* fix: Added equal sign after variable name

Co-authored-by: Serdar Dalgıç <[email protected]>

* fix: Updated message.

Co-authored-by: Serdar Dalgıç <[email protected]>

* fix: Updated message.

Co-authored-by: Serdar Dalgıç <[email protected]>

* fix: Updated message.

Co-authored-by: Serdar Dalgıç <[email protected]>

* fix: Use `frameworkdiag` for more specific

Co-authored-by: Serdar Dalgıç <[email protected]>

* fix: Use `sdkdiag ` for more specific

Co-authored-by: Serdar Dalgıç <[email protected]>

* fix: Run make docs

* fix: Fixed unexpected of terraform plan and inconsistent result after apply

* fix: Fixed test failure

* feat: Add helper function for BA API Errors

* fix: Handle BigAnimal Error

* fix: Removed data_source_regions

* fix: Correct regions -> region in the ACC test

* fix: Removed data_source_regions

* fix: remove the unused biganimal_regions data sources.

* fix: Fixed panic

---------

Co-authored-by: Serdar Dalgic <[email protected]>
Co-authored-by: Serdar Dalgıç <[email protected]>
  • Loading branch information
3 people authored Jul 11, 2023
1 parent 272d16b commit 92afa7f
Show file tree
Hide file tree
Showing 17 changed files with 429 additions and 225 deletions.
5 changes: 5 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,8 @@ BA_TF_ACC_VAR_region_region_id=
# data_source_pgd
BA_TF_ACC_VAR_pgd_project_id=
BA_TF_ACC_VAR_pgd_name=

# data_source_region
BA_TF_ACC_VAR_ds_region_project_id=
BA_TF_ACC_VAR_ds_region_provider=
BA_TF_ACC_VAR_ds_region_region_id=
20 changes: 10 additions & 10 deletions docs/data-sources/region.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# biganimal_region (Data Source)
The region data source shows the available regions within a cloud provider.


## Example Usage
```terraform
Expand All @@ -8,8 +8,8 @@ variable "cloud_provider" {
description = "Cloud Provider"
validation {
condition = contains(["aws", "azure"], var.cloud_provider)
error_message = "Please select one of the supported regions: aws, azure."
condition = contains(["aws", "azure", "bah:aws"], var.cloud_provider)
error_message = "Please select one of the supported regions: aws, azure or bah:aws."
}
}
Expand Down Expand Up @@ -40,7 +40,7 @@ output "cloud_provider_id" {

### Required

- `cloud_provider` (String) Cloud provider to list the regions. For example, "aws" or "azure".
- `cloud_provider` (String) Cloud provider to list the regions. For example, "aws", "azure" or "bah:aws".
- `project_id` (String) BigAnimal Project ID.

### Optional
Expand All @@ -50,15 +50,15 @@ output "cloud_provider_id" {

### Read-Only

- `id` (String) The ID of this resource.
- `regions` (List of Object) Region information. (see [below for nested schema](#nestedatt--regions))
- `id` (String) Datasource ID.
- `regions` (Attributes List) Region information. (see [below for nested schema](#nestedatt--regions))

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

Read-Only:

- `continent` (String)
- `name` (String)
- `region_id` (String)
- `status` (String)
- `continent` (String) Continent that region belongs to.
- `name` (String) Region name of the region.
- `region_id` (String) Region ID of the region.
- `status` (String) Region status of the region.
13 changes: 11 additions & 2 deletions docs/resources/region.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ output "region_continent" {

### Required

- `cloud_provider` (String) Cloud provider. For example, "aws" or "azure".
- `cloud_provider` (String) Cloud provider. For example, "aws", "azure" or "bah:aws".
- `project_id` (String) BigAnimal Project ID.
- `region_id` (String) Region ID of the region. For example, "germanywestcentral" in the Azure cloud provider or "eu-west-1" in the AWS cloud provider.

Expand All @@ -55,7 +55,7 @@ output "region_continent" {
### Read-Only

- `continent` (String) Continent that region belongs to. For example, "Asia", "Australia", or "Europe".
- `id` (String) The ID of this resource.
- `id` (String) Resource ID of the region.
- `name` (String) Region name of the region. For example, "Germany West Central" or "EU West 1".

<a id="nestedblock--timeouts"></a>
Expand All @@ -66,3 +66,12 @@ Optional:
- `create` (String)
- `delete` (String)
- `update` (String)

## Import

Import is supported using the following syntax:

```shell
# terraform import biganimal_project.<resource_name> <project_id>/<cloud_provider>/<region_id>
terraform import biganimal_region.this prj_deadbeef01234567/aws/eu-west-1
```
4 changes: 2 additions & 2 deletions examples/data-sources/biganimal_region/data-source.tf
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ variable "cloud_provider" {
description = "Cloud Provider"

validation {
condition = contains(["aws", "azure"], var.cloud_provider)
error_message = "Please select one of the supported regions: aws, azure."
condition = contains(["aws", "azure", "bah:aws"], var.cloud_provider)
error_message = "Please select one of the supported regions: aws, azure or bah:aws."
}
}

Expand Down
2 changes: 2 additions & 0 deletions examples/resources/biganimal_region/import.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# terraform import biganimal_project.<resource_name> <project_id>/<cloud_provider>/<region_id>
terraform import biganimal_region.this prj_deadbeef01234567/aws/eu-west-1
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ require (
github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320
github.com/hashicorp/terraform-plugin-docs v0.15.0
github.com/hashicorp/terraform-plugin-framework v1.3.1
github.com/hashicorp/terraform-plugin-framework-timeouts v0.3.1
github.com/hashicorp/terraform-plugin-framework-validators v0.10.0
github.com/hashicorp/terraform-plugin-go v0.16.0
github.com/hashicorp/terraform-plugin-log v0.9.0
github.com/hashicorp/terraform-plugin-mux v0.10.0
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ github.com/hashicorp/terraform-plugin-docs v0.15.0 h1:W5xYB5kCUBqO7lyjE2UMmUBh95
github.com/hashicorp/terraform-plugin-docs v0.15.0/go.mod h1:K5Taof1Y7sL4dw6Ie0qMFyQnHN0W+RSVMD0iIyFDFJc=
github.com/hashicorp/terraform-plugin-framework v1.3.1 h1:uhd+SuyuDq3oh5VB2Toq5IPyaC5XFAUf9vUFKBmNNOk=
github.com/hashicorp/terraform-plugin-framework v1.3.1/go.mod h1:A1WD3Ry7FhrThViUTbkx4ZDsMq9oaAv4U9oTI8bBzCU=
github.com/hashicorp/terraform-plugin-framework-timeouts v0.3.1 h1:5GhozvHUsrqxqku+yd0UIRTkmDLp2QPX5paL1Kq5uUA=
github.com/hashicorp/terraform-plugin-framework-timeouts v0.3.1/go.mod h1:ThtYDU8p6sJ9+SI+TYxXrw28vXxgBwYOpoPv1EojSJI=
github.com/hashicorp/terraform-plugin-framework-validators v0.10.0 h1:4L0tmy/8esP6OcvocVymw52lY0HyQ5OxB7VNl7k4bS0=
github.com/hashicorp/terraform-plugin-framework-validators v0.10.0/go.mod h1:qdQJCdimB9JeX2YwOpItEu+IrfoJjWQ5PhLpAOMDQAE=
github.com/hashicorp/terraform-plugin-go v0.16.0 h1:DSOQ0rz5FUiVO4NUzMs8ln9gsPgHMTsfns7Nk+6gPuE=
github.com/hashicorp/terraform-plugin-go v0.16.0/go.mod h1:4sn8bFuDbt+2+Yztt35IbOrvZc0zyEi87gJzsTgCES8=
github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0=
Expand Down
3 changes: 2 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package main
import (
"context"
"flag"
"log"

"github.com/EnterpriseDB/terraform-provider-biganimal/pkg/provider"
"github.com/hashicorp/terraform-plugin-framework/providerserver"
"github.com/hashicorp/terraform-plugin-go/tfprotov5"
Expand All @@ -11,7 +13,6 @@ import (
"github.com/hashicorp/terraform-plugin-mux/tf5to6server"
"github.com/hashicorp/terraform-plugin-mux/tf6muxserver"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"log"
)

// Run "go generate" to format example terraform files and generate the docs for the registry/website
Expand Down
8 changes: 4 additions & 4 deletions pkg/models/region.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package models

type Region struct {
Id string `json:"regionId,omitempty" mapstructure:"region_id"`
Name string `json:"regionName,omitempty" mapstructure:"name,omitempty"`
Status string `json:"status,omitempty" mapstructure:"status,omitempty"`
Continent string `json:"continent,omitempty" mapstructure:"continent,omitempty"`
Id string `json:"regionId,omitempty" tfsdk:"region_id"`
Name string `json:"regionName,omitempty" tfsdk:"name"`
Status string `json:"status,omitempty" tfsdk:"status"`
Continent string `json:"continent,omitempty" tfsdk:"continent"`
}

func (r Region) String() string {
Expand Down
157 changes: 92 additions & 65 deletions pkg/provider/data_source_region.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,114 +2,141 @@ package provider

import (
"context"
"errors"
"fmt"
"strconv"
"time"

"github.com/EnterpriseDB/terraform-provider-biganimal/pkg/api"
"github.com/EnterpriseDB/terraform-provider-biganimal/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/EnterpriseDB/terraform-provider-biganimal/pkg/models"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
)

// RegionResource is a struct to namespace all the functions
// involved in the Region Resource. When multiple resources and objects
// are in the same pkg/provider, then it's difficult to namespace things well
type RegionData struct{}
var _ datasource.DataSourceWithConfigure = &regionsDataSource{}

func NewRegionData() *RegionData {
return &RegionData{}
// NewRegionsDataSource is a helper function to simplify the provider implementation.
func NewRegionsDataSource() datasource.DataSource {
return &regionsDataSource{}
}

func (r *RegionData) Schema() *schema.Resource {
return &schema.Resource{
Description: "The region data source shows the available regions within a cloud provider.",
ReadContext: r.Read,
// regionsDataSource is the data source implementation.
type regionsDataSource struct {
client *api.RegionClient
}

// Configure adds the provider configured client to the data source.
func (r *regionsDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
if req.ProviderData == nil {
return
}

r.client = req.ProviderData.(*api.API).RegionClient()
}

func (r *regionsDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_region"
}

//{
// "regionId": "eu-west-1",
// "regionName": "EU West 1",
// "status": "ACTIVE",
// "continent": "Europe"
//}
Schema: map[string]*schema.Schema{
"regions": {
func (r *regionsDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
Description: "Datasource ID.",
Computed: true,
},
"regions": schema.ListNestedAttribute{
Description: "Region information.",
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"region_id": {
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
"region_id": schema.StringAttribute{
Description: "Region ID of the region.",
Type: schema.TypeString,
Computed: true,
},
"name": {
"name": schema.StringAttribute{
Description: "Region name of the region.",
Type: schema.TypeString,
Computed: true,
},
"status": {
"status": schema.StringAttribute{
Description: "Region status of the region.",
Type: schema.TypeString,
Computed: true,
},
"continent": {
"continent": schema.StringAttribute{
Description: "Continent that region belongs to.",
Type: schema.TypeString,
Computed: true,
},
},
},
},
"cloud_provider": {
Description: "Cloud provider to list the regions. For example, \"aws\" or \"azure\".",
Type: schema.TypeString,

"cloud_provider": schema.StringAttribute{
Description: "Cloud provider to list the regions. For example, \"aws\", \"azure\" or \"bah:aws\".",
Required: true,
},
"project_id": {
Description: "BigAnimal Project ID.",
Type: schema.TypeString,
Required: true,
ValidateDiagFunc: validateProjectId,
"project_id": schema.StringAttribute{
Description: "BigAnimal Project ID.",
Required: true,
Validators: []validator.String{
ProjectIdValidator(),
},
},
"query": {
"query": schema.StringAttribute{
Description: "Query to filter region list.",
Type: schema.TypeString,
Optional: true,
},
"region_id": {
"region_id": schema.StringAttribute{
Description: "Unique region ID. For example, \"germanywestcentral\" in the Azure cloud provider, \"eu-west-1\" in the AWS cloud provider.",
Type: schema.TypeString,
Optional: true,
},
},
}
}

func (r *RegionData) Read(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics {
diags := diag.Diagnostics{}
client := api.BuildAPI(meta).RegionClient()
cloud_provider := d.Get("cloud_provider").(string)
projectId := d.Get("project_id").(string)

query := d.Get("query").(string)
type regionsDataSourceModel struct {
ID *string `tfsdk:"id"`
ProjectId *string `tfsdk:"project_id"`
CloudProvider *string `tfsdk:"cloud_provider"`
RegionId *string `tfsdk:"region_id"`
Query types.String `tfsdk:"query"`
Regions []*models.Region `tfsdk:"regions"`
}

id, ok := d.Get("region_id").(string)
if ok {
query = id
func (r *regionsDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
var cfg regionsDataSourceModel
diags := req.Config.Get(ctx, &cfg)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}

regions, err := client.List(ctx, projectId, cloud_provider, query)
if err != nil {
return fromBigAnimalErr(err)
}
regions := []*models.Region{}
if cfg.RegionId != nil {
region, err := r.client.Read(ctx, *cfg.ProjectId, *cfg.CloudProvider, *cfg.RegionId)
if err != nil {
if appendDiagFromBAErr(err, &diags) {
return
}
diags.AddError(fmt.Sprintf("Error reading region by id: %q", *cfg.RegionId), err.Error())
return
}
regions = append(regions, region)

if id != "" && len(regions) != 1 {
return diag.FromErr(errors.New("unable to find a unique region"))
} else {
respRegions, err := r.client.List(ctx, *cfg.ProjectId, *cfg.CloudProvider, cfg.Query.ValueString())
if err != nil {
if appendDiagFromBAErr(err, &diags) {
return
}
diags.AddError(fmt.Sprintf("Error reading region by query: %q", cfg.Query.ValueString()), err.Error())
return
}
regions = respRegions
}

utils.SetOrPanic(d, "regions", regions)
d.SetId(fmt.Sprintf("%s/%s", cloud_provider, query))

return diags
cfg.Regions = append(cfg.Regions, regions...)
resourceID := strconv.FormatInt(time.Now().Unix(), 10)
cfg.ID = &resourceID
resp.Diagnostics.Append(resp.State.Set(ctx, &cfg)...)
}
Loading

0 comments on commit 92afa7f

Please sign in to comment.