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