Skip to content

Commit bb34548

Browse files
Bobbins228astefanutti
authored andcommitted
Changed behaviour to create routes instead of ingresses on OpenShift
1 parent ff10371 commit bb34548

File tree

6 files changed

+265
-182
lines changed

6 files changed

+265
-182
lines changed

src/codeflare_sdk/cluster/cluster.py

Lines changed: 98 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
generate_appwrapper,
3333
)
3434
from ..utils.kube_api_helpers import _kube_api_error_handling
35+
from ..utils.generate_yaml import is_openshift_cluster
3536
from ..utils.openshift_oauth import (
3637
create_openshift_oauth_objects,
3738
delete_openshift_oauth_objects,
@@ -189,7 +190,7 @@ def create_app_wrapper(self):
189190
local_interactive = self.config.local_interactive
190191
image_pull_secrets = self.config.image_pull_secrets
191192
dispatch_priority = self.config.dispatch_priority
192-
domain_name = self.config.domain_name
193+
ingress_domain = self.config.ingress_domain
193194
ingress_options = self.config.ingress_options
194195
return generate_appwrapper(
195196
name=name,
@@ -214,7 +215,7 @@ def create_app_wrapper(self):
214215
dispatch_priority=dispatch_priority,
215216
priority_val=priority_val,
216217
openshift_oauth=self.config.openshift_oauth,
217-
domain_name=domain_name,
218+
ingress_domain=ingress_domain,
218219
ingress_options=ingress_options,
219220
)
220221

@@ -415,25 +416,48 @@ def cluster_dashboard_uri(self) -> str:
415416
"""
416417
Returns a string containing the cluster's dashboard URI.
417418
"""
418-
try:
419-
config_check()
420-
api_instance = client.NetworkingV1Api(api_config_handler())
421-
ingresses = api_instance.list_namespaced_ingress(self.config.namespace)
422-
except Exception as e: # pragma no cover
423-
return _kube_api_error_handling(e)
419+
config_check()
420+
if is_openshift_cluster():
421+
try:
422+
api_instance = client.CustomObjectsApi(api_config_handler())
423+
routes = api_instance.list_namespaced_custom_object(
424+
group="route.openshift.io",
425+
version="v1",
426+
namespace=self.config.namespace,
427+
plural="routes",
428+
)
429+
except Exception as e: # pragma: no cover
430+
return _kube_api_error_handling(e)
431+
432+
for route in routes["items"]:
433+
if route["metadata"][
434+
"name"
435+
] == f"ray-dashboard-{self.config.name}" or route["metadata"][
436+
"name"
437+
].startswith(
438+
f"{self.config.name}-ingress"
439+
):
440+
protocol = "https" if route["spec"].get("tls") else "http"
441+
return f"{protocol}://{route['spec']['host']}"
442+
else:
443+
try:
444+
api_instance = client.NetworkingV1Api(api_config_handler())
445+
ingresses = api_instance.list_namespaced_ingress(self.config.namespace)
446+
except Exception as e: # pragma no cover
447+
return _kube_api_error_handling(e)
424448

425-
for ingress in ingresses.items:
426-
annotations = ingress.metadata.annotations
427-
protocol = "http"
428-
if (
429-
ingress.metadata.name == f"ray-dashboard-{self.config.name}"
430-
or ingress.metadata.name.startswith(f"{self.config.name}-ingress")
431-
):
432-
if annotations == None:
433-
protocol = "http"
434-
elif "route.openshift.io/termination" in annotations:
435-
protocol = "https"
436-
return f"{protocol}://{ingress.spec.rules[0].host}"
449+
for ingress in ingresses.items:
450+
annotations = ingress.metadata.annotations
451+
protocol = "http"
452+
if (
453+
ingress.metadata.name == f"ray-dashboard-{self.config.name}"
454+
or ingress.metadata.name.startswith(f"{self.config.name}-ingress")
455+
):
456+
if annotations == None:
457+
protocol = "http"
458+
elif "route.openshift.io/termination" in annotations:
459+
protocol = "https"
460+
return f"{protocol}://{ingress.spec.rules[0].host}"
437461
return "Dashboard ingress not available yet, have you run cluster.up()?"
438462

439463
def list_jobs(self) -> List:
@@ -468,7 +492,7 @@ def torchx_config(
468492
to_return["requirements"] = requirements
469493
return to_return
470494

471-
def from_k8_cluster_object(rc, mcad=True, domain_name=None):
495+
def from_k8_cluster_object(rc, mcad=True, ingress_domain=None):
472496
machine_types = (
473497
rc["metadata"]["labels"]["orderedinstance"].split("_")
474498
if "orderedinstance" in rc["metadata"]["labels"]
@@ -508,7 +532,7 @@ def from_k8_cluster_object(rc, mcad=True, domain_name=None):
508532
]["image"],
509533
local_interactive=local_interactive,
510534
mcad=mcad,
511-
domain_name=domain_name,
535+
ingress_domain=ingress_domain,
512536
)
513537
return Cluster(cluster_config)
514538

@@ -533,6 +557,14 @@ def _component_resources_up(
533557
plural="rayclusters",
534558
body=resource,
535559
)
560+
elif resource["kind"] == "Ingress":
561+
api_instance.create_namespaced_custom_object(
562+
group="networking.k8s.io",
563+
version="v1",
564+
namespace=namespace,
565+
plural="ingresses",
566+
body=resource,
567+
)
536568
elif resource["kind"] == "Route":
537569
api_instance.create_namespaced_custom_object(
538570
group="route.openshift.io",
@@ -562,6 +594,15 @@ def _component_resources_down(
562594
plural="rayclusters",
563595
name=self.app_wrapper_name,
564596
)
597+
elif resource["kind"] == "Ingress":
598+
name = resource["metadata"]["name"]
599+
api_instance.delete_namespaced_custom_object(
600+
group="networking.k8s.io",
601+
version="v1",
602+
namespace=namespace,
603+
plural="ingresses",
604+
name=name,
605+
)
565606
elif resource["kind"] == "Route":
566607
name = resource["metadata"]["name"]
567608
api_instance.delete_namespaced_custom_object(
@@ -629,7 +670,7 @@ def get_current_namespace(): # pragma: no cover
629670
return None
630671

631672

632-
def get_cluster(cluster_name: str, namespace: str = "default"):
673+
def get_cluster(cluster_name: str, namespace: str = "default", ingress_domain=None):
633674
try:
634675
config_check()
635676
api_instance = client.CustomObjectsApi(api_config_handler())
@@ -645,9 +686,8 @@ def get_cluster(cluster_name: str, namespace: str = "default"):
645686
for rc in rcs["items"]:
646687
if rc["metadata"]["name"] == cluster_name:
647688
mcad = _check_aw_exists(cluster_name, namespace)
648-
domain_name = _extract_domain_name(cluster_name, namespace)
649689
return Cluster.from_k8_cluster_object(
650-
rc, mcad=mcad, domain_name=domain_name
690+
rc, mcad=mcad, ingress_domain=ingress_domain
651691
)
652692
raise FileNotFoundError(
653693
f"Cluster {cluster_name} is not found in {namespace} namespace"
@@ -673,49 +713,42 @@ def _check_aw_exists(name: str, namespace: str) -> bool:
673713
return False
674714

675715

676-
def _extract_domain_name(name: str, namespace: str) -> str:
677-
try:
678-
config_check()
679-
api_instance = client.CustomObjectsApi(api_config_handler())
680-
aws = api_instance.list_namespaced_custom_object(
681-
group="workload.codeflare.dev",
682-
version="v1beta1",
683-
namespace=namespace,
684-
plural="appwrappers",
685-
)
686-
except Exception as e: # pragma: no cover
687-
return _kube_api_error_handling(e, print_error=False)
688-
for aw in aws["items"]:
689-
if aw["metadata"]["name"] == name:
690-
host = aw["spec"]["resources"]["GenericItems"][1]["generictemplate"][
691-
"spec"
692-
]["rules"][0]["host"]
693-
694-
dot_index = host.find(".")
695-
if dot_index != -1:
696-
domain_name = host[dot_index + 1 :]
697-
return domain_name
698-
else:
699-
print("Host is not configured correctly.")
700-
return None
701-
702-
703716
# Cant test this until get_current_namespace is fixed and placed in this function over using `self`
704717
def _get_ingress_domain(self): # pragma: no cover
705-
try:
706-
config_check()
707-
api_client = client.NetworkingV1Api(api_config_handler())
708-
if self.config.namespace != None:
709-
namespace = self.config.namespace
710-
else:
711-
namespace = get_current_namespace()
712-
ingresses = api_client.list_namespaced_ingress(namespace)
713-
except Exception as e: # pragma: no cover
714-
return _kube_api_error_handling(e)
718+
config_check()
719+
720+
if self.config.namespace != None:
721+
namespace = self.config.namespace
722+
else:
723+
namespace = get_current_namespace()
715724
domain = None
716-
for ingress in ingresses.items:
717-
if ingress.spec.rules[0].http.paths[0].backend.service.port.number == 10001:
718-
domain = ingress.spec.rules[0].host
725+
726+
if is_openshift_cluster():
727+
try:
728+
api_instance = client.CustomObjectsApi(api_config_handler())
729+
730+
routes = api_instance.list_namespaced_custom_object(
731+
group="route.openshift.io",
732+
version="v1",
733+
namespace=namespace,
734+
plural="routes",
735+
)
736+
except Exception as e: # pragma: no cover
737+
return _kube_api_error_handling(e)
738+
739+
for route in routes["items"]:
740+
if route["spec"]["port"]["targetPort"] == "client":
741+
domain = route["spec"]["host"]
742+
else:
743+
try:
744+
api_client = client.NetworkingV1Api(api_config_handler())
745+
ingresses = api_client.list_namespaced_ingress(namespace)
746+
except Exception as e: # pragma: no cover
747+
return _kube_api_error_handling(e)
748+
749+
for ingress in ingresses.items:
750+
if ingress.spec.rules[0].http.paths[0].backend.service.port.number == 10001:
751+
domain = ingress.spec.rules[0].host
719752
return domain
720753

721754

src/codeflare_sdk/cluster/config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,4 @@ class ClusterConfiguration:
5454
dispatch_priority: str = None
5555
openshift_oauth: bool = False # NOTE: to use the user must have permission to create a RoleBinding for system:auth-delegator
5656
ingress_options: dict = field(default_factory=dict)
57-
domain_name: str = None
57+
ingress_domain: str = None

src/codeflare_sdk/templates/base-template.yaml

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ spec:
289289
apiVersion: networking.k8s.io/v1
290290
kind: Ingress
291291
metadata:
292-
name: ray-dashboard-raytest
292+
name: ray-dashboard-deployment-ingress
293293
namespace: default
294294
annotations:
295295
annotations-example:annotations-example
@@ -306,12 +306,28 @@ spec:
306306
pathType: Prefix
307307
path: /
308308
host: ray-dashboard-raytest.<ingress-domain>
309+
- replicas: 1
310+
generictemplate:
311+
kind: Route
312+
apiVersion: route.openshift.io/v1
313+
metadata:
314+
name: ray-dashboard-deployment-route
315+
namespace: default
316+
labels:
317+
# allows me to return name of service that Ray operator creates
318+
odh-ray-cluster-service: deployment-name-head-svc
319+
spec:
320+
to:
321+
kind: Service
322+
name: deployment-name-head-svc
323+
port:
324+
targetPort: dashboard
309325
- replicas: 1
310326
generictemplate:
311327
apiVersion: networking.k8s.io/v1
312328
kind: Ingress
313329
metadata:
314-
name: rayclient-deployment-name
330+
name: rayclient-deployment-ingress
315331
namespace: default
316332
annotations:
317333
annotations-example:annotations-example
@@ -330,6 +346,24 @@ spec:
330346
path: ''
331347
pathType: ImplementationSpecific
332348
host: rayclient-raytest.<ingress-domain>
349+
- replicas: 1
350+
generictemplate:
351+
apiVersion: route.openshift.io/v1
352+
kind: Route
353+
metadata:
354+
name: rayclient-deployment-route
355+
namespace: default
356+
labels:
357+
# allows me to return name of service that Ray operator creates
358+
odh-ray-cluster-service: deployment-name-head-svc
359+
spec:
360+
port:
361+
targetPort: client
362+
tls:
363+
termination: passthrough
364+
to:
365+
kind: Service
366+
name: deployment-name-head-svc
333367
- replicas: 1
334368
generictemplate:
335369
apiVersion: v1

0 commit comments

Comments
 (0)