-
Notifications
You must be signed in to change notification settings - Fork 9.3k
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
resource_aws_kinesis_firehose_delivery_stream: Avoid invalid state on refresh (cont.) #9103
Changes from all commits
ef059b2
560cf07
c821503
d90aaf3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -328,11 +328,25 @@ func flattenFirehoseDataFormatConversionConfiguration(dfcc *firehose.DataFormatC | |
return []map[string]interface{}{} | ||
} | ||
|
||
enabled := aws.BoolValue(dfcc.Enabled) | ||
ifc := flattenFirehoseInputFormatConfiguration(dfcc.InputFormatConfiguration) | ||
ofc := flattenFirehoseOutputFormatConfiguration(dfcc.OutputFormatConfiguration) | ||
sc := flattenFirehoseSchemaConfiguration(dfcc.SchemaConfiguration) | ||
|
||
// The AWS SDK can represent "no data format conversion configuration" in two ways: | ||
// 1. With a nil value | ||
// 2. With enabled set to false and nil for ALL the config sections. | ||
// These two cases are equivalent so we use the same state description, to avoid diffs. | ||
if !enabled && len(ifc) == 0 && len(ofc) == 0 && len(sc) == 0 { | ||
log.Printf("Found ambiguous AWS response") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Extraneous log line can be removed |
||
return []map[string]interface{}{} | ||
} | ||
|
||
m := map[string]interface{}{ | ||
"enabled": aws.BoolValue(dfcc.Enabled), | ||
"input_format_configuration": flattenFirehoseInputFormatConfiguration(dfcc.InputFormatConfiguration), | ||
"output_format_configuration": flattenFirehoseOutputFormatConfiguration(dfcc.OutputFormatConfiguration), | ||
"schema_configuration": flattenFirehoseSchemaConfiguration(dfcc.SchemaConfiguration), | ||
"enabled": enabled, | ||
"input_format_configuration": ifc, | ||
"output_format_configuration": ofc, | ||
"schema_configuration": sc, | ||
} | ||
|
||
return []map[string]interface{}{m} | ||
|
@@ -531,6 +545,16 @@ func flattenProcessingConfiguration(pc *firehose.ProcessingConfiguration, roleAr | |
return []map[string]interface{}{} | ||
} | ||
|
||
enabled := aws.BoolValue(pc.Enabled) | ||
|
||
// The AWS SDK can represent "no processing configuration" in two ways: | ||
// 1. With a nil value | ||
// 2. With an empty processor list and enabled set to false. | ||
// These are equivalent so we use the same state description, to avoid diffs. | ||
if !enabled && len(pc.Processors) == 0 { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Typically, if the configuration block contains a nested "enabled" or similar attribute that we appropriately handle the default case, we prefer to actually pass through the API response into the state as-is (e.g. 1 list item and enabled = false) and then introduce This change was good to revert back to how it was. If for some reason this does need to be changed, we should add a covering acceptance test to show the errant behavior in a future change request. 👍 |
||
return []map[string]interface{}{} | ||
} | ||
|
||
processingConfiguration := make([]map[string]interface{}, 1) | ||
|
||
// It is necessary to explicitly filter this out | ||
|
@@ -571,7 +595,7 @@ func flattenProcessingConfiguration(pc *firehose.ProcessingConfiguration, roleAr | |
} | ||
} | ||
processingConfiguration[0] = map[string]interface{}{ | ||
"enabled": aws.BoolValue(pc.Enabled), | ||
"enabled": enabled, | ||
"processors": processors, | ||
} | ||
return processingConfiguration | ||
|
@@ -1402,8 +1426,12 @@ func createExtendedS3Config(d *schema.ResourceData) *firehose.ExtendedS3Destinat | |
configuration.CloudWatchLoggingOptions = extractCloudWatchLoggingConfiguration(s3) | ||
} | ||
|
||
if v, ok := s3["error_output_prefix"]; ok && v.(string) != "" { | ||
if v, ok := s3["error_output_prefix"]; ok { | ||
configuration.ErrorOutputPrefix = aws.String(v.(string)) | ||
} else { | ||
// It is possible to just pass nil here, but this seems to be the | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We haven't found an AWS API that has required this additional logic so we would prefer to leave this in its original form. If there is some errant behavior with the original logic, let's add a covering acceptance test to show the errant behavior in a future change request. 👍 |
||
// canonical form that AWS uses, and is less likely to produce diffs. | ||
configuration.ErrorOutputPrefix = aws.String("") | ||
} | ||
|
||
if s3BackupMode, ok := s3["s3_backup_mode"]; ok { | ||
|
@@ -1487,8 +1515,12 @@ func updateExtendedS3Config(d *schema.ResourceData) *firehose.ExtendedS3Destinat | |
configuration.CloudWatchLoggingOptions = extractCloudWatchLoggingConfiguration(s3) | ||
} | ||
|
||
if v, ok := s3["error_output_prefix"]; ok && v.(string) != "" { | ||
if v, ok := s3["error_output_prefix"]; ok { | ||
configuration.ErrorOutputPrefix = aws.String(v.(string)) | ||
} else { | ||
// It is possible to just pass nil here, but this seems to be the | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here. 👍 |
||
// canonical form that AWS uses, and is less likely to produce diffs. | ||
configuration.ErrorOutputPrefix = aws.String("") | ||
} | ||
|
||
if s3BackupMode, ok := s3["s3_backup_mode"]; ok { | ||
|
@@ -1501,7 +1533,11 @@ func updateExtendedS3Config(d *schema.ResourceData) *firehose.ExtendedS3Destinat | |
|
||
func expandFirehoseDataFormatConversionConfiguration(l []interface{}) *firehose.DataFormatConversionConfiguration { | ||
if len(l) == 0 || l[0] == nil { | ||
return nil | ||
// It is possible to just pass nil here, but this seems to be the | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We typically do not need to normalize information when sending requests to the API. This doesn't appear to hurt anything here though, so will leave this in for now. |
||
// canonical form that AWS uses, and is less likely to produce diffs. | ||
return &firehose.DataFormatConversionConfiguration{ | ||
Enabled: aws.Bool(false), | ||
} | ||
} | ||
|
||
m := l[0].(map[string]interface{}) | ||
|
@@ -1676,7 +1712,12 @@ func expandFirehoseSchemaConfiguration(l []interface{}) *firehose.SchemaConfigur | |
func extractProcessingConfiguration(s3 map[string]interface{}) *firehose.ProcessingConfiguration { | ||
config := s3["processing_configuration"].([]interface{}) | ||
if len(config) == 0 { | ||
return nil | ||
// It is possible to just pass nil here, but this seems to be the | ||
// canonical form that AWS uses, and is less likely to produce diffs. | ||
return &firehose.ProcessingConfiguration{ | ||
Enabled: aws.Bool(false), | ||
Processors: []*firehose.Processor{}, | ||
} | ||
} | ||
|
||
processingConfiguration := config[0].(map[string]interface{}) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -339,6 +339,60 @@ func TestAccAWSKinesisFirehoseDeliveryStream_ExtendedS3_DataFormatConversionConf | |
}) | ||
} | ||
|
||
func TestAccAWSKinesisFirehoseDeliveryStream_ExtendedS3_ExternalUpdate(t *testing.T) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thank you very much for adding this acceptance test! 💯 |
||
var stream firehose.DeliveryStreamDescription | ||
rInt := acctest.RandInt() | ||
rName := acctest.RandomWithPrefix("tf-acc-test") | ||
resourceName := "aws_kinesis_firehose_delivery_stream.test" | ||
|
||
resource.ParallelTest(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
Providers: testAccProviders, | ||
CheckDestroy: testAccCheckKinesisFirehoseDeliveryStreamDestroy_ExtendedS3, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccKinesisFirehoseDeliveryStreamConfig_ExtendedS3_ExternalUpdate(rName, rInt), | ||
Check: resource.ComposeTestCheckFunc( | ||
testAccCheckKinesisFirehoseDeliveryStreamExists(resourceName, &stream), | ||
resource.TestCheckResourceAttr(resourceName, "extended_s3_configuration.#", "1"), | ||
resource.TestCheckResourceAttr(resourceName, "extended_s3_configuration.0.data_format_conversion_configuration.#", "0"), | ||
resource.TestCheckResourceAttr(resourceName, "extended_s3_configuration.0.processing_configuration.#", "0"), | ||
), | ||
}, | ||
{ | ||
PreConfig: func() { | ||
conn := testAccProvider.Meta().(*AWSClient).firehoseconn | ||
udi := firehose.UpdateDestinationInput{ | ||
DeliveryStreamName: aws.String(rName), | ||
DestinationId: aws.String("destinationId-000000000001"), | ||
CurrentDeliveryStreamVersionId: aws.String("1"), | ||
ExtendedS3DestinationUpdate: &firehose.ExtendedS3DestinationUpdate{ | ||
DataFormatConversionConfiguration: &firehose.DataFormatConversionConfiguration{ | ||
Enabled: aws.Bool(false), | ||
}, | ||
ProcessingConfiguration: &firehose.ProcessingConfiguration{ | ||
Enabled: aws.Bool(false), | ||
Processors: []*firehose.Processor{}, | ||
}, | ||
}, | ||
} | ||
_, err := conn.UpdateDestination(&udi) | ||
if err != nil { | ||
t.Fatalf("Unable to update firehose destination: %s", err) | ||
} | ||
}, | ||
Config: testAccKinesisFirehoseDeliveryStreamConfig_ExtendedS3_ExternalUpdate(rName, rInt), | ||
Check: resource.ComposeTestCheckFunc( | ||
testAccCheckKinesisFirehoseDeliveryStreamExists(resourceName, &stream), | ||
resource.TestCheckResourceAttr(resourceName, "extended_s3_configuration.#", "1"), | ||
resource.TestCheckResourceAttr(resourceName, "extended_s3_configuration.0.data_format_conversion_configuration.#", "0"), | ||
resource.TestCheckResourceAttr(resourceName, "extended_s3_configuration.0.processing_configuration.#", "0"), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func TestAccAWSKinesisFirehoseDeliveryStream_ExtendedS3_DataFormatConversionConfiguration_Deserializer_Update(t *testing.T) { | ||
var stream firehose.DeliveryStreamDescription | ||
rInt := acctest.RandInt() | ||
|
@@ -1640,6 +1694,20 @@ resource "aws_kinesis_firehose_delivery_stream" "test" { | |
`, rName, rName, rName) | ||
} | ||
|
||
func testAccKinesisFirehoseDeliveryStreamConfig_ExtendedS3_ExternalUpdate(rName string, rInt int) string { | ||
return fmt.Sprintf(testAccKinesisFirehoseDeliveryStreamBaseConfig, rInt, rInt, rInt) + fmt.Sprintf(` | ||
resource "aws_kinesis_firehose_delivery_stream" "test" { | ||
destination = "extended_s3" | ||
name = "%s" | ||
|
||
extended_s3_configuration { | ||
bucket_arn = "${aws_s3_bucket.bucket.arn}" | ||
role_arn = "${aws_iam_role.firehose.arn}" | ||
} | ||
} | ||
`, rName) | ||
} | ||
|
||
func testAccKinesisFirehoseDeliveryStreamConfig_ExtendedS3_DataFormatConversionConfiguration_OpenXJsonSerDe_Empty(rName string, rInt int) string { | ||
return fmt.Sprintf(testAccKinesisFirehoseDeliveryStreamBaseConfig, rInt, rInt, rInt) + fmt.Sprintf(` | ||
resource "aws_glue_catalog_database" "test" { | ||
|
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.
After various testing and investigation, even though we prefer to not introduce logic like this since it changes the behavior of the configuration when its returned from the API, this seems to be one of the few options we have for now since the configuration block
enabled
attribute hasDefault: true
. 👍