skyplane-project / skyplane

🔥 Blazing fast bulk data transfers between any cloud 🔥
https://skyplane.org
Apache License 2.0
1.09k stars 62 forks source link

[bug] skyplane init with GCP asks for service usage permission, which may not be set #732

Closed parasj closed 1 year ago

parasj commented 1 year ago

Describe the bug When running skyplane init on a GCP account off the UC Berkeley IST account, we get a permission error:

(3) Configuring GCP:
    Do you want to configure GCP support in Skyplane? [Y/n]: Y
    GCP credentials will be re-initialized
    GCP credentials found in GCP CLI
    GCP credentials found, do you want to enable GCP support in Skyplane? [Y/n]:
    Enter the GCP project ID [skyplane23-paras]:
    Using GCP service account skyplane-manual
╭─────────────────────────────── Traceback (most recent call last) ────────────────────────────────╮
│ /Users/paras/code/skylark/skyplane/cli/cli_init.py:402 in init                                   │
│                                                                                                  │
│   399 │   # load GCP config                                                                      │
│   400 │   typer.secho("\n(3) Configuring GCP:", fg="yellow", bold=True)                          │
│   401 │   if not disable_config_gcp:                                                             │
│ ❱ 402 │   │   cloud_config = load_gcp_config(cloud_config, force_init=reinit_gcp, non_interact   │
│   403 │                                                                                          │
│   404 │   cloud_config.to_config_file(config_path)                                               │
│   405 │   typer.secho(f"\nConfig file saved to {config_path}", fg="green")                       │
│                                                                                                  │
│ ╭───────────────────────────────────────── locals ─────────────────────────────────────────╮     │
│ │         cloud_config = SkyplaneConfig(                                                   │     │
│ │                        │   aws_enabled=True,                                             │     │
│ │                        │   azure_enabled=True,                                           │     │
│ │                        │   gcp_enabled=True,                                             │     │
│ │                        │   anon_clientid='00000000000000000000faad5c786d5b',             │     │
│ │                        │   azure_principal_id='875ed669-9f56-4362-ae79-9dbc6f71fa31',    │     │
│ │                        │   azure_subscription_id='63833c83-12e7-4df6-8be2-2f35e750213c', │     │
│ │                        │   azure_resource_group='skyplane',                              │     │
│ │                        │   azure_umi_name='skyplane_umi',                                │     │
│ │                        │   azure_client_id='51fffcd4-e9c3-468c-817a-15c327d38668',       │     │
│ │                        │   gcp_project_id='skyplane23-paras'                             │     │
│ │                        )                                                                 │     │
│ │   disable_config_aws = False                                                             │     │
│ │ disable_config_azure = False                                                             │     │
│ │   disable_config_gcp = False                                                             │     │
│ │      non_interactive = False                                                             │     │
│ │         reinit_azure = False                                                             │     │
│ │           reinit_gcp = True                                                              │     │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────╯     │
│                                                                                                  │
│ /Users/paras/code/skylark/skyplane/cli/cli_init.py:340 in load_gcp_config                        │
│                                                                                                  │
│   337 │   │   │   │   config.gcp_enabled = True                                                  │
│   338 │   │   │   │   auth = compute.GCPAuthentication(config=config)                            │
│   339 │   │   │   │   typer.secho(f"    Using GCP service account {auth.service_account_name}"   │
│ ❱ 340 │   │   │   │   if not check_gcp_service(auth, non_interactive):                           │
│   341 │   │   │   │   │   return disable_gcp_support()                                           │
│   342 │   │   │   │   try:                                                                       │
│   343 │   │   │   │   │   auth.save_region_config()                                              │
│                                                                                                  │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │                auth = <skyplane.compute.gcp.gcp_auth.GCPAuthentication object at             │ │
│ │                       0x12fb681f0>                                                           │ │
│ │              config = SkyplaneConfig(                                                        │ │
│ │                       │   aws_enabled=True,                                                  │ │
│ │                       │   azure_enabled=True,                                                │ │
│ │                       │   gcp_enabled=True,                                                  │ │
│ │                       │   anon_clientid='00000000000000000000faad5c786d5b',                  │ │
│ │                       │   azure_principal_id='875ed669-9f56-4362-ae79-9dbc6f71fa31',         │ │
│ │                       │   azure_subscription_id='63833c83-12e7-4df6-8be2-2f35e750213c',      │ │
│ │                       │   azure_resource_group='skyplane',                                   │ │
│ │                       │   azure_umi_name='skyplane_umi',                                     │ │
│ │                       │   azure_client_id='51fffcd4-e9c3-468c-817a-15c327d38668',            │ │
│ │                       │   gcp_project_id='skyplane23-paras'                                  │ │
│ │                       )                                                                      │ │
│ │ disable_gcp_support = <function load_gcp_config.<locals>.disable_gcp_support at 0x12fb2a8c0> │ │
│ │          force_init = True                                                                   │ │
│ │       inferred_cred = <google.oauth2.credentials.Credentials object at 0x150a2fa00>          │ │
│ │    inferred_project = 'skyplane23-paras'                                                     │ │
│ │     non_interactive = False                                                                  │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                  │
│ /Users/paras/code/skylark/skyplane/cli/cli_init.py:292 in check_gcp_service                      │
│                                                                                                  │
│   289 def check_gcp_service(gcp_auth: compute.GCPAuthentication, non_interactive: bool = False   │
│   290 │   services = {"iam": "IAM", "compute": "Compute Engine", "storage": "Storage", "cloudr   │
│   291 │   for service, name in services.items():                                                 │
│ ❱ 292 │   │   if not gcp_auth.check_api_enabled(service):                                        │
│   293 │   │   │   typer.secho(f"    GCP {name} API not enabled", fg="red", err=True)             │
│   294 │   │   │   if non_interactive or typer.confirm(f"    Do you want to enable the {name} A   │
│   295 │   │   │   │   gcp_auth.enable_api(service)                                               │
│                                                                                                  │
│ ╭───────────────────────────────────────── locals ──────────────────────────────────────────╮    │
│ │        gcp_auth = <skyplane.compute.gcp.gcp_auth.GCPAuthentication object at 0x12fb681f0> │    │
│ │            name = 'IAM'                                                                   │    │
│ │ non_interactive = False                                                                   │    │
│ │         service = 'iam'                                                                   │    │
│ │        services = {                                                                       │    │
│ │                   │   'iam': 'IAM',                                                       │    │
│ │                   │   'compute': 'Compute Engine',                                        │    │
│ │                   │   'storage': 'Storage',                                               │    │
│ │                   │   'cloudresourcemanager': 'Cloud Resource Manager'                    │    │
│ │                   }                                                                       │    │
│ ╰───────────────────────────────────────────────────────────────────────────────────────────╯    │
│                                                                                                  │
│ /Users/paras/code/skylark/skyplane/compute/gcp/gcp_auth.py:209 in check_api_enabled              │
│                                                                                                  │
│   206 │                                                                                          │
│   207 │   def check_api_enabled(self, api_name: str):                                            │
│   208 │   │   service_usage = self.get_gcp_client(service_name="serviceusage")                   │
│ ❱ 209 │   │   services = service_usage.services().get(name=f"projects/{self.project_id}/servic   │
│   210 │   │   return services.get("state") == "ENABLED"                                          │
│   211 │                                                                                          │
│   212 │   def enable_api(self, service_name: str):                                               │
│                                                                                                  │
│ ╭──────────────────────────────────────── locals ─────────────────────────────────────────╮      │
│ │      api_name = 'iam'                                                                   │      │
│ │          self = <skyplane.compute.gcp.gcp_auth.GCPAuthentication object at 0x12fb681f0> │      │
│ │ service_usage = <googleapiclient.discovery.Resource object at 0x151390760>              │      │
│ ╰─────────────────────────────────────────────────────────────────────────────────────────╯      │
│                                                                                                  │
│ /opt/homebrew/Caskroom/miniconda/base/lib/python3.10/site-packages/googleapiclient/_helpers.py:1 │
│ 30 in positional_wrapper                                                                         │
│                                                                                                  │
│   127 │   │   │   │   │   raise TypeError(message)                                               │
│   128 │   │   │   │   elif positional_parameters_enforcement == POSITIONAL_WARNING:              │
│   129 │   │   │   │   │   logger.warning(message)                                                │
│ ❱ 130 │   │   │   return wrapped(*args, **kwargs)                                                │
│   131 │   │                                                                                      │
│   132 │   │   return positional_wrapper                                                          │
│   133                                                                                            │
│                                                                                                  │
│ ╭───────────────────────────────────── locals ──────────────────────────────────────╮            │
│ │                args = (<googleapiclient.http.HttpRequest object at 0x151391480>,) │            │
│ │              kwargs = {}                                                          │            │
│ │ max_positional_args = 1                                                           │            │
│ │             wrapped = <function HttpRequest.execute at 0x15137b250>               │            │
│ ╰───────────────────────────────────────────────────────────────────────────────────╯            │
│                                                                                                  │
│ /opt/homebrew/Caskroom/miniconda/base/lib/python3.10/site-packages/googleapiclient/http.py:938   │
│ in execute                                                                                       │
│                                                                                                  │
│    935 │   │   for callback in self.response_callbacks:                                          │
│    936 │   │   │   callback(resp)                                                                │
│    937 │   │   if resp.status >= 300:                                                            │
│ ❱  938 │   │   │   raise HttpError(resp, content, uri=self.uri)                                  │
│    939 │   │   return self.postproc(resp, content)                                               │
│    940 │                                                                                         │
│    941 │   @util.positional(2)                                                                   │
│                                                                                                  │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │     content = b'{\n  "error": {\n    "code": 403,\n    "message": "Caller does not have      │ │
│ │               required pe'+995                                                               │ │
│ │        http = <google_auth_httplib2.AuthorizedHttp object at 0x1513904c0>                    │ │
│ │ num_retries = 0                                                                              │ │
│ │        resp = {                                                                              │ │
│ │               │   'vary': 'Origin, X-Origin, Referer',                                       │ │
│ │               │   'content-type': 'application/json; charset=UTF-8',                         │ │
│ │               │   'date': 'Sun, 08 Jan 2023 01:48:24 GMT',                                   │ │
│ │               │   'server': 'ESF',                                                           │ │
│ │               │   'cache-control': 'private',                                                │ │
│ │               │   'x-xss-protection': '0',                                                   │ │
│ │               │   'x-frame-options': 'SAMEORIGIN',                                           │ │
│ │               │   'x-content-type-options': 'nosniff',                                       │ │
│ │               │   'alt-svc': 'h3=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-Q050=":443"; │ │
│ │               ma=2592000,h3-Q04'+82,                                                         │ │
│ │               │   'transfer-encoding': 'chunked',                                            │ │
│ │               │   ... +3                                                                     │ │
│ │               }                                                                              │ │
│ │        self = <googleapiclient.http.HttpRequest object at 0x151391480>                       │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
HttpError: <HttpError 403 when requesting https://serviceusage.googleapis.com/v1/projects/skyplane23-paras/services/iam.googleapis.com?alt=json returned "Caller does not have required permission to use project
skyplane23-paras. Grant the caller the roles/serviceusage.serviceUsageConsumer role, or a custom role with the serviceusage.services.use permission, by visiting
https://console.developers.google.com/iam-admin/iam/project?project=skyplane23-paras and then retry. Propagation of the new permission may take a few minutes.". Details: "[{'@type':
'type.googleapis.com/google.rpc.Help', 'links': [{'description': 'Google developer console IAM admin', 'url': 'https://console.developers.google.com/iam-admin/iam/project?project=skyplane23-paras'}]}, {'@type':
'type.googleapis.com/google.rpc.ErrorInfo', 'reason': 'USER_PROJECT_DENIED', 'domain': 'googleapis.com', 'metadata': {'consumer': 'projects/skyplane23-paras', 'service': 'serviceusage.googleapis.com'}}]">
parasj commented 1 year ago

Fixed by running gcloud auth application-default login