Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
7 changes: 5 additions & 2 deletions cloudstack/data_source_cloudstack_service_offering_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ func TestAccServiceOfferingDataSource_basic(t *testing.T) {
datasourceName := "data.cloudstack_service_offering.service-offering-data-source"

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
PreCheck: func() { testAccPreCheck(t) },
ProtoV6ProviderFactories: testAccMuxProvider,
Steps: []resource.TestStep{
{
Config: testServiceOfferingDataSourceConfig_basic,
Expand All @@ -47,6 +47,9 @@ const testServiceOfferingDataSourceConfig_basic = `
resource "cloudstack_service_offering" "service-offering-resource" {
name = "TestServiceUpdate"
display_text = "DisplayService"
cpu_number = 2
cpu_speed = 2200
memory = 8096
}

data "cloudstack_service_offering" "service-offering-data-source" {
Expand Down
5 changes: 3 additions & 2 deletions cloudstack/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand All @@ -41,13 +41,15 @@ func New() *schema.Provider {
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("CLOUDSTACK_API_KEY", nil),
ConflictsWith: []string{"config", "profile"},
Sensitive: true,
},

"secret_key": {
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("CLOUDSTACK_SECRET_KEY", nil),
ConflictsWith: []string{"config", "profile"},
Sensitive: true,
},

"config": {
Expand Down Expand Up @@ -124,7 +126,6 @@ func New() *schema.Provider {
"cloudstack_disk_offering": resourceCloudStackDiskOffering(),
"cloudstack_volume": resourceCloudStackVolume(),
"cloudstack_zone": resourceCloudStackZone(),
"cloudstack_service_offering": resourceCloudStackServiceOffering(),
"cloudstack_account": resourceCloudStackAccount(),
"cloudstack_user": resourceCloudStackUser(),
"cloudstack_domain": resourceCloudStackDomain(),
Expand Down
84 changes: 62 additions & 22 deletions cloudstack/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,55 +22,79 @@ 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"
)

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,
},
Expand All @@ -80,7 +104,7 @@ func TestMuxServer(t *testing.T) {

const testMuxServerConfig_basic = `
resource "cloudstack_zone" "zone_resource"{
name = "TestZone"
name = "TestZone1"
dns1 = "8.8.8.8"
internal_dns1 = "172.20.0.1"
network_type = "Advanced"
Expand All @@ -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")
Expand Down
157 changes: 157 additions & 0 deletions cloudstack/provider_v6.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
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{
NewCloudstackServiceOfferingResource,
}
}

func (p *CloudstackProvider) DataSources(ctx context.Context) []func() datasource.DataSource {
return []func() datasource.DataSource{}
}
Loading