Skip to content

Commit 9d8a078

Browse files
authored
feat: reveal image not found error (#739)
* feat: reveal image not found error * print ConfigError cause * capitalize the cause sentense
1 parent 0a25c3f commit 9d8a078

File tree

3 files changed

+49
-40
lines changed

3 files changed

+49
-40
lines changed

images/utils/launcher/__init__.py

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,15 @@ def start(self):
248248
self.shell.start(f"{self.config.network} > ", self.handle_command)
249249

250250

251+
def print_config_error_cause(e: ConfigError) -> None:
252+
if e.__cause__:
253+
cause = str(e.__cause__)
254+
if cause == "":
255+
print(type(e.__cause__))
256+
else:
257+
print(cause.capitalize())
258+
259+
251260
class Launcher:
252261
def __init__(self):
253262
self.logger = logging.getLogger("launcher.Launcher")
@@ -266,17 +275,17 @@ def launch(self):
266275
print()
267276
except ConfigError as e:
268277
if e.scope == ConfigErrorScope.COMMAND_LINE_ARGS:
269-
print("Failed to parse command-line arguments, exiting.")
270-
print(f"Error details: {e.__cause__}")
278+
print("Failed to parse command-line arguments, exiting.")
279+
print_config_error_cause(e)
271280
elif e.scope == ConfigErrorScope.GENERAL_CONF:
272-
print("Failed to parse config file {}, exiting.".format(e.conf_file))
273-
print(f"Error details: {e.__cause__}")
281+
print("Failed to parse config file {}, exiting.".format(e.conf_file))
282+
print_config_error_cause(e)
274283
elif e.scope == ConfigErrorScope.NETWORK_CONF:
275-
print("Failed to parse config file {}, exiting.".format(e.conf_file))
276-
print(f"Error details: {e.__cause__}")
284+
print("Failed to parse config file {}, exiting.".format(e.conf_file))
285+
print_config_error_cause(e)
277286
except FatalError as e:
278287
if config and config.logfile:
279-
print(f"❌ Error: {e}. For more details, see {config.logfile}")
288+
print("{}. For more details, see {}".format(e, config.logfile))
280289
else:
281290
traceback.print_exc()
282291
except Exception: # exclude system exceptions like SystemExit

images/utils/launcher/node/__init__.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -209,13 +209,13 @@ def down(self):
209209

210210
def _display_container_status_text(self, status):
211211
if status == "missing":
212-
return "missing"
212+
return "create"
213213
elif status == "outdated":
214-
return "outdated"
214+
return "recreate"
215215
elif status == "external_with_container":
216-
return "non-native"
216+
return "remove"
217217
elif status == "disabled_with_container":
218-
return "disabled"
218+
return "remove"
219219

220220
def _readable_details(self, details):
221221
if not details:
@@ -244,8 +244,8 @@ def update(self) -> bool:
244244
outdated = True
245245
image_outdated = True
246246
elif status == "UNAVAILABLE":
247-
all_unavailable_images = [x for x in images if x.status == "UNAVAILABLE"]
248-
raise FatalError("Image(s) not available: %r" % all_unavailable_images)
247+
all_unavailable_images = [x.name for x in images if x.status == "UNAVAILABLE"]
248+
raise FatalError("Image(s) not found: %s" % ", ".join(all_unavailable_images))
249249

250250
# Step 2. check all containers
251251
containers = self.nodes.values()

images/utils/launcher/node/image.py

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -212,27 +212,35 @@ def fetch_cloud_metadata(self):
212212
except:
213213
self.logger.exception("Failed to fetch cloud image metadata")
214214

215-
def fetch_cloud_metadata_wrapper(self):
216-
for i in range(3):
217-
metadata = self.fetch_cloud_metadata()
218-
if metadata:
219-
return metadata
220-
self.logger.exception("Image not found on cloud: %s (retry in 10 seconds)" % self.name)
221-
time.sleep(10)
222-
raise RuntimeError("Failed to fetch cloud image metadata (3 times): %s" % self.name)
223-
224-
def get_status(self):
215+
def get_status(self) -> str:
216+
"""Get image update status
217+
218+
:return: image status
219+
- UP_TO_DATE: The local image is the same as the cloud.
220+
- LOCAL_OUTDATED: The local image hash is different from the cloud.
221+
- LOCAL_NEWER: The local image is created after the cloud.
222+
- LOCAL_MISSING: The cloud image exists but no local image.
223+
- LOCAL_ONLY: The image only exists locally.
224+
- UNAVAILABLE: The image is not found locally or remotely.
225+
"""
225226
if self.node.node_config["use_local_image"]:
226227
self.cloud_metadata = None
227228
return "LOCAL_NEWER"
228229

229-
self.cloud_metadata = self.fetch_cloud_metadata_wrapper()
230230
local = self.local_metadata
231+
232+
self.cloud_metadata = self.fetch_cloud_metadata()
231233
cloud = self.cloud_metadata
232-
assert cloud
234+
235+
if not local and not cloud:
236+
return "UNAVAILABLE"
237+
238+
if local and not cloud:
239+
return "LOCAL_ONLY"
233240

234241
if not local and cloud:
235242
return "LOCAL_MISSING"
243+
236244
if local.digest == cloud.digest:
237245
return "UP_TO_DATE"
238246
else:
@@ -243,13 +251,13 @@ def status_message(self):
243251
if self.status == "UNAVAILABLE":
244252
return "unavailable"
245253
elif self.status == "LOCAL_ONLY":
246-
return "local"
254+
return "using local version"
247255
elif self.status == "LOCAL_MISSING":
248-
return "missing"
256+
return "pull"
249257
elif self.status == "LOCAL_NEWER":
250-
return "newer"
258+
return "using local version"
251259
elif self.status == "LOCAL_OUTDATED":
252-
return "outdated"
260+
return "pull"
253261
elif self.status == "UP_TO_DATE":
254262
return "up-to-date"
255263

@@ -320,24 +328,16 @@ def check_for_updates(self) -> List[Image]:
320328
images = [image for image in images if image.node.mode == "native" and not image.node.disabled]
321329

322330
def print_failed(failed):
323-
for image, error in failed:
324-
error_message = get_useful_error_message(error)
325-
if error_message == "timeout":
326-
raise FatalError("Timeout error: Couldn't connect to Docker to check for updates. Please check your internet connection and https://status.docker.com/.")
327-
print("Failed to check for image updates.")
328-
for image, error in failed:
329-
error_message = get_useful_error_message(error)
330-
print("- {}: {}".format(image.name, error_message))
331+
pass
331332

332333
def try_again():
333-
answer = self.shell.yes_or_no("Try again?")
334-
return answer == "yes"
334+
return False
335335

336336
parallel_execute(images, lambda i: i.check_for_updates(), 30, print_failed, try_again)
337337

338338
return images
339339

340-
def update_images(self):
340+
def update_images(self) -> None:
341341
for image in self.images.values():
342342
status = image.status
343343
pull_image = image.pull_image

0 commit comments

Comments
 (0)