Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

r/glue_partition_index - new resource #21234

Merged
merged 2 commits into from
Oct 13, 2021
Merged
Show file tree
Hide file tree
Changes from all 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: 7 additions & 0 deletions .changelog/21234.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
```release-note:bug
resource/aws_glue_catalog_table: change `partition_index.keys` to list instead of set
```

```release-note:new-resource
aws_glue_partition_index
```
54 changes: 54 additions & 0 deletions aws/internal/service/glue/finder/finder.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,3 +164,57 @@ func ConnectionByName(conn *glue.Glue, name, catalogID string) (*glue.Connection

return output.Connection, nil
}

// PartitionIndexByName returns the Partition Index corresponding to the specified Partition Index Name.
func PartitionIndexByName(conn *glue.Glue, id string) (*glue.PartitionIndexDescriptor, error) {

catalogID, dbName, tableName, partIndex, err := tfglue.ReadAwsGluePartitionIndexID(id)
if err != nil {
return nil, err
}

input := &glue.GetPartitionIndexesInput{
CatalogId: aws.String(catalogID),
DatabaseName: aws.String(dbName),
TableName: aws.String(tableName),
}

var result *glue.PartitionIndexDescriptor

output, err := conn.GetPartitionIndexes(input)

if tfawserr.ErrCodeEquals(err, glue.ErrCodeEntityNotFoundException) {
return nil, &resource.NotFoundError{
LastError: err,
LastRequest: input,
}
}

if err != nil {
return nil, err
}

if output == nil {
return nil, tfresource.NewEmptyResultError(input)
}

for _, partInd := range output.PartitionIndexDescriptorList {
if partInd == nil {
continue
}

if aws.StringValue(partInd.IndexName) == partIndex {
result = partInd
break
}
}

if result == nil {
return nil, &resource.NotFoundError{
LastError: err,
LastRequest: input,
}
}

return result, nil
}
12 changes: 12 additions & 0 deletions aws/internal/service/glue/id.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,22 @@ func ReadAwsGluePartitionID(id string) (catalogID string, dbName string, tableNa
return idParts[0], idParts[1], idParts[2], vals, nil
}

func ReadAwsGluePartitionIndexID(id string) (catalogID, dbName, tableName, indexName string, error error) {
idParts := strings.Split(id, ":")
if len(idParts) != 4 {
return "", "", "", "", fmt.Errorf("expected ID in format catalog-id:database-name:table-name:index-name, received: %s", id)
}
return idParts[0], idParts[1], idParts[2], idParts[3], nil
}

func CreateAwsGluePartitionID(catalogID, dbName, tableName string, values []interface{}) string {
return fmt.Sprintf("%s:%s:%s:%s", catalogID, dbName, tableName, stringifyAwsGluePartition(values))
}

func CreateAwsGluePartitionIndexID(catalogID, dbName, tableName, indexName string) string {
return fmt.Sprintf("%s:%s:%s:%s", catalogID, dbName, tableName, indexName)
}

func stringifyAwsGluePartition(partValues []interface{}) string {
var b bytes.Buffer
for _, val := range partValues {
Expand Down
16 changes: 16 additions & 0 deletions aws/internal/service/glue/waiter/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,19 @@ func GlueDevEndpointStatus(conn *glue.Glue, name string) resource.StateRefreshFu
return output, aws.StringValue(output.Status), nil
}
}

func GluePartitionIndexStatus(conn *glue.Glue, id string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
output, err := finder.PartitionIndexByName(conn, id)

if tfresource.NotFound(err) {
return nil, "", nil
}

if err != nil {
return nil, "", err
}

return output, aws.StringValue(output.IndexStatus), nil
}
}
34 changes: 34 additions & 0 deletions aws/internal/service/glue/waiter/waiter.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,3 +196,37 @@ func GlueDevEndpointDeleted(conn *glue.Glue, name string) (*glue.DevEndpoint, er

return nil, err
}

func GluePartitionIndexCreated(conn *glue.Glue, id string) (*glue.PartitionIndexDescriptor, error) {
stateConf := &resource.StateChangeConf{
Pending: []string{glue.PartitionIndexStatusCreating},
Target: []string{glue.PartitionIndexStatusActive},
Refresh: GluePartitionIndexStatus(conn, id),
Timeout: 2 * time.Minute,
}

outputRaw, err := stateConf.WaitForState()

if output, ok := outputRaw.(*glue.PartitionIndexDescriptor); ok {
return output, err
}

return nil, err
}

func GluePartitionIndexDeleted(conn *glue.Glue, id string) (*glue.PartitionIndexDescriptor, error) {
stateConf := &resource.StateChangeConf{
Pending: []string{glue.PartitionIndexStatusDeleting},
Target: []string{},
Refresh: GluePartitionIndexStatus(conn, id),
Timeout: 2 * time.Minute,
}

outputRaw, err := stateConf.WaitForState()

if output, ok := outputRaw.(*glue.PartitionIndexDescriptor); ok {
return output, err
}

return nil, err
}
1 change: 1 addition & 0 deletions aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -835,6 +835,7 @@ func Provider() *schema.Provider {
"aws_glue_job": resourceAwsGlueJob(),
"aws_glue_ml_transform": resourceAwsGlueMLTransform(),
"aws_glue_partition": resourceAwsGluePartition(),
"aws_glue_partition_index": resourceAwsGluePartitionIndex(),
"aws_glue_registry": resourceAwsGlueRegistry(),
"aws_glue_resource_policy": resourceAwsGlueResourcePolicy(),
"aws_glue_schema": resourceAwsGlueSchema(),
Expand Down
7 changes: 4 additions & 3 deletions aws/resource_aws_glue_catalog_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,7 @@ func resourceAwsGlueCatalogTable() *schema.Resource {
"partition_index": {
Type: schema.TypeList,
Optional: true,
Computed: true,
ForceNew: true,
MaxItems: 3,
Elem: &schema.Resource{
Expand All @@ -328,7 +329,7 @@ func resourceAwsGlueCatalogTable() *schema.Resource {
ValidateFunc: validation.StringLenBetween(1, 255),
},
"keys": {
Type: schema.TypeSet,
Type: schema.TypeList,
Required: true,
MinItems: 1,
Elem: &schema.Schema{Type: schema.TypeString},
Expand Down Expand Up @@ -563,7 +564,7 @@ func expandGlueTablePartitionIndexes(a []interface{}) []*glue.PartitionIndex {
func expandGlueTablePartitionIndex(m map[string]interface{}) *glue.PartitionIndex {
partitionIndex := &glue.PartitionIndex{
IndexName: aws.String(m["index_name"].(string)),
Keys: expandStringSet(m["keys"].(*schema.Set)),
Keys: expandStringList(m["keys"].([]interface{})),
}

return partitionIndex
Expand Down Expand Up @@ -872,7 +873,7 @@ func flattenGluePartitionIndex(c *glue.PartitionIndexDescriptor) map[string]inte
for _, key := range c.Keys {
names = append(names, key.Name)
}
partitionIndex["keys"] = flattenStringSet(names)
partitionIndex["keys"] = flattenStringList(names)
}

return partitionIndex
Expand Down
180 changes: 180 additions & 0 deletions aws/resource_aws_glue_partition_index.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
package aws

import (
"fmt"
"log"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/glue"
"github.com/hashicorp/aws-sdk-go-base/tfawserr"
"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"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/service/glue/waiter"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource"
)

func resourceAwsGluePartitionIndex() *schema.Resource {
return &schema.Resource{
Create: resourceAwsGluePartitionIndexCreate,
Read: resourceAwsGluePartitionIndexRead,
Delete: resourceAwsGluePartitionIndexDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Schema: map[string]*schema.Schema{
"catalog_id": {
Type: schema.TypeString,
ForceNew: true,
Optional: true,
Computed: true,
},
"database_name": {
Type: schema.TypeString,
ForceNew: true,
Required: true,
ValidateFunc: validation.StringLenBetween(1, 255),
},
"table_name": {
Type: schema.TypeString,
ForceNew: true,
Required: true,
ValidateFunc: validation.StringLenBetween(1, 255),
},
"partition_index": {
Type: schema.TypeList,
Required: true,
ForceNew: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"index_name": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
"index_status": {
Type: schema.TypeString,
Computed: true,
},
"keys": {
Type: schema.TypeList,
Optional: true,
ForceNew: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
},
},
},
},
}
}

func resourceAwsGluePartitionIndexCreate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).glueconn
catalogID := createAwsGlueCatalogID(d, meta.(*AWSClient).accountid)
dbName := d.Get("database_name").(string)
tableName := d.Get("table_name").(string)

input := &glue.CreatePartitionIndexInput{
CatalogId: aws.String(catalogID),
DatabaseName: aws.String(dbName),
TableName: aws.String(tableName),
PartitionIndex: expandAwsGluePartitionIndex(d.Get("partition_index").([]interface{})),
}

log.Printf("[DEBUG] Creating Glue Partition Index: %#v", input)
_, err := conn.CreatePartitionIndex(input)
if err != nil {
return fmt.Errorf("error creating Glue Partition Index: %w", err)
}

d.SetId(tfglue.CreateAwsGluePartitionIndexID(catalogID, dbName, tableName, aws.StringValue(input.PartitionIndex.IndexName)))

if _, err := waiter.GluePartitionIndexCreated(conn, d.Id()); err != nil {
return fmt.Errorf("error while waiting for Glue Partition Index (%s) to become available: %w", d.Id(), err)
}

return resourceAwsGluePartitionIndexRead(d, meta)
}

func resourceAwsGluePartitionIndexRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).glueconn

catalogID, dbName, tableName, _, tableErr := tfglue.ReadAwsGluePartitionIndexID(d.Id())
if tableErr != nil {
return tableErr
}

log.Printf("[DEBUG] Reading Glue Partition Index: %s", d.Id())
partition, err := finder.PartitionIndexByName(conn, d.Id())
if !d.IsNewResource() && tfresource.NotFound(err) {
log.Printf("[WARN] Glue Partition Index (%s) not found, removing from state", d.Id())
d.SetId("")
return nil
}

if err != nil {
return fmt.Errorf("error reading Glue Partition Index (%s): %w", d.Id(), err)
}

d.Set("table_name", tableName)
d.Set("catalog_id", catalogID)
d.Set("database_name", dbName)

if err := d.Set("partition_index", []map[string]interface{}{flattenGluePartitionIndex(partition)}); err != nil {
return fmt.Errorf("error setting partition_index: %w", err)
}

return nil
}

func resourceAwsGluePartitionIndexDelete(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).glueconn

catalogID, dbName, tableName, partIndex, tableErr := tfglue.ReadAwsGluePartitionIndexID(d.Id())
if tableErr != nil {
return tableErr
}

log.Printf("[DEBUG] Deleting Glue Partition Index: %s", d.Id())
_, err := conn.DeletePartitionIndex(&glue.DeletePartitionIndexInput{
CatalogId: aws.String(catalogID),
TableName: aws.String(tableName),
DatabaseName: aws.String(dbName),
IndexName: aws.String(partIndex),
})
if err != nil {
if tfawserr.ErrCodeEquals(err, glue.ErrCodeEntityNotFoundException) {
return nil
}
return fmt.Errorf("Error deleting Glue Partition Index: %w", err)
}

if _, err := waiter.GluePartitionIndexDeleted(conn, d.Id()); err != nil {
return fmt.Errorf("error while waiting for Glue Partition Index (%s) to be deleted: %w", d.Id(), err)
}

return nil
}

func expandAwsGluePartitionIndex(l []interface{}) *glue.PartitionIndex {
if len(l) == 0 || l[0] == nil {
return nil
}

s := l[0].(map[string]interface{})
parIndex := &glue.PartitionIndex{}

if v, ok := s["keys"].([]interface{}); ok && len(v) > 0 {
parIndex.Keys = expandStringList(v)
}

if v, ok := s["index_name"].(string); ok && v != "" {
parIndex.IndexName = aws.String(v)
}

return parIndex
}
Loading