This is an automated email from the ASF dual-hosted git repository.
vishesh pushed a commit to branch main
in repository
https://gitbox.apache.org/repos/asf/cloudstack-terraform-provider.git
The following commit(s) were added to refs/heads/main by this push:
new e6bcc74 feat: migrate to terraform plugin framework (#113)
e6bcc74 is described below
commit e6bcc7489e84db74e30117146b6dec8f76461eeb
Author: Fábio Matavelli <[email protected]>
AuthorDate: Thu Jul 25 01:36:50 2024 -0300
feat: migrate to terraform plugin framework (#113)
---
cloudstack/provider.go | 4 +-
cloudstack/provider_test.go | 82 +++++++++++++++++------
cloudstack/provider_v6.go | 155 ++++++++++++++++++++++++++++++++++++++++++++
cloudstack/resources.go | 23 +++++++
go.mod | 8 ++-
go.sum | 16 +++--
main.go | 32 ++++++---
7 files changed, 280 insertions(+), 40 deletions(-)
diff --git a/cloudstack/provider.go b/cloudstack/provider.go
index 6d7b7b5..5aad7c5 100644
--- a/cloudstack/provider.go
+++ b/cloudstack/provider.go
@@ -26,7 +26,7 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
-func New() *schema.Provider {
+func Provider() *schema.Provider {
return &schema.Provider{
Schema: map[string]*schema.Schema{
"api_url": {
@@ -41,6 +41,7 @@ func New() *schema.Provider {
Optional: true,
DefaultFunc:
schema.EnvDefaultFunc("CLOUDSTACK_API_KEY", nil),
ConflictsWith: []string{"config", "profile"},
+ Sensitive: true,
},
"secret_key": {
@@ -48,6 +49,7 @@ func New() *schema.Provider {
Optional: true,
DefaultFunc:
schema.EnvDefaultFunc("CLOUDSTACK_SECRET_KEY", nil),
ConflictsWith: []string{"config", "profile"},
+ Sensitive: true,
},
"config": {
diff --git a/cloudstack/provider_test.go b/cloudstack/provider_test.go
index 0a3acf0..fb868e4 100644
--- a/cloudstack/provider_test.go
+++ b/cloudstack/provider_test.go
@@ -22,10 +22,13 @@ package cloudstack
import (
"context"
"os"
+ "regexp"
"testing"
- "github.com/hashicorp/terraform-plugin-go/tfprotov5"
- "github.com/hashicorp/terraform-plugin-mux/tf5muxserver"
+ "github.com/hashicorp/terraform-plugin-framework/providerserver"
+ "github.com/hashicorp/terraform-plugin-go/tfprotov6"
+ "github.com/hashicorp/terraform-plugin-mux/tf5to6server"
+ "github.com/hashicorp/terraform-plugin-mux/tf6muxserver"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
)
@@ -33,44 +36,65 @@ import (
var testAccProviders map[string]*schema.Provider
var testAccProvider *schema.Provider
+var testAccMuxProvider map[string]func() (tfprotov6.ProviderServer, error)
+
var cloudStackTemplateURL = os.Getenv("CLOUDSTACK_TEMPLATE_URL")
func init() {
- testAccProvider = New()
+ testAccProvider = Provider()
testAccProviders = map[string]*schema.Provider{
"cloudstack": testAccProvider,
}
+
+ testAccMuxProvider = map[string]func() (tfprotov6.ProviderServer,
error){
+ "cloudstack": func() (tfprotov6.ProviderServer, error) {
+ ctx := context.Background()
+
+ upgradedSdkServer, err := tf5to6server.UpgradeServer(
+ ctx,
+ Provider().GRPCProvider,
+ )
+
+ if err != nil {
+ return nil, err
+ }
+
+ providers := []func() tfprotov6.ProviderServer{
+ providerserver.NewProtocol6(New()),
+ func() tfprotov6.ProviderServer {
+ return upgradedSdkServer
+ },
+ }
+
+ muxServer, err := tf6muxserver.NewMuxServer(ctx,
providers...)
+
+ if err != nil {
+ return nil, err
+ }
+
+ return muxServer.ProviderServer(), nil
+ },
+ }
}
func TestProvider(t *testing.T) {
- if err := New().InternalValidate(); err != nil {
+ if err := Provider().InternalValidate(); err != nil {
t.Fatalf("err: %s", err)
}
}
func TestProvider_impl(t *testing.T) {
- var _ *schema.Provider = New()
+ var _ *schema.Provider = Provider()
}
func TestMuxServer(t *testing.T) {
resource.Test(t, resource.TestCase{
- ProtoV5ProviderFactories: map[string]func()
(tfprotov5.ProviderServer, error){
- "cloudstack": func() (tfprotov5.ProviderServer, error) {
- ctx := context.Background()
- providers := []func() tfprotov5.ProviderServer{
- New().GRPCProvider,
- }
-
- muxServer, err :=
tf5muxserver.NewMuxServer(ctx, providers...)
-
- if err != nil {
- return nil, err
- }
-
- return muxServer.ProviderServer(), nil
- },
- },
+ ProtoV6ProviderFactories: testAccMuxProvider,
Steps: []resource.TestStep{
+ {
+ Config: testMuxServerConfig_conflict,
+ ExpectError: regexp.MustCompile("Invalid
Attribute Combination"),
+ },
{
Config: testMuxServerConfig_basic,
},
@@ -94,6 +118,22 @@ resource "cloudstack_zone" "zone_resource"{
}
`
+const testMuxServerConfig_conflict = `
+provider "cloudstack" {
+ api_url = "http://localhost:8080/client/api"
+ api_key = "xxxxx"
+ secret_key = "xxxxx"
+ config = "cloudstack.ini"
+}
+
+data "cloudstack_zone" "zone_data_source"{
+ filter{
+ name = "name"
+ value = "test"
+ }
+}
+ `
+
func testAccPreCheck(t *testing.T) {
if v := os.Getenv("CLOUDSTACK_API_URL"); v == "" {
t.Fatal("CLOUDSTACK_API_URL must be set for acceptance tests")
diff --git a/cloudstack/provider_v6.go b/cloudstack/provider_v6.go
new file mode 100644
index 0000000..339e4b3
--- /dev/null
+++ b/cloudstack/provider_v6.go
@@ -0,0 +1,155 @@
+package cloudstack
+
+import (
+ "context"
+ "fmt"
+ "os"
+ "strconv"
+
+
"github.com/hashicorp/terraform-plugin-framework-validators/providervalidator"
+ "github.com/hashicorp/terraform-plugin-framework/datasource"
+ "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/types"
+)
+
+type CloudstackProvider struct{}
+
+type CloudstackProviderModel struct {
+ ApiUrl types.String `tfsdk:"api_url"`
+ ApiKey types.String `tfsdk:"api_key"`
+ SecretKey types.String `tfsdk:"secret_key"`
+ Config types.String `tfsdk:"config"`
+ Profile types.String `tfsdk:"profile"`
+ HttpGetOnly types.Bool `tfsdk:"http_get_only"`
+ Timeout types.Int64 `tfsdk:"timeout"`
+}
+
+var _ provider.Provider = (*CloudstackProvider)(nil)
+
+func New() provider.Provider {
+ return &CloudstackProvider{}
+}
+
+func (p *CloudstackProvider) Metadata(ctx context.Context, req
provider.MetadataRequest, resp *provider.MetadataResponse) {
+ resp.TypeName = "cloudstack"
+}
+
+func (p *CloudstackProvider) Schema(ctx context.Context, req
provider.SchemaRequest, resp *provider.SchemaResponse) {
+ resp.Schema = schema.Schema{
+ Attributes: map[string]schema.Attribute{
+ "api_url": schema.StringAttribute{
+ Optional: true,
+ },
+ "api_key": schema.StringAttribute{
+ Optional: true,
+ Sensitive: true,
+ },
+ "secret_key": schema.StringAttribute{
+ Optional: true,
+ Sensitive: true,
+ },
+ "config": schema.StringAttribute{
+ Optional: true,
+ },
+ "profile": schema.StringAttribute{
+ Optional: true,
+ },
+ "http_get_only": schema.BoolAttribute{
+ Optional: true,
+ },
+ "timeout": schema.Int64Attribute{
+ Optional: true,
+ },
+ },
+ }
+}
+
+func (p *CloudstackProvider) Configure(ctx context.Context, req
provider.ConfigureRequest, resp *provider.ConfigureResponse) {
+ apiUrl := os.Getenv("CLOUDSTACK_API_URL")
+ apiKey := os.Getenv("CLOUDSTACK_API_KEY")
+ secretKey := os.Getenv("CLOUDSTACK_SECRET_KEY")
+ httpGetOnly, _ :=
strconv.ParseBool(os.Getenv("CLOUDSTACK_HTTP_GET_ONLY"))
+ timeout, _ := strconv.ParseInt(os.Getenv("CLOUDSTACK_TIMEOUT"), 2, 64)
+
+ var data CloudstackProviderModel
+
+ resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
+
+ if data.ApiUrl.ValueString() != "" {
+ apiUrl = data.ApiUrl.ValueString()
+ }
+
+ if data.ApiKey.ValueString() != "" {
+ apiKey = data.ApiKey.ValueString()
+ }
+
+ if data.SecretKey.ValueString() != "" {
+ secretKey = data.SecretKey.ValueString()
+ }
+
+ if data.HttpGetOnly.ValueBool() {
+ httpGetOnly = true
+ }
+
+ if data.Timeout.ValueInt64() != 0 {
+ timeout = data.Timeout.ValueInt64()
+ }
+
+ cfg := Config{
+ APIURL: apiUrl,
+ APIKey: apiKey,
+ SecretKey: secretKey,
+ HTTPGETOnly: httpGetOnly,
+ Timeout: timeout,
+ }
+
+ client, err := cfg.NewClient()
+
+ if err != nil {
+ resp.Diagnostics.AddError("cloudstack", fmt.Sprintf("failed to
create client: %T", err))
+ return
+ }
+
+ resp.ResourceData = client
+ resp.DataSourceData = client
+}
+
+func (p *CloudstackProvider) ConfigValidators(ctx context.Context)
[]provider.ConfigValidator {
+ return []provider.ConfigValidator{
+ providervalidator.Conflicting(
+ path.MatchRoot("api_url"),
+ path.MatchRoot("config"),
+ ),
+ providervalidator.Conflicting(
+ path.MatchRoot("api_url"),
+ path.MatchRoot("profile"),
+ ),
+ providervalidator.Conflicting(
+ path.MatchRoot("api_key"),
+ path.MatchRoot("config"),
+ ),
+ providervalidator.Conflicting(
+ path.MatchRoot("api_key"),
+ path.MatchRoot("profile"),
+ ),
+ providervalidator.Conflicting(
+ path.MatchRoot("secret_key"),
+ path.MatchRoot("config"),
+ ),
+ providervalidator.Conflicting(
+ path.MatchRoot("secret_key"),
+ path.MatchRoot("profile"),
+ ),
+ }
+}
+
+func (p *CloudstackProvider) Resources(ctx context.Context) []func()
resource.Resource {
+ return []func() resource.Resource{}
+}
+
+func (p *CloudstackProvider) DataSources(ctx context.Context) []func()
datasource.DataSource {
+ return []func() datasource.DataSource{}
+}
diff --git a/cloudstack/resources.go b/cloudstack/resources.go
index 0fedb70..22b2adc 100644
--- a/cloudstack/resources.go
+++ b/cloudstack/resources.go
@@ -20,6 +20,7 @@
package cloudstack
import (
+ "context"
"fmt"
"log"
"regexp"
@@ -27,6 +28,7 @@ import (
"time"
"github.com/apache/cloudstack-go/v2/cloudstack"
+ "github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
@@ -170,3 +172,24 @@ func importStatePassthrough(d *schema.ResourceData, meta
interface{}) ([]*schema
return []*schema.ResourceData{d}, nil
}
+
+type ResourceWithConfigure struct {
+ client *cloudstack.CloudStackClient
+}
+
+func (r *ResourceWithConfigure) Configure(ctx context.Context, req
resource.ConfigureRequest, resp *resource.ConfigureResponse) {
+ if req.ProviderData == nil {
+ return
+ }
+
+ client, ok := req.ProviderData.(*cloudstack.CloudStackClient)
+
+ if !ok {
+ resp.Diagnostics.AddError(
+ "Unexpected Resource Configure Type",
+ fmt.Sprintf("Expected *cloudstack.CloudStackClient, got
%T", req.ProviderData),
+ )
+ }
+
+ r.client = client
+}
diff --git a/go.mod b/go.mod
index 7a55244..8952c35 100644
--- a/go.mod
+++ b/go.mod
@@ -4,7 +4,9 @@ require (
github.com/apache/cloudstack-go/v2 v2.16.1
github.com/go-ini/ini v1.67.0
github.com/hashicorp/go-multierror v1.1.1
- github.com/hashicorp/terraform-plugin-go v0.22.0
+ github.com/hashicorp/terraform-plugin-framework v1.7.0
+ github.com/hashicorp/terraform-plugin-framework-validators v0.12.0
+ github.com/hashicorp/terraform-plugin-go v0.22.1
github.com/hashicorp/terraform-plugin-mux v0.15.0
github.com/hashicorp/terraform-plugin-sdk/v2 v2.33.0
github.com/hashicorp/terraform-plugin-testing v1.7.0
@@ -59,8 +61,8 @@ require (
golang.org/x/tools v0.13.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto/googleapis/rpc
v0.0.0-20240123012728-ef4313101c80 // indirect
- google.golang.org/grpc v1.62.0 // indirect
- google.golang.org/protobuf v1.32.0 // indirect
+ google.golang.org/grpc v1.62.1 // indirect
+ google.golang.org/protobuf v1.33.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
)
diff --git a/go.sum b/go.sum
index 010e7b8..51980c3 100644
--- a/go.sum
+++ b/go.sum
@@ -79,8 +79,12 @@ github.com/hashicorp/terraform-exec v0.20.0
h1:DIZnPsqzPGuUnq6cH8jWcPunBfY+C+M8J
github.com/hashicorp/terraform-exec v0.20.0/go.mod
h1:ckKGkJWbsNqFKV1itgMnE0hY9IYf1HoiekpuN0eWoDw=
github.com/hashicorp/terraform-json v0.21.0
h1:9NQxbLNqPbEMze+S6+YluEdXgJmhQykRyRNd+zTI05U=
github.com/hashicorp/terraform-json v0.21.0/go.mod
h1:qdeBs11ovMzo5puhrRibdD6d2Dq6TyE/28JiU4tIQxk=
-github.com/hashicorp/terraform-plugin-go v0.22.0
h1:1OS1Jk5mO0f5hrziWJGXXIxBrMe2j/B8E+DVGw43Xmc=
-github.com/hashicorp/terraform-plugin-go v0.22.0/go.mod
h1:mPULV91VKss7sik6KFEcEu7HuTogMLLO/EvWCuFkRVE=
+github.com/hashicorp/terraform-plugin-framework v1.7.0
h1:wOULbVmfONnJo9iq7/q+iBOBJul5vRovaYJIu2cY/Pw=
+github.com/hashicorp/terraform-plugin-framework v1.7.0/go.mod
h1:jY9Id+3KbZ17OMpulgnWLSfwxNVYSoYBQFTgsx044CI=
+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.22.1
h1:iTS7WHNVrn7uhe3cojtvWWn83cm2Z6ryIUDTRO0EV7w=
+github.com/hashicorp/terraform-plugin-go v0.22.1/go.mod
h1:qrjnqRghvQ6KnDbB12XeZ4FluclYwptntoWCr9QaXTI=
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.15.0
h1:+/+lDx0WUsIOpkAmdwBIoFU8UP9o2eZASoOnLsWbKME=
@@ -224,12 +228,12 @@ google.golang.org/appengine v1.6.8
h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAs
google.golang.org/appengine v1.6.8/go.mod
h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80
h1:AjyfHzEPEFp/NpvfN5g+KDla3EMojjhRVZc1i7cj+oM=
google.golang.org/genproto/googleapis/rpc
v0.0.0-20240123012728-ef4313101c80/go.mod
h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s=
-google.golang.org/grpc v1.62.0 h1:HQKZ/fa1bXkX1oFOvSjmZEUL8wLSaZTjCcLAlmZRtdk=
-google.golang.org/grpc v1.62.0/go.mod
h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE=
+google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk=
+google.golang.org/grpc v1.62.1/go.mod
h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE=
google.golang.org/protobuf v1.26.0-rc.1/go.mod
h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod
h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.32.0
h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
-google.golang.org/protobuf v1.32.0/go.mod
h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+google.golang.org/protobuf v1.33.0
h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
+google.golang.org/protobuf v1.33.0/go.mod
h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod
h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod
h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c
h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
diff --git a/main.go b/main.go
index 0ec5162..b018e6a 100644
--- a/main.go
+++ b/main.go
@@ -24,10 +24,12 @@ import (
"flag"
"log"
- "github.com/hashicorp/terraform-plugin-go/tfprotov5"
- "github.com/hashicorp/terraform-plugin-go/tfprotov5/tf5server"
- "github.com/hashicorp/terraform-plugin-mux/tf5muxserver"
+ "github.com/hashicorp/terraform-plugin-go/tfprotov6"
+ "github.com/hashicorp/terraform-plugin-go/tfprotov6/tf6server"
+ "github.com/hashicorp/terraform-plugin-mux/tf6muxserver"
+ "github.com/hashicorp/terraform-plugin-framework/providerserver"
+ "github.com/hashicorp/terraform-plugin-mux/tf5to6server"
"github.com/terraform-providers/terraform-provider-cloudstack/cloudstack"
)
@@ -39,23 +41,35 @@ func main() {
flag.BoolVar(&debug, "debug", false, "set to true to run the provider
with support for debuggers like delve")
flag.Parse()
- providers := []func() tfprotov5.ProviderServer{
- cloudstack.New().GRPCProvider,
+ updatedSdkServer, err := tf5to6server.UpgradeServer(
+ ctx,
+ cloudstack.Provider().GRPCProvider,
+ )
+
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ providers := []func() tfprotov6.ProviderServer{
+ providerserver.NewProtocol6(cloudstack.New()),
+ func() tfprotov6.ProviderServer {
+ return updatedSdkServer
+ },
}
- muxServer, err := tf5muxserver.NewMuxServer(ctx, providers...)
+ muxServer, err := tf6muxserver.NewMuxServer(ctx, providers...)
if err != nil {
log.Fatal(err)
}
- var serveOpts []tf5server.ServeOpt
+ var serveOpts []tf6server.ServeOpt
if debug {
- serveOpts = append(serveOpts, tf5server.WithManagedDebug())
+ serveOpts = append(serveOpts, tf6server.WithManagedDebug())
}
- err = tf5server.Serve(
+ err = tf6server.Serve(
"registry.terraform.io/cloudstack/cloudstack",
muxServer.ProviderServer,
serveOpts...,