Skip to content

Commit e262bbd

Browse files
committed
feat(RHOAIENG-29391): Store entrypoint scripts in configMaps
Signed-off-by: Pat O'Connor <[email protected]>
1 parent 5a77f7b commit e262bbd

File tree

6 files changed

+1082
-1
lines changed

6 files changed

+1082
-1
lines changed

helper.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
"""
2+
Helper script for testing multiple script mounting in RayJobs
3+
"""
4+
import ray
5+
from datetime import datetime
6+
7+
8+
def get_cluster_info():
9+
"""Get information about the Ray cluster"""
10+
try:
11+
cluster_info = {
12+
"ray_version": ray.__version__,
13+
"cluster_resources": ray.cluster_resources(),
14+
"available_resources": ray.available_resources(),
15+
"nodes": len(ray.nodes()),
16+
"timestamp": datetime.now().isoformat(),
17+
}
18+
return cluster_info
19+
except Exception as e:
20+
return {"error": str(e), "timestamp": datetime.now().isoformat()}
21+
22+
23+
def run_simple_ray_task():
24+
"""Run a simple Ray task to test cluster functionality"""
25+
26+
@ray.remote
27+
def hello_task(name):
28+
import time
29+
30+
time.sleep(1) # Simulate some work
31+
return f"Hello {name} from Ray worker!"
32+
33+
# Submit multiple tasks
34+
tasks = [hello_task.remote(f"Task-{i}") for i in range(3)]
35+
results = ray.get(tasks)
36+
37+
return results
38+
39+
40+
def print_mounted_files():
41+
"""Check what files are available in the scripts directory"""
42+
import os
43+
44+
script_dir = "/home/ray/scripts"
45+
46+
print(f"📁 Contents of {script_dir}:")
47+
try:
48+
if os.path.exists(script_dir):
49+
files = os.listdir(script_dir)
50+
for file in sorted(files):
51+
file_path = os.path.join(script_dir, file)
52+
if os.path.isfile(file_path):
53+
size = os.path.getsize(file_path)
54+
print(f" 📄 {file} ({size} bytes)")
55+
else:
56+
print(f" ❌ Directory {script_dir} does not exist")
57+
except Exception as e:
58+
print(f" ❌ Error listing files: {e}")

src/codeflare_sdk/ray/rayjobs/config.py

Lines changed: 86 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121
import pathlib
2222
from dataclasses import dataclass, field, fields
23-
from typing import Dict, List, Optional, Union, get_args, get_origin, Any
23+
from typing import Dict, List, Optional, Union, get_args, get_origin, Any, Tuple
2424
from kubernetes.client import (
2525
V1ConfigMapVolumeSource,
2626
V1KeyToPath,
@@ -515,3 +515,88 @@ def _build_gcs_ft_options(self) -> Dict[str, Any]:
515515
}
516516

517517
return gcs_ft_options
518+
519+
def add_script_volumes(
520+
self, configmap_name: str, mount_path: str = "/home/ray/scripts"
521+
):
522+
"""
523+
Add script volume and mount references to cluster configuration.
524+
525+
Args:
526+
configmap_name: Name of the ConfigMap containing scripts
527+
mount_path: Where to mount scripts in containers (default: /home/ray/scripts)
528+
"""
529+
# Check if script volume already exists
530+
volume_name = "ray-job-scripts"
531+
existing_volume = next(
532+
(v for v in self.volumes if getattr(v, "name", None) == volume_name), None
533+
)
534+
if existing_volume:
535+
logger.debug(f"Script volume '{volume_name}' already exists, skipping...")
536+
return
537+
538+
# Check if script mount already exists
539+
existing_mount = next(
540+
(m for m in self.volume_mounts if getattr(m, "name", None) == volume_name),
541+
None,
542+
)
543+
if existing_mount:
544+
logger.debug(
545+
f"Script volume mount '{volume_name}' already exists, skipping..."
546+
)
547+
return
548+
549+
# Add script volume to cluster configuration
550+
script_volume = V1Volume(
551+
name=volume_name, config_map=V1ConfigMapVolumeSource(name=configmap_name)
552+
)
553+
self.volumes.append(script_volume)
554+
555+
# Add script volume mount to cluster configuration
556+
script_mount = V1VolumeMount(name=volume_name, mount_path=mount_path)
557+
self.volume_mounts.append(script_mount)
558+
559+
logger.info(
560+
f"Added script volume '{configmap_name}' to cluster config: mount_path={mount_path}"
561+
)
562+
563+
def build_script_configmap_spec(
564+
self, job_name: str, namespace: str, scripts: Dict[str, str]
565+
) -> Dict[str, Any]:
566+
"""
567+
Build ConfigMap specification for scripts (no API calls).
568+
569+
Args:
570+
job_name: Name of the RayJob (used for ConfigMap naming)
571+
namespace: Kubernetes namespace
572+
scripts: Dictionary of script_name -> script_content
573+
574+
Returns:
575+
Dict: ConfigMap specification ready for Kubernetes API
576+
"""
577+
configmap_name = f"{job_name}-scripts"
578+
return {
579+
"apiVersion": "v1",
580+
"kind": "ConfigMap",
581+
"metadata": {"name": configmap_name, "namespace": namespace},
582+
"data": scripts,
583+
}
584+
585+
def build_script_volume_specs(
586+
self, configmap_name: str, mount_path: str = "/home/ray/scripts"
587+
) -> Tuple[Dict[str, Any], Dict[str, Any]]:
588+
"""
589+
Build volume and mount specifications for scripts (no API calls).
590+
591+
Args:
592+
configmap_name: Name of the ConfigMap containing scripts
593+
mount_path: Where to mount scripts in containers
594+
595+
Returns:
596+
Tuple of (volume_spec, mount_spec) as dictionaries
597+
"""
598+
volume_spec = {"name": "ray-job-scripts", "configMap": {"name": configmap_name}}
599+
600+
mount_spec = {"name": "ray-job-scripts", "mountPath": mount_path}
601+
602+
return volume_spec, mount_spec

0 commit comments

Comments
 (0)