From 6fa0946571efac027a506da4340949816b1b89fa Mon Sep 17 00:00:00 2001 From: Jake Champlin Date: Wed, 8 Feb 2017 21:30:30 -0500 Subject: [PATCH] provider/aws: Fix AWS Security Group Rule Timeout An AWS Security Group Rule requires at least one of `cidr_blocks`, `self`, or `source_security_group_id` in order to be successfully created. If the `aws_security_group_rule` doesn't contain one of these attributes, the AWS API will still return a `200` response, and not report any error in the response. Example response from the API on a malformed submission: ``` 2017/02/08 16:04:33 [DEBUG] plugin: terraform: ----------------------------------------------------- 2017/02/08 16:04:33 [DEBUG] plugin: terraform: aws-provider (internal) 2017/02/08 16:04:33 [DEBUG] [aws-sdk-go] DEBUG: Response ec2/AuthorizeSecurityGroupIngress Details: 2017/02/08 16:04:33 [DEBUG] plugin: terraform: ---[ RESPONSE ]-------------------------------------- 2017/02/08 16:04:33 [DEBUG] plugin: terraform: HTTP/1.1 200 OK 2017/02/08 16:04:33 [DEBUG] plugin: terraform: Connection: close 2017/02/08 16:04:33 [DEBUG] plugin: terraform: Transfer-Encoding: chunked 2017/02/08 16:04:33 [DEBUG] plugin: terraform: Content-Type: text/xml;charset=UTF-8 2017/02/08 16:04:33 [DEBUG] plugin: terraform: Date: Wed, 08 Feb 2017 21:04:33 GMT 2017/02/08 16:04:33 [DEBUG] plugin: terraform: Server: AmazonEC2 2017/02/08 16:04:33 [DEBUG] plugin: terraform: Vary: Accept-Encoding 2017/02/08 16:04:33 [DEBUG] plugin: terraform: 2017/02/08 16:04:33 [DEBUG] plugin: terraform: 102 2017/02/08 16:04:33 [DEBUG] plugin: terraform: 2017/02/08 16:04:33 [DEBUG] plugin: terraform: 2017/02/08 16:04:33 [DEBUG] plugin: terraform: ac08c33f-8043-46d4-b637-4c4b2fc7a094 2017/02/08 16:04:33 [DEBUG] plugin: terraform: true 2017/02/08 16:04:33 [DEBUG] plugin: terraform: 2017/02/08 16:04:33 [DEBUG] plugin: terraform: 0 2017/02/08 16:04:33 [DEBUG] plugin: terraform: 2017/02/08 16:04:33 [DEBUG] plugin: terraform: 2017/02/08 16:04:33 [DEBUG] plugin: terraform: ----------------------------------------------------- ``` This previously caused Terraform to wait until the security_group_rule propagated, which never happened due to the silent failure. The changeset ensures that one of the required attributes are set prior to creating the aws_security_group_rule. Also catches the error returned from the retry function. Previously the error was ignored, and only logged at the `DEBUG` level. --- .../aws/resource_aws_security_group_rule.go | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/builtin/providers/aws/resource_aws_security_group_rule.go b/builtin/providers/aws/resource_aws_security_group_rule.go index 7a7034f98528..e1de498030c2 100644 --- a/builtin/providers/aws/resource_aws_security_group_rule.go +++ b/builtin/providers/aws/resource_aws_security_group_rule.go @@ -110,6 +110,14 @@ func resourceAwsSecurityGroupRuleCreate(d *schema.ResourceData, meta interface{} return err } + // Verify that either 'cidr_blocks', 'self', or 'source_security_group_id' is set + // If they are not set the AWS API will silently fail. This causes TF to hit a timeout + // at 5-minutes waiting for the security group rule to appear, when it was never actually + // created. + if err := validateAwsSecurityGroupRule(d); err != nil { + return err + } + ruleType := d.Get("type").(string) isVPC := sg.VpcId != nil && *sg.VpcId != "" @@ -194,9 +202,8 @@ information and instructions for recovery. Error message: %s`, sg_id, awsErr.Mes }) if retErr != nil { - log.Printf("[DEBUG] Error finding matching %s Security Group Rule (%s) for Group %s -- NO STATE WILL BE SAVED", + return fmt.Errorf("Error finding matching %s Security Group Rule (%s) for Group %s", ruleType, id, sg_id) - return nil } d.SetId(id) @@ -595,3 +602,15 @@ func setFromIPPerm(d *schema.ResourceData, sg *ec2.SecurityGroup, rule *ec2.IpPe return nil } + +// Validates that either 'cidr_blocks', 'self', or 'source_security_group_id' is set +func validateAwsSecurityGroupRule(d *schema.ResourceData) error { + _, blocksOk := d.GetOk("cidr_blocks") + _, sourceOk := d.GetOk("source_security_group_id") + _, selfOk := d.GetOk("self") + if !blocksOk && !sourceOk && !selfOk { + return fmt.Errorf( + "One of ['cidr_blocks', 'self', 'source_security_group_id'] must be set to create an AWS Security Group Rule") + } + return nil +}