Skip to content

Commit 4b2dd86

Browse files
Michaelvllcg505nkwangleiGITromilbhardwajcbrownstein-lambda
authored
Merge master (#40)
* [perf] optimizations for sky jobs launch (#4341) * cache AWS get_user_identities With SSO enabled (and maybe without?) this takes about a second. We already use an lru_cache for Azure, do the same here. * skip optimization for sky jobs launch --yes The only reason we call optimize for jobs_launch is to give a preview of the resources we expect to use, and give the user an opportunity to back out if it's not what they expect. If you use --yes or -y, you don't have a chance to back out and you're probably running from a script, where you don't care. Optimization can take ~2 seconds, so just skip it. * update logging * address PR comments * [ux] cache cluster status of autostop or spot clusters for 2s (#4332) * add status_updated_at to DB * don't refresh autostop/spot cluster if it's recently been refreshed * update locking mechanism for status check to early exit * address PR comments * add warning about cluster status lock timeout * [k8s] fix managed job issue on k8s (#4357) Signed-off-by: nkwangleiGIT <[email protected]> * [Core] Add `NO_UPLOAD` for `remote_identity` (#4307) * Add skip flag to remote_identity * Rename to NO_UPLOAD * Fixes * lint * comments * Add comments * lint * Add Lambda's GH200 instance type (#4377) Add GH200 instance type * [FluidStack] Fix provisioning and add new gpu types (#4359) [FluidStack] Fix provisioning and add new gpu types * Add new `provisioning` status to fix failed deployments * Add H100 SXM5 GPU mapping * [ux] display human-readable name for controller (#4376) * [k8s] Handle apt update log not existing (#4381) do not panic if file does not exist, it may be written soon * Support event based smoke test instead of sleep time based to reduce flaky test and faster test (#4284) * event based smoke test * more event based smoke test * more test cases * more test cases with managed jobs * bug fix * bump up seconds * merge master and resolve conflict * restore sleep for fail test case * [UX] user-friendly message shown if Kubernetes is not enabled. (#4336) try except * [Jobs] Disable deduplication for logs (#4388) Disable dedup * [OCI] set zone in the ProvisionRecord (#4383) * fix: Add zone to the ProvisionRecord * fix * [Examples] Specify version for vllm cuz vllm v0.6.4.post1 has issue (#4391) * [OCI] Specify vllm version because the latest vllm v0.6.4.post1 has issue * version for vllm-flash-attn * [docs] Specify compartment for OCI resources. (#4384) * [docs] Specify compartment for OCI resources. * Add link to compartment definition page * [k8s] Improve multi-node provisioning time (nimbus) (#4393) * Tracking k8s events with timeline * Remove SSH wait * Parallelize pod creation and status check * Parallelize labelling, add docs on optimizing base image, bump default provision timeout * More parallelization, batching and optimizations * lint * correctness * Fix double launch bug * fix num threads * Add fd limit warning * [k8s] Move setup and ray start to pod args to make them async (#4389) * move scripts to args * Avoid ray setup * fix * Add checks for ray healthiness * remove bc installation * wait for healthy * add todo * fix * fix * format * format * remove unnecessary logging * print out error setup * Add comment * clean up the logging * style * Fixes for ubuntu images * format * remove unused comments * Optimize ray start * add comments * Add comments * Fix comments and logging * missing end_epoch * Add logging * Longer timeout and trigger ray start * Fixes for the ray port and AWS credential setup * Update netcat-openbsd, comments * _NUM_THREADS rename * add num_nodes to calculate timeout * lint * revert * use uv for pip install and for venv creation (#4394) * use uv for pip install and for venv creation uv is a tool that can replace pip and venv (and some other stuff we're not using I think). It's written in rust and in testing is significantly faster for many operation, especially things like `pip list` or `pip install skypilot` when skypilot or all its dependencies are already installed. * add comment to SKY_PIP_CMD * sudo handling for ray * Add comment in dockerfile * fix pod checks * lint --------- Co-authored-by: Zhanghao Wu <[email protected]> Co-authored-by: Christopher Cooper <[email protected]> * [Core] Skip worker ray start for multinode (#4390) * Optimize ray start * add comments * update logging * remove `uv` from runtime setup due to azure installation issue (#4401) * [k8s] Skip listing all pods to speed up optimizer (#4398) * Reduce API calls * lint * [k8s] Nimbus backward compatibility (#4400) * Add nimbus backward compatibility * add uv backcompat * add uv backcompat * add uv backcompat * lint * merge * merge * [Storage] Call `sync_file_mounts` when either rsync or storage file_mounts are specified (#4317) do file mounts if storage is specified * [k8s] Support in-cluster and kubeconfig auth simultaneously (#4188) * per-context SA + incluster auth fixes * lint * Support both incluster and kubeconfig * wip * Ignore kubeconfig when context is not specified, add su, mounting kubeconfig * lint * comments * fix merge issues * lint * Fix Spot instance on Azure (#4408) * [UX] Allow disabling ports in CLI (#4378) [UX] Allow disabling ports * [AWS] Get rid of credential files if `remote_identity: SERVICE_ACCOUNT` specified (#4395) * syntax * minor * Fix OD instance on Azure (#4411) * [UX] Remove K80 and M60 from common GPU list (#4382) * Remove K80 and M60 from GPU list * Fix kubernetes instance type with space * comments * format * format * remove mi25 * Event based smoke tests -- manged jobs (#4386) * event based smoke test * more event based smoke test * more test cases * more test cases with managed jobs * bug fix * bump up seconds * merge master and resolve conflict * more test case * support test_managed_jobs_pipeline_failed_setup * support test_managed_jobs_recovery_aws * manged job status * bug fix * test managed job cancel * test_managed_jobs_storage * more test cases * resolve pr comment * private member function * bug fix * interface change * bug fix * bug fix * raise error on empty status * [k8s] Fix in-cluster auth namespace fetching (#4420) * Fix incluster auth namespace fetching * Fixes * [k8s] Update comparison page image (#4415) Update image * Add a pre commit config to help format before pushing (#4258) * pre commit config * yapf version * fix * mypy check all files * skip smoke_test.py * add doc * better format * newline format * sync with format.sh * comment fix * fix the pylint hook for pre-commit (#4422) * fix the pylint hook * remove default arg * change name * limit pylint files * [k8s] Fix resources.image_id backward compatibility (#4425) * Fix back compat * Fix back compat for image_id + regions * lint * comments * [Tests] Move tests to uv to speed up the dependency installation by >10x (#4424) * correct cache for pypi * Add doc cache and test cache * Add examples folder * fix policy path * use uv for pylint * Fix azure cli * disable cache * use venv * set venv * source instead * rename doc build * Move to uv * Fix azure cli * Add -e * Update .github/workflows/format.yml Co-authored-by: Christopher Cooper <[email protected]> * Update .github/workflows/mypy.yml Co-authored-by: Christopher Cooper <[email protected]> * Update .github/workflows/pylint.yml Co-authored-by: Christopher Cooper <[email protected]> * Update .github/workflows/pytest.yml Co-authored-by: Christopher Cooper <[email protected]> * Update .github/workflows/test-doc-build.yml Co-authored-by: Christopher Cooper <[email protected]> * fix pytest yml * Add merge group --------- Co-authored-by: Christopher Cooper <[email protected]> * fix db * fix launch * remove transaction id * format * format * format * test doc build * doc build * update readme for test kubernetes example (#4426) * update readme * fetch version from gcloud * rename var to GKE_VERSION * subnetwork also use REGION * format * fix types * fix * format * fix types * [k8s] Fix `show-gpus` availability map when nvidia drivers are not installed (#4429) * Fix availability map * Fix availability map * fix types * avoid catching ValueError during failover (#4432) * avoid catching ValueError during failover If the cloud api raises ValueError or a subclass of ValueError during instance termination, we will assume the cluster was downed. Fix this by introducing a new exception ClusterDoesNotExist that we can catch instead of the more general ValueError. * add unit test * lint * [Core] Execute setup when `--detach-setup` and no `run` section (#4430) * Execute setup when --detach-setup and no run section * Update sky/backends/cloud_vm_ray_backend.py Co-authored-by: Tian Xia <[email protected]> * add comments * Fix types * format * minor * Add test for detach setup only --------- Co-authored-by: Tian Xia <[email protected]> * wait for cleanup * [Jobs] Allow logs for finished jobs and add `sky jobs logs --refresh` for restartin jobs controller (#4380) * Stream logs for finished jobs * Allow stream logs for finished jobs * Read files after the indicator lines * Add refresh for `sky jobs logs` * fix log message * address comments * Add smoke test * fix smoke * fix jobs queue smoke test * fix storage * fix merge issue * fix merge issue * Fix merging issue * format --------- Signed-off-by: nkwangleiGIT <[email protected]> Co-authored-by: Christopher Cooper <[email protected]> Co-authored-by: Lei <[email protected]> Co-authored-by: Romil Bhardwaj <[email protected]> Co-authored-by: Cody Brownstein <[email protected]> Co-authored-by: mjibril <[email protected]> Co-authored-by: zpoint <[email protected]> Co-authored-by: Hysun He <[email protected]> Co-authored-by: Tian Xia <[email protected]> Co-authored-by: zpoint <[email protected]>
1 parent aae6ae5 commit 4b2dd86

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

82 files changed

+2140
-878
lines changed

.github/workflows/format.yml

+13-7
Original file line numberDiff line numberDiff line change
@@ -22,29 +22,35 @@ jobs:
2222
python-version: ["3.8"]
2323
steps:
2424
- uses: actions/checkout@v3
25-
- name: Set up Python ${{ matrix.python-version }}
26-
uses: actions/setup-python@v4
25+
- name: Install the latest version of uv
26+
uses: astral-sh/setup-uv@v4
2727
with:
28+
version: "latest"
2829
python-version: ${{ matrix.python-version }}
2930
- name: Install dependencies
3031
run: |
31-
python -m pip install --upgrade pip
32-
pip install yapf==0.32.0
33-
pip install toml==0.10.2
34-
pip install black==22.10.0
35-
pip install isort==5.12.0
32+
uv venv --seed ~/test-env
33+
source ~/test-env/bin/activate
34+
uv pip install yapf==0.32.0
35+
uv pip install toml==0.10.2
36+
uv pip install black==22.10.0
37+
uv pip install isort==5.12.0
3638
- name: Running yapf
3739
run: |
40+
source ~/test-env/bin/activate
3841
yapf --diff --recursive ./ --exclude 'sky/skylet/ray_patches/**' \
3942
--exclude 'sky/skylet/providers/ibm/**'
4043
- name: Running black
4144
run: |
45+
source ~/test-env/bin/activate
4246
black --diff --check sky/skylet/providers/ibm/
4347
- name: Running isort for black formatted files
4448
run: |
49+
source ~/test-env/bin/activate
4550
isort --diff --check --profile black -l 88 -m 3 \
4651
sky/skylet/providers/ibm/
4752
- name: Running isort for yapf formatted files
4853
run: |
54+
source ~/test-env/bin/activate
4955
isort --diff --check ./ --sg 'sky/skylet/ray_patches/**' \
5056
--sg 'sky/skylet/providers/ibm/**'

.github/workflows/mypy-generic.yml

-23
This file was deleted.

.github/workflows/mypy.yml

+10-5
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ on:
1212
- master
1313
- 'releases/**'
1414
- restapi
15+
merge_group:
16+
1517
jobs:
1618
mypy:
1719
runs-on: ubuntu-latest
@@ -20,15 +22,18 @@ jobs:
2022
python-version: ["3.8"]
2123
steps:
2224
- uses: actions/checkout@v3
23-
- name: Set up Python ${{ matrix.python-version }}
24-
uses: actions/setup-python@v4
25+
- name: Install the latest version of uv
26+
uses: astral-sh/setup-uv@v4
2527
with:
28+
version: "latest"
2629
python-version: ${{ matrix.python-version }}
2730
- name: Install dependencies
2831
run: |
29-
python -m pip install --upgrade pip
30-
pip install mypy==$(grep mypy requirements-dev.txt | cut -d'=' -f3)
31-
pip install $(grep types- requirements-dev.txt | tr '\n' ' ')
32+
uv venv --seed ~/test-env
33+
source ~/test-env/bin/activate
34+
uv pip install mypy==$(grep mypy requirements-dev.txt | cut -d'=' -f3)
35+
uv pip install $(grep types- requirements-dev.txt | tr '\n' ' ')
3236
- name: Running mypy
3337
run: |
38+
source ~/test-env/bin/activate
3439
mypy $(cat tests/mypy_files.txt)

.github/workflows/pylint.yml

+10-6
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,20 @@ jobs:
2222
python-version: ["3.8"]
2323
steps:
2424
- uses: actions/checkout@v3
25-
- name: Set up Python ${{ matrix.python-version }}
26-
uses: actions/setup-python@v4
25+
- name: Install the latest version of uv
26+
uses: astral-sh/setup-uv@v4
2727
with:
28+
version: "latest"
2829
python-version: ${{ matrix.python-version }}
2930
- name: Install dependencies
3031
run: |
31-
python -m pip install --upgrade pip
32-
pip install ".[all]"
33-
pip install pylint==2.14.5
34-
pip install pylint-quotes==0.2.3
32+
uv venv --seed ~/test-env
33+
source ~/test-env/bin/activate
34+
uv pip install --prerelease=allow "azure-cli>=2.65.0"
35+
uv pip install ".[all]"
36+
uv pip install pylint==2.14.5
37+
uv pip install pylint-quotes==0.2.3
3538
- name: Analysing the code with pylint
3639
run: |
40+
source ~/test-env/bin/activate
3741
pylint --load-plugins pylint_quotes sky

.github/workflows/pytest.yml

+13-18
Original file line numberDiff line numberDiff line change
@@ -35,26 +35,21 @@ jobs:
3535
steps:
3636
- name: Checkout repository
3737
uses: actions/checkout@v3
38-
39-
- name: Install Python ${{ matrix.python-version }}
40-
uses: actions/setup-python@v4
38+
- name: Install the latest version of uv
39+
uses: astral-sh/setup-uv@v4
4140
with:
41+
version: "latest"
4242
python-version: ${{ matrix.python-version }}
43-
44-
- name: Cache dependencies
45-
uses: actions/cache@v3
46-
if: startsWith(runner.os, 'Linux')
47-
with:
48-
path: ~/.cache/pip
49-
key: ${{ runner.os }}-pip-pytest-${{ matrix.python-version }}
50-
restore-keys: |
51-
${{ runner.os }}-pip-pytest-${{ matrix.python-version }}
52-
5343
- name: Install dependencies
5444
run: |
55-
python -m pip install --upgrade pip
56-
pip install -e ".[all]"
57-
pip install pytest pytest-xdist pytest-env>=0.6 memory-profiler==0.61.0
58-
45+
uv venv --seed ~/test-env
46+
source ~/test-env/bin/activate
47+
uv pip install --prerelease=allow "azure-cli>=2.65.0"
48+
# Use -e to include examples and tests folder in the path for unit
49+
# tests to access them.
50+
uv pip install -e ".[all]"
51+
uv pip install pytest pytest-xdist pytest-env>=0.6 memory-profiler==0.61.0
5952
- name: Run tests with pytest
60-
run: SKYPILOT_DISABLE_USAGE_COLLECTION=1 SKYPILOT_SKIP_CLOUD_IDENTITY_CHECK=1 pytest -n 0 --dist no ${{ matrix.test-path }}
53+
run: |
54+
source ~/test-env/bin/activate
55+
SKYPILOT_DISABLE_USAGE_COLLECTION=1 SKYPILOT_SKIP_CLOUD_IDENTITY_CHECK=1 pytest -n 0 --dist no ${{ matrix.test-path }}

.github/workflows/test-doc-build.yml

+11-6
Original file line numberDiff line numberDiff line change
@@ -11,27 +11,32 @@ on:
1111
branches:
1212
- master
1313
- 'releases/**'
14+
- restapi
1415
merge_group:
1516

1617
jobs:
17-
format:
18+
doc-build:
1819
runs-on: ubuntu-latest
1920
strategy:
2021
matrix:
2122
python-version: ["3.10"]
2223
steps:
2324
- uses: actions/checkout@v3
24-
- name: Set up Python ${{ matrix.python-version }}
25-
uses: actions/setup-python@v4
25+
- name: Install the latest version of uv
26+
uses: astral-sh/setup-uv@v4
2627
with:
28+
version: "latest"
2729
python-version: ${{ matrix.python-version }}
2830
- name: Install dependencies
2931
run: |
30-
python -m pip install --upgrade pip
31-
pip install .
32+
uv venv --seed ~/test-env
33+
source ~/test-env/bin/activate
34+
uv pip install --prerelease=allow "azure-cli>=2.65.0"
35+
uv pip install ".[all]"
3236
cd docs
33-
pip install -r ./requirements-docs.txt
37+
uv pip install -r ./requirements-docs.txt
3438
- name: Build documentation
3539
run: |
40+
source ~/test-env/bin/activate
3641
cd ./docs
3742
./build.sh

.pre-commit-config.yaml

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# Ensure this configuration aligns with format.sh and requirements.txt
2+
repos:
3+
- repo: https://github.com/pre-commit/pre-commit-hooks
4+
rev: v5.0.0
5+
hooks:
6+
- id: trailing-whitespace
7+
- id: end-of-file-fixer
8+
- id: check-yaml
9+
- id: check-added-large-files
10+
11+
- repo: https://github.com/psf/black
12+
rev: 22.10.0 # Match the version from requirements
13+
hooks:
14+
- id: black
15+
name: black (IBM specific)
16+
files: "^sky/skylet/providers/ibm/.*" # Match only files in the IBM directory
17+
18+
- repo: https://github.com/pycqa/isort
19+
rev: 5.12.0 # Match the version from requirements
20+
hooks:
21+
# First isort command
22+
- id: isort
23+
name: isort (general)
24+
args:
25+
- "--sg=build/**" # Matches "${ISORT_YAPF_EXCLUDES[@]}"
26+
- "--sg=sky/skylet/providers/ibm/**"
27+
files: "^(sky|tests|examples|llm|docs)/.*" # Only match these directories
28+
# Second isort command
29+
- id: isort
30+
name: isort (IBM specific)
31+
args:
32+
- "--profile=black"
33+
- "-l=88"
34+
- "-m=3"
35+
files: "^sky/skylet/providers/ibm/.*" # Only match IBM-specific directory
36+
37+
- repo: https://github.com/pre-commit/mirrors-mypy
38+
rev: v0.991 # Match the version from requirements
39+
hooks:
40+
- id: mypy
41+
args:
42+
# From tests/mypy_files.txt
43+
- "sky"
44+
- "--exclude"
45+
- "sky/benchmark|sky/callbacks|sky/skylet/providers/azure|sky/resources.py|sky/backends/monkey_patches"
46+
pass_filenames: false
47+
additional_dependencies:
48+
- types-PyYAML
49+
- types-requests<2.31 # Match the condition in requirements.txt
50+
- types-setuptools
51+
- types-cachetools
52+
- types-pyvmomi
53+
54+
- repo: https://github.com/google/yapf
55+
rev: v0.32.0 # Match the version from requirements
56+
hooks:
57+
- id: yapf
58+
name: yapf
59+
exclude: (build/.*|sky/skylet/providers/ibm/.*) # Matches exclusions from the script
60+
args: ['--recursive', '--parallel'] # Only necessary flags
61+
additional_dependencies: [toml==0.10.2]
62+
63+
- repo: https://github.com/pylint-dev/pylint
64+
rev: v2.14.5 # Match the version from requirements
65+
hooks:
66+
- id: pylint
67+
additional_dependencies:
68+
- pylint-quotes==0.2.3 # Match the version from requirements
69+
name: pylint
70+
args:
71+
- --rcfile=.pylintrc # Use your custom pylint configuration
72+
- --load-plugins=pylint_quotes # Load the pylint-quotes plugin
73+
files: ^sky/ # Only include files from the 'sky/' directory
74+
exclude: ^sky/skylet/providers/ibm/

CONTRIBUTING.md

+1
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ It has some convenience features which you might find helpful (see [Dockerfile](
7878
- If relevant, add tests for your changes. For changes that touch the core system, run the [smoke tests](#testing) and ensure they pass.
7979
- Follow the [Google style guide](https://google.github.io/styleguide/pyguide.html).
8080
- Ensure code is properly formatted by running [`format.sh`](https://github.com/skypilot-org/skypilot/blob/master/format.sh).
81+
- [Optional] You can also install pre-commit hooks by running `pre-commit install` to automatically format your code on commit.
8182
- Push your changes to your fork and open a pull request in the SkyPilot repository.
8283
- In the PR description, write a `Tested:` section to describe relevant tests performed.
8384

Dockerfile_k8s

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ ARG DEBIAN_FRONTEND=noninteractive
77

88
# Initialize conda for root user, install ssh and other local dependencies
99
RUN apt update -y && \
10-
apt install git gcc rsync sudo patch openssh-server pciutils nano fuse socat netcat curl -y && \
10+
apt install git gcc rsync sudo patch openssh-server pciutils nano fuse socat netcat-openbsd curl -y && \
1111
rm -rf /var/lib/apt/lists/* && \
1212
apt remove -y python3 && \
1313
conda init

Dockerfile_k8s_gpu

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ ARG DEBIAN_FRONTEND=noninteractive
77
# We remove cuda lists to avoid conflicts with the cuda version installed by ray
88
RUN rm -rf /etc/apt/sources.list.d/cuda* && \
99
apt update -y && \
10-
apt install git gcc rsync sudo patch openssh-server pciutils nano fuse unzip socat netcat curl -y && \
10+
apt install git gcc rsync sudo patch openssh-server pciutils nano fuse unzip socat netcat-openbsd curl -y && \
1111
rm -rf /var/lib/apt/lists/*
1212

1313
# Setup SSH and generate hostkeys
@@ -36,6 +36,7 @@ SHELL ["/bin/bash", "-c"]
3636

3737
# Install conda and other dependencies
3838
# Keep the conda and Ray versions below in sync with the ones in skylet.constants
39+
# Keep this section in sync with the custom image optimization recommendations in our docs (kubernetes-getting-started.rst)
3940
RUN curl https://repo.anaconda.com/miniconda/Miniconda3-py310_23.11.0-2-Linux-x86_64.sh -o Miniconda3-Linux-x86_64.sh && \
4041
bash Miniconda3-Linux-x86_64.sh -b && \
4142
eval "$(~/miniconda3/bin/conda shell.bash hook)" && conda init && conda config --set auto_activate_base true && conda activate base && \

docs/source/getting-started/installation.rst

+8
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,14 @@ The :code:`~/.oci/config` file should contain the following fields:
267267
# Note that we should avoid using full home path for the key_file configuration, e.g. use ~/.oci instead of /home/username/.oci
268268
key_file=~/.oci/oci_api_key.pem
269269
270+
By default, the provisioned nodes will be in the root `compartment <https://docs.oracle.com/en/cloud/foundation/cloud_architecture/governance/compartments.html>`__. To specify the `compartment <https://docs.oracle.com/en/cloud/foundation/cloud_architecture/governance/compartments.html>`_ other than root, create/edit the file :code:`~/.sky/config.yaml`, put the compartment's OCID there, as the following:
271+
272+
.. code-block:: text
273+
274+
oci:
275+
default:
276+
compartment_ocid: ocid1.compartment.oc1..aaaaaaaa......
277+
270278
271279
Lambda Cloud
272280
~~~~~~~~~~~~~~~~~~

docs/source/reference/comparison.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ SkyPilot provides faster iteration for interactive development. For example, a c
4646
* :strong:`With SkyPilot, a single command (`:literal:`sky launch`:strong:`) takes care of everything.` Behind the scenes, SkyPilot provisions pods, installs all required dependencies, executes the job, returns logs, and provides SSH and VSCode access to debug.
4747

4848

49-
.. figure:: https://blog.skypilot.co/ai-on-kubernetes/images/k8s_vs_skypilot_iterative_v2.png
49+
.. figure:: https://i.imgur.com/xfCfz4N.png
5050
:align: center
5151
:width: 95%
5252
:alt: Iterative Development with Kubernetes vs SkyPilot

0 commit comments

Comments
 (0)