Skip to content

Commit ee91bff

Browse files
committed
[275] Implement ExposeService method
1 parent 65b8889 commit ee91bff

File tree

5 files changed

+143
-99
lines changed

5 files changed

+143
-99
lines changed

test/e2e/mnist_rayjob_mcad_raycluster_test.go

Lines changed: 1 addition & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,15 @@ package e2e
1818

1919
import (
2020
"encoding/base64"
21-
"net/url"
2221
"testing"
2322

2423
. "github.com/onsi/gomega"
2524
mcadv1beta1 "github.com/project-codeflare/multi-cluster-app-dispatcher/pkg/apis/controller/v1beta1"
2625
rayv1alpha1 "github.com/ray-project/kuberay/ray-operator/apis/ray/v1alpha1"
2726

2827
corev1 "k8s.io/api/core/v1"
29-
networkingv1 "k8s.io/api/networking/v1"
3028
"k8s.io/apimachinery/pkg/api/resource"
3129
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
32-
"k8s.io/apimachinery/pkg/util/intstr"
33-
34-
routev1 "github.com/openshift/api/route/v1"
3530

3631
. "github.com/project-codeflare/codeflare-operator/test/support"
3732
)
@@ -257,98 +252,7 @@ func TestMNISTRayJobMCADRayCluster(t *testing.T) {
257252
test.Expect(err).NotTo(HaveOccurred())
258253
test.T().Logf("Created RayJob %s/%s successfully", rayJob.Namespace, rayJob.Name)
259254

260-
var rayDashboardURL url.URL
261-
if IsOpenShift(test) {
262-
// Create a route to expose the Ray cluster API
263-
route := &routev1.Route{
264-
TypeMeta: metav1.TypeMeta{
265-
APIVersion: routev1.GroupVersion.String(),
266-
Kind: "Route",
267-
},
268-
ObjectMeta: metav1.ObjectMeta{
269-
Namespace: namespace.Name,
270-
Name: "ray-dashboard",
271-
},
272-
Spec: routev1.RouteSpec{
273-
To: routev1.RouteTargetReference{
274-
Name: "raycluster-head-svc",
275-
},
276-
Port: &routev1.RoutePort{
277-
TargetPort: intstr.FromString("dashboard"),
278-
},
279-
},
280-
}
281-
282-
_, err := test.Client().Route().RouteV1().Routes(namespace.Name).Create(test.Ctx(), route, metav1.CreateOptions{})
283-
test.Expect(err).NotTo(HaveOccurred())
284-
test.T().Logf("Created Route %s/%s successfully", route.Namespace, route.Name)
285-
286-
test.T().Logf("Waiting for Route %s/%s to be admitted", route.Namespace, route.Name)
287-
test.Eventually(Route(test, route.Namespace, route.Name), TestTimeoutMedium).
288-
Should(WithTransform(ConditionStatus(routev1.RouteAdmitted), Equal(corev1.ConditionTrue)))
289-
290-
route = GetRoute(test, route.Namespace, route.Name)
291-
292-
rayDashboardURL = url.URL{
293-
Scheme: "http",
294-
Host: route.Status.Ingress[0].Host,
295-
}
296-
} else {
297-
ingress := &networkingv1.Ingress{
298-
TypeMeta: metav1.TypeMeta{
299-
APIVersion: networkingv1.SchemeGroupVersion.String(),
300-
Kind: "Ingress",
301-
},
302-
ObjectMeta: metav1.ObjectMeta{
303-
Namespace: namespace.Name,
304-
Name: "ray-dashboard",
305-
Annotations: map[string]string{
306-
"nginx.ingress.kubernetes.io/use-regex": "true",
307-
"nginx.ingress.kubernetes.io/rewrite-target": "/$2",
308-
},
309-
},
310-
Spec: networkingv1.IngressSpec{
311-
Rules: []networkingv1.IngressRule{
312-
{
313-
IngressRuleValue: networkingv1.IngressRuleValue{
314-
HTTP: &networkingv1.HTTPIngressRuleValue{
315-
Paths: []networkingv1.HTTPIngressPath{
316-
{
317-
Path: "/ray-dashboard(/|$)(.*)",
318-
PathType: Ptr(networkingv1.PathTypePrefix),
319-
Backend: networkingv1.IngressBackend{
320-
Service: &networkingv1.IngressServiceBackend{
321-
Name: "raycluster-head-svc",
322-
Port: networkingv1.ServiceBackendPort{
323-
Name: "dashboard",
324-
},
325-
},
326-
},
327-
},
328-
},
329-
},
330-
},
331-
},
332-
},
333-
},
334-
}
335-
336-
_, err := test.Client().Core().NetworkingV1().Ingresses(ingress.Namespace).Create(test.Ctx(), ingress, metav1.CreateOptions{})
337-
test.Expect(err).NotTo(HaveOccurred())
338-
test.T().Logf("Created Ingress %s/%s successfully", ingress.Namespace, ingress.Name)
339-
340-
test.T().Logf("Waiting for Ingress %s/%s to be admitted", ingress.Namespace, ingress.Name)
341-
test.Eventually(Ingress(test, ingress.Namespace, ingress.Name), TestTimeoutMedium).
342-
Should(WithTransform(LoadBalancerIngresses, HaveLen(1)))
343-
344-
ingress = GetIngress(test, ingress.Namespace, ingress.Name)
345-
346-
rayDashboardURL = url.URL{
347-
Scheme: "http",
348-
Host: ingress.Status.LoadBalancer.Ingress[0].IP,
349-
Path: "ray-dashboard",
350-
}
351-
}
255+
rayDashboardURL := ExposeService(test, "ray-dashboard", namespace.Name, "raycluster-head-svc", "dashboard")
352256

353257
test.T().Logf("Connecting to Ray cluster at: %s", rayDashboardURL.String())
354258
rayClient := NewRayClusterClient(rayDashboardURL)

test/support/ingress.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ limitations under the License.
1717
package support
1818

1919
import (
20+
"net/url"
21+
2022
"github.com/onsi/gomega"
2123

2224
networkingv1 "k8s.io/api/networking/v1"
@@ -39,3 +41,61 @@ func GetIngress(t Test, namespace, name string) *networkingv1.Ingress {
3941
func LoadBalancerIngresses(ingress *networkingv1.Ingress) []networkingv1.IngressLoadBalancerIngress {
4042
return ingress.Status.LoadBalancer.Ingress
4143
}
44+
45+
func ExposeServiceByIngress(t Test, name string, namespace string, serviceName string, servicePort string) url.URL {
46+
ingress := &networkingv1.Ingress{
47+
TypeMeta: metav1.TypeMeta{
48+
APIVersion: networkingv1.SchemeGroupVersion.String(),
49+
Kind: "Ingress",
50+
},
51+
ObjectMeta: metav1.ObjectMeta{
52+
Name: name,
53+
Namespace: namespace,
54+
Annotations: map[string]string{
55+
"nginx.ingress.kubernetes.io/use-regex": "true",
56+
"nginx.ingress.kubernetes.io/rewrite-target": "/$2",
57+
},
58+
},
59+
Spec: networkingv1.IngressSpec{
60+
Rules: []networkingv1.IngressRule{
61+
networkingv1.IngressRule{
62+
IngressRuleValue: networkingv1.IngressRuleValue{
63+
HTTP: &networkingv1.HTTPIngressRuleValue{
64+
Paths: []networkingv1.HTTPIngressPath{
65+
networkingv1.HTTPIngressPath{
66+
Path: "/" + name + "(/|$)(.*)",
67+
PathType: Ptr(networkingv1.PathTypePrefix),
68+
Backend: networkingv1.IngressBackend{
69+
Service: &networkingv1.IngressServiceBackend{
70+
Name: serviceName,
71+
Port: networkingv1.ServiceBackendPort{
72+
Name: servicePort,
73+
},
74+
},
75+
},
76+
},
77+
},
78+
},
79+
},
80+
},
81+
},
82+
},
83+
}
84+
85+
_, err := t.Client().Core().NetworkingV1().Ingresses(ingress.Namespace).Create(t.Ctx(), ingress, metav1.CreateOptions{})
86+
t.Expect(err).NotTo(gomega.HaveOccurred())
87+
t.T().Logf("Created Ingress %s/%s successfully", ingress.Namespace, ingress.Name)
88+
89+
t.T().Logf("Waiting for Ingress %s/%s to be admitted", ingress.Namespace, ingress.Name)
90+
t.Eventually(Ingress(t, ingress.Namespace, ingress.Name), TestTimeoutMedium).
91+
Should(gomega.WithTransform(LoadBalancerIngresses, gomega.HaveLen(1)))
92+
93+
ingress = GetIngress(t, ingress.Namespace, ingress.Name)
94+
95+
ingressURL := url.URL{
96+
Scheme: "http",
97+
Host: ingress.Status.LoadBalancer.Ingress[0].IP,
98+
Path: name,
99+
}
100+
return ingressURL
101+
}

test/support/route.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,14 @@ limitations under the License.
1717
package support
1818

1919
import (
20+
"net/http"
21+
"net/url"
22+
2023
"github.com/onsi/gomega"
2124

25+
corev1 "k8s.io/api/core/v1"
2226
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27+
"k8s.io/apimachinery/pkg/util/intstr"
2328

2429
routev1 "github.com/openshift/api/route/v1"
2530
)
@@ -36,3 +41,51 @@ func GetRoute(t Test, namespace, name string) *routev1.Route {
3641
t.T().Helper()
3742
return Route(t, namespace, name)(t)
3843
}
44+
45+
func ExposeServiceByRoute(t Test, name string, namespace string, serviceName string, servicePort string) url.URL {
46+
r := &routev1.Route{
47+
TypeMeta: metav1.TypeMeta{
48+
APIVersion: routev1.SchemeGroupVersion.String(),
49+
Kind: "Route",
50+
},
51+
ObjectMeta: metav1.ObjectMeta{
52+
Name: name,
53+
Namespace: namespace,
54+
},
55+
Spec: routev1.RouteSpec{
56+
To: routev1.RouteTargetReference{
57+
Name: serviceName,
58+
},
59+
Port: &routev1.RoutePort{
60+
TargetPort: intstr.FromString(servicePort),
61+
},
62+
},
63+
}
64+
65+
_, err := t.Client().Route().RouteV1().Routes(r.Namespace).Create(t.Ctx(), r, metav1.CreateOptions{})
66+
t.Expect(err).NotTo(gomega.HaveOccurred())
67+
t.T().Logf("Created Route %s/%s successfully", r.Namespace, r.Name)
68+
69+
t.T().Logf("Waiting for Route %s/%s to be available", r.Namespace, r.Name)
70+
t.Eventually(Route(t, r.Namespace, r.Name), TestTimeoutLong).
71+
Should(gomega.WithTransform(ConditionStatus(routev1.RouteAdmitted), gomega.Equal(corev1.ConditionTrue)))
72+
73+
// Retrieve hostname
74+
r, err = t.Client().Route().RouteV1().Routes(r.Namespace).Get(t.Ctx(), r.Name, metav1.GetOptions{})
75+
t.Expect(err).NotTo(gomega.HaveOccurred())
76+
hostname := r.Status.Ingress[0].Host
77+
78+
// Wait for expected HTTP code
79+
t.Eventually(func() int {
80+
resp, _ := http.Get("http://" + hostname)
81+
return resp.StatusCode
82+
}, TestTimeoutLong).Should(gomega.Not(gomega.Equal(503)))
83+
84+
r = GetRoute(t, r.Namespace, r.Name)
85+
routeURL := url.URL{
86+
Scheme: "http",
87+
Host: r.Status.Ingress[0].Host,
88+
}
89+
90+
return routeURL
91+
}

test/support/service.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
Copyright 2023.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package support
18+
19+
import "net/url"
20+
21+
func ExposeService(t Test, name string, namespace string, serviceName string, servicePort string) url.URL {
22+
if IsOpenShift(t) {
23+
return ExposeServiceByRoute(t, name, namespace, serviceName, servicePort)
24+
} else {
25+
return ExposeServiceByIngress(t, name, namespace, serviceName, servicePort)
26+
}
27+
}

test/support/support.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@ import (
2828
)
2929

3030
var (
31+
ApplyOptions = metav1.ApplyOptions{FieldManager: "codeflare-test", Force: true}
32+
3133
TestTimeoutShort = 1 * time.Minute
3234
TestTimeoutMedium = 2 * time.Minute
3335
TestTimeoutLong = 5 * time.Minute
34-
35-
ApplyOptions = metav1.ApplyOptions{FieldManager: "codeflare-test", Force: true}
3636
)
3737

3838
func init() {

0 commit comments

Comments
 (0)