toil 8.0.0__py3-none-any.whl → 8.2.0__py3-none-any.whl

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 (270) hide show
  1. toil/__init__.py +4 -39
  2. toil/batchSystems/abstractBatchSystem.py +1 -1
  3. toil/batchSystems/abstractGridEngineBatchSystem.py +1 -1
  4. toil/batchSystems/awsBatch.py +1 -1
  5. toil/batchSystems/cleanup_support.py +1 -1
  6. toil/batchSystems/kubernetes.py +53 -7
  7. toil/batchSystems/local_support.py +1 -1
  8. toil/batchSystems/mesos/batchSystem.py +13 -8
  9. toil/batchSystems/mesos/test/__init__.py +3 -2
  10. toil/batchSystems/options.py +1 -0
  11. toil/batchSystems/singleMachine.py +1 -1
  12. toil/batchSystems/slurm.py +229 -84
  13. toil/bus.py +5 -3
  14. toil/common.py +198 -54
  15. toil/cwl/cwltoil.py +32 -11
  16. toil/job.py +110 -86
  17. toil/jobStores/abstractJobStore.py +24 -3
  18. toil/jobStores/aws/jobStore.py +46 -10
  19. toil/jobStores/fileJobStore.py +25 -1
  20. toil/jobStores/googleJobStore.py +104 -30
  21. toil/leader.py +9 -0
  22. toil/lib/accelerators.py +3 -1
  23. toil/lib/aws/session.py +14 -3
  24. toil/lib/aws/utils.py +92 -35
  25. toil/lib/aws/utils.py.orig +504 -0
  26. toil/lib/bioio.py +1 -1
  27. toil/lib/docker.py +252 -91
  28. toil/lib/dockstore.py +387 -0
  29. toil/lib/ec2nodes.py +3 -2
  30. toil/lib/exceptions.py +5 -3
  31. toil/lib/history.py +1345 -0
  32. toil/lib/history_submission.py +695 -0
  33. toil/lib/io.py +56 -23
  34. toil/lib/misc.py +25 -1
  35. toil/lib/resources.py +2 -1
  36. toil/lib/retry.py +10 -10
  37. toil/lib/threading.py +11 -10
  38. toil/lib/{integration.py → trs.py} +95 -46
  39. toil/lib/web.py +38 -0
  40. toil/options/common.py +25 -2
  41. toil/options/cwl.py +10 -0
  42. toil/options/wdl.py +11 -0
  43. toil/provisioners/gceProvisioner.py +4 -4
  44. toil/server/api_spec/LICENSE +201 -0
  45. toil/server/api_spec/README.rst +5 -0
  46. toil/server/cli/wes_cwl_runner.py +5 -4
  47. toil/server/utils.py +2 -3
  48. toil/statsAndLogging.py +35 -1
  49. toil/test/__init__.py +275 -115
  50. toil/test/batchSystems/batchSystemTest.py +227 -205
  51. toil/test/batchSystems/test_slurm.py +199 -2
  52. toil/test/cactus/pestis.tar.gz +0 -0
  53. toil/test/conftest.py +7 -0
  54. toil/test/cwl/2.fasta +11 -0
  55. toil/test/cwl/2.fastq +12 -0
  56. toil/test/cwl/conftest.py +39 -0
  57. toil/test/cwl/cwlTest.py +1015 -780
  58. toil/test/cwl/directory/directory/file.txt +15 -0
  59. toil/test/cwl/download_directory_file.json +4 -0
  60. toil/test/cwl/download_directory_s3.json +4 -0
  61. toil/test/cwl/download_file.json +6 -0
  62. toil/test/cwl/download_http.json +6 -0
  63. toil/test/cwl/download_https.json +6 -0
  64. toil/test/cwl/download_s3.json +6 -0
  65. toil/test/cwl/download_subdirectory_file.json +5 -0
  66. toil/test/cwl/download_subdirectory_s3.json +5 -0
  67. toil/test/cwl/empty.json +1 -0
  68. toil/test/cwl/mock_mpi/fake_mpi.yml +8 -0
  69. toil/test/cwl/mock_mpi/fake_mpi_run.py +42 -0
  70. toil/test/cwl/optional-file-exists.json +6 -0
  71. toil/test/cwl/optional-file-missing.json +6 -0
  72. toil/test/cwl/optional-file.cwl +18 -0
  73. toil/test/cwl/preemptible_expression.json +1 -0
  74. toil/test/cwl/revsort-job-missing.json +6 -0
  75. toil/test/cwl/revsort-job.json +6 -0
  76. toil/test/cwl/s3_secondary_file.json +16 -0
  77. toil/test/cwl/seqtk_seq_job.json +6 -0
  78. toil/test/cwl/stream.json +6 -0
  79. toil/test/cwl/test_filename_conflict_resolution.ms/table.dat +0 -0
  80. toil/test/cwl/test_filename_conflict_resolution.ms/table.f0 +0 -0
  81. toil/test/cwl/test_filename_conflict_resolution.ms/table.f1 +0 -0
  82. toil/test/cwl/test_filename_conflict_resolution.ms/table.f1i +0 -0
  83. toil/test/cwl/test_filename_conflict_resolution.ms/table.f2 +0 -0
  84. toil/test/cwl/test_filename_conflict_resolution.ms/table.f2_TSM0 +0 -0
  85. toil/test/cwl/test_filename_conflict_resolution.ms/table.f3 +0 -0
  86. toil/test/cwl/test_filename_conflict_resolution.ms/table.f3_TSM0 +0 -0
  87. toil/test/cwl/test_filename_conflict_resolution.ms/table.f4 +0 -0
  88. toil/test/cwl/test_filename_conflict_resolution.ms/table.f4_TSM0 +0 -0
  89. toil/test/cwl/test_filename_conflict_resolution.ms/table.f5 +0 -0
  90. toil/test/cwl/test_filename_conflict_resolution.ms/table.info +0 -0
  91. toil/test/cwl/test_filename_conflict_resolution.ms/table.lock +0 -0
  92. toil/test/cwl/whale.txt +16 -0
  93. toil/test/docs/scripts/example_alwaysfail.py +38 -0
  94. toil/test/docs/scripts/example_alwaysfail_with_files.wdl +33 -0
  95. toil/test/docs/scripts/example_cachingbenchmark.py +117 -0
  96. toil/test/docs/scripts/stagingExampleFiles/in.txt +1 -0
  97. toil/test/docs/scripts/stagingExampleFiles/out.txt +2 -0
  98. toil/test/docs/scripts/tutorial_arguments.py +23 -0
  99. toil/test/docs/scripts/tutorial_debugging.patch +12 -0
  100. toil/test/docs/scripts/tutorial_debugging_hangs.wdl +126 -0
  101. toil/test/docs/scripts/tutorial_debugging_works.wdl +129 -0
  102. toil/test/docs/scripts/tutorial_docker.py +20 -0
  103. toil/test/docs/scripts/tutorial_dynamic.py +24 -0
  104. toil/test/docs/scripts/tutorial_encapsulation.py +28 -0
  105. toil/test/docs/scripts/tutorial_encapsulation2.py +29 -0
  106. toil/test/docs/scripts/tutorial_helloworld.py +15 -0
  107. toil/test/docs/scripts/tutorial_invokeworkflow.py +27 -0
  108. toil/test/docs/scripts/tutorial_invokeworkflow2.py +30 -0
  109. toil/test/docs/scripts/tutorial_jobfunctions.py +22 -0
  110. toil/test/docs/scripts/tutorial_managing.py +29 -0
  111. toil/test/docs/scripts/tutorial_managing2.py +56 -0
  112. toil/test/docs/scripts/tutorial_multiplejobs.py +25 -0
  113. toil/test/docs/scripts/tutorial_multiplejobs2.py +21 -0
  114. toil/test/docs/scripts/tutorial_multiplejobs3.py +22 -0
  115. toil/test/docs/scripts/tutorial_promises.py +25 -0
  116. toil/test/docs/scripts/tutorial_promises2.py +30 -0
  117. toil/test/docs/scripts/tutorial_quickstart.py +22 -0
  118. toil/test/docs/scripts/tutorial_requirements.py +44 -0
  119. toil/test/docs/scripts/tutorial_services.py +45 -0
  120. toil/test/docs/scripts/tutorial_staging.py +45 -0
  121. toil/test/docs/scripts/tutorial_stats.py +64 -0
  122. toil/test/lib/aws/test_iam.py +3 -1
  123. toil/test/lib/dockerTest.py +205 -122
  124. toil/test/lib/test_history.py +236 -0
  125. toil/test/lib/test_trs.py +161 -0
  126. toil/test/provisioners/aws/awsProvisionerTest.py +12 -9
  127. toil/test/provisioners/clusterTest.py +4 -4
  128. toil/test/provisioners/gceProvisionerTest.py +16 -14
  129. toil/test/sort/sort.py +4 -1
  130. toil/test/src/busTest.py +17 -17
  131. toil/test/src/deferredFunctionTest.py +145 -132
  132. toil/test/src/importExportFileTest.py +71 -63
  133. toil/test/src/jobEncapsulationTest.py +27 -28
  134. toil/test/src/jobServiceTest.py +149 -133
  135. toil/test/src/jobTest.py +219 -211
  136. toil/test/src/miscTests.py +66 -60
  137. toil/test/src/promisedRequirementTest.py +163 -169
  138. toil/test/src/regularLogTest.py +24 -24
  139. toil/test/src/resourceTest.py +82 -76
  140. toil/test/src/restartDAGTest.py +51 -47
  141. toil/test/src/resumabilityTest.py +24 -19
  142. toil/test/src/retainTempDirTest.py +60 -57
  143. toil/test/src/systemTest.py +17 -13
  144. toil/test/src/threadingTest.py +29 -32
  145. toil/test/utils/ABCWorkflowDebug/B_file.txt +1 -0
  146. toil/test/utils/ABCWorkflowDebug/debugWorkflow.py +204 -0
  147. toil/test/utils/ABCWorkflowDebug/mkFile.py +16 -0
  148. toil/test/utils/ABCWorkflowDebug/sleep.cwl +12 -0
  149. toil/test/utils/ABCWorkflowDebug/sleep.yaml +1 -0
  150. toil/test/utils/toilDebugTest.py +117 -102
  151. toil/test/utils/toilKillTest.py +54 -53
  152. toil/test/utils/utilsTest.py +303 -229
  153. toil/test/wdl/lint_error.wdl +9 -0
  154. toil/test/wdl/md5sum/empty_file.json +1 -0
  155. toil/test/wdl/md5sum/md5sum-gs.json +1 -0
  156. toil/test/wdl/md5sum/md5sum.1.0.wdl +32 -0
  157. toil/test/wdl/md5sum/md5sum.input +1 -0
  158. toil/test/wdl/md5sum/md5sum.json +1 -0
  159. toil/test/wdl/md5sum/md5sum.wdl +25 -0
  160. toil/test/wdl/miniwdl_self_test/inputs-namespaced.json +1 -0
  161. toil/test/wdl/miniwdl_self_test/inputs.json +1 -0
  162. toil/test/wdl/miniwdl_self_test/self_test.wdl +40 -0
  163. toil/test/wdl/standard_library/as_map.json +16 -0
  164. toil/test/wdl/standard_library/as_map_as_input.wdl +23 -0
  165. toil/test/wdl/standard_library/as_pairs.json +7 -0
  166. toil/test/wdl/standard_library/as_pairs_as_input.wdl +23 -0
  167. toil/test/wdl/standard_library/ceil.json +3 -0
  168. toil/test/wdl/standard_library/ceil_as_command.wdl +16 -0
  169. toil/test/wdl/standard_library/ceil_as_input.wdl +16 -0
  170. toil/test/wdl/standard_library/collect_by_key.json +1 -0
  171. toil/test/wdl/standard_library/collect_by_key_as_input.wdl +23 -0
  172. toil/test/wdl/standard_library/cross.json +11 -0
  173. toil/test/wdl/standard_library/cross_as_input.wdl +19 -0
  174. toil/test/wdl/standard_library/flatten.json +7 -0
  175. toil/test/wdl/standard_library/flatten_as_input.wdl +18 -0
  176. toil/test/wdl/standard_library/floor.json +3 -0
  177. toil/test/wdl/standard_library/floor_as_command.wdl +16 -0
  178. toil/test/wdl/standard_library/floor_as_input.wdl +16 -0
  179. toil/test/wdl/standard_library/keys.json +8 -0
  180. toil/test/wdl/standard_library/keys_as_input.wdl +24 -0
  181. toil/test/wdl/standard_library/length.json +7 -0
  182. toil/test/wdl/standard_library/length_as_input.wdl +16 -0
  183. toil/test/wdl/standard_library/length_as_input_with_map.json +7 -0
  184. toil/test/wdl/standard_library/length_as_input_with_map.wdl +17 -0
  185. toil/test/wdl/standard_library/length_invalid.json +3 -0
  186. toil/test/wdl/standard_library/range.json +3 -0
  187. toil/test/wdl/standard_library/range_0.json +3 -0
  188. toil/test/wdl/standard_library/range_as_input.wdl +17 -0
  189. toil/test/wdl/standard_library/range_invalid.json +3 -0
  190. toil/test/wdl/standard_library/read_boolean.json +3 -0
  191. toil/test/wdl/standard_library/read_boolean_as_command.wdl +17 -0
  192. toil/test/wdl/standard_library/read_float.json +3 -0
  193. toil/test/wdl/standard_library/read_float_as_command.wdl +17 -0
  194. toil/test/wdl/standard_library/read_int.json +3 -0
  195. toil/test/wdl/standard_library/read_int_as_command.wdl +17 -0
  196. toil/test/wdl/standard_library/read_json.json +3 -0
  197. toil/test/wdl/standard_library/read_json_as_output.wdl +31 -0
  198. toil/test/wdl/standard_library/read_lines.json +3 -0
  199. toil/test/wdl/standard_library/read_lines_as_output.wdl +31 -0
  200. toil/test/wdl/standard_library/read_map.json +3 -0
  201. toil/test/wdl/standard_library/read_map_as_output.wdl +31 -0
  202. toil/test/wdl/standard_library/read_string.json +3 -0
  203. toil/test/wdl/standard_library/read_string_as_command.wdl +17 -0
  204. toil/test/wdl/standard_library/read_tsv.json +3 -0
  205. toil/test/wdl/standard_library/read_tsv_as_output.wdl +31 -0
  206. toil/test/wdl/standard_library/round.json +3 -0
  207. toil/test/wdl/standard_library/round_as_command.wdl +16 -0
  208. toil/test/wdl/standard_library/round_as_input.wdl +16 -0
  209. toil/test/wdl/standard_library/size.json +3 -0
  210. toil/test/wdl/standard_library/size_as_command.wdl +17 -0
  211. toil/test/wdl/standard_library/size_as_output.wdl +36 -0
  212. toil/test/wdl/standard_library/stderr.json +3 -0
  213. toil/test/wdl/standard_library/stderr_as_output.wdl +30 -0
  214. toil/test/wdl/standard_library/stdout.json +3 -0
  215. toil/test/wdl/standard_library/stdout_as_output.wdl +30 -0
  216. toil/test/wdl/standard_library/sub.json +3 -0
  217. toil/test/wdl/standard_library/sub_as_input.wdl +17 -0
  218. toil/test/wdl/standard_library/sub_as_input_with_file.wdl +17 -0
  219. toil/test/wdl/standard_library/transpose.json +6 -0
  220. toil/test/wdl/standard_library/transpose_as_input.wdl +18 -0
  221. toil/test/wdl/standard_library/write_json.json +6 -0
  222. toil/test/wdl/standard_library/write_json_as_command.wdl +17 -0
  223. toil/test/wdl/standard_library/write_lines.json +7 -0
  224. toil/test/wdl/standard_library/write_lines_as_command.wdl +17 -0
  225. toil/test/wdl/standard_library/write_map.json +6 -0
  226. toil/test/wdl/standard_library/write_map_as_command.wdl +17 -0
  227. toil/test/wdl/standard_library/write_tsv.json +6 -0
  228. toil/test/wdl/standard_library/write_tsv_as_command.wdl +17 -0
  229. toil/test/wdl/standard_library/zip.json +12 -0
  230. toil/test/wdl/standard_library/zip_as_input.wdl +19 -0
  231. toil/test/wdl/test.csv +3 -0
  232. toil/test/wdl/test.tsv +3 -0
  233. toil/test/wdl/testfiles/croo.wdl +38 -0
  234. toil/test/wdl/testfiles/drop_files.wdl +62 -0
  235. toil/test/wdl/testfiles/drop_files_subworkflow.wdl +13 -0
  236. toil/test/wdl/testfiles/empty.txt +0 -0
  237. toil/test/wdl/testfiles/not_enough_outputs.wdl +33 -0
  238. toil/test/wdl/testfiles/random.wdl +66 -0
  239. toil/test/wdl/testfiles/string_file_coercion.json +1 -0
  240. toil/test/wdl/testfiles/string_file_coercion.wdl +35 -0
  241. toil/test/wdl/testfiles/test.json +4 -0
  242. toil/test/wdl/testfiles/test_boolean.txt +1 -0
  243. toil/test/wdl/testfiles/test_float.txt +1 -0
  244. toil/test/wdl/testfiles/test_int.txt +1 -0
  245. toil/test/wdl/testfiles/test_lines.txt +5 -0
  246. toil/test/wdl/testfiles/test_map.txt +2 -0
  247. toil/test/wdl/testfiles/test_string.txt +1 -0
  248. toil/test/wdl/testfiles/url_to_file.wdl +13 -0
  249. toil/test/wdl/testfiles/url_to_optional_file.wdl +13 -0
  250. toil/test/wdl/testfiles/vocab.json +1 -0
  251. toil/test/wdl/testfiles/vocab.wdl +66 -0
  252. toil/test/wdl/testfiles/wait.wdl +34 -0
  253. toil/test/wdl/wdl_specification/type_pair.json +23 -0
  254. toil/test/wdl/wdl_specification/type_pair_basic.wdl +36 -0
  255. toil/test/wdl/wdl_specification/type_pair_with_files.wdl +36 -0
  256. toil/test/wdl/wdl_specification/v1_spec.json +1 -0
  257. toil/test/wdl/wdl_specification/v1_spec_declaration.wdl +39 -0
  258. toil/test/wdl/wdltoil_test.py +681 -408
  259. toil/test/wdl/wdltoil_test_kubernetes.py +2 -2
  260. toil/version.py +10 -10
  261. toil/wdl/wdltoil.py +350 -123
  262. toil/worker.py +113 -33
  263. {toil-8.0.0.dist-info → toil-8.2.0.dist-info}/METADATA +13 -7
  264. toil-8.2.0.dist-info/RECORD +439 -0
  265. {toil-8.0.0.dist-info → toil-8.2.0.dist-info}/WHEEL +1 -1
  266. toil/test/lib/test_integration.py +0 -104
  267. toil-8.0.0.dist-info/RECORD +0 -253
  268. {toil-8.0.0.dist-info → toil-8.2.0.dist-info}/entry_points.txt +0 -0
  269. {toil-8.0.0.dist-info → toil-8.2.0.dist-info/licenses}/LICENSE +0 -0
  270. {toil-8.0.0.dist-info → toil-8.2.0.dist-info}/top_level.txt +0 -0
toil/__init__.py CHANGED
@@ -19,7 +19,7 @@ import sys
19
19
  from datetime import datetime
20
20
  from typing import TYPE_CHECKING, Optional
21
21
 
22
- import requests
22
+ from toil.lib.web import web_session
23
23
 
24
24
  from docker.errors import ImageNotFound
25
25
  from toil.lib.memoize import memoize
@@ -425,7 +425,7 @@ def requestCheckRegularDocker(
425
425
  ioURL = "https://{webhost}/v2/{pathName}/manifests/{tag}" "".format(
426
426
  webhost=registryName, pathName=imageName, tag=tag
427
427
  )
428
- response = requests.head(ioURL)
428
+ response = web_session.head(ioURL)
429
429
  if not response.ok:
430
430
  raise ApplianceImageNotFound(origAppliance, ioURL, response.status_code)
431
431
  else:
@@ -459,10 +459,10 @@ def requestCheckDockerIo(origAppliance: str, imageName: str, tag: str) -> bool:
459
459
  )
460
460
  requests_url = f"https://registry-1.docker.io/v2/{imageName}/manifests/{tag}"
461
461
 
462
- token = requests.get(token_url)
462
+ token = web_session.get(token_url)
463
463
  jsonToken = token.json()
464
464
  bearer = jsonToken["token"]
465
- response = requests.head(
465
+ response = web_session.head(
466
466
  requests_url, headers={"Authorization": f"Bearer {bearer}"}
467
467
  )
468
468
  if not response.ok:
@@ -480,38 +480,3 @@ def logProcessContext(config: "Config") -> None:
480
480
  log.info("Running Toil version %s on host %s.", version, socket.gethostname())
481
481
  log.debug("Configuration: %s", config.__dict__)
482
482
 
483
-
484
- try:
485
- cache_path = "~/.cache/aws/cached_temporary_credentials"
486
- datetime_format = (
487
- "%Y-%m-%dT%H:%M:%SZ" # incidentally the same as the format used by AWS
488
- )
489
- log = logging.getLogger(__name__)
490
-
491
- # But in addition to our manual cache, we also are going to turn on boto3's
492
- # new built-in caching layer.
493
-
494
- def datetime_to_str(dt):
495
- """
496
- Convert a naive (implicitly UTC) datetime object into a string, explicitly UTC.
497
-
498
- >>> datetime_to_str(datetime(1970, 1, 1, 0, 0, 0))
499
- '1970-01-01T00:00:00Z'
500
- """
501
- return dt.strftime(datetime_format)
502
-
503
- def str_to_datetime(s):
504
- """
505
- Convert a string, explicitly UTC into a naive (implicitly UTC) datetime object.
506
-
507
- >>> str_to_datetime( '1970-01-01T00:00:00Z' )
508
- datetime.datetime(1970, 1, 1, 0, 0)
509
-
510
- Just to show that the constructor args for seconds and microseconds are optional:
511
- >>> datetime(1970, 1, 1, 0, 0, 0)
512
- datetime.datetime(1970, 1, 1, 0, 0)
513
- """
514
- return datetime.strptime(s, datetime_format)
515
-
516
- except ImportError:
517
- pass
@@ -310,7 +310,7 @@ class BatchSystemSupport(AbstractBatchSystem):
310
310
  """Partial implementation of AbstractBatchSystem, support methods."""
311
311
 
312
312
  def __init__(
313
- self, config: Config, maxCores: float, maxMemory: int, maxDisk: int
313
+ self, config: Config, maxCores: float, maxMemory: float, maxDisk: int
314
314
  ) -> None:
315
315
  """
316
316
  Initialize initial state of the object.
@@ -421,7 +421,7 @@ class AbstractGridEngineBatchSystem(BatchSystemCleanupSupport):
421
421
  raise NotImplementedError()
422
422
 
423
423
  def __init__(
424
- self, config: Config, maxCores: float, maxMemory: int, maxDisk: int
424
+ self, config: Config, maxCores: float, maxMemory: float, maxDisk: float
425
425
  ) -> None:
426
426
  super().__init__(config, maxCores, maxMemory, maxDisk)
427
427
  self.config = config
@@ -83,7 +83,7 @@ class AWSBatchBatchSystem(BatchSystemCleanupSupport):
83
83
  return True
84
84
 
85
85
  def __init__(
86
- self, config: Config, maxCores: float, maxMemory: int, maxDisk: int
86
+ self, config: Config, maxCores: float, maxMemory: float, maxDisk: int
87
87
  ) -> None:
88
88
  super().__init__(config, maxCores, maxMemory, maxDisk)
89
89
 
@@ -45,7 +45,7 @@ class BatchSystemCleanupSupport(BatchSystemLocalSupport):
45
45
  return contexts
46
46
 
47
47
  def __init__(
48
- self, config: Config, maxCores: float, maxMemory: int, maxDisk: int
48
+ self, config: Config, maxCores: float, maxMemory: float, maxDisk: int
49
49
  ) -> None:
50
50
  super().__init__(config, maxCores, maxMemory, maxDisk)
51
51
 
@@ -21,6 +21,7 @@ cannot yet be launched. That functionality will need to wait for user-mode
21
21
  Docker
22
22
  """
23
23
  import datetime
24
+ import io
24
25
  import logging
25
26
  import math
26
27
  import os
@@ -50,7 +51,8 @@ else:
50
51
  from typing import Protocol, TypedDict, runtime_checkable
51
52
 
52
53
  import urllib3
53
- import yaml
54
+ import ruamel.yaml as yaml
55
+ import json
54
56
 
55
57
  # The Right Way to use the Kubernetes module is to `import kubernetes` and then you get all your stuff as like ApiClient. But this doesn't work for the stubs: the stubs seem to only support importing things from the internal modules in `kubernetes` where they are actually defined. See for example <https://github.com/MaterializeInc/kubernetes-stubs/issues/9 and <https://github.com/MaterializeInc/kubernetes-stubs/issues/10>. So we just import all the things we use into our global namespace here.
56
58
  from kubernetes.client import (
@@ -77,6 +79,7 @@ from kubernetes.client import (
77
79
  V1ResourceRequirements,
78
80
  V1SecretVolumeSource,
79
81
  V1SecurityContext,
82
+ V1PodSecurityContext,
80
83
  V1Toleration,
81
84
  V1Volume,
82
85
  V1VolumeMount,
@@ -148,7 +151,7 @@ class KubernetesBatchSystem(BatchSystemCleanupSupport):
148
151
  customObjects: NotRequired[CustomObjectsApi]
149
152
 
150
153
  def __init__(
151
- self, config: Config, maxCores: int, maxMemory: int, maxDisk: int
154
+ self, config: Config, maxCores: int, maxMemory: float, maxDisk: int
152
155
  ) -> None:
153
156
  super().__init__(config, maxCores, maxMemory, maxDisk)
154
157
 
@@ -314,7 +317,10 @@ class KubernetesBatchSystem(BatchSystemCleanupSupport):
314
317
  del here[k]
315
318
 
316
319
  drop_boring(root_dict)
317
- return yaml.dump(root_dict)
320
+ s = io.StringIO()
321
+ YAML = yaml.YAML(typ='safe')
322
+ YAML.dump(root_dict, s)
323
+ return s.getvalue()
318
324
 
319
325
  @overload
320
326
  def _api(
@@ -803,6 +809,26 @@ class KubernetesBatchSystem(BatchSystemCleanupSupport):
803
809
  ],
804
810
  )
805
811
 
812
+ class FakeResponse:
813
+ data: str
814
+
815
+ T = TypeVar('T')
816
+ def _load_kubernetes_object(self, file: str, cls: type[T]) -> T:
817
+ """
818
+ Deserialize a YAML representation into a Kubernetes object
819
+ :param file: Path to YAML file
820
+ :param cls: Kubernetes API model type for deserialized object
821
+ :return: Deserialized object
822
+ """
823
+ YAML = yaml.YAML(typ='safe')
824
+ object_def = YAML.load(open('container.yaml').read())
825
+ # The kubernetes API does not have an actual deserializer, so this is a workaround
826
+ # See: https://github.com/kubernetes-client/python/issues/977
827
+ faked_response = self.FakeResponse()
828
+ faked_response.data = json.dumps(object_def)
829
+ return ApiClient().deserialize(faked_response, cls)
830
+
831
+
806
832
  def _create_pod_spec(
807
833
  self,
808
834
  command: str,
@@ -946,17 +972,24 @@ class KubernetesBatchSystem(BatchSystemCleanupSupport):
946
972
  volume_mounts=mounts,
947
973
  )
948
974
 
975
+ if self.config.kubernetes_security_context:
976
+ container.security_context = self._load_kubernetes_object(self.config.kubernetes_security_context, V1SecurityContext)
977
+
949
978
  # In case security context rules are not allowed to be set, we only apply
950
979
  # a security context at all if we need to turn on privileged mode.
951
980
  if self.config.kubernetes_privileged:
952
- container.security_context = V1SecurityContext(
953
- privileged=self.config.kubernetes_privileged
954
- )
981
+ if container.security_context is None:
982
+ container.security_context = V1SecurityContext()
983
+ container.security_context.privileged = self.config.kubernetes_privileged
955
984
 
956
985
  # Wrap the container in a spec
957
986
  pod_spec = V1PodSpec(
958
987
  containers=[container], volumes=volumes, restart_policy="Never"
959
988
  )
989
+
990
+ if self.config.kubernetes_pod_security_context:
991
+ pod_spec.security_context = self._load_kubernetes_object(self.config.kubernetes_pod_security_context, V1PodSecurityContext)
992
+
960
993
  # Tell the spec where to land
961
994
  placement.apply(pod_spec)
962
995
 
@@ -2126,7 +2159,18 @@ class KubernetesBatchSystem(BatchSystemCleanupSupport):
2126
2159
  "privileged operations, such as FUSE. On Toil-managed clusters with --enableFuse, "
2127
2160
  "this is set to True. (default: %(default)s)",
2128
2161
  )
2129
-
2162
+ parser.add_argument("--kubernetesPodSecurityContext",
2163
+ dest='kubernetes_pod_security_context',
2164
+ type=str,
2165
+ env_var="TOIL_KUBERNETES_POD_SECURITY_CONTEXT",
2166
+ default=None,
2167
+ help="Path to a YAML defining a pod security context to apply to all pods.")
2168
+ parser.add_argument("--kubernetesSecurityContext",
2169
+ dest='kubernetes_security_context',
2170
+ type=str,
2171
+ env_var="TOIL_KUBERNETES_SECURITY_CONTEXT",
2172
+ default=None,
2173
+ help="Path to a YAML defining a security context to apply to all containers.")
2130
2174
  OptionType = TypeVar("OptionType")
2131
2175
 
2132
2176
  @classmethod
@@ -2138,3 +2182,5 @@ class KubernetesBatchSystem(BatchSystemCleanupSupport):
2138
2182
  )
2139
2183
  setOption("kubernetes_pod_timeout")
2140
2184
  setOption("kubernetes_privileged")
2185
+ setOption("kubernetes_pod_security_context")
2186
+ setOption("kubernetes_security_context")
@@ -30,7 +30,7 @@ class BatchSystemLocalSupport(BatchSystemSupport):
30
30
  """Adds a local queue for helper jobs, useful for CWL & others."""
31
31
 
32
32
  def __init__(
33
- self, config: Config, maxCores: float, maxMemory: int, maxDisk: int
33
+ self, config: Config, maxCores: float, maxMemory: float, maxDisk: int
34
34
  ) -> None:
35
35
  super().__init__(config, maxCores, maxMemory, maxDisk)
36
36
  max_local_jobs = (
@@ -40,6 +40,7 @@ from toil.batchSystems.abstractBatchSystem import (
40
40
  from toil.batchSystems.local_support import BatchSystemLocalSupport
41
41
  from toil.batchSystems.mesos import JobQueue, MesosShape, TaskData, ToilJob
42
42
  from toil.batchSystems.options import OptionSetter
43
+ from toil.common import Config
43
44
  from toil.job import JobDescription
44
45
  from toil.lib.conversions import b_to_mib, mib_to_b
45
46
  from toil.lib.memoize import strict_bool
@@ -61,22 +62,26 @@ class MesosBatchSystem(BatchSystemLocalSupport, AbstractScalableBatchSystem, Sch
61
62
  """
62
63
 
63
64
  @classmethod
64
- def supportsAutoDeployment(cls):
65
+ def supportsAutoDeployment(cls) -> bool:
65
66
  return True
66
67
 
67
68
  @classmethod
68
- def supportsWorkerCleanup(cls):
69
+ def supportsWorkerCleanup(cls) -> bool:
69
70
  return True
70
71
 
71
72
  class ExecutorInfo:
72
- def __init__(self, nodeAddress, agentId, nodeInfo, lastSeen):
73
+ def __init__(
74
+ self, nodeAddress: str, agentId: str, nodeInfo: str, lastSeen: str
75
+ ) -> None:
73
76
  super().__init__()
74
77
  self.nodeAddress = nodeAddress
75
78
  self.agentId = agentId
76
79
  self.nodeInfo = nodeInfo
77
80
  self.lastSeen = lastSeen
78
81
 
79
- def __init__(self, config, maxCores, maxMemory, maxDisk):
82
+ def __init__(
83
+ self, config: Config, maxCores: float, maxMemory: float, maxDisk: int
84
+ ) -> None:
80
85
  super().__init__(config, maxCores, maxMemory, maxDisk)
81
86
 
82
87
  # The auto-deployed resource representing the user script. Will be passed along in every
@@ -165,13 +170,13 @@ class MesosBatchSystem(BatchSystemLocalSupport, AbstractScalableBatchSystem, Sch
165
170
 
166
171
  self._startDriver(config)
167
172
 
168
- def setUserScript(self, userScript):
173
+ def setUserScript(self, userScript: str) -> None:
169
174
  self.userScript = userScript
170
175
 
171
- def ignoreNode(self, nodeAddress):
176
+ def ignoreNode(self, nodeAddress: str) -> None:
172
177
  self.ignoredNodes.add(nodeAddress)
173
178
 
174
- def unignoreNode(self, nodeAddress):
179
+ def unignoreNode(self, nodeAddress: str) -> None:
175
180
  self.ignoredNodes.remove(nodeAddress)
176
181
 
177
182
  def issueBatchJob(
@@ -179,7 +184,7 @@ class MesosBatchSystem(BatchSystemLocalSupport, AbstractScalableBatchSystem, Sch
179
184
  command: str,
180
185
  jobNode: JobDescription,
181
186
  job_environment: Optional[dict[str, str]] = None,
182
- ):
187
+ ) -> str:
183
188
  """
184
189
  Issues the following command returning a unique jobID. Command is the string to run, memory
185
190
  is an int giving the number of bytes the job needs to run in and cores is the number of cpus
@@ -7,6 +7,7 @@ from abc import ABCMeta, abstractmethod
7
7
  from contextlib import closing
8
8
  from shutil import which
9
9
  from urllib.request import urlopen
10
+ from typing import Optional
10
11
 
11
12
  from toil.lib.retry import retry
12
13
  from toil.lib.threading import ExceptionalThread, cpu_count
@@ -25,7 +26,7 @@ class MesosTestSupport:
25
26
  with closing(urlopen("http://127.0.0.1:5050/version")) as content:
26
27
  content.read()
27
28
 
28
- def _startMesos(self, numCores=None):
29
+ def _startMesos(self, numCores: Optional[int] = None) -> None:
29
30
  if numCores is None:
30
31
  numCores = cpu_count()
31
32
  shutil.rmtree("/tmp/mesos", ignore_errors=True)
@@ -52,7 +53,7 @@ class MesosTestSupport:
52
53
  log.warning("Forcibly killing child which ignored SIGTERM")
53
54
  process.kill()
54
55
 
55
- def _stopMesos(self):
56
+ def _stopMesos(self) -> None:
56
57
  self._stopProcess(self.agent.popen)
57
58
  self.agent.join()
58
59
  self._stopProcess(self.master.popen)
@@ -185,6 +185,7 @@ def add_all_batchsystem_options(parser: Union[ArgumentParser, _ArgumentGroup]) -
185
185
  "systems such as gridengine, htcondor, torque, slurm, and lsf.",
186
186
  )
187
187
 
188
+ # TODO: Move this to Slurm specifically.
188
189
  parser.add_argument(
189
190
  "--memoryIsProduct",
190
191
  dest="memory_is_product",
@@ -94,7 +94,7 @@ class SingleMachineBatchSystem(BatchSystemSupport):
94
94
  self,
95
95
  config: Config,
96
96
  maxCores: float,
97
- maxMemory: int,
97
+ maxMemory: float,
98
98
  maxDisk: int,
99
99
  max_jobs: Optional[int] = None,
100
100
  ) -> None: