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
toil/utils/toilLaunchCluster.py
CHANGED
|
@@ -15,25 +15,27 @@
|
|
|
15
15
|
|
|
16
16
|
import logging
|
|
17
17
|
import os
|
|
18
|
-
from typing import
|
|
18
|
+
from typing import Union
|
|
19
19
|
|
|
20
20
|
from toil import applianceSelf
|
|
21
21
|
from toil.common import parser_with_common_options
|
|
22
|
-
|
|
22
|
+
|
|
23
|
+
try:
|
|
24
|
+
from toil.lib.aws import build_tag_dict_from_env
|
|
25
|
+
except ModuleNotFoundError:
|
|
26
|
+
build_tag_dict_from_env: dict[str, str] = lambda _: {} # type: ignore[no-redef]
|
|
23
27
|
from toil.lib.conversions import opt_strtobool
|
|
24
|
-
from toil.provisioners import
|
|
25
|
-
cluster_factory,
|
|
26
|
-
parse_node_types)
|
|
28
|
+
from toil.provisioners import check_valid_node_types, cluster_factory, parse_node_types
|
|
27
29
|
from toil.statsAndLogging import set_logging_from_options
|
|
28
30
|
|
|
29
31
|
logger = logging.getLogger(__name__)
|
|
30
32
|
|
|
31
33
|
|
|
32
|
-
def create_tags_dict(tags:
|
|
34
|
+
def create_tags_dict(tags: list[str]) -> dict[str, str]:
|
|
33
35
|
tags_dict = dict()
|
|
34
36
|
for tag in tags:
|
|
35
37
|
try:
|
|
36
|
-
key, value = tag.split(
|
|
38
|
+
key, value = tag.split("=")
|
|
37
39
|
except ValueError:
|
|
38
40
|
logger.error("Tag specification '%s' must contain '='", tag)
|
|
39
41
|
raise
|
|
@@ -42,88 +44,160 @@ def create_tags_dict(tags: List[str]) -> Dict[str, str]:
|
|
|
42
44
|
|
|
43
45
|
|
|
44
46
|
def main() -> None:
|
|
45
|
-
parser = parser_with_common_options(
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
parser.add_argument(
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
parser.add_argument(
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
parser.add_argument(
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
47
|
+
parser = parser_with_common_options(
|
|
48
|
+
provisioner_options=True, jobstore_option=False, prog="toil launch-cluster"
|
|
49
|
+
)
|
|
50
|
+
parser.add_argument(
|
|
51
|
+
"-T",
|
|
52
|
+
"--clusterType",
|
|
53
|
+
dest="clusterType",
|
|
54
|
+
choices=["mesos", "kubernetes"],
|
|
55
|
+
default=None, # TODO: change default to "kubernetes" when we are ready.
|
|
56
|
+
help="Cluster scheduler to use.",
|
|
57
|
+
)
|
|
58
|
+
parser.add_argument(
|
|
59
|
+
"--leaderNodeType",
|
|
60
|
+
dest="leaderNodeType",
|
|
61
|
+
required=True,
|
|
62
|
+
help="Non-preemptible node type to use for the cluster leader.",
|
|
63
|
+
)
|
|
64
|
+
parser.add_argument(
|
|
65
|
+
"--keyPairName",
|
|
66
|
+
dest="keyPairName",
|
|
67
|
+
help="On AWS, the name of the AWS key pair to include on the instance."
|
|
68
|
+
" On Google/GCE, this is the ssh key pair.",
|
|
69
|
+
)
|
|
70
|
+
parser.add_argument(
|
|
71
|
+
"--owner",
|
|
72
|
+
dest="owner",
|
|
73
|
+
help="The owner tag for all instances. If not given, the value in"
|
|
74
|
+
"TOIL_OWNER_TAG will be used, or else the value of --keyPairName.",
|
|
75
|
+
)
|
|
76
|
+
parser.add_argument(
|
|
77
|
+
"--boto",
|
|
78
|
+
dest="botoPath",
|
|
79
|
+
help="The path to the boto credentials directory. This is transferred "
|
|
80
|
+
"to all nodes in order to access the AWS jobStore from non-AWS instances.",
|
|
81
|
+
)
|
|
82
|
+
parser.add_argument(
|
|
83
|
+
"-t",
|
|
84
|
+
"--tag",
|
|
85
|
+
metavar="NAME=VALUE",
|
|
86
|
+
dest="tags",
|
|
87
|
+
default=[],
|
|
88
|
+
action="append",
|
|
89
|
+
help="Tags are added to the AWS cluster for this node and all of its "
|
|
90
|
+
"children. Tags are of the form:\n"
|
|
91
|
+
" -t key1=value1 --tag key2=value2\n"
|
|
92
|
+
"Multiple tags are allowed and each tag needs its own flag. By "
|
|
93
|
+
"default the cluster is tagged with "
|
|
94
|
+
" {\n"
|
|
95
|
+
' "Name": clusterName,\n'
|
|
96
|
+
' "Owner": IAM username\n'
|
|
97
|
+
" }. ",
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
parser.add_argument(
|
|
101
|
+
"--network", help="GCE cloud network to use. default: 'default'"
|
|
102
|
+
)
|
|
103
|
+
parser.add_argument(
|
|
104
|
+
"--vpcSubnet",
|
|
105
|
+
help="VPC subnet ID to launch cluster leader in. Uses default subnet "
|
|
106
|
+
"if not specified. This subnet needs to have auto assign IPs turned on.",
|
|
107
|
+
)
|
|
108
|
+
parser.add_argument(
|
|
109
|
+
"--use_private_ip",
|
|
110
|
+
dest="use_private_ip",
|
|
111
|
+
action="store_true",
|
|
112
|
+
default=False,
|
|
113
|
+
help="if specified, ignore the public ip of the nodes",
|
|
114
|
+
)
|
|
115
|
+
parser.add_argument(
|
|
116
|
+
"--nodeTypes",
|
|
117
|
+
dest="nodeTypes",
|
|
118
|
+
default=None,
|
|
119
|
+
type=str,
|
|
120
|
+
help="Specifies a list of comma-separated node types, each of which is "
|
|
121
|
+
"composed of slash-separated instance types, and an optional spot "
|
|
122
|
+
"bid set off by a colon, making the node type preemptible. Instance "
|
|
123
|
+
"types may appear in multiple node types, and the same node type "
|
|
124
|
+
"may appear as both preemptible and non-preemptible.\n"
|
|
125
|
+
"Valid argument specifying two node types:\n"
|
|
126
|
+
"\tc5.4xlarge/c5a.4xlarge:0.42,t2.large\n"
|
|
127
|
+
"Node types:\n"
|
|
128
|
+
"\tc5.4xlarge/c5a.4xlarge:0.42 and t2.large\n"
|
|
129
|
+
"Instance types:\n"
|
|
130
|
+
"\tc5.4xlarge, c5a.4xlarge, and t2.large\n"
|
|
131
|
+
"Semantics:\n"
|
|
132
|
+
"\tBid $0.42/hour for either c5.4xlarge or c5a.4xlarge instances,\n"
|
|
133
|
+
"\ttreated interchangeably, while they are available at that price,\n"
|
|
134
|
+
"\tand buy t2.large instances at full price\n"
|
|
135
|
+
"Must also provide the --workers argument to specify how many "
|
|
136
|
+
"workers of each node type to create.",
|
|
137
|
+
)
|
|
138
|
+
parser.add_argument(
|
|
139
|
+
"-w",
|
|
140
|
+
"--workers",
|
|
141
|
+
dest="workers",
|
|
142
|
+
default=None,
|
|
143
|
+
type=str,
|
|
144
|
+
help="Comma-separated list of the ranges of numbers of workers of each "
|
|
145
|
+
"node type to launch, such as '0-2,5,1-3'. If a range is given, "
|
|
146
|
+
"workers will automatically be launched and terminated by the cluster "
|
|
147
|
+
"to auto-scale to the workload.",
|
|
148
|
+
)
|
|
149
|
+
parser.add_argument(
|
|
150
|
+
"--leaderStorage",
|
|
151
|
+
dest="leaderStorage",
|
|
152
|
+
type=int,
|
|
153
|
+
default=50,
|
|
154
|
+
help="Specify the size (in gigabytes) of the root volume for the leader "
|
|
155
|
+
"instance. This is an EBS volume.",
|
|
156
|
+
)
|
|
157
|
+
parser.add_argument(
|
|
158
|
+
"--nodeStorage",
|
|
159
|
+
dest="nodeStorage",
|
|
160
|
+
type=int,
|
|
161
|
+
default=50,
|
|
162
|
+
help="Specify the size (in gigabytes) of the root volume for any worker "
|
|
163
|
+
"instances created when using the -w flag. This is an EBS volume.",
|
|
164
|
+
)
|
|
165
|
+
parser.add_argument(
|
|
166
|
+
"--forceDockerAppliance",
|
|
167
|
+
dest="forceDockerAppliance",
|
|
168
|
+
action="store_true",
|
|
169
|
+
default=False,
|
|
170
|
+
help="Disables sanity checking the existence of the docker image specified "
|
|
171
|
+
"by TOIL_APPLIANCE_SELF, which Toil uses to provision mesos for "
|
|
172
|
+
"autoscaling.",
|
|
173
|
+
)
|
|
174
|
+
parser.add_argument(
|
|
175
|
+
"--awsEc2ProfileArn",
|
|
176
|
+
dest="awsEc2ProfileArn",
|
|
177
|
+
default=None,
|
|
178
|
+
type=str,
|
|
179
|
+
help="If provided, the specified ARN is used as the instance profile for EC2 instances."
|
|
180
|
+
"Useful for setting custom IAM profiles. If not specified, a new IAM role is created "
|
|
181
|
+
"by default with sufficient access to perform basic cluster operations.",
|
|
182
|
+
)
|
|
183
|
+
parser.add_argument(
|
|
184
|
+
"--awsEc2ExtraSecurityGroupId",
|
|
185
|
+
dest="awsEc2ExtraSecurityGroupIds",
|
|
186
|
+
default=[],
|
|
187
|
+
action="append",
|
|
188
|
+
help="Any additional security groups to attach to EC2 instances. Note that a security group "
|
|
189
|
+
"with its name equal to the cluster name will always be created, thus ensure that "
|
|
190
|
+
"the extra security groups do not have the same name as the cluster name.",
|
|
191
|
+
)
|
|
192
|
+
parser.add_argument(
|
|
193
|
+
"--allowFuse",
|
|
194
|
+
type=opt_strtobool,
|
|
195
|
+
default=True,
|
|
196
|
+
help="Enable both the leader and worker nodes to be able to run Singularity with FUSE. For "
|
|
197
|
+
"Kubernetes, this will make the leader privileged and ask workers to run as privileged. "
|
|
198
|
+
"(default: %(default)s)",
|
|
199
|
+
)
|
|
200
|
+
# TODO Set Aws Profile in CLI options
|
|
127
201
|
options = parser.parse_args()
|
|
128
202
|
set_logging_from_options(options)
|
|
129
203
|
|
|
@@ -131,75 +205,94 @@ def main() -> None:
|
|
|
131
205
|
|
|
132
206
|
# Get worker node types
|
|
133
207
|
worker_node_types = parse_node_types(options.nodeTypes)
|
|
134
|
-
check_valid_node_types(
|
|
208
|
+
check_valid_node_types(
|
|
209
|
+
options.provisioner, worker_node_types + [({options.leaderNodeType}, None)]
|
|
210
|
+
)
|
|
135
211
|
|
|
136
212
|
# Holds string ranges, like "5", or "3-10"
|
|
137
|
-
worker_node_ranges = options.workers.split(
|
|
213
|
+
worker_node_ranges = options.workers.split(",") if options.workers else []
|
|
138
214
|
|
|
139
215
|
# checks the validity of TOIL_APPLIANCE_SELF before proceeding
|
|
140
216
|
applianceSelf(forceDockerAppliance=options.forceDockerAppliance)
|
|
141
217
|
|
|
142
218
|
# This holds either ints to launch static nodes, or tuples of ints
|
|
143
219
|
# specifying ranges to launch managed auto-scaling nodes, for each type.
|
|
144
|
-
nodeCounts:
|
|
220
|
+
nodeCounts: list[Union[int, tuple[int, int]]] = []
|
|
145
221
|
|
|
146
|
-
if (
|
|
147
|
-
|
|
222
|
+
if (worker_node_types != [] or worker_node_ranges != []) and not (
|
|
223
|
+
worker_node_types != [] and worker_node_ranges != []
|
|
224
|
+
):
|
|
148
225
|
raise RuntimeError("The --nodeTypes option requires --workers, and visa versa.")
|
|
149
226
|
if worker_node_types and worker_node_ranges:
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
227
|
+
if not len(worker_node_types) == len(worker_node_ranges):
|
|
228
|
+
raise RuntimeError(
|
|
229
|
+
"List of worker count ranges must be the same length as the list of node types."
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
for spec in worker_node_ranges:
|
|
233
|
+
if "-" in spec:
|
|
234
|
+
# Provision via autoscaling
|
|
235
|
+
parts = spec.split("-")
|
|
236
|
+
if len(parts) != 2:
|
|
237
|
+
raise RuntimeError("Unacceptable range: " + spec)
|
|
238
|
+
nodeCounts.append((int(parts[0]), int(parts[1])))
|
|
239
|
+
else:
|
|
240
|
+
# Provision fixed nodes
|
|
241
|
+
nodeCounts.append(int(spec))
|
|
242
|
+
|
|
243
|
+
owner = (
|
|
244
|
+
options.owner or os.getenv("TOIL_OWNER_TAG") or options.keyPairName or "toil"
|
|
245
|
+
)
|
|
165
246
|
|
|
166
247
|
# Check to see if the user specified a zone. If not, see if one is stored in an environment variable.
|
|
167
|
-
options.zone = options.zone or os.environ.get(
|
|
248
|
+
options.zone = options.zone or os.environ.get(
|
|
249
|
+
f"TOIL_{options.provisioner.upper()}_ZONE"
|
|
250
|
+
)
|
|
168
251
|
|
|
169
252
|
if not options.zone:
|
|
170
|
-
raise RuntimeError(
|
|
171
|
-
|
|
253
|
+
raise RuntimeError(
|
|
254
|
+
f"Please provide a value for --zone or set a default in the "
|
|
255
|
+
f"TOIL_{options.provisioner.upper()}_ZONE environment variable."
|
|
256
|
+
)
|
|
172
257
|
|
|
173
258
|
if options.clusterType == "mesos":
|
|
174
|
-
logger.warning(
|
|
175
|
-
|
|
176
|
-
|
|
259
|
+
logger.warning(
|
|
260
|
+
"You are using a Mesos cluster, which is no longer recommended as Toil is "
|
|
261
|
+
"transitioning to Kubernetes-based clusters. Consider switching to "
|
|
262
|
+
"--clusterType=kubernetes instead."
|
|
263
|
+
)
|
|
177
264
|
|
|
178
265
|
if options.clusterType is None:
|
|
179
|
-
logger.warning(
|
|
180
|
-
|
|
181
|
-
|
|
266
|
+
logger.warning(
|
|
267
|
+
'Argument --clusterType is not set... using "mesos". '
|
|
268
|
+
"In future versions of Toil, the default cluster scheduler will be "
|
|
269
|
+
'set to "kubernetes" if the cluster type is not specified.'
|
|
270
|
+
)
|
|
182
271
|
options.clusterType = "mesos"
|
|
183
272
|
|
|
184
|
-
logger.info(
|
|
185
|
-
|
|
186
|
-
cluster = cluster_factory(
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
273
|
+
logger.info("Creating cluster %s...", options.clusterName)
|
|
274
|
+
|
|
275
|
+
cluster = cluster_factory(
|
|
276
|
+
provisioner=options.provisioner,
|
|
277
|
+
clusterName=options.clusterName,
|
|
278
|
+
clusterType=options.clusterType,
|
|
279
|
+
zone=options.zone,
|
|
280
|
+
nodeStorage=options.nodeStorage,
|
|
281
|
+
enable_fuse=options.allowFuse,
|
|
282
|
+
)
|
|
283
|
+
|
|
284
|
+
cluster.launchCluster(
|
|
285
|
+
leaderNodeType=options.leaderNodeType,
|
|
286
|
+
leaderStorage=options.leaderStorage,
|
|
287
|
+
owner=owner,
|
|
288
|
+
keyName=options.keyPairName,
|
|
289
|
+
botoPath=options.botoPath,
|
|
290
|
+
userTags=tags,
|
|
291
|
+
network=options.network,
|
|
292
|
+
vpcSubnet=options.vpcSubnet,
|
|
293
|
+
awsEc2ProfileArn=options.awsEc2ProfileArn,
|
|
294
|
+
awsEc2ExtraSecurityGroupIds=options.awsEc2ExtraSecurityGroupIds,
|
|
295
|
+
)
|
|
203
296
|
|
|
204
297
|
for typeNum, spec in enumerate(nodeCounts):
|
|
205
298
|
# For each batch of workers to make
|
|
@@ -217,8 +310,12 @@ def main() -> None:
|
|
|
217
310
|
cluster.addNodes(nodeTypes=wanted[0], numNodes=spec, preemptible=False)
|
|
218
311
|
else:
|
|
219
312
|
# We have a spot bid
|
|
220
|
-
cluster.addNodes(
|
|
221
|
-
|
|
313
|
+
cluster.addNodes(
|
|
314
|
+
nodeTypes=wanted[0],
|
|
315
|
+
numNodes=spec,
|
|
316
|
+
preemptible=True,
|
|
317
|
+
spotBid=wanted[1],
|
|
318
|
+
)
|
|
222
319
|
|
|
223
320
|
elif isinstance(spec, tuple):
|
|
224
321
|
# Make a range of auto-scaling nodes
|
|
@@ -235,11 +332,20 @@ def main() -> None:
|
|
|
235
332
|
|
|
236
333
|
if wanted[1] is None:
|
|
237
334
|
# Make non-spot instances
|
|
238
|
-
cluster.addManagedNodes(
|
|
239
|
-
|
|
335
|
+
cluster.addManagedNodes(
|
|
336
|
+
nodeTypes=wanted[0],
|
|
337
|
+
minNodes=min_count,
|
|
338
|
+
maxNodes=max_count,
|
|
339
|
+
preemptible=False,
|
|
340
|
+
)
|
|
240
341
|
else:
|
|
241
342
|
# Bid at the given price.
|
|
242
|
-
cluster.addManagedNodes(
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
343
|
+
cluster.addManagedNodes(
|
|
344
|
+
nodeTypes=wanted[0],
|
|
345
|
+
minNodes=min_count,
|
|
346
|
+
maxNodes=max_count,
|
|
347
|
+
preemptible=True,
|
|
348
|
+
spotBid=wanted[1],
|
|
349
|
+
)
|
|
350
|
+
|
|
351
|
+
logger.info("Cluster created successfully.")
|
toil/utils/toilMain.py
CHANGED
|
@@ -3,9 +3,8 @@ import re
|
|
|
3
3
|
import sys
|
|
4
4
|
import textwrap
|
|
5
5
|
import types
|
|
6
|
-
from typing import Any, Dict
|
|
7
|
-
|
|
8
6
|
from importlib.metadata import version as metadata_version
|
|
7
|
+
from typing import Any
|
|
9
8
|
|
|
10
9
|
from toil.version import version
|
|
11
10
|
|
|
@@ -13,23 +12,25 @@ from toil.version import version
|
|
|
13
12
|
def main() -> None:
|
|
14
13
|
modules = loadModules()
|
|
15
14
|
|
|
16
|
-
if len(sys.argv) < 2 or sys.argv[1] ==
|
|
15
|
+
if len(sys.argv) < 2 or sys.argv[1] == "--help":
|
|
17
16
|
printHelp(modules)
|
|
18
17
|
sys.exit(0)
|
|
19
18
|
|
|
20
19
|
cmd = sys.argv[1]
|
|
21
|
-
if cmd ==
|
|
20
|
+
if cmd == "--version":
|
|
22
21
|
printVersion()
|
|
23
22
|
sys.exit(0)
|
|
24
23
|
|
|
25
24
|
try:
|
|
26
25
|
module = modules[cmd]
|
|
27
26
|
except KeyError:
|
|
28
|
-
sys.stderr.write(
|
|
27
|
+
sys.stderr.write(
|
|
28
|
+
f'Unknown option "{cmd}". Pass --help to display usage information.\n'
|
|
29
|
+
)
|
|
29
30
|
sys.exit(1)
|
|
30
31
|
|
|
31
32
|
del sys.argv[1]
|
|
32
|
-
get_or_die(module,
|
|
33
|
+
get_or_die(module, "main")()
|
|
33
34
|
|
|
34
35
|
|
|
35
36
|
def get_or_die(module: types.ModuleType, name: str) -> Any:
|
|
@@ -39,12 +40,14 @@ def get_or_die(module: types.ModuleType, name: str) -> Any:
|
|
|
39
40
|
if hasattr(module, name):
|
|
40
41
|
return getattr(module, name)
|
|
41
42
|
else:
|
|
42
|
-
sys.stderr.write(
|
|
43
|
-
|
|
43
|
+
sys.stderr.write(
|
|
44
|
+
f"Internal Toil error!\nToil utility module "
|
|
45
|
+
f"{module.__name__} is missing required attribute {name}\n"
|
|
46
|
+
)
|
|
44
47
|
sys.exit(1)
|
|
45
48
|
|
|
46
49
|
|
|
47
|
-
def loadModules() ->
|
|
50
|
+
def loadModules() -> dict[str, types.ModuleType]:
|
|
48
51
|
# noinspection PyUnresolvedReferences
|
|
49
52
|
from toil.utils import toilClean # noqa
|
|
50
53
|
from toil.utils import toilConfig # noqa
|
|
@@ -59,13 +62,22 @@ def loadModules() -> Dict[str, types.ModuleType]:
|
|
|
59
62
|
from toil.utils import toilStats # noqa
|
|
60
63
|
from toil.utils import toilStatus # noqa
|
|
61
64
|
|
|
62
|
-
return {
|
|
65
|
+
return {
|
|
66
|
+
"-".join([i.lower() for i in re.findall("[A-Z][^A-Z]*", name)]): module
|
|
67
|
+
for name, module in locals().items()
|
|
68
|
+
}
|
|
63
69
|
|
|
64
70
|
|
|
65
|
-
def printHelp(modules:
|
|
71
|
+
def printHelp(modules: dict[str, types.ModuleType]) -> None:
|
|
66
72
|
name = os.path.basename(sys.argv[0])
|
|
67
|
-
descriptions =
|
|
68
|
-
|
|
73
|
+
descriptions = "\n ".join(
|
|
74
|
+
f'{cmd} - {get_or_die(mod, "__doc__").strip()}'
|
|
75
|
+
for cmd, mod in modules.items()
|
|
76
|
+
if mod
|
|
77
|
+
)
|
|
78
|
+
print(
|
|
79
|
+
textwrap.dedent(
|
|
80
|
+
f"""
|
|
69
81
|
Usage: {name} COMMAND ...
|
|
70
82
|
{name} --help
|
|
71
83
|
{name} COMMAND --help
|
|
@@ -73,11 +85,20 @@ def printHelp(modules: Dict[str, types.ModuleType]) -> None:
|
|
|
73
85
|
Where COMMAND is one of the following:
|
|
74
86
|
|
|
75
87
|
{descriptions}
|
|
76
|
-
"""[
|
|
88
|
+
"""[
|
|
89
|
+
1:
|
|
90
|
+
]
|
|
91
|
+
)
|
|
92
|
+
)
|
|
77
93
|
|
|
78
94
|
|
|
79
95
|
def printVersion() -> None:
|
|
80
96
|
try:
|
|
81
|
-
|
|
97
|
+
detected_version = metadata_version("toil")
|
|
98
|
+
if "a" in detected_version:
|
|
99
|
+
# This probably means Toil is installed as development
|
|
100
|
+
print(version)
|
|
101
|
+
else:
|
|
102
|
+
print(detected_version)
|
|
82
103
|
except:
|
|
83
|
-
print(f
|
|
104
|
+
print(f"Version gathered from toil.version: {version}")
|
toil/utils/toilRsyncCluster.py
CHANGED
|
@@ -17,29 +17,42 @@ import logging
|
|
|
17
17
|
import sys
|
|
18
18
|
|
|
19
19
|
from toil.common import parser_with_common_options
|
|
20
|
-
from toil.provisioners import
|
|
20
|
+
from toil.provisioners import NoSuchClusterException, cluster_factory
|
|
21
21
|
from toil.statsAndLogging import set_logging_from_options
|
|
22
22
|
|
|
23
23
|
logger = logging.getLogger(__name__)
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
def main() -> None:
|
|
27
|
-
parser = parser_with_common_options(
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
parser.add_argument(
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
27
|
+
parser = parser_with_common_options(
|
|
28
|
+
provisioner_options=True, jobstore_option=False, prog="toil rsync-cluster"
|
|
29
|
+
)
|
|
30
|
+
parser.add_argument(
|
|
31
|
+
"--insecure",
|
|
32
|
+
dest="insecure",
|
|
33
|
+
action="store_true",
|
|
34
|
+
required=False,
|
|
35
|
+
help="Temporarily disable strict host key checking.",
|
|
36
|
+
)
|
|
37
|
+
parser.add_argument(
|
|
38
|
+
"args",
|
|
39
|
+
nargs=argparse.REMAINDER,
|
|
40
|
+
help="Arguments to pass to"
|
|
41
|
+
"`rsync`. Takes any arguments that rsync accepts. Specify the"
|
|
42
|
+
" remote with a colon. For example, to upload `example.py`,"
|
|
43
|
+
" specify `toil rsync-cluster -p aws test-cluster example.py :`."
|
|
44
|
+
"\nOr, to download a file from the remote:, `toil rsync-cluster"
|
|
45
|
+
" -p aws test-cluster :example.py .`",
|
|
46
|
+
)
|
|
36
47
|
options = parser.parse_args()
|
|
37
48
|
set_logging_from_options(options)
|
|
38
|
-
cluster = cluster_factory(
|
|
39
|
-
|
|
40
|
-
|
|
49
|
+
cluster = cluster_factory(
|
|
50
|
+
provisioner=options.provisioner,
|
|
51
|
+
clusterName=options.clusterName,
|
|
52
|
+
zone=options.zone,
|
|
53
|
+
)
|
|
41
54
|
try:
|
|
42
55
|
cluster.getLeader().coreRsync(args=options.args, strict=not options.insecure)
|
|
43
56
|
except NoSuchClusterException as e:
|
|
44
57
|
logger.error(e)
|
|
45
|
-
sys.exit(1)
|
|
58
|
+
sys.exit(1)
|