PowerShell NetApp SnapMirror Destination Migration

This article shows how to use PowerShell and the NetApp PowerShell Module to migrate all NetApp SnapVault/SnapMirror relationships to a new system. The script also builds the SVM Relationships and does the cutovers of the relationships on the source ONTAP Systems.

Disclaimer: This content and scripts are provided free of charge and I do not take any responsability for them nor any harm they may cause, it is up to you to review and test them properly before deploying them anywhere.

Introduction

If you ever had to migrate a SnapMirror Destination ONTAP System to a new one, you probably already faced the struggle to migrate Volume by Volume and SnapMirror by SnapMirror to keep all Snapshots.

The good news: You don't have to do this manually as NetApp has a great PowerShell integration for both, ONTAP and 7-Mode Systems.

The magic

Since I had to migrate multiple SnapMirror Destination ONTAP Clusters to new ones and realized how much effort this is per volume, I came up with this PowerShell script to automate this process.

What this script does is:

  • SVM Peering
  • Volume creation
  • Intermediate SnapMirror Relationship and Initialization
  • Cutover on the Source Systems from the old SnapMirror Destination over to new SnapMirror Destination (keeping the existing policy, schedule and settings)
  • Break-up off the existing SnapMirror from Source Systems to the old Destination System

Prerequisites:

  • Credentials for all involved ONTAP Systems
  • Cluster Peering between old destination system and new destination system
  • Cluster Peering between source systems and new destination systems
  • SnapMirror Policies, Schedules and Snapshot Labels from all source storages pre-created on the new destination system (the script will not create them)

How to use it

To use the script, simply fill in the variables at the start of the script, please make sure to cross check all information you enter. On the first run, it will ask you for credentials for both, the old and the new destination system. After that, it will create the SVM Peerings (if not existent), the volumes and the SnapMirrors between the old and new destination system and initialize them.

It will take some time (hours to weeks) to transfer the data in those volumes between the old destination and the new destination systems depending on both systems performance and the amount of data.

You can check the status on the new destination system by executing snapmirror show and verifying that the status is snapmirrored and idle.

As soon as that's the case, run the script once more. It will start by fetching the status then quiescing, breaking and deleting the mirrors to the old backup system and ask you for credentials to all involved source systems. After entering the credentials, it will start to build the SnapMirror Relationships from the source system to the new destination system, invoke a resync and release the SnapMirror to the old backup system.

The script

  1#region Variables
  2$oldIP = "<Management IP of old destination storage>"
  3$newIP = "<Management IP of new destination storage>"
  4
  5[array]$svms = @(
  6    @{
  7        Old = "<SVM Name on old destination storage>"
  8        New = "<SVM Name on new destination storage>"
  9    }
 10    <#
 11        Add as many SVMs as required
 12        @{
 13            Old = "<SVM Name on old destination storage>"
 14            New = "<SVM Name on new destination storage>"
 15        }
 16    #>
 17)
 18#endregion
 19
 20#region Code below
 21
 22if(!$oldCreds){
 23    $oldCreds = Get-Credential -Message "Old System"
 24}
 25if(!$newCreds){
 26    $newCreds = Get-Credential -Message "New System"
 27}
 28
 29$oldCluster = Connect-NcController -HTTPS -Credential $oldCreds -Name $oldIP
 30$newCluster = Connect-NcController -HTTPS -Credential $newCreds -Name $newIP
 31
 32$oldClusterName = (Get-NcCluster -Controller $oldCluster).ClusterName
 33$newClusterName = (Get-NcCluster -Controller $newCluster).ClusterName
 34
 35if(!$CredentialTable){
 36    $CredentialTable = @{}
 37}
 38if(!$IPTable){
 39    $IPTable = @{}
 40}
 41if(!$ClusterTable){
 42    $ClusterTable = @{}
 43}
 44
 45if(!($calculatedBlacklist)){
 46    $calculatedBlacklist = @()
 47}
 48
 49$svms.GetEnumerator() | ForEach-Object {
 50
 51    $OldSVM = $_.Old
 52    $NewSVM = $_.New
 53
 54    $OldSVMObj = Get-NcVserver -Name $OldSVM -Controller $oldCluster
 55
 56    # Check if Destination SVM Exists
 57    if(!($NewSVMObj = Get-NcVserver -Name $newSVM -Controller $newCluster)){
 58        Write-Host("Creating new vServer $newSVM on $newClusterName")
 59        $aggr = (Get-NcAggr -Controller $newCluster | Sort-Object -Property Available -Descending)[0].Name
 60        $null = New-NcVserver   -Name $NewSVM `
 61                        -RootVolumeAggregate $aggr `
 62                        -RootVolumeSecurityStyle $oldsvmobj.RootVolumeSecurityStyle `
 63                        -Language $oldsvmobj.Language `
 64                        -Controller $newCluster
 65    }
 66
 67    # Check if Destination SVM is peered with source vserver
 68    if(!($peerrelationship = Get-NcVserverPeer -Vserver $OldSVM -PeerVserver $NewSVM -Controller $oldCluster -Application "snapmirror")){
 69        Write-Host("Creating new vServer Peer Relationship for $($oldClusterName):$($OldSVM) to $($newClusterName):$($NewSVM)")
 70        $peerrelationship = New-NcVserverPeer -Vserver $OldSVM -PeerVserver $NewSVM -Controller $oldCluster -Application "snapmirror" -PeerCluster $newClusterName
 71    }
 72    
 73    # Check if SVM Peer is unitialized
 74    if($peerrelationship.PeerState -eq "initiated"){
 75        Write-Host("Confirming new vServer Peer Relationship for $($oldClusterName):$($OldSVM) to $($newClusterName):$($NewSVM)")
 76        $null = Confirm-NcVserverPeer -Vserver $NewSVM -PeerVserver $OldSVM -Controller $newCluster
 77    }
 78    
 79    # Get existing volumes
 80    Write-Host("Getting volumes for $oldSVM on $oldClusterName")
 81    $vols = @()
 82    Get-NcVol -Vserver $OldSVM -Controller $oldCluster | Where-Object { $_.Name -notlike "*root*" } | ForEach-Object {
 83        $vols += @{
 84            Size = $_.TotalSize
 85            Language = $_.VolumeLanguageAttributes.LanguageCode
 86            Name = $_.Name
 87            Security = $_.VolumeSecurityAttributes.Style
 88        }
 89    }
 90        
 91    # Run through volumes 
 92    $vols.GetEnumerator() | Where-Object { 
 93                                            ($_.Name -notin $calculatedBlacklist) -and 
 94                                            ($_.Name -notin $volumeBlacklist)
 95                                         } | ForEach-Object {
 96        # Create new volume if it doesn't exist
 97        $aggr = (Get-NcAggr -Controller $newCluster | Sort-Object -Property Available -Descending)[0].Name
 98        if(!($volume = Get-NcVol -Name $_.Name -Vserver $NewSVM -Controller $newCluster)){
 99            Write-Host("Creating new volume `"$($_.Name)`" for $newSVM on $newClusterName")
100            $null = New-NcVol -Size $_.Size -Name $_.Name -Language $_.Language -SecurityStyle $_.Security -VserverContext $NewSVM -Aggregate $aggr -Type dp -JunctionActive:$false -JunctionPath $null -Controller $newCluster
101        }
102        
103        # Create new snapmirror if it doesn't exist
104        if(!($snapmirror = Get-NcSnapmirror -SourceCluster $oldClusterName -SourceVserver $OldSVM -SourceVolume $_.Name -DestinationCluster $newClusterName -DestinationVserver $NewSVM -DestinationVolume $_.Name -Controller $newCluster)){
105            Write-Host("Creating new snapmirror from $($oldClusterName):$($OldSVM):$($_.Name) to $($newClusterName):$($NewSVM):$($_.Name)")
106            $snapmirror = New-NcSnapmirror -SourceCluster $oldClusterName -SourceVserver $OldSVM -SourceVolume $_.Name -DestinationCluster $newClusterName -DestinationVserver $NewSVM -DestinationVolume $_.Name -Schedule "hourly" -Policy "MirrorAllSnapshots" -Controller $newCluster
107        }
108
109        # Initialize new snapmirror if not done yet
110        if(
111            $snapmirror.MirrorState -eq "uninitialized" -and
112            $snapmirror.Status -ne "transferring" -and
113            $snapmirror.Status -ne "finalizing"    
114        ){
115            Write-Host("Initializing new snapmirror from $($oldClusterName):$($OldSVM):$($_.Name) to $($newClusterName):$($NewSVM):$($_.Name)")
116            $null = Invoke-NcSnapmirrorInitialize -SourceCluster $oldClusterName -SourceVserver $OldSVM -SourceVolume $_.Name -DestinationCluster $newClusterName -DestinationVserver $NewSVM -DestinationVolume $_.Name -Controller $newCluster
117        }
118
119        if(
120            ($snapmirror.MirrorState -eq "snapmirrored") -and
121            ($snapmirror.status -eq "idle") -and
122            ($snapmirror.IsHealthy) -and
123            ($oldSnapmirror = Get-NcSnapmirror -DestinationCluster $oldClusterName -Destination $_.Name -Controller $oldCluster) -and
124            ($peerVserver = Get-NcVserverPeer -Controller $oldCluster | Where-Object { 
125                                                                                        $_.PeerVserverUuid -eq $oldsnapmirror.SourceVserverUuid -and 
126                                                                                        $_.VserverUuid -eq $oldsnapmirror.DestinationVserverUuid 
127                                                                                     }
128            )
129        ){
130            Write-Host("Found healthy snapmirror for $($oldClusterName):$($OldSVM):$($_.Name), source cluster $($peerVserver.PeerCluster) - ready for cutover.")
131            $peerCluster = $peerVserver.PeerCluster
132            if(!($IPTable[$peerCluster])){
133                $IPTable[$peerCluster] = Read-Host -Prompt "Enter IP for: $peerCluster"
134            }
135            if(!($CredentialTable[$peerCluster])){
136                $CredentialTable[$peerCluster] = Get-Credential -Message "Enter Credentials for: $peerCluster" -UserName "admin"
137            }
138            if(!($ClusterTable[$peerCluster])){
139                $ClusterTable[$peerCluster] = Connect-NcController -HTTPS -Credential $CredentialTable[$peerCluster] -Name $IPTable[$peerCluster]
140            }
141            
142            if(Get-NcVol -Name $oldsnapmirror.SourceVolume -Vserver $oldSnapmirror.SourceVserver -Controller $ClusterTable[$peerCluster]){                          
143                Write-Host("Found healthy snapmirror for $($oldClusterName):$($OldSVM):$($_.Name), source cluster $($peerVserver.PeerCluster) - successfully validated volume on source cluster.")
144                $curVol = $_
145                if(!(Get-NcClusterPeer -Name $peerCluster -Controller $newCluster)){
146                    Write-Host -Object "Cluster Peering between $peerCluster and $newClusterName does not exist, please peer first!"
147                    break;
148                }
149
150                # Check if Destination SVM is peered with source vserver
151                if(!($peerrelationship = Get-NcVserverPeer -Vserver $peervserver.PeerVserver -PeerVserver $NewSVM -Controller $ClusterTable[$peerCluster] -Application "snapmirror")){
152                    Write-Host("Creating new vServer Peer Relationship for $($peerCluster):$($peervserver.PeerVserver) to $($newClusterName):$($NewSVM)")
153                    $peerrelationship = New-NcVserverPeer -Vserver $peervserver.PeerVserver -PeerVserver $NewSVM -Controller $ClusterTable[$peerCluster] -Application "snapmirror" -PeerCluster $newClusterName
154                }
155    
156                # Check if SVM Peer is unitialized
157                if($peerrelationship.PeerState -eq "initiated"){
158                    Write-Host("Confirming vServer Peer Relationship for $($peerCluster):$($peervserver.PeerVserver) to $($newClusterName):$($NewSVM)")
159                    $null = Confirm-NcVserverPeer -Vserver $NewSVM -PeerVserver $peervserver.PeerVserver -Controller $newCluster
160                }
161
162                # Stop replicating from source to old cluster
163                ## Quiesce Snapmirror on old cluster from source cluster
164                Write-Host("Quiscing Snapmirror from $($oldsnapmirror.SourceLocation) to $($oldsnapmirror.DestinationLocation)")
165                Invoke-NcSnapmirrorQuiesce -Destination $oldsnapmirror.DestinationLocation -Source $oldsnapmirror.SourceLocation -Controller $oldCluster  
166
167                # Break Relationship new cluster to old cluster                
168                ## Quiesce Snapmirror on new cluster from old cluster
169                Write-Host("Quiscing Snapmirror from $($snapmirror.SourceLocation) to $($snapmirror.DestinationLocation)")
170                Invoke-NcSnapmirrorQuiesce -Destination $snapmirror.DestinationLocation -Source $snapmirror.SourceLocation -Controller $newCluster                
171                
172                ## Break Snapmirror on new cluster from old cluster
173                Write-Host("Break Snapmirror from $($snapmirror.SourceLocation) to $($snapmirror.DestinationLocation)")
174                Invoke-NcSnapmirrorBreak -Destination $snapmirror.DestinationLocation -Source $snapmirror.SourceLocation -Controller $newCluster -Confirm:$false
175                
176                ## Delete Snapmirror on new cluster from old cluster
177                Remove-NcSnapmirror -Destination $snapmirror.DestinationLocation -Source $snapmirror.SourceLocation -Controller $newCluster -Confirm:$false
178                
179                ## Release Snapmirror on old cluster to new cluster
180                Invoke-NcSnapmirrorRelease -Source $snapmirror.SourceLocation -Destination $snapmirror.DestinationLocation -Controller $oldCluster -Confirm:$false                             
181
182                # Build Snapmirror to new cluster from source cluster and cleanup
183                ## Create new snapmirror
184                New-NcSnapmirror -Destination $snapmirror.DestinationLocation -Source $oldsnapmirror.SourceLocation -Schedule $oldsnapmirror.Schedule -Policy $oldsnapmirror.Policy -Controller $newCluster -Type $oldsnapmirror.PolicyType
185
186                ## Resync new snapmirror
187                Invoke-NcSnapmirrorResync -Destination $snapmirror.DestinationLocation -Source $oldsnapmirror.SourceLocation -Controller $newCluster -Confirm:$false
188                                
189                ## Break Snapmirror on old cluster from source cluster
190                Invoke-NcSnapmirrorRelease -Destination $oldsnapmirror.DestinationLocation -Source $oldsnapmirror.SourceLocation -Controller $ClusterTable[$peerCluster] -Confirm:$false
191                
192                ## Delete Snapmirror on old cluster from source cluster
193                Remove-NcSnapmirror -Destination $oldsnapmirror.DestinationLocation -Source $oldsnapmirror.SourceLocation -Controller $oldCluster -Confirm:$false
194
195                ## Add Volume to calculated blacklist
196                $calculatedBlacklist += $_.Name
197
198                Start-Sleep -Seconds 15
199            }
200        }
201    }
202}
203
204#endregion