-
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
resource/aws_security_group_rule: Prevent sg rule recreation when source_security_group_id has accountId prefix #11809
Conversation
…ource sg id is specified with account id prefix
Is there an easy way for someone to plug this update into a stack for testing? I have only used upstream/stable/released versions of Terraform and it's providers, but I'd be happy to assist with testing if that's useful. |
What you can do, is make a local build of the provider using my branch and place it in your local terraform plugins directory at Instructions for making a local build is here: https://github.com/terraform-providers/terraform-provider-aws#developing-the-provider Note: If you're not running the latest version of the provider, you may want to just cherry pick my changes and apply them on top of the version of the provider you are using. |
Sorry to mention you @bflad - since I saw you participated in the referenced issues - would it be possible for you to take a quick look at this PR and share what you think? Hopefully this is small enough such that it doesn't take too much of your time We've been experiencing slight downtime each time we apply Terraform because of this issue and am hoping in the next provider release that it can be addressed. |
@@ -759,7 +759,19 @@ func setFromIPPerm(d *schema.ResourceData, sg *ec2.SecurityGroup, rule *ec2.IpPe | |||
s := rule.UserIdGroupPairs[0] | |||
|
|||
if isVPC { | |||
d.Set("source_security_group_id", s.GroupId) | |||
if existingSourceSgId, ok := d.GetOk("source_security_group_id"); 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.
looks good 👍
as an alternative, I believe you could even use the value of the s.UserId
to handle the if/else as it'll be an empty string for security groups not tied to a specific accountId prefix
if existingSourceSgId, ok := d.GetOk("source_security_group_id"); ok { | |
if userId := aws.StringValue(s.UserId); len(userId) > 0 { | |
d.Set("source_security_group_id", fmt.Sprintf("%s/%s", userId, aws.StringValue(s.GroupId))) | |
} else { | |
d.Set("source_security_group_id", s.GroupId) | |
} |
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 the review!
as it'll be an empty string for security groups not tied to a specific accountId prefix
I believe that is not true. I believe s.UserId
always has a value defined as the AWS API always returns a value for it whether or not we have a accoundId prefix in the source_security_group_id
string
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.
😅 Using d.Get()
or d.GetOk()
to influence d.Set()
calls is generally discouraged since there are different semantics between resources created versus imported, however in this case, we don't have any options other than maybe #4454 (a DiffSuppressFunc
) since the API seems to be very ambiguous about how it requires canonicalization. I'm hesitantly thinking this change to base the decision of d.Set()
value is fine in principle since it should keep the existing resource behavior for previous configurations.
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.
hi @ktham, thank you for this PR and apologies for the wait!
the changes LGTM, only a small suggestion 👍
Output of acceptance tests:
--- PASS: TestAccAWSSecurityGroup_*
--- PASS: TestIpPermissionIDHash*
--- PASS: TestAccAWSSecurityGroupRule*
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 submitting this, @ktham 👍 Please see the below and reach out with any questions.
@@ -759,7 +759,19 @@ func setFromIPPerm(d *schema.ResourceData, sg *ec2.SecurityGroup, rule *ec2.IpPe | |||
s := rule.UserIdGroupPairs[0] | |||
|
|||
if isVPC { | |||
d.Set("source_security_group_id", s.GroupId) | |||
if existingSourceSgId, ok := d.GetOk("source_security_group_id"); 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.
😅 Using d.Get()
or d.GetOk()
to influence d.Set()
calls is generally discouraged since there are different semantics between resources created versus imported, however in this case, we don't have any options other than maybe #4454 (a DiffSuppressFunc
) since the API seems to be very ambiguous about how it requires canonicalization. I'm hesitantly thinking this change to base the decision of d.Set()
value is fine in principle since it should keep the existing resource behavior for previous configurations.
|
||
if hasAccountIdPrefix { | ||
// then ensure on refresh that we prefix the account id | ||
d.Set("source_security_group_id", *s.UserId+"/"+*s.GroupId) |
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 prevent potential panics (as recommended above), we should use the AWS Go SDK conversion functions, in case the new requirement of s.UserId
does happen to be nil
in some environments:
d.Set("source_security_group_id", *s.UserId+"/"+*s.GroupId) | |
d.Set("source_security_group_id", fmt.Sprintf("%s/%s", aws.StringValue(s.UserId), aws.StringValue(s.GroupId)) |
Or the conditional above should check && s.UserId != nil
// Ensure plan shows no difference after state is refreshed | ||
{ | ||
Config: testAccAWSSecurityGroupRule_Ingress_Source_with_AccountId(rInt), | ||
PlanOnly: true, | ||
ExpectNonEmptyPlan: 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.
This is extraneous as the acceptance testing framework automatically checks a refresh plan for differences after applying a Config
👍
// Ensure plan shows no difference after state is refreshed | |
{ | |
Config: testAccAWSSecurityGroupRule_Ingress_Source_with_AccountId(rInt), | |
PlanOnly: true, | |
ExpectNonEmptyPlan: false, | |
}, |
Thanks @bflad ! I've updated the PR |
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.
Let's give this a go -- thank you @ktham for submitting this and @anGie44 for the initial review!
Output from acceptance testing:
--- PASS: TestAccAWSSecurityGroupRule_Description_AllPorts (30.64s)
--- PASS: TestAccAWSSecurityGroupRule_Description_AllPorts_NonZeroPorts (27.59s)
--- PASS: TestAccAWSSecurityGroupRule_Egress (26.17s)
--- PASS: TestAccAWSSecurityGroupRule_EgressDescription (20.02s)
--- PASS: TestAccAWSSecurityGroupRule_EgressDescription_updates (40.24s)
--- PASS: TestAccAWSSecurityGroupRule_ExpectInvalidCIDR (5.11s)
--- PASS: TestAccAWSSecurityGroupRule_ExpectInvalidTypeError (3.78s)
--- PASS: TestAccAWSSecurityGroupRule_Ingress_Classic (23.37s)
--- PASS: TestAccAWSSecurityGroupRule_Ingress_Ipv6 (45.69s)
--- PASS: TestAccAWSSecurityGroupRule_Ingress_Protocol (40.01s)
--- PASS: TestAccAWSSecurityGroupRule_Ingress_Source_With_Account_Id (32.57s)
--- PASS: TestAccAWSSecurityGroupRule_Ingress_VPC (19.53s)
--- PASS: TestAccAWSSecurityGroupRule_IngressDescription (19.74s)
--- PASS: TestAccAWSSecurityGroupRule_IngressDescription_updates (53.31s)
--- PASS: TestAccAWSSecurityGroupRule_Issue5310 (35.05s)
--- PASS: TestAccAWSSecurityGroupRule_MultiDescription (48.81s)
--- PASS: TestAccAWSSecurityGroupRule_MultiIngress (39.92s)
--- PASS: TestAccAWSSecurityGroupRule_MultipleRuleSearching_AllProtocolCrash (16.15s)
--- PASS: TestAccAWSSecurityGroupRule_PartialMatching_basic (39.64s)
--- PASS: TestAccAWSSecurityGroupRule_PartialMatching_Source (29.01s)
--- PASS: TestAccAWSSecurityGroupRule_PrefixListEgress (58.93s)
--- PASS: TestAccAWSSecurityGroupRule_Race (98.35s)
--- PASS: TestAccAWSSecurityGroupRule_SelfReference (36.32s)
--- PASS: TestAccAWSSecurityGroupRule_SelfSource (35.30s)
This has been released in version 2.62.0 of the Terraform AWS provider. Please see the Terraform documentation on provider versioning or reach out if you need any assistance upgrading. For further feature requests or bug reports with this functionality, please create a new GitHub issue following the template for triage. Thanks! |
Hi @ktham , I'm using version 2.65 of the AWS provider and the issue still present.
|
Hi @jnonino , is that problem still repeatedly happening for you? Do note, that, right after upgrading to the provider version that contains the fix, depending on what your workaround beforehand was (e.g. if you had a lifecycle ignore rule on |
Thanks, I applied the change and seems the state was updated and it working as expected now. Thanks |
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! |
Community Note
Closes #159 and #141
Release note for CHANGELOG:
Output from acceptance testing (with code change):
Output from acceptance test prior to code change, which reproduces #159/#141 (account id is redacted in the output):