-
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
r/aws_api_gateway_stage: implement access logging #4369
Conversation
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.
Looking good @appilon! Left some comments below -- please let me know if you have any questions 😄
@@ -177,6 +202,8 @@ func resourceAwsApiGatewayStageRead(d *schema.ResourceData, meta interface{}) er | |||
} | |||
log.Printf("[DEBUG] Received API Gateway Stage: %s", stage) | |||
|
|||
d.Set("access_log_settings", flattenApiGatewayStageAccessLogSettings(stage.AccessLogSettings)) |
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 do error checking when setting non-scalar attributes 👍 e.g.
if err := d.Set("access_log_settings", flattenApiGatewayStageAccessLogSettings(stage.AccessLogSettings)); err != nil {
return fmt.Errorf("error setting access_log_settings: %s", err)
}
Config: testAccAWSAPIGatewayStageConfig_basic(rName), | ||
Check: resource.ComposeTestCheckFunc( | ||
testAccCheckAWSAPIGatewayStageExists("aws_api_gateway_stage.test", &conf), | ||
testAccCheckAWSAPIGatewayStageAccessLogSettingsIsNil(&conf), |
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.
You can combine both this check and the below with resource.TestCheckResourceAttr("aws_api_gateway_stage.test", "access_logs_settings.#", "0")
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.
because my flattener returns nil
if the sdk struct is nil
, access_logs_settings.#
doesn't even exist in the state, should I just check that access_logs_settings
is not set? Alternatively I could change my flattener to return an empty array. It boils down to what do we prefer for the 'zero' value on a nested block, nil
or empty []interface{}
?
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 tend to lean towards returning empy list/set/map so it explicitly gets set as a zero value in the state. I believe the reasoning is that it helps with writing conditionals like ${length(aws_api_gateway_stage.example.access_log_settings)}
(where if its not set it'll return an error about the attribute not existing instead of returning 0).
Providers: testAccProviders, | ||
CheckDestroy: testAccCheckAWSAPIGatewayStageDestroy, | ||
Steps: []resource.TestStep{ | ||
resource.TestStep{ |
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.
Minor nitpick: The resource.TestStep
declarations here are extraneous as its already defined by []resource.TestStep{
above
Check: resource.ComposeTestCheckFunc( | ||
testAccCheckAWSAPIGatewayStageExists("aws_api_gateway_stage.test", &conf), | ||
resource.TestCheckResourceAttr("aws_api_gateway_stage.test", "access_log_settings.#", "1"), | ||
testAccCheckAWSAPIGatewayStageAccessLogSettingsDestinationArnIsValid("aws_api_gateway_stage.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.
Something for consideration instead of writing a new function:
resource.TestMatchResourceAttr("aws_api_gateway_stage.test", "access_log_settings.0.destination_arn", regexp.MustCompile(fmt.Sprintf("^arn:[^:]+:logs:[^:]+:[^:]+:foo-bar-%s$", rName))),
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.
your regex skills are lit 🔥
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.
sadly that rule didn't work I was inspired by you though and tweaked it let me know if you think it's robust enough.
logGroupArnRegex := regexp.MustCompile(fmt.Sprintf("^(arn:aws:logs:)(.*)(log-group:foo-bar-%s)$", rName))
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.
Looks like it just needed log-group:
before foo-bar-%s
:
resource.TestMatchResourceAttr("aws_api_gateway_stage.test", "access_log_settings.0.destination_arn", regexp.MustCompile(fmt.Sprintf("^arn:[^:]+:logs:[^:]+:[^:]+:log-group:foo-bar-%s$", rName))),
Whatever you think is best. I try to avoid wildcards.
I will say we should to try to not hardcode arn:aws
at the beginning because at some point these tests will be running in US GovCloud (aws-us-gov
) and maybe China partitions (aws-cn
).
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 does bring up a valid point that maybe we should have a simple ARN matching TestCheckFunc
instead of handcrafting these.
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.
👍 to arn matcher and to your points on harcoded arn:aws
I didn't even think of that!
@@ -69,6 +69,7 @@ The following arguments are supported: | |||
* `rest_api_id` - (Required) The ID of the associated REST API | |||
* `stage_name` - (Required) The name of the stage | |||
* `deployment_id` - (Required) The ID of the deployment that the stage points to | |||
* `access_log_settings` - (Optional) enables access logs for the api stage |
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.
Should probably mention: ...API stage. Detailed below.
#### `access_log_settings` | ||
|
||
* `destination_arn` - (Required) ARN of the log group to send the logs to. | ||
~> **Note:** Referencing a log group arn from a Terraform resource will normally include a `:*` suffix which is not valid for the destination arn, Terraform automatically strips this suffix when configuring this argument. |
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 don't think we need this bold callout that makes it sound like Terraform is doing something wrong or this is Terraform specific behavior (as the ARN value with :*
coming from the CloudWatch API). I think a simple Automatically removes trailing `:*` if present.
in the line above would suffice. 👍
return nil | ||
} | ||
item := make(map[string]interface{}) | ||
if accessLogSettings.DestinationArn != nil { |
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.
Something to consider when working in the AWS provider is that the SDK provides helper functions so you don't need these wrapping nil
checks (in most cases anyways): item["destination_arn"] = aws.StringValue(accessLogSettings.DestinationArn)
@@ -276,6 +305,27 @@ func resourceAwsApiGatewayStageUpdate(d *schema.ResourceData, meta interface{}) | |||
newV := n.(map[string]interface{}) | |||
operations = append(operations, diffVariablesOps("/variables/", oldV, newV)...) | |||
} | |||
if d.HasChange("access_log_settings") { | |||
accessLogSettings := d.Get("access_log_settings").([]interface{}) |
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.
@bflad if the user deletes the nested block, is this code risky? My acceptance tests pass but I'm concerned len(accessLogSettings)
might gag... (I've admittedly never used much interface{}
or type casts until TF)
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.
As far as I know helper/schema.Schema
should return the appropriate Go type []interface{}
here with either 0 or 1 elements: https://godoc.org/github.com/hashicorp/terraform/helper/schema#Schema
add acceptance test with different accepted log formats make note of sanitization performed on destinatation_arn
@bflad I think I've addressed all the comments! |
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 looks great @appilon, thanks! 🚀
2 tests passed (all tests)
=== RUN TestAccAWSAPIGatewayStage_accessLogSettings
--- PASS: TestAccAWSAPIGatewayStage_accessLogSettings (392.52s)
=== RUN TestAccAWSAPIGatewayStage_basic
--- PASS: TestAccAWSAPIGatewayStage_basic (519.82s)
This has been released in version 1.17.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! |
Fix #2406
implement access logging for apigw stage
add acceptance test with different accepted log formats
make note of sanitization performed on destination_arn