diff --git a/.changelog/17344.txt b/.changelog/17344.txt new file mode 100644 index 00000000000..5500b9e7494 --- /dev/null +++ b/.changelog/17344.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_glue_partition - Fix `partition_values` to perserve order. +``` diff --git a/aws/internal/service/glue/finder/finder.go b/aws/internal/service/glue/finder/finder.go index fdceee9166b..e402963f1c1 100644 --- a/aws/internal/service/glue/finder/finder.go +++ b/aws/internal/service/glue/finder/finder.go @@ -50,3 +50,30 @@ func SchemaVersionByID(conn *glue.Glue, id string) (*glue.GetSchemaVersionOutput return output, nil } + +// PartitionByValues returns the Partition corresponding to the specified Partition Values. +func PartitionByValues(conn *glue.Glue, id string) (*glue.Partition, error) { + + catalogID, dbName, tableName, values, err := tfglue.ReadAwsGluePartitionID(id) + if err != nil { + return nil, err + } + + input := &glue.GetPartitionInput{ + CatalogId: aws.String(catalogID), + DatabaseName: aws.String(dbName), + TableName: aws.String(tableName), + PartitionValues: aws.StringSlice(values), + } + + output, err := conn.GetPartition(input) + if err != nil { + return nil, err + } + + if output == nil && output.Partition == nil { + return nil, nil + } + + return output.Partition, nil +} diff --git a/aws/internal/service/glue/id.go b/aws/internal/service/glue/id.go index 2bc05fff411..77a22050498 100644 --- a/aws/internal/service/glue/id.go +++ b/aws/internal/service/glue/id.go @@ -7,7 +7,6 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/glue" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) func ReadAwsGluePartitionID(id string) (catalogID string, dbName string, tableName string, values []string, error error) { @@ -19,13 +18,13 @@ func ReadAwsGluePartitionID(id string) (catalogID string, dbName string, tableNa return idParts[0], idParts[1], idParts[2], vals, nil } -func CreateAwsGluePartitionID(catalogID, dbName, tableName string, values *schema.Set) string { +func CreateAwsGluePartitionID(catalogID, dbName, tableName string, values []interface{}) string { return fmt.Sprintf("%s:%s:%s:%s", catalogID, dbName, tableName, stringifyAwsGluePartition(values)) } -func stringifyAwsGluePartition(partValues *schema.Set) string { +func stringifyAwsGluePartition(partValues []interface{}) string { var b bytes.Buffer - for _, val := range partValues.List() { + for _, val := range partValues { b.WriteString(fmt.Sprintf("%s#", val.(string))) } vals := strings.Trim(b.String(), "#") diff --git a/aws/resource_aws_glue_partition.go b/aws/resource_aws_glue_partition.go index 7bc957b4a8d..245df802500 100644 --- a/aws/resource_aws_glue_partition.go +++ b/aws/resource_aws_glue_partition.go @@ -10,6 +10,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" tfglue "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/glue" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/glue/finder" ) func resourceAwsGluePartition() *schema.Resource { @@ -42,7 +43,7 @@ func resourceAwsGluePartition() *schema.Resource { ValidateFunc: validation.StringLenBetween(1, 255), }, "partition_values": { - Type: schema.TypeSet, + Type: schema.TypeList, Required: true, ForceNew: true, Elem: &schema.Schema{Type: schema.TypeString}, @@ -198,7 +199,7 @@ func resourceAwsGluePartitionCreate(d *schema.ResourceData, meta interface{}) er catalogID := createAwsGlueCatalogID(d, meta.(*AWSClient).accountid) dbName := d.Get("database_name").(string) tableName := d.Get("table_name").(string) - values := d.Get("partition_values").(*schema.Set) + values := d.Get("partition_values").([]interface{}) input := &glue.CreatePartitionInput{ CatalogId: aws.String(catalogID), @@ -221,37 +222,21 @@ func resourceAwsGluePartitionCreate(d *schema.ResourceData, meta interface{}) er func resourceAwsGluePartitionRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).glueconn - catalogID, dbName, tableName, values, err := tfglue.ReadAwsGluePartitionID(d.Id()) - if err != nil { - return err - } - log.Printf("[DEBUG] Reading Glue Partition: %s", d.Id()) - input := &glue.GetPartitionInput{ - CatalogId: aws.String(catalogID), - DatabaseName: aws.String(dbName), - TableName: aws.String(tableName), - PartitionValues: aws.StringSlice(values), - } - - out, err := conn.GetPartition(input) + partition, err := finder.PartitionByValues(conn, d.Id()) if err != nil { - if isAWSErr(err, glue.ErrCodeEntityNotFoundException, "") { log.Printf("[WARN] Glue Partition (%s) not found, removing from state", d.Id()) d.SetId("") return nil } - return fmt.Errorf("error reading Glue Partition: %w", err) } - partition := out.Partition - d.Set("table_name", partition.TableName) - d.Set("catalog_id", catalogID) + d.Set("catalog_id", partition.CatalogId) d.Set("database_name", partition.DatabaseName) - d.Set("partition_values", flattenStringSet(partition.Values)) + d.Set("partition_values", flattenStringList(partition.Values)) if partition.LastAccessTime != nil { d.Set("last_accessed_time", partition.LastAccessTime.Format(time.RFC3339)) @@ -332,8 +317,8 @@ func expandGluePartitionInput(d *schema.ResourceData) *glue.PartitionInput { tableInput.Parameters = stringMapToPointers(v.(map[string]interface{})) } - if v, ok := d.GetOk("partition_values"); ok && v.(*schema.Set).Len() > 0 { - tableInput.Values = expandStringSet(v.(*schema.Set)) + if v, ok := d.GetOk("partition_values"); ok && len(v.([]interface{})) > 0 { + tableInput.Values = expandStringList(v.([]interface{})) } return tableInput diff --git a/aws/resource_aws_glue_partition_test.go b/aws/resource_aws_glue_partition_test.go index 5001ec0d8ae..4fbf56617ab 100644 --- a/aws/resource_aws_glue_partition_test.go +++ b/aws/resource_aws_glue_partition_test.go @@ -2,15 +2,13 @@ package aws import ( "fmt" - "reflect" "testing" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/glue" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - tfglue "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/glue" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/glue/finder" ) func TestAccAWSGluePartition_basic(t *testing.T) { @@ -30,7 +28,7 @@ func TestAccAWSGluePartition_basic(t *testing.T) { testAccCheckResourceAttrAccountID(resourceName, "catalog_id"), resource.TestCheckResourceAttr(resourceName, "database_name", rName), resource.TestCheckResourceAttr(resourceName, "partition_values.#", "1"), - resource.TestCheckTypeSetElemAttr(resourceName, "partition_values.*", parValue), + resource.TestCheckResourceAttr(resourceName, "partition_values.0", parValue), resource.TestCheckResourceAttr(resourceName, "parameters.%", "0"), resource.TestCheckResourceAttrSet(resourceName, "creation_time"), ), @@ -60,8 +58,8 @@ func TestAccAWSGluePartition_multipleValues(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckGluePartitionExists(resourceName), resource.TestCheckResourceAttr(resourceName, "partition_values.#", "2"), - resource.TestCheckTypeSetElemAttr(resourceName, "partition_values.*", parValue), - resource.TestCheckTypeSetElemAttr(resourceName, "partition_values.*", parValue2), + resource.TestCheckResourceAttr(resourceName, "partition_values.0", parValue), + resource.TestCheckResourceAttr(resourceName, "partition_values.1", parValue2), ), }, { @@ -147,18 +145,7 @@ func testAccCheckGluePartitionDestroy(s *terraform.State) error { continue } - catalogID, dbName, tableName, values, err := tfglue.ReadAwsGluePartitionID(rs.Primary.ID) - if err != nil { - return err - } - - input := &glue.GetPartitionInput{ - DatabaseName: aws.String(dbName), - CatalogId: aws.String(catalogID), - TableName: aws.String(tableName), - PartitionValues: aws.StringSlice(values), - } - if _, err := conn.GetPartition(input); err != nil { + if _, err := finder.PartitionByValues(conn, rs.Primary.ID); err != nil { if isAWSErr(err, glue.ErrCodeEntityNotFoundException, "") { continue } @@ -181,31 +168,16 @@ func testAccCheckGluePartitionExists(name string) resource.TestCheckFunc { return fmt.Errorf("No ID is set") } - catalogID, dbName, tableName, values, err := tfglue.ReadAwsGluePartitionID(rs.Primary.ID) - if err != nil { - return err - } - conn := testAccProvider.Meta().(*AWSClient).glueconn - out, err := conn.GetPartition(&glue.GetPartitionInput{ - DatabaseName: aws.String(dbName), - CatalogId: aws.String(catalogID), - TableName: aws.String(tableName), - PartitionValues: aws.StringSlice(values), - }) - + out, err := finder.PartitionByValues(conn, rs.Primary.ID) if err != nil { return err } - if out.Partition == nil { + if out == nil { return fmt.Errorf("No Glue Partition Found") } - if !reflect.DeepEqual(aws.StringValueSlice(out.Partition.Values), values) { - return fmt.Errorf("Glue Partition Mismatch") - } - return nil } }