Skip to content

Commit af16540

Browse files
authored
Netapp all squash (#15436)
1 parent 8ffd15e commit af16540

File tree

5 files changed

+831
-893
lines changed

5 files changed

+831
-893
lines changed

mmv1/products/netapp/Volume.yaml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ async:
4848
resource_inside_response: false
4949
custom_code:
5050
pre_delete: 'templates/terraform/pre_delete/netapp_volume_force_delete.go.tmpl'
51-
pre_update: 'templates/terraform/pre_update/netapp_volume_custom_block_devices_update.tmpl'
51+
pre_update: 'templates/terraform/pre_update/netapp_volume_update.go.tmpl'
5252
constants: 'templates/terraform/constants/netapp_volume.go.tmpl'
5353
examples:
5454
- name: 'netapp_volume_basic'
@@ -152,6 +152,7 @@ properties:
152152
type: String
153153
description: |-
154154
If enabled, the root user (UID = 0) of the specified clients doesn't get mapped to nobody (UID = 65534). This is also known as no_root_squash.
155+
It's overwritten by the squash_mode parameter. Use either squash_mode or has_root_access.
155156
default_from_api: true
156157
- name: 'accessType'
157158
type: Enum
@@ -197,15 +198,17 @@ properties:
197198
type: Enum
198199
description: |-
199200
SquashMode defines how remote user privileges are restricted when accessing an NFS export. It controls how the user identities (like root) are mapped to anonymous users to limit access and enforce security.
201+
It overwrites the has_root_access parameter. Use either squash_mode or has_root_access. For ALL_SQUASH, access_type needs to be set to READ_WRITE.
200202
enum_values:
203+
- 'SQUASH_MODE_UNSPECIFIED'
201204
- 'NO_ROOT_SQUASH'
202205
- 'ROOT_SQUASH'
203206
- 'ALL_SQUASH'
204-
default_from_api: true
207+
diff_suppress_func: 'suppressSquashModeDiff'
205208
- name: 'anonUid'
206209
type: Integer
207210
description: |-
208-
An integer representing the anonymous user ID. Range is 0 to 4294967295. Required when `squash_mode` is `ROOT_SQUASH` or `ALL_SQUASH`.
211+
An integer representing the anonymous user ID. Range is 0 to 4294967295. Required when `squash_mode` is `ALL_SQUASH`.
209212
- name: 'protocols'
210213
type: Array
211214
description: |

mmv1/templates/terraform/constants/netapp_volume.go.tmpl

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,45 @@ func ProjectIDDiffSuppress(_, old, new string, _ *schema.ResourceData) bool {
1919

2020
// Compare the extracted suffixes.
2121
return suffix1 == suffix2
22-
}
22+
}
23+
24+
func suppressSquashModeDiff(k, old, new string, d *schema.ResourceData) bool {
25+
// k: The key of the field, e.g., "export_policy.0.rules.1.squash_mode"
26+
// old: The value in the state (what the API returned on last read)
27+
// new: The value in the configuration (what the user set)
28+
// d: The ResourceData for the entire resource
29+
30+
// 1. Only suppress if the user did NOT set squash_mode in the config.
31+
// According to the requirements, a "classic rule" is identified by the ABSENCE of squash_mode.
32+
if new == "ALL_SQUASH" {
33+
// If 'new' is not an empty string, the user has explicitly provided a value
34+
// for squash_mode in the Terraform configuration. In this scenario, any
35+
// difference between the API's value ('old') and the configured value ('new')
36+
// is a real change and should NOT be suppressed.
37+
return false
38+
}
39+
40+
if new == "" && old != "ALL_SQUASH" {
41+
return true
42+
}
43+
44+
// 2. The user did not specify squash_mode in the configuration ('new' is empty).
45+
// Now, we suppress the diff if the API/state value ('old') is one of the
46+
// specific values that should be treated as equivalent to an unset field.
47+
// These values are "NO_ROOT_SQUASH", "ROOT_SQUASH".
48+
switch old {
49+
case "NO_ROOT_SQUASH", "ROOT_SQUASH", "":
50+
// The API returned one of the values that we consider equivalent to the field
51+
// being unconfigured by the user. Since the user also didn't configure it,
52+
// we should suppress this diff.
53+
return true
54+
default:
55+
// If 'old' is not one of the values to be suppressed (and 'new' is empty),
56+
// we do not suppress the diff. This could happen if, for instance, the API
57+
// returned an unexpected value or if 'old' is also empty.
58+
return false
59+
}
60+
// Note: The previous logic involving parsing 'k' and checking 'has_root_access'
61+
// has been removed because squash_mode is independent of has_root_access,
62+
// and a "classic rule" is defined by the absence of squash_mode itself.
63+
}

mmv1/templates/terraform/pre_update/netapp_volume_custom_block_devices_update.tmpl

Lines changed: 0 additions & 24 deletions
This file was deleted.
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
// remove sizeGib and identifier from the update request for block_devices
2+
3+
if v, ok := d.GetOk("block_devices"); ok {
4+
5+
l := v.([]interface{})
6+
newBlockDevices := make([]interface{}, 0, len(l))
7+
8+
for _, item := range v.([]interface{}) {
9+
if item == nil { continue }
10+
blockDevice := item.(map[string]interface{})
11+
newblockDevice := make(map[string]interface{})
12+
13+
if val, exists := blockDevice["name"]; exists { newblockDevice["name"] = val }
14+
if val, exists := blockDevice["host_groups"]; exists { newblockDevice["host_groups"] = val }
15+
if val, exists := blockDevice["os_type"]; exists { newblockDevice["os_type"] = val }
16+
17+
newBlockDevices = append(newBlockDevices, newblockDevice)
18+
}
19+
20+
if len(newBlockDevices) > 0 {
21+
obj["blockDevices"] = newBlockDevices
22+
}
23+
}
24+
25+
// detect export_policy presence in TF config of volume
26+
27+
if v, ok := d.GetOk("export_policy"); ok {
28+
29+
l := v.([]interface{})
30+
newExportPolicy := make([]interface{}, 0, len(l))
31+
32+
for _, item := range v.([]interface{}) {
33+
if item == nil { continue }
34+
ruleSet := item.(map[string]interface{})
35+
36+
if ruleMap, ruleMapExists := ruleSet["rules"]; ruleMapExists {
37+
38+
l := ruleMap.([]interface{})
39+
newRuleMap := make([]interface{}, 0, len(l))
40+
for _, ruleMapItem := range ruleMap.([]interface{}) {
41+
if ruleMapItem == nil {continue}
42+
ruleMapItemSet := ruleMapItem.(map[string]interface{})
43+
newRuleMapItemSet := make(map[string]interface{})
44+
45+
if val, exists := ruleMapItemSet["access_type"]; exists { newRuleMapItemSet["accessType"] = val }
46+
if val, exists := ruleMapItemSet["allowed_clients"]; exists { newRuleMapItemSet["allowedClients"] = val }
47+
if val, exists := ruleMapItemSet["has_root_access"]; exists { newRuleMapItemSet["hasRootAccess"] = val }
48+
if val, exists := ruleMapItemSet["nfsv3"]; exists { newRuleMapItemSet["nfsv3"] = val }
49+
if val, exists := ruleMapItemSet["kerberos5_read_only"]; exists { newRuleMapItemSet["kerberos5ReadOnly"] = val }
50+
if val, exists := ruleMapItemSet["kerberos5_read_write"]; exists { newRuleMapItemSet["kerberos5ReadWrite"] = val }
51+
if val, exists := ruleMapItemSet["kerberos5i_read_only"]; exists { newRuleMapItemSet["kerberos5iReadOnly"] = val }
52+
if val, exists := ruleMapItemSet["kerberos5i_read_write"]; exists { newRuleMapItemSet["kerberos5iReadWrite"] = val }
53+
if val, exists := ruleMapItemSet["kerberos5p_read_only"]; exists { newRuleMapItemSet["kerberos5pReadOnly"] = val }
54+
if val, exists := ruleMapItemSet["kerberos5p_read_write"]; exists { newRuleMapItemSet["kerberos5pReadWrite"] = val }
55+
56+
// Handle "squash_mode":
57+
squashModeVal, squashModeExists := ruleMapItemSet["squash_mode"]
58+
59+
// Only send if the user explicitly added it.
60+
// If not added, send as null.
61+
if squashModeExists && squashModeVal == "ALL_SQUASH" {
62+
// User provided the field, send their value
63+
newRuleMapItemSet["squashMode"] = squashModeVal
64+
} else {
65+
// User did NOT provide the field, or provided an empty value.
66+
// Explicitly send null to the API.
67+
newRuleMapItemSet["squashMode"] = nil
68+
}
69+
70+
// Handle "anon_uid"
71+
anonUidVal, anonUidExists := ruleMapItemSet["anon_uid"]
72+
73+
// Only send if the user explicitly added it.
74+
// If not added, send as null.
75+
if anonUidExists && anonUidVal != nil && anonUidVal != 0 {
76+
// User provided the field, send their value
77+
newRuleMapItemSet["anonUid"] = anonUidVal
78+
} else {
79+
// User did NOT provide the field, or provided an empty value.
80+
// Explicitly send null to the API.
81+
newRuleMapItemSet["anonUid"] = nil
82+
}
83+
84+
newRuleMap = append(newRuleMap, newRuleMapItemSet)
85+
86+
}
87+
ruleSet["rules"] = newRuleMap
88+
newExportPolicy = append(newExportPolicy, ruleSet)
89+
}
90+
}
91+
if len(newExportPolicy) > 0 {
92+
obj["exportPolicy"] = newExportPolicy[0]
93+
}
94+
}

0 commit comments

Comments
 (0)