Skip to content

Commit 0e1022c

Browse files
committed
Increase timeout for commands to a default of 60 seconds
Ensure a valid message is sent back to the user if a dynamic restore fails If git checkout times out, cancel the restore attempt
1 parent eef9131 commit 0e1022c

File tree

6 files changed

+208
-182
lines changed

6 files changed

+208
-182
lines changed

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,11 @@ To do this you will need to install Version Control For SplunkCloud on your Splu
261261
[SplunkVersionControlCloud github](https://github.com/gjanders/SplunkVersionControlCloud)
262262

263263
## Release Notes
264+
### 1.1.7
265+
Increase timeout for commands to a default of 60 seconds
266+
Ensure a valid message is sent back to the user if a dynamic restore fails
267+
If git checkout times out, cancel the restore attempt
268+
264269
### 1.1.6
265270
Allow the backup process to run on search head clusters for those that wish to do this...
266271

SplunkVersionControl.tgz

257 Bytes
Binary file not shown.

bin/splunkversioncontrol_rest_restore.py

Lines changed: 35 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
'maxBytes' : 2097152,
3838
'level': logging.DEBUG,
3939
'backupCount' : 5 }
40-
},
40+
},
4141
root = {
4242
'handlers': ['h','file'],
4343
'level': logging.DEBUG,
@@ -64,7 +64,7 @@ def handle_POST(self):
6464
payload = six.moves.urllib.parse.parse_qs(self.request['payload'])
6565
#self.response.write(str(payload) + "\n")
6666
#currently we only receive the Splunk authorization key, so obtain that
67-
67+
6868
req_attributes = ['Authorization', 'splunk_vc_name', 'app', 'type', 'obj_name', 'tag', 'scope', 'timeout' ]
6969
for attr in req_attributes:
7070
if attr not in payload:
@@ -74,49 +74,49 @@ def handle_POST(self):
7474
logger.error("Received remote call but attr=%s was missing from arguments, received=\"%s\"" % (attr, payload))
7575
self.response.write("Received remote call but attr=%s was missing from arguments, received=\"%s\"" % (attr, payload))
7676
return
77-
77+
7878
headers = { "Authorization" : payload['Authorization'][0] }
7979

8080
#Run a query back against the source system to check the username/role
8181
remoteAddr = self.request['remoteAddr']
8282
url = "https://" + remoteAddr + ":8089/services/authentication/current-context?output_mode=json"
8383
logger.info("Received remote request checking username and role related to the token on url=%s" % (url))
8484
logger.debug("token=%s" % (payload['Authorization'][0]))
85-
85+
8686
res = self.runHttpRequest(url, headers, None, "get", "checking username with token (based on incoming ip address)")
8787
if not res:
8888
return
89-
90-
json_dict = json.loads(res.text)
89+
90+
json_dict = json.loads(res.text)
9191
#self.response.write(str(json_dict) + "\n\n\n")
9292
username = json_dict['entry'][0]['content']['username']
9393
roles = json_dict['entry'][0]['content']['roles']
9494

9595
#self.response.write(username + "\n")
9696
#self.response.write(str(roles) + "\n")
9797
logger.info("username=%s roles=%s" % (username, roles))
98-
98+
9999
splunk_vc_name = payload['splunk_vc_name'][0]
100100
#self.response.write(splunk_vc_name + "\n\n\n")
101-
101+
102102
#Now run queries locally to check if the mentioned config matches an existing backup name
103103
headers = { "Authorization" : "Splunk " + self.request['systemAuth'] }
104104
url = "https://localhost:8089/servicesNS/-/-/data/inputs/splunkversioncontrol_restore/" + six.moves.urllib.parse.quote(splunk_vc_name) + "?output_mode=json"
105105
logger.debug("Now running query against url=%s to obtain config information" % (url))
106-
106+
107107
res = self.runHttpRequest(url, headers, None, "get", "querying the inputs for splunkversioncontrol_restore with name %s" % (splunk_vc_name))
108108
if not res:
109109
return
110-
110+
111111
#Look under the entry/content section for the relevant information we require, mainly destURL, useLocalAuth and potentially destUsername/destPassword
112112
json_dict = json.loads(res.text)['entry'][0]['content']
113113
#self.response.write(str(json_dict) + "\n\n\n")
114-
114+
115115
useLocalAuth = False
116116
if 'useLocalAuth' in json_dict:
117117
if json_dict['useLocalAuth'].lower() == 't' or json_dict['useLocalAuth'].lower() == "true":
118118
useLocalAuth = True
119-
119+
120120
if not useLocalAuth:
121121
if not 'destUsername' in json_dict or not 'destPassword' in json_dict or not 'destURL' in json_dict:
122122
logger.error("Missing one of destUsername, destPassword or destURL from the splunk version control restore stanza, and useLocalAuth is not true, invalid configuration")
@@ -125,7 +125,7 @@ def handle_POST(self):
125125
destUsername = json_dict['destUsername']
126126
destPassword = json_dict['destPassword']
127127
if destPassword.find("password:") == 0:
128-
destPassword = get_password(destPassword[9:], self.request['systemAuth'], logger)
128+
destPassword = get_password(destPassword[9:], self.request['systemAuth'], logger)
129129
else:
130130
if not 'destURL' in json_dict:
131131
logger.error("Missing one of destURL from the splunk version control restore stanza, invalid configuration")
@@ -136,7 +136,7 @@ def handle_POST(self):
136136

137137
headers = {}
138138
auth = None
139-
139+
140140
if useLocalAuth:
141141
headers = { "Authorization" : "Splunk " + self.request['systemAuth'] }
142142
else:
@@ -154,30 +154,30 @@ def handle_POST(self):
154154
logger.warn("Time wait value of %s is invalid, not an integer, defaulting to 600 seconds" % (json_dict['timewait']))
155155
time_wait = 600
156156
else:
157-
time_wait = 600
158-
157+
time_wait = 600
158+
159159
app = payload['app'][0]
160160
type = payload['type'][0]
161161
obj_name = payload['obj_name'][0]
162162
tag = payload['tag'][0]
163163
timeout = payload['timeout'][0]
164-
164+
165165
if not 'restoreAsUser' in payload:
166166
restoreAsUser = ''
167167
else:
168168
restoreAsUser = payload['restoreAsUser'][0]
169169
scope = payload['scope'][0]
170-
170+
171171
logger.debug("Converting timeout of argument %s to integer" % timeout)
172172
timeout = int(timeout)
173173
#We need a little bit of time to index the _audit event that literally just happened
174174
#a 30 second delay is annoying but it appears to work...hardcoding this for now
175175
logger.info("Sleeping for %s seconds to wait for audit logs" % (timeout))
176176
time.sleep(timeout)
177177
logger.info("Sleep completed")
178-
178+
179179
starttime = starttime-60-timeout
180-
180+
181181
json_res = self.runSearchJob(destURL, remoteAppName, headers, auth, username, starttime)
182182

183183
if 'error' in json_res:
@@ -202,8 +202,8 @@ def handle_POST(self):
202202
url = "https://localhost:8089/servicesNS/nobody/SplunkVersionControl/storage/collections/data/splunkversioncontrol_rest_restore_status"
203203
res = self.runHttpRequest(url, headers, None, "get", "checking kvstore collection splunkversioncontrol_rest_restore_status")
204204
if not res:
205-
return
206-
205+
return
206+
207207
res = json.loads(res.text)
208208
#An empty list is good in this case, we are safe to run, if not we have checks to do
209209
if not len(res) == 0:
@@ -223,37 +223,37 @@ def handle_POST(self):
223223
self.response.write("Attempted to run but found a running restore instance with time %s and current time is %s, will delete and move on after current time minus %s seconds (which would be %s) " % (kvstore_start_time, curtime, time_wait, removal_target))
224224
self.response.write("Please try your restore request again in a minute...")
225225
return
226-
226+
227227
payload = json.dumps({ 'start_time': curtime })
228228
headers['Content-Type'] = 'application/json'
229229
#update kvstore with runtime
230230
res = self.runHttpRequest(url, headers, payload, 'post', 'updating kvstore collection splunkversioncontrol_rest_restore_status')
231231
if not res:
232232
return res
233-
234-
result = svc_restore_obj.run_script(resList, json_dict)
235-
if result:
233+
234+
(result, message) = svc_restore_obj.run_script(resList, json_dict)
235+
if result == True:
236236
self.response.write("Restore has completed successfully in app %s, object of type %s, with name %s was restored from tag %s, scope %s with restoreAsUser %s and your username of %s" % (app, type, obj_name, tag, scope, restoreAsUser, username))
237237
logger.info("Restore has completed successfully in app=%s, object of type=%s, with name=%s was restored from tag=%s, scope=%s with restoreAsUser=%s and requested by username=%s" % (app, type, obj_name, tag, scope, restoreAsUser, username))
238238
else:
239-
self.response.write("Restore has failed to complete successfully in app %s, object of type %s, with name %s was not restored from tag %s, scope %s with restoreAsUser %s and your username of %s" % (app, type, obj_name, tag, scope, restoreAsUser, username))
240-
logger.warn("Restore has failed to complete successfully in app=%s, object of type=%s, with name=%s was not restored from tag=%s, scope=%s with restoreAsUser=%s and requested by username=%s" % (app, type, obj_name, tag, scope, restoreAsUser, username))
241-
239+
self.response.write("Restore has failed to complete successfully in app %s, object of type %s, with name %s, from tag %s, scope %s with restoreAsUser %s and your username of %s. Message is %s" % (app, type, obj_name, tag, scope, restoreAsUser, username, message))
240+
logger.warn("Restore has failed to complete successfully in app=%s, object of type=%s, with name=%s, from tag=%s, scope=%s with restoreAsUser=%s and requested by username=%s, message=%s" % (app, type, obj_name, tag, scope, restoreAsUser, username, message))
241+
242242
self.runHttpRequest(url, headers, None, 'delete', 'wiping kvstore splunkversioncontrol_rest_restore_status after completed run')
243-
243+
244244
#Run a Splunk query via the search/jobs endpoint
245245
def runSearchJob(self, url, appname, headers, auth, username, earliest_time):
246246
url = url + "/servicesNS/-/%s/search/jobs" % (appname)
247247
query = "savedsearch \"Splunk Version Control Audit Query POST\" username=\"%s\" | stats count | where count>0" % (username)
248248
logger.debug("Running requests.post() on url=%s query=\"%s\"" % (url, query))
249249
data = { "search" : query, "output_mode" : "json", "exec_mode" : "oneshot", "earliest_time" : earliest_time }
250-
250+
251251
res = requests.post(url, auth=auth, headers=headers, verify=False, data=data)
252252
if (res.status_code != requests.codes.ok):
253253
logger.error("url=%s status_code=%s reason=%s, response=\"%s\"" % (url, res.status_code, res.reason, res.text))
254-
return { "error": "url=%s status_code=%s reason=%s, response=\"%s\"" % (url, res.status_code, res.reason, res.text) }
254+
return { "error": "url=%s status_code=%s reason=%s, response=\"%s\"" % (url, res.status_code, res.reason, res.text) }
255255
res = json.loads(res.text)
256-
256+
257257
#Log return messages from Splunk, often these advise of an issue but not always...
258258
if len(res["messages"]) > 0:
259259
firstMessage = res["messages"][0]
@@ -271,10 +271,10 @@ def runHttpRequest(self, url, headers, data, type, text):
271271
res = requests.post(url, headers=headers, verify=False, data=data)
272272
elif type == "get":
273273
res = requests.get(url, headers=headers, verify=False)
274-
274+
275275
if (res.status_code != requests.codes.ok and res.status_code != 201):
276276
logger.error("Unexpected response code while %s, on url=%s, statuscode=%s reason=%s, response=\"%s\", payload=\"%s\"" % (text, url, res.status_code, res.reason, res.text, data))
277277
self.response.write("Error unexpected response code while %s, on url %s, statuscode %s reason %s, response \"%s\", payload=\"%s\"" % (text, url, res.status_code, res.reason, res.text, data))
278278
return
279-
279+
280280
return res

0 commit comments

Comments
 (0)