Skip to content

Commit 6d8b730

Browse files
committed
feat(RHOAIENG-29330):Deny RayCluster creation with Ray Version mismatches fixed
1 parent dc47dc9 commit 6d8b730

File tree

6 files changed

+383
-3
lines changed

6 files changed

+383
-3
lines changed

src/codeflare_sdk/common/utils/test_validation.py

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1+
<<<<<<< HEAD
12
# Copyright 2024 IBM, Red Hat
3+
=======
4+
# Copyright 2022-2025 IBM, Red Hat
5+
>>>>>>> 7327753 (feat(RHOAIENG-29330):Deny RayCluster creation with Ray Version mismatches fixed)
26
#
37
# Licensed under the Apache License, Version 2.0 (the "License");
48
# you may not use this file except in compliance with the License.
@@ -12,7 +16,10 @@
1216
# See the License for the specific language governing permissions and
1317
# limitations under the License.
1418

19+
<<<<<<< HEAD
1520
import pytest
21+
=======
22+
>>>>>>> 7327753 (feat(RHOAIENG-29330):Deny RayCluster creation with Ray Version mismatches fixed)
1623
from codeflare_sdk.common.utils.validation import (
1724
extract_ray_version_from_image,
1825
validate_ray_version_compatibility,
@@ -105,6 +112,7 @@ class TestRayVersionValidation:
105112
def test_validate_compatible_versions(self):
106113
"""Test validation with compatible Ray versions."""
107114
# Exact match
115+
<<<<<<< HEAD
108116
is_compatible, message = validate_ray_version_compatibility(
109117
f"ray:{RAY_VERSION}"
110118
)
@@ -116,37 +124,81 @@ def test_validate_compatible_versions(self):
116124
f"quay.io/modh/ray:{RAY_VERSION}-py311-cu121"
117125
)
118126
assert is_compatible is True
127+
=======
128+
is_compatible, is_warning, message = validate_ray_version_compatibility(
129+
f"ray:{RAY_VERSION}"
130+
)
131+
assert is_compatible is True
132+
assert is_warning is False
133+
assert "Ray versions match" in message
134+
135+
# With registry and suffixes
136+
is_compatible, is_warning, message = validate_ray_version_compatibility(
137+
f"quay.io/modh/ray:{RAY_VERSION}-py311-cu121"
138+
)
139+
assert is_compatible is True
140+
assert is_warning is False
141+
>>>>>>> 7327753 (feat(RHOAIENG-29330):Deny RayCluster creation with Ray Version mismatches fixed)
119142
assert "Ray versions match" in message
120143

121144
def test_validate_incompatible_versions(self):
122145
"""Test validation with incompatible Ray versions."""
123146
# Different version
147+
<<<<<<< HEAD
124148
is_compatible, message = validate_ray_version_compatibility("ray:2.46.0")
125149
assert is_compatible is False
150+
=======
151+
is_compatible, is_warning, message = validate_ray_version_compatibility(
152+
"ray:2.46.0"
153+
)
154+
assert is_compatible is False
155+
assert is_warning is False
156+
>>>>>>> 7327753 (feat(RHOAIENG-29330):Deny RayCluster creation with Ray Version mismatches fixed)
126157
assert "Ray version mismatch detected" in message
127158
assert "CodeFlare SDK uses Ray" in message
128159
assert "runtime image uses Ray" in message
129160

130161
# Older version
162+
<<<<<<< HEAD
131163
is_compatible, message = validate_ray_version_compatibility("ray:1.13.0")
132164
assert is_compatible is False
165+
=======
166+
is_compatible, is_warning, message = validate_ray_version_compatibility(
167+
"ray:1.13.0"
168+
)
169+
assert is_compatible is False
170+
assert is_warning is False
171+
>>>>>>> 7327753 (feat(RHOAIENG-29330):Deny RayCluster creation with Ray Version mismatches fixed)
133172
assert "Ray version mismatch detected" in message
134173

135174
def test_validate_empty_image(self):
136175
"""Test validation with no custom image (should use default)."""
137176
# Empty string
177+
<<<<<<< HEAD
138178
is_compatible, message = validate_ray_version_compatibility("")
139179
assert is_compatible is True
140180
assert "Using default Ray image compatible with SDK" in message
141181

142182
# None
143183
is_compatible, message = validate_ray_version_compatibility(None)
144184
assert is_compatible is True
185+
=======
186+
is_compatible, is_warning, message = validate_ray_version_compatibility("")
187+
assert is_compatible is True
188+
assert is_warning is False
189+
assert "Using default Ray image compatible with SDK" in message
190+
191+
# None
192+
is_compatible, is_warning, message = validate_ray_version_compatibility(None)
193+
assert is_compatible is True
194+
assert is_warning is False
195+
>>>>>>> 7327753 (feat(RHOAIENG-29330):Deny RayCluster creation with Ray Version mismatches fixed)
145196
assert "Using default Ray image compatible with SDK" in message
146197

147198
def test_validate_unknown_version(self):
148199
"""Test validation when version cannot be determined."""
149200
# SHA-based image
201+
<<<<<<< HEAD
150202
is_compatible, message = validate_ray_version_compatibility(
151203
"quay.io/modh/ray@sha256:6d076aeb38ab3c34a6a2ef0f58dc667089aa15826fa08a73273c629333e12f1e"
152204
)
@@ -159,10 +211,27 @@ def test_validate_unknown_version(self):
159211
)
160212
assert is_compatible is True
161213
assert "Warning: Cannot determine Ray version" in message
214+
=======
215+
is_compatible, is_warning, message = validate_ray_version_compatibility(
216+
"quay.io/modh/ray@sha256:6d076aeb38ab3c34a6a2ef0f58dc667089aa15826fa08a73273c629333e12f1e"
217+
)
218+
assert is_compatible is True
219+
assert is_warning is True
220+
assert "Cannot determine Ray version" in message
221+
222+
# Custom image without version
223+
is_compatible, is_warning, message = validate_ray_version_compatibility(
224+
"my-custom-ray:latest"
225+
)
226+
assert is_compatible is True
227+
assert is_warning is True
228+
assert "Cannot determine Ray version" in message
229+
>>>>>>> 7327753 (feat(RHOAIENG-29330):Deny RayCluster creation with Ray Version mismatches fixed)
162230

163231
def test_validate_custom_sdk_version(self):
164232
"""Test validation with custom SDK version."""
165233
# Compatible with custom SDK version
234+
<<<<<<< HEAD
166235
is_compatible, message = validate_ray_version_compatibility(
167236
"ray:2.46.0", "2.46.0"
168237
)
@@ -174,15 +243,61 @@ def test_validate_custom_sdk_version(self):
174243
"ray:2.47.1", "2.46.0"
175244
)
176245
assert is_compatible is False
246+
=======
247+
is_compatible, is_warning, message = validate_ray_version_compatibility(
248+
"ray:2.46.0", "2.46.0"
249+
)
250+
assert is_compatible is True
251+
assert is_warning is False
252+
assert "Ray versions match" in message
253+
254+
# Incompatible with custom SDK version
255+
is_compatible, is_warning, message = validate_ray_version_compatibility(
256+
"ray:2.47.1", "2.46.0"
257+
)
258+
assert is_compatible is False
259+
assert is_warning is False
260+
>>>>>>> 7327753 (feat(RHOAIENG-29330):Deny RayCluster creation with Ray Version mismatches fixed)
177261
assert "CodeFlare SDK uses Ray 2.46.0" in message
178262
assert "runtime image uses Ray 2.47.1" in message
179263

180264
def test_validate_message_content(self):
181265
"""Test that validation messages contain expected guidance."""
182266
# Mismatch message should contain helpful guidance
267+
<<<<<<< HEAD
183268
is_compatible, message = validate_ray_version_compatibility("ray:2.46.0")
184269
assert is_compatible is False
270+
=======
271+
is_compatible, is_warning, message = validate_ray_version_compatibility(
272+
"ray:2.46.0"
273+
)
274+
assert is_compatible is False
275+
assert is_warning is False
276+
>>>>>>> 7327753 (feat(RHOAIENG-29330):Deny RayCluster creation with Ray Version mismatches fixed)
185277
assert "compatibility issues" in message.lower()
186278
assert "unexpected behavior" in message.lower()
187279
assert "please use a runtime image" in message.lower()
188280
assert "update your sdk version" in message.lower()
281+
<<<<<<< HEAD
282+
=======
283+
284+
def test_semantic_version_comparison(self):
285+
"""Test that semantic version comparison works correctly."""
286+
# Test that 2.10.0 > 2.9.1 (would fail with string comparison)
287+
is_compatible, is_warning, message = validate_ray_version_compatibility(
288+
"ray:2.10.0", "2.9.1"
289+
)
290+
assert is_compatible is False
291+
assert is_warning is False
292+
assert "CodeFlare SDK uses Ray 2.9.1" in message
293+
assert "runtime image uses Ray 2.10.0" in message
294+
295+
# Test that 2.9.1 < 2.10.0 (would fail with string comparison)
296+
is_compatible, is_warning, message = validate_ray_version_compatibility(
297+
"ray:2.9.1", "2.10.0"
298+
)
299+
assert is_compatible is False
300+
assert is_warning is False
301+
assert "CodeFlare SDK uses Ray 2.10.0" in message
302+
assert "runtime image uses Ray 2.9.1" in message
303+
>>>>>>> 7327753 (feat(RHOAIENG-29330):Deny RayCluster creation with Ray Version mismatches fixed)

src/codeflare_sdk/common/utils/validation.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1+
<<<<<<< HEAD
12
# Copyright 2024 IBM, Red Hat
3+
=======
4+
# Copyright 2022-2025 IBM, Red Hat
5+
>>>>>>> 7327753 (feat(RHOAIENG-29330):Deny RayCluster creation with Ray Version mismatches fixed)
26
#
37
# Licensed under the Apache License, Version 2.0 (the "License");
48
# you may not use this file except in compliance with the License.
@@ -19,10 +23,21 @@
1923
configuration compatibility and correctness.
2024
"""
2125

26+
<<<<<<< HEAD
2227
import re
2328
from typing import Optional, Tuple
2429
from .constants import RAY_VERSION
2530

31+
=======
32+
import logging
33+
import re
34+
from typing import Optional, Tuple
35+
from packaging.version import Version, InvalidVersion
36+
from .constants import RAY_VERSION
37+
38+
logger = logging.getLogger(__name__)
39+
40+
>>>>>>> 7327753 (feat(RHOAIENG-29330):Deny RayCluster creation with Ray Version mismatches fixed)
2641

2742
def extract_ray_version_from_image(image_name: str) -> Optional[str]:
2843
"""
@@ -62,7 +77,11 @@ def extract_ray_version_from_image(image_name: str) -> Optional[str]:
6277

6378
def validate_ray_version_compatibility(
6479
image_name: str, sdk_ray_version: str = RAY_VERSION
80+
<<<<<<< HEAD
6581
) -> Tuple[bool, str]:
82+
=======
83+
) -> Tuple[bool, bool, str]:
84+
>>>>>>> 7327753 (feat(RHOAIENG-29330):Deny RayCluster creation with Ray Version mismatches fixed)
6685
"""
6786
Validate that the Ray version in the runtime image matches the SDK's Ray version.
6887
@@ -71,20 +90,32 @@ def validate_ray_version_compatibility(
7190
sdk_ray_version: The Ray version used by the CodeFlare SDK
7291
7392
Returns:
93+
<<<<<<< HEAD
7494
tuple: (is_compatible, message)
7595
- is_compatible: True if versions match or cannot be determined, False if mismatch
96+
=======
97+
tuple: (is_compatible, is_warning, message)
98+
- is_compatible: True if versions match or cannot be determined, False if mismatch
99+
- is_warning: True if this is a warning (non-fatal), False otherwise
100+
>>>>>>> 7327753 (feat(RHOAIENG-29330):Deny RayCluster creation with Ray Version mismatches fixed)
76101
- message: Descriptive message about the validation result
77102
"""
78103
if not image_name:
79104
# No custom image specified, will use default - this is compatible
105+
<<<<<<< HEAD
80106
return True, "Using default Ray image compatible with SDK"
107+
=======
108+
logger.debug("Using default Ray image compatible with SDK")
109+
return True, False, "Using default Ray image compatible with SDK"
110+
>>>>>>> 7327753 (feat(RHOAIENG-29330):Deny RayCluster creation with Ray Version mismatches fixed)
81111

82112
image_ray_version = extract_ray_version_from_image(image_name)
83113

84114
if image_ray_version is None:
85115
# Cannot determine version from image name, issue a warning but allow
86116
return (
87117
True,
118+
<<<<<<< HEAD
88119
f"Warning: Cannot determine Ray version from image '{image_name}'. Please ensure it's compatible with Ray {sdk_ray_version}",
89120
)
90121

@@ -101,5 +132,46 @@ def validate_ray_version_compatibility(
101132
# Versions match
102133
return (
103134
True,
135+
=======
136+
True,
137+
f"Cannot determine Ray version from image '{image_name}'. Please ensure it's compatible with Ray {sdk_ray_version}",
138+
)
139+
140+
# Use semantic version comparison for robust version checking
141+
try:
142+
sdk_version = Version(sdk_ray_version)
143+
image_version = Version(image_ray_version)
144+
145+
if image_version != sdk_version:
146+
# Version mismatch detected
147+
message = (
148+
f"Ray version mismatch detected!\n"
149+
f"CodeFlare SDK uses Ray {sdk_ray_version}, but runtime image uses Ray {image_ray_version}.\n"
150+
f"This mismatch can cause compatibility issues and unexpected behavior.\n"
151+
f"Please use a runtime image with Ray {sdk_ray_version} or update your SDK version."
152+
)
153+
return False, False, message
154+
except InvalidVersion as e:
155+
# If version parsing fails, fall back to string comparison with a warning
156+
logger.warning(
157+
f"Failed to parse version for comparison ({e}), falling back to string comparison"
158+
)
159+
if image_ray_version != sdk_ray_version:
160+
message = (
161+
f"Ray version mismatch detected!\n"
162+
f"CodeFlare SDK uses Ray {sdk_ray_version}, but runtime image uses Ray {image_ray_version}.\n"
163+
f"This mismatch can cause compatibility issues and unexpected behavior.\n"
164+
f"Please use a runtime image with Ray {sdk_ray_version} or update your SDK version."
165+
)
166+
return False, False, message
167+
168+
# Versions match
169+
logger.debug(
170+
f"Ray version validation successful: SDK and runtime image both use Ray {sdk_ray_version}"
171+
)
172+
return (
173+
True,
174+
False,
175+
>>>>>>> 7327753 (feat(RHOAIENG-29330):Deny RayCluster creation with Ray Version mismatches fixed)
104176
f"Ray versions match: SDK and runtime image both use Ray {sdk_ray_version}",
105177
)

src/codeflare_sdk/ray/cluster/config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from kubernetes.client import V1Toleration, V1Volume, V1VolumeMount
2626
from ...common.utils.validation import validate_ray_version_compatibility
2727

28+
2829
dir = pathlib.Path(__file__).parent.parent.resolve()
2930

3031
# https://docs.ray.io/en/latest/ray-core/scheduling/accelerators.html

src/codeflare_sdk/ray/cluster/test_config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2024 IBM, Red Hat
1+
# Copyright 2022-2025 IBM, Red Hat
22
#
33
# Licensed under the Apache License, Version 2.0 (the "License");
44
# you may not use this file except in compliance with the License.

0 commit comments

Comments
 (0)