diff --git a/docs/cluster/cluster.html b/docs/cluster/cluster.html index e33b9cc2f..8a313dc75 100644 --- a/docs/cluster/cluster.html +++ b/docs/cluster/cluster.html @@ -60,7 +60,9 @@
codeflare_sdk.cluster.cluster
codeflare_sdk.cluster.cluster
codeflare_sdk.cluster.cluster
codeflare_sdk.cluster.cluster
codeflare_sdk.cluster.cluster
codeflare_sdk.cluster.cluster
codeflare_sdk.cluster.cluster
codeflare_sdk.cluster.cluster
codeflare_sdk.cluster.cluster
codeflare_sdk.cluster.cluster
@@ -1678,6 +1684,8 @@ Methods
local_interactive = self.config.local_interactive
image_pull_secrets = self.config.image_pull_secrets
dispatch_priority = self.config.dispatch_priority
+ ingress_domain = self.config.ingress_domain
+ ingress_options = self.config.ingress_options
return generate_appwrapper(
name=name,
namespace=namespace,
@@ -1701,6 +1709,8 @@ Methods
dispatch_priority=dispatch_priority,
priority_val=priority_val,
openshift_oauth=self.config.openshift_oauth,
+ ingress_domain=ingress_domain,
+ ingress_options=ingress_options,
)
@@ -1858,7 +1868,7 @@ def local_client_url(self):
if self.config.local_interactive == True:
- ingress_domain = _get_ingress_domain()
- return f"ray://rayclient-{self.config.name}-{self.config.namespace}.{ingress_domain}"
+ ingress_domain = _get_ingress_domain(self)
+ return f"ray://{ingress_domain}"
else:
return "None"
diff --git a/docs/cluster/config.html b/docs/cluster/config.html
index 37242b177..f9b762baf 100644
--- a/docs/cluster/config.html
+++ b/docs/cluster/config.html
@@ -84,7 +84,9 @@ codeflare_sdk.cluster.config
class ClusterConfiguration
-(name: str, namespace: str = None, head_info: list = <factory>, head_cpus: int = 2, head_memory: int = 8, head_gpus: int = 0, machine_types: list = <factory>, min_cpus: int = 1, max_cpus: int = 1, num_workers: int = 1, min_memory: int = 2, max_memory: int = 2, num_gpus: int = 0, template: str = '/home/runner/work/codeflare-sdk/codeflare-sdk/src/codeflare_sdk/templates/base-template.yaml', instascale: bool = False, mcad: bool = True, envs: dict = <factory>, image: str = 'quay.io/project-codeflare/ray:latest-py39-cu118', local_interactive: bool = False, image_pull_secrets: list = <factory>, dispatch_priority: str = None, openshift_oauth: bool = False)
+(name: str, namespace: str = None, head_info: list = <factory>, head_cpus: int = 2, head_memory: int = 8, head_gpus: int = 0, machine_types: list = <factory>, min_cpus: int = 1, max_cpus: int = 1, num_workers: int = 1, min_memory: int = 2, max_memory: int = 2, num_gpus: int = 0, template: str = '/home/runner/work/codeflare-sdk/codeflare-sdk/src/codeflare_sdk/templates/base-template.yaml', instascale: bool = False, mcad: bool = True, envs: dict = <factory>, image: str = 'quay.io/project-codeflare/ray:latest-py39-cu118', local_interactive: bool = False, image_pull_secrets: list = <factory>, dispatch_priority: str = None, openshift_oauth: bool = False, ingress_options: dict = <factory>, ingress_domain: str = None)
This dataclass is used to specify resource requirements and other details, and @@ -134,7 +136,9 @@
var ingress_domain : str
var ingress_options : dict
var instascale : bool
head_memory
image
image_pull_secrets
ingress_domain
ingress_options
instascale
local_interactive
machine_types
codeflare_sdk.utils.generate_yaml
codeflare_sdk.utils.generate_yaml
codeflare_sdk.utils.generate_yaml
codeflare_sdk.utils.generate_yaml
codeflare_sdk.utils.generate_yaml
codeflare_sdk.utils.generate_yaml
-def enable_local_interactive(resources, cluster_name, namespace)
+def enable_local_interactive(resources, cluster_name, namespace, ingress_domain)
def enable_local_interactive(resources, cluster_name, namespace):
- rayclient_route_item = resources["resources"].get("GenericItems")[2]
+def enable_local_interactive(resources, cluster_name, namespace, ingress_domain):
+ rayclient_ingress_item = resources["resources"].get("GenericItems")[2]
ca_secret_item = resources["resources"].get("GenericItems")[3]
item = resources["resources"].get("GenericItems")[0]
- update_rayclient_route(rayclient_route_item, cluster_name, namespace)
update_ca_secret(ca_secret_item, cluster_name, namespace)
# update_ca_secret_volumes
item["generictemplate"]["spec"]["headGroupSpec"]["template"]["spec"]["volumes"][0][
@@ -688,16 +822,27 @@ Functions
][0].get("command")[2]
command = command.replace("deployment-name", cluster_name)
- try:
- config_check()
- api_client = client.CustomObjectsApi(api_config_handler())
- ingress = api_client.get_cluster_custom_object(
- "config.openshift.io", "v1", "ingresses", "cluster"
+
+ if is_openshift_cluster():
+ # We can try get the domain through checking ingresses.config.openshift.io
+ try:
+ config_check()
+ api_client = client.CustomObjectsApi(api_config_handler())
+ ingress = api_client.get_cluster_custom_object(
+ "config.openshift.io", "v1", "ingresses", "cluster"
+ )
+ except Exception as e: # pragma: no cover
+ return _kube_api_error_handling(e)
+ domain = ingress["spec"]["domain"]
+ elif ingress_domain is None:
+ raise ValueError(
+ "ingress_domain is invalid. For Kubernetes Clusters please specify an ingress domain"
)
- except Exception as e: # pragma: no cover
- return _kube_api_error_handling(e)
- domain = ingress["spec"]["domain"]
+ else:
+ domain = ingress_domain
+
command = command.replace("server-name", domain)
+ update_rayclient_ingress(rayclient_ingress_item, cluster_name, namespace, domain)
item["generictemplate"]["spec"]["headGroupSpec"]["template"]["spec"][
"initContainers"
@@ -724,7 +869,7 @@ Functions
port_name = "oauth-proxy"
host = _get_api_host(k8_client)
host = host.replace(
- "api.", f"{gen_dashboard_route_name(cluster_name)}-{namespace}.apps."
+ "api.", f"{gen_dashboard_ingress_name(cluster_name)}-{namespace}.apps."
)
oauth_sidecar = _create_oauth_sidecar_object(
namespace,
@@ -759,8 +904,8 @@ Functions
)
-def gen_dashboard_route_name(cluster_name)
+
+def gen_dashboard_ingress_name(cluster_name)
-
@@ -768,7 +913,7 @@
Functions
Expand source code
-def gen_dashboard_route_name(cluster_name):
+def gen_dashboard_ingress_name(cluster_name):
return f"ray-dashboard-{cluster_name}"
@@ -792,7 +937,7 @@ Functions
-def generate_appwrapper(name: str, namespace: str, head_cpus: int, head_memory: int, head_gpus: int, min_cpu: int, max_cpu: int, min_memory: int, max_memory: int, gpu: int, workers: int, template: str, image: str, instascale: bool, mcad: bool, instance_types: list, env, local_interactive: bool, image_pull_secrets: list, dispatch_priority: str, priority_val: int, openshift_oauth: bool)
+def generate_appwrapper(name: str, namespace: str, head_cpus: int, head_memory: int, head_gpus: int, min_cpu: int, max_cpu: int, min_memory: int, max_memory: int, gpu: int, workers: int, template: str, image: str, instascale: bool, mcad: bool, instance_types: list, env, local_interactive: bool, image_pull_secrets: list, dispatch_priority: str, priority_val: int, openshift_oauth: bool, ingress_domain: str, ingress_options: dict)
-
@@ -823,12 +968,14 @@
Functions
dispatch_priority: str,
priority_val: int,
openshift_oauth: bool,
+ ingress_domain: str,
+ ingress_options: dict,
):
user_yaml = read_template(template)
appwrapper_name, cluster_name = gen_names(name)
resources = user_yaml.get("spec", "resources")
item = resources["resources"].get("GenericItems")[0]
- route_item = resources["resources"].get("GenericItems")[1]
+ ingress_item = resources["resources"].get("GenericItems")[1]
update_names(user_yaml, item, appwrapper_name, cluster_name, namespace)
update_labels(user_yaml, instascale, instance_types)
update_priority(user_yaml, item, dispatch_priority, priority_val)
@@ -861,9 +1008,11 @@ Functions
head_memory,
head_gpus,
)
- update_dashboard_route(route_item, cluster_name, namespace)
+ update_dashboard_ingress(
+ ingress_item, cluster_name, namespace, ingress_options, ingress_domain
+ )
if local_interactive:
- enable_local_interactive(resources, cluster_name, namespace)
+ enable_local_interactive(resources, cluster_name, namespace, ingress_domain)
else:
disable_raycluster_tls(resources["resources"])
@@ -878,6 +1027,32 @@ Functions
return outfile
+
+def is_openshift_cluster()
+
def is_openshift_cluster():
+ try:
+ config_check()
+ api_instance = client.CustomObjectsApi(api_config_handler())
+ api_instance.get_cluster_custom_object(
+ "config.openshift.io", "v1", "ingresses", "cluster"
+ )
+
+ return True
+ except client.ApiException as e: # pragma: no cover
+ if e.status == 404 or e.status == 403:
+ return False
+ else:
+ print(f"Error detecting cluster type defaulting to Kubernetes: {e}")
+ return False
+
def read_template(template)
-def update_dashboard_route(route_item, cluster_name, namespace)
+
+def update_dashboard_ingress(ingress_item, cluster_name, namespace, ingress_options, ingress_domain)
-
@@ -1006,13 +1181,79 @@
Functions
Expand source code
-def update_dashboard_route(route_item, cluster_name, namespace):
- metadata = route_item.get("generictemplate", {}).get("metadata")
- metadata["name"] = gen_dashboard_route_name(cluster_name)
- metadata["namespace"] = namespace
- metadata["labels"]["odh-ray-cluster-service"] = f"{cluster_name}-head-svc"
- spec = route_item.get("generictemplate", {}).get("spec")
- spec["to"]["name"] = f"{cluster_name}-head-svc"
+def update_dashboard_ingress(
+ ingress_item, cluster_name, namespace, ingress_options, ingress_domain
+): # pragma: no cover
+ metadata = ingress_item.get("generictemplate", {}).get("metadata")
+ spec = ingress_item.get("generictemplate", {}).get("spec")
+ if ingress_options != {}:
+ for index, ingress_option in enumerate(ingress_options["ingresses"]):
+ if "ingressName" not in ingress_option.keys():
+ raise ValueError(
+ f"Error: 'ingressName' is missing or empty for ingress item at index {index}"
+ )
+ if "port" not in ingress_option.keys():
+ raise ValueError(
+ f"Error: 'port' is missing or empty for ingress item at index {index}"
+ )
+ elif not isinstance(ingress_option["port"], int):
+ raise ValueError(
+ f"Error: 'port' is not of type int for ingress item at index {index}"
+ )
+ if ingress_option["port"] == 8265:
+ metadata["name"] = ingress_option["ingressName"]
+ metadata["namespace"] = namespace
+ if "annotations" not in ingress_option.keys():
+ del metadata["annotations"]
+ else:
+ metadata["annotations"] = ingress_option["annotations"]
+ if "path" not in ingress_option.keys():
+ del spec["rules"][0]["http"]["paths"][0]["path"]
+ else:
+ spec["rules"][0]["http"]["paths"][0]["path"] = ingress_option[
+ "path"
+ ]
+ if "pathType" not in ingress_option.keys():
+ spec["rules"][0]["http"]["paths"][0][
+ "pathType"
+ ] = "ImplementationSpecific"
+ if "host" not in ingress_option.keys():
+ del spec["rules"][0]["host"]
+ else:
+ spec["rules"][0]["host"] = ingress_option["host"]
+ if "ingressClassName" not in ingress_option.keys():
+ del spec["ingressClassName"]
+ else:
+ spec["ingressClassName"] = ingress_option["ingressClassName"]
+
+ spec["rules"][0]["http"]["paths"][0]["backend"]["service"][
+ "name"
+ ] = f"{cluster_name}-head-svc"
+ else:
+ metadata["name"] = f"ray-dashboard-{cluster_name}"
+ metadata["namespace"] = namespace
+ spec["rules"][0]["http"]["paths"][0]["backend"]["service"][
+ "name"
+ ] = f"{cluster_name}-head-svc"
+ if is_openshift_cluster():
+ try:
+ config_check()
+ api_client = client.CustomObjectsApi(api_config_handler())
+ ingress = api_client.get_cluster_custom_object(
+ "config.openshift.io", "v1", "ingresses", "cluster"
+ )
+ del spec["ingressClassName"]
+ except Exception as e: # pragma: no cover
+ return _kube_api_error_handling(e)
+ domain = ingress["spec"]["domain"]
+ elif ingress_domain is None:
+ raise ValueError(
+ "ingress_domain is invalid. For Kubernetes Clusters please specify an ingress domain"
+ )
+ else:
+ domain = ingress_domain
+ del metadata["annotations"]
+ spec["rules"][0]["host"] = f"ray-dashboard-{cluster_name}-{namespace}.{domain}"
@@ -1188,8 +1429,8 @@ Functions
spec.pop("priority")
-
-def update_rayclient_route(route_item, cluster_name, namespace)
+
+def update_rayclient_ingress(ingress_item, cluster_name, namespace, ingress_domain)
-
@@ -1197,13 +1438,51 @@
Functions
Expand source code
-def update_rayclient_route(route_item, cluster_name, namespace):
- metadata = route_item.get("generictemplate", {}).get("metadata")
+def update_rayclient_ingress(
+ ingress_item, cluster_name, namespace, ingress_domain
+): # pragma: no cover
+ metadata = ingress_item.get("generictemplate", {}).get("metadata")
+ spec = ingress_item.get("generictemplate", {}).get("spec")
metadata["name"] = f"rayclient-{cluster_name}"
metadata["namespace"] = namespace
metadata["labels"]["odh-ray-cluster-service"] = f"{cluster_name}-head-svc"
- spec = route_item.get("generictemplate", {}).get("spec")
- spec["to"]["name"] = f"{cluster_name}-head-svc"
+
+ spec["rules"][0]["http"]["paths"][0]["backend"]["service"][
+ "name"
+ ] = f"{cluster_name}-head-svc"
+
+ if is_openshift_cluster():
+ try:
+ config_check()
+ api_client = client.CustomObjectsApi(api_config_handler())
+ ingress = api_client.get_cluster_custom_object(
+ "config.openshift.io", "v1", "ingresses", "cluster"
+ )
+ ingressClassName = "openshift-default"
+ annotations = {
+ "nginx.ingress.kubernetes.io/rewrite-target": "/",
+ "nginx.ingress.kubernetes.io/ssl-redirect": "true",
+ "route.openshift.io/termination": "passthrough",
+ }
+ except Exception as e: # pragma: no cover
+ return _kube_api_error_handling(e)
+ domain = ingress["spec"]["domain"]
+ elif ingress_domain is None:
+ raise ValueError(
+ "ingress_domain is invalid. For Kubernetes Clusters please specify an ingress domain"
+ )
+ else:
+ domain = ingress_domain
+ ingressClassName = "nginx"
+ annotations = {
+ "nginx.ingress.kubernetes.io/rewrite-target": "/",
+ "nginx.ingress.kubernetes.io/ssl-redirect": "true",
+ "nginx.ingress.kubernetes.io/ssl-passthrough": "true",
+ }
+
+ metadata["annotations"] = annotations
+ spec["ingressClassName"] = ingressClassName
+ spec["rules"][0]["host"] = f"rayclient-{cluster_name}-{namespace}.{domain}"
@@ -1288,14 +1567,15 @@ Index
disable_raycluster_tls
enable_local_interactive
enable_openshift_oauth
-gen_dashboard_route_name
+gen_dashboard_ingress_name
gen_names
generate_appwrapper
+is_openshift_cluster
read_template
update_affinity
update_ca_secret
update_custompodresources
-update_dashboard_route
+update_dashboard_ingress
update_env
update_image
update_image_pull_secrets
@@ -1303,7 +1583,7 @@ Index
update_names
update_nodes
update_priority
-update_rayclient_route
+update_rayclient_ingress
update_resources
write_components
write_user_appwrapper
diff --git a/docs/utils/openshift_oauth.html b/docs/utils/openshift_oauth.html
index 0fc27b6b2..e8df74823 100644
--- a/docs/utils/openshift_oauth.html
+++ b/docs/utils/openshift_oauth.html
@@ -27,7 +27,7 @@ Module codeflare_sdk.utils.openshift_oauth
Expand source code
from urllib3.util import parse_url
-from .generate_yaml import gen_dashboard_route_name
+from .generate_yaml import gen_dashboard_ingress_name
from .kube_api_helpers import _get_api_host
from base64 import b64decode
@@ -47,7 +47,7 @@ Module codeflare_sdk.utils.openshift_oauth
host = _get_api_host(api_client)
# replace "^api" with the expected host
- host = f"{gen_dashboard_route_name(cluster_name)}-{namespace}.apps" + host.lstrip(
+ host = f"{gen_dashboard_ingress_name(cluster_name)}-{namespace}.apps" + host.lstrip(
"api"
)
@@ -272,7 +272,7 @@ Functions
host = _get_api_host(api_client)
# replace "^api" with the expected host
- host = f"{gen_dashboard_route_name(cluster_name)}-{namespace}.apps" + host.lstrip(
+ host = f"{gen_dashboard_ingress_name(cluster_name)}-{namespace}.apps" + host.lstrip(
"api"
)