Skip to content

Commit 5d42a91

Browse files
fix: string based ordering for google_compute_region_security_policy causes recreate after apply (#14093) (#23076)
[upstream:f55da64d5c5a549bb0da32e383922adb75d79fe7] Signed-off-by: Modular Magician <[email protected]>
1 parent 2bf981f commit 5d42a91

File tree

3 files changed

+149
-4
lines changed

3 files changed

+149
-4
lines changed

.changelog/14093.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:bug
2+
compute: fixed an issue where rules ordering in `google_compute_region_security_policy` caused a diff after apply
3+
```

google/services/compute/resource_compute_region_security_policy.go

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,35 @@ import (
3535
"github.com/hashicorp/terraform-provider-google/google/verify"
3636
)
3737

38+
func resourceComputeRegionSecurityPolicySpecRulesDiffSuppress(k, o, n string, d *schema.ResourceData) bool {
39+
oldCount, newCount := d.GetChange("rules.#")
40+
var count int
41+
// There could be duplicates - worth continuing even if the counts are unequal.
42+
if oldCount.(int) < newCount.(int) {
43+
count = newCount.(int)
44+
} else {
45+
count = oldCount.(int)
46+
}
47+
48+
old := make([]interface{}, 0, count)
49+
new := make([]interface{}, 0, count)
50+
for i := 0; i < count; i++ {
51+
o, n := d.GetChange(fmt.Sprintf("rules.%d", i))
52+
53+
if o != nil {
54+
old = append(old, o)
55+
}
56+
if n != nil {
57+
new = append(new, n)
58+
}
59+
}
60+
61+
oldSet := schema.NewSet(schema.HashResource(ResourceComputeRegionSecurityPolicy().Schema["rules"].Elem.(*schema.Resource)), old)
62+
newSet := schema.NewSet(schema.HashResource(ResourceComputeRegionSecurityPolicy().Schema["rules"].Elem.(*schema.Resource)), new)
63+
64+
return oldSet.Equal(newSet)
65+
}
66+
3867
func ResourceComputeRegionSecurityPolicy() *schema.Resource {
3968
return &schema.Resource{
4069
Create: resourceComputeRegionSecurityPolicyCreate,
@@ -98,10 +127,11 @@ Specifically, the name must be 1-63 characters long and match the regular expres
98127
If it is not provided, the provider region is used.`,
99128
},
100129
"rules": {
101-
Type: schema.TypeList,
102-
Computed: true,
103-
Optional: true,
104-
Description: `The set of rules that belong to this policy. There must always be a default rule (rule with priority 2147483647 and match "*"). If no rules are provided when creating a security policy, a default rule with action "allow" will be added.`,
130+
Type: schema.TypeList,
131+
Computed: true,
132+
Optional: true,
133+
DiffSuppressFunc: resourceComputeRegionSecurityPolicySpecRulesDiffSuppress,
134+
Description: `The set of rules that belong to this policy. There must always be a default rule (rule with priority 2147483647 and match "*"). If no rules are provided when creating a security policy, a default rule with action "allow" will be added.`,
105135
Elem: &schema.Resource{
106136
Schema: map[string]*schema.Schema{
107137
"action": {

google/services/compute/resource_compute_region_security_policy_test.go

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -734,3 +734,115 @@ func testAccComputeRegionSecurityPolicy_withMultipleEnforceOnKeyConfigs_update(c
734734
}
735735
`, context)
736736
}
737+
738+
func TestAccComputeRegionSecurityPolicy_regionSecurityPolicyRuleOrderingWithMultipleRules(t *testing.T) {
739+
t.Parallel()
740+
741+
context := map[string]interface{}{
742+
"random_suffix": acctest.RandString(t, 10),
743+
}
744+
745+
acctest.VcrTest(t, resource.TestCase{
746+
PreCheck: func() { acctest.AccTestPreCheck(t) },
747+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
748+
CheckDestroy: testAccCheckComputeRegionSecurityPolicyDestroyProducer(t),
749+
Steps: []resource.TestStep{
750+
{
751+
Config: testAccComputeRegionSecurityPolicy_ruleOrderingWithMultipleRules_create(context),
752+
},
753+
{
754+
ResourceName: "google_compute_region_security_policy.policy",
755+
ImportState: true,
756+
ImportStateVerify: true,
757+
},
758+
{
759+
Config: testAccComputeRegionSecurityPolicy_ruleOrderingWithMultipleRules_update(context),
760+
},
761+
{
762+
ResourceName: "google_compute_region_security_policy.policy",
763+
ImportState: true,
764+
ImportStateVerify: true,
765+
},
766+
},
767+
})
768+
}
769+
770+
func testAccComputeRegionSecurityPolicy_ruleOrderingWithMultipleRules_create(context map[string]interface{}) string {
771+
return acctest.Nprintf(`
772+
773+
resource "google_compute_region_security_policy" "policy" {
774+
name = "tf-test-ordering%{random_suffix}"
775+
description = "basic region security policy with multiple rules"
776+
type = "CLOUD_ARMOR"
777+
region = "us-central1"
778+
779+
rules {
780+
action = "deny"
781+
priority = "3000"
782+
match {
783+
expr {
784+
expression = "request.path.matches(\"/login.html\") && token.recaptcha_session.score < 0.2"
785+
}
786+
}
787+
}
788+
789+
rules {
790+
action = "deny"
791+
priority = "2147483647"
792+
match {
793+
versioned_expr = "SRC_IPS_V1"
794+
config {
795+
src_ip_ranges = ["*"]
796+
}
797+
}
798+
description = "default rule"
799+
}
800+
}
801+
802+
`, context)
803+
}
804+
805+
func testAccComputeRegionSecurityPolicy_ruleOrderingWithMultipleRules_update(context map[string]interface{}) string {
806+
return acctest.Nprintf(`
807+
808+
resource "google_compute_region_security_policy" "policy" {
809+
name = "tf-test-ordering%{random_suffix}"
810+
description = "basic region security policy with multiple rules, updated"
811+
type = "CLOUD_ARMOR"
812+
region = "us-central1"
813+
814+
rules {
815+
action = "allow"
816+
priority = "4000"
817+
match {
818+
expr {
819+
expression = "request.path.matches(\"/login.html\") && token.recaptcha_session.score < 0.2"
820+
}
821+
}
822+
}
823+
824+
rules {
825+
action = "allow"
826+
priority = "5000"
827+
match {
828+
expr {
829+
expression = "request.path.matches(\"/404.html\") && token.recaptcha_session.score > 0.4"
830+
}
831+
}
832+
description = "new rule"
833+
}
834+
835+
rules {
836+
action = "deny"
837+
priority = "2147483647"
838+
match {
839+
versioned_expr = "SRC_IPS_V1"
840+
config {
841+
src_ip_ranges = ["*"]
842+
}
843+
}
844+
description = "default rule"
845+
}
846+
}
847+
`, context)
848+
}

0 commit comments

Comments
 (0)