toil 6.1.0a1__py3-none-any.whl → 8.0.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.
- toil/__init__.py +122 -315
- toil/batchSystems/__init__.py +1 -0
- toil/batchSystems/abstractBatchSystem.py +173 -89
- toil/batchSystems/abstractGridEngineBatchSystem.py +272 -148
- toil/batchSystems/awsBatch.py +244 -135
- toil/batchSystems/cleanup_support.py +26 -16
- toil/batchSystems/contained_executor.py +31 -28
- toil/batchSystems/gridengine.py +86 -50
- toil/batchSystems/htcondor.py +166 -89
- toil/batchSystems/kubernetes.py +632 -382
- toil/batchSystems/local_support.py +20 -15
- toil/batchSystems/lsf.py +134 -81
- toil/batchSystems/lsfHelper.py +13 -11
- toil/batchSystems/mesos/__init__.py +41 -29
- toil/batchSystems/mesos/batchSystem.py +290 -151
- toil/batchSystems/mesos/executor.py +79 -50
- toil/batchSystems/mesos/test/__init__.py +31 -23
- toil/batchSystems/options.py +46 -28
- toil/batchSystems/registry.py +53 -19
- toil/batchSystems/singleMachine.py +296 -125
- toil/batchSystems/slurm.py +603 -138
- toil/batchSystems/torque.py +47 -33
- toil/bus.py +186 -76
- toil/common.py +664 -368
- toil/cwl/__init__.py +1 -1
- toil/cwl/cwltoil.py +1136 -483
- toil/cwl/utils.py +17 -22
- toil/deferred.py +63 -42
- toil/exceptions.py +5 -3
- toil/fileStores/__init__.py +5 -5
- toil/fileStores/abstractFileStore.py +140 -60
- toil/fileStores/cachingFileStore.py +717 -269
- toil/fileStores/nonCachingFileStore.py +116 -87
- toil/job.py +1225 -368
- toil/jobStores/abstractJobStore.py +416 -266
- toil/jobStores/aws/jobStore.py +863 -477
- toil/jobStores/aws/utils.py +201 -120
- toil/jobStores/conftest.py +3 -2
- toil/jobStores/fileJobStore.py +292 -154
- toil/jobStores/googleJobStore.py +140 -74
- toil/jobStores/utils.py +36 -15
- toil/leader.py +668 -272
- toil/lib/accelerators.py +115 -18
- toil/lib/aws/__init__.py +74 -31
- 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 +214 -39
- toil/lib/aws/utils.py +287 -231
- toil/lib/bioio.py +13 -5
- toil/lib/compatibility.py +11 -6
- toil/lib/conversions.py +104 -47
- toil/lib/docker.py +131 -103
- toil/lib/ec2.py +361 -199
- toil/lib/ec2nodes.py +174 -106
- 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 +5 -3
- toil/lib/ftp_utils.py +217 -0
- toil/lib/generatedEC2Lists.py +127 -19
- toil/lib/humanize.py +6 -2
- toil/lib/integration.py +341 -0
- toil/lib/io.py +141 -15
- toil/lib/iterables.py +4 -2
- toil/lib/memoize.py +12 -8
- toil/lib/misc.py +66 -21
- toil/lib/objects.py +2 -2
- toil/lib/resources.py +68 -15
- toil/lib/retry.py +126 -81
- toil/lib/threading.py +299 -82
- toil/lib/throttle.py +16 -15
- toil/options/common.py +843 -409
- toil/options/cwl.py +175 -90
- toil/options/runner.py +50 -0
- toil/options/wdl.py +73 -17
- toil/provisioners/__init__.py +117 -46
- toil/provisioners/abstractProvisioner.py +332 -157
- toil/provisioners/aws/__init__.py +70 -33
- toil/provisioners/aws/awsProvisioner.py +1145 -715
- toil/provisioners/clusterScaler.py +541 -279
- toil/provisioners/gceProvisioner.py +282 -179
- toil/provisioners/node.py +155 -79
- toil/realtimeLogger.py +34 -22
- toil/resource.py +137 -75
- toil/server/app.py +128 -62
- toil/server/celery_app.py +3 -1
- toil/server/cli/wes_cwl_runner.py +82 -53
- toil/server/utils.py +54 -28
- 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 +224 -70
- toil/test/__init__.py +282 -183
- toil/test/batchSystems/batchSystemTest.py +460 -210
- toil/test/batchSystems/batch_system_plugin_test.py +90 -0
- toil/test/batchSystems/test_gridengine.py +173 -0
- toil/test/batchSystems/test_lsf_helper.py +67 -58
- toil/test/batchSystems/test_slurm.py +110 -49
- toil/test/cactus/__init__.py +0 -0
- toil/test/cactus/test_cactus_integration.py +56 -0
- toil/test/cwl/cwlTest.py +496 -287
- toil/test/cwl/measure_default_memory.cwl +12 -0
- toil/test/cwl/not_run_required_input.cwl +29 -0
- toil/test/cwl/scatter_duplicate_outputs.cwl +40 -0
- toil/test/cwl/seqtk_seq.cwl +1 -1
- toil/test/docs/scriptsTest.py +69 -46
- toil/test/jobStores/jobStoreTest.py +427 -264
- toil/test/lib/aws/test_iam.py +118 -50
- 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 +58 -50
- toil/test/lib/test_integration.py +104 -0
- toil/test/lib/test_misc.py +12 -5
- toil/test/mesos/MesosDataStructuresTest.py +23 -10
- toil/test/mesos/helloWorld.py +7 -6
- toil/test/mesos/stress.py +25 -20
- toil/test/options/__init__.py +13 -0
- toil/test/options/options.py +42 -0
- toil/test/provisioners/aws/awsProvisionerTest.py +320 -150
- toil/test/provisioners/clusterScalerTest.py +440 -250
- toil/test/provisioners/clusterTest.py +166 -44
- 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 +141 -101
- 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 +32 -24
- toil/test/src/environmentTest.py +135 -0
- toil/test/src/fileStoreTest.py +539 -272
- toil/test/src/helloWorldTest.py +7 -4
- toil/test/src/importExportFileTest.py +61 -31
- toil/test/src/jobDescriptionTest.py +46 -21
- 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 +121 -71
- 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 +10 -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 +73 -23
- toil/test/utils/toilDebugTest.py +103 -33
- toil/test/utils/toilKillTest.py +4 -5
- toil/test/utils/utilsTest.py +245 -106
- toil/test/wdl/wdltoil_test.py +818 -149
- toil/test/wdl/wdltoil_test_kubernetes.py +91 -0
- toil/toilState.py +120 -35
- toil/utils/toilConfig.py +13 -4
- toil/utils/toilDebugFile.py +44 -27
- toil/utils/toilDebugJob.py +214 -27
- toil/utils/toilDestroyCluster.py +11 -6
- toil/utils/toilKill.py +8 -3
- toil/utils/toilLaunchCluster.py +256 -140
- toil/utils/toilMain.py +37 -16
- toil/utils/toilRsyncCluster.py +32 -14
- toil/utils/toilSshCluster.py +49 -22
- toil/utils/toilStats.py +356 -273
- toil/utils/toilStatus.py +292 -139
- toil/utils/toilUpdateEC2Instances.py +3 -1
- toil/version.py +12 -12
- toil/wdl/utils.py +5 -5
- toil/wdl/wdltoil.py +3913 -1033
- toil/worker.py +367 -184
- {toil-6.1.0a1.dist-info → toil-8.0.0.dist-info}/LICENSE +25 -0
- toil-8.0.0.dist-info/METADATA +173 -0
- toil-8.0.0.dist-info/RECORD +253 -0
- {toil-6.1.0a1.dist-info → toil-8.0.0.dist-info}/WHEEL +1 -1
- toil-6.1.0a1.dist-info/METADATA +0 -125
- toil-6.1.0a1.dist-info/RECORD +0 -237
- {toil-6.1.0a1.dist-info → toil-8.0.0.dist-info}/entry_points.txt +0 -0
- {toil-6.1.0a1.dist-info → toil-8.0.0.dist-info}/top_level.txt +0 -0
toil/lib/aws/ami.py
CHANGED
|
@@ -1,19 +1,25 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import logging
|
|
3
3
|
import os
|
|
4
|
+
import time
|
|
4
5
|
import urllib.request
|
|
5
|
-
from
|
|
6
|
+
from collections.abc import Iterator
|
|
7
|
+
from typing import Optional, cast
|
|
6
8
|
from urllib.error import HTTPError, URLError
|
|
7
9
|
|
|
8
10
|
from botocore.client import BaseClient
|
|
9
|
-
from botocore.exceptions import ClientError
|
|
11
|
+
from botocore.exceptions import ClientError, EndpointConnectionError
|
|
10
12
|
|
|
11
13
|
from toil.lib.retry import retry
|
|
12
14
|
|
|
13
15
|
logger = logging.getLogger(__name__)
|
|
14
16
|
|
|
17
|
+
class ReleaseFeedUnavailableError(RuntimeError):
|
|
18
|
+
"""Raised when a Flatcar releases can't be located."""
|
|
19
|
+
pass
|
|
15
20
|
|
|
16
|
-
|
|
21
|
+
@retry(errors=[ReleaseFeedUnavailableError])
|
|
22
|
+
def get_flatcar_ami(ec2_client: BaseClient, architecture: str = "amd64") -> str:
|
|
17
23
|
"""
|
|
18
24
|
Retrieve the flatcar AMI image to use as the base for all Toil autoscaling instances.
|
|
19
25
|
|
|
@@ -24,124 +30,139 @@ def get_flatcar_ami(ec2_client: BaseClient, architecture: str = 'amd64') -> str:
|
|
|
24
30
|
2. Official AMI from stable.release.flatcar-linux.net
|
|
25
31
|
3. Search the AWS Marketplace
|
|
26
32
|
|
|
27
|
-
|
|
33
|
+
:raises ReleaseFeedUnavailableError: if all of these sources fail.
|
|
28
34
|
|
|
29
35
|
:param ec2_client: Boto3 EC2 Client
|
|
30
36
|
:param architecture: The architecture type for the new AWS machine. Can be either amd64 or arm64
|
|
31
37
|
"""
|
|
32
|
-
|
|
33
38
|
# Take a user override
|
|
34
|
-
ami = os.environ.get(
|
|
35
|
-
try_number = 0
|
|
36
|
-
if not ami:
|
|
37
|
-
logger.debug('No AMI found in TOIL_AWS_AMI; checking stable Flatcar release feed')
|
|
38
|
-
ami = feed_flatcar_ami_release(ec2_client=ec2_client, architecture=architecture, source='stable')
|
|
39
|
+
ami = os.environ.get("TOIL_AWS_AMI")
|
|
39
40
|
if not ami:
|
|
40
|
-
logger.
|
|
41
|
-
|
|
41
|
+
logger.debug(
|
|
42
|
+
"No AMI found in TOIL_AWS_AMI; checking stable Flatcar release feed"
|
|
43
|
+
)
|
|
44
|
+
ami = feed_flatcar_ami_release(
|
|
45
|
+
ec2_client=ec2_client, architecture=architecture, source="stable"
|
|
46
|
+
)
|
|
42
47
|
if not ami:
|
|
43
|
-
logger.
|
|
44
|
-
|
|
48
|
+
logger.warning(
|
|
49
|
+
"No available AMI found in Flatcar release feed; checking marketplace"
|
|
50
|
+
)
|
|
51
|
+
ami = aws_marketplace_flatcar_ami_search(
|
|
52
|
+
ec2_client=ec2_client, architecture=architecture
|
|
53
|
+
)
|
|
45
54
|
if not ami:
|
|
46
|
-
logger.debug(
|
|
47
|
-
|
|
55
|
+
logger.debug(
|
|
56
|
+
"No AMI found in Toil project feed; checking beta Flatcar release feed"
|
|
57
|
+
)
|
|
58
|
+
ami = feed_flatcar_ami_release(
|
|
59
|
+
ec2_client=ec2_client, architecture=architecture, source="beta"
|
|
60
|
+
)
|
|
48
61
|
if not ami:
|
|
49
|
-
logger.debug(
|
|
50
|
-
|
|
62
|
+
logger.debug(
|
|
63
|
+
"No AMI found in beta Flatcar release feed; checking archived Flatcar release feed"
|
|
64
|
+
)
|
|
65
|
+
ami = feed_flatcar_ami_release(
|
|
66
|
+
ec2_client=ec2_client, architecture=architecture, source="archive"
|
|
67
|
+
)
|
|
51
68
|
if not ami:
|
|
52
|
-
logger.critical(
|
|
53
|
-
raise
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
69
|
+
logger.critical("No available Flatcar AMI in any source!")
|
|
70
|
+
raise ReleaseFeedUnavailableError(
|
|
71
|
+
f"Unable to fetch the latest flatcar image. Upload "
|
|
72
|
+
f"https://stable.release.flatcar-linux.net/{architecture}-usr/current/flatcar_production_ami_image.bin.bz2 "
|
|
73
|
+
f"to AWS as am AMI and set TOIL_AWS_AMI in the environment to its AMI ID."
|
|
74
|
+
)
|
|
75
|
+
logger.info("Selected Flatcar AMI: %s", ami)
|
|
57
76
|
return ami
|
|
58
77
|
|
|
59
|
-
|
|
60
|
-
def _fetch_flatcar_feed(architecture: str =
|
|
78
|
+
|
|
79
|
+
def _fetch_flatcar_feed(architecture: str = "amd64", source: str = "stable") -> bytes:
|
|
61
80
|
"""
|
|
62
81
|
Get the binary data of the Flatcar release feed for the given architecture.
|
|
63
|
-
|
|
82
|
+
|
|
64
83
|
:param source: can be set to a Flatcar release channel ('stable', 'beta',
|
|
65
84
|
or 'alpha'), 'archive' to check the Internet Archive for a feed,
|
|
66
85
|
and 'toil' to check if the Toil project has put up a feed.
|
|
67
|
-
|
|
86
|
+
|
|
68
87
|
:raises HTTPError: if the feed cannot be fetched.
|
|
69
88
|
"""
|
|
70
|
-
|
|
89
|
+
|
|
71
90
|
# We have a few places we know to get the feed from.
|
|
72
91
|
JSON_FEED_URL = {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
'toil': f'https://raw.githubusercontent.com/DataBiosphere/toil/master/contrib/flatcar/{architecture}-usr/current/flatcar_production_ami_all.json'
|
|
92
|
+
"stable": f"https://stable.release.flatcar-linux.net/{architecture}-usr/current/flatcar_production_ami_all.json",
|
|
93
|
+
"beta": f"https://beta.release.flatcar-linux.net/{architecture}-usr/current/flatcar_production_ami_all.json",
|
|
94
|
+
# "alpha": f"https://alpha.release.flatcar-linux.net/{architecture}-usr/current/flatcar_production_ami_all.json",
|
|
95
|
+
"archive": f"https://web.archive.org/web/20220625112618if_/https://stable.release.flatcar-linux.net/{architecture}-usr/current/flatcar_production_ami_all.json"
|
|
78
96
|
}[source]
|
|
79
97
|
return cast(bytes, urllib.request.urlopen(JSON_FEED_URL).read())
|
|
80
98
|
|
|
81
|
-
|
|
99
|
+
|
|
100
|
+
def flatcar_release_feed_ami(
|
|
101
|
+
region: str, architecture: str = "amd64", source: str = "stable"
|
|
102
|
+
) -> Optional[str]:
|
|
82
103
|
"""
|
|
83
104
|
Yield AMI IDs for the given architecture from the Flatcar release feed.
|
|
84
|
-
|
|
105
|
+
|
|
85
106
|
:param source: can be set to a Flatcar release channel ('stable', 'beta',
|
|
86
107
|
or 'alpha'), 'archive' to check the Internet Archive for a feed,
|
|
87
108
|
and 'toil' to check if the Toil project has put up a feed.
|
|
88
|
-
|
|
109
|
+
|
|
89
110
|
Retries if the release feed cannot be fetched. If the release feed has a
|
|
90
111
|
permanent error, yields nothing. If some entries in the release feed are
|
|
91
112
|
unparseable, yields the others.
|
|
92
113
|
"""
|
|
93
|
-
|
|
114
|
+
|
|
94
115
|
# If we get non-JSON content we want to retry.
|
|
95
116
|
MAX_TRIES = 3
|
|
96
|
-
|
|
117
|
+
|
|
97
118
|
try_number = 0
|
|
98
119
|
while try_number < MAX_TRIES:
|
|
120
|
+
if try_number != 0:
|
|
121
|
+
time.sleep(1)
|
|
99
122
|
try:
|
|
100
123
|
feed = json.loads(_fetch_flatcar_feed(architecture, source))
|
|
101
124
|
break
|
|
102
125
|
except HTTPError:
|
|
103
126
|
# Flatcar servers did not return the feed
|
|
104
|
-
logger.exception(f
|
|
105
|
-
#
|
|
106
|
-
return
|
|
127
|
+
logger.exception(f"Could not retrieve {source} Flatcar release feed JSON")
|
|
128
|
+
# This is probably a permanent error, or at least unlikely to go away immediately.
|
|
129
|
+
return None
|
|
107
130
|
except json.JSONDecodeError:
|
|
108
131
|
# Feed is not JSON
|
|
109
|
-
logger.exception(f
|
|
132
|
+
logger.exception(f"Could not decode {source} Flatcar release feed JSON")
|
|
110
133
|
# Try again
|
|
111
134
|
try_number += 1
|
|
112
135
|
continue
|
|
113
136
|
except URLError:
|
|
114
137
|
# Could be a connection timeout
|
|
115
|
-
logger.exception(f
|
|
138
|
+
logger.exception(f"Failed to retrieve {source} Flatcar release feed JSON")
|
|
116
139
|
# Try again
|
|
117
140
|
try_number += 1
|
|
118
141
|
continue
|
|
119
142
|
if try_number == MAX_TRIES:
|
|
120
143
|
# We could not get the JSON
|
|
121
|
-
logger.error(f
|
|
144
|
+
logger.error(f"Could not get a readable {source} Flatcar release feed JSON")
|
|
122
145
|
# Bail on this method
|
|
123
|
-
return
|
|
146
|
+
return None
|
|
124
147
|
|
|
125
|
-
for ami_record in feed.get(
|
|
148
|
+
for ami_record in feed.get("amis", []):
|
|
126
149
|
# Scan the list of regions
|
|
127
|
-
if ami_record.get(
|
|
128
|
-
|
|
129
|
-
if 'hvm' in ami_record:
|
|
130
|
-
yield ami_record['hvm']
|
|
131
|
-
# And stop, there should be one per region.
|
|
132
|
-
return
|
|
150
|
+
if ami_record.get("name") == region:
|
|
151
|
+
return str(ami_record.get("hvm")) if ami_record.get("hvm") else None
|
|
133
152
|
# We didn't find our region
|
|
134
|
-
logger.warning(f
|
|
135
|
-
|
|
136
|
-
|
|
153
|
+
logger.warning(f"Flatcar {source} release feed does not have an image for region {region}")
|
|
154
|
+
|
|
137
155
|
|
|
138
|
-
|
|
139
|
-
|
|
156
|
+
def feed_flatcar_ami_release(
|
|
157
|
+
ec2_client: BaseClient, architecture: str = "amd64", source: str = "stable"
|
|
158
|
+
) -> Optional[str]:
|
|
140
159
|
"""
|
|
141
160
|
Check a Flatcar release feed for the latest flatcar AMI.
|
|
142
|
-
|
|
161
|
+
|
|
143
162
|
Verify it's on AWS.
|
|
144
163
|
|
|
164
|
+
Does not raise exceptions.
|
|
165
|
+
|
|
145
166
|
:param ec2_client: Boto3 EC2 Client
|
|
146
167
|
:param architecture: The architecture type for the new AWS machine. Can be either amd64 or arm64
|
|
147
168
|
:param source: can be set to a Flatcar release channel ('stable', 'beta',
|
|
@@ -152,40 +173,54 @@ def feed_flatcar_ami_release(ec2_client: BaseClient, architecture: str = 'amd64'
|
|
|
152
173
|
# Rather than hardcode a list of AMIs by region that will die, we use
|
|
153
174
|
# their JSON feed of the current ones.
|
|
154
175
|
|
|
155
|
-
region = ec2_client._client_config.region_name # type: ignore
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
return ami
|
|
163
|
-
else:
|
|
164
|
-
logger.warning(f'Flatcar release feed suggests image {ami} which does not exist on AWS in {region}')
|
|
165
|
-
except ClientError:
|
|
166
|
-
# Sometimes we get back nonsense like:
|
|
167
|
-
# botocore.exceptions.ClientError: An error occurred (AuthFailure) when calling the DescribeImages operation: AWS was not able to validate the provided access credentials
|
|
168
|
-
# Don't hold that against the AMI.
|
|
169
|
-
logger.exception(f'Unable to check if AMI {ami} exists on AWS in {region}; assuming it does')
|
|
176
|
+
region = ec2_client._client_config.region_name # type: ignore
|
|
177
|
+
|
|
178
|
+
ami = flatcar_release_feed_ami(region, architecture, source)
|
|
179
|
+
# verify it exists on AWS
|
|
180
|
+
try:
|
|
181
|
+
response = ec2_client.describe_images(Filters=[{"Name": "image-id", "Values": [ami]}]) # type: ignore
|
|
182
|
+
if (len(response["Images"]) == 1 and response["Images"][0]["State"] == "available"):
|
|
170
183
|
return ami
|
|
184
|
+
else:
|
|
185
|
+
logger.warning(f"Flatcar release feed suggests image {ami} which does not exist on AWS in {region}")
|
|
186
|
+
except (ClientError, EndpointConnectionError):
|
|
187
|
+
# Sometimes we get back nonsense like:
|
|
188
|
+
# botocore.exceptions.ClientError: An error occurred (AuthFailure) when calling the DescribeImages operation: AWS was not able to validate the provided access credentials
|
|
189
|
+
# Don't hold that against the AMI.
|
|
190
|
+
logger.exception(f"Unable to check if AMI {ami} exists on AWS in {region}; assuming it does")
|
|
191
|
+
return ami
|
|
171
192
|
# We didn't find it
|
|
172
|
-
logger.warning(f
|
|
173
|
-
|
|
193
|
+
logger.warning(f"Flatcar release feed does not have an image for region {region} that exists on AWS")
|
|
194
|
+
|
|
174
195
|
|
|
196
|
+
def aws_marketplace_flatcar_ami_search(
|
|
197
|
+
ec2_client: BaseClient, architecture: str = "amd64"
|
|
198
|
+
) -> Optional[str]:
|
|
199
|
+
"""
|
|
200
|
+
Query AWS for all AMI names matching ``Flatcar-stable-*`` and return the most recent one.
|
|
175
201
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
202
|
+
Does not raise exceptions.
|
|
203
|
+
|
|
204
|
+
:returns: An AMI name, or None if no matching AMI was found or we could not talk to AWS.
|
|
205
|
+
"""
|
|
179
206
|
|
|
180
207
|
# https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ec2.html#EC2.Client.describe_images
|
|
181
208
|
# Possible arch choices on AWS: 'i386'|'x86_64'|'arm64'|'x86_64_mac'
|
|
182
|
-
architecture_mapping = {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
209
|
+
architecture_mapping = {"amd64": "x86_64", "arm64": "arm64"}
|
|
210
|
+
try:
|
|
211
|
+
response = ec2_client.describe_images( # type: ignore[attr-defined]
|
|
212
|
+
Owners=["aws-marketplace"],
|
|
213
|
+
Filters=[{"Name": "name", "Values": ["Flatcar-stable-*"]}],
|
|
214
|
+
)
|
|
215
|
+
except (ClientError, EndpointConnectionError):
|
|
216
|
+
logger.exception("Unable to search AWS marketplace")
|
|
217
|
+
return None
|
|
218
|
+
latest: dict[str, str] = {"CreationDate": "0lder than atoms."}
|
|
219
|
+
for image in response["Images"]:
|
|
220
|
+
if (
|
|
221
|
+
image["Architecture"] == architecture_mapping[architecture]
|
|
222
|
+
and image["State"] == "available"
|
|
223
|
+
):
|
|
224
|
+
if image["CreationDate"] > latest["CreationDate"]:
|
|
190
225
|
latest = image
|
|
191
|
-
return latest.get(
|
|
226
|
+
return latest.get("ImageId", None)
|