1
- ## The library contain common functions which are used for both single and group VM backup and restore.
1
+ """ The library contain common functions which are used for both single and group VM backup and restore. """
2
2
3
- ## The script can be run with Python 3.5 or higher version.
3
+ ## The script can be run with Python 3.6 or higher version.
4
4
5
- ## The script requires 'requests' library to make the API calls. The library can be installed using the command: pip install requests.
5
+ ## The script requires 'requests' library to make the API calls.
6
6
7
7
import json
8
8
import os
12
12
13
13
headers = {"Content-Type" : "application/vnd.netbackup+json;version=4.0" }
14
14
15
- # Get the base netbackup url
15
+ # Get the base NetBackup url
16
16
def get_nbu_base_url (host , port ):
17
+ """ This function return NetBackup base url """
17
18
port = f":{ str (port )} " if port else ''
18
19
baseurl = f"https://{ host } { port } /netbackup/"
19
20
return baseurl
20
21
21
- # Login to the netbackup and get the authorization token
22
+ # Login to the NetBackup and get the authorization token
22
23
def get_authenticate_token (baseurl , username , password ):
24
+ """ This function return token of NB master server """
23
25
creds = {'userName' :username , 'password' :password }
24
- url = baseurl + ' login'
26
+ url = f" { baseurl } login"
25
27
status_code , response_text = rest_request ('POST' , url , headers , data = creds )
26
28
validate_response (status_code , 201 , response_text )
27
29
token = response_text ['token' ]
28
30
return token
29
31
30
32
# Add vCenter credential
31
33
def add_vcenter_credential (baseurl , token , vcenter_server , vcenter_username , vcenter_password , vcenter_port , vcenter_server_type ):
32
- print (f"Add the vcenter credential:[{ vcenter_server } ]" )
33
- headers .update ({'Authorization' : token })
34
- url = baseurl + 'config/servers/vmservers'
35
- payload = {'serverName' :vcenter_server , 'vmType' :vcenter_server_type , 'userId' :vcenter_username , 'password' :vcenter_password , 'port' :vcenter_port }
34
+ """ This function add the vCenter into NBU master server """
35
+ print (f"Add the vCenter credential:[{ vcenter_server } ]" )
36
+ headers .update ({'Authorization' : token })
37
+ url = f"{ baseurl } config/servers/vmservers"
38
+ payload = {'serverName' :vcenter_server , 'vmType' :vcenter_server_type , 'userId' :vcenter_username ,\
39
+ 'password' :vcenter_password , 'port' :vcenter_port }
36
40
status_code , response_text = rest_request ('POST' , url , headers , data = payload )
37
41
validate_response (status_code , 201 , response_text )
38
- print (f"Vcenter credentials added successfully:[{ vcenter_server } ]" )
42
+ print (f"vCenter credentials added successfully:[{ vcenter_server } ]" )
39
43
40
44
# Get Vmware server discovery status
41
45
def get_vmware_discovery_status (baseurl , token , workload_type , vcenter_server ):
46
+ """ This function return the discovery status of vCenter server """
42
47
headers .update ({'Authorization' : token })
43
- url = baseurl + "admin/discovery/workloads/" + workload_type + "/status?filter=serverName eq '" + vcenter_server + "'"
48
+ url = f"{ baseurl } admin/discovery/workloads/{ workload_type } /status?" \
49
+ f"filter=serverName eq '{ vcenter_server } '"
44
50
status_code , response_text = rest_request ('GET' , url , headers )
45
51
validate_response (status_code , 200 , response_text )
46
52
discovery_status = response_text ['data' ][0 ]['attributes' ]['discoveryStatus' ]
47
53
return discovery_status
48
54
49
- # Get Vmware server discovery status
55
+ # Verify Vmware server discovery status
50
56
def verify_vmware_discovery_status (baseurl , token , workload_type , vcenter_server , timeout = 600 ):
51
- print (f"Wait for Vcenter Discovery :[{ vcenter_server } ]" )
57
+ """ This function verify the 'SUCESS' discovery status of vCenter """
58
+ print (f"Wait for vCenter Discovery :[{ vcenter_server } ]" )
52
59
discovery_status = ''
53
60
end_time = time .time () + timeout
54
61
while time .time () < end_time :
55
62
time .sleep (30 )
56
63
discovery_status = get_vmware_discovery_status (baseurl , token , workload_type , vcenter_server )
57
64
if discovery_status == 'SUCCESS' :
58
- print (f"Vcenter added successfully:[{ vcenter_server } ]" )
65
+ print (f"vCenter added successfully:[{ vcenter_server } ]" )
59
66
break
60
67
else :
61
- print (f"Failed to verify VCenter :[{ vcenter_server } ] discovery with status:[{ discovery_status } ]" )
68
+ print (f"Failed to verify vCenter :[{ vcenter_server } ] discovery with status:[{ discovery_status } ]" )
62
69
sys .exit (1 )
63
- print (f"Vcenter discovery successful:[{ vcenter_server } ] with status:[{ discovery_status } ]" )
70
+ print (f"vCenter discovery successful:[{ vcenter_server } ] with status:[{ discovery_status } ]" )
64
71
65
72
# Get asset info
66
73
def get_asset_info (baseurl , token , workload_type , client ):
74
+ """ This function return the asset info """
67
75
print (f"Get client asset info:[{ client } ]" )
68
76
headers .update ({'Authorization' : token })
69
- url = baseurl + "asset-service/workloads/" + workload_type + "/assets?filter=commonAssetAttributes/displayName eq '" + client + "'"
77
+ url = f"{ baseurl } asset-service/workloads/{ workload_type } /assets?" \
78
+ f"filter=commonAssetAttributes/displayName eq '{ client } '"
70
79
status_code , response_text = rest_request ('GET' , url , headers )
71
80
validate_response (status_code , 200 , response_text )
81
+
72
82
asset_id = response_text ['data' ][0 ]['id' ]
73
83
uuid = response_text ['data' ][0 ]['attributes' ]['instanceUuid' ]
74
84
exsi_host = response_text ['data' ][0 ]['attributes' ]['host' ]
85
+
75
86
print (f"Client asset Id:[{ asset_id } ]" )
76
87
print (f"Client uuid Id:[{ uuid } ]" )
77
88
print (f"Client exsi host:[{ exsi_host } ]" )
78
89
return asset_id , uuid , exsi_host
79
90
80
91
# Get StorageUnits
81
92
def get_storage_units (baseurl , token ):
93
+ """ This function return the storage unit name """
82
94
headers .update ({'Authorization' : token })
83
- url = baseurl + " storage/storage-units"
95
+ url = f" { baseurl } storage/storage-units"
84
96
status_code , response_text = rest_request ('GET' , url , headers )
85
97
validate_response (status_code , 200 , response_text )
86
98
storage_unit_name = response_text ['data' ][0 ]['id' ]
87
99
is_instant_access_enable = response_text ['data' ][0 ]['attributes' ]['instantAccessEnabled' ]
100
+
88
101
if is_instant_access_enable :
89
102
print (f"Storage unit:[{ storage_unit_name } ] enabled for instant access" )
90
- return storage_unit_name
91
103
else :
92
104
print (f"Storage unit:[{ storage_unit_name } ] disable for instant access" )
93
105
raise Exception (f"Storage unit:[{ storage_unit_name } ] disabled for instant access" )
106
+ return storage_unit_name
94
107
95
108
# Create protection plan
96
109
def create_protection_plan (baseurl , token , protection_plan_name , storage_unit_name ):
110
+ """ This function create the protection plan """
97
111
print (f"Create protection plan:[{ protection_plan_name } ]" )
98
112
headers .update ({'Authorization' : token })
99
- payload = {}
100
- url = baseurl + 'servicecatalog/slos?meta=accessControlId'
113
+ url = f"{ baseurl } servicecatalog/slos?meta=accessControlId"
101
114
102
115
cur_dir = os .path .dirname (os .path .abspath (__file__ ))
103
116
file_name = os .path .join (cur_dir , "create_protection_plan_template.json" )
104
- f = open (file_name )
105
- data = json .load (f )
117
+ file_handle = open (file_name )
118
+ data = json .load (file_handle )
106
119
data ['data' ]['attributes' ]['name' ] = protection_plan_name
107
120
data ['data' ]['attributes' ]['policyNamePrefix' ] = protection_plan_name
108
121
data ['data' ]['attributes' ]['schedules' ][0 ]['backupStorageUnit' ] = storage_unit_name
@@ -115,12 +128,14 @@ def create_protection_plan(baseurl, token, protection_plan_name, storage_unit_na
115
128
return protection_plan_id
116
129
117
130
# Subscription asset to SLO
118
- def subscription_asset_to_slo (baseurl , token , protection_plan_id , asset_id , is_vm_group = 0 ):
131
+ def subscription_asset_to_slo (baseurl , token , protection_plan_id , asset_id , is_vm_group = 0 ):
132
+ """ This function subscribe the asset/group asset to protection plan """
119
133
print (f"Subscribe client to protection plan id: [{ protection_plan_id } ]" )
120
134
headers .update ({'Authorization' : token })
121
- url = baseurl + " servicecatalog/slos/" + protection_plan_id + " /subscriptions"
135
+ url = f" { baseurl } servicecatalog/slos/{ protection_plan_id } /subscriptions"
122
136
selection_type = "ASSETGROUP" if is_vm_group else "ASSET"
123
- payload = {"data" : {"type" : "subscription" ,"attributes" : {"selectionType" : selection_type ,"selectionId" : asset_id }}}
137
+ payload = {"data" : {"type" : "subscription" , "attributes" : \
138
+ {"selectionType" : selection_type , "selectionId" : asset_id }}}
124
139
status_code , response_text = rest_request ('POST' , url , headers , data = payload )
125
140
validate_response (status_code , 201 , response_text )
126
141
subscription_id = response_text ['data' ]['id' ]
@@ -130,22 +145,25 @@ def subscription_asset_to_slo(baseurl, token, protection_plan_id, asset_id, is_v
130
145
131
146
# Get subscription
132
147
def get_subscription (baseurl , token , protection_plan_id , subscription_id ):
148
+ """ This function return the subscription info """
133
149
headers .update ({'Authorization' : token })
134
- url = baseurl + " servicecatalog/slos/" + protection_plan_id + " /subscriptions/" + subscription_id
150
+ url = f" { baseurl } servicecatalog/slos/{ protection_plan_id } /subscriptions/{ subscription_id } "
135
151
status_code , response_text = rest_request ('GET' , url , headers )
136
152
validate_response (status_code , 200 , response_text )
137
153
print (f"Sucessfully fetched the subscription:[{ subscription_id } ] details." )
138
-
154
+
139
155
# Get job details
140
156
def get_job_details (baseurl , token , jobid ):
157
+ """ This function return the job details """
141
158
headers .update ({'Authorization' : token })
142
- url = baseurl + " admin/jobs/" + str (jobid )
159
+ url = f" { baseurl } admin/jobs/{ str (jobid )} "
143
160
status_code , response_text = rest_request ('GET' , url , headers )
144
161
validate_response (status_code , 200 , response_text )
145
162
return response_text
146
163
147
164
# Verify given job state and status
148
165
def verify_job_state (baseurl , token , jobid , expected_state , expected_status = 0 , timeout = 1200 ):
166
+ """ This function verify the job status and state with expected status and state """
149
167
if jobid :
150
168
print (f"Wait for backup job to complete. Backup jobid:[{ jobid } ]" )
151
169
# Verify backup job status
@@ -158,7 +176,7 @@ def verify_job_state(baseurl, token, jobid, expected_state, expected_status=0, t
158
176
print (f"Job:[{ jobid } ] completed with expected state:[{ expected_state } ]" )
159
177
status = response_text ['data' ]['attributes' ]['status' ]
160
178
print (f"Actual status:[{ status } ] and expected status:[{ expected_status } ]" )
161
- if status == expected_status or status == 1 :
179
+ if status == expected_status :
162
180
print (f"Job:[{ jobid } ] completed with expected status:[{ expected_status } ]" )
163
181
break
164
182
else :
@@ -168,37 +186,40 @@ def verify_job_state(baseurl, token, jobid, expected_state, expected_status=0, t
168
186
print (f"Failed backup jobid:[{ jobid } ] with state:[{ state } ]" )
169
187
raise Exception (f"Failed backup jobid:[{ jobid } ] with state:[{ state } ]" )
170
188
171
-
172
-
173
189
# Remove protection plan
174
190
def remove_protectionplan (baseurl , token , protection_plan_id ):
191
+ """ This function remove the given protection plan """
175
192
if protection_plan_id :
176
193
headers .update ({'Authorization' : token })
177
- url = baseurl + ' servicecatalog/slos/' + protection_plan_id
194
+ url = f" { baseurl } servicecatalog/slos/{ protection_plan_id } "
178
195
status_code , response_text = rest_request ('DELETE' , url , headers )
179
- validate_response (status_code , 204 , response_text )
196
+ validate_response (status_code , 204 , response_text )
180
197
print (f"Successfully removed protection plan:[{ protection_plan_id } ]" )
181
198
182
199
# Remove vm subscription from protection plan
183
200
def remove_subscription (baseurl , token , protection_plan_id , subscription_id ):
201
+ """ This function remove subscription from protection plan """
184
202
if protection_plan_id and subscription_id :
185
203
headers .update ({'Authorization' : token })
186
- url = baseurl + ' servicecatalog/slos/' + protection_plan_id + ' /subscriptions/' + subscription_id
204
+ url = f" { baseurl } servicecatalog/slos/{ protection_plan_id } /subscriptions/{ subscription_id } "
187
205
status_code , response_text = rest_request ('DELETE' , url , headers )
188
- validate_response (status_code , 204 , response_text )
189
- print (f"Successfully removed asset subscription:[{ subscription_id } ] from protection plan:[{ protection_plan_id } ]" )
206
+ validate_response (status_code , 204 , response_text )
207
+ print (f"Successfully removed asset subscription:[{ subscription_id } ] " \
208
+ f"from protection plan:[{ protection_plan_id } ]" )
190
209
191
- # Remove vcenter creds from netbackup master
210
+ # Remove vCenter creds from NetBackup master
192
211
def remove_vcenter_creds (baseurl , token , vcenter_name ):
212
+ """ This function remove the vCenter from NBU master """
193
213
if vcenter_name :
194
214
headers .update ({'Authorization' : token })
195
- url = baseurl + ' config/servers/vmservers/' + vcenter_name
215
+ url = f" { baseurl } config/servers/vmservers/{ vcenter_name } "
196
216
status_code , response_text = rest_request ('DELETE' , url , headers )
197
217
validate_response (status_code , 204 , response_text )
198
- print (f"Successfully removed vcenter :[{ vcenter_name } ] credential " )
218
+ print (f"Successfully removed vCenter :[{ vcenter_name } ] from NBU master " )
199
219
200
220
# Execute REST API request
201
221
def rest_request (request_type , uri , header = None , ** kwargs ):
222
+ """ This function make call to the REST API """
202
223
session = requests .session ()
203
224
payload = kwargs .get ('data' )
204
225
if request_type == 'POST' :
@@ -233,17 +254,18 @@ def rest_request(request_type, uri, header=None, **kwargs):
233
254
except json .decoder .JSONDecodeError :
234
255
print (f"Could not parse json from [{ response_text } ]" )
235
256
236
- print (f"Sucessfully sent REST request:[{ uri } ]" )
257
+ print (f"Successfully sent REST request:[{ uri } ]" )
237
258
print (f"Status code:[{ response .status_code } ]" )
238
259
print (f"Response text:[{ response .text } ]" )
239
260
return response .status_code , response_text
240
261
262
+ # Validate the response code of the request
241
263
def validate_response (actual_status_code , expected_status_code , response_text ):
242
- # Validate the response code of the request
243
- if (actual_status_code == expected_status_code ):
244
- print (f"Sucessfully validate the response status code:[{ expected_status_code } ]" )
245
- return True
264
+ """ This function validate the response status code with expected response code """
265
+ if actual_status_code == expected_status_code :
266
+ print (f"Successfully validate the response status code:[{ expected_status_code } ]" )
246
267
else :
247
- print (f"Actual status code:[{ actual_status_code } ] not match with expected status code:[{ expected_status_code } ]" )
248
- raise Exception (f"Response Error:[{ response_text ['errorMessage' ]} ] and details:[{ response_text ['errorDetails' ]} ]" )
249
- return False
268
+ print (f"Actual status code:[{ actual_status_code } ] not match " \
269
+ f"with expected status code:[{ expected_status_code } ]" )
270
+ raise Exception (f"Response Error:[{ response_text ['errorMessage' ]} ] and " \
271
+ f"details:[{ response_text ['errorDetails' ]} ]" )
0 commit comments