-
Notifications
You must be signed in to change notification settings - Fork 9.2k
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
Add RDS Restore Option #2728
Add RDS Restore Option #2728
Conversation
Been a month... any updates? |
Hi @jasonmcintosh sorry for the maintainer delay in getting this reviewed for you. I don't have time to give this a fully exhaustive review right now but skimming the acceptance test, is it possible to actually test and have this succeed currently? It looks like it would be trying to pull the S3 backup from a random bucket and not succeed. Does AWS have a sample S3 backup that might work with this? Otherwise, we might need to get real creative. |
XtraBackup database - we can create and share a sample file. When I was testing in the provider, we only did unit tests vs. integration tests. Then, we built the provider and did manual integration tests. If you want an automatic integration test I can look at adding that support. It'll be trickier but doable - just have to create a random bucket, a bucket item from the sample file, and then run the integration tests and tear down. We'd need to store the xtrabackup file in the tests but thankfully it's a tiny binary file. |
Bringing in master changes (which look like really one file) to validate/test again. |
@bflad Note, this COULD be a misunderstanding on our part - we're pretty new to Go (some of us are). Were these acceptance tests and we just missed something on this? |
Sorry our terminology for "acceptance" testing is equivalent to "integration" testing. It expects to fully test a Terraform configuration against the AWS APIs and have it succeed end-to-end. In order to accomplish that, it looks like we'll need to have the test perform quite a few steps according to the documentation including setting up an IAM role that RDS can assume and having a S3 location ready to go with a valid backup file in an automated fashion. As for handling a valid backup file in S3, I can think of a few automated options:
But similar to what you said previously, we're probably going to want to go with one of the last two options, but I think it really depends on the size of the backup file. We probably don't want to include something in the repository over a few MB. So short story here is that at the very least, the acceptance test for this feature will need to handle the IAM role creation, then we need to figure out the S3 backup file handling. If you don't have time or interest in doing this, that's perfectly okay too 👍 . It just means this PR will be delayed as this functionality is not currently a priority (that I know about) for any of the Hashicorp employed maintainers. |
We're happy to add this support :) Looking at options 3 & 4 right now - we're thinking option 4 should be viable (creating a test file now, getting it as small as we can). On role... looks like there's another test that creates a monitoring role. Can see if I can't re-use some of that. Good feedback/information - thanks! It may be early next week before we can get to this though. We can run the provider locally for now to get us moving while we add support. |
@bflad We have a 1.3MB tiny backup with a test DB. Do you want it in git (it's a .tar.gz file) or an email so you can create a public S3 location? Working on the tests shortly :) Note, we'll be looking to add the same functionality to aurora - do you want those changes in the same pull request or separate? |
@jasonmcintosh for now can you email it to my Github username at hashicorp dot com? I'll discuss how we want to handle this internally. Separate pull request would be preferred. Thanks! |
@bflad We've got acceptance tests quasi-working. It creates the database from an s3 restore. However, we've got a problem where IAM role creation is required for this to work, and the IAM role doesn't seem to be fully propagated before it's used. Do you have any thoughts on solutions around this? e.g. how to add a sleep into the code to make sure the IAM role is there first? We tried a depends_on block similar to the way the enhanced monitoring RDS role works, but that doesn't seem to work in the case of a restore. As we understand it, Step blocks in acceptance tests are destroyed before the next steps, so we can't do a Step "Pre-setup resources", Step "Sleep", Step "Create S3"? |
Inside the err = resource.Retry(5*time.Minute, func() *resource.RetryError {
_, err = conn.RestoreDBInstanceFromS3(&opts)
if err != nil {
if isAWSErr(err, "InvalidParameterValue", "... IAM role message here ...") {
return resource.RetryableError(err)
}
if isAWSErr(err, "InvalidParameterValue", "ENHANCED_MONITORING") {
return resource.RetryableError(err)
}
return resource.NonRetryableError(err)
}
return nil
}) |
Went ahead and put this in a files/ folder - happy to change the config if you don't like this... didn't seem like there were many good options. Hadn't heard if you'd put this in a public S3 bucket someplace for test purposes. We're starting on the aurora piece next |
Turns out terraform creates S3 buckets and IAM roles so fast, had to retry on both bucket and IAM role. But acceptance tests passed locally. We added VPC creation code as we delete default vpcs to make sure that everything needed for the test to pass would work regardless of environment. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for working through this @jasonmcintosh -- I left an initial review down below. Can you check the items and let us know if you have any questions or do not have time to implement the feedback?
aws/resource_aws_db_instance.go
Outdated
@@ -220,6 +220,49 @@ func resourceAwsDbInstance() *schema.Resource { | |||
}, | |||
}, | |||
|
|||
"s3_import": { | |||
Type: schema.TypeSet, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For simple nested attributes with MaxItems: 1
we prefer schema.TypeList
👍
aws/resource_aws_db_instance.go
Outdated
"bucket_name": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
Optional: false, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Required: true
is defined, so Optional: false
is extraneous
}, | ||
"bucket_prefix": { | ||
Type: schema.TypeString, | ||
Required: false, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Optional: true
is defined, so Required: false
is extraneous
aws/resource_aws_db_instance.go
Outdated
Type: schema.TypeString, | ||
Required: false, | ||
Optional: true, | ||
Default: "", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The zero value for schema.TypeString
is ""
so Default: ""
is extraneous
@@ -220,6 +220,49 @@ func resourceAwsDbInstance() *schema.Resource { | |||
}, | |||
}, | |||
|
|||
"s3_import": { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should add ForceNew: true
to all child attributes of s3_import
as there is no "update" available for it. 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added this, though I could see long term an interesting debate. if it's use as a spring-board to create a database, should be able to remove the backup file after the database is created. SO in theory, deleting the block shouldn't cause a rebuild/recreate. But I guess that can be done with ignore attributes block instead...
aws/resource_aws_db_instance.go
Outdated
err = resource.Retry(5*time.Minute, func() *resource.RetryError { | ||
_, err = conn.RestoreDBInstanceFromS3(&opts) | ||
if err != nil { | ||
if awsErr, ok := err.(awserr.Error); ok { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be simplified with:
if isAWSErr(err, "InvalidParameterValue", "ENHANCED_MONITORING") {
return resource.RetryableError(awsErr)
}
if isAWSErr(err, "InvalidParameterValue", "S3_SNAPSHOT_INGESTION") {
return resource.RetryableError(err)
}
if isAWSErr(err, "InvalidParameterValue", "S3 bucket cannot be found") {
return resource.RetryableError(err)
}
aws/resource_aws_db_instance_test.go
Outdated
resource "aws_s3_bucket_object" "xtrabackup_db" { | ||
bucket = "${aws_s3_bucket.xtrabackup.id}" | ||
key = "%s/sample.tar.gz" | ||
source = "../files/2018-02-26_19-31-02.tar.gz" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we please rename the backup file to something meaningful? e.g. mysql-5-6-xtrabackup.tar.gz
|
||
~> **NOTE:** Removing the `replicate_source_db` attribute from an existing RDS | ||
Replicate database managed by Terraform will promote the database to a fully | ||
standalone database. | ||
|
||
### S3 Import Options | ||
Full details on the core parameters and impacts are in the API Docs: [RestoreDBInstanceFromS3](http://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_RestoreDBInstanceFromS3.html). Sample | ||
```hcl |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this requires an extra newline above or the formatting will not work -- it can be verified using make website
(available very recently in master)
aws/resource_aws_db_instance_test.go
Outdated
} | ||
|
||
resource "aws_iam_policy" "test" { | ||
name = "tf-s3-rds-access-policy" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to be randomized with -%s
in case of test failures/concurrency. 👍
aws/resource_aws_db_instance_test.go
Outdated
} | ||
|
||
resource "aws_db_subnet_group" "foo" { | ||
name = "foo" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to be randomized with -%s
in case of test failures/concurrency. 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work on this @jasonmcintosh! 🚀
21 tests passed (all tests)
=== RUN TestAccAWSDBInstance_ec2Classic
--- PASS: TestAccAWSDBInstance_ec2Classic (389.91s)
=== RUN TestAccAWSDBInstance_importBasic
--- PASS: TestAccAWSDBInstance_importBasic (434.16s)
=== RUN TestAccAWSDBInstance_kmsKey
--- PASS: TestAccAWSDBInstance_kmsKey (463.16s)
=== RUN TestAccAWSDBInstance_basic
--- PASS: TestAccAWSDBInstance_basic (483.81s)
=== RUN TestAccAWSDBInstance_MinorVersion
--- PASS: TestAccAWSDBInstance_MinorVersion (493.82s)
=== RUN TestAccAWSDBInstance_diffSuppressInitialState
--- PASS: TestAccAWSDBInstance_diffSuppressInitialState (504.25s)
=== RUN TestAccAWSDBInstance_iamAuth
--- PASS: TestAccAWSDBInstance_iamAuth (544.28s)
=== RUN TestAccAWSDBInstance_portUpdate
--- PASS: TestAccAWSDBInstance_portUpdate (579.35s)
=== RUN TestAccAWSDBInstance_optionGroup
--- PASS: TestAccAWSDBInstance_optionGroup (604.39s)
=== RUN TestAccAWSDBInstance_separate_iops_update
--- PASS: TestAccAWSDBInstance_separate_iops_update (730.22s)
=== RUN TestAccAWSDBInstance_s3
--- PASS: TestAccAWSDBInstance_s3 (789.36s)
=== RUN TestAccAWSDBInstance_enhancedMonitoring
--- PASS: TestAccAWSDBInstance_enhancedMonitoring (860.33s)
=== RUN TestAccAWSDBInstance_noSnapshot
--- PASS: TestAccAWSDBInstance_noSnapshot (866.56s)
=== RUN TestAccAWSDBInstance_cloudwatchLogsExportConfigurationUpdate
--- PASS: TestAccAWSDBInstance_cloudwatchLogsExportConfigurationUpdate (696.78s)
=== RUN TestAccAWSDBInstance_generatedName
--- PASS: TestAccAWSDBInstance_generatedName (1349.43s)
=== RUN TestAccAWSDBInstance_cloudwatchLogsExportConfiguration
--- PASS: TestAccAWSDBInstance_cloudwatchLogsExportConfiguration (1409.68s)
=== RUN TestAccAWSDBInstance_namePrefix
--- PASS: TestAccAWSDBInstance_namePrefix (1435.82s)
=== RUN TestAccAWSDBInstance_replica
--- PASS: TestAccAWSDBInstance_replica (1686.79s)
=== RUN TestAccAWSDBInstance_subnetGroup
--- PASS: TestAccAWSDBInstance_subnetGroup (1769.29s)
=== RUN TestAccAWSDBInstance_snapshot
--- PASS: TestAccAWSDBInstance_snapshot (1993.40s)
=== RUN TestAccAWSDBInstance_MSSQL_TZ
--- PASS: TestAccAWSDBInstance_MSSQL_TZ (2444.66s)
Thanks a ton @bflad will have one for Aurora soon. I'm HOPING in some spare time I can work on refactoring some of that codebase. There's a lot of duplication there that I think could be cleaned up. |
This has been released in version 1.16.0 of the AWS provider. Please see the Terraform documentation on provider versioning or reach out if you need any assistance upgrading. |
I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues. If you feel this issue should be reopened, we encourage creating a new issue linking back to this one for added context. Thanks! |
Adds support for creating a DB Instance from an S3 xtrabackup snapshot
#2410
First attempt to do go, so certain points are not entirely ideal. Also would love to rewrite the restore and create so many of the required options are set in a function vs. duplicated, but that can be refactored later