toil 7.0.0__py3-none-any.whl → 8.1.0b1__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.
- toil/__init__.py +124 -86
- toil/batchSystems/__init__.py +1 -0
- toil/batchSystems/abstractBatchSystem.py +137 -77
- toil/batchSystems/abstractGridEngineBatchSystem.py +211 -101
- toil/batchSystems/awsBatch.py +237 -128
- toil/batchSystems/cleanup_support.py +22 -16
- toil/batchSystems/contained_executor.py +30 -26
- toil/batchSystems/gridengine.py +85 -49
- toil/batchSystems/htcondor.py +164 -87
- toil/batchSystems/kubernetes.py +622 -386
- toil/batchSystems/local_support.py +17 -12
- toil/batchSystems/lsf.py +132 -79
- toil/batchSystems/lsfHelper.py +13 -11
- toil/batchSystems/mesos/__init__.py +41 -29
- toil/batchSystems/mesos/batchSystem.py +288 -149
- toil/batchSystems/mesos/executor.py +77 -49
- toil/batchSystems/mesos/test/__init__.py +31 -23
- toil/batchSystems/options.py +39 -29
- toil/batchSystems/registry.py +53 -19
- toil/batchSystems/singleMachine.py +293 -123
- toil/batchSystems/slurm.py +651 -155
- toil/batchSystems/torque.py +46 -32
- toil/bus.py +141 -73
- toil/common.py +784 -397
- toil/cwl/__init__.py +1 -1
- toil/cwl/cwltoil.py +1137 -534
- toil/cwl/utils.py +17 -22
- toil/deferred.py +62 -41
- toil/exceptions.py +5 -3
- toil/fileStores/__init__.py +5 -5
- toil/fileStores/abstractFileStore.py +88 -57
- toil/fileStores/cachingFileStore.py +711 -247
- toil/fileStores/nonCachingFileStore.py +113 -75
- toil/job.py +1031 -349
- toil/jobStores/abstractJobStore.py +387 -243
- toil/jobStores/aws/jobStore.py +772 -412
- toil/jobStores/aws/utils.py +161 -109
- toil/jobStores/conftest.py +1 -0
- toil/jobStores/fileJobStore.py +289 -151
- toil/jobStores/googleJobStore.py +137 -70
- toil/jobStores/utils.py +36 -15
- toil/leader.py +614 -269
- toil/lib/accelerators.py +115 -18
- toil/lib/aws/__init__.py +55 -28
- toil/lib/aws/ami.py +122 -87
- toil/lib/aws/iam.py +284 -108
- toil/lib/aws/s3.py +31 -0
- toil/lib/aws/session.py +204 -58
- toil/lib/aws/utils.py +290 -213
- toil/lib/bioio.py +13 -5
- toil/lib/compatibility.py +11 -6
- toil/lib/conversions.py +83 -49
- toil/lib/docker.py +131 -103
- toil/lib/dockstore.py +379 -0
- toil/lib/ec2.py +322 -209
- toil/lib/ec2nodes.py +174 -105
- toil/lib/encryption/_dummy.py +5 -3
- toil/lib/encryption/_nacl.py +10 -6
- toil/lib/encryption/conftest.py +1 -0
- toil/lib/exceptions.py +26 -7
- toil/lib/expando.py +4 -2
- toil/lib/ftp_utils.py +217 -0
- toil/lib/generatedEC2Lists.py +127 -19
- toil/lib/history.py +1271 -0
- toil/lib/history_submission.py +681 -0
- toil/lib/humanize.py +6 -2
- toil/lib/io.py +121 -12
- toil/lib/iterables.py +4 -2
- toil/lib/memoize.py +12 -8
- toil/lib/misc.py +83 -18
- toil/lib/objects.py +2 -2
- toil/lib/resources.py +19 -7
- toil/lib/retry.py +125 -87
- toil/lib/threading.py +282 -80
- toil/lib/throttle.py +15 -14
- toil/lib/trs.py +390 -0
- toil/lib/web.py +38 -0
- toil/options/common.py +850 -402
- toil/options/cwl.py +185 -90
- toil/options/runner.py +50 -0
- toil/options/wdl.py +70 -19
- toil/provisioners/__init__.py +111 -46
- toil/provisioners/abstractProvisioner.py +322 -157
- toil/provisioners/aws/__init__.py +62 -30
- toil/provisioners/aws/awsProvisioner.py +980 -627
- toil/provisioners/clusterScaler.py +541 -279
- toil/provisioners/gceProvisioner.py +283 -180
- toil/provisioners/node.py +147 -79
- toil/realtimeLogger.py +34 -22
- toil/resource.py +137 -75
- toil/server/app.py +127 -61
- toil/server/celery_app.py +3 -1
- toil/server/cli/wes_cwl_runner.py +84 -55
- toil/server/utils.py +56 -31
- toil/server/wes/abstract_backend.py +64 -26
- toil/server/wes/amazon_wes_utils.py +21 -15
- toil/server/wes/tasks.py +121 -63
- toil/server/wes/toil_backend.py +142 -107
- toil/server/wsgi_app.py +4 -3
- toil/serviceManager.py +58 -22
- toil/statsAndLogging.py +183 -65
- toil/test/__init__.py +263 -179
- toil/test/batchSystems/batchSystemTest.py +438 -195
- toil/test/batchSystems/batch_system_plugin_test.py +18 -7
- toil/test/batchSystems/test_gridengine.py +173 -0
- toil/test/batchSystems/test_lsf_helper.py +67 -58
- toil/test/batchSystems/test_slurm.py +265 -49
- toil/test/cactus/test_cactus_integration.py +20 -22
- toil/test/cwl/conftest.py +39 -0
- toil/test/cwl/cwlTest.py +375 -72
- toil/test/cwl/measure_default_memory.cwl +12 -0
- toil/test/cwl/not_run_required_input.cwl +29 -0
- toil/test/cwl/optional-file.cwl +18 -0
- toil/test/cwl/scatter_duplicate_outputs.cwl +40 -0
- toil/test/docs/scriptsTest.py +60 -34
- toil/test/jobStores/jobStoreTest.py +412 -235
- toil/test/lib/aws/test_iam.py +116 -48
- toil/test/lib/aws/test_s3.py +16 -9
- toil/test/lib/aws/test_utils.py +5 -6
- toil/test/lib/dockerTest.py +118 -141
- toil/test/lib/test_conversions.py +113 -115
- toil/test/lib/test_ec2.py +57 -49
- toil/test/lib/test_history.py +212 -0
- toil/test/lib/test_misc.py +12 -5
- toil/test/lib/test_trs.py +161 -0
- toil/test/mesos/MesosDataStructuresTest.py +23 -10
- toil/test/mesos/helloWorld.py +7 -6
- toil/test/mesos/stress.py +25 -20
- toil/test/options/options.py +7 -2
- toil/test/provisioners/aws/awsProvisionerTest.py +293 -140
- toil/test/provisioners/clusterScalerTest.py +440 -250
- toil/test/provisioners/clusterTest.py +81 -42
- toil/test/provisioners/gceProvisionerTest.py +174 -100
- toil/test/provisioners/provisionerTest.py +25 -13
- toil/test/provisioners/restartScript.py +5 -4
- toil/test/server/serverTest.py +188 -141
- toil/test/sort/restart_sort.py +137 -68
- toil/test/sort/sort.py +134 -66
- toil/test/sort/sortTest.py +91 -49
- toil/test/src/autoDeploymentTest.py +140 -100
- toil/test/src/busTest.py +20 -18
- toil/test/src/checkpointTest.py +8 -2
- toil/test/src/deferredFunctionTest.py +49 -35
- toil/test/src/dockerCheckTest.py +33 -26
- toil/test/src/environmentTest.py +20 -10
- toil/test/src/fileStoreTest.py +538 -271
- toil/test/src/helloWorldTest.py +7 -4
- toil/test/src/importExportFileTest.py +61 -31
- toil/test/src/jobDescriptionTest.py +32 -17
- toil/test/src/jobEncapsulationTest.py +2 -0
- toil/test/src/jobFileStoreTest.py +74 -50
- toil/test/src/jobServiceTest.py +187 -73
- toil/test/src/jobTest.py +120 -70
- toil/test/src/miscTests.py +19 -18
- toil/test/src/promisedRequirementTest.py +82 -36
- toil/test/src/promisesTest.py +7 -6
- toil/test/src/realtimeLoggerTest.py +6 -6
- toil/test/src/regularLogTest.py +71 -37
- toil/test/src/resourceTest.py +80 -49
- toil/test/src/restartDAGTest.py +36 -22
- toil/test/src/resumabilityTest.py +9 -2
- toil/test/src/retainTempDirTest.py +45 -14
- toil/test/src/systemTest.py +12 -8
- toil/test/src/threadingTest.py +44 -25
- toil/test/src/toilContextManagerTest.py +10 -7
- toil/test/src/userDefinedJobArgTypeTest.py +8 -5
- toil/test/src/workerTest.py +33 -16
- toil/test/utils/toilDebugTest.py +70 -58
- toil/test/utils/toilKillTest.py +4 -5
- toil/test/utils/utilsTest.py +239 -102
- toil/test/wdl/wdltoil_test.py +789 -148
- toil/test/wdl/wdltoil_test_kubernetes.py +37 -23
- toil/toilState.py +52 -26
- toil/utils/toilConfig.py +13 -4
- toil/utils/toilDebugFile.py +44 -27
- toil/utils/toilDebugJob.py +85 -25
- toil/utils/toilDestroyCluster.py +11 -6
- toil/utils/toilKill.py +8 -3
- toil/utils/toilLaunchCluster.py +251 -145
- toil/utils/toilMain.py +37 -16
- toil/utils/toilRsyncCluster.py +27 -14
- toil/utils/toilSshCluster.py +45 -22
- toil/utils/toilStats.py +75 -36
- toil/utils/toilStatus.py +226 -119
- toil/utils/toilUpdateEC2Instances.py +3 -1
- toil/version.py +6 -6
- toil/wdl/utils.py +5 -5
- toil/wdl/wdltoil.py +3528 -1053
- toil/worker.py +370 -149
- toil-8.1.0b1.dist-info/METADATA +178 -0
- toil-8.1.0b1.dist-info/RECORD +259 -0
- {toil-7.0.0.dist-info → toil-8.1.0b1.dist-info}/WHEEL +1 -1
- toil-7.0.0.dist-info/METADATA +0 -158
- toil-7.0.0.dist-info/RECORD +0 -244
- {toil-7.0.0.dist-info → toil-8.1.0b1.dist-info}/LICENSE +0 -0
- {toil-7.0.0.dist-info → toil-8.1.0b1.dist-info}/entry_points.txt +0 -0
- {toil-7.0.0.dist-info → toil-8.1.0b1.dist-info}/top_level.txt +0 -0
|
@@ -19,26 +19,37 @@ import time
|
|
|
19
19
|
from abc import abstractmethod
|
|
20
20
|
from inspect import getsource
|
|
21
21
|
from textwrap import dedent
|
|
22
|
-
from typing import
|
|
22
|
+
from typing import TYPE_CHECKING, Optional
|
|
23
23
|
from uuid import uuid4
|
|
24
24
|
|
|
25
|
-
import botocore.exceptions
|
|
26
25
|
import pytest
|
|
27
|
-
from mypy_boto3_ec2 import EC2Client
|
|
28
|
-
from mypy_boto3_ec2.type_defs import EbsInstanceBlockDeviceTypeDef, InstanceTypeDef, InstanceBlockDeviceMappingTypeDef, FilterTypeDef, DescribeVolumesResultTypeDef, VolumeTypeDef
|
|
29
26
|
|
|
30
27
|
from toil.provisioners import cluster_factory
|
|
31
28
|
from toil.provisioners.aws.awsProvisioner import AWSProvisioner
|
|
32
|
-
from toil.test import (
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
29
|
+
from toil.test import (
|
|
30
|
+
ToilTest,
|
|
31
|
+
integrative,
|
|
32
|
+
needs_aws_ec2,
|
|
33
|
+
needs_fetchable_appliance,
|
|
34
|
+
needs_mesos,
|
|
35
|
+
slow,
|
|
36
|
+
timeLimit,
|
|
37
|
+
)
|
|
39
38
|
from toil.test.provisioners.clusterTest import AbstractClusterTest
|
|
40
39
|
from toil.version import exactPython
|
|
41
40
|
|
|
41
|
+
if TYPE_CHECKING:
|
|
42
|
+
from mypy_boto3_ec2 import EC2Client
|
|
43
|
+
from mypy_boto3_ec2.type_defs import (
|
|
44
|
+
DescribeVolumesResultTypeDef,
|
|
45
|
+
EbsInstanceBlockDeviceTypeDef,
|
|
46
|
+
FilterTypeDef,
|
|
47
|
+
InstanceBlockDeviceMappingTypeDef,
|
|
48
|
+
InstanceTypeDef,
|
|
49
|
+
VolumeTypeDef,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
|
|
42
53
|
log = logging.getLogger(__name__)
|
|
43
54
|
|
|
44
55
|
|
|
@@ -50,11 +61,13 @@ class AWSProvisionerBenchTest(ToilTest):
|
|
|
50
61
|
# Needs to talk to EC2 for image discovery
|
|
51
62
|
@needs_aws_ec2
|
|
52
63
|
def test_AMI_finding(self):
|
|
53
|
-
for zone in [
|
|
54
|
-
provisioner = AWSProvisioner(
|
|
64
|
+
for zone in ["us-west-2a", "eu-central-1a", "sa-east-1b"]:
|
|
65
|
+
provisioner = AWSProvisioner(
|
|
66
|
+
"fakename", "mesos", zone, 10000, None, None, enable_fuse=False
|
|
67
|
+
)
|
|
55
68
|
ami = provisioner._discoverAMI()
|
|
56
69
|
# Make sure we got an AMI and it looks plausible
|
|
57
|
-
assert
|
|
70
|
+
assert ami.startswith("ami-")
|
|
58
71
|
|
|
59
72
|
@needs_aws_ec2
|
|
60
73
|
def test_read_write_global_files(self):
|
|
@@ -62,8 +75,16 @@ class AWSProvisionerBenchTest(ToilTest):
|
|
|
62
75
|
Make sure the `_write_file_to_cloud()` and `_read_file_from_cloud()`
|
|
63
76
|
functions of the AWS provisioner work as intended.
|
|
64
77
|
"""
|
|
65
|
-
provisioner = AWSProvisioner(
|
|
66
|
-
|
|
78
|
+
provisioner = AWSProvisioner(
|
|
79
|
+
f"aws-provisioner-test-{uuid4()}",
|
|
80
|
+
"mesos",
|
|
81
|
+
"us-west-2a",
|
|
82
|
+
50,
|
|
83
|
+
None,
|
|
84
|
+
None,
|
|
85
|
+
enable_fuse=False,
|
|
86
|
+
)
|
|
87
|
+
key = "config/test.txt"
|
|
67
88
|
contents = b"Hello, this is a test."
|
|
68
89
|
|
|
69
90
|
try:
|
|
@@ -84,23 +105,23 @@ class AbstractAWSAutoscaleTest(AbstractClusterTest):
|
|
|
84
105
|
def __init__(self, methodName):
|
|
85
106
|
super().__init__(methodName=methodName)
|
|
86
107
|
self.instanceTypes = ["m5a.large"]
|
|
87
|
-
self.clusterName =
|
|
88
|
-
self.numWorkers = [
|
|
108
|
+
self.clusterName = "aws-provisioner-test-" + str(uuid4())
|
|
109
|
+
self.numWorkers = ["2"]
|
|
89
110
|
self.numSamples = 2
|
|
90
111
|
self.spotBid = 0.15
|
|
91
112
|
# We can't dump our user script right in /tmp or /home, because hot
|
|
92
113
|
# deploy refuses to zip up those whole directories. So we make sure to
|
|
93
114
|
# have a subdirectory to upload the script to.
|
|
94
|
-
self.scriptDir =
|
|
115
|
+
self.scriptDir = "/tmp/t"
|
|
95
116
|
# Where should we put our virtualenv?
|
|
96
|
-
self.venvDir =
|
|
117
|
+
self.venvDir = "/tmp/venv"
|
|
97
118
|
# Where should we put our data to work on?
|
|
98
119
|
# Must exist in the Toil container; the leader will try to rsync to it
|
|
99
120
|
# (for the SSE key) and not create it.
|
|
100
|
-
self.dataDir =
|
|
121
|
+
self.dataDir = "/tmp"
|
|
101
122
|
# What filename should we use for our script (without path)?
|
|
102
123
|
# Can be changed by derived tests.
|
|
103
|
-
self.scriptName =
|
|
124
|
+
self.scriptName = "test_script.py"
|
|
104
125
|
|
|
105
126
|
def script(self):
|
|
106
127
|
"""
|
|
@@ -115,20 +136,35 @@ class AbstractAWSAutoscaleTest(AbstractClusterTest):
|
|
|
115
136
|
return os.path.join(self.dataDir, filename)
|
|
116
137
|
|
|
117
138
|
def rsyncUtil(self, src, dest):
|
|
118
|
-
subprocess.check_call(
|
|
139
|
+
subprocess.check_call(
|
|
140
|
+
[
|
|
141
|
+
"toil",
|
|
142
|
+
"rsync-cluster",
|
|
143
|
+
"--insecure",
|
|
144
|
+
"-p=aws",
|
|
145
|
+
"-z",
|
|
146
|
+
self.zone,
|
|
147
|
+
self.clusterName,
|
|
148
|
+
]
|
|
149
|
+
+ [src, dest]
|
|
150
|
+
)
|
|
119
151
|
|
|
120
152
|
def getRootVolID(self) -> str:
|
|
121
|
-
instances:
|
|
153
|
+
instances: list["InstanceTypeDef"] = self.cluster._get_nodes_in_cluster_boto3()
|
|
122
154
|
instances.sort(key=lambda x: x.get("LaunchTime"))
|
|
123
|
-
leader: InstanceTypeDef = instances[0] # assume leader was launched first
|
|
155
|
+
leader: "InstanceTypeDef" = instances[0] # assume leader was launched first
|
|
124
156
|
|
|
125
|
-
bdm: Optional[
|
|
157
|
+
bdm: Optional[list["InstanceBlockDeviceMappingTypeDef"]] = leader.get(
|
|
158
|
+
"BlockDeviceMappings"
|
|
159
|
+
)
|
|
126
160
|
assert bdm is not None
|
|
127
|
-
root_block_device: Optional[EbsInstanceBlockDeviceTypeDef] = None
|
|
161
|
+
root_block_device: Optional["EbsInstanceBlockDeviceTypeDef"] = None
|
|
128
162
|
for device in bdm:
|
|
129
163
|
if device["DeviceName"] == "/dev/xvda":
|
|
130
164
|
root_block_device = device["Ebs"]
|
|
131
|
-
assert
|
|
165
|
+
assert (
|
|
166
|
+
root_block_device is not None
|
|
167
|
+
) # There should be a device named "/dev/xvda"
|
|
132
168
|
assert root_block_device.get("VolumeId") is not None
|
|
133
169
|
return root_block_device["VolumeId"]
|
|
134
170
|
|
|
@@ -141,18 +177,19 @@ class AbstractAWSAutoscaleTest(AbstractClusterTest):
|
|
|
141
177
|
"""
|
|
142
178
|
Helper method for _getScript to inject a script file at the configured script path, from text.
|
|
143
179
|
"""
|
|
144
|
-
cluster = cluster_factory(
|
|
180
|
+
cluster = cluster_factory(
|
|
181
|
+
provisioner="aws", zone=self.zone, clusterName=self.clusterName
|
|
182
|
+
)
|
|
145
183
|
leader = cluster.getLeader()
|
|
146
184
|
|
|
147
|
-
self.sshUtil([
|
|
185
|
+
self.sshUtil(["mkdir", "-p", self.scriptDir])
|
|
148
186
|
|
|
149
|
-
with tempfile.NamedTemporaryFile(mode=
|
|
187
|
+
with tempfile.NamedTemporaryFile(mode="w") as t:
|
|
150
188
|
# use appliance ssh method instead of sshutil so we can specify input param
|
|
151
189
|
t.write(content)
|
|
152
190
|
# This works to make writes visible on non-Windows
|
|
153
191
|
t.flush()
|
|
154
|
-
leader.injectFile(t.name, self.script(),
|
|
155
|
-
|
|
192
|
+
leader.injectFile(t.name, self.script(), "toil_leader")
|
|
156
193
|
|
|
157
194
|
@abstractmethod
|
|
158
195
|
def _runScript(self, toilOptions):
|
|
@@ -171,40 +208,50 @@ class AbstractAWSAutoscaleTest(AbstractClusterTest):
|
|
|
171
208
|
self.launchCluster()
|
|
172
209
|
# get the leader so we know the IP address - we don't need to wait since create cluster
|
|
173
210
|
# already insures the leader is running
|
|
174
|
-
self.cluster = cluster_factory(
|
|
211
|
+
self.cluster = cluster_factory(
|
|
212
|
+
provisioner="aws", zone=self.zone, clusterName=self.clusterName
|
|
213
|
+
)
|
|
175
214
|
self.leader = self.cluster.getLeader()
|
|
176
|
-
self.sshUtil([
|
|
177
|
-
self.sshUtil([
|
|
215
|
+
self.sshUtil(["mkdir", "-p", self.scriptDir])
|
|
216
|
+
self.sshUtil(["mkdir", "-p", self.dataDir])
|
|
178
217
|
|
|
179
218
|
assert len(self.cluster._getRoleNames()) == 1
|
|
180
219
|
# --never-download prevents silent upgrades to pip, wheel and setuptools
|
|
181
|
-
venv_command = [
|
|
220
|
+
venv_command = [
|
|
221
|
+
"virtualenv",
|
|
222
|
+
"--system-site-packages",
|
|
223
|
+
"--python",
|
|
224
|
+
exactPython,
|
|
225
|
+
"--never-download",
|
|
226
|
+
self.venvDir,
|
|
227
|
+
]
|
|
182
228
|
self.sshUtil(venv_command)
|
|
183
229
|
|
|
184
|
-
log.info(
|
|
230
|
+
log.info("Set up script...")
|
|
185
231
|
self._getScript()
|
|
186
232
|
|
|
187
|
-
toilOptions = [
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
233
|
+
toilOptions = [
|
|
234
|
+
self.jobStore,
|
|
235
|
+
"--workDir=/var/lib/toil",
|
|
236
|
+
"--clean=always",
|
|
237
|
+
"--retryCount=2",
|
|
238
|
+
"--logDebug",
|
|
239
|
+
"--logFile=" + os.path.join(self.scriptDir, "sort.log"),
|
|
240
|
+
]
|
|
194
241
|
|
|
195
242
|
if preemptibleJobs:
|
|
196
|
-
toilOptions.extend([
|
|
243
|
+
toilOptions.extend(["--defaultPreemptible"])
|
|
197
244
|
|
|
198
|
-
log.info(
|
|
245
|
+
log.info("Run script...")
|
|
199
246
|
self._runScript(toilOptions)
|
|
200
247
|
|
|
201
248
|
assert len(self.cluster._getRoleNames()) == 1
|
|
202
249
|
|
|
203
250
|
volumeID = self.getRootVolID()
|
|
204
251
|
self.cluster.destroyCluster()
|
|
205
|
-
boto3_ec2: EC2Client = self.aws.client(region=self.region, service_name="ec2")
|
|
206
|
-
volume_filter: FilterTypeDef = {"Name": "volume-id", "Values": [volumeID]}
|
|
207
|
-
volumes: Optional[
|
|
252
|
+
boto3_ec2: "EC2Client" = self.aws.client(region=self.region, service_name="ec2")
|
|
253
|
+
volume_filter: "FilterTypeDef" = {"Name": "volume-id", "Values": [volumeID]}
|
|
254
|
+
volumes: Optional[list["VolumeTypeDef"]] = None
|
|
208
255
|
for attempt in range(6):
|
|
209
256
|
# https://github.com/BD2KGenomics/toil/issues/1567
|
|
210
257
|
# retry this for up to 1 minute until the volume disappears
|
|
@@ -214,7 +261,7 @@ class AbstractAWSAutoscaleTest(AbstractClusterTest):
|
|
|
214
261
|
break
|
|
215
262
|
time.sleep(10)
|
|
216
263
|
if volumes is None or len(volumes) > 0:
|
|
217
|
-
self.fail(
|
|
264
|
+
self.fail("Volume with ID %s was not cleaned up properly" % volumeID)
|
|
218
265
|
|
|
219
266
|
assert len(self.cluster._getRoleNames()) == 0
|
|
220
267
|
|
|
@@ -225,34 +272,49 @@ class AbstractAWSAutoscaleTest(AbstractClusterTest):
|
|
|
225
272
|
class AWSAutoscaleTest(AbstractAWSAutoscaleTest):
|
|
226
273
|
def __init__(self, name):
|
|
227
274
|
super().__init__(name)
|
|
228
|
-
self.clusterName =
|
|
275
|
+
self.clusterName = "provisioner-test-" + str(uuid4())
|
|
229
276
|
self.requestedLeaderStorage = 80
|
|
230
|
-
self.scriptName =
|
|
277
|
+
self.scriptName = "sort.py"
|
|
231
278
|
|
|
232
279
|
def setUp(self):
|
|
233
280
|
super().setUp()
|
|
234
|
-
self.jobStore = f
|
|
281
|
+
self.jobStore = f"aws:{self.awsRegion()}:autoscale-{uuid4()}"
|
|
235
282
|
|
|
236
283
|
def _getScript(self):
|
|
237
284
|
fileToSort = os.path.join(os.getcwd(), str(uuid4()))
|
|
238
|
-
with open(fileToSort,
|
|
285
|
+
with open(fileToSort, "w") as f:
|
|
239
286
|
# Fixme: making this file larger causes the test to hang
|
|
240
|
-
f.write(
|
|
241
|
-
self.rsyncUtil(
|
|
242
|
-
|
|
287
|
+
f.write("01234567890123456789012345678901")
|
|
288
|
+
self.rsyncUtil(
|
|
289
|
+
os.path.join(self._projectRootPath(), "src/toil/test/sort/sort.py"),
|
|
290
|
+
":" + self.script(),
|
|
291
|
+
)
|
|
292
|
+
self.rsyncUtil(fileToSort, ":" + self.data("sortFile"))
|
|
243
293
|
os.unlink(fileToSort)
|
|
244
294
|
|
|
245
295
|
def _runScript(self, toilOptions):
|
|
246
|
-
toilOptions.extend(
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
296
|
+
toilOptions.extend(
|
|
297
|
+
[
|
|
298
|
+
"--provisioner=aws",
|
|
299
|
+
"--batchSystem=mesos",
|
|
300
|
+
"--nodeTypes=" + ",".join(self.instanceTypes),
|
|
301
|
+
"--maxNodes=" + ",".join(self.numWorkers),
|
|
302
|
+
]
|
|
303
|
+
)
|
|
304
|
+
runCommand = [
|
|
305
|
+
self.python(),
|
|
306
|
+
self.script(),
|
|
307
|
+
"--fileToSort=" + self.data("sortFile"),
|
|
308
|
+
"--sseKey=" + self.data("sortFile"),
|
|
309
|
+
]
|
|
250
310
|
runCommand.extend(toilOptions)
|
|
251
311
|
self.sshUtil(runCommand)
|
|
252
312
|
|
|
253
313
|
def launchCluster(self):
|
|
254
314
|
# add arguments to test that we can specify leader storage
|
|
255
|
-
self.createClusterUtil(
|
|
315
|
+
self.createClusterUtil(
|
|
316
|
+
args=["--leaderStorage", str(self.requestedLeaderStorage)]
|
|
317
|
+
)
|
|
256
318
|
|
|
257
319
|
def getRootVolID(self) -> str:
|
|
258
320
|
"""
|
|
@@ -261,10 +323,12 @@ class AWSAutoscaleTest(AbstractAWSAutoscaleTest):
|
|
|
261
323
|
:return: volumeID
|
|
262
324
|
"""
|
|
263
325
|
volumeID = super().getRootVolID()
|
|
264
|
-
boto3_ec2: EC2Client = self.aws.client(region=self.region, service_name="ec2")
|
|
265
|
-
volume_filter: FilterTypeDef = {"Name": "volume-id", "Values": [volumeID]}
|
|
266
|
-
volumes: DescribeVolumesResultTypeDef = boto3_ec2.describe_volumes(
|
|
267
|
-
|
|
326
|
+
boto3_ec2: "EC2Client" = self.aws.client(region=self.region, service_name="ec2")
|
|
327
|
+
volume_filter: "FilterTypeDef" = {"Name": "volume-id", "Values": [volumeID]}
|
|
328
|
+
volumes: "DescribeVolumesResultTypeDef" = boto3_ec2.describe_volumes(
|
|
329
|
+
Filters=[volume_filter]
|
|
330
|
+
)
|
|
331
|
+
root_volume: "VolumeTypeDef" = volumes["Volumes"][0] # should be first
|
|
268
332
|
# test that the leader is given adequate storage
|
|
269
333
|
self.assertGreaterEqual(root_volume["Size"], self.requestedLeaderStorage)
|
|
270
334
|
return volumeID
|
|
@@ -273,21 +337,21 @@ class AWSAutoscaleTest(AbstractAWSAutoscaleTest):
|
|
|
273
337
|
@needs_aws_ec2
|
|
274
338
|
def testAutoScale(self):
|
|
275
339
|
self.instanceTypes = ["m5a.large"]
|
|
276
|
-
self.numWorkers = [
|
|
340
|
+
self.numWorkers = ["2"]
|
|
277
341
|
self._test()
|
|
278
342
|
|
|
279
343
|
@integrative
|
|
280
344
|
@needs_aws_ec2
|
|
281
345
|
def testSpotAutoScale(self):
|
|
282
346
|
self.instanceTypes = ["m5a.large:%f" % self.spotBid]
|
|
283
|
-
self.numWorkers = [
|
|
347
|
+
self.numWorkers = ["2"]
|
|
284
348
|
self._test(preemptibleJobs=True)
|
|
285
349
|
|
|
286
350
|
@integrative
|
|
287
351
|
@needs_aws_ec2
|
|
288
352
|
def testSpotAutoScaleBalancingTypes(self):
|
|
289
353
|
self.instanceTypes = ["m5.large/m5a.large:%f" % self.spotBid]
|
|
290
|
-
self.numWorkers = [
|
|
354
|
+
self.numWorkers = ["2"]
|
|
291
355
|
self._test(preemptibleJobs=True)
|
|
292
356
|
|
|
293
357
|
|
|
@@ -296,23 +360,35 @@ class AWSAutoscaleTest(AbstractAWSAutoscaleTest):
|
|
|
296
360
|
@pytest.mark.timeout(2400)
|
|
297
361
|
class AWSStaticAutoscaleTest(AWSAutoscaleTest):
|
|
298
362
|
"""Runs the tests on a statically provisioned cluster with autoscaling enabled."""
|
|
363
|
+
|
|
299
364
|
def __init__(self, name):
|
|
300
365
|
super().__init__(name)
|
|
301
366
|
self.requestedNodeStorage = 20
|
|
302
367
|
|
|
303
368
|
def launchCluster(self):
|
|
304
369
|
from toil.lib.ec2 import wait_instances_running
|
|
305
|
-
self.createClusterUtil(args=['--leaderStorage', str(self.requestedLeaderStorage),
|
|
306
|
-
'--nodeTypes', ",".join(self.instanceTypes),
|
|
307
|
-
'-w', ",".join(self.numWorkers),
|
|
308
|
-
'--nodeStorage', str(self.requestedLeaderStorage)])
|
|
309
370
|
|
|
310
|
-
self.
|
|
371
|
+
self.createClusterUtil(
|
|
372
|
+
args=[
|
|
373
|
+
"--leaderStorage",
|
|
374
|
+
str(self.requestedLeaderStorage),
|
|
375
|
+
"--nodeTypes",
|
|
376
|
+
",".join(self.instanceTypes),
|
|
377
|
+
"-w",
|
|
378
|
+
",".join(self.numWorkers),
|
|
379
|
+
"--nodeStorage",
|
|
380
|
+
str(self.requestedLeaderStorage),
|
|
381
|
+
]
|
|
382
|
+
)
|
|
383
|
+
|
|
384
|
+
self.cluster = cluster_factory(
|
|
385
|
+
provisioner="aws", zone=self.zone, clusterName=self.clusterName
|
|
386
|
+
)
|
|
311
387
|
# We need to wait a little bit here because the workers might not be
|
|
312
388
|
# visible to EC2 read requests immediately after the create returns,
|
|
313
389
|
# which is the last thing that starting the cluster does.
|
|
314
390
|
time.sleep(10)
|
|
315
|
-
nodes:
|
|
391
|
+
nodes: list["InstanceTypeDef"] = self.cluster._get_nodes_in_cluster_boto3()
|
|
316
392
|
nodes.sort(key=lambda x: x.get("LaunchTime"))
|
|
317
393
|
# assuming that leader is first
|
|
318
394
|
workers = nodes[1:]
|
|
@@ -321,29 +397,49 @@ class AWSStaticAutoscaleTest(AWSAutoscaleTest):
|
|
|
321
397
|
# test that workers have expected storage size
|
|
322
398
|
# just use the first worker
|
|
323
399
|
worker = workers[0]
|
|
324
|
-
boto3_ec2: EC2Client = self.aws.client(region=self.region, service_name="ec2")
|
|
400
|
+
boto3_ec2: "EC2Client" = self.aws.client(region=self.region, service_name="ec2")
|
|
325
401
|
|
|
326
|
-
worker: InstanceTypeDef = next(wait_instances_running(boto3_ec2, [worker]))
|
|
402
|
+
worker: "InstanceTypeDef" = next(wait_instances_running(boto3_ec2, [worker]))
|
|
327
403
|
|
|
328
|
-
bdm: Optional[
|
|
404
|
+
bdm: Optional[list["InstanceBlockDeviceMappingTypeDef"]] = worker.get(
|
|
405
|
+
"BlockDeviceMappings"
|
|
406
|
+
)
|
|
329
407
|
assert bdm is not None
|
|
330
|
-
root_block_device: Optional[EbsInstanceBlockDeviceTypeDef] = None
|
|
408
|
+
root_block_device: Optional["EbsInstanceBlockDeviceTypeDef"] = None
|
|
331
409
|
for device in bdm:
|
|
332
410
|
if device["DeviceName"] == "/dev/xvda":
|
|
333
411
|
root_block_device = device["Ebs"]
|
|
334
412
|
assert root_block_device is not None
|
|
335
|
-
assert
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
413
|
+
assert (
|
|
414
|
+
root_block_device.get("VolumeId") is not None
|
|
415
|
+
) # TypedDicts cannot have runtime type checks
|
|
416
|
+
|
|
417
|
+
volume_filter: "FilterTypeDef" = {
|
|
418
|
+
"Name": "volume-id",
|
|
419
|
+
"Values": [root_block_device["VolumeId"]],
|
|
420
|
+
}
|
|
421
|
+
root_volume: "VolumeTypeDef" = boto3_ec2.describe_volumes(
|
|
422
|
+
Filters=[volume_filter]
|
|
423
|
+
)["Volumes"][
|
|
424
|
+
0
|
|
425
|
+
] # should be first
|
|
339
426
|
self.assertGreaterEqual(root_volume.get("Size"), self.requestedNodeStorage)
|
|
340
427
|
|
|
341
428
|
def _runScript(self, toilOptions):
|
|
342
429
|
# Autoscale even though we have static nodes
|
|
343
|
-
toilOptions.extend(
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
430
|
+
toilOptions.extend(
|
|
431
|
+
[
|
|
432
|
+
"--provisioner=aws",
|
|
433
|
+
"--batchSystem=mesos",
|
|
434
|
+
"--nodeTypes=" + ",".join(self.instanceTypes),
|
|
435
|
+
"--maxNodes=" + ",".join(self.numWorkers),
|
|
436
|
+
]
|
|
437
|
+
)
|
|
438
|
+
runCommand = [
|
|
439
|
+
self.python(),
|
|
440
|
+
self.script(),
|
|
441
|
+
"--fileToSort=" + self.data("sortFile"),
|
|
442
|
+
]
|
|
347
443
|
runCommand.extend(toilOptions)
|
|
348
444
|
self.sshUtil(runCommand)
|
|
349
445
|
|
|
@@ -352,23 +448,39 @@ class AWSStaticAutoscaleTest(AWSAutoscaleTest):
|
|
|
352
448
|
@pytest.mark.timeout(1200)
|
|
353
449
|
class AWSManagedAutoscaleTest(AWSAutoscaleTest):
|
|
354
450
|
"""Runs the tests on a self-scaling Kubernetes cluster."""
|
|
451
|
+
|
|
355
452
|
def __init__(self, name):
|
|
356
453
|
super().__init__(name)
|
|
357
454
|
self.requestedNodeStorage = 20
|
|
358
455
|
|
|
359
456
|
def launchCluster(self):
|
|
360
|
-
self.createClusterUtil(
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
457
|
+
self.createClusterUtil(
|
|
458
|
+
args=[
|
|
459
|
+
"--leaderStorage",
|
|
460
|
+
str(self.requestedLeaderStorage),
|
|
461
|
+
"--nodeTypes",
|
|
462
|
+
",".join(self.instanceTypes),
|
|
463
|
+
"--workers",
|
|
464
|
+
",".join([f"0-{c}" for c in self.numWorkers]),
|
|
465
|
+
"--nodeStorage",
|
|
466
|
+
str(self.requestedLeaderStorage),
|
|
467
|
+
"--clusterType",
|
|
468
|
+
"kubernetes",
|
|
469
|
+
]
|
|
470
|
+
)
|
|
471
|
+
|
|
472
|
+
self.cluster = cluster_factory(
|
|
473
|
+
provisioner="aws", zone=self.zone, clusterName=self.clusterName
|
|
474
|
+
)
|
|
367
475
|
|
|
368
476
|
def _runScript(self, toilOptions):
|
|
369
477
|
# Don't use the provisioner, and use Kubernetes instead of Mesos
|
|
370
|
-
toilOptions.extend([
|
|
371
|
-
runCommand = [
|
|
478
|
+
toilOptions.extend(["--batchSystem=kubernetes"])
|
|
479
|
+
runCommand = [
|
|
480
|
+
self.python(),
|
|
481
|
+
self.script(),
|
|
482
|
+
"--fileToSort=" + self.data("sortFile"),
|
|
483
|
+
]
|
|
372
484
|
runCommand.extend(toilOptions)
|
|
373
485
|
self.sshUtil(runCommand)
|
|
374
486
|
|
|
@@ -379,37 +491,51 @@ class AWSManagedAutoscaleTest(AWSAutoscaleTest):
|
|
|
379
491
|
class AWSAutoscaleTestMultipleNodeTypes(AbstractAWSAutoscaleTest):
|
|
380
492
|
def __init__(self, name):
|
|
381
493
|
super().__init__(name)
|
|
382
|
-
self.clusterName =
|
|
494
|
+
self.clusterName = "provisioner-test-" + str(uuid4())
|
|
383
495
|
|
|
384
496
|
def setUp(self):
|
|
385
497
|
super().setUp()
|
|
386
|
-
self.jobStore = f
|
|
498
|
+
self.jobStore = f"aws:{self.awsRegion()}:autoscale-{uuid4()}"
|
|
387
499
|
|
|
388
500
|
def _getScript(self):
|
|
389
|
-
sseKeyFile = os.path.join(os.getcwd(),
|
|
390
|
-
with open(sseKeyFile,
|
|
391
|
-
f.write(
|
|
392
|
-
self.rsyncUtil(
|
|
393
|
-
|
|
501
|
+
sseKeyFile = os.path.join(os.getcwd(), "keyFile")
|
|
502
|
+
with open(sseKeyFile, "w") as f:
|
|
503
|
+
f.write("01234567890123456789012345678901")
|
|
504
|
+
self.rsyncUtil(
|
|
505
|
+
os.path.join(self._projectRootPath(), "src/toil/test/sort/sort.py"),
|
|
506
|
+
":" + self.script(),
|
|
507
|
+
)
|
|
508
|
+
self.rsyncUtil(sseKeyFile, ":" + self.data("keyFile"))
|
|
394
509
|
os.unlink(sseKeyFile)
|
|
395
510
|
|
|
396
511
|
def _runScript(self, toilOptions):
|
|
397
512
|
# Set memory requirements so that sort jobs can be run
|
|
398
513
|
# on small instances, but merge jobs must be run on large
|
|
399
514
|
# instances
|
|
400
|
-
toilOptions.extend(
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
515
|
+
toilOptions.extend(
|
|
516
|
+
[
|
|
517
|
+
"--provisioner=aws",
|
|
518
|
+
"--batchSystem=mesos",
|
|
519
|
+
"--nodeTypes=" + ",".join(self.instanceTypes),
|
|
520
|
+
"--maxNodes=" + ",".join(self.numWorkers),
|
|
521
|
+
]
|
|
522
|
+
)
|
|
523
|
+
runCommand = [
|
|
524
|
+
self.python(),
|
|
525
|
+
self.script(),
|
|
526
|
+
"--fileToSort=/home/s3am/bin/asadmin",
|
|
527
|
+
"--sortMemory=0.6G",
|
|
528
|
+
"--mergeMemory=3.0G",
|
|
529
|
+
]
|
|
404
530
|
runCommand.extend(toilOptions)
|
|
405
|
-
runCommand.append(
|
|
531
|
+
runCommand.append("--sseKey=" + self.data("keyFile"))
|
|
406
532
|
self.sshUtil(runCommand)
|
|
407
533
|
|
|
408
534
|
@integrative
|
|
409
535
|
@needs_aws_ec2
|
|
410
536
|
def testAutoScale(self):
|
|
411
537
|
self.instanceTypes = ["t2.small", "m5a.large"]
|
|
412
|
-
self.numWorkers = [
|
|
538
|
+
self.numWorkers = ["2", "1"]
|
|
413
539
|
self._test()
|
|
414
540
|
|
|
415
541
|
|
|
@@ -418,16 +544,17 @@ class AWSAutoscaleTestMultipleNodeTypes(AbstractAWSAutoscaleTest):
|
|
|
418
544
|
@pytest.mark.timeout(1200)
|
|
419
545
|
class AWSRestartTest(AbstractAWSAutoscaleTest):
|
|
420
546
|
"""This test insures autoscaling works on a restarted Toil run."""
|
|
547
|
+
|
|
421
548
|
def __init__(self, name):
|
|
422
549
|
super().__init__(name)
|
|
423
|
-
self.clusterName =
|
|
424
|
-
self.scriptName =
|
|
550
|
+
self.clusterName = "restart-test-" + str(uuid4())
|
|
551
|
+
self.scriptName = "restartScript.py"
|
|
425
552
|
|
|
426
553
|
def setUp(self):
|
|
427
554
|
super().setUp()
|
|
428
|
-
self.instanceTypes = [
|
|
429
|
-
self.numWorkers = [
|
|
430
|
-
self.jobStore = f
|
|
555
|
+
self.instanceTypes = ["t2.small"]
|
|
556
|
+
self.numWorkers = ["1"]
|
|
557
|
+
self.jobStore = f"aws:{self.awsRegion()}:restart-{uuid4()}"
|
|
431
558
|
|
|
432
559
|
def _getScript(self):
|
|
433
560
|
def restartScript():
|
|
@@ -438,38 +565,56 @@ class AWSRestartTest(AbstractAWSAutoscaleTest):
|
|
|
438
565
|
from toil.job import Job
|
|
439
566
|
|
|
440
567
|
def f0(job):
|
|
441
|
-
if
|
|
442
|
-
raise RuntimeError(
|
|
568
|
+
if "FAIL" in os.environ:
|
|
569
|
+
raise RuntimeError("failed on purpose")
|
|
443
570
|
|
|
444
|
-
if __name__ ==
|
|
571
|
+
if __name__ == "__main__":
|
|
445
572
|
parser = ArgumentParser()
|
|
446
573
|
Job.Runner.addToilOptions(parser)
|
|
447
574
|
options = parser.parse_args()
|
|
448
|
-
rootJob = Job.wrapJobFn(f0, cores=0.5, memory=
|
|
575
|
+
rootJob = Job.wrapJobFn(f0, cores=0.5, memory="50 M", disk="50 M")
|
|
449
576
|
Job.Runner.startToil(rootJob, options)
|
|
450
577
|
|
|
451
|
-
script = dedent(
|
|
578
|
+
script = dedent("\n".join(getsource(restartScript).split("\n")[1:]))
|
|
452
579
|
self.putScript(script)
|
|
453
580
|
|
|
454
581
|
def _runScript(self, toilOptions):
|
|
455
582
|
# Use the provisioner in the workflow
|
|
456
|
-
toilOptions.extend(
|
|
457
|
-
|
|
458
|
-
|
|
583
|
+
toilOptions.extend(
|
|
584
|
+
[
|
|
585
|
+
"--provisioner=aws",
|
|
586
|
+
"--batchSystem=mesos",
|
|
587
|
+
"--nodeTypes=" + ",".join(self.instanceTypes),
|
|
588
|
+
"--maxNodes=" + ",".join(self.numWorkers),
|
|
589
|
+
]
|
|
590
|
+
)
|
|
459
591
|
# clean = onSuccess
|
|
460
|
-
disallowedOptions = [
|
|
461
|
-
newOptions = [
|
|
592
|
+
disallowedOptions = ["--clean=always", "--retryCount=2"]
|
|
593
|
+
newOptions = [
|
|
594
|
+
option for option in toilOptions if option not in disallowedOptions
|
|
595
|
+
]
|
|
462
596
|
try:
|
|
463
597
|
# include a default memory - on restart the minimum memory requirement is the default, usually 2 GB
|
|
464
|
-
command = [
|
|
598
|
+
command = [
|
|
599
|
+
self.python(),
|
|
600
|
+
self.script(),
|
|
601
|
+
"--setEnv",
|
|
602
|
+
"FAIL=true",
|
|
603
|
+
"--defaultMemory=50000000",
|
|
604
|
+
]
|
|
465
605
|
command.extend(newOptions)
|
|
466
606
|
self.sshUtil(command)
|
|
467
607
|
except subprocess.CalledProcessError:
|
|
468
608
|
pass
|
|
469
609
|
else:
|
|
470
|
-
self.fail(
|
|
610
|
+
self.fail("Command succeeded when we expected failure")
|
|
471
611
|
with timeLimit(600):
|
|
472
|
-
command = [
|
|
612
|
+
command = [
|
|
613
|
+
self.python(),
|
|
614
|
+
self.script(),
|
|
615
|
+
"--restart",
|
|
616
|
+
"--defaultMemory=50000000",
|
|
617
|
+
]
|
|
473
618
|
command.extend(toilOptions)
|
|
474
619
|
self.sshUtil(command)
|
|
475
620
|
|
|
@@ -483,14 +628,17 @@ class AWSRestartTest(AbstractAWSAutoscaleTest):
|
|
|
483
628
|
class PreemptibleDeficitCompensationTest(AbstractAWSAutoscaleTest):
|
|
484
629
|
def __init__(self, name):
|
|
485
630
|
super().__init__(name)
|
|
486
|
-
self.clusterName =
|
|
487
|
-
self.scriptName =
|
|
631
|
+
self.clusterName = "deficit-test-" + str(uuid4())
|
|
632
|
+
self.scriptName = "userScript.py"
|
|
488
633
|
|
|
489
634
|
def setUp(self):
|
|
490
635
|
super().setUp()
|
|
491
|
-
self.instanceTypes = [
|
|
492
|
-
|
|
493
|
-
|
|
636
|
+
self.instanceTypes = [
|
|
637
|
+
"m5a.large:0.01",
|
|
638
|
+
"m5a.large",
|
|
639
|
+
] # instance needs to be available on the spot market
|
|
640
|
+
self.numWorkers = ["1", "1"]
|
|
641
|
+
self.jobStore = f"aws:{self.awsRegion()}:deficit-{uuid4()}"
|
|
494
642
|
|
|
495
643
|
def test(self):
|
|
496
644
|
self._test(preemptibleJobs=True)
|
|
@@ -507,10 +655,10 @@ class PreemptibleDeficitCompensationTest(AbstractAWSAutoscaleTest):
|
|
|
507
655
|
# we will observe a deficit of preemptible nodes that the non-preemptible scaler will
|
|
508
656
|
# compensate for by spinning up non-preemptible nodes instead.
|
|
509
657
|
#
|
|
510
|
-
def job(job, disk=
|
|
658
|
+
def job(job, disk="10M", cores=1, memory="10M", preemptible=True):
|
|
511
659
|
pass
|
|
512
660
|
|
|
513
|
-
if __name__ ==
|
|
661
|
+
if __name__ == "__main__":
|
|
514
662
|
options = Job.Runner.getDefaultArgumentParser().parse_args()
|
|
515
663
|
with Toil(options) as toil:
|
|
516
664
|
if toil.config.restart:
|
|
@@ -518,14 +666,19 @@ class PreemptibleDeficitCompensationTest(AbstractAWSAutoscaleTest):
|
|
|
518
666
|
else:
|
|
519
667
|
toil.start(Job.wrapJobFn(job))
|
|
520
668
|
|
|
521
|
-
script = dedent(
|
|
669
|
+
script = dedent("\n".join(getsource(userScript).split("\n")[1:]))
|
|
522
670
|
self.putScript(script)
|
|
523
671
|
|
|
524
672
|
def _runScript(self, toilOptions):
|
|
525
|
-
toilOptions.extend(
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
673
|
+
toilOptions.extend(
|
|
674
|
+
[
|
|
675
|
+
"--provisioner=aws",
|
|
676
|
+
"--batchSystem=mesos",
|
|
677
|
+
"--nodeTypes=" + ",".join(self.instanceTypes),
|
|
678
|
+
"--maxNodes=" + ",".join(self.numWorkers),
|
|
679
|
+
]
|
|
680
|
+
)
|
|
681
|
+
toilOptions.extend(["--preemptibleCompensation=1.0"])
|
|
529
682
|
command = [self.python(), self.script()]
|
|
530
683
|
command.extend(toilOptions)
|
|
531
684
|
self.sshUtil(command)
|