Skip to content

Commit

Permalink
Merge pull request #24172 from DrFaust92/athena-import
Browse files Browse the repository at this point in the history
r/athena_database - add `properties` + import support
  • Loading branch information
ewbankkit authored Apr 12, 2022
2 parents 65d0933 + b974c52 commit bf896df
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 6 deletions.
11 changes: 11 additions & 0 deletions .changelog/24172.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
```release-note:enhancement
resource/aws_athena_database: Add import support.
```

```release-note:enhancement
resource/aws_athena_database: Add `properties` argument.
```

```release-note:bug
resource/aws_athena_database: Add drift detection for `comment`.
```
39 changes: 33 additions & 6 deletions internal/service/athena/database.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package athena

import (
"bytes"
"fmt"
"log"
"regexp"
Expand All @@ -22,6 +23,9 @@ func ResourceDatabase() *schema.Resource {
Read: resourceDatabaseRead,
Update: schema.Noop,
Delete: resourceDatabaseDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Schema: map[string]*schema.Schema{
"acl_configuration": {
Expand Down Expand Up @@ -86,6 +90,12 @@ func ResourceDatabase() *schema.Resource {
ForceNew: true,
ValidateFunc: validation.StringMatch(regexp.MustCompile("^[_a-z0-9]+$"), "must be lowercase letters, numbers, or underscore ('_')"),
},
"properties": {
Type: schema.TypeMap,
Optional: true,
ForceNew: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
},
}
}
Expand All @@ -94,16 +104,31 @@ func resourceDatabaseCreate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*conns.AWSClient).AthenaConn

name := d.Get("name").(string)
var queryString string
var queryString bytes.Buffer

createStmt := fmt.Sprintf("create database `%s`", name)
queryString.WriteString(createStmt)

if v, ok := d.GetOk("comment"); ok {
queryString = fmt.Sprintf("create database `%[1]s` comment '%[2]s';", name, strings.Replace(v.(string), "'", "\\'", -1))
} else {
queryString = fmt.Sprintf("create database `%[1]s`;", name)
if v, ok := d.GetOk("comment"); ok && v.(string) != "" {
commentStmt := fmt.Sprintf(" comment '%s'", strings.Replace(v.(string), "'", "\\'", -1))
queryString.WriteString(commentStmt)
}

if v, ok := d.GetOk("properties"); ok && len(v.(map[string]interface{})) > 0 {
var props []string
for k, v := range v.(map[string]interface{}) {
prop := fmt.Sprintf(" '%[1]s' = '%[2]s' ", k, v.(string))
props = append(props, prop)
}

propStmt := fmt.Sprintf(" WITH DBPROPERTIES(%s)", strings.Join(props, ","))
queryString.WriteString(propStmt)
}

queryString.WriteString(";")

input := &athena.StartQueryExecutionInput{
QueryString: aws.String(queryString),
QueryString: aws.String(queryString.String()),
ResultConfiguration: expandAthenaResultConfiguration(d),
}

Expand Down Expand Up @@ -144,6 +169,8 @@ func resourceDatabaseRead(d *schema.ResourceData, meta interface{}) error {
db := res.Database

d.Set("name", db.Name)
d.Set("comment", db.Description)
d.Set("properties", db.Parameters)

return nil
}
Expand Down
88 changes: 88 additions & 0 deletions internal/service/athena/database_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,45 @@ func TestAccAthenaDatabase_basic(t *testing.T) {
resource.TestCheckResourceAttrPair(resourceName, "bucket", "aws_s3_bucket.test", "bucket"),
resource.TestCheckResourceAttr(resourceName, "acl_configuration.#", "0"),
resource.TestCheckResourceAttr(resourceName, "encryption_configuration.#", "0"),
resource.TestCheckResourceAttr(resourceName, "properties.%", "0"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"bucket", "force_destroy"},
},
},
})
}

func TestAccAthenaDatabase_properties(t *testing.T) {
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
dbName := sdkacctest.RandString(8)
resourceName := "aws_athena_database.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(t) },
ErrorCheck: acctest.ErrorCheck(t, athena.EndpointsID),
Providers: acctest.Providers,
CheckDestroy: testAccCheckDatabaseDestroy,
Steps: []resource.TestStep{
{
Config: testAccAthenaDatabasePropertiesConfig(rName, dbName, false),
Check: resource.ComposeTestCheckFunc(
testAccCheckDatabaseExists(resourceName),
resource.TestCheckResourceAttr(resourceName, "name", dbName),
resource.TestCheckResourceAttr(resourceName, "properties.%", "1"),
resource.TestCheckResourceAttr(resourceName, "properties.creator", "Jane D."),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"bucket", "force_destroy"},
},
},
})
}
Expand All @@ -60,6 +97,12 @@ func TestAccAthenaDatabase_acl(t *testing.T) {
resource.TestCheckResourceAttr(resourceName, "acl_configuration.0.s3_acl_option", "BUCKET_OWNER_FULL_CONTROL"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"bucket", "acl_configuration", "force_destroy"},
},
},
})
}
Expand All @@ -84,6 +127,12 @@ func TestAccAthenaDatabase_encryption(t *testing.T) {
resource.TestCheckResourceAttrPair(resourceName, "encryption_configuration.0.kms_key", "aws_kms_key.test", "arn"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"bucket", "force_destroy", "encryption_configuration"},
},
},
})
}
Expand All @@ -106,6 +155,12 @@ func TestAccAthenaDatabase_nameStartsWithUnderscore(t *testing.T) {
resource.TestCheckResourceAttr(resourceName, "name", dbName),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"bucket", "force_destroy"},
},
},
})
}
Expand Down Expand Up @@ -188,8 +243,15 @@ func TestAccAthenaDatabase_description(t *testing.T) {
Check: resource.ComposeTestCheckFunc(
testAccCheckDatabaseExists(resourceName),
resource.TestCheckResourceAttr(resourceName, "name", dbName),
resource.TestCheckResourceAttr(resourceName, "comment", "athena is a goddess"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"bucket", "force_destroy"},
},
},
})
}
Expand All @@ -210,8 +272,15 @@ func TestAccAthenaDatabase_unescaped_description(t *testing.T) {
Check: resource.ComposeTestCheckFunc(
testAccCheckDatabaseExists(resourceName),
resource.TestCheckResourceAttr(resourceName, "name", dbName),
resource.TestCheckResourceAttr(resourceName, "comment", "athena's a goddess"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"bucket", "force_destroy"},
},
},
})
}
Expand Down Expand Up @@ -403,6 +472,25 @@ resource "aws_athena_database" "test" {
`, rName, dbName, forceDestroy)
}

func testAccAthenaDatabasePropertiesConfig(rName string, dbName string, forceDestroy bool) string {
return fmt.Sprintf(`
resource "aws_s3_bucket" "test" {
bucket = %[1]q
force_destroy = true
}
resource "aws_athena_database" "test" {
name = %[2]q
bucket = aws_s3_bucket.test.bucket
force_destroy = %[3]t
properties = {
creator = "Jane D."
}
}
`, rName, dbName, forceDestroy)
}

func testAccAthenaDatabaseAclConfig(rName string, dbName string, forceDestroy bool) string {
return fmt.Sprintf(`
resource "aws_s3_bucket" "test" {
Expand Down
23 changes: 23 additions & 0 deletions website/docs/r/athena_database.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ The following arguments are supported:
* `encryption_configuration` - (Optional) The encryption key block AWS Athena uses to decrypt the data in S3, such as an AWS Key Management Service (AWS KMS) key. See [Encryption Configuration](#encryption-configuration) below.
* `expected_bucket_owner` - (Optional) The AWS account ID that you expect to be the owner of the Amazon S3 bucket.
* `force_destroy` - (Optional, Default: false) A boolean that indicates all tables should be deleted from the database so that the database can be destroyed without error. The tables are *not* recoverable.
* `properties` - (Optional) A key-value map of custom metadata properties for the database definition.

### ACL Configuration

Expand All @@ -51,3 +52,25 @@ The following arguments are supported:
In addition to all arguments above, the following attributes are exported:

* `id` - The database name

## Import

Athena Databases can be imported using their name, e.g.,

```
$ terraform import aws_athena_database.example example
```

Certain resource arguments, like `encryption_configuration` and `bucket`, do not have an API method for reading the information after creation. If the argument is set in the Terraform configuration on an imported resource, Terraform will always show a difference. To workaround this behavior, either omit the argument from the Terraform configuration or use [`ignore_changes`](https://www.terraform.io/docs/configuration/meta-arguments/lifecycle.html#ignore_changes) to hide the difference, e.g.,

```terraform
resource "aws_athena_database" "example" {
name = "database_name"
bucket = aws_s3_bucket.example.bucket
# There is no API for reading bucket
lifecycle {
ignore_changes = [bucket]
}
}
```

0 comments on commit bf896df

Please sign in to comment.