toil 9.0.0__py3-none-any.whl → 9.1.1__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/batchSystems/abstractBatchSystem.py +13 -5
- toil/batchSystems/abstractGridEngineBatchSystem.py +17 -5
- toil/batchSystems/kubernetes.py +13 -2
- toil/batchSystems/mesos/batchSystem.py +33 -2
- toil/batchSystems/slurm.py +191 -16
- toil/cwl/cwltoil.py +17 -82
- toil/fileStores/__init__.py +1 -1
- toil/fileStores/abstractFileStore.py +5 -2
- toil/fileStores/cachingFileStore.py +1 -1
- toil/job.py +30 -14
- toil/jobStores/abstractJobStore.py +24 -19
- toil/jobStores/aws/jobStore.py +862 -1963
- toil/jobStores/aws/utils.py +24 -270
- toil/jobStores/googleJobStore.py +25 -9
- toil/jobStores/utils.py +0 -327
- toil/leader.py +27 -22
- toil/lib/aws/config.py +22 -0
- toil/lib/aws/s3.py +477 -9
- toil/lib/aws/utils.py +22 -33
- toil/lib/checksum.py +88 -0
- toil/lib/conversions.py +33 -31
- toil/lib/directory.py +217 -0
- toil/lib/ec2.py +97 -29
- toil/lib/exceptions.py +2 -1
- toil/lib/expando.py +2 -2
- toil/lib/generatedEC2Lists.py +73 -16
- toil/lib/io.py +33 -2
- toil/lib/memoize.py +21 -7
- toil/lib/pipes.py +385 -0
- toil/lib/retry.py +1 -1
- toil/lib/threading.py +1 -1
- toil/lib/web.py +4 -5
- toil/provisioners/__init__.py +5 -2
- toil/provisioners/aws/__init__.py +43 -36
- toil/provisioners/aws/awsProvisioner.py +22 -13
- toil/provisioners/node.py +60 -12
- toil/resource.py +3 -13
- toil/test/__init__.py +14 -16
- toil/test/batchSystems/test_slurm.py +103 -14
- toil/test/cwl/staging_cat.cwl +27 -0
- toil/test/cwl/staging_make_file.cwl +25 -0
- toil/test/cwl/staging_workflow.cwl +43 -0
- toil/test/cwl/zero_default.cwl +61 -0
- toil/test/docs/scripts/tutorial_staging.py +17 -8
- toil/test/jobStores/jobStoreTest.py +23 -133
- toil/test/lib/aws/test_iam.py +7 -7
- toil/test/lib/aws/test_s3.py +30 -33
- toil/test/lib/aws/test_utils.py +9 -9
- toil/test/provisioners/aws/awsProvisionerTest.py +59 -6
- toil/test/src/autoDeploymentTest.py +2 -3
- toil/test/src/fileStoreTest.py +89 -87
- toil/test/utils/ABCWorkflowDebug/ABC.txt +1 -0
- toil/test/utils/ABCWorkflowDebug/debugWorkflow.py +4 -4
- toil/test/utils/toilKillTest.py +35 -28
- toil/test/wdl/md5sum/md5sum.json +1 -1
- toil/test/wdl/testfiles/gather.wdl +52 -0
- toil/test/wdl/wdltoil_test.py +120 -38
- toil/test/wdl/wdltoil_test_kubernetes.py +9 -0
- toil/utils/toilDebugFile.py +6 -3
- toil/utils/toilStats.py +17 -2
- toil/version.py +6 -6
- toil/wdl/wdltoil.py +1038 -549
- toil/worker.py +5 -2
- {toil-9.0.0.dist-info → toil-9.1.1.dist-info}/METADATA +12 -12
- {toil-9.0.0.dist-info → toil-9.1.1.dist-info}/RECORD +69 -61
- toil/lib/iterables.py +0 -112
- toil/test/docs/scripts/stagingExampleFiles/in.txt +0 -1
- {toil-9.0.0.dist-info → toil-9.1.1.dist-info}/WHEEL +0 -0
- {toil-9.0.0.dist-info → toil-9.1.1.dist-info}/entry_points.txt +0 -0
- {toil-9.0.0.dist-info → toil-9.1.1.dist-info}/licenses/LICENSE +0 -0
- {toil-9.0.0.dist-info → toil-9.1.1.dist-info}/top_level.txt +0 -0
toil/test/lib/aws/test_iam.py
CHANGED
|
@@ -28,9 +28,9 @@ logging.basicConfig(level=logging.DEBUG)
|
|
|
28
28
|
class IAMTest(ToilTest):
|
|
29
29
|
"""Check that given permissions and associated functions perform correctly"""
|
|
30
30
|
|
|
31
|
-
def test_permissions_iam(self):
|
|
31
|
+
def test_permissions_iam(self) -> None:
|
|
32
32
|
granted_perms = {
|
|
33
|
-
"*": {"Action": ["ec2:*", "iam:*", "s3:*"
|
|
33
|
+
"*": {"Action": ["ec2:*", "iam:*", "s3:*"], "NotAction": []}
|
|
34
34
|
}
|
|
35
35
|
assert (
|
|
36
36
|
iam.policy_permissions_allow(
|
|
@@ -46,8 +46,8 @@ class IAMTest(ToilTest):
|
|
|
46
46
|
is True
|
|
47
47
|
)
|
|
48
48
|
|
|
49
|
-
def test_negative_permissions_iam(self):
|
|
50
|
-
granted_perms = {"*": {"Action": ["ec2:*", "s3:*"
|
|
49
|
+
def test_negative_permissions_iam(self) -> None:
|
|
50
|
+
granted_perms = {"*": {"Action": ["ec2:*", "s3:*"], "NotAction": []}}
|
|
51
51
|
assert (
|
|
52
52
|
iam.policy_permissions_allow(
|
|
53
53
|
granted_perms, iam.CLUSTER_LAUNCHING_PERMISSIONS
|
|
@@ -62,7 +62,7 @@ class IAMTest(ToilTest):
|
|
|
62
62
|
is False
|
|
63
63
|
)
|
|
64
64
|
|
|
65
|
-
def test_wildcard_handling(self):
|
|
65
|
+
def test_wildcard_handling(self) -> None:
|
|
66
66
|
assert iam.permission_matches_any("iam:CreateRole", ["iam:Create**"]) is True
|
|
67
67
|
assert iam.permission_matches_any("iam:GetUser", ["iam:???????"]) is True
|
|
68
68
|
assert iam.permission_matches_any("iam:ListRoleTags", ["iam:*?*Tags"]) is True
|
|
@@ -71,7 +71,7 @@ class IAMTest(ToilTest):
|
|
|
71
71
|
|
|
72
72
|
@mock_aws
|
|
73
73
|
@needs_aws_s3 # mock is incomplete, this avoid 'botocore.exceptions.NoCredentialsError: Unable to locate credentials'
|
|
74
|
-
def test_get_policy_permissions(self):
|
|
74
|
+
def test_get_policy_permissions(self) -> None:
|
|
75
75
|
mock_iam = boto3.client("iam")
|
|
76
76
|
|
|
77
77
|
# username that moto pretends we have from client.get_user()
|
|
@@ -167,7 +167,7 @@ class IAMTest(ToilTest):
|
|
|
167
167
|
assert notactions_set == set()
|
|
168
168
|
|
|
169
169
|
@needs_aws_s3
|
|
170
|
-
def test_create_delete_iam_role(self):
|
|
170
|
+
def test_create_delete_iam_role(self) -> None:
|
|
171
171
|
region = "us-west-2"
|
|
172
172
|
role_name = f'test{str(uuid4()).replace("-", "")}'
|
|
173
173
|
with self.subTest("Create role w/policies."):
|
toil/test/lib/aws/test_s3.py
CHANGED
|
@@ -18,67 +18,64 @@ from typing import TYPE_CHECKING, Optional
|
|
|
18
18
|
|
|
19
19
|
from toil.jobStores.aws.jobStore import AWSJobStore
|
|
20
20
|
from toil.lib.aws.session import establish_boto3_session
|
|
21
|
-
from toil.lib.aws.utils import create_s3_bucket, get_bucket_region
|
|
21
|
+
from toil.lib.aws.utils import create_s3_bucket, delete_s3_bucket, get_bucket_region
|
|
22
22
|
from toil.test import ToilTest, needs_aws_s3
|
|
23
23
|
|
|
24
24
|
logger = logging.getLogger(__name__)
|
|
25
25
|
logging.basicConfig(level=logging.DEBUG)
|
|
26
26
|
|
|
27
|
+
if TYPE_CHECKING:
|
|
28
|
+
from mypy_boto3_s3 import S3ServiceResource
|
|
29
|
+
from mypy_boto3_s3.service_resource import Bucket
|
|
27
30
|
|
|
28
31
|
@needs_aws_s3
|
|
29
32
|
class S3Test(ToilTest):
|
|
30
33
|
"""Confirm the workarounds for us-east-1."""
|
|
31
34
|
|
|
32
|
-
if TYPE_CHECKING:
|
|
33
|
-
from mypy_boto3_s3 import S3ServiceResource
|
|
34
|
-
from mypy_boto3_s3.service_resource import Bucket
|
|
35
|
-
|
|
36
35
|
s3_resource: Optional["S3ServiceResource"]
|
|
37
|
-
bucket: Optional["Bucket"]
|
|
38
36
|
|
|
39
37
|
@classmethod
|
|
40
38
|
def setUpClass(cls) -> None:
|
|
41
39
|
super().setUpClass()
|
|
42
40
|
session = establish_boto3_session(region_name="us-east-1")
|
|
43
41
|
cls.s3_resource = session.resource("s3", region_name="us-east-1")
|
|
44
|
-
cls.bucket = None
|
|
45
42
|
|
|
46
43
|
def test_create_bucket(self) -> None:
|
|
47
44
|
"""Test bucket creation for us-east-1."""
|
|
48
45
|
bucket_name = f"toil-s3test-{uuid.uuid4()}"
|
|
49
46
|
assert self.s3_resource
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
47
|
+
bucket: Optional["Bucket"] = None
|
|
48
|
+
try:
|
|
49
|
+
bucket = create_s3_bucket(self.s3_resource, bucket_name, "us-east-1")
|
|
50
|
+
bucket.wait_until_exists()
|
|
51
|
+
owner_tag = os.environ.get("TOIL_OWNER_TAG")
|
|
52
|
+
if owner_tag:
|
|
53
|
+
bucket_tagging = self.s3_resource.BucketTagging(bucket_name)
|
|
54
|
+
bucket_tagging.put(
|
|
55
|
+
Tagging={"TagSet": [{"Key": "Owner", "Value": owner_tag}]}
|
|
56
|
+
)
|
|
57
|
+
self.assertEqual(get_bucket_region(bucket_name), "us-east-1")
|
|
59
58
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
59
|
+
# Make sure all the bucket location getting strategies work on a bucket we created
|
|
60
|
+
self.assertEqual(
|
|
61
|
+
get_bucket_region(bucket_name, only_strategies={1}), "us-east-1"
|
|
62
|
+
)
|
|
63
|
+
self.assertEqual(
|
|
64
|
+
get_bucket_region(bucket_name, only_strategies={2}), "us-east-1"
|
|
65
|
+
)
|
|
66
|
+
self.assertEqual(
|
|
67
|
+
get_bucket_region(bucket_name, only_strategies={3}), "us-east-1"
|
|
68
|
+
)
|
|
69
|
+
finally:
|
|
70
|
+
# Clean up the bucket if we managed to make it
|
|
71
|
+
if bucket is not None:
|
|
72
|
+
delete_s3_bucket(self.s3_resource, bucket_name)
|
|
70
73
|
|
|
71
74
|
def test_get_bucket_location_public_bucket(self) -> None:
|
|
72
75
|
"""
|
|
73
|
-
Test getting
|
|
76
|
+
Test getting bucket location for a bucket we don't own.
|
|
74
77
|
"""
|
|
75
78
|
|
|
76
79
|
bucket_name = "spacenet-dataset"
|
|
77
80
|
# This bucket happens to live in us-east-1
|
|
78
81
|
self.assertEqual(get_bucket_region(bucket_name), "us-east-1")
|
|
79
|
-
|
|
80
|
-
@classmethod
|
|
81
|
-
def tearDownClass(cls) -> None:
|
|
82
|
-
if cls.bucket:
|
|
83
|
-
AWSJobStore._delete_bucket(cls.bucket)
|
|
84
|
-
super().tearDownClass()
|
toil/test/lib/aws/test_utils.py
CHANGED
|
@@ -27,35 +27,35 @@ class TagGenerationTest(ToilTest):
|
|
|
27
27
|
Test for tag generation from environment variables
|
|
28
28
|
"""
|
|
29
29
|
|
|
30
|
-
def test_build_tag(self):
|
|
30
|
+
def test_build_tag(self) -> None:
|
|
31
31
|
environment = dict()
|
|
32
32
|
environment["TOIL_OWNER_TAG"] = "😀"
|
|
33
|
-
environment["TOIL_AWS_TAGS"] =
|
|
33
|
+
environment["TOIL_AWS_TAGS"] = ""
|
|
34
34
|
tag_dict = build_tag_dict_from_env(environment)
|
|
35
35
|
assert tag_dict == {"Owner": "😀"}
|
|
36
36
|
|
|
37
|
-
def test_empty_aws_tags(self):
|
|
37
|
+
def test_empty_aws_tags(self) -> None:
|
|
38
38
|
environment = dict()
|
|
39
|
-
environment["TOIL_OWNER_TAG"] =
|
|
39
|
+
environment["TOIL_OWNER_TAG"] = ""
|
|
40
40
|
environment["TOIL_AWS_TAGS"] = "{}"
|
|
41
41
|
tag_dict = build_tag_dict_from_env(environment)
|
|
42
42
|
assert tag_dict == dict()
|
|
43
43
|
|
|
44
|
-
def test_incorrect_json_object(self):
|
|
44
|
+
def test_incorrect_json_object(self) -> None:
|
|
45
45
|
with pytest.raises(SystemExit):
|
|
46
46
|
environment = dict()
|
|
47
|
-
environment["TOIL_OWNER_TAG"] =
|
|
47
|
+
environment["TOIL_OWNER_TAG"] = ""
|
|
48
48
|
environment["TOIL_AWS_TAGS"] = "231"
|
|
49
49
|
tag_dict = build_tag_dict_from_env(environment)
|
|
50
50
|
|
|
51
|
-
def test_incorrect_json_emoji(self):
|
|
51
|
+
def test_incorrect_json_emoji(self) -> None:
|
|
52
52
|
with pytest.raises(SystemExit):
|
|
53
53
|
environment = dict()
|
|
54
|
-
environment["TOIL_OWNER_TAG"] =
|
|
54
|
+
environment["TOIL_OWNER_TAG"] = ""
|
|
55
55
|
environment["TOIL_AWS_TAGS"] = "😀"
|
|
56
56
|
tag_dict = build_tag_dict_from_env(environment)
|
|
57
57
|
|
|
58
|
-
def test_build_tag_with_tags(self):
|
|
58
|
+
def test_build_tag_with_tags(self) -> None:
|
|
59
59
|
environment = dict()
|
|
60
60
|
environment["TOIL_OWNER_TAG"] = "😀"
|
|
61
61
|
environment["TOIL_AWS_TAGS"] = '{"1": "2", " ":")"}'
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
|
+
import datetime
|
|
14
15
|
import logging
|
|
15
16
|
import os
|
|
16
17
|
import subprocess
|
|
@@ -24,13 +25,22 @@ from uuid import uuid4
|
|
|
24
25
|
|
|
25
26
|
import pytest
|
|
26
27
|
|
|
28
|
+
import toil.lib.aws.session
|
|
29
|
+
|
|
30
|
+
from toil.lib.aws import zone_to_region
|
|
27
31
|
from toil.provisioners import cluster_factory
|
|
28
32
|
from toil.provisioners.aws.awsProvisioner import AWSProvisioner
|
|
33
|
+
from toil.provisioners.aws import (
|
|
34
|
+
_get_spot_history,
|
|
35
|
+
get_aws_zone_from_spot_market,
|
|
36
|
+
get_best_aws_zone,
|
|
37
|
+
)
|
|
29
38
|
from toil.test import (
|
|
30
39
|
ToilTest,
|
|
31
40
|
get_data,
|
|
32
41
|
integrative,
|
|
33
42
|
needs_aws_ec2,
|
|
43
|
+
needs_aws_s3,
|
|
34
44
|
needs_fetchable_appliance,
|
|
35
45
|
needs_mesos,
|
|
36
46
|
slow,
|
|
@@ -53,10 +63,35 @@ if TYPE_CHECKING:
|
|
|
53
63
|
|
|
54
64
|
log = logging.getLogger(__name__)
|
|
55
65
|
|
|
66
|
+
@pytest.fixture
|
|
67
|
+
def aws_zone():
|
|
68
|
+
"""
|
|
69
|
+
Supply an appropriate AWS zone to work in to tests that need one.
|
|
70
|
+
"""
|
|
71
|
+
zone = get_best_aws_zone()
|
|
72
|
+
assert (
|
|
73
|
+
zone is not None
|
|
74
|
+
), "Could not determine AWS availability zone to test in; is TOIL_AWS_ZONE set?"
|
|
75
|
+
return zone
|
|
76
|
+
|
|
77
|
+
@pytest.fixture
|
|
78
|
+
def aws_region(aws_zone):
|
|
79
|
+
"""
|
|
80
|
+
Supply an appropriate AWS region to work in to tests that need one.
|
|
81
|
+
"""
|
|
82
|
+
return zone_to_region(aws_zone)
|
|
83
|
+
|
|
84
|
+
@pytest.fixture
|
|
85
|
+
def ec2_client(aws_region):
|
|
86
|
+
"""
|
|
87
|
+
Supply an AWS EC2 client tests that need one.
|
|
88
|
+
"""
|
|
89
|
+
return toil.lib.aws.session.client("ec2", aws_region)
|
|
90
|
+
|
|
56
91
|
|
|
57
|
-
class
|
|
92
|
+
class TestAWSProvisionerBenchTest:
|
|
58
93
|
"""
|
|
59
|
-
Tests for the AWS provisioner that don't actually provision
|
|
94
|
+
Tests for the AWS provisioner that don't actually provision instances.
|
|
60
95
|
"""
|
|
61
96
|
|
|
62
97
|
# Needs to talk to EC2 for image discovery
|
|
@@ -71,7 +106,8 @@ class AWSProvisionerBenchTest(ToilTest):
|
|
|
71
106
|
assert ami.startswith("ami-")
|
|
72
107
|
|
|
73
108
|
@needs_aws_ec2
|
|
74
|
-
|
|
109
|
+
@needs_aws_s3
|
|
110
|
+
def test_read_write_global_files(self, aws_zone):
|
|
75
111
|
"""
|
|
76
112
|
Make sure the `_write_file_to_cloud()` and `_read_file_from_cloud()`
|
|
77
113
|
functions of the AWS provisioner work as intended.
|
|
@@ -79,7 +115,7 @@ class AWSProvisionerBenchTest(ToilTest):
|
|
|
79
115
|
provisioner = AWSProvisioner(
|
|
80
116
|
f"aws-provisioner-test-{uuid4()}",
|
|
81
117
|
"mesos",
|
|
82
|
-
|
|
118
|
+
aws_zone,
|
|
83
119
|
50,
|
|
84
120
|
None,
|
|
85
121
|
None,
|
|
@@ -90,13 +126,30 @@ class AWSProvisionerBenchTest(ToilTest):
|
|
|
90
126
|
|
|
91
127
|
try:
|
|
92
128
|
url = provisioner._write_file_to_cloud(key, contents=contents)
|
|
93
|
-
|
|
129
|
+
assert url.startswith("s3://")
|
|
94
130
|
|
|
95
|
-
|
|
131
|
+
assert provisioner._read_file_from_cloud(key) == contents
|
|
96
132
|
finally:
|
|
97
133
|
# the cluster was never launched, but we need to clean up the s3 bucket
|
|
98
134
|
provisioner.destroyCluster()
|
|
99
135
|
|
|
136
|
+
@needs_aws_ec2
|
|
137
|
+
def test_get_spot_history(self, ec2_client) -> None:
|
|
138
|
+
"""
|
|
139
|
+
Make sure that we can download spot price history from AWS.
|
|
140
|
+
"""
|
|
141
|
+
history = _get_spot_history(ec2_client, "t3.large")
|
|
142
|
+
# We should have 7 days of history, newest first.
|
|
143
|
+
|
|
144
|
+
@needs_aws_ec2
|
|
145
|
+
def test_get_aws_zone_from_spot_market(self, ec2_client) -> None:
|
|
146
|
+
"""
|
|
147
|
+
Make sure that we can process spot price history to pick a zone.
|
|
148
|
+
"""
|
|
149
|
+
zone_options = ["us-west-2a", "af-south-1c"]
|
|
150
|
+
zone_choice = get_aws_zone_from_spot_market(0.01, "t3.large", ec2_client, zone_options)
|
|
151
|
+
assert zone_choice in zone_options
|
|
152
|
+
|
|
100
153
|
|
|
101
154
|
@needs_aws_ec2
|
|
102
155
|
@needs_fetchable_appliance
|
|
@@ -4,7 +4,6 @@ import time
|
|
|
4
4
|
from contextlib import contextmanager
|
|
5
5
|
|
|
6
6
|
from toil.exceptions import FailedJobsException
|
|
7
|
-
from toil.lib.iterables import concat
|
|
8
7
|
from toil.test import ApplianceTestSupport, needs_local_appliance, needs_mesos, slow
|
|
9
8
|
from toil.version import exactPython
|
|
10
9
|
|
|
@@ -85,7 +84,7 @@ class AutoDeploymentTest(ApplianceTestSupport):
|
|
|
85
84
|
"--defaultMemory=10M",
|
|
86
85
|
"/data/jobstore",
|
|
87
86
|
]
|
|
88
|
-
command =
|
|
87
|
+
command = pythonArgs + toilArgs
|
|
89
88
|
self.assertRaises(
|
|
90
89
|
subprocess.CalledProcessError, leader.runOnAppliance, *command
|
|
91
90
|
)
|
|
@@ -96,7 +95,7 @@ class AutoDeploymentTest(ApplianceTestSupport):
|
|
|
96
95
|
path=self.sitePackages, packagePath="foo.bar", script=userScript
|
|
97
96
|
)
|
|
98
97
|
# ... and restart Toil.
|
|
99
|
-
command =
|
|
98
|
+
command = pythonArgs + ["--restart"] + toilArgs
|
|
100
99
|
leader.runOnAppliance(*command)
|
|
101
100
|
|
|
102
101
|
def testSplitRootPackages(self):
|