cloudos-cli 2.19.1__tar.gz → 2.20.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. {cloudos_cli-2.19.1 → cloudos_cli-2.20.0}/PKG-INFO +19 -1
  2. {cloudos_cli-2.19.1 → cloudos_cli-2.20.0}/README.md +18 -0
  3. {cloudos_cli-2.19.1 → cloudos_cli-2.20.0}/cloudos_cli/__main__.py +69 -1
  4. cloudos_cli-2.20.0/cloudos_cli/_version.py +1 -0
  5. {cloudos_cli-2.19.1 → cloudos_cli-2.20.0}/cloudos_cli/clos.py +29 -1
  6. {cloudos_cli-2.19.1 → cloudos_cli-2.20.0}/cloudos_cli/utils/requests.py +34 -0
  7. {cloudos_cli-2.19.1 → cloudos_cli-2.20.0}/cloudos_cli.egg-info/PKG-INFO +19 -1
  8. {cloudos_cli-2.19.1 → cloudos_cli-2.20.0}/cloudos_cli.egg-info/SOURCES.txt +1 -0
  9. cloudos_cli-2.20.0/tests/test_clos/test_abort_job.py +68 -0
  10. cloudos_cli-2.19.1/cloudos_cli/_version.py +0 -1
  11. {cloudos_cli-2.19.1 → cloudos_cli-2.20.0}/LICENSE +0 -0
  12. {cloudos_cli-2.19.1 → cloudos_cli-2.20.0}/cloudos_cli/__init__.py +0 -0
  13. {cloudos_cli-2.19.1 → cloudos_cli-2.20.0}/cloudos_cli/jobs/__init__.py +0 -0
  14. {cloudos_cli-2.19.1 → cloudos_cli-2.20.0}/cloudos_cli/jobs/job.py +0 -0
  15. {cloudos_cli-2.19.1 → cloudos_cli-2.20.0}/cloudos_cli/queue/__init__.py +0 -0
  16. {cloudos_cli-2.19.1 → cloudos_cli-2.20.0}/cloudos_cli/queue/queue.py +0 -0
  17. {cloudos_cli-2.19.1 → cloudos_cli-2.20.0}/cloudos_cli/utils/__init__.py +0 -0
  18. {cloudos_cli-2.19.1 → cloudos_cli-2.20.0}/cloudos_cli/utils/errors.py +0 -0
  19. {cloudos_cli-2.19.1 → cloudos_cli-2.20.0}/cloudos_cli.egg-info/dependency_links.txt +0 -0
  20. {cloudos_cli-2.19.1 → cloudos_cli-2.20.0}/cloudos_cli.egg-info/entry_points.txt +0 -0
  21. {cloudos_cli-2.19.1 → cloudos_cli-2.20.0}/cloudos_cli.egg-info/requires.txt +0 -0
  22. {cloudos_cli-2.19.1 → cloudos_cli-2.20.0}/cloudos_cli.egg-info/top_level.txt +0 -0
  23. {cloudos_cli-2.19.1 → cloudos_cli-2.20.0}/setup.cfg +0 -0
  24. {cloudos_cli-2.19.1 → cloudos_cli-2.20.0}/setup.py +0 -0
  25. {cloudos_cli-2.19.1 → cloudos_cli-2.20.0}/tests/__init__.py +0 -0
  26. {cloudos_cli-2.19.1 → cloudos_cli-2.20.0}/tests/functions_for_pytest.py +0 -0
  27. {cloudos_cli-2.19.1 → cloudos_cli-2.20.0}/tests/test_clos/__init__.py +0 -0
  28. {cloudos_cli-2.19.1 → cloudos_cli-2.20.0}/tests/test_clos/test_create_cromwell_header.py +0 -0
  29. {cloudos_cli-2.19.1 → cloudos_cli-2.20.0}/tests/test_clos/test_cromwell_switch.py +0 -0
  30. {cloudos_cli-2.19.1 → cloudos_cli-2.20.0}/tests/test_clos/test_detect_workflow.py +0 -0
  31. {cloudos_cli-2.19.1 → cloudos_cli-2.20.0}/tests/test_clos/test_get_cromwell_status.py +0 -0
  32. {cloudos_cli-2.19.1 → cloudos_cli-2.20.0}/tests/test_clos/test_get_curated_workflow_list.py +0 -0
  33. {cloudos_cli-2.19.1 → cloudos_cli-2.20.0}/tests/test_clos/test_get_job_list.py +0 -0
  34. {cloudos_cli-2.19.1 → cloudos_cli-2.20.0}/tests/test_clos/test_get_job_status.py +0 -0
  35. {cloudos_cli-2.19.1 → cloudos_cli-2.20.0}/tests/test_clos/test_get_project_list.py +0 -0
  36. {cloudos_cli-2.19.1 → cloudos_cli-2.20.0}/tests/test_clos/test_get_user_info.py +0 -0
  37. {cloudos_cli-2.19.1 → cloudos_cli-2.20.0}/tests/test_clos/test_get_workflow_list.py +0 -0
  38. {cloudos_cli-2.19.1 → cloudos_cli-2.20.0}/tests/test_clos/test_is_module.py +0 -0
  39. {cloudos_cli-2.19.1 → cloudos_cli-2.20.0}/tests/test_clos/test_process_job_list.py +0 -0
  40. {cloudos_cli-2.19.1 → cloudos_cli-2.20.0}/tests/test_clos/test_process_project_list.py +0 -0
  41. {cloudos_cli-2.19.1 → cloudos_cli-2.20.0}/tests/test_clos/test_process_workflow_list.py +0 -0
  42. {cloudos_cli-2.19.1 → cloudos_cli-2.20.0}/tests/test_clos/test_wait_job_completion.py +0 -0
  43. {cloudos_cli-2.19.1 → cloudos_cli-2.20.0}/tests/test_clos/test_workflow_import.py +0 -0
  44. {cloudos_cli-2.19.1 → cloudos_cli-2.20.0}/tests/test_jobs/__init__.py +0 -0
  45. {cloudos_cli-2.19.1 → cloudos_cli-2.20.0}/tests/test_jobs/test_convert_nextflow_to_json.py +0 -0
  46. {cloudos_cli-2.19.1 → cloudos_cli-2.20.0}/tests/test_jobs/test_project_id.py +0 -0
  47. {cloudos_cli-2.19.1 → cloudos_cli-2.20.0}/tests/test_jobs/test_send_job.py +0 -0
  48. {cloudos_cli-2.19.1 → cloudos_cli-2.20.0}/tests/test_jobs/test_workflow_id.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cloudos_cli
3
- Version: 2.19.1
3
+ Version: 2.20.0
4
4
  Summary: Python package for interacting with CloudOS
5
5
  Home-page: https://github.com/lifebit-ai/cloudos-cli
6
6
  Author: David Piñeyro
@@ -329,6 +329,24 @@ Executing run...
329
329
  Your job took 420 seconds to complete successfully.
330
330
  ```
331
331
 
332
+ #### Abort single or multiple jobs from CloudOS
333
+
334
+ Aborts jobs in the CloudOS workspace that are either running or initialising. It can be used with one or more job IDs provided as a comma separated string using the `--job-ids` parameter.
335
+
336
+ Example:
337
+ ```console
338
+ cloudos job abort \
339
+ --cloudos-url $CLOUDOS \
340
+ --apikey $MY_API_KEY \
341
+ --workspace-id $WORKSPACE_ID \
342
+ --job-ids "680a3cf80e56949775c02f16"
343
+
344
+
345
+ Aborting jobs...
346
+ Job 680a3cf80e56949775c02f16 aborted successfully.
347
+ ```
348
+
349
+
332
350
  #### Executor support
333
351
 
334
352
  CloudOS supports [AWS batch](https://www.nextflow.io/docs/latest/executor.html?highlight=executors#aws-batch) executor by default.
@@ -294,6 +294,24 @@ Executing run...
294
294
  Your job took 420 seconds to complete successfully.
295
295
  ```
296
296
 
297
+ #### Abort single or multiple jobs from CloudOS
298
+
299
+ Aborts jobs in the CloudOS workspace that are either running or initialising. It can be used with one or more job IDs provided as a comma separated string using the `--job-ids` parameter.
300
+
301
+ Example:
302
+ ```console
303
+ cloudos job abort \
304
+ --cloudos-url $CLOUDOS \
305
+ --apikey $MY_API_KEY \
306
+ --workspace-id $WORKSPACE_ID \
307
+ --job-ids "680a3cf80e56949775c02f16"
308
+
309
+
310
+ Aborting jobs...
311
+ Job 680a3cf80e56949775c02f16 aborted successfully.
312
+ ```
313
+
314
+
297
315
  #### Executor support
298
316
 
299
317
  CloudOS supports [AWS batch](https://www.nextflow.io/docs/latest/executor.html?highlight=executors#aws-batch) executor by default.
@@ -24,6 +24,7 @@ HPC_NEXTFLOW_VERSIONS = ['22.10.8']
24
24
  AWS_NEXTFLOW_LATEST = '24.04.4'
25
25
  AZURE_NEXTFLOW_LATEST = '22.11.1-edge'
26
26
  HPC_NEXTFLOW_LATEST = '22.10.8'
27
+ ABORT_JOB_STATES = ['running', 'initializing']
27
28
 
28
29
 
29
30
  def ssl_selector(disable_ssl_verification, ssl_cert):
@@ -68,7 +69,7 @@ def run_cloudos_cli():
68
69
 
69
70
  @run_cloudos_cli.group()
70
71
  def job():
71
- """CloudOS job functionality: run and check jobs in CloudOS."""
72
+ """CloudOS job functionality: run, check and abort jobs in CloudOS."""
72
73
  print(job.__doc__ + '\n')
73
74
 
74
75
 
@@ -859,6 +860,73 @@ def list_jobs(apikey,
859
860
  print(f'\tJob list saved to {outfile}')
860
861
 
861
862
 
863
+ @job.command('abort')
864
+ @click.option('-k',
865
+ '--apikey',
866
+ help='Your CloudOS API key',
867
+ required=True)
868
+ @click.option('-c',
869
+ '--cloudos-url',
870
+ help=('The CloudOS url you are trying to access to. ' +
871
+ 'Default=https://cloudos.lifebit.ai.'),
872
+ default='https://cloudos.lifebit.ai')
873
+ @click.option('--workspace-id',
874
+ help='The specific CloudOS workspace id.',
875
+ required=True)
876
+ @click.option('--job-ids',
877
+ help=('One or more job ids to abort. If more than ' +
878
+ 'one is provided, they must be provided as ' +
879
+ 'a comma separated list of ids. E.g. id1,id2,id3'),
880
+ required=True)
881
+ @click.option('--verbose',
882
+ help='Whether to print information messages or not.',
883
+ is_flag=True)
884
+ @click.option('--disable-ssl-verification',
885
+ help=('Disable SSL certificate verification. Please, remember that this option is ' +
886
+ 'not generally recommended for security reasons.'),
887
+ is_flag=True)
888
+ @click.option('--ssl-cert',
889
+ help='Path to your SSL certificate file.')
890
+ def abort_jobs(apikey,
891
+ cloudos_url,
892
+ workspace_id,
893
+ job_ids,
894
+ verbose,
895
+ disable_ssl_verification,
896
+ ssl_cert):
897
+ """Abort all specified jobs from a CloudOS workspace."""
898
+ cloudos_url = cloudos_url.rstrip('/')
899
+ verify_ssl = ssl_selector(disable_ssl_verification, ssl_cert)
900
+ print('Aborting jobs...')
901
+ if verbose:
902
+ print('\t...Preparing objects')
903
+ cl = Cloudos(cloudos_url, apikey, None)
904
+ if verbose:
905
+ print('\tThe following Cloudos object was created:')
906
+ print('\t' + str(cl) + '\n')
907
+ print('\tSearching for jobs in the following workspace: ' +
908
+ f'{workspace_id}')
909
+ # check if the user provided an empty job list
910
+ jobs = job_ids.replace(' ', '')
911
+ if not jobs:
912
+ raise ValueError('No job IDs provided. Please specify at least one job ID to abort.')
913
+ jobs = jobs.split(',')
914
+
915
+ for job in jobs:
916
+ try:
917
+ j_status = cl.get_job_status(job, verify_ssl)
918
+ except Exception as e:
919
+ print(f"[WARNING] Failed to get status for job {job}, please make sure it exists in the workspace: {e}")
920
+ continue
921
+ j_status_content = json.loads(j_status.content)
922
+ # check if job id is valid & is in working state (initial, running)
923
+ if j_status_content['status'] not in ABORT_JOB_STATES:
924
+ print(f"[WARNING] Job {job} is not in a state that can be aborted and is ignored. Current status: {j_status_content['status']}")
925
+ else:
926
+ cl.abort_job(job, workspace_id, verify_ssl)
927
+ print(f"\tJob '{job}' aborted successfully.")
928
+
929
+
862
930
  @workflow.command('list')
863
931
  @click.option('-k',
864
932
  '--apikey',
@@ -0,0 +1 @@
1
+ __version__ = '2.20.0'
@@ -7,7 +7,7 @@ import time
7
7
  import json
8
8
  from dataclasses import dataclass
9
9
  from cloudos_cli.utils.errors import BadRequestException
10
- from cloudos_cli.utils.requests import retry_requests_get, retry_requests_post
10
+ from cloudos_cli.utils.requests import retry_requests_get, retry_requests_post, retry_requests_put
11
11
  import pandas as pd
12
12
 
13
13
  # GLOBAL VARS
@@ -757,3 +757,31 @@ class Cloudos:
757
757
  if r.status_code >= 400:
758
758
  raise BadRequestException(r)
759
759
  return json.loads(r.content)
760
+
761
+ def abort_job(self, job, workspace_id, verify=True):
762
+ """Abort a job.
763
+
764
+ Parameters
765
+ ----------
766
+ job : string
767
+ The CloudOS job id of the job to abort.
768
+ verify: [bool|string]
769
+ Whether to use SSL verification or not. Alternatively, if
770
+ a string is passed, it will be interpreted as the path to
771
+ the SSL certificate file.
772
+
773
+ Returns
774
+ -------
775
+ r : requests.models.Response
776
+ The server response
777
+ """
778
+ cloudos_url = self.cloudos_url
779
+ apikey = self.apikey
780
+ headers = {
781
+ "Content-type": "application/json",
782
+ "apikey": apikey
783
+ }
784
+ r = retry_requests_put("{}/api/v1/jobs/{}/abort?teamId={}".format(cloudos_url, job, workspace_id), headers=headers, verify=verify)
785
+ if r.status_code >= 400:
786
+ raise BadRequestException(r)
787
+ return r
@@ -73,3 +73,37 @@ def retry_requests_post(url, total=5, status_forcelist=[429, 500, 502, 503, 504]
73
73
  # Make a request using the session object
74
74
  response = session.post(url, **kwargs)
75
75
  return response
76
+
77
+
78
+ def retry_requests_put(url, total=5, status_forcelist=[429, 500, 502, 503, 504], **kwargs):
79
+ """Wrap normal requests put with an error strategy.
80
+
81
+ Parameters
82
+ ----------
83
+ url : string
84
+ The request URL
85
+ total : int
86
+ Total number of retries
87
+ status_forcelist : list
88
+ A list of ints with the status codes to trigger the retries
89
+
90
+ Return
91
+ ------
92
+ response : requests.Response
93
+ The Response object returned by the API server
94
+ """
95
+ retry_strategy = Retry(
96
+ total=total,
97
+ status_forcelist=status_forcelist
98
+ )
99
+ # Create an HTTP adapter with the retry strategy and mount it to session
100
+ adapter = HTTPAdapter(max_retries=retry_strategy)
101
+
102
+ # Create a new session object
103
+ session = requests.Session()
104
+ session.mount('http://', adapter)
105
+ session.mount('https://', adapter)
106
+
107
+ # Make a request using the session object
108
+ response = session.put(url, **kwargs)
109
+ return response
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cloudos_cli
3
- Version: 2.19.1
3
+ Version: 2.20.0
4
4
  Summary: Python package for interacting with CloudOS
5
5
  Home-page: https://github.com/lifebit-ai/cloudos-cli
6
6
  Author: David Piñeyro
@@ -329,6 +329,24 @@ Executing run...
329
329
  Your job took 420 seconds to complete successfully.
330
330
  ```
331
331
 
332
+ #### Abort single or multiple jobs from CloudOS
333
+
334
+ Aborts jobs in the CloudOS workspace that are either running or initialising. It can be used with one or more job IDs provided as a comma separated string using the `--job-ids` parameter.
335
+
336
+ Example:
337
+ ```console
338
+ cloudos job abort \
339
+ --cloudos-url $CLOUDOS \
340
+ --apikey $MY_API_KEY \
341
+ --workspace-id $WORKSPACE_ID \
342
+ --job-ids "680a3cf80e56949775c02f16"
343
+
344
+
345
+ Aborting jobs...
346
+ Job 680a3cf80e56949775c02f16 aborted successfully.
347
+ ```
348
+
349
+
332
350
  #### Executor support
333
351
 
334
352
  CloudOS supports [AWS batch](https://www.nextflow.io/docs/latest/executor.html?highlight=executors#aws-batch) executor by default.
@@ -21,6 +21,7 @@ cloudos_cli/utils/requests.py
21
21
  tests/__init__.py
22
22
  tests/functions_for_pytest.py
23
23
  tests/test_clos/__init__.py
24
+ tests/test_clos/test_abort_job.py
24
25
  tests/test_clos/test_create_cromwell_header.py
25
26
  tests/test_clos/test_cromwell_switch.py
26
27
  tests/test_clos/test_detect_workflow.py
@@ -0,0 +1,68 @@
1
+ """Pytest added for function abort_job"""
2
+ import json
3
+ import mock
4
+ import pytest
5
+ import requests
6
+ import responses
7
+ from cloudos_cli.clos import Cloudos
8
+ from cloudos_cli.utils.errors import BadRequestException
9
+ from tests.functions_for_pytest import load_json_file
10
+
11
+ APIKEY = 'vnoiweur89u2ongs'
12
+ CLOUDOS_URL = 'http://cloudos.lifebit.ai'
13
+ WORKSPACE_ID = 'lv89ufc838sdig'
14
+ JOB_ID = "616ee9681b866a01d69fa1cd"
15
+
16
+
17
+ @mock.patch('cloudos_cli.clos', mock.MagicMock())
18
+ @responses.activate
19
+ def test_abort_job_correct_response():
20
+ """
21
+ Test 'abort_job' to work as intended
22
+ API request is mocked and replicated with json files
23
+ """
24
+ header = {
25
+ "Content-type": "application/json",
26
+ "apikey": APIKEY
27
+ }
28
+ # mock GET method with the .json
29
+ responses.add(
30
+ responses.PUT,
31
+ url=f"{CLOUDOS_URL}/api/v1/jobs/{JOB_ID}/abort?teamId={WORKSPACE_ID}",
32
+ headers=header,
33
+ status=200)
34
+ # start cloudOS service
35
+ clos = Cloudos(apikey=APIKEY, cromwell_token=None, cloudos_url=CLOUDOS_URL)
36
+ # get mock response
37
+ response = clos.abort_job(JOB_ID, WORKSPACE_ID)
38
+ assert response.status_code == 200
39
+ assert isinstance(response, requests.models.Response)
40
+
41
+
42
+ @mock.patch('cloudos_cli.clos', mock.MagicMock())
43
+ @responses.activate
44
+ def test_abort_job_incorrect_response():
45
+ """
46
+ Test 'abort_job' to fail with '400' response
47
+ """
48
+ # prepare error message
49
+ error_message = {"statusCode": 400, "code": "BadRequest",
50
+ "message": "Bad Request.", "time": "2025-04-25_17:31:07"}
51
+ error_json = json.dumps(error_message)
52
+ header = {
53
+ "Content-type": "application/json",
54
+ "apikey": APIKEY
55
+ }
56
+ # mock GET method with the .json
57
+ responses.add(
58
+ responses.PUT,
59
+ url=f"{CLOUDOS_URL}/api/v1/jobs/{JOB_ID}/abort?teamId={WORKSPACE_ID}",
60
+ body=error_json,
61
+ headers=header,
62
+ status=400)
63
+ # raise 400 error
64
+ with pytest.raises(BadRequestException) as error:
65
+ # check if it failed
66
+ clos = Cloudos(apikey=APIKEY, cromwell_token=None, cloudos_url=CLOUDOS_URL)
67
+ clos.abort_job(JOB_ID, WORKSPACE_ID)
68
+ assert "Bad Request" in (str(error))
@@ -1 +0,0 @@
1
- __version__ = '2.19.1'
File without changes
File without changes
File without changes