Skip to content

Commit 80671bd

Browse files
azurerm_netapp_volume, azurerm_netapp_volume_group_oracle, azurerm_netapp_volume_group_sap_hana - add support for updating protocols(#30643)
1 parent 02e104d commit 80671bd

18 files changed

+1847
-31
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
## Example: NetApp Volume Protocol Conversion between NFSv3 and NFSv4.1
2+
3+
This example demonstrates how to convert a NetApp volume between NFSv3 and NFSv4.1 protocols and vice-versa.
4+
5+
### Variables
6+
7+
* `prefix` - (Optional) The prefix used for all resources in this example. Defaults to "example".
8+
9+
* `location` - (Optional) The Azure Region in which the resources in this example should be created. Defaults to "westus3".
10+
11+
* `resource_group_name` - (Optional) The name of the resource group. Defaults to "example-netapp-protocol-conversion-rg".
12+
13+
* `protocol_type` - (Optional) The NFS protocol type (NFSv3 or NFSv4.1). Defaults to "NFSv3".
14+
15+
### Usage example to demonstrate the conversion
16+
17+
1. **Initial setup** - Create a volume with NFSv3:
18+
```bash
19+
terraform apply -var="protocol_type=NFSv3"
20+
```
21+
22+
2. **Convert to NFSv4.1**:
23+
```bash
24+
terraform apply -var="protocol_type=NFSv4.1"
25+
```
26+
27+
3. **Convert back to NFSv3**:
28+
```bash
29+
terraform apply -var="protocol_type=NFSv3"
30+
```
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
provider "azurerm" {
2+
features {
3+
netapp {
4+
prevent_volume_destruction = true
5+
}
6+
}
7+
}
8+
9+
data "azurerm_client_config" "current" {}
10+
11+
# Create the resource group
12+
resource "azurerm_resource_group" "example" {
13+
name = var.resource_group_name
14+
location = var.location
15+
tags = {
16+
"SkipNRMSNSG" = "true"
17+
}
18+
}
19+
20+
# Create the virtual network
21+
resource "azurerm_virtual_network" "example" {
22+
name = "${var.prefix}-vnet"
23+
location = azurerm_resource_group.example.location
24+
resource_group_name = azurerm_resource_group.example.name
25+
address_space = ["10.6.0.0/16"]
26+
}
27+
28+
# Create the subnet
29+
resource "azurerm_subnet" "example" {
30+
name = "${var.prefix}-delegated-subnet"
31+
resource_group_name = azurerm_resource_group.example.name
32+
virtual_network_name = azurerm_virtual_network.example.name
33+
address_prefixes = ["10.6.2.0/24"]
34+
35+
delegation {
36+
name = "Microsoft.Netapp.volumes"
37+
38+
service_delegation {
39+
name = "Microsoft.Netapp/volumes"
40+
actions = ["Microsoft.Network/networkinterfaces/*", "Microsoft.Network/virtualNetworks/subnets/join/action"]
41+
}
42+
}
43+
}
44+
45+
# Create the NetApp account
46+
resource "azurerm_netapp_account" "example" {
47+
name = "${var.prefix}-netappaccount"
48+
location = azurerm_resource_group.example.location
49+
resource_group_name = azurerm_resource_group.example.name
50+
}
51+
52+
# Create the NetApp pool
53+
resource "azurerm_netapp_pool" "example" {
54+
name = "${var.prefix}-netapppool"
55+
location = azurerm_resource_group.example.location
56+
resource_group_name = azurerm_resource_group.example.name
57+
account_name = azurerm_netapp_account.example.name
58+
service_level = "Standard"
59+
size_in_tb = 4
60+
}
61+
62+
# Create a NetApp volume with NFSv3 protocol (initial state)
63+
resource "azurerm_netapp_volume" "example" {
64+
lifecycle {
65+
prevent_destroy = true
66+
}
67+
68+
name = "${var.prefix}-netappvolume"
69+
location = azurerm_resource_group.example.location
70+
resource_group_name = azurerm_resource_group.example.name
71+
account_name = azurerm_netapp_account.example.name
72+
pool_name = azurerm_netapp_pool.example.name
73+
volume_path = "${var.prefix}-netappvolume"
74+
service_level = "Standard"
75+
subnet_id = azurerm_subnet.example.id
76+
protocols = [var.protocol_type]
77+
security_style = "unix"
78+
storage_quota_in_gb = 100
79+
80+
export_policy_rule {
81+
rule_index = 1
82+
allowed_clients = ["0.0.0.0/0"]
83+
protocols_enabled = [var.protocol_type]
84+
unix_read_only = false
85+
unix_read_write = true
86+
root_access_enabled = true
87+
}
88+
89+
tags = {
90+
environment = "example"
91+
purpose = "protocol-conversion-demo"
92+
}
93+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
variable "resource_group_name" {
2+
description = "The name of the resource group"
3+
type = string
4+
default = "example-netapp-protocol-conversion-rg"
5+
}
6+
7+
variable "location" {
8+
description = "The Azure region for the resources"
9+
type = string
10+
default = "westus3"
11+
}
12+
13+
variable "prefix" {
14+
description = "The prefix for all resources"
15+
type = string
16+
default = "example"
17+
}
18+
19+
variable "protocol_type" {
20+
description = "The NFS protocol type (NFSv3 or NFSv4.1)"
21+
type = string
22+
default = "NFSv3"
23+
24+
validation {
25+
condition = contains(["NFSv3", "NFSv4.1"], var.protocol_type)
26+
error_message = "Protocol type must be either NFSv3 or NFSv4.1."
27+
}
28+
}

examples/netapp/volume/main.tf

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ provider "azurerm" {
88
resource "azurerm_resource_group" "example" {
99
name = "${var.prefix}-resources"
1010
location = var.location
11+
tags = {
12+
"SkipNRMSNSG" = "true"
13+
}
1114
}
1215

1316
resource "azurerm_virtual_network" "example" {
@@ -61,7 +64,7 @@ resource "azurerm_netapp_volume" "example" {
6164
volume_path = "my-unique-file-path"
6265
service_level = "Premium"
6366
subnet_id = azurerm_subnet.example.id
64-
protocols = ["NFSv4.1"]
67+
protocols = ["NFSv3"]
6568
storage_quota_in_gb = 100
6669

6770
export_policy_rule {

internal/services/netapp/netapp_volume_group_oracle_resource.go

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,6 @@ func (r NetAppVolumeGroupOracleResource) Arguments() map[string]*pluginsdk.Schem
144144

145145
"protocols": {
146146
Type: pluginsdk.TypeList,
147-
ForceNew: true,
148147
Required: true,
149148
MinItems: 1,
150149
MaxItems: 1,
@@ -321,6 +320,53 @@ func (r NetAppVolumeGroupOracleResource) Attributes() map[string]*pluginsdk.Sche
321320
return map[string]*pluginsdk.Schema{}
322321
}
323322

323+
func (r NetAppVolumeGroupOracleResource) CustomizeDiff() sdk.ResourceFunc {
324+
return sdk.ResourceFunc{
325+
Timeout: 5 * time.Minute,
326+
Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
327+
rd := metadata.ResourceDiff
328+
329+
// Validate NFSv3 to NFSv4.1 protocol conversion restrictions for volume groups
330+
volumes := rd.Get("volume").([]interface{})
331+
for i := range volumes {
332+
protocolsKey := fmt.Sprintf("volume.%d.protocols", i)
333+
334+
if rd.HasChange(protocolsKey) {
335+
old, new := rd.GetChange(protocolsKey)
336+
oldProtocols := old.([]interface{})
337+
newProtocols := new.([]interface{})
338+
339+
// Convert to string slices for validation
340+
oldProtocolsStr := make([]string, len(oldProtocols))
341+
newProtocolsStr := make([]string, len(newProtocols))
342+
343+
for j, v := range oldProtocols {
344+
oldProtocolsStr[j] = v.(string)
345+
}
346+
for j, v := range newProtocols {
347+
newProtocolsStr[j] = v.(string)
348+
}
349+
350+
// Get the export policy rules configuration for this volume
351+
exportPolicyRulesKey := fmt.Sprintf("volume.%d.export_policy_rule", i)
352+
exportPolicyRules := rd.Get(exportPolicyRulesKey).([]interface{})
353+
354+
// For volume groups, kerberos and data replication are not directly supported, so we pass empty values
355+
var kerberosEnabled bool
356+
var dataReplication []interface{}
357+
358+
validationErrors := netAppValidate.ValidateNetAppVolumeProtocolConversion(oldProtocolsStr, newProtocolsStr, kerberosEnabled, dataReplication, exportPolicyRules)
359+
for _, err := range validationErrors {
360+
return err
361+
}
362+
}
363+
}
364+
365+
return nil
366+
},
367+
}
368+
}
369+
324370
func (r NetAppVolumeGroupOracleResource) Create() sdk.ResourceFunc {
325371
return sdk.ResourceFunc{
326372
Timeout: 90 * time.Minute,
@@ -458,10 +504,29 @@ func (r NetAppVolumeGroupOracleResource) Update() sdk.ResourceFunc {
458504
return fmt.Errorf("one or more issues found while performing export policies validations for %s:\n%+v", id, errors)
459505
}
460506

461-
exportPolicyRule := expandNetAppVolumeGroupVolumeExportPolicyRulePatch(exportPolicyRuleRaw)
507+
var protocolOverride []string
508+
// Only override export policy protocols if we're also changing volume protocols
509+
if metadata.ResourceData.HasChange(fmt.Sprintf("%v.protocols", volumeItem)) {
510+
protocolsRaw := metadata.ResourceData.Get(fmt.Sprintf("%v.protocols", volumeItem)).([]interface{})
511+
protocolOverride = make([]string, len(protocolsRaw))
512+
for i, p := range protocolsRaw {
513+
protocolOverride[i] = p.(string)
514+
}
515+
}
516+
517+
exportPolicyRule := expandNetAppVolumeGroupVolumeExportPolicyRulePatchWithProtocolConversion(exportPolicyRuleRaw, protocolOverride)
462518
update.Properties.ExportPolicy = exportPolicyRule
463519
}
464520

521+
if metadata.ResourceData.HasChange(fmt.Sprintf("%v.protocols", volumeItem)) {
522+
protocolsRaw := metadata.ResourceData.Get(fmt.Sprintf("%v.protocols", volumeItem)).([]interface{})
523+
protocols := make([]string, len(protocolsRaw))
524+
for i, p := range protocolsRaw {
525+
protocols[i] = p.(string)
526+
}
527+
update.Properties.ProtocolTypes = pointer.To(protocols)
528+
}
529+
465530
if metadata.ResourceData.HasChange(fmt.Sprintf("%v.data_protection_snapshot_policy", volumeItem)) {
466531
// Validating that snapshot policies are not being created in a data protection volume
467532
dataProtectionReplicationRaw := metadata.ResourceData.Get(fmt.Sprintf("%v.data_protection_replication", volumeItem)).([]interface{})

0 commit comments

Comments
 (0)