Skip to content

Commit 007984e

Browse files
authoredOct 19, 2020
Merge pull request #27 from edvgui/improvement/api-call-timeout
Adding timeout capability to api_call
·
v1.9.0v1.1.2
2 parents 3a78334 + 4d3d143 commit 007984e

File tree

3 files changed

+25
-10
lines changed

3 files changed

+25
-10
lines changed
 

‎cpapi/api_exceptions.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,7 @@ class APIClientException(APIException):
1212
def __init__(self, value):
1313
APIException.__init__(self, value, None)
1414

15+
16+
class TimeoutException(APIException):
17+
def __init__(self, value):
18+
APIException.__init__(self, value, None)

‎cpapi/mgmt_api.py

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
import sys
1414

1515
# compatible import for python 2 and 3
16-
from .api_exceptions import APIException, APIClientException
16+
from .api_exceptions import APIException, APIClientException, TimeoutException
1717
from .api_response import APIResponse
1818
from cpapi.utils import get_massage_from_io_error, compatible_loads
1919

@@ -248,7 +248,7 @@ def login_as_root(self, domain=None, payload=None):
248248
except (WindowsError) as err:
249249
raise APIClientException("Could not login as root:\n" + str(type(err)) + " - " + str(err))
250250

251-
def api_call(self, command, payload=None, sid=None, wait_for_task=True):
251+
def api_call(self, command, payload=None, sid=None, wait_for_task=True, timeout=-1):
252252
"""
253253
performs a web-service API request to the management server
254254
@@ -260,9 +260,12 @@ def api_call(self, command, payload=None, sid=None, wait_for_task=True):
260260
and will not return until the task is completed.
261261
when wait_for_task=False, it is up to the user to call the "show-task" API and check
262262
the status of the command.
263+
:param timeout: Optional positive timeout (in seconds) before stop waiting for the task even if not completed.
263264
:return: APIResponse object
264265
:side-effects: updates the class's uid and server variables
265266
"""
267+
timeout_start = time.time()
268+
266269
self.check_fingerprint()
267270
if payload is None:
268271
payload = {}
@@ -351,9 +354,9 @@ def api_call(self, command, payload=None, sid=None, wait_for_task=True):
351354
# If we want to wait for the task to end, wait for it
352355
if wait_for_task is True and res.success and command != "show-task":
353356
if "task-id" in res.data:
354-
res = self.__wait_for_task(res.data["task-id"])
357+
res = self.__wait_for_task(res.data["task-id"], timeout=(timeout - time.time() + timeout_start))
355358
elif "tasks" in res.data:
356-
res = self.__wait_for_tasks(res.data["tasks"])
359+
res = self.__wait_for_tasks(res.data["tasks"], timeout=(timeout - time.time() + timeout_start))
357360

358361
return res
359362

@@ -478,7 +481,7 @@ def get_server_fingerprint(self):
478481
conn.close()
479482
return fingerprint_hash
480483

481-
def __wait_for_task(self, task_id):
484+
def __wait_for_task(self, task_id, timeout=-1):
482485
"""
483486
When the server needs to perform an API call that may take a long time (e.g. run-script, install-policy,
484487
publish), the server responds with a 'task-id'.
@@ -487,15 +490,22 @@ def __wait_for_task(self, task_id):
487490
The function will return when the task (and its sub-tasks) are no longer in-progress.
488491
489492
:param task_id: The task identifier.
493+
:param timeout: Optional positive timeout (in seconds) that will end the task even if not completed.
490494
:return: APIResponse object (response of show-task command).
491495
:raises APIException
492496
"""
493497
task_complete = False
494498
task_result = None
499+
task_start = time.time()
495500
in_progress = "in progress"
496501

497-
# As long as there is a task in progress
502+
# As long as there is a task in progress or the timeout isn't expired (and is positive)
498503
while not task_complete:
504+
505+
# If timeout parameter was set and valid and timeout did expire, raise exception
506+
if timeout >= 0 and time.time() - task_start > timeout:
507+
raise TimeoutException("Timeout reached when waiting for task to complete")
508+
499509
# Check the status of the task
500510
task_result = self.api_call("show-task", {"task-id": task_id, "details-level": "full"}, self.sid, False)
501511

@@ -526,21 +536,22 @@ def __wait_for_task(self, task_id):
526536
self.check_tasks_status(task_result)
527537
return task_result
528538

529-
def __wait_for_tasks(self, task_objects):
539+
def __wait_for_tasks(self, task_objects, timeout=-1):
530540
"""
531541
The version of __wait_for_task function for the collection of tasks
532542
533543
:param task_objects: A list of task objects
534544
:return: APIResponse object (response of show-task command).
535545
"""
546+
timeout_start = time.time()
536547

537548
# A list of task ids to be retrieved
538549
tasks = []
539550
for task_obj in task_objects:
540551
# Retrieve the taskId and wait for the task to be completed
541552
task_id = task_obj["task-id"]
542553
tasks.append(task_id)
543-
self.__wait_for_task(task_id)
554+
self.__wait_for_task(task_id, timeout=(timeout - time.time() + timeout_start))
544555

545556
task_result = self.api_call("show-task", {"task-id": tasks, "details-level": "full"},
546557
self.sid, False)
@@ -557,7 +568,7 @@ def check_tasks_status(task_result):
557568
:return:
558569
"""
559570
for task in task_result.data["tasks"]:
560-
if task["status"] == "failed" or task["status"] == "partially succeeded":
571+
if task["status"] == "failed" or task["status"] == "partially succeeded" or task["status"] == "in progress":
561572
task_result.set_success_status(False)
562573
break
563574

‎setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
setup(
55
name="cpapi",
6-
version="1.1.1",
6+
version="1.1.2",
77
author="API team",
88
author_email="api_team@checkpoint.com",
99
description="Check Point Management API SDK",

0 commit comments

Comments
 (0)
Please sign in to comment.