@@ -2,12 +2,14 @@ package athena
2
2
3
3
import (
4
4
"fmt"
5
+ "log"
5
6
"regexp"
6
7
"strings"
7
8
"time"
8
9
9
10
"github.com/aws/aws-sdk-go/aws"
10
11
"github.com/aws/aws-sdk-go/service/athena"
12
+ "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr"
11
13
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
12
14
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
13
15
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
@@ -18,161 +20,217 @@ func ResourceDatabase() *schema.Resource {
18
20
return & schema.Resource {
19
21
Create : resourceDatabaseCreate ,
20
22
Read : resourceDatabaseRead ,
21
- Update : resourceDatabaseUpdate ,
23
+ Update : schema . Noop ,
22
24
Delete : resourceDatabaseDelete ,
23
25
24
26
Schema : map [string ]* schema.Schema {
25
- "name" : {
26
- Type : schema .TypeString ,
27
- Required : true ,
28
- ForceNew : true ,
29
- ValidateFunc : validation .StringMatch (regexp .MustCompile ("^[_a-z0-9]+$" ), "must be lowercase letters, numbers, or underscore ('_')" ),
27
+ "acl_configuration" : {
28
+ Type : schema .TypeList ,
29
+ Optional : true ,
30
+ ForceNew : true ,
31
+ MaxItems : 1 ,
32
+ Elem : & schema.Resource {
33
+ Schema : map [string ]* schema.Schema {
34
+ "s3_acl_option" : {
35
+ Type : schema .TypeString ,
36
+ Required : true ,
37
+ ValidateFunc : validation .StringInSlice (athena .S3AclOption_Values (), false ),
38
+ ForceNew : true ,
39
+ },
40
+ },
41
+ },
30
42
},
31
43
"bucket" : {
32
44
Type : schema .TypeString ,
33
- Required : true ,
34
- ForceNew : true ,
45
+ Optional : true ,
35
46
},
36
- "force_destroy " : {
37
- Type : schema .TypeBool ,
47
+ "comment " : {
48
+ Type : schema .TypeString ,
38
49
Optional : true ,
39
- Default : false ,
50
+ ForceNew : true ,
40
51
},
41
52
"encryption_configuration" : {
42
53
Type : schema .TypeList ,
43
54
Optional : true ,
55
+ ForceNew : true ,
44
56
MaxItems : 1 ,
45
57
Elem : & schema.Resource {
46
58
Schema : map [string ]* schema.Schema {
59
+ "encryption_option" : {
60
+ Type : schema .TypeString ,
61
+ Required : true ,
62
+ ValidateFunc : validation .StringInSlice (athena .EncryptionOption_Values (), false ),
63
+ ForceNew : true ,
64
+ },
47
65
"kms_key" : {
48
66
Type : schema .TypeString ,
49
67
Optional : true ,
50
- },
51
- "encryption_option" : {
52
- Type : schema .TypeString ,
53
- Required : true ,
54
- ValidateFunc : validation .StringInSlice ([]string {
55
- athena .EncryptionOptionCseKms ,
56
- athena .EncryptionOptionSseKms ,
57
- athena .EncryptionOptionSseS3 ,
58
- }, false ),
68
+ ForceNew : true ,
59
69
},
60
70
},
61
71
},
62
72
},
73
+ "expected_bucket_owner" : {
74
+ Type : schema .TypeString ,
75
+ Optional : true ,
76
+ ForceNew : true ,
77
+ },
78
+ "force_destroy" : {
79
+ Type : schema .TypeBool ,
80
+ Optional : true ,
81
+ Default : false ,
82
+ },
83
+ "name" : {
84
+ Type : schema .TypeString ,
85
+ Required : true ,
86
+ ForceNew : true ,
87
+ ValidateFunc : validation .StringMatch (regexp .MustCompile ("^[_a-z0-9]+$" ), "must be lowercase letters, numbers, or underscore ('_')" ),
88
+ },
63
89
},
64
90
}
65
91
}
66
92
67
- func expandAthenaResultConfiguration (bucket string , encryptionConfigurationList []interface {}) * athena.ResultConfiguration {
68
- resultConfig := athena.ResultConfiguration {
69
- OutputLocation : aws .String ("s3://" + bucket ),
70
- }
71
-
72
- if len (encryptionConfigurationList ) <= 0 {
73
- return & resultConfig
74
- }
75
-
76
- data := encryptionConfigurationList [0 ].(map [string ]interface {})
77
- keyType := data ["encryption_option" ].(string )
78
- keyID := data ["kms_key" ].(string )
93
+ func resourceDatabaseCreate (d * schema.ResourceData , meta interface {}) error {
94
+ conn := meta .(* conns.AWSClient ).AthenaConn
79
95
80
- encryptionConfig := athena.EncryptionConfiguration {
81
- EncryptionOption : aws .String (keyType ),
82
- }
96
+ name := d .Get ("name" ).(string )
97
+ var queryString string
83
98
84
- if len (keyID ) > 0 {
85
- encryptionConfig .KmsKey = aws .String (keyID )
99
+ if v , ok := d .GetOk ("comment" ); ok {
100
+ queryString = fmt .Sprintf ("create database `%[1]s` comment '%[2]s';" , name , strings .Replace (v .(string ), "'" , "\\ '" , - 1 ))
101
+ } else {
102
+ queryString = fmt .Sprintf ("create database `%[1]s`;" , name )
86
103
}
87
104
88
- resultConfig .EncryptionConfiguration = & encryptionConfig
89
-
90
- return & resultConfig
91
- }
92
-
93
- func resourceDatabaseCreate (d * schema.ResourceData , meta interface {}) error {
94
- conn := meta .(* conns.AWSClient ).AthenaConn
95
-
96
105
input := & athena.StartQueryExecutionInput {
97
- QueryString : aws .String (fmt . Sprintf ( "create database `%s`;" , d . Get ( "name" ).( string )) ),
98
- ResultConfiguration : expandAthenaResultConfiguration (d . Get ( "bucket" ).( string ), d . Get ( "encryption_configuration" ).([] interface {}) ),
106
+ QueryString : aws .String (queryString ),
107
+ ResultConfiguration : expandAthenaResultConfiguration (d ),
99
108
}
100
109
101
110
resp , err := conn .StartQueryExecution (input )
111
+
102
112
if err != nil {
103
- return err
113
+ return fmt . Errorf ( "error starting Athena Database (%s) query execution: %w" , name , err )
104
114
}
105
115
106
- if err := executeAndExpectNoRowsWhenCreate (* resp .QueryExecutionId , conn ); err != nil {
116
+ if err := executeAndExpectNoRows (* resp .QueryExecutionId , "create" , conn ); err != nil {
107
117
return err
108
118
}
109
- d .SetId (d .Get ("name" ).(string ))
119
+
120
+ d .SetId (name )
121
+
110
122
return resourceDatabaseRead (d , meta )
111
123
}
112
124
113
125
func resourceDatabaseRead (d * schema.ResourceData , meta interface {}) error {
114
126
conn := meta .(* conns.AWSClient ).AthenaConn
115
127
116
128
input := & athena.GetDatabaseInput {
117
- DatabaseName : aws .String (d .Get ( "name" ).( string )),
129
+ DatabaseName : aws .String (d .Id ( )),
118
130
CatalogName : aws .String ("AwsDataCatalog" ),
119
131
}
120
- _ , err := conn .GetDatabase (input )
132
+ res , err := conn .GetDatabase (input )
133
+
134
+ if tfawserr .ErrMessageContains (err , athena .ErrCodeMetadataException , "not found" ) && ! d .IsNewResource () {
135
+ log .Printf ("[WARN] Athena Database (%s) not found, removing from state" , d .Id ())
136
+ d .SetId ("" )
137
+ return nil
138
+ }
139
+
121
140
if err != nil {
122
- return err
141
+ return fmt . Errorf ( "error reading Athena Database (%s): %w" , d . Id (), err )
123
142
}
124
- return nil
125
- }
126
143
127
- func resourceDatabaseUpdate (d * schema.ResourceData , meta interface {}) error {
128
- return resourceDatabaseRead (d , meta )
144
+ db := res .Database
145
+
146
+ d .Set ("name" , db .Name )
147
+
148
+ return nil
129
149
}
130
150
131
151
func resourceDatabaseDelete (d * schema.ResourceData , meta interface {}) error {
132
152
conn := meta .(* conns.AWSClient ).AthenaConn
133
153
134
- name := d .Get ("name" ).(string )
135
-
136
- queryString := fmt .Sprintf ("drop database `%s`" , name )
154
+ queryString := fmt .Sprintf ("drop database `%s`" , d .Id ())
137
155
if d .Get ("force_destroy" ).(bool ) {
138
156
queryString += " cascade"
139
157
}
140
158
queryString += ";"
141
159
142
160
input := & athena.StartQueryExecutionInput {
143
161
QueryString : aws .String (queryString ),
144
- ResultConfiguration : expandAthenaResultConfiguration (d . Get ( "bucket" ).( string ), d . Get ( "encryption_configuration" ).([] interface {}) ),
162
+ ResultConfiguration : expandAthenaResultConfiguration (d ),
145
163
}
146
164
147
165
resp , err := conn .StartQueryExecution (input )
148
166
if err != nil {
149
167
return err
150
168
}
151
169
152
- if err := executeAndExpectNoRowsWhenDrop (* resp .QueryExecutionId , conn ); err != nil {
170
+ if err := executeAndExpectNoRows (* resp .QueryExecutionId , "delete" , conn ); err != nil {
153
171
return err
154
172
}
173
+
155
174
return nil
156
175
}
157
176
158
- func executeAndExpectNoRowsWhenCreate (qeid string , conn * athena.Athena ) error {
159
- rs , err := QueryExecutionResult (qeid , conn )
160
- if err != nil {
161
- return err
177
+ func expandAthenaResultConfiguration (d * schema.ResourceData ) * athena.ResultConfiguration {
178
+
179
+ resultConfig := & athena.ResultConfiguration {
180
+ OutputLocation : aws .String ("s3://" + d .Get ("bucket" ).(string )),
181
+ EncryptionConfiguration : expandAthenaResultConfigurationEncryptionConfig (d .Get ("encryption_configuration" ).([]interface {})),
162
182
}
163
- if len (rs .Rows ) != 0 {
164
- return fmt .Errorf ("Athena create database, unexpected query result: %s" , flattenAthenaResultSet (rs ))
183
+
184
+ if v , ok := d .GetOk ("expected_bucket_owner" ); ok {
185
+ resultConfig .ExpectedBucketOwner = aws .String (v .(string ))
165
186
}
166
- return nil
187
+
188
+ if v , ok := d .GetOk ("acl_configuration" ); ok && len (v .([]interface {})) > 0 {
189
+ resultConfig .AclConfiguration = expandAthenaResultConfigurationAclConfig (v .([]interface {}))
190
+ }
191
+
192
+ return resultConfig
193
+ }
194
+
195
+ func expandAthenaResultConfigurationEncryptionConfig (config []interface {}) * athena.EncryptionConfiguration {
196
+ if len (config ) <= 0 {
197
+ return nil
198
+ }
199
+
200
+ data := config [0 ].(map [string ]interface {})
201
+
202
+ encryptionConfig := & athena.EncryptionConfiguration {
203
+ EncryptionOption : aws .String (data ["encryption_option" ].(string )),
204
+ }
205
+
206
+ if v , ok := data ["kms_key" ].(string ); ok && v != "" {
207
+ encryptionConfig .KmsKey = aws .String (v )
208
+ }
209
+
210
+ return encryptionConfig
211
+ }
212
+
213
+ func expandAthenaResultConfigurationAclConfig (config []interface {}) * athena.AclConfiguration {
214
+ if len (config ) <= 0 {
215
+ return nil
216
+ }
217
+
218
+ data := config [0 ].(map [string ]interface {})
219
+
220
+ encryptionConfig := & athena.AclConfiguration {
221
+ S3AclOption : aws .String (data ["s3_acl_option" ].(string )),
222
+ }
223
+
224
+ return encryptionConfig
167
225
}
168
226
169
- func executeAndExpectNoRowsWhenDrop (qeid string , conn * athena.Athena ) error {
227
+ func executeAndExpectNoRows (qeid , action string , conn * athena.Athena ) error {
170
228
rs , err := QueryExecutionResult (qeid , conn )
171
229
if err != nil {
172
230
return err
173
231
}
174
232
if len (rs .Rows ) != 0 {
175
- return fmt .Errorf ("Athena drop database, unexpected query result: %s" , flattenAthenaResultSet (rs ))
233
+ return fmt .Errorf ("Athena %s database, unexpected query result: %s" , action , flattenAthenaResultSet (rs ))
176
234
}
177
235
return nil
178
236
}
0 commit comments