Skip to content

Commit f45dff2

Browse files
matheusaleixo-citamanMahendroo
authored andcommitted
Fixed preconfigured_waf_config permadiff causing rules being recreated (GoogleCloudPlatform#11946)
1 parent c6104e0 commit f45dff2

File tree

3 files changed

+75
-22
lines changed

3 files changed

+75
-22
lines changed

mmv1/third_party/terraform/services/compute/resource_compute_security_policy.go.tmpl

+33-17
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import (
44
"context"
55
"fmt"
66
"log"
7+
"reflect"
78
"strings"
8-
99
"time"
1010

1111
"github.com/hashicorp/errwrap"
@@ -24,6 +24,16 @@ import (
2424
{{- end }}
2525
)
2626

27+
// IsEmptyValue does not consider a empty PreconfiguredWafConfig object as empty so we check it's nested values
28+
func preconfiguredWafConfigIsEmptyValue(config *compute.SecurityPolicyRulePreconfiguredWafConfig) bool {
29+
if (tpgresource.IsEmptyValue(reflect.ValueOf(config.Exclusions)) &&
30+
tpgresource.IsEmptyValue(reflect.ValueOf(config.ForceSendFields)) &&
31+
tpgresource.IsEmptyValue(reflect.ValueOf(config.NullFields))) {
32+
return true
33+
}
34+
return false
35+
}
36+
2737
func ResourceComputeSecurityPolicy() *schema.Resource {
2838
return &schema.Resource{
2939
Create: resourceComputeSecurityPolicyCreate,
@@ -198,7 +208,6 @@ func ResourceComputeSecurityPolicy() *schema.Resource {
198208
Description: `A match condition that incoming traffic is evaluated against. If it evaluates to true, the corresponding action is enforced.`,
199209
},
200210

201-
{{ if ne $.TargetVersionName `ga` -}}
202211
"preconfigured_waf_config": {
203212
Type: schema.TypeList,
204213
Optional: true,
@@ -246,7 +255,6 @@ func ResourceComputeSecurityPolicy() *schema.Resource {
246255
},
247256
Description: `Preconfigured WAF configuration to be applied for the rule. If the rule does not evaluate preconfigured WAF rules, i.e., if evaluatePreconfiguredWaf() is not used, this field will have no effect.`,
248257
},
249-
{{- end }}
250258

251259
"description": {
252260
Type: schema.TypeString,
@@ -597,7 +605,6 @@ func ResourceComputeSecurityPolicy() *schema.Resource {
597605
}
598606
}
599607

600-
{{ if ne $.TargetVersionName `ga` -}}
601608
func resourceComputeSecurityPolicyRulePreconfiguredWafConfigExclusionFieldParamsSchema(description string) *schema.Schema {
602609
return &schema.Schema{
603610
Type: schema.TypeList,
@@ -620,7 +627,6 @@ func resourceComputeSecurityPolicyRulePreconfiguredWafConfigExclusionFieldParams
620627
Description: description,
621628
}
622629
}
623-
{{- end }}
624630

625631
func rulesCustomizeDiff(_ context.Context, diff *schema.ResourceDiff, _ interface{}) error {
626632
_, n := diff.GetChange("rule")
@@ -730,7 +736,7 @@ func resourceComputeSecurityPolicyRead(d *schema.ResourceData, meta interface{})
730736
if err := d.Set("type", securityPolicy.Type); err != nil {
731737
return fmt.Errorf("Error setting type: %s", err)
732738
}
733-
if err := d.Set("rule", flattenSecurityPolicyRules(securityPolicy.Rules)); err != nil {
739+
if err := d.Set("rule", flattenSecurityPolicyRules(securityPolicy.Rules, d)); err != nil {
734740
return err
735741
}
736742
if err := d.Set("fingerprint", securityPolicy.Fingerprint); err != nil {
@@ -1042,9 +1048,7 @@ func expandSecurityPolicyRule(raw interface{}) *compute.SecurityPolicyRule {
10421048
Action: data["action"].(string),
10431049
Preview: data["preview"].(bool),
10441050
Match: expandSecurityPolicyMatch(data["match"].([]interface{})),
1045-
{{- if ne $.TargetVersionName "ga" }}
10461051
PreconfiguredWafConfig: expandSecurityPolicyPreconfiguredWafConfig(data["preconfigured_waf_config"].([]interface{})),
1047-
{{- end }}
10481052
RateLimitOptions: expandSecurityPolicyRuleRateLimitOptions(data["rate_limit_options"].([]interface{})),
10491053
RedirectOptions: expandSecurityPolicyRuleRedirectOptions(data["redirect_options"].([]interface{})),
10501054
HeaderAction: expandSecurityPolicyRuleHeaderAction(data["header_action"].([]interface{})),
@@ -1128,7 +1132,6 @@ func expandSecurityPolicyMatchExprOptionsRecaptchaOptions(recaptchaOptions []int
11281132
}
11291133
}
11301134

1131-
{{ if ne $.TargetVersionName `ga` -}}
11321135
func expandSecurityPolicyPreconfiguredWafConfig(configured []interface{}) *compute.SecurityPolicyRulePreconfiguredWafConfig {
11331136
if len(configured) == 0 || configured[0] == nil {
11341137
return nil
@@ -1175,9 +1178,8 @@ func expandSecurityPolicyRulePreconfiguredWafConfigExclusionFieldParam(raw inter
11751178
Val: data["value"].(string),
11761179
}
11771180
}
1178-
{{- end }}
11791181

1180-
func flattenSecurityPolicyRules(rules []*compute.SecurityPolicyRule) []map[string]interface{} {
1182+
func flattenSecurityPolicyRules(rules []*compute.SecurityPolicyRule, d *schema.ResourceData) []map[string]interface{} {
11811183
rulesSchema := make([]map[string]interface{}, 0, len(rules))
11821184
for _, rule := range rules {
11831185
data := map[string]interface{}{
@@ -1186,9 +1188,7 @@ func flattenSecurityPolicyRules(rules []*compute.SecurityPolicyRule) []map[strin
11861188
"action": rule.Action,
11871189
"preview": rule.Preview,
11881190
"match": flattenMatch(rule.Match),
1189-
{{- if ne $.TargetVersionName "ga" }}
1190-
"preconfigured_waf_config": flattenPreconfiguredWafConfig(rule.PreconfiguredWafConfig),
1191-
{{- end }}
1191+
"preconfigured_waf_config": flattenPreconfiguredWafConfig(rule.PreconfiguredWafConfig, d, int(rule.Priority)),
11921192
"rate_limit_options": flattenSecurityPolicyRuleRateLimitOptions(rule.RateLimitOptions),
11931193
"redirect_options": flattenSecurityPolicyRedirectOptions(rule.RedirectOptions),
11941194
"header_action": flattenSecurityPolicyRuleHeaderAction(rule.HeaderAction),
@@ -1266,12 +1266,29 @@ func flattenMatchExpr(match *compute.SecurityPolicyRuleMatcher) []map[string]int
12661266
return []map[string]interface{}{data}
12671267
}
12681268

1269-
{{ if ne $.TargetVersionName `ga` -}}
1270-
func flattenPreconfiguredWafConfig(config *compute.SecurityPolicyRulePreconfiguredWafConfig) []map[string]interface{} {
1269+
func flattenPreconfiguredWafConfig(config *compute.SecurityPolicyRulePreconfiguredWafConfig, d *schema.ResourceData, rulePriority int) []map[string]interface{} {
12711270
if config == nil {
12721271
return nil
12731272
}
12741273

1274+
// We find the current value for this field in the config and check if its empty, then check if the API is returning a empty non-null value
1275+
if schemaRules, ok := d.GetOk("rule"); ok {
1276+
for _, itemRaw := range schemaRules.(*schema.Set).List() {
1277+
if itemRaw == nil {
1278+
continue
1279+
}
1280+
item := itemRaw.(map[string]interface{})
1281+
1282+
schemaPriority := item["priority"].(int)
1283+
if rulePriority == schemaPriority {
1284+
if preconfiguredWafConfigIsEmptyValue(config) && tpgresource.IsEmptyValue(reflect.ValueOf(item["preconfigured_waf_config"])) {
1285+
return nil
1286+
}
1287+
break
1288+
}
1289+
}
1290+
}
1291+
12751292
data := map[string]interface{}{
12761293
"exclusion": flattenPreconfiguredWafConfigExclusions(config.Exclusions),
12771294
}
@@ -1307,7 +1324,6 @@ func flattenPreconfiguredWafConfigExclusionField(fieldParams []*compute.Security
13071324
}
13081325
return fieldSchema
13091326
}
1310-
{{- end }}
13111327

13121328
func expandSecurityPolicyAdvancedOptionsConfig(configured []interface{}) *compute.SecurityPolicyAdvancedOptionsConfig {
13131329
if len(configured) == 0 || configured[0] == nil {

mmv1/third_party/terraform/services/compute/resource_compute_security_policy_test.go.tmpl

+41-4
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,6 @@ func TestAccComputeSecurityPolicy_withRuleExpr(t *testing.T) {
7777
})
7878
}
7979

80-
{{ if ne $.TargetVersionName `ga` -}}
8180
func TestAccComputeSecurityPolicy_withPreconfiguredWafConfig(t *testing.T) {
8281
t.Parallel()
8382

@@ -112,10 +111,18 @@ func TestAccComputeSecurityPolicy_withPreconfiguredWafConfig(t *testing.T) {
112111
ImportState: true,
113112
ImportStateVerify: true,
114113
},
114+
{
115+
Config: testAccComputeSecurityPolicy_withPreconfiguredWafConfig_removed(spName),
116+
},
117+
{
118+
ResourceName: "google_compute_security_policy.policy",
119+
ImportState: true,
120+
ImportStateVerify: true,
121+
ImportStateVerifyIgnore: []string{"rule.1.preconfigured_waf_config.#", "rule.1.preconfigured_waf_config.0.%"}, // API will still return a empty object
122+
},
115123
},
116124
})
117125
}
118-
{{- end }}
119126

120127
func TestAccComputeSecurityPolicy_update(t *testing.T) {
121128
t.Parallel()
@@ -991,7 +998,6 @@ resource "google_compute_security_policy" "policy" {
991998
`, spName)
992999
}
9931000

994-
{{ if ne $.TargetVersionName `ga` -}}
9951001
func testAccComputeSecurityPolicy_withPreconfiguredWafConfig(spName string) string {
9961002
return fmt.Sprintf(`
9971003
resource "google_compute_security_policy" "policy" {
@@ -1150,7 +1156,38 @@ resource "google_compute_security_policy" "policy" {
11501156
}
11511157
`, spName)
11521158
}
1153-
{{- end }}
1159+
1160+
func testAccComputeSecurityPolicy_withPreconfiguredWafConfig_removed(spName string) string {
1161+
return fmt.Sprintf(`
1162+
resource "google_compute_security_policy" "policy" {
1163+
name = "%s"
1164+
1165+
rule {
1166+
action = "allow"
1167+
priority = "2147483647"
1168+
match {
1169+
versioned_expr = "SRC_IPS_V1"
1170+
config {
1171+
src_ip_ranges = ["*"]
1172+
}
1173+
}
1174+
description = "default rule"
1175+
}
1176+
1177+
rule {
1178+
action = "deny"
1179+
priority = "1000"
1180+
match {
1181+
expr {
1182+
expression = "evaluatePreconfiguredWaf('rce-stable') || evaluatePreconfiguredWaf('xss-stable')"
1183+
}
1184+
}
1185+
// remove waf config field to test if last step wont cause a permadiff //
1186+
preview = false
1187+
}
1188+
}
1189+
`, spName)
1190+
}
11541191

11551192
func testAccComputeSecurityPolicy_withoutHeadAction(spName string) string {
11561193
return fmt.Sprintf(`

mmv1/third_party/terraform/website/docs/r/compute_security_policy.html.markdown

+1-1
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ The following arguments are supported:
229229
* `match` - (Required) A match condition that incoming traffic is evaluated against.
230230
If it evaluates to true, the corresponding `action` is enforced. Structure is [documented below](#nested_match).
231231

232-
* `preconfigured_waf_config` - (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html)) Preconfigured WAF configuration to be applied for the rule. If the rule does not evaluate preconfigured WAF rules, i.e., if `evaluatePreconfiguredWaf()` is not used, this field will have no effect. Structure is [documented below](#nested_preconfigured_waf_config).
232+
* `preconfigured_waf_config` - (Optional) Preconfigured WAF configuration to be applied for the rule. If the rule does not evaluate preconfigured WAF rules, i.e., if `evaluatePreconfiguredWaf()` is not used, this field will have no effect. Structure is [documented below](#nested_preconfigured_waf_config).
233233

234234
* `description` - (Optional) An optional description of this rule. Max size is 64.
235235

0 commit comments

Comments
 (0)