Skip to content

Commit 2252591

Browse files
add blockDevices and ISCSI changes for volume resource (#15405) (#10974)
[upstream:1e1ffeda88f34212b3717e09eefe0703877d3885] Signed-off-by: Modular Magician <[email protected]>
1 parent 29520ad commit 2252591

File tree

5 files changed

+447
-19
lines changed

5 files changed

+447
-19
lines changed

.changelog/15405.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:enhancement
2+
netapp: added `block_devices` field and `ISCSI` protocol support to `goolge_netapp_volume` resource, and increased timeouts on its operations
3+
```

google-beta/services/netapp/resource_netapp_volume.go

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

38+
// Suppress diffs when the value read from api
39+
// has the project ID instead of the project number
40+
func ProjectIDDiffSuppress(_, old, new string, _ *schema.ResourceData) bool {
41+
42+
const marker = "/locations"
43+
44+
// Find the starting index of "/locations" in both strings.
45+
index1 := strings.Index(old, marker)
46+
index2 := strings.Index(new, marker)
47+
48+
// If "/locations" is not found in either string, they can't be compared as requested.
49+
if index1 == -1 || index2 == -1 {
50+
return false
51+
}
52+
53+
// Extract the substrings from the marker to the end.
54+
suffix1 := old[index1:]
55+
suffix2 := new[index2:]
56+
57+
// Compare the extracted suffixes.
58+
return suffix1 == suffix2
59+
}
60+
3861
func ResourceNetappVolume() *schema.Resource {
3962
return &schema.Resource{
4063
Create: resourceNetappVolumeCreate,
@@ -47,9 +70,9 @@ func ResourceNetappVolume() *schema.Resource {
4770
},
4871

4972
Timeouts: &schema.ResourceTimeout{
50-
Create: schema.DefaultTimeout(20 * time.Minute),
51-
Update: schema.DefaultTimeout(20 * time.Minute),
52-
Delete: schema.DefaultTimeout(20 * time.Minute),
73+
Create: schema.DefaultTimeout(50 * time.Minute),
74+
Update: schema.DefaultTimeout(30 * time.Minute),
75+
Delete: schema.DefaultTimeout(30 * time.Minute),
5376
},
5477

5578
CustomizeDiff: customdiff.All(
@@ -79,18 +102,12 @@ func ResourceNetappVolume() *schema.Resource {
79102
Type: schema.TypeList,
80103
Required: true,
81104
ForceNew: true,
82-
Description: `The protocol of the volume. Allowed combinations are '['NFSV3']', '['NFSV4']', '['SMB']', '['NFSV3', 'NFSV4']', '['SMB', 'NFSV3']' and '['SMB', 'NFSV4']'. Possible values: ["NFSV3", "NFSV4", "SMB"]`,
105+
Description: `The protocol of the volume. Allowed combinations are '['NFSV3']', '['NFSV4']', '['SMB']', '['NFSV3', 'NFSV4']', '['SMB', 'NFSV3']' and '['SMB', 'NFSV4']'. Possible values: ["NFSV3", "NFSV4", "SMB", "ISCSI"]`,
83106
Elem: &schema.Schema{
84107
Type: schema.TypeString,
85-
ValidateFunc: verify.ValidateEnum([]string{"NFSV3", "NFSV4", "SMB"}),
108+
ValidateFunc: verify.ValidateEnum([]string{"NFSV3", "NFSV4", "SMB", "ISCSI"}),
86109
},
87110
},
88-
"share_name": {
89-
Type: schema.TypeString,
90-
Required: true,
91-
ForceNew: true,
92-
Description: `Share name (SMB) or export path (NFS) of the volume. Needs to be unique per location.`,
93-
},
94111
"storage_pool": {
95112
Type: schema.TypeString,
96113
Required: true,
@@ -125,6 +142,63 @@ Format: 'projects/{{projectId}}/locations/{{location}}/backupVaults/{{backupVaul
125142
},
126143
},
127144
},
145+
"block_devices": {
146+
Type: schema.TypeList,
147+
Optional: true,
148+
Description: `Block device represents the device(s) which are stored in the block volume.
149+
Currently, only one block device is permitted per Volume.`,
150+
Elem: &schema.Resource{
151+
Schema: map[string]*schema.Schema{
152+
"os_type": {
153+
Type: schema.TypeString,
154+
Required: true,
155+
ForceNew: true,
156+
ValidateFunc: verify.ValidateEnum([]string{"LINUX", "WINDOWS", "ESXI"}),
157+
Description: `The OS type of the volume.
158+
This field can't be changed after the block device is created. Possible values: ["LINUX", "WINDOWS", "ESXI"]`,
159+
},
160+
"host_groups": {
161+
Type: schema.TypeList,
162+
Computed: true,
163+
Optional: true,
164+
DiffSuppressFunc: ProjectIDDiffSuppress,
165+
Description: `A list of host groups that identify hosts that can mount the block volume.
166+
Format:
167+
'projects/{project_id}/locations/{location}/hostGroups/{host_group_id}'
168+
This field can be updated after the block device is created.`,
169+
Elem: &schema.Schema{
170+
Type: schema.TypeString,
171+
},
172+
},
173+
"name": {
174+
Type: schema.TypeString,
175+
Computed: true,
176+
Optional: true,
177+
Description: `User-defined name for the block device, unique within the Volume. In case
178+
no user input is provided, name will be autogenerated in the backend.
179+
The name must meet the following requirements:
180+
* Be between 1 and 255 characters long.
181+
* Contain only uppercase or lowercase letters (A-Z, a-z), numbers (0-9),
182+
and the following special characters: "-", "_", "}", "{", ".".
183+
* Spaces are not allowed.`,
184+
},
185+
"identifier": {
186+
Type: schema.TypeString,
187+
Computed: true,
188+
Description: `Device identifier of the Block volume. This represents lun_serial_number
189+
for ISCSI volumes`,
190+
},
191+
"size_gib": {
192+
Type: schema.TypeInt,
193+
Computed: true,
194+
Description: `The size of the block device in GiB.
195+
Any value provided in this field during Volume creation is IGNORED.
196+
The block device's size is system-managed and will be set to match
197+
the parent Volume's 'capacity_gib'.`,
198+
},
199+
},
200+
},
201+
},
128202
"description": {
129203
Type: schema.TypeString,
130204
Optional: true,
@@ -366,6 +440,12 @@ Format: 'projects/{{project}}/locations/{{location}}/volumes/{{volume}}/snapshot
366440
Description: `Security Style of the Volume. Use UNIX to use UNIX or NFSV4 ACLs for file permissions.
367441
Use NTFS to use NTFS ACLs for file permissions. Can only be set for volumes which use SMB together with NFS as protocol. Possible values: ["NTFS", "UNIX"]`,
368442
},
443+
"share_name": {
444+
Type: schema.TypeString,
445+
Optional: true,
446+
ForceNew: true,
447+
Description: `Share name (SMB) or export path (NFS) of the volume. Needs to be unique per location.`,
448+
},
369449
"smb_settings": {
370450
Type: schema.TypeList,
371451
Computed: true,
@@ -833,6 +913,12 @@ func resourceNetappVolumeCreate(d *schema.ResourceData, meta interface{}) error
833913
} else if v, ok := d.GetOkExists("throughput_mibps"); !tpgresource.IsEmptyValue(reflect.ValueOf(throughputMibpsProp)) && (ok || !reflect.DeepEqual(v, throughputMibpsProp)) {
834914
obj["throughputMibps"] = throughputMibpsProp
835915
}
916+
blockDevicesProp, err := expandNetappVolumeBlockDevices(d.Get("block_devices"), d, config)
917+
if err != nil {
918+
return err
919+
} else if v, ok := d.GetOkExists("block_devices"); !tpgresource.IsEmptyValue(reflect.ValueOf(blockDevicesProp)) && (ok || !reflect.DeepEqual(v, blockDevicesProp)) {
920+
obj["blockDevices"] = blockDevicesProp
921+
}
836922
effectiveLabelsProp, err := expandNetappVolumeEffectiveLabels(d.Get("effective_labels"), d, config)
837923
if err != nil {
838924
return err
@@ -1055,6 +1141,9 @@ func resourceNetappVolumeRead(d *schema.ResourceData, meta interface{}) error {
10551141
if err := d.Set("hot_tier_size_used_gib", flattenNetappVolumeHotTierSizeUsedGib(res["hotTierSizeUsedGib"], d, config)); err != nil {
10561142
return fmt.Errorf("Error reading Volume: %s", err)
10571143
}
1144+
if err := d.Set("block_devices", flattenNetappVolumeBlockDevices(res["blockDevices"], d, config)); err != nil {
1145+
return fmt.Errorf("Error reading Volume: %s", err)
1146+
}
10581147
if err := d.Set("terraform_labels", flattenNetappVolumeTerraformLabels(res["labels"], d, config)); err != nil {
10591148
return fmt.Errorf("Error reading Volume: %s", err)
10601149
}
@@ -1165,6 +1254,12 @@ func resourceNetappVolumeUpdate(d *schema.ResourceData, meta interface{}) error
11651254
} else if v, ok := d.GetOkExists("throughput_mibps"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, throughputMibpsProp)) {
11661255
obj["throughputMibps"] = throughputMibpsProp
11671256
}
1257+
blockDevicesProp, err := expandNetappVolumeBlockDevices(d.Get("block_devices"), d, config)
1258+
if err != nil {
1259+
return err
1260+
} else if v, ok := d.GetOkExists("block_devices"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, blockDevicesProp)) {
1261+
obj["blockDevices"] = blockDevicesProp
1262+
}
11681263
effectiveLabelsProp, err := expandNetappVolumeEffectiveLabels(d.Get("effective_labels"), d, config)
11691264
if err != nil {
11701265
return err
@@ -1241,6 +1336,10 @@ func resourceNetappVolumeUpdate(d *schema.ResourceData, meta interface{}) error
12411336
updateMask = append(updateMask, "throughputMibps")
12421337
}
12431338

1339+
if d.HasChange("block_devices") {
1340+
updateMask = append(updateMask, "blockDevices")
1341+
}
1342+
12441343
if d.HasChange("effective_labels") {
12451344
updateMask = append(updateMask, "labels")
12461345
}
@@ -1250,6 +1349,38 @@ func resourceNetappVolumeUpdate(d *schema.ResourceData, meta interface{}) error
12501349
if err != nil {
12511350
return err
12521351
}
1352+
// remove sizeGib and identifier from the update request for block_devices
1353+
1354+
if v, ok := d.GetOk("block_devices"); ok {
1355+
1356+
l := v.([]interface{})
1357+
newBlockDevices := make([]interface{}, 0, len(l))
1358+
1359+
for _, item := range v.([]interface{}) {
1360+
if item == nil {
1361+
continue
1362+
}
1363+
blockDevice := item.(map[string]interface{})
1364+
newblockDevice := make(map[string]interface{})
1365+
1366+
if val, exists := blockDevice["name"]; exists {
1367+
newblockDevice["name"] = val
1368+
}
1369+
if val, exists := blockDevice["host_groups"]; exists {
1370+
newblockDevice["host_groups"] = val
1371+
}
1372+
if val, exists := blockDevice["os_type"]; exists {
1373+
newblockDevice["os_type"] = val
1374+
}
1375+
1376+
newBlockDevices = append(newBlockDevices, newblockDevice)
1377+
}
1378+
1379+
log.Printf("newBlockDevices %v", newBlockDevices)
1380+
if len(newBlockDevices) > 0 {
1381+
obj["blockDevices"] = newBlockDevices
1382+
}
1383+
}
12531384

12541385
// err == nil indicates that the billing_project value was found
12551386
if bp, err := tpgresource.GetBillingProject(d, config); err == nil {
@@ -2108,6 +2239,61 @@ func flattenNetappVolumeHotTierSizeUsedGib(v interface{}, d *schema.ResourceData
21082239
return v
21092240
}
21102241

2242+
func flattenNetappVolumeBlockDevices(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
2243+
if v == nil {
2244+
return v
2245+
}
2246+
l := v.([]interface{})
2247+
transformed := make([]interface{}, 0, len(l))
2248+
for _, raw := range l {
2249+
original := raw.(map[string]interface{})
2250+
if len(original) < 1 {
2251+
// Do not include empty json objects coming back from the api
2252+
continue
2253+
}
2254+
transformed = append(transformed, map[string]interface{}{
2255+
"name": flattenNetappVolumeBlockDevicesName(original["name"], d, config),
2256+
"host_groups": flattenNetappVolumeBlockDevicesHostGroups(original["hostGroups"], d, config),
2257+
"identifier": flattenNetappVolumeBlockDevicesIdentifier(original["identifier"], d, config),
2258+
"size_gib": flattenNetappVolumeBlockDevicesSizeGib(original["sizeGib"], d, config),
2259+
"os_type": flattenNetappVolumeBlockDevicesOsType(original["osType"], d, config),
2260+
})
2261+
}
2262+
return transformed
2263+
}
2264+
func flattenNetappVolumeBlockDevicesName(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
2265+
return v
2266+
}
2267+
2268+
func flattenNetappVolumeBlockDevicesHostGroups(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
2269+
return v
2270+
}
2271+
2272+
func flattenNetappVolumeBlockDevicesIdentifier(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
2273+
return v
2274+
}
2275+
2276+
func flattenNetappVolumeBlockDevicesSizeGib(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
2277+
// Handles the string fixed64 format
2278+
if strVal, ok := v.(string); ok {
2279+
if intVal, err := tpgresource.StringToFixed64(strVal); err == nil {
2280+
return intVal
2281+
}
2282+
}
2283+
2284+
// number values are represented as float64
2285+
if floatVal, ok := v.(float64); ok {
2286+
intVal := int(floatVal)
2287+
return intVal
2288+
}
2289+
2290+
return v // let terraform core handle it otherwise
2291+
}
2292+
2293+
func flattenNetappVolumeBlockDevicesOsType(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
2294+
return v
2295+
}
2296+
21112297
func flattenNetappVolumeTerraformLabels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
21122298
if v == nil {
21132299
return v
@@ -2899,6 +3085,79 @@ func expandNetappVolumeThroughputMibps(v interface{}, d tpgresource.TerraformRes
28993085
return v, nil
29003086
}
29013087

3088+
func expandNetappVolumeBlockDevices(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
3089+
if v == nil {
3090+
return nil, nil
3091+
}
3092+
l := v.([]interface{})
3093+
req := make([]interface{}, 0, len(l))
3094+
for _, raw := range l {
3095+
if raw == nil {
3096+
continue
3097+
}
3098+
original := raw.(map[string]interface{})
3099+
transformed := make(map[string]interface{})
3100+
3101+
transformedName, err := expandNetappVolumeBlockDevicesName(original["name"], d, config)
3102+
if err != nil {
3103+
return nil, err
3104+
} else if val := reflect.ValueOf(transformedName); val.IsValid() && !tpgresource.IsEmptyValue(val) {
3105+
transformed["name"] = transformedName
3106+
}
3107+
3108+
transformedHostGroups, err := expandNetappVolumeBlockDevicesHostGroups(original["host_groups"], d, config)
3109+
if err != nil {
3110+
return nil, err
3111+
} else if val := reflect.ValueOf(transformedHostGroups); val.IsValid() && !tpgresource.IsEmptyValue(val) {
3112+
transformed["hostGroups"] = transformedHostGroups
3113+
}
3114+
3115+
transformedIdentifier, err := expandNetappVolumeBlockDevicesIdentifier(original["identifier"], d, config)
3116+
if err != nil {
3117+
return nil, err
3118+
} else if val := reflect.ValueOf(transformedIdentifier); val.IsValid() && !tpgresource.IsEmptyValue(val) {
3119+
transformed["identifier"] = transformedIdentifier
3120+
}
3121+
3122+
transformedSizeGib, err := expandNetappVolumeBlockDevicesSizeGib(original["size_gib"], d, config)
3123+
if err != nil {
3124+
return nil, err
3125+
} else if val := reflect.ValueOf(transformedSizeGib); val.IsValid() && !tpgresource.IsEmptyValue(val) {
3126+
transformed["sizeGib"] = transformedSizeGib
3127+
}
3128+
3129+
transformedOsType, err := expandNetappVolumeBlockDevicesOsType(original["os_type"], d, config)
3130+
if err != nil {
3131+
return nil, err
3132+
} else if val := reflect.ValueOf(transformedOsType); val.IsValid() && !tpgresource.IsEmptyValue(val) {
3133+
transformed["osType"] = transformedOsType
3134+
}
3135+
3136+
req = append(req, transformed)
3137+
}
3138+
return req, nil
3139+
}
3140+
3141+
func expandNetappVolumeBlockDevicesName(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
3142+
return v, nil
3143+
}
3144+
3145+
func expandNetappVolumeBlockDevicesHostGroups(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
3146+
return v, nil
3147+
}
3148+
3149+
func expandNetappVolumeBlockDevicesIdentifier(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
3150+
return v, nil
3151+
}
3152+
3153+
func expandNetappVolumeBlockDevicesSizeGib(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
3154+
return v, nil
3155+
}
3156+
3157+
func expandNetappVolumeBlockDevicesOsType(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
3158+
return v, nil
3159+
}
3160+
29023161
func expandNetappVolumeEffectiveLabels(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (map[string]string, error) {
29033162
if v == nil {
29043163
return map[string]string{}, nil

google-beta/services/netapp/resource_netapp_volume_generated_meta.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ fields:
99
- api_field: 'backupConfig.backupPolicies'
1010
- api_field: 'backupConfig.backupVault'
1111
- api_field: 'backupConfig.scheduledBackupEnabled'
12+
- api_field: 'blockDevices.hostGroups'
13+
- api_field: 'blockDevices.identifier'
14+
- api_field: 'blockDevices.name'
15+
- api_field: 'blockDevices.osType'
16+
- api_field: 'blockDevices.sizeGib'
1217
- api_field: 'capacityGib'
1318
- api_field: 'coldTierSizeGib'
1419
- api_field: 'createTime'

0 commit comments

Comments
 (0)