From 33b05ff8315457444acdf4ee2ae56eef6ab5515b Mon Sep 17 00:00:00 2001 From: Tian Xia Date: Thu, 28 Sep 2023 13:22:33 -0700 Subject: [PATCH] [UX] Print useful message when image id not found (#2535) * add aws, gcp * fix * fix * add IBM message * Update sky/clouds/gcp.py Co-authored-by: Zongheng Yang * Update sky/clouds/aws.py Co-authored-by: Zongheng Yang * apply suggestion from code review * add newline * add blank line * add comments for constants --------- Co-authored-by: Zongheng Yang --- sky/clouds/aws.py | 6 ++++-- sky/clouds/gcp.py | 24 +++++++++++++++++++++--- sky/clouds/ibm.py | 12 ++++++++++-- 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/sky/clouds/aws.py b/sky/clouds/aws.py index dbce73f3056..e6721120d83 100644 --- a/sky/clouds/aws.py +++ b/sky/clouds/aws.py @@ -251,8 +251,10 @@ def get_image_size(cls, image_id: str, region: Optional[str]) -> float: return DEFAULT_AMI_GB except aws.botocore_exceptions().ClientError: with ux_utils.print_exception_no_traceback(): - raise ValueError(f'Image {image_id!r} not found in ' - f'AWS region {region}') from None + raise ValueError( + f'Image {image_id!r} not found in AWS region {region}.\n' + f'\nTo find AWS AMI IDs: https://docs.aws.amazon.com/cli/latest/reference/ec2/describe-images.html#examples\n' # pylint: disable=line-too-long + 'Example: ami-0729d913a335efca7') from None return image_size @classmethod diff --git a/sky/clouds/gcp.py b/sky/clouds/gcp.py index 2d539287d25..948dd716297 100644 --- a/sky/clouds/gcp.py +++ b/sky/clouds/gcp.py @@ -11,6 +11,7 @@ from typing import Any, Dict, Iterator, List, Optional, Set, Tuple import cachetools +import colorama from sky import clouds from sky import exceptions @@ -83,8 +84,22 @@ # TODO(zhwu): Move the default AMI size to the catalog instead. DEFAULT_GCP_IMAGE_GB = 50 +# Firewall rule name for user opened ports. USER_PORTS_FIREWALL_RULE_NAME = 'sky-ports-{}' +# UX message when image not found in GCP. +# pylint: disable=line-too-long +_IMAGE_NOT_FOUND_UX_MESSAGE = ( + 'Image {image_id!r} not found in GCP.\n' + '\nTo find GCP images: https://cloud.google.com/compute/docs/images\n' + f'Format: {colorama.Style.BRIGHT}projects//global/images/{colorama.Style.RESET_ALL}\n' + 'Example: projects/deeplearning-platform-release/global/images/common-cpu-v20230615-debian-11-py310\n' + '\nTo find machine images: https://cloud.google.com/compute/docs/machine-images\n' + f'Format: {colorama.Style.BRIGHT}projects//global/machineImages/{colorama.Style.RESET_ALL}\n' + f'\nYou can query image id using: {colorama.Style.BRIGHT}gcloud compute images list --project --no-standard-images{colorama.Style.RESET_ALL}' + f'\nTo query common AI images: {colorama.Style.BRIGHT}gcloud compute images list --project deeplearning-platform-release | less{colorama.Style.RESET_ALL}' +) + def _run_output(cmd): proc = subprocess.run(cmd, @@ -364,7 +379,9 @@ def _get_image_size(cls, image_id: str) -> float: try: image_attrs = image_id.split('/') if len(image_attrs) == 1: - raise ValueError(f'Image {image_id!r} not found in GCP.') + with ux_utils.print_exception_no_traceback(): + raise ValueError( + _IMAGE_NOT_FOUND_UX_MESSAGE.format(image_id=image_id)) project = image_attrs[1] image_name = image_attrs[-1] # We support both GCP's Machine Images and Custom Images, both @@ -392,8 +409,9 @@ def _get_image_size(cls, image_id: str) -> float: f'{image_id!r}') from None if e.resp.status == 404: with ux_utils.print_exception_no_traceback(): - raise ValueError(f'Image {image_id!r} not found in ' - 'GCP.') from None + raise ValueError( + _IMAGE_NOT_FOUND_UX_MESSAGE.format( + image_id=image_id)) from None raise @classmethod diff --git a/sky/clouds/ibm.py b/sky/clouds/ibm.py index b8f30f666a2..8b3376784e7 100644 --- a/sky/clouds/ibm.py +++ b/sky/clouds/ibm.py @@ -355,8 +355,16 @@ def get_image_size(cls, image_id: str, region: Optional[str]) -> float: except ibm.ibm_cloud_sdk_core.ApiException as e: # type: ignore[union-attr] logger.error(e.message) with ux_utils.print_exception_no_traceback(): - raise ValueError(f'Image {image_id!r} not found in ' - f'IBM region "{region}"') from None + raise ValueError( + f'Image {image_id!r} not found in IBM region "{region}".\n' + '\nTo use image id in IBM, create a private VPC image and ' + 'paste its ID in the image_id section.\n' + '\nTo create an image manually:\n' + 'https://cloud.ibm.com/docs/vpc?topic=vpc-creating-and-using-an-image-from-volume\n' # pylint: disable=line-too-long + '\nTo use an official VPC image creation tool:\n' + 'https://www.ibm.com/cloud/blog/use-ibm-packer-plugin-to-create-custom-images-on-ibm-cloud-vpc-infrastructure\n' # pylint: disable=line-too-long + '\nTo use a more limited but easier to manage tool:\n' + 'https://github.com/IBM/vpc-img-inst') from None try: # image_size['file']['size'] is not relevant, since # the minimum size of a volume onto which this image