Skip to content

Commit

Permalink
AV-84160 make cluster timezone optional (#215)
Browse files Browse the repository at this point in the history
Co-authored-by: Saicharan Rachamadugu <[email protected]>
  • Loading branch information
Lagher0 and SaicharanCB authored Aug 29, 2024
1 parent 70f7efd commit 9f19516
Show file tree
Hide file tree
Showing 3 changed files with 252 additions and 8 deletions.
228 changes: 225 additions & 3 deletions internal/resources/acceptance_tests/cluster_acceptance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,7 @@ func TestAccClusterResourceWithOnlyReqFieldAWS(t *testing.T) {
resource.TestCheckResourceAttr(resourceReference, "availability.type", "multi"),
resource.TestCheckResourceAttr(resourceReference, "support.plan", "developer pro"),
resource.TestCheckResourceAttr(resourceReference, "support.timezone", "PT"),

//When the cluster is created for the first time, the ETag of the created cluster is 5
//resource.TestCheckResourceAttr(resourceReference, "etag", "Version: 5"),
resource.TestCheckResourceAttrSet(resourceReference, "etag"),
),
},
//// ImportState testing
Expand All @@ -84,6 +82,10 @@ func TestAccClusterResourceWithOnlyReqFieldAWS(t *testing.T) {
ImportStateIdFunc: generateClusterImportIdForResource(resourceReference),
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{
"audit.modified_at",
"audit.version",
},
},
// Update number of nodes, compute type, disk size and type, cluster name, support plan, time zone and description from empty string,
// and Read testing
Expand Down Expand Up @@ -438,6 +440,117 @@ func TestAccClusterResourceGCP(t *testing.T) {
},
})
}
func TestAccClusterResourceWithReqFieldsAWSBasicPlan(t *testing.T) {
resourceName := "acc_cluster_" + acctest.GenerateRandomResourceName()
resourceReference := "couchbase-capella_cluster." + resourceName
projectResourceName := "acc_project_" + acctest.GenerateRandomResourceName()
projectResourceReference := "couchbase-capella_project." + projectResourceName
cidr := "10.255.250.0/23"
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.TestAccPreCheck(t) },
ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories,
Steps: []resource.TestStep{
// Create and Read testing
{
PreConfig: testAccProjecCreationWaitTime(),
Config: testAccClusterResourceConfigReqFieldsBasicPlan(acctest.Cfg, resourceName, projectResourceName, projectResourceReference, cidr),
Check: resource.ComposeAggregateTestCheckFunc(
testAccExistsClusterResource(resourceReference),
resource.TestCheckResourceAttr(resourceReference, "name", resourceName),
resource.TestCheckResourceAttr(resourceReference, "description", ""),
resource.TestCheckResourceAttr(resourceReference, "cloud_provider.type", "aws"),
resource.TestCheckResourceAttr(resourceReference, "cloud_provider.region", "us-east-1"),
resource.TestCheckResourceAttr(resourceReference, "cloud_provider.cidr", cidr),
resource.TestCheckResourceAttr(resourceReference, "service_groups.0.node.compute.cpu", "4"),
resource.TestCheckResourceAttr(resourceReference, "service_groups.0.node.compute.ram", "16"),
resource.TestCheckResourceAttr(resourceReference, "service_groups.0.node.disk.storage", "50"),
resource.TestCheckResourceAttr(resourceReference, "service_groups.0.node.disk.type", "io2"),
resource.TestCheckResourceAttr(resourceReference, "service_groups.0.node.disk.iops", "3000"),
resource.TestCheckResourceAttr(resourceReference, "service_groups.0.num_of_nodes", "3"),
resource.TestCheckResourceAttr(resourceReference, "service_groups.0.services.#", "3"),
resource.TestCheckResourceAttr(resourceReference, "service_groups.0.services.0", "data"),
resource.TestCheckResourceAttr(resourceReference, "service_groups.0.services.1", "index"),
resource.TestCheckResourceAttr(resourceReference, "service_groups.0.services.2", "query"),
resource.TestCheckResourceAttr(resourceReference, "availability.type", "single"),
resource.TestCheckResourceAttr(resourceReference, "support.plan", "basic"),

//When the cluster is created for the first time, the ETag of the created cluster is 5
//resource.TestCheckResourceAttr(resourceReference, "etag", "Version: 5"),
),
},
//// ImportState testing
{
ResourceName: resourceReference,
ImportStateIdFunc: generateClusterImportIdForResource(resourceReference),
ImportState: true,
ImportStateVerify: true,
},
// Update number of nodes, compute type, disk size and type, cluster name, support plan, time zone and description from empty string,
// and Read testing
{
Config: testAccClusterResourceConfigUpdateWhenClusterCreatedWithReqFieldOnlyAndIfMatchBasicPlan(acctest.Cfg, resourceName, projectResourceName, projectResourceReference, cidr),
Check: resource.ComposeAggregateTestCheckFunc(
testAccExistsClusterResource(resourceReference),
resource.TestCheckResourceAttr(resourceReference, "name", "Terraform Acceptance Test Cluster Update"),
resource.TestCheckResourceAttr(resourceReference, "description", "Cluster Updated."),
resource.TestCheckResourceAttr(resourceReference, "cloud_provider.type", "aws"),
resource.TestCheckResourceAttr(resourceReference, "cloud_provider.region", "us-east-1"),
resource.TestCheckResourceAttr(resourceReference, "cloud_provider.cidr", cidr),
resource.TestCheckResourceAttr(resourceReference, "service_groups.1.node.compute.cpu", "8"),
resource.TestCheckResourceAttr(resourceReference, "service_groups.1.node.compute.ram", "32"),
resource.TestCheckResourceAttr(resourceReference, "service_groups.1.node.disk.storage", "51"),
resource.TestCheckResourceAttr(resourceReference, "service_groups.1.node.disk.type", "gp3"),
resource.TestCheckResourceAttr(resourceReference, "service_groups.1.node.disk.iops", "3001"),
resource.TestCheckResourceAttr(resourceReference, "service_groups.1.num_of_nodes", "2"),
resource.TestCheckResourceAttr(resourceReference, "service_groups.1.services.#", "2"),
resource.TestCheckResourceAttr(resourceReference, "service_groups.1.services.0", "index"),
resource.TestCheckResourceAttr(resourceReference, "service_groups.1.services.1", "query"),
resource.TestCheckResourceAttr(resourceReference, "service_groups.0.node.compute.cpu", "4"),
resource.TestCheckResourceAttr(resourceReference, "service_groups.0.node.compute.ram", "16"),
resource.TestCheckResourceAttr(resourceReference, "service_groups.0.node.disk.storage", "51"),
resource.TestCheckResourceAttr(resourceReference, "service_groups.0.node.disk.type", "gp3"),
resource.TestCheckResourceAttr(resourceReference, "service_groups.0.node.disk.iops", "3001"),
resource.TestCheckResourceAttr(resourceReference, "service_groups.0.num_of_nodes", "3"),
resource.TestCheckResourceAttr(resourceReference, "service_groups.0.services.#", "1"),
resource.TestCheckResourceAttr(resourceReference, "service_groups.0.services.0", "data"),
resource.TestCheckResourceAttr(resourceReference, "availability.type", "single"),
resource.TestCheckResourceAttr(resourceReference, "support.plan", "basic"),
),
},
{
Config: testAccClusterResourceConfigUpdateWhenClusterCreatedWithReqFieldOnly(acctest.Cfg, resourceName, projectResourceName, projectResourceReference, cidr),
Check: resource.ComposeAggregateTestCheckFunc(
testAccExistsClusterResource(resourceReference),
resource.TestCheckResourceAttr(resourceReference, "name", "Terraform Acceptance Test Cluster Update 2"),
resource.TestCheckResourceAttr(resourceReference, "description", "Cluster Updated."),
resource.TestCheckResourceAttr(resourceReference, "cloud_provider.type", "aws"),
resource.TestCheckResourceAttr(resourceReference, "cloud_provider.region", "us-east-1"),
resource.TestCheckResourceAttr(resourceReference, "cloud_provider.cidr", cidr),
resource.TestCheckResourceAttr(resourceReference, "service_groups.1.node.compute.cpu", "8"),
resource.TestCheckResourceAttr(resourceReference, "service_groups.1.node.compute.ram", "32"),
resource.TestCheckResourceAttr(resourceReference, "service_groups.1.node.disk.storage", "51"),
resource.TestCheckResourceAttr(resourceReference, "service_groups.1.node.disk.type", "gp3"),
resource.TestCheckResourceAttr(resourceReference, "service_groups.1.node.disk.iops", "3001"),
resource.TestCheckResourceAttr(resourceReference, "service_groups.1.num_of_nodes", "2"),
resource.TestCheckResourceAttr(resourceReference, "service_groups.1.services.#", "2"),
resource.TestCheckResourceAttr(resourceReference, "service_groups.1.services.0", "index"),
resource.TestCheckResourceAttr(resourceReference, "service_groups.1.services.1", "query"),
resource.TestCheckResourceAttr(resourceReference, "service_groups.0.node.compute.cpu", "4"),
resource.TestCheckResourceAttr(resourceReference, "service_groups.0.node.compute.ram", "16"),
resource.TestCheckResourceAttr(resourceReference, "service_groups.0.node.disk.storage", "51"),
resource.TestCheckResourceAttr(resourceReference, "service_groups.0.node.disk.type", "gp3"),
resource.TestCheckResourceAttr(resourceReference, "service_groups.0.node.disk.iops", "3001"),
resource.TestCheckResourceAttr(resourceReference, "service_groups.0.num_of_nodes", "3"),
resource.TestCheckResourceAttr(resourceReference, "service_groups.0.services.#", "1"),
resource.TestCheckResourceAttr(resourceReference, "service_groups.0.services.0", "data"),
resource.TestCheckResourceAttr(resourceReference, "availability.type", "multi"),
resource.TestCheckResourceAttr(resourceReference, "support.plan", "enterprise"),
),
},
// Delete testing automatically occurs in TestCase
},
})
}

// TestAccClusterResourceWithOptionalFieldAWSInvalidScenario is a Terraform acceptance test that covers an invalid scenario
// during the creation of a cluster resource with optional fields for an AWS (Amazon Web Services) cloud provider.
Expand Down Expand Up @@ -574,6 +687,52 @@ func TestAccClusterResourceNotFound(t *testing.T) {
})
}

func testAccClusterResourceConfigReqFieldsBasicPlan(cfg, resourceName, projectResourceName, projectResourceReference, cidr string) string {
return fmt.Sprintf(`
%[1]s
resource "couchbase-capella_project" "%[3]s" {
organization_id = var.organization_id
name = "acc_test_project_name"
description = "description"
}
resource "couchbase-capella_cluster" "%[2]s" {
organization_id = var.organization_id
project_id = %[4]s.id
name = "%[2]s"
cloud_provider = {
type = "aws"
region = "us-east-1"
cidr = "%[5]s"
}
service_groups = [
{
node = {
compute = {
cpu = 4
ram = 16
}
disk = {
storage = 50
type = "io2"
iops = 3000
}
}
num_of_nodes = 3
services = ["data", "index", "query"]
}
]
availability = {
"type" : "single"
}
support = {
plan = "basic"
}
}
`, cfg, resourceName, projectResourceName, projectResourceReference, cidr)
}

// testAccClusterResourceConfigWithOnlyReqField generates a Terraform configuration string for testing an acceptance test
// scenario for creating a cluster with only required fields.
func testAccClusterResourceConfigWithOnlyReqField(cfg, resourceName, projectResourceName, projectResourceReference, cidr string) string {
Expand Down Expand Up @@ -1138,6 +1297,69 @@ resource "couchbase-capella_cluster" "%[2]s" {
`, cfg, resourceName, projectResourceName, projectResourceReference, cidr)
}

func testAccClusterResourceConfigUpdateWhenClusterCreatedWithReqFieldOnlyAndIfMatchBasicPlan(cfg, resourceName, projectResourceName, projectResourceReference, cidr string) string {
return fmt.Sprintf(`
%[1]s
resource "couchbase-capella_project" "%[3]s" {
organization_id = var.organization_id
name = "acc_test_project_name"
description = "description"
}
resource "couchbase-capella_cluster" "%[2]s" {
organization_id = var.organization_id
project_id = %[4]s.id
name = "Terraform Acceptance Test Cluster Update"
description = "Cluster Updated."
cloud_provider = {
type = "aws"
region = "us-east-1"
cidr = "%[5]s"
}
service_groups = [
{
node = {
compute = {
cpu = 8
ram = 32
}
disk = {
storage = 51
type = "gp3"
iops = 3001
}
}
num_of_nodes = 2
services = ["index", "query"]
},
{
node = {
compute = {
cpu = 4
ram = 16
}
disk = {
storage = 51
type = "gp3"
iops = 3001
}
}
num_of_nodes = 3
services = ["data"]
}
]
availability = {
"type" : "single"
}
support = {
plan = "basic"
}
if_match = 5
}
`, cfg, resourceName, projectResourceName, projectResourceReference, cidr)
}

// testAccClusterResourceConfigUpdateWhenClusterCreatedWithReqFieldOnlyAndIfMatch generates a Terraform configuration string for testing an acceptance test scenario
// where an existing cluster resource is updated where cluster is created with required fields only and if match flag is provided.
func testAccClusterResourceConfigUpdateWhenClusterCreatedWithReqFieldOnlyAndIfMatch(cfg, resourceName, projectResourceName, projectResourceReference, cidr string) string {
Expand Down
30 changes: 26 additions & 4 deletions internal/resources/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,22 @@ func (c *Cluster) Create(ctx context.Context, req resource.CreateRequest, resp *
Type: clusterapi.CloudProviderType(plan.CloudProvider.Type.ValueString()),
},
Support: clusterapi.Support{
Plan: clusterapi.SupportPlan(plan.Support.Plan.ValueString()),
Timezone: clusterapi.SupportTimezone(plan.Support.Timezone.ValueString()),
Plan: clusterapi.SupportPlan(plan.Support.Plan.ValueString()),
},
}

if !plan.Support.Timezone.IsNull() && !plan.Support.Timezone.IsUnknown() {
clusterRequest.Support.Timezone = clusterapi.SupportTimezone(plan.Support.Timezone.ValueString())

if clusterRequest.Support.Plan == clusterapi.SupportPlan("basic") && clusterRequest.Support.Timezone != clusterapi.SupportTimezone("PT") {
resp.Diagnostics.AddError(
"Error creating cluster",
"Could not create cluster, unexpected error: Invalid timezone provided for basic cluster",
)
return
}
}

if !plan.Description.IsNull() && !plan.Description.IsUnknown() {
clusterRequest.Description = plan.Description.ValueStringPointer()
}
Expand Down Expand Up @@ -322,11 +333,22 @@ func (c *Cluster) Update(ctx context.Context, req resource.UpdateRequest, resp *
Description: plan.Description.ValueString(),
Name: plan.Name.ValueString(),
Support: clusterapi.Support{
Plan: clusterapi.SupportPlan(plan.Support.Plan.ValueString()),
Timezone: clusterapi.SupportTimezone(plan.Support.Timezone.ValueString()),
Plan: clusterapi.SupportPlan(plan.Support.Plan.ValueString()),
},
}

if !plan.Support.Timezone.IsNull() && !plan.Support.Timezone.IsUnknown() {
ClusterRequest.Support.Timezone = clusterapi.SupportTimezone(plan.Support.Timezone.ValueString())

if ClusterRequest.Support.Plan == clusterapi.SupportPlan("basic") && ClusterRequest.Support.Timezone != clusterapi.SupportTimezone("PT") {
resp.Diagnostics.AddError(
"Error creating cluster",
"Could not update cluster, unexpected error: Invalid timezone provided for basic cluster",
)
return
}
}

serviceGroups, err := c.morphToApiServiceGroups(plan)
if err != nil {
resp.Diagnostics.AddError(
Expand Down
2 changes: 1 addition & 1 deletion internal/resources/cluster_schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ func ClusterSchema() schema.Schema {
Required: true,
Attributes: map[string]schema.Attribute{
"plan": stringAttribute([]string{required}),
"timezone": stringAttribute([]string{required}),
"timezone": stringAttribute([]string{computed, optional}),
},
},
"current_state": stringAttribute([]string{computed}),
Expand Down

0 comments on commit 9f19516

Please sign in to comment.