diff --git a/internal/clients/consul_cluster.go b/internal/clients/consul_cluster.go index 9b4c95913..3d1553466 100644 --- a/internal/clients/consul_cluster.go +++ b/internal/clients/consul_cluster.go @@ -164,28 +164,15 @@ func ListConsulUpgradeVersions(ctx context.Context, client *Client, loc *sharedm // UpdateConsulCluster will make a call to the Consul service to initiate the update Consul // cluster workflow. -func UpdateConsulCluster(ctx context.Context, client *Client, loc *sharedmodels.HashicorpCloudLocationLocation, - clusterID, newConsulVersion string) (*consulmodels.HashicorpCloudConsul20210204UpdateResponse, error) { - - cluster := consulmodels.HashicorpCloudConsul20210204Cluster{ - ConsulVersion: newConsulVersion, - ID: clusterID, - Location: &sharedmodels.HashicorpCloudLocationLocation{ - ProjectID: loc.ProjectID, - OrganizationID: loc.OrganizationID, - Region: &sharedmodels.HashicorpCloudLocationRegion{ - Region: loc.Region.Region, - Provider: loc.Region.Provider, - }, - }, - } +func UpdateConsulCluster(ctx context.Context, client *Client, + newCluster *consulmodels.HashicorpCloudConsul20210204Cluster) (*consulmodels.HashicorpCloudConsul20210204UpdateResponse, error) { updateParams := consul_service.NewUpdateParams() updateParams.Context = ctx - updateParams.ClusterID = cluster.ID - updateParams.ClusterLocationProjectID = loc.ProjectID - updateParams.ClusterLocationOrganizationID = loc.OrganizationID - updateParams.Body = &cluster + updateParams.ClusterID = newCluster.ID + updateParams.ClusterLocationProjectID = newCluster.Location.ProjectID + updateParams.ClusterLocationOrganizationID = newCluster.Location.OrganizationID + updateParams.Body = newCluster // Invoke update cluster endpoint updateResp, err := client.Consul.Update(updateParams, nil) diff --git a/internal/provider/resource_consul_cluster.go b/internal/provider/resource_consul_cluster.go index b51bb3b1f..8c90b949e 100644 --- a/internal/provider/resource_consul_cluster.go +++ b/internal/provider/resource_consul_cluster.go @@ -131,7 +131,6 @@ func resourceConsulCluster() *schema.Resource { Description: "The t-shirt size representation of each server VM that this Consul cluster is provisioned with. Valid option for development tier - `x_small`. Valid options for other tiers - `small`, `medium`, `large`. For more details - https://cloud.hashicorp.com/pricing/consul", Type: schema.TypeString, Optional: true, - ForceNew: true, Computed: true, ValidateDiagFunc: validateConsulClusterSize, DiffSuppressFunc: func(_, old, new string, _ *schema.ResourceData) bool { @@ -583,30 +582,59 @@ func resourceConsulClusterUpdate(ctx context.Context, d *schema.ResourceData, me return diag.Errorf("unable to fetch Consul cluster (%s): %v", clusterID, err) } - // Fetch available upgrade versions - upgradeVersions, err := clients.ListConsulUpgradeVersions(ctx, client, cluster.Location, clusterID) - if err != nil { - return diag.Errorf("unable to list Consul upgrade versions (%s): %v", clusterID, err) + // Confirm update fields have been changed + sizeChanged := d.HasChange("size") + versionChanged := d.HasChange("min_consul_version") + + if !sizeChanged && !versionChanged { + return diag.Errorf("at least one of: [min_consul_version, size] is required in order to update the cluster") } - v, ok := d.GetOk("min_consul_version") - if !ok { - return diag.Errorf("min_consul_version is required in order to upgrade the cluster") + targetCluster := consulmodels.HashicorpCloudConsul20210204Cluster{ + ID: clusterID, + Location: &sharedmodels.HashicorpCloudLocationLocation{ + ProjectID: cluster.Location.ProjectID, + OrganizationID: cluster.Location.OrganizationID, + Region: &sharedmodels.HashicorpCloudLocationRegion{ + Region: cluster.Location.Region.Region, + Provider: cluster.Location.Region.Provider, + }, + }, } - newConsulVersion := input.NormalizeVersion(v.(string)) - // Check that there are any valid upgrade versions - if upgradeVersions == nil { - return diag.Errorf("no upgrade versions of Consul are available for this cluster; you may already be on the latest Consul version supported by HCP") + if versionChanged { + // Fetch available upgrade versions + upgradeVersions, err := clients.ListConsulUpgradeVersions(ctx, client, cluster.Location, clusterID) + if err != nil { + return diag.Errorf("unable to list Consul upgrade versions (%s): %v", clusterID, err) + } + version := d.Get("min_consul_version") + newConsulVersion := input.NormalizeVersion(version.(string)) + + // Check that there are any valid upgrade versions + if upgradeVersions == nil { + return diag.Errorf("no upgrade versions of Consul are available for this cluster; you may already be on the latest Consul version supported by HCP") + } + + // Validate that the upgrade version is valid + if !consul.IsValidVersion(newConsulVersion, upgradeVersions) { + return diag.Errorf("specified Consul version (%s) is unavailable; must be one of: [%s]", newConsulVersion, consul.VersionsToString(upgradeVersions)) + } + + targetCluster.ConsulVersion = newConsulVersion } - // Validate that the upgrade version is valid - if !consul.IsValidVersion(newConsulVersion, upgradeVersions) { - return diag.Errorf("specified Consul version (%s) is unavailable; must be one of: [%s]", newConsulVersion, consul.VersionsToString(upgradeVersions)) + if sizeChanged { + newSize := d.Get("size").(string) + targetCluster.Config = &consulmodels.HashicorpCloudConsul20210204ClusterConfig{ + CapacityConfig: &consulmodels.HashicorpCloudConsul20210204CapacityConfig{ + Size: consulmodels.HashicorpCloudConsul20210204CapacityConfigSize(strings.ToUpper(newSize)), + }, + } } // Invoke update cluster endpoint - updateResp, err := clients.UpdateConsulCluster(ctx, client, cluster.Location, clusterID, newConsulVersion) + updateResp, err := clients.UpdateConsulCluster(ctx, client, &targetCluster) if err != nil { return diag.Errorf("error updating Consul cluster (%s): %v", clusterID, err) } @@ -616,13 +644,19 @@ func resourceConsulClusterUpdate(ctx context.Context, d *schema.ResourceData, me return diag.Errorf("unable to update Consul cluster (%s): %v", clusterID, err) } + // Get updated Consul cluster + updatedCluster, err := clients.GetConsulClusterByID(ctx, client, loc, clusterID) + if err != nil { + return diag.Errorf("unable to retrieve Consul cluster (%s): %v", clusterID, err) + } + // get the cluster's Consul client config files clientConfigFiles, err := clients.GetConsulClientConfigFiles(ctx, client, cluster.Location, clusterID) if err != nil { return diag.Errorf("unable to retrieve Consul cluster (%s) client config files: %v", clusterID, err) } - if err := setConsulClusterResourceData(d, cluster, clientConfigFiles); err != nil { + if err := setConsulClusterResourceData(d, updatedCluster, clientConfigFiles); err != nil { return diag.FromErr(err) } diff --git a/internal/provider/resource_consul_cluster_test.go b/internal/provider/resource_consul_cluster_test.go index bcaa0a072..c143792c5 100644 --- a/internal/provider/resource_consul_cluster_test.go +++ b/internal/provider/resource_consul_cluster_test.go @@ -10,27 +10,42 @@ import ( "github.com/hashicorp/terraform-provider-hcp/internal/clients" ) -var testAccConsulClusterConfig = ` -resource "hcp_hvn" "test" { - hvn_id = "test-hvn" - cloud_provider = "aws" - region = "us-west-2" +var consulCluster = ` +resource "hcp_consul_cluster" "test" { + cluster_id = "test-consul-cluster" + hvn_id = hcp_hvn.test.hvn_id + tier = "standard" } +` +var updatedConsulCluster = ` resource "hcp_consul_cluster" "test" { cluster_id = "test-consul-cluster" hvn_id = hcp_hvn.test.hvn_id - tier = "development" + tier = "standard" + size = "medium" } +` -data "hcp_consul_cluster" "test" { - cluster_id = hcp_consul_cluster.test.cluster_id -} +func setTestAccConsulClusterConfig(consulCluster string) string { + return fmt.Sprintf(` + resource "hcp_hvn" "test" { + hvn_id = "test-hvn" + cloud_provider = "aws" + region = "us-west-2" + } -resource "hcp_consul_cluster_root_token" "test" { - cluster_id = hcp_consul_cluster.test.cluster_id + %s + + data "hcp_consul_cluster" "test" { + cluster_id = hcp_consul_cluster.test.cluster_id + } + + resource "hcp_consul_cluster_root_token" "test" { + cluster_id = hcp_consul_cluster.test.cluster_id + } +`, consulCluster) } -` // This includes tests against both the resource, the corresponding datasource, // and creation of the Consul cluster root token resource in order to shorten @@ -47,17 +62,17 @@ func TestAccConsulCluster(t *testing.T) { Steps: []resource.TestStep{ // Tests create { - Config: testConfig(testAccConsulClusterConfig), + Config: testConfig(setTestAccConsulClusterConfig(consulCluster)), Check: resource.ComposeTestCheckFunc( testAccCheckConsulClusterExists(resourceName), resource.TestCheckResourceAttr(resourceName, "cluster_id", "test-consul-cluster"), resource.TestCheckResourceAttr(resourceName, "hvn_id", "test-hvn"), - resource.TestCheckResourceAttr(resourceName, "tier", "DEVELOPMENT"), + resource.TestCheckResourceAttr(resourceName, "tier", "STANDARD"), resource.TestCheckResourceAttr(resourceName, "cloud_provider", "aws"), resource.TestCheckResourceAttr(resourceName, "region", "us-west-2"), resource.TestCheckResourceAttr(resourceName, "public_endpoint", "false"), resource.TestCheckResourceAttr(resourceName, "datacenter", "test-consul-cluster"), - resource.TestCheckResourceAttr(resourceName, "scale", "1"), + resource.TestCheckResourceAttr(resourceName, "scale", "3"), resource.TestCheckResourceAttr(resourceName, "consul_snapshot_interval", "24h"), resource.TestCheckResourceAttr(resourceName, "consul_snapshot_retention", "30d"), resource.TestCheckResourceAttr(resourceName, "connect_enabled", "true"), @@ -94,17 +109,17 @@ func TestAccConsulCluster(t *testing.T) { }, // Tests read { - Config: testConfig(testAccConsulClusterConfig), + Config: testConfig(setTestAccConsulClusterConfig(consulCluster)), Check: resource.ComposeTestCheckFunc( testAccCheckConsulClusterExists(resourceName), resource.TestCheckResourceAttr(resourceName, "cluster_id", "test-consul-cluster"), resource.TestCheckResourceAttr(resourceName, "hvn_id", "test-hvn"), - resource.TestCheckResourceAttr(resourceName, "tier", "DEVELOPMENT"), + resource.TestCheckResourceAttr(resourceName, "tier", "STANDARD"), resource.TestCheckResourceAttr(resourceName, "cloud_provider", "aws"), resource.TestCheckResourceAttr(resourceName, "region", "us-west-2"), resource.TestCheckResourceAttr(resourceName, "public_endpoint", "false"), resource.TestCheckResourceAttr(resourceName, "datacenter", "test-consul-cluster"), - resource.TestCheckResourceAttr(resourceName, "scale", "1"), + resource.TestCheckResourceAttr(resourceName, "scale", "3"), resource.TestCheckResourceAttr(resourceName, "consul_snapshot_interval", "24h"), resource.TestCheckResourceAttr(resourceName, "consul_snapshot_retention", "30d"), resource.TestCheckResourceAttr(resourceName, "connect_enabled", "true"), @@ -125,7 +140,7 @@ func TestAccConsulCluster(t *testing.T) { }, // Tests datasource { - Config: testConfig(testAccConsulClusterConfig), + Config: testConfig(setTestAccConsulClusterConfig(consulCluster)), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrPair(resourceName, "cluster_id", dataSourceName, "cluster_id"), resource.TestCheckResourceAttrPair(resourceName, "project_id", dataSourceName, "project_id"), @@ -154,7 +169,7 @@ func TestAccConsulCluster(t *testing.T) { }, // Tests root token { - Config: testConfig(testAccConsulClusterConfig), + Config: testConfig(setTestAccConsulClusterConfig(consulCluster)), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(rootTokenResourceName, "cluster_id", "test-consul-cluster"), resource.TestCheckResourceAttrSet(rootTokenResourceName, "accessor_id"), @@ -162,6 +177,14 @@ func TestAccConsulCluster(t *testing.T) { resource.TestCheckResourceAttrSet(rootTokenResourceName, "kubernetes_secret"), ), }, + // Tests update + { + Config: testConfig(setTestAccConsulClusterConfig(updatedConsulCluster)), + Check: resource.ComposeTestCheckFunc( + testAccCheckConsulClusterExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "size", "MEDIUM"), + ), + }, }, }) }