Skip to content

Commit 6051d9f

Browse files
authored
Merge pull request #233 from NetApp/integration/main
Integration/main
2 parents 4bd74fa + 4aa5aae commit 6051d9f

13 files changed

Lines changed: 630 additions & 23 deletions

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
## 27.1.0
2+
3+
NEW FEATURES:
4+
* resource/volume: Added support for AVS integration in Azure HA SAZ CVOs. Allows setup and removal of AVS on ISCSI volumes in Azure HA SAZ CVOs.
5+
* resource/volume: Added support for SYNC operation on AVS hosts in the cluster. Allows to sync configuration across AVS hosts.
6+
7+
BUG FIXES:
8+
* resource/volume: Fixed iSCSI volume creation when using a custom SVM (`svm_name`). The provider now uses the configured `svm_name` for igroup lookups and initiator creation instead of defaulting to the working environment SVM, fixing "SVM does not exist" errors for CVOs with non-default SVM names.
9+
10+
ENHANCEMENTS:
11+
* resource/connector_azure: Upgraded the diagnostics storage account to `StorageV2` for connector templates.
12+
* resource/cvo_aws, cvo_azure, cvo_gcp: Enable WORM on existing CVOs without recreation. WORM retention parameters (`worm_retention_period_length` and `worm_retention_period_unit`) can now be added to existing CVOs via in-place update instead of forcing resource replacement. Both parameters must be specified together, and once set, WORM retention cannot be modified (immutable). When WORM is enabled, `capacity_tier` must be set to 'NONE' as data tiering and WORM are mutually exclusive.
13+
114
## 27.0.0
215
NEW FEATURES:
316
* resource/cvo_azure: Supports configuration of `storage_account_network_access` while creating Azure SN and HA CVO.

cloudmanager/helper.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,10 @@ type accessConfigs struct {
288288
NatIP string `json:"natIP"`
289289
}
290290

291+
type enableWormRequest struct {
292+
RetentionPeriod wormRetentionPeriod `structs:"retentionPeriod"`
293+
}
294+
291295
// check deployment mode and validate the input
292296
func (c *Client) checkDeploymentMode(d *schema.ResourceData, clientID string) (bool, string, error) {
293297
isSaaS := true
@@ -1547,6 +1551,47 @@ func updateCVOWritingSpeedState(d *schema.ResourceData, meta interface{}, client
15471551
return nil
15481552
}
15491553

1554+
func enableCVOWorm(d *schema.ResourceData, meta interface{}, clientID string, isSaas bool, connectorIP string) error {
1555+
client := meta.(*Client)
1556+
1557+
// Get the retention period values
1558+
length, lengthOk := d.GetOk("worm_retention_period_length")
1559+
unit, unitOk := d.GetOk("worm_retention_period_unit")
1560+
1561+
if !lengthOk || !unitOk {
1562+
return fmt.Errorf("both worm_retention_period_length and worm_retention_period_unit are required")
1563+
}
1564+
1565+
// Build request
1566+
var request enableWormRequest
1567+
request.RetentionPeriod.Length = length.(int)
1568+
request.RetentionPeriod.Unit = unit.(string)
1569+
1570+
log.Printf("Enabling WORM with retention: %d %s", request.RetentionPeriod.Length, request.RetentionPeriod.Unit)
1571+
1572+
id := d.Id()
1573+
baseURL := fmt.Sprintf("/working-environments/%s/enable-worm", id)
1574+
1575+
// Use the common API caller which handles all cloud providers
1576+
updateErr := client.callCMUpdateAPI("PUT", request, baseURL, id, "enableCVOWorm", clientID, isSaas, connectorIP)
1577+
if updateErr != nil {
1578+
return updateErr
1579+
}
1580+
1581+
retryCount := 40
1582+
if d.Get("is_ha").(bool) {
1583+
retryCount = retryCount * 2
1584+
}
1585+
1586+
err := client.waitOnCompletionCVOUpdate(id, retryCount, 60, clientID, isSaas, connectorIP)
1587+
if err != nil {
1588+
return fmt.Errorf("enable WORM failed: %v", err)
1589+
}
1590+
1591+
log.Printf("WORM enabled successfully on CVO %s", id)
1592+
return nil
1593+
}
1594+
15501595
func (c *Client) waitOnCompletionOntapImageUpgrade(apiRoot string, id string, targetVersion string, retryCount int, waitInterval int, clientID string, isSaas bool, connectorIP string) error {
15511596
// check upgrade status
15521597
log.Print("Check CVO ontap image upgrade status")

cloudmanager/occm_azure_json.go

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -178,10 +178,11 @@ func (c *Client) callTemplate() string {
178178
{
179179
"name": "[variables('diagnosticsStorageAccountName')]",
180180
"type": "Microsoft.Storage/storageAccounts",
181-
"apiVersion": "2015-06-15",
181+
"apiVersion": "2021-09-01",
182182
"location": "[parameters('location')]",
183-
"properties": {
184-
"accountType": "[variables('diagnosticsStorageAccountType')]"
183+
"kind": "StorageV2",
184+
"sku": {
185+
"name": "[variables('diagnosticsStorageAccountType')]"
185186
}
186187
},
187188
{
@@ -372,10 +373,11 @@ func (c *Client) callTemplateDisablePublicIP() string {
372373
{
373374
"name": "[variables('diagnosticsStorageAccountName')]",
374375
"type": "Microsoft.Storage/storageAccounts",
375-
"apiVersion": "2015-06-15",
376+
"apiVersion": "2021-09-01",
376377
"location": "[parameters('location')]",
377-
"properties": {
378-
"accountType": "[variables('diagnosticsStorageAccountType')]"
378+
"kind": "StorageV2",
379+
"sku": {
380+
"name": "[variables('diagnosticsStorageAccountType')]"
379381
}
380382
},
381383
{

cloudmanager/resource_netapp_cloudmanager_cvo_aws.go

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,13 +143,11 @@ func resourceCVOAWS() *schema.Resource {
143143
"worm_retention_period_length": {
144144
Type: schema.TypeInt,
145145
Optional: true,
146-
ForceNew: true,
147146
},
148147
"worm_retention_period_unit": {
149148
Type: schema.TypeString,
150149
ValidateFunc: validation.StringInSlice([]string{"years", "months", "days", "hours", "minutes", "seconds"}, true),
151150
Optional: true,
152-
ForceNew: true,
153151
},
154152
"writing_speed_state": {
155153
Type: schema.TypeString,
@@ -690,6 +688,24 @@ func resourceCVOAWSUpdate(d *schema.ResourceData, meta interface{}) error {
690688
return upgradeErr
691689
}
692690

691+
// check if WORM parameters are changed
692+
if d.HasChange("worm_retention_period_length") || d.HasChange("worm_retention_period_unit") {
693+
oldLength, newLength := d.GetChange("worm_retention_period_length")
694+
oldUnit, newUnit := d.GetChange("worm_retention_period_unit")
695+
696+
isEnabling := (oldLength.(int) == 0 && oldUnit.(string) == "") &&
697+
(newLength.(int) > 0 && newUnit.(string) != "")
698+
699+
if isEnabling {
700+
respErr := enableCVOWorm(d, meta, clientID, true, "")
701+
if respErr != nil {
702+
return respErr
703+
}
704+
} else if oldLength.(int) > 0 || oldUnit.(string) != "" {
705+
return fmt.Errorf("WORM retention period cannot be changed once set. WORM is immutable")
706+
}
707+
}
708+
693709
return nil
694710
}
695711

@@ -698,6 +714,22 @@ func resourceCVOAWSCustomizeDiff(diff *schema.ResourceDiff, v interface{}) error
698714
if respErr != nil {
699715
return respErr
700716
}
717+
// WORM validation
718+
wormLength, lengthOk := diff.GetOk("worm_retention_period_length")
719+
wormUnit, unitOk := diff.GetOk("worm_retention_period_unit")
720+
721+
if lengthOk != unitOk {
722+
return fmt.Errorf("worm_retention_period_length and worm_retention_period_unit must be specified together")
723+
}
724+
725+
if lengthOk && unitOk && wormLength.(int) > 0 && wormUnit.(string) != "" {
726+
if capacityTier, ok := diff.GetOk("capacity_tier"); ok {
727+
tier := capacityTier.(string)
728+
if tier != "" && tier != "NONE" {
729+
return fmt.Errorf("capacity_tier must be 'NONE' when WORM is enabled. WORM and data tiering are mutually exclusive")
730+
}
731+
}
732+
}
701733
return nil
702734
}
703735

cloudmanager/resource_netapp_cloudmanager_cvo_azure.go

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,13 +186,11 @@ func resourceCVOAzure() *schema.Resource {
186186
"worm_retention_period_length": {
187187
Type: schema.TypeInt,
188188
Optional: true,
189-
ForceNew: true,
190189
},
191190
"worm_retention_period_unit": {
192191
Type: schema.TypeString,
193192
ValidateFunc: validation.StringInSlice([]string{"years", "months", "days", "hours", "minutes", "seconds"}, true),
194193
Optional: true,
195-
ForceNew: true,
196194
},
197195
"writing_speed_state": {
198196
Type: schema.TypeString,
@@ -672,6 +670,24 @@ func resourceCVOAzureUpdate(d *schema.ResourceData, meta interface{}) error {
672670
return upgradeErr
673671
}
674672

673+
// check if WORM parameters are changed
674+
if d.HasChange("worm_retention_period_length") || d.HasChange("worm_retention_period_unit") {
675+
oldLength, newLength := d.GetChange("worm_retention_period_length")
676+
oldUnit, newUnit := d.GetChange("worm_retention_period_unit")
677+
678+
isEnabling := (oldLength.(int) == 0 && oldUnit.(string) == "") &&
679+
(newLength.(int) > 0 && newUnit.(string) != "")
680+
681+
if isEnabling {
682+
respErr := enableCVOWorm(d, meta, clientID, true, "")
683+
if respErr != nil {
684+
return respErr
685+
}
686+
} else if oldLength.(int) > 0 || oldUnit.(string) != "" {
687+
return fmt.Errorf("WORM retention period cannot be changed once set. WORM is immutable")
688+
}
689+
}
690+
675691
return nil
676692
}
677693

@@ -694,6 +710,23 @@ func resourceCVOAzureCustomizeDiff(diff *schema.ResourceDiff, v interface{}) err
694710
}
695711
}
696712

713+
// WORM-tiering validation
714+
wormLength, lengthOk := diff.GetOk("worm_retention_period_length")
715+
wormUnit, unitOk := diff.GetOk("worm_retention_period_unit")
716+
717+
if lengthOk != unitOk {
718+
return fmt.Errorf("worm_retention_period_length and worm_retention_period_unit must be specified together")
719+
}
720+
721+
if lengthOk && unitOk && wormLength.(int) > 0 && wormUnit.(string) != "" {
722+
if capacityTier, ok := diff.GetOk("capacity_tier"); ok {
723+
tier := capacityTier.(string)
724+
if tier != "" && tier != "NONE" {
725+
return fmt.Errorf("capacity_tier must be 'NONE' when WORM is enabled. WORM and data tiering are mutually exclusive")
726+
}
727+
}
728+
}
729+
697730
// Prevent modifying root_volume_aggregate for existing SVMs
698731
if diff.HasChange("svm") {
699732
oldRaw, newRaw := diff.GetChange("svm")

cloudmanager/resource_netapp_cloudmanager_cvo_gcp.go

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,13 +163,11 @@ func resourceCVOGCP() *schema.Resource {
163163
"worm_retention_period_length": {
164164
Type: schema.TypeInt,
165165
Optional: true,
166-
ForceNew: true,
167166
},
168167
"worm_retention_period_unit": {
169168
Type: schema.TypeString,
170169
ValidateFunc: validation.StringInSlice([]string{"years", "months", "days", "hours", "minutes", "seconds"}, true),
171170
Optional: true,
172-
ForceNew: true,
173171
},
174172
"nss_account": {
175173
Type: schema.TypeString,
@@ -834,6 +832,24 @@ func resourceCVOGCPUpdate(d *schema.ResourceData, meta interface{}) error {
834832
return upgradeErr
835833
}
836834

835+
// check if WORM parameters are changed
836+
if d.HasChange("worm_retention_period_length") || d.HasChange("worm_retention_period_unit") {
837+
oldLength, newLength := d.GetChange("worm_retention_period_length")
838+
oldUnit, newUnit := d.GetChange("worm_retention_period_unit")
839+
840+
isEnabling := (oldLength.(int) == 0 && oldUnit.(string) == "") &&
841+
(newLength.(int) > 0 && newUnit.(string) != "")
842+
843+
if isEnabling {
844+
respErr := enableCVOWorm(d, meta, clientID, isSaas, connectorIP)
845+
if respErr != nil {
846+
return respErr
847+
}
848+
} else if oldLength.(int) > 0 || oldUnit.(string) != "" {
849+
return fmt.Errorf("WORM retention period cannot be changed once set. WORM is immutable")
850+
}
851+
}
852+
837853
return nil
838854
}
839855

@@ -951,6 +967,23 @@ func resourceCVOGCPCustomizeDiff(diff *schema.ResourceDiff, v interface{}) error
951967
}
952968
}
953969

970+
// WORM validation
971+
wormLength, lengthOk := diff.GetOk("worm_retention_period_length")
972+
wormUnit, unitOk := diff.GetOk("worm_retention_period_unit")
973+
974+
if lengthOk != unitOk {
975+
return fmt.Errorf("worm_retention_period_length and worm_retention_period_unit must be specified together")
976+
}
977+
978+
if lengthOk && unitOk && wormLength.(int) > 0 && wormUnit.(string) != "" {
979+
if capacityTier, ok := diff.GetOk("capacity_tier"); ok {
980+
tier := capacityTier.(string)
981+
if tier != "" && tier != "NONE" {
982+
return fmt.Errorf("capacity_tier must be 'NONE' when WORM is enabled. WORM and data tiering are mutually exclusive")
983+
}
984+
}
985+
}
986+
954987
return nil
955988
}
956989

0 commit comments

Comments
 (0)