Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: integrate terraform-plugin-mux and reimplement r/network_pool using the plugin framework #192

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
9 changes: 5 additions & 4 deletions docs/resources/network_pool.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,12 @@ The following data is prerequisite for creating a new Network Pool

### Optional

- `timeouts` (Block, Optional) (see [below for nested schema](#nestedblock--timeouts))
- `network` (Block List) Represents a network in a network pool (see [below for nested schema](#nestedblock--network))
- `timeouts` (Attributes) (see [below for nested schema](#nestedatt--timeouts))

### Read-Only

- `id` (String) The ID of this resource.
- `id` (String) Service generated identifier for the network pool.

<a id="nestedblock--network"></a>
### Nested Schema for `network`
Expand Down Expand Up @@ -67,9 +68,9 @@ Optional:



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

Optional:

- `create` (String)
- `create` (String) A string that can be [parsed as a duration](https://pkg.go.dev/time#ParseDuration) consisting of numbers and unit suffixes, such as "30s" or "2h45m". Valid time units are "s" (seconds), "m" (minutes), "h" (hours).
6 changes: 5 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ require (
github.com/go-openapi/runtime v0.28.0
github.com/go-openapi/strfmt v0.23.0
github.com/hashicorp/terraform-plugin-docs v0.19.4
github.com/hashicorp/terraform-plugin-framework v1.9.0
github.com/hashicorp/terraform-plugin-framework-validators v0.12.0
github.com/hashicorp/terraform-plugin-framework-timeouts v0.4.1
github.com/hashicorp/terraform-plugin-go v0.23.0
github.com/hashicorp/terraform-plugin-log v0.9.0
github.com/hashicorp/terraform-plugin-mux v0.16.0
github.com/hashicorp/terraform-plugin-sdk/v2 v2.34.0
github.com/stretchr/testify v1.9.0
github.com/vmware/vcf-sdk-go v0.3.2
Expand Down Expand Up @@ -57,7 +62,6 @@ require (
github.com/hashicorp/logutils v1.0.0 // indirect
github.com/hashicorp/terraform-exec v0.21.0 // indirect
github.com/hashicorp/terraform-json v0.22.1 // indirect
github.com/hashicorp/terraform-plugin-go v0.23.0 // indirect
github.com/hashicorp/terraform-registry-address v0.2.3 // indirect
github.com/hashicorp/terraform-svchost v0.1.1 // indirect
github.com/hashicorp/yamux v0.1.1 // indirect
Expand Down
8 changes: 8 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -126,10 +126,18 @@ github.com/hashicorp/terraform-json v0.22.1 h1:xft84GZR0QzjPVWs4lRUwvTcPnegqlyS7
github.com/hashicorp/terraform-json v0.22.1/go.mod h1:JbWSQCLFSXFFhg42T7l9iJwdGXBYV8fmmD6o/ML4p3A=
github.com/hashicorp/terraform-plugin-docs v0.19.4 h1:G3Bgo7J22OMtegIgn8Cd/CaSeyEljqjH3G39w28JK4c=
github.com/hashicorp/terraform-plugin-docs v0.19.4/go.mod h1:4pLASsatTmRynVzsjEhbXZ6s7xBlUw/2Kt0zfrq8HxA=
github.com/hashicorp/terraform-plugin-framework v1.9.0 h1:caLcDoxiRucNi2hk8+j3kJwkKfvHznubyFsJMWfZqKU=
github.com/hashicorp/terraform-plugin-framework v1.9.0/go.mod h1:qBXLDn69kM97NNVi/MQ9qgd1uWWsVftGSnygYG1tImM=
github.com/hashicorp/terraform-plugin-framework-timeouts v0.4.1 h1:gm5b1kHgFFhaKFhm4h2TgvMUlNzFAtUqlcOWnWPm+9E=
github.com/hashicorp/terraform-plugin-framework-timeouts v0.4.1/go.mod h1:MsjL1sQ9L7wGwzJ5RjcI6FzEMdyoBnw+XK8ZnOvQOLY=
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.23.0 h1:AALVuU1gD1kPb48aPQUjug9Ir/125t+AAurhqphJ2Co=
github.com/hashicorp/terraform-plugin-go v0.23.0/go.mod h1:1E3Cr9h2vMlahWMbsSEcNrOCxovCZhOOIXjFHbjc/lQ=
github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0=
github.com/hashicorp/terraform-plugin-log v0.9.0/go.mod h1:rKL8egZQ/eXSyDqzLUuwUYLVdlYeamldAHSxjUFADow=
github.com/hashicorp/terraform-plugin-mux v0.16.0 h1:RCzXHGDYwUwwqfYYWJKBFaS3fQsWn/ZECEiW7p2023I=
github.com/hashicorp/terraform-plugin-mux v0.16.0/go.mod h1:PF79mAsPc8CpusXPfEVa4X8PtkB+ngWoiUClMrNZlYo=
github.com/hashicorp/terraform-plugin-sdk/v2 v2.34.0 h1:kJiWGx2kiQVo97Y5IOGR4EMcZ8DtMswHhUuFibsCQQE=
github.com/hashicorp/terraform-plugin-sdk/v2 v2.34.0/go.mod h1:sl/UoabMc37HA6ICVMmGO+/0wofkVIRxf+BMb/dnoIg=
github.com/hashicorp/terraform-registry-address v0.2.3 h1:2TAiKJ1A3MAkZlH1YI/aTVcLZRu7JseiXNRHbOAyoTI=
Expand Down
210 changes: 210 additions & 0 deletions internal/provider/framework_provider.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
// Copyright 2024 Broadcom. All Rights Reserved.
// SPDX-License-Identifier:" MPL-2.0

package provider

import (
"context"
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/provider"
"github.com/hashicorp/terraform-plugin-framework/provider/schema"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/vmware/terraform-provider-vcf/internal/api_client"
"github.com/vmware/terraform-provider-vcf/internal/constants"
"os"
"strconv"
)

type FrameworkProviderModel struct {
SddcManagerUsername types.String `tfsdk:"sddc_manager_username"`
SddcManagerPassword types.String `tfsdk:"sddc_manager_password"`
SddcManagerHost types.String `tfsdk:"sddc_manager_host"`

CloudBuilderUsername types.String `tfsdk:"cloud_builder_username"`
CloudBuilderPassword types.String `tfsdk:"cloud_builder_password"`
CloudBuilderHost types.String `tfsdk:"cloud_builder_host"`

AllowUnverifiedTls types.Bool `tfsdk:"allow_unverified_tls"`
}

type FrameworkProvider struct {
// The clients are exposed for the purpose of running the existing tests
// Individual resources should obtain access to these in their Configure methods
// via the ConfigureRequest
SddcManagerClient *api_client.SddcManagerClient
CloudBuilderClient *api_client.CloudBuilderClient
}

func New() provider.Provider {
return &FrameworkProvider{}
}

func (frameworkProvider *FrameworkProvider) Schema(ctx context.Context, req provider.SchemaRequest, res *provider.SchemaResponse) {
res.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"sddc_manager_username": schema.StringAttribute{
Optional: true,
Description: "Username to authenticate to SDDC Manager",
Validators: []validator.String{
getSddcManagerConflictsValidator(),
stringvalidator.AlsoRequires(
path.Expressions{
path.MatchRoot("sddc_manager_password"),
path.MatchRoot("sddc_manager_host"),
}...),
},
},
"sddc_manager_password": schema.StringAttribute{
Optional: true,
Description: "Password to authenticate to SDDC Manager",
Validators: []validator.String{
getSddcManagerConflictsValidator(),
stringvalidator.AlsoRequires(
path.Expressions{
path.MatchRoot("sddc_manager_username"),
path.MatchRoot("sddc_manager_host"),
}...),
},
},
"sddc_manager_host": schema.StringAttribute{
Optional: true,
Description: "Fully qualified domain name or IP address of the SDDC Manager",
Validators: []validator.String{
getSddcManagerConflictsValidator(),
stringvalidator.AlsoRequires(
path.Expressions{
path.MatchRoot("sddc_manager_username"),
path.MatchRoot("sddc_manager_password"),
}...),
},
},
"cloud_builder_username": schema.StringAttribute{
Optional: true,
Description: "Username to authenticate to CloudBuilder",
Validators: []validator.String{
getCloudBuilderConflictsValidator(),
stringvalidator.AlsoRequires(
path.Expressions{
path.MatchRoot("cloud_builder_password"),
path.MatchRoot("cloud_builder_host"),
}...),
},
},
"cloud_builder_password": schema.StringAttribute{
Optional: true,
Description: "Password to authenticate to CloudBuilder",
Validators: []validator.String{
getCloudBuilderConflictsValidator(),
stringvalidator.AlsoRequires(
path.Expressions{
path.MatchRoot("cloud_builder_username"),
path.MatchRoot("cloud_builder_host"),
}...),
},
},
"cloud_builder_host": schema.StringAttribute{
Optional: true,
Description: "Fully qualified domain name or IP address of the CloudBuilder",
Validators: []validator.String{
getCloudBuilderConflictsValidator(),
stringvalidator.AlsoRequires(
path.Expressions{
path.MatchRoot("cloud_builder_username"),
path.MatchRoot("cloud_builder_password"),
}...),
},
},
"allow_unverified_tls": schema.BoolAttribute{
Optional: true,
Description: "If set, VMware VCF client will permit unverifiable TLS certificates.",
},
},
}
}

func (frameworkProvider *FrameworkProvider) Metadata(ctx context.Context, req provider.MetadataRequest, res *provider.MetadataResponse) {
res.TypeName = "vcf"
}

func (frameworkProvider *FrameworkProvider) Resources(ctx context.Context) []func() resource.Resource {
return []func() resource.Resource{
func() resource.Resource {
return &ResourceNetworkPool{}
},
}
}

func (frameworkProvider *FrameworkProvider) DataSources(ctx context.Context) []func() datasource.DataSource {
return []func() datasource.DataSource{}
}

func (frameworkProvider *FrameworkProvider) Configure(ctx context.Context, req provider.ConfigureRequest, res *provider.ConfigureResponse) {
var data FrameworkProviderModel

res.Diagnostics.Append(req.Config.Get(ctx, &data)...)

sddcManagerUsername := getAttributeValue(data.SddcManagerUsername.ValueString(), constants.VcfTestUsername).(string)

if sddcManagerUsername != "" {
// Connect to SDDC Manager
client := api_client.NewSddcManagerClient(
sddcManagerUsername,
getAttributeValue(data.SddcManagerPassword.ValueString(), constants.VcfTestPassword).(string),
getAttributeValue(data.SddcManagerHost.ValueString(), constants.VcfTestUrl).(string),
getAttributeValue(data.AllowUnverifiedTls.ValueBool(), constants.VcfTestAllowUnverifiedTls).(bool),
)

if err := client.Connect(); err != nil {
res.Diagnostics.Append(diag.NewErrorDiagnostic("Failed to connect to the SDDC Manager", err.Error()))
}

frameworkProvider.SddcManagerClient = client
res.ResourceData = client
} else {
// Connect to Cloud Builder
client := api_client.NewCloudBuilderClient(
getAttributeValue(data.CloudBuilderUsername.ValueString(), constants.CloudBuilderTestUsername).(string),
getAttributeValue(data.CloudBuilderPassword.ValueString(), constants.CloudBuilderTestPassword).(string),
getAttributeValue(data.CloudBuilderHost.ValueString(), constants.CloudBuilderTestUrl).(string),
getAttributeValue(data.AllowUnverifiedTls.ValueBool(), constants.VcfTestAllowUnverifiedTls).(bool),
)

frameworkProvider.CloudBuilderClient = client
res.ResourceData = client
}
}

func getAttributeValue[T string | bool](data T, envVar string) interface{} {
spacegospod marked this conversation as resolved.
Show resolved Hide resolved
if envVal := os.Getenv(envVar); envVal != "" {
if val, err := strconv.ParseBool(envVal); err == nil {
return val
}

return envVal
}

return data
}

func getSddcManagerConflictsValidator() validator.String {
return stringvalidator.ConflictsWith(
path.Expressions{
path.MatchRoot("cloud_builder_username"),
path.MatchRoot("cloud_builder_password"),
path.MatchRoot("cloud_builder_host"),
}...)
}

func getCloudBuilderConflictsValidator() validator.String {
return stringvalidator.ConflictsWith(
path.Expressions{
path.MatchRoot("sddc_manager_username"),
path.MatchRoot("sddc_manager_password"),
path.MatchRoot("sddc_manager_host"),
}...)
}
1 change: 0 additions & 1 deletion internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ func Provider() *schema.Provider {
ResourcesMap: map[string]*schema.Resource{
"vcf_instance": ResourceVcfInstance(),
"vcf_user": ResourceUser(),
"vcf_network_pool": ResourceNetworkPool(),
"vcf_ceip": ResourceCeip(),
"vcf_host": ResourceHost(),
"vcf_domain": ResourceDomain(),
Expand Down
11 changes: 11 additions & 0 deletions internal/provider/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
package provider

import (
"github.com/hashicorp/terraform-plugin-framework/provider"
"github.com/hashicorp/terraform-plugin-framework/providerserver"
"github.com/hashicorp/terraform-plugin-go/tfprotov6"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/vmware/terraform-provider-vcf/internal/constants"
validationUtils "github.com/vmware/terraform-provider-vcf/internal/validation"
Expand All @@ -12,6 +15,7 @@ import (
)

var testAccProvider *schema.Provider
var testAccFrameworkProvider provider.Provider

func init() {
testAccProvider = Provider()
Expand All @@ -29,6 +33,13 @@ var providerFactories = map[string]func() (*schema.Provider, error){
},
}

func protoV6ProviderFactories() map[string]func() (tfprotov6.ProviderServer, error) {
testAccFrameworkProvider = New()
return map[string]func() (tfprotov6.ProviderServer, error){
"vcf": providerserver.NewProtocol6WithError(testAccFrameworkProvider),
}
}

// testAccPreCheck validates all required environment variables for running acceptance
// tests are set.
func testAccPreCheck(t *testing.T) {
Expand Down
Loading