Skip to content

Commit 592a2a9

Browse files
authored
Create copy-replica-pgsnap.py
1 parent 43ee5c1 commit 592a2a9

File tree

1 file changed

+142
-0
lines changed

1 file changed

+142
-0
lines changed

copy-replica-pgsnap.py

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
#!/usr/bin/env python
2+
# Copyright (c) 2018 Pure Storage, Inc.
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""
16+
Simple python program for restoring locally on the target FlashArray the volumes contained
17+
in a replica protection group. This action is particularly useful for a rapid restore
18+
in a disaster recovery situation.
19+
A temporary protection group is created on the FlashArray to host the volumes in order
20+
to perform a copy of the protection group snapshot. The temporary volumes is deleted and
21+
eradicated immediately after.
22+
"""
23+
24+
from __future__ import print_function
25+
26+
__author__ = "Eugenio Grosso"
27+
__copyright__ = "Copyright 2018, Pure Storage Inc."
28+
__credits__ = ""
29+
__license__ = "Apache v2.0"
30+
__version__ = "0.1"
31+
__maintainer__ = "Eugenio Grosso"
32+
__email__ = "geneg@purestorage.com"
33+
__status__ = "Development"
34+
35+
36+
import purestorage
37+
import urllib3
38+
import argparse
39+
40+
41+
def parse_args():
42+
argp = argparse.ArgumentParser()
43+
argp.add_argument('-e','--endpoint',
44+
required=True,
45+
action='store',
46+
help="FA hostname or ip address")
47+
argp.add_argument('-t','--apitoken',
48+
required=True,
49+
action='store',
50+
help="FA api_token")
51+
argp.add_argument('-s','--suffix',
52+
required=False,
53+
action='store',
54+
help="Protection group snapshot to restore on this FA. If you specify just the pgname then the most recent snapshot is used.")
55+
argp.add_argument('-p','--pgroup',
56+
required=True,
57+
action='store',
58+
help="Protection group to create/overwrite on this FA")
59+
return argp.parse_args()
60+
61+
62+
def main():
63+
64+
# Key function to retrieve the most recent snapshot
65+
def return_created(elem):
66+
return elem['created']
67+
68+
args = parse_args()
69+
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
70+
71+
vol_list = []
72+
vol_hg_list = []
73+
fainfo = {}
74+
pgsnap = args.pgroup
75+
76+
if args.suffix:
77+
pgsnap = pgroup + '.' + args.suffix
78+
79+
try:
80+
fa = purestorage.FlashArray(args.endpoint, api_token=args.apitoken)
81+
# Retrieve existing volumes already created from
82+
# the same protection group snapshot
83+
fainfo = fa.get_pgroup(args.pgroup)
84+
pgvol = fainfo['volumes']
85+
volumes = fa.list_volumes()
86+
for pv in pgvol:
87+
for v in volumes:
88+
if v['source'] == pv:
89+
vol_list.append(v['name'])
90+
break
91+
# Create temporay protection group to store
92+
# volumes
93+
tmp_pgroup = args.pgroup.split(':')[1] + '---tmp'
94+
fainfo = fa.list_pgroups()
95+
for pg in fainfo:
96+
if pg['name'] == tmp_pgroup:
97+
fa.destroy_pgroup(tmp_pgroup)
98+
fa.eradicate_pgroup(tmp_pgroup)
99+
break
100+
101+
fa.create_pgroup(tmp_pgroup)
102+
for v in vol_list:
103+
fa.add_volume(v, tmp_pgroup)
104+
105+
# Disconnect host group from target volumes.
106+
# This is required for the copy over to succeed
107+
for vol in vol_list:
108+
sh_conn = fa.list_volume_shared_connections(vol)
109+
if not sh_conn:
110+
continue
111+
vol_hg_list.append({'name': sh_conn[0]['name'],
112+
'lun': sh_conn[0]['lun'],
113+
'hgroup': sh_conn[0]['hgroup']})
114+
fa.disconnect_hgroup(sh_conn[0]['hgroup'], vol)
115+
print("Volume '" + vol + "' disconnected from host group '" + sh_conn[0]['hgroup'] + "'")
116+
117+
# Retrieve the most recent snapshot. If the full name of as snapshot is provided
118+
# this search returns the very same name
119+
fainfo = fa.get_pgroup(pgsnap, snap=True)
120+
snap_sorted = sorted(fainfo, key=return_created, reverse=True)
121+
pgsnap = snap_sorted[0]['name']
122+
123+
fa.create_pgroup(tmp_pgroup, source=pgsnap, overwrite=True)
124+
fa.destroy_pgroup(tmp_pgroup)
125+
fa.eradicate_pgroup(tmp_pgroup)
126+
print("Recovered volumes using pg snapshot '" + pgsnap + "'")
127+
128+
except purestorage.PureError as e:
129+
print(e)
130+
return (-1)
131+
finally:
132+
# Reconnect volumes if we disconnected them before
133+
for vol in vol_hg_list:
134+
fa.connect_hgroup(vol['hgroup'], vol['name'], lun = vol['lun'])
135+
print("Volume '" + vol['name'] + "' reconnected to hostgroup '" + vol['hgroup'] + "'")
136+
137+
fa.invalidate_cookie()
138+
139+
140+
if __name__ == '__main__':
141+
main()
142+

0 commit comments

Comments
 (0)