Skip to content

Commit 3228739

Browse files
feat(RHOAIENG-26487): rayjob lifecycled cluster improvements and tests
1 parent 2fea2b6 commit 3228739

File tree

17 files changed

+1604
-185
lines changed

17 files changed

+1604
-185
lines changed

poetry.lock

Lines changed: 21 additions & 21 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ cryptography = "43.0.3"
2929
executing = "1.2.0"
3030
pydantic = "< 2"
3131
ipywidgets = "8.1.2"
32-
odh-kuberay-client = {version = "0.0.0.dev40", source = "testpypi"}
32+
python-client = { git = "https://github.com/ray-project/kuberay.git", subdirectory = "clients/python-client", rev = "d1e750d9beac612ad455b951c1a789f971409ab3" }
3333

3434
[[tool.poetry.source]]
3535
name = "pypi"
@@ -67,4 +67,3 @@ markers = [
6767
]
6868
addopts = "--timeout=900"
6969
testpaths = ["src/codeflare_sdk"]
70-
collect_ignore = ["src/codeflare_sdk/common/utils/unit_test_support.py"]

src/codeflare_sdk/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
AppWrapperStatus,
1212
RayJobClient,
1313
RayJob,
14+
RayJobClusterConfig,
1415
)
1516

1617
from .common.widgets import view_clusters

src/codeflare_sdk/common/kueue/kueue.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
from kubernetes import client
1919
from kubernetes.client.exceptions import ApiException
2020

21+
from ...common.utils import get_current_namespace
22+
2123

2224
def get_default_kueue_name(namespace: str) -> Optional[str]:
2325
"""
@@ -81,7 +83,6 @@ def list_local_queues(
8183
List[dict]:
8284
A list of dictionaries containing the name of the local queue and the available flavors
8385
"""
84-
from ...ray.cluster.cluster import get_current_namespace
8586

8687
if namespace is None: # pragma: no cover
8788
namespace = get_current_namespace()
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
"""
2+
Common utilities for the CodeFlare SDK.
3+
"""
4+
5+
from .k8s_utils import get_current_namespace
6+
7+
__all__ = ["get_current_namespace"]
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
"""
2+
Kubernetes utility functions for the CodeFlare SDK.
3+
"""
4+
5+
import os
6+
from kubernetes import config
7+
from ..kubernetes_cluster import config_check, _kube_api_error_handling
8+
9+
10+
def get_current_namespace():
11+
"""
12+
Retrieves the current Kubernetes namespace.
13+
14+
This function attempts to detect the current namespace by:
15+
1. First checking if running inside a pod (reading from service account namespace file)
16+
2. Falling back to reading from the current kubeconfig context
17+
18+
Returns:
19+
str:
20+
The current namespace or None if not found.
21+
"""
22+
if os.path.isfile("/var/run/secrets/kubernetes.io/serviceaccount/namespace"):
23+
try:
24+
file = open("/var/run/secrets/kubernetes.io/serviceaccount/namespace", "r")
25+
active_context = file.readline().strip("\n")
26+
return active_context
27+
except Exception as e:
28+
print("Unable to find current namespace")
29+
print("trying to gather from current context")
30+
try:
31+
_, active_context = config.list_kube_config_contexts(config_check())
32+
except Exception as e:
33+
return _kube_api_error_handling(e)
34+
try:
35+
return active_context["context"]["namespace"]
36+
except KeyError:
37+
return None
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# Copyright 2025 IBM, Red Hat
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""
16+
Tests for demos module.
17+
"""
18+
19+
import pytest
20+
import tempfile
21+
from pathlib import Path
22+
from unittest.mock import patch, MagicMock
23+
from codeflare_sdk.common.utils.demos import copy_demo_nbs
24+
25+
26+
class TestCopyDemoNbs:
27+
"""Test cases for copy_demo_nbs function."""
28+
29+
def test_copy_demo_nbs_directory_exists_error(self):
30+
"""Test that FileExistsError is raised when directory exists and overwrite=False."""
31+
with tempfile.TemporaryDirectory() as temp_dir:
32+
# Create a subdirectory that will conflict
33+
conflict_dir = Path(temp_dir) / "demo-notebooks"
34+
conflict_dir.mkdir()
35+
36+
with pytest.raises(FileExistsError, match="Directory.*already exists"):
37+
copy_demo_nbs(dir=str(conflict_dir), overwrite=False)
38+
39+
def test_copy_demo_nbs_overwrite_true(self):
40+
"""Test that overwrite=True allows copying to existing directory."""
41+
with tempfile.TemporaryDirectory() as temp_dir:
42+
# Create a subdirectory that will conflict
43+
conflict_dir = Path(temp_dir) / "demo-notebooks"
44+
conflict_dir.mkdir()
45+
46+
# Mock the demo_dir to point to a real directory
47+
with patch("codeflare_sdk.common.utils.demos.demo_dir", temp_dir):
48+
# Should not raise an error with overwrite=True
49+
copy_demo_nbs(dir=str(conflict_dir), overwrite=True)
50+
51+
def test_copy_demo_nbs_default_parameters(self):
52+
"""Test copy_demo_nbs with default parameters."""
53+
with tempfile.TemporaryDirectory() as temp_dir:
54+
# Mock the demo_dir to point to a real directory
55+
with patch("codeflare_sdk.common.utils.demos.demo_dir", temp_dir):
56+
# Should work with default parameters
57+
copy_demo_nbs(dir=temp_dir, overwrite=True)

0 commit comments

Comments
 (0)