skypilot-nightly 1.0.0.dev20250509__py3-none-any.whl → 1.0.0.dev20251107__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.
Potentially problematic release.
This version of skypilot-nightly might be problematic. Click here for more details.
- sky/__init__.py +22 -6
- sky/adaptors/aws.py +25 -7
- sky/adaptors/common.py +24 -1
- sky/adaptors/coreweave.py +278 -0
- sky/adaptors/do.py +8 -2
- sky/adaptors/hyperbolic.py +8 -0
- sky/adaptors/kubernetes.py +149 -18
- sky/adaptors/nebius.py +170 -17
- sky/adaptors/primeintellect.py +1 -0
- sky/adaptors/runpod.py +68 -0
- sky/adaptors/seeweb.py +167 -0
- sky/adaptors/shadeform.py +89 -0
- sky/admin_policy.py +187 -4
- sky/authentication.py +179 -225
- sky/backends/__init__.py +4 -2
- sky/backends/backend.py +22 -9
- sky/backends/backend_utils.py +1299 -380
- sky/backends/cloud_vm_ray_backend.py +1715 -518
- sky/backends/docker_utils.py +1 -1
- sky/backends/local_docker_backend.py +11 -6
- sky/backends/wheel_utils.py +37 -9
- sky/{clouds/service_catalog → catalog}/__init__.py +21 -19
- sky/{clouds/service_catalog → catalog}/aws_catalog.py +27 -8
- sky/{clouds/service_catalog → catalog}/azure_catalog.py +10 -7
- sky/{clouds/service_catalog → catalog}/common.py +89 -48
- sky/{clouds/service_catalog → catalog}/cudo_catalog.py +8 -5
- sky/{clouds/service_catalog → catalog}/data_fetchers/analyze.py +1 -1
- sky/{clouds/service_catalog → catalog}/data_fetchers/fetch_aws.py +30 -40
- sky/{clouds/service_catalog → catalog}/data_fetchers/fetch_cudo.py +38 -38
- sky/{clouds/service_catalog → catalog}/data_fetchers/fetch_gcp.py +42 -15
- sky/catalog/data_fetchers/fetch_hyperbolic.py +136 -0
- sky/{clouds/service_catalog → catalog}/data_fetchers/fetch_lambda_cloud.py +1 -0
- sky/catalog/data_fetchers/fetch_nebius.py +335 -0
- sky/catalog/data_fetchers/fetch_runpod.py +698 -0
- sky/catalog/data_fetchers/fetch_seeweb.py +329 -0
- sky/catalog/data_fetchers/fetch_shadeform.py +142 -0
- sky/{clouds/service_catalog → catalog}/data_fetchers/fetch_vast.py +1 -1
- sky/{clouds/service_catalog → catalog}/data_fetchers/fetch_vsphere.py +1 -1
- sky/{clouds/service_catalog → catalog}/do_catalog.py +5 -2
- sky/{clouds/service_catalog → catalog}/fluidstack_catalog.py +6 -3
- sky/{clouds/service_catalog → catalog}/gcp_catalog.py +41 -15
- sky/catalog/hyperbolic_catalog.py +136 -0
- sky/{clouds/service_catalog → catalog}/ibm_catalog.py +9 -6
- sky/{clouds/service_catalog → catalog}/kubernetes_catalog.py +36 -24
- sky/{clouds/service_catalog → catalog}/lambda_catalog.py +9 -6
- sky/{clouds/service_catalog → catalog}/nebius_catalog.py +9 -7
- sky/{clouds/service_catalog → catalog}/oci_catalog.py +9 -6
- sky/{clouds/service_catalog → catalog}/paperspace_catalog.py +5 -2
- sky/catalog/primeintellect_catalog.py +95 -0
- sky/{clouds/service_catalog → catalog}/runpod_catalog.py +11 -4
- sky/{clouds/service_catalog → catalog}/scp_catalog.py +9 -6
- sky/catalog/seeweb_catalog.py +184 -0
- sky/catalog/shadeform_catalog.py +165 -0
- sky/catalog/ssh_catalog.py +167 -0
- sky/{clouds/service_catalog → catalog}/vast_catalog.py +6 -3
- sky/{clouds/service_catalog → catalog}/vsphere_catalog.py +5 -2
- sky/check.py +491 -203
- sky/cli.py +5 -6005
- sky/client/{cli.py → cli/command.py} +2477 -1885
- sky/client/cli/deprecation_utils.py +99 -0
- sky/client/cli/flags.py +359 -0
- sky/client/cli/table_utils.py +320 -0
- sky/client/common.py +70 -32
- sky/client/oauth.py +82 -0
- sky/client/sdk.py +1203 -297
- sky/client/sdk_async.py +833 -0
- sky/client/service_account_auth.py +47 -0
- sky/cloud_stores.py +73 -0
- sky/clouds/__init__.py +13 -0
- sky/clouds/aws.py +358 -93
- sky/clouds/azure.py +105 -83
- sky/clouds/cloud.py +127 -36
- sky/clouds/cudo.py +68 -50
- sky/clouds/do.py +66 -48
- sky/clouds/fluidstack.py +63 -44
- sky/clouds/gcp.py +339 -110
- sky/clouds/hyperbolic.py +293 -0
- sky/clouds/ibm.py +70 -49
- sky/clouds/kubernetes.py +563 -162
- sky/clouds/lambda_cloud.py +74 -54
- sky/clouds/nebius.py +206 -80
- sky/clouds/oci.py +88 -66
- sky/clouds/paperspace.py +61 -44
- sky/clouds/primeintellect.py +317 -0
- sky/clouds/runpod.py +164 -74
- sky/clouds/scp.py +89 -83
- sky/clouds/seeweb.py +466 -0
- sky/clouds/shadeform.py +400 -0
- sky/clouds/ssh.py +263 -0
- sky/clouds/utils/aws_utils.py +10 -4
- sky/clouds/utils/gcp_utils.py +87 -11
- sky/clouds/utils/oci_utils.py +38 -14
- sky/clouds/utils/scp_utils.py +177 -124
- sky/clouds/vast.py +99 -77
- sky/clouds/vsphere.py +51 -40
- sky/core.py +349 -139
- sky/dag.py +15 -0
- sky/dashboard/out/404.html +1 -1
- sky/dashboard/out/_next/static/chunks/1141-e6aa9ab418717c59.js +11 -0
- sky/dashboard/out/_next/static/chunks/1272-1ef0bf0237faccdb.js +1 -0
- sky/dashboard/out/_next/static/chunks/1871-74503c8e80fd253b.js +6 -0
- sky/dashboard/out/_next/static/chunks/2260-7703229c33c5ebd5.js +1 -0
- sky/dashboard/out/_next/static/chunks/2350.fab69e61bac57b23.js +1 -0
- sky/dashboard/out/_next/static/chunks/2369.fc20f0c2c8ed9fe7.js +15 -0
- sky/dashboard/out/_next/static/chunks/2755.fff53c4a3fcae910.js +26 -0
- sky/dashboard/out/_next/static/chunks/3294.72362fa129305b19.js +1 -0
- sky/dashboard/out/_next/static/chunks/3785.ad6adaa2a0fa9768.js +1 -0
- sky/dashboard/out/_next/static/chunks/3850-ff4a9a69d978632b.js +1 -0
- sky/dashboard/out/_next/static/chunks/3937.210053269f121201.js +1 -0
- sky/dashboard/out/_next/static/chunks/4725.a830b5c9e7867c92.js +1 -0
- sky/dashboard/out/_next/static/chunks/4937.a2baa2df5572a276.js +15 -0
- sky/dashboard/out/_next/static/chunks/5739-d67458fcb1386c92.js +8 -0
- sky/dashboard/out/_next/static/chunks/6130-2be46d70a38f1e82.js +1 -0
- sky/dashboard/out/_next/static/chunks/616-3d59f75e2ccf9321.js +39 -0
- sky/dashboard/out/_next/static/chunks/6212-7bd06f60ba693125.js +13 -0
- sky/dashboard/out/_next/static/chunks/6601-06114c982db410b6.js +1 -0
- sky/dashboard/out/_next/static/chunks/6856-ef8ba11f96d8c4a3.js +1 -0
- sky/dashboard/out/_next/static/chunks/6989-01359c57e018caa4.js +1 -0
- sky/dashboard/out/_next/static/chunks/6990-32b6e2d3822301fa.js +1 -0
- sky/dashboard/out/_next/static/chunks/7359-c8d04e06886000b3.js +30 -0
- sky/dashboard/out/_next/static/chunks/7411-b15471acd2cba716.js +41 -0
- sky/dashboard/out/_next/static/chunks/7615-3301e838e5f25772.js +1 -0
- sky/dashboard/out/_next/static/chunks/8640.5b9475a2d18c5416.js +16 -0
- sky/dashboard/out/_next/static/chunks/8969-1e4613c651bf4051.js +1 -0
- sky/dashboard/out/_next/static/chunks/9025.fa408f3242e9028d.js +6 -0
- sky/dashboard/out/_next/static/chunks/9353-cff34f7e773b2e2b.js +1 -0
- sky/dashboard/out/_next/static/chunks/9360.7310982cf5a0dc79.js +31 -0
- sky/dashboard/out/_next/static/chunks/9847.3aaca6bb33455140.js +30 -0
- sky/dashboard/out/_next/static/chunks/fd9d1056-86323a29a8f7e46a.js +1 -0
- sky/dashboard/out/_next/static/chunks/framework-cf60a09ccd051a10.js +33 -0
- sky/dashboard/out/_next/static/chunks/main-app-587214043926b3cc.js +1 -0
- sky/dashboard/out/_next/static/chunks/main-f15ccb73239a3bf1.js +1 -0
- sky/dashboard/out/_next/static/chunks/pages/_app-bde01e4a2beec258.js +34 -0
- sky/dashboard/out/_next/static/chunks/pages/_error-c66a4e8afc46f17b.js +1 -0
- sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]/[job]-c736ead69c2d86ec.js +16 -0
- sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]-a37d2063af475a1c.js +1 -0
- sky/dashboard/out/_next/static/chunks/pages/clusters-d44859594e6f8064.js +1 -0
- sky/dashboard/out/_next/static/chunks/pages/config-dfb9bf07b13045f4.js +1 -0
- sky/dashboard/out/_next/static/chunks/pages/index-444f1804401f04ea.js +1 -0
- sky/dashboard/out/_next/static/chunks/pages/infra/[context]-c0b5935149902e6f.js +1 -0
- sky/dashboard/out/_next/static/chunks/pages/infra-aed0ea19df7cf961.js +1 -0
- sky/dashboard/out/_next/static/chunks/pages/jobs/[job]-5796e8d6aea291a0.js +16 -0
- sky/dashboard/out/_next/static/chunks/pages/jobs/pools/[pool]-6edeb7d06032adfc.js +21 -0
- sky/dashboard/out/_next/static/chunks/pages/jobs-479dde13399cf270.js +1 -0
- sky/dashboard/out/_next/static/chunks/pages/users-5ab3b907622cf0fe.js +1 -0
- sky/dashboard/out/_next/static/chunks/pages/volumes-b84b948ff357c43e.js +1 -0
- sky/dashboard/out/_next/static/chunks/pages/workspace/new-3f88a1c7e86a3f86.js +1 -0
- sky/dashboard/out/_next/static/chunks/pages/workspaces/[name]-c5a3eeee1c218af1.js +1 -0
- sky/dashboard/out/_next/static/chunks/pages/workspaces-22b23febb3e89ce1.js +1 -0
- sky/dashboard/out/_next/static/chunks/webpack-2679be77fc08a2f8.js +1 -0
- sky/dashboard/out/_next/static/css/0748ce22df867032.css +3 -0
- sky/dashboard/out/_next/static/zB0ed6ge_W1MDszVHhijS/_buildManifest.js +1 -0
- sky/dashboard/out/clusters/[cluster]/[job].html +1 -1
- sky/dashboard/out/clusters/[cluster].html +1 -1
- sky/dashboard/out/clusters.html +1 -1
- sky/dashboard/out/config.html +1 -0
- sky/dashboard/out/index.html +1 -1
- sky/dashboard/out/infra/[context].html +1 -0
- sky/dashboard/out/infra.html +1 -0
- sky/dashboard/out/jobs/[job].html +1 -1
- sky/dashboard/out/jobs/pools/[pool].html +1 -0
- sky/dashboard/out/jobs.html +1 -1
- sky/dashboard/out/users.html +1 -0
- sky/dashboard/out/volumes.html +1 -0
- sky/dashboard/out/workspace/new.html +1 -0
- sky/dashboard/out/workspaces/[name].html +1 -0
- sky/dashboard/out/workspaces.html +1 -0
- sky/data/data_utils.py +137 -1
- sky/data/mounting_utils.py +269 -84
- sky/data/storage.py +1451 -1807
- sky/data/storage_utils.py +43 -57
- sky/exceptions.py +132 -2
- sky/execution.py +206 -63
- sky/global_user_state.py +2374 -586
- sky/jobs/__init__.py +5 -0
- sky/jobs/client/sdk.py +242 -65
- sky/jobs/client/sdk_async.py +143 -0
- sky/jobs/constants.py +9 -8
- sky/jobs/controller.py +839 -277
- sky/jobs/file_content_utils.py +80 -0
- sky/jobs/log_gc.py +201 -0
- sky/jobs/recovery_strategy.py +398 -152
- sky/jobs/scheduler.py +315 -189
- sky/jobs/server/core.py +829 -255
- sky/jobs/server/server.py +156 -115
- sky/jobs/server/utils.py +136 -0
- sky/jobs/state.py +2092 -701
- sky/jobs/utils.py +1242 -160
- sky/logs/__init__.py +21 -0
- sky/logs/agent.py +108 -0
- sky/logs/aws.py +243 -0
- sky/logs/gcp.py +91 -0
- sky/metrics/__init__.py +0 -0
- sky/metrics/utils.py +443 -0
- sky/models.py +78 -1
- sky/optimizer.py +164 -70
- sky/provision/__init__.py +90 -4
- sky/provision/aws/config.py +147 -26
- sky/provision/aws/instance.py +135 -50
- sky/provision/azure/instance.py +10 -5
- sky/provision/common.py +13 -1
- sky/provision/cudo/cudo_machine_type.py +1 -1
- sky/provision/cudo/cudo_utils.py +14 -8
- sky/provision/cudo/cudo_wrapper.py +72 -71
- sky/provision/cudo/instance.py +10 -6
- sky/provision/do/instance.py +10 -6
- sky/provision/do/utils.py +4 -3
- sky/provision/docker_utils.py +114 -23
- sky/provision/fluidstack/instance.py +13 -8
- sky/provision/gcp/__init__.py +1 -0
- sky/provision/gcp/config.py +301 -19
- sky/provision/gcp/constants.py +218 -0
- sky/provision/gcp/instance.py +36 -8
- sky/provision/gcp/instance_utils.py +18 -4
- sky/provision/gcp/volume_utils.py +247 -0
- sky/provision/hyperbolic/__init__.py +12 -0
- sky/provision/hyperbolic/config.py +10 -0
- sky/provision/hyperbolic/instance.py +437 -0
- sky/provision/hyperbolic/utils.py +373 -0
- sky/provision/instance_setup.py +93 -14
- sky/provision/kubernetes/__init__.py +5 -0
- sky/provision/kubernetes/config.py +9 -52
- sky/provision/kubernetes/constants.py +17 -0
- sky/provision/kubernetes/instance.py +789 -247
- sky/provision/kubernetes/manifests/fusermount-server-daemonset.yaml +1 -2
- sky/provision/kubernetes/network.py +27 -17
- sky/provision/kubernetes/network_utils.py +40 -43
- sky/provision/kubernetes/utils.py +1192 -531
- sky/provision/kubernetes/volume.py +282 -0
- sky/provision/lambda_cloud/instance.py +22 -16
- sky/provision/nebius/constants.py +50 -0
- sky/provision/nebius/instance.py +19 -6
- sky/provision/nebius/utils.py +196 -91
- sky/provision/oci/instance.py +10 -5
- sky/provision/paperspace/instance.py +10 -7
- sky/provision/paperspace/utils.py +1 -1
- sky/provision/primeintellect/__init__.py +10 -0
- sky/provision/primeintellect/config.py +11 -0
- sky/provision/primeintellect/instance.py +454 -0
- sky/provision/primeintellect/utils.py +398 -0
- sky/provision/provisioner.py +110 -36
- sky/provision/runpod/__init__.py +5 -0
- sky/provision/runpod/instance.py +27 -6
- sky/provision/runpod/utils.py +51 -18
- sky/provision/runpod/volume.py +180 -0
- sky/provision/scp/__init__.py +15 -0
- sky/provision/scp/config.py +93 -0
- sky/provision/scp/instance.py +531 -0
- sky/provision/seeweb/__init__.py +11 -0
- sky/provision/seeweb/config.py +13 -0
- sky/provision/seeweb/instance.py +807 -0
- sky/provision/shadeform/__init__.py +11 -0
- sky/provision/shadeform/config.py +12 -0
- sky/provision/shadeform/instance.py +351 -0
- sky/provision/shadeform/shadeform_utils.py +83 -0
- sky/provision/ssh/__init__.py +18 -0
- sky/provision/vast/instance.py +13 -8
- sky/provision/vast/utils.py +10 -7
- sky/provision/vsphere/common/vim_utils.py +1 -2
- sky/provision/vsphere/instance.py +15 -10
- sky/provision/vsphere/vsphere_utils.py +9 -19
- sky/py.typed +0 -0
- sky/resources.py +844 -118
- sky/schemas/__init__.py +0 -0
- sky/schemas/api/__init__.py +0 -0
- sky/schemas/api/responses.py +225 -0
- sky/schemas/db/README +4 -0
- sky/schemas/db/env.py +90 -0
- sky/schemas/db/global_user_state/001_initial_schema.py +124 -0
- sky/schemas/db/global_user_state/002_add_workspace_to_cluster_history.py +35 -0
- sky/schemas/db/global_user_state/003_fix_initial_revision.py +61 -0
- sky/schemas/db/global_user_state/004_is_managed.py +34 -0
- sky/schemas/db/global_user_state/005_cluster_event.py +32 -0
- sky/schemas/db/global_user_state/006_provision_log.py +41 -0
- sky/schemas/db/global_user_state/007_cluster_event_request_id.py +34 -0
- sky/schemas/db/global_user_state/008_skylet_ssh_tunnel_metadata.py +34 -0
- sky/schemas/db/global_user_state/009_last_activity_and_launched_at.py +89 -0
- sky/schemas/db/global_user_state/010_save_ssh_key.py +66 -0
- sky/schemas/db/script.py.mako +28 -0
- sky/schemas/db/serve_state/001_initial_schema.py +67 -0
- sky/schemas/db/skypilot_config/001_initial_schema.py +30 -0
- sky/schemas/db/spot_jobs/001_initial_schema.py +97 -0
- sky/schemas/db/spot_jobs/002_cluster_pool.py +42 -0
- sky/schemas/db/spot_jobs/003_pool_hash.py +34 -0
- sky/schemas/db/spot_jobs/004_job_file_contents.py +42 -0
- sky/schemas/db/spot_jobs/005_logs_gc.py +38 -0
- sky/schemas/generated/__init__.py +0 -0
- sky/schemas/generated/autostopv1_pb2.py +36 -0
- sky/schemas/generated/autostopv1_pb2.pyi +43 -0
- sky/schemas/generated/autostopv1_pb2_grpc.py +146 -0
- sky/schemas/generated/jobsv1_pb2.py +86 -0
- sky/schemas/generated/jobsv1_pb2.pyi +254 -0
- sky/schemas/generated/jobsv1_pb2_grpc.py +542 -0
- sky/schemas/generated/managed_jobsv1_pb2.py +74 -0
- sky/schemas/generated/managed_jobsv1_pb2.pyi +278 -0
- sky/schemas/generated/managed_jobsv1_pb2_grpc.py +278 -0
- sky/schemas/generated/servev1_pb2.py +58 -0
- sky/schemas/generated/servev1_pb2.pyi +115 -0
- sky/schemas/generated/servev1_pb2_grpc.py +322 -0
- sky/serve/autoscalers.py +357 -5
- sky/serve/client/impl.py +310 -0
- sky/serve/client/sdk.py +47 -139
- sky/serve/client/sdk_async.py +130 -0
- sky/serve/constants.py +10 -8
- sky/serve/controller.py +64 -19
- sky/serve/load_balancer.py +106 -60
- sky/serve/load_balancing_policies.py +115 -1
- sky/serve/replica_managers.py +273 -162
- sky/serve/serve_rpc_utils.py +179 -0
- sky/serve/serve_state.py +554 -251
- sky/serve/serve_utils.py +733 -220
- sky/serve/server/core.py +66 -711
- sky/serve/server/impl.py +1093 -0
- sky/serve/server/server.py +21 -18
- sky/serve/service.py +133 -48
- sky/serve/service_spec.py +135 -16
- sky/serve/spot_placer.py +3 -0
- sky/server/auth/__init__.py +0 -0
- sky/server/auth/authn.py +50 -0
- sky/server/auth/loopback.py +38 -0
- sky/server/auth/oauth2_proxy.py +200 -0
- sky/server/common.py +475 -181
- sky/server/config.py +81 -23
- sky/server/constants.py +44 -6
- sky/server/daemons.py +229 -0
- sky/server/html/token_page.html +185 -0
- sky/server/metrics.py +160 -0
- sky/server/requests/executor.py +528 -138
- sky/server/requests/payloads.py +351 -17
- sky/server/requests/preconditions.py +21 -17
- sky/server/requests/process.py +112 -29
- sky/server/requests/request_names.py +120 -0
- sky/server/requests/requests.py +817 -224
- sky/server/requests/serializers/decoders.py +82 -31
- sky/server/requests/serializers/encoders.py +140 -22
- sky/server/requests/threads.py +106 -0
- sky/server/rest.py +417 -0
- sky/server/server.py +1290 -284
- sky/server/state.py +20 -0
- sky/server/stream_utils.py +345 -57
- sky/server/uvicorn.py +217 -3
- sky/server/versions.py +270 -0
- sky/setup_files/MANIFEST.in +5 -0
- sky/setup_files/alembic.ini +156 -0
- sky/setup_files/dependencies.py +136 -31
- sky/setup_files/setup.py +44 -42
- sky/sky_logging.py +102 -5
- sky/skylet/attempt_skylet.py +1 -0
- sky/skylet/autostop_lib.py +129 -8
- sky/skylet/configs.py +27 -20
- sky/skylet/constants.py +171 -19
- sky/skylet/events.py +105 -21
- sky/skylet/job_lib.py +335 -104
- sky/skylet/log_lib.py +297 -18
- sky/skylet/log_lib.pyi +44 -1
- sky/skylet/ray_patches/__init__.py +17 -3
- sky/skylet/ray_patches/autoscaler.py.diff +18 -0
- sky/skylet/ray_patches/cli.py.diff +19 -0
- sky/skylet/ray_patches/command_runner.py.diff +17 -0
- sky/skylet/ray_patches/log_monitor.py.diff +20 -0
- sky/skylet/ray_patches/resource_demand_scheduler.py.diff +32 -0
- sky/skylet/ray_patches/updater.py.diff +18 -0
- sky/skylet/ray_patches/worker.py.diff +41 -0
- sky/skylet/services.py +564 -0
- sky/skylet/skylet.py +63 -4
- sky/skylet/subprocess_daemon.py +103 -29
- sky/skypilot_config.py +506 -99
- sky/ssh_node_pools/__init__.py +1 -0
- sky/ssh_node_pools/core.py +135 -0
- sky/ssh_node_pools/server.py +233 -0
- sky/task.py +621 -137
- sky/templates/aws-ray.yml.j2 +10 -3
- sky/templates/azure-ray.yml.j2 +1 -1
- sky/templates/do-ray.yml.j2 +1 -1
- sky/templates/gcp-ray.yml.j2 +57 -0
- sky/templates/hyperbolic-ray.yml.j2 +67 -0
- sky/templates/jobs-controller.yaml.j2 +27 -24
- sky/templates/kubernetes-loadbalancer.yml.j2 +2 -0
- sky/templates/kubernetes-ray.yml.j2 +607 -51
- sky/templates/lambda-ray.yml.j2 +1 -1
- sky/templates/nebius-ray.yml.j2 +33 -12
- sky/templates/paperspace-ray.yml.j2 +1 -1
- sky/templates/primeintellect-ray.yml.j2 +71 -0
- sky/templates/runpod-ray.yml.j2 +9 -1
- sky/templates/scp-ray.yml.j2 +3 -50
- sky/templates/seeweb-ray.yml.j2 +108 -0
- sky/templates/shadeform-ray.yml.j2 +72 -0
- sky/templates/sky-serve-controller.yaml.j2 +22 -2
- sky/templates/websocket_proxy.py +178 -18
- sky/usage/usage_lib.py +18 -11
- sky/users/__init__.py +0 -0
- sky/users/model.conf +15 -0
- sky/users/permission.py +387 -0
- sky/users/rbac.py +121 -0
- sky/users/server.py +720 -0
- sky/users/token_service.py +218 -0
- sky/utils/accelerator_registry.py +34 -5
- sky/utils/admin_policy_utils.py +84 -38
- sky/utils/annotations.py +16 -5
- sky/utils/asyncio_utils.py +78 -0
- sky/utils/auth_utils.py +153 -0
- sky/utils/benchmark_utils.py +60 -0
- sky/utils/cli_utils/status_utils.py +159 -86
- sky/utils/cluster_utils.py +31 -9
- sky/utils/command_runner.py +354 -68
- sky/utils/command_runner.pyi +93 -3
- sky/utils/common.py +35 -8
- sky/utils/common_utils.py +310 -87
- sky/utils/config_utils.py +87 -5
- sky/utils/context.py +402 -0
- sky/utils/context_utils.py +222 -0
- sky/utils/controller_utils.py +264 -89
- sky/utils/dag_utils.py +31 -12
- sky/utils/db/__init__.py +0 -0
- sky/utils/db/db_utils.py +470 -0
- sky/utils/db/migration_utils.py +133 -0
- sky/utils/directory_utils.py +12 -0
- sky/utils/env_options.py +13 -0
- sky/utils/git.py +567 -0
- sky/utils/git_clone.sh +460 -0
- sky/utils/infra_utils.py +195 -0
- sky/utils/kubernetes/cleanup-tunnel.sh +62 -0
- sky/utils/kubernetes/config_map_utils.py +133 -0
- sky/utils/kubernetes/create_cluster.sh +13 -27
- sky/utils/kubernetes/delete_cluster.sh +10 -7
- sky/utils/kubernetes/deploy_remote_cluster.py +1299 -0
- sky/utils/kubernetes/exec_kubeconfig_converter.py +22 -31
- sky/utils/kubernetes/generate_kind_config.py +6 -66
- sky/utils/kubernetes/generate_kubeconfig.sh +4 -1
- sky/utils/kubernetes/gpu_labeler.py +5 -5
- sky/utils/kubernetes/kubernetes_deploy_utils.py +354 -47
- sky/utils/kubernetes/ssh-tunnel.sh +379 -0
- sky/utils/kubernetes/ssh_utils.py +221 -0
- sky/utils/kubernetes_enums.py +8 -15
- sky/utils/lock_events.py +94 -0
- sky/utils/locks.py +368 -0
- sky/utils/log_utils.py +300 -6
- sky/utils/perf_utils.py +22 -0
- sky/utils/resource_checker.py +298 -0
- sky/utils/resources_utils.py +249 -32
- sky/utils/rich_utils.py +213 -37
- sky/utils/schemas.py +905 -147
- sky/utils/serialize_utils.py +16 -0
- sky/utils/status_lib.py +10 -0
- sky/utils/subprocess_utils.py +38 -15
- sky/utils/tempstore.py +70 -0
- sky/utils/timeline.py +24 -52
- sky/utils/ux_utils.py +84 -15
- sky/utils/validator.py +11 -1
- sky/utils/volume.py +86 -0
- sky/utils/yaml_utils.py +111 -0
- sky/volumes/__init__.py +13 -0
- sky/volumes/client/__init__.py +0 -0
- sky/volumes/client/sdk.py +149 -0
- sky/volumes/server/__init__.py +0 -0
- sky/volumes/server/core.py +258 -0
- sky/volumes/server/server.py +122 -0
- sky/volumes/volume.py +212 -0
- sky/workspaces/__init__.py +0 -0
- sky/workspaces/core.py +655 -0
- sky/workspaces/server.py +101 -0
- sky/workspaces/utils.py +56 -0
- skypilot_nightly-1.0.0.dev20251107.dist-info/METADATA +675 -0
- skypilot_nightly-1.0.0.dev20251107.dist-info/RECORD +594 -0
- {skypilot_nightly-1.0.0.dev20250509.dist-info → skypilot_nightly-1.0.0.dev20251107.dist-info}/WHEEL +1 -1
- sky/benchmark/benchmark_state.py +0 -256
- sky/benchmark/benchmark_utils.py +0 -641
- sky/clouds/service_catalog/constants.py +0 -7
- sky/dashboard/out/_next/static/LksQgChY5izXjokL3LcEu/_buildManifest.js +0 -1
- sky/dashboard/out/_next/static/chunks/236-f49500b82ad5392d.js +0 -6
- sky/dashboard/out/_next/static/chunks/312-c3c8845990db8ffc.js +0 -15
- sky/dashboard/out/_next/static/chunks/37-0a572fe0dbb89c4d.js +0 -6
- sky/dashboard/out/_next/static/chunks/678-206dddca808e6d16.js +0 -59
- sky/dashboard/out/_next/static/chunks/845-0f8017370869e269.js +0 -1
- sky/dashboard/out/_next/static/chunks/979-7bf73a4c7cea0f5c.js +0 -1
- sky/dashboard/out/_next/static/chunks/fd9d1056-2821b0f0cabcd8bd.js +0 -1
- sky/dashboard/out/_next/static/chunks/framework-87d061ee6ed71b28.js +0 -33
- sky/dashboard/out/_next/static/chunks/main-app-241eb28595532291.js +0 -1
- sky/dashboard/out/_next/static/chunks/main-e0e2335212e72357.js +0 -1
- sky/dashboard/out/_next/static/chunks/pages/_app-e6b013bc3f77ad60.js +0 -1
- sky/dashboard/out/_next/static/chunks/pages/_error-1be831200e60c5c0.js +0 -1
- sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]/[job]-e15db85d0ea1fbe1.js +0 -1
- sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]-f383db7389368ea7.js +0 -1
- sky/dashboard/out/_next/static/chunks/pages/clusters-a93b93e10b8b074e.js +0 -1
- sky/dashboard/out/_next/static/chunks/pages/index-f9f039532ca8cbc4.js +0 -1
- sky/dashboard/out/_next/static/chunks/pages/jobs/[job]-03f279c6741fb48b.js +0 -1
- sky/dashboard/out/_next/static/chunks/pages/jobs-a75029b67aab6a2e.js +0 -1
- sky/dashboard/out/_next/static/chunks/webpack-830f59b8404e96b8.js +0 -1
- sky/dashboard/out/_next/static/css/c6933bbb2ce7f4dd.css +0 -3
- sky/jobs/dashboard/dashboard.py +0 -223
- sky/jobs/dashboard/static/favicon.ico +0 -0
- sky/jobs/dashboard/templates/index.html +0 -831
- sky/jobs/server/dashboard_utils.py +0 -69
- sky/skylet/providers/scp/__init__.py +0 -2
- sky/skylet/providers/scp/config.py +0 -149
- sky/skylet/providers/scp/node_provider.py +0 -578
- sky/templates/kubernetes-ssh-jump.yml.j2 +0 -94
- sky/utils/db_utils.py +0 -100
- sky/utils/kubernetes/deploy_remote_cluster.sh +0 -308
- sky/utils/kubernetes/ssh_jump_lifecycle_manager.py +0 -191
- skypilot_nightly-1.0.0.dev20250509.dist-info/METADATA +0 -361
- skypilot_nightly-1.0.0.dev20250509.dist-info/RECORD +0 -396
- /sky/{clouds/service_catalog → catalog}/config.py +0 -0
- /sky/{benchmark → catalog/data_fetchers}/__init__.py +0 -0
- /sky/{clouds/service_catalog → catalog}/data_fetchers/fetch_azure.py +0 -0
- /sky/{clouds/service_catalog → catalog}/data_fetchers/fetch_fluidstack.py +0 -0
- /sky/{clouds/service_catalog → catalog}/data_fetchers/fetch_ibm.py +0 -0
- /sky/{clouds/service_catalog/data_fetchers → client/cli}/__init__.py +0 -0
- /sky/dashboard/out/_next/static/{LksQgChY5izXjokL3LcEu → zB0ed6ge_W1MDszVHhijS}/_ssgManifest.js +0 -0
- {skypilot_nightly-1.0.0.dev20250509.dist-info → skypilot_nightly-1.0.0.dev20251107.dist-info}/entry_points.txt +0 -0
- {skypilot_nightly-1.0.0.dev20250509.dist-info → skypilot_nightly-1.0.0.dev20251107.dist-info}/licenses/LICENSE +0 -0
- {skypilot_nightly-1.0.0.dev20250509.dist-info → skypilot_nightly-1.0.0.dev20251107.dist-info}/top_level.txt +0 -0
sky/server/auth/authn.py
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""Authentication module."""
|
|
2
|
+
import json
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
import fastapi
|
|
6
|
+
|
|
7
|
+
from sky import models
|
|
8
|
+
from sky import sky_logging
|
|
9
|
+
from sky.skylet import constants
|
|
10
|
+
|
|
11
|
+
logger = sky_logging.init_logger(__name__)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# TODO(hailong): Remove this function and use request.state.auth_user instead.
|
|
15
|
+
async def override_user_info_in_request_body(request: fastapi.Request,
|
|
16
|
+
auth_user: Optional[models.User]):
|
|
17
|
+
# Skip for upload requests to avoid consuming the body prematurely, which
|
|
18
|
+
# will break the streaming upload.
|
|
19
|
+
if request.url.path.startswith('/upload'):
|
|
20
|
+
return
|
|
21
|
+
if auth_user is None:
|
|
22
|
+
return
|
|
23
|
+
|
|
24
|
+
body = await request.body()
|
|
25
|
+
if body:
|
|
26
|
+
try:
|
|
27
|
+
original_json = await request.json()
|
|
28
|
+
except (json.JSONDecodeError, UnicodeDecodeError) as e:
|
|
29
|
+
logger.error(f'Error parsing request JSON: {e}')
|
|
30
|
+
else:
|
|
31
|
+
logger.debug(f'Overriding user for {request.state.request_id}: '
|
|
32
|
+
f'{auth_user.name}, {auth_user.id}')
|
|
33
|
+
if 'env_vars' in original_json:
|
|
34
|
+
if isinstance(original_json.get('env_vars'), dict):
|
|
35
|
+
original_json['env_vars'][
|
|
36
|
+
constants.USER_ID_ENV_VAR] = auth_user.id
|
|
37
|
+
original_json['env_vars'][
|
|
38
|
+
constants.USER_ENV_VAR] = auth_user.name
|
|
39
|
+
else:
|
|
40
|
+
logger.warning(
|
|
41
|
+
f'"env_vars" in request body is not a dictionary '
|
|
42
|
+
f'for request {request.state.request_id}. '
|
|
43
|
+
'Skipping user info injection into body.')
|
|
44
|
+
else:
|
|
45
|
+
original_json['env_vars'] = {}
|
|
46
|
+
original_json['env_vars'][
|
|
47
|
+
constants.USER_ID_ENV_VAR] = auth_user.id
|
|
48
|
+
original_json['env_vars'][
|
|
49
|
+
constants.USER_ENV_VAR] = auth_user.name
|
|
50
|
+
request._body = json.dumps(original_json).encode('utf-8') # pylint: disable=protected-access
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""Shared loopback detection utilities for auth middlewares."""
|
|
2
|
+
|
|
3
|
+
import ipaddress
|
|
4
|
+
|
|
5
|
+
import fastapi
|
|
6
|
+
|
|
7
|
+
from sky import sky_logging
|
|
8
|
+
|
|
9
|
+
logger = sky_logging.init_logger(__name__)
|
|
10
|
+
|
|
11
|
+
COMMON_PROXY_HEADERS = [
|
|
12
|
+
'X-Forwarded-For', 'Forwarded', 'X-Real-IP', 'X-Client-IP',
|
|
13
|
+
'X-Forwarded-Host', 'X-Forwarded-Proto'
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _is_loopback_ip(ip_str: str) -> bool:
|
|
18
|
+
"""Check if an IP address is a loopback address."""
|
|
19
|
+
try:
|
|
20
|
+
ip = ipaddress.ip_address(ip_str)
|
|
21
|
+
return ip.is_loopback
|
|
22
|
+
except ValueError:
|
|
23
|
+
return False
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def is_loopback_request(request: fastapi.Request) -> bool:
|
|
27
|
+
"""Determine if a request is coming from localhost."""
|
|
28
|
+
if request.client is None:
|
|
29
|
+
return False
|
|
30
|
+
|
|
31
|
+
client_host = request.client.host
|
|
32
|
+
if client_host == 'localhost' or _is_loopback_ip(client_host):
|
|
33
|
+
# Additional checks: ensure no forwarding headers are present.
|
|
34
|
+
# If there are any, assume this traffic went through a proxy.
|
|
35
|
+
return not any(
|
|
36
|
+
request.headers.get(header) for header in COMMON_PROXY_HEADERS)
|
|
37
|
+
|
|
38
|
+
return False
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
"""Authentication based on oauth2-proxy."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import hashlib
|
|
5
|
+
import http
|
|
6
|
+
import os
|
|
7
|
+
import traceback
|
|
8
|
+
from typing import Optional
|
|
9
|
+
import urllib
|
|
10
|
+
|
|
11
|
+
import aiohttp
|
|
12
|
+
import fastapi
|
|
13
|
+
import starlette.middleware.base
|
|
14
|
+
|
|
15
|
+
from sky import global_user_state
|
|
16
|
+
from sky import models
|
|
17
|
+
from sky import sky_logging
|
|
18
|
+
from sky.jobs import utils as managed_job_utils
|
|
19
|
+
from sky.server.auth import authn
|
|
20
|
+
from sky.server.auth import loopback
|
|
21
|
+
from sky.users import permission
|
|
22
|
+
from sky.utils import common_utils
|
|
23
|
+
|
|
24
|
+
logger = sky_logging.init_logger(__name__)
|
|
25
|
+
|
|
26
|
+
# We do not support setting these in config.yaml because:
|
|
27
|
+
# 1. config.yaml can be updated dynamically, but auth middleware does not
|
|
28
|
+
# support hot reload yet.
|
|
29
|
+
# 2. If we introduce hot reload for auth middleware, bad config might
|
|
30
|
+
# invalidate all authenticated sessions and thus cannot be rolled back
|
|
31
|
+
# by API users.
|
|
32
|
+
# TODO(aylei): we should introduce server.yaml for static server admin config,
|
|
33
|
+
# which is more structured than multiple environment variables and can be less
|
|
34
|
+
# confusing to users.
|
|
35
|
+
OAUTH2_PROXY_BASE_URL_ENV_VAR = 'SKYPILOT_AUTH_OAUTH2_PROXY_BASE_URL'
|
|
36
|
+
OAUTH2_PROXY_ENABLED_ENV_VAR = 'SKYPILOT_AUTH_OAUTH2_PROXY_ENABLED'
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class OAuth2ProxyMiddleware(starlette.middleware.base.BaseHTTPMiddleware):
|
|
40
|
+
"""Middleware to handle authentication by delegating to OAuth2 Proxy."""
|
|
41
|
+
|
|
42
|
+
def __init__(self, *args, **kwargs):
|
|
43
|
+
super().__init__(*args, **kwargs)
|
|
44
|
+
self.enabled: bool = (os.getenv(OAUTH2_PROXY_ENABLED_ENV_VAR,
|
|
45
|
+
'false') == 'true')
|
|
46
|
+
self.proxy_base: str = ''
|
|
47
|
+
if self.enabled:
|
|
48
|
+
proxy_base = os.getenv(OAUTH2_PROXY_BASE_URL_ENV_VAR)
|
|
49
|
+
if not proxy_base:
|
|
50
|
+
raise ValueError('OAuth2 Proxy is enabled but base_url is not '
|
|
51
|
+
'set')
|
|
52
|
+
self.proxy_base = proxy_base.rstrip('/')
|
|
53
|
+
|
|
54
|
+
async def dispatch(self, request: fastapi.Request, call_next):
|
|
55
|
+
if not self.enabled:
|
|
56
|
+
return await call_next(request)
|
|
57
|
+
|
|
58
|
+
# Forward /oauth2/* to oauth2-proxy, including /oauth2/start and
|
|
59
|
+
# /oauth2/callback.
|
|
60
|
+
if request.url.path.startswith('/oauth2'):
|
|
61
|
+
return await self.forward_to_oauth2_proxy(request)
|
|
62
|
+
|
|
63
|
+
return await self.authenticate(request, call_next)
|
|
64
|
+
|
|
65
|
+
async def forward_to_oauth2_proxy(self, request: fastapi.Request):
|
|
66
|
+
"""Forward requests to oauth2-proxy service."""
|
|
67
|
+
logger.debug(f'forwarding to oauth2-proxy: {request.url.path}')
|
|
68
|
+
path = request.url.path.lstrip('/')
|
|
69
|
+
target_url = f'{self.proxy_base}/{path}'
|
|
70
|
+
body = await request.body()
|
|
71
|
+
async with aiohttp.ClientSession() as session:
|
|
72
|
+
try:
|
|
73
|
+
forwarded_headers = dict(request.headers)
|
|
74
|
+
async with session.request(
|
|
75
|
+
method=request.method,
|
|
76
|
+
url=target_url,
|
|
77
|
+
headers=forwarded_headers,
|
|
78
|
+
data=body,
|
|
79
|
+
cookies=request.cookies,
|
|
80
|
+
params=request.query_params,
|
|
81
|
+
allow_redirects=False,
|
|
82
|
+
) as response:
|
|
83
|
+
response_body = await response.read()
|
|
84
|
+
fastapi_response = fastapi.responses.Response(
|
|
85
|
+
content=response_body,
|
|
86
|
+
status_code=response.status,
|
|
87
|
+
headers=dict(response.headers),
|
|
88
|
+
)
|
|
89
|
+
# Forward cookies from OAuth2 proxy response to client
|
|
90
|
+
for cookie_name, cookie in response.cookies.items():
|
|
91
|
+
fastapi_response.set_cookie(
|
|
92
|
+
key=cookie_name,
|
|
93
|
+
value=cookie.value,
|
|
94
|
+
max_age=cookie.get('max-age'),
|
|
95
|
+
expires=cookie.get('expires'),
|
|
96
|
+
path=cookie.get('path', '/'),
|
|
97
|
+
domain=cookie.get('domain'),
|
|
98
|
+
secure=cookie.get('secure', False),
|
|
99
|
+
httponly=cookie.get('httponly', False),
|
|
100
|
+
)
|
|
101
|
+
return fastapi_response
|
|
102
|
+
except (aiohttp.ClientError, asyncio.TimeoutError) as e:
|
|
103
|
+
logger.error(f'Error forwarding to OAuth2 proxy: {e}')
|
|
104
|
+
return fastapi.responses.JSONResponse(
|
|
105
|
+
status_code=http.HTTPStatus.BAD_GATEWAY,
|
|
106
|
+
content={'detail': 'oauth2-proxy service unavailable'})
|
|
107
|
+
|
|
108
|
+
async def authenticate(self, request: fastapi.Request, call_next):
|
|
109
|
+
if request.state.auth_user is not None:
|
|
110
|
+
# Already authenticated
|
|
111
|
+
return await call_next(request)
|
|
112
|
+
|
|
113
|
+
if managed_job_utils.is_consolidation_mode(
|
|
114
|
+
) and loopback.is_loopback_request(request):
|
|
115
|
+
return await call_next(request)
|
|
116
|
+
|
|
117
|
+
async with aiohttp.ClientSession() as session:
|
|
118
|
+
try:
|
|
119
|
+
return await self._authenticate(request, call_next, session)
|
|
120
|
+
except (aiohttp.ClientError, asyncio.TimeoutError) as e:
|
|
121
|
+
logger.error(f'Error communicating with OAuth2 proxy: {e}'
|
|
122
|
+
f'{traceback.format_exc()}')
|
|
123
|
+
return fastapi.responses.JSONResponse(
|
|
124
|
+
status_code=http.HTTPStatus.BAD_GATEWAY,
|
|
125
|
+
content={'detail': 'oauth2-proxy service unavailable'})
|
|
126
|
+
|
|
127
|
+
async def _authenticate(self, request: fastapi.Request, call_next,
|
|
128
|
+
session: aiohttp.ClientSession):
|
|
129
|
+
forwarded_headers = {}
|
|
130
|
+
auth_url = f'{self.proxy_base}/oauth2/auth'
|
|
131
|
+
forwarded_headers['X-Forwarded-Uri'] = str(request.url).rstrip('/')
|
|
132
|
+
forwarded_headers['Host'] = request.url.hostname
|
|
133
|
+
logger.debug(f'authenticate request: {auth_url}, '
|
|
134
|
+
f'headers: {forwarded_headers}')
|
|
135
|
+
|
|
136
|
+
async with session.request(
|
|
137
|
+
method='GET',
|
|
138
|
+
url=auth_url,
|
|
139
|
+
headers=forwarded_headers,
|
|
140
|
+
cookies=request.cookies,
|
|
141
|
+
timeout=aiohttp.ClientTimeout(total=10),
|
|
142
|
+
allow_redirects=False,
|
|
143
|
+
) as auth_response:
|
|
144
|
+
|
|
145
|
+
if auth_response.status == http.HTTPStatus.ACCEPTED:
|
|
146
|
+
# User is authenticated, extract user info from headers
|
|
147
|
+
auth_user = self.get_auth_user(auth_response)
|
|
148
|
+
if not auth_user:
|
|
149
|
+
return fastapi.responses.JSONResponse(
|
|
150
|
+
status_code=http.HTTPStatus.INTERNAL_SERVER_ERROR,
|
|
151
|
+
content={
|
|
152
|
+
'detail':
|
|
153
|
+
'oauth2-proxy is enabled but did not'
|
|
154
|
+
'return user info, check your oauth2-proxy'
|
|
155
|
+
'setup.'
|
|
156
|
+
})
|
|
157
|
+
newly_added = global_user_state.add_or_update_user(auth_user)
|
|
158
|
+
if newly_added:
|
|
159
|
+
permission.permission_service.add_user_if_not_exists(
|
|
160
|
+
auth_user.id)
|
|
161
|
+
request.state.auth_user = auth_user
|
|
162
|
+
await authn.override_user_info_in_request_body(
|
|
163
|
+
request, auth_user)
|
|
164
|
+
return await call_next(request)
|
|
165
|
+
elif auth_response.status == http.HTTPStatus.UNAUTHORIZED:
|
|
166
|
+
# For /api/health, we should allow unauthenticated requests to
|
|
167
|
+
# not break healthz check.
|
|
168
|
+
# TODO(aylei): remove this to an aggregated login middleware
|
|
169
|
+
# in favor of the unified authentication.
|
|
170
|
+
if request.url.path.startswith('/api/health'):
|
|
171
|
+
request.state.anonymous_user = True
|
|
172
|
+
return await call_next(request)
|
|
173
|
+
|
|
174
|
+
# TODO(aylei): in unified authentication, the redirection
|
|
175
|
+
# or rejection should be done after all the authentication
|
|
176
|
+
# methods are performed.
|
|
177
|
+
# Not authenticated, redirect to sign-in
|
|
178
|
+
redirect_path = request.url.path
|
|
179
|
+
if request.url.query:
|
|
180
|
+
redirect_path += f'?{request.url.query}'
|
|
181
|
+
rd = urllib.parse.quote(redirect_path)
|
|
182
|
+
signin_url = (f'{request.base_url}oauth2/start?'
|
|
183
|
+
f'rd={rd}')
|
|
184
|
+
return fastapi.responses.RedirectResponse(url=signin_url)
|
|
185
|
+
else:
|
|
186
|
+
logger.error('oauth2-proxy returned unexpected status '
|
|
187
|
+
f'{auth_response.status}: {auth_response.text}')
|
|
188
|
+
return fastapi.responses.JSONResponse(
|
|
189
|
+
status_code=auth_response.status,
|
|
190
|
+
content={'detail': 'oauth2-proxy error'})
|
|
191
|
+
|
|
192
|
+
def get_auth_user(
|
|
193
|
+
self, response: aiohttp.ClientResponse) -> Optional[models.User]:
|
|
194
|
+
"""Extract user info from OAuth2 proxy response headers."""
|
|
195
|
+
email_header = response.headers.get('X-Auth-Request-Email')
|
|
196
|
+
if email_header:
|
|
197
|
+
user_hash = hashlib.md5(email_header.encode()).hexdigest(
|
|
198
|
+
)[:common_utils.USER_HASH_LENGTH]
|
|
199
|
+
return models.User(id=user_hash, name=email_header)
|
|
200
|
+
return None
|