Skip to content

Commit 5a19495

Browse files
Merge pull request #145 from laurafitzgerald/RHOAIENG-47147
CARRY: set enableIngress to false
2 parents eba1798 + 04ac898 commit 5a19495

8 files changed

+527
-126
lines changed

ray-operator/controllers/ray/authentication_controller.go

Lines changed: 48 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -214,9 +214,14 @@ func (r *AuthenticationController) handleOIDCConfiguration(ctx context.Context,
214214
return nil
215215
}
216216

217-
// Ensure ingress is enabled for httproute creation
218-
if err := r.ensureIngressEnabled(ctx, rayCluster, logger); err != nil {
219-
return fmt.Errorf("failed to ensure ingress enabled: %w", err)
217+
// On OpenShift, enforce enableIngress: false for Gateway-only access
218+
// This handles both new clusters (webhook sets it) and existing clusters (upgrade scenario)
219+
// HTTPRoute creation is independent of enableIngress
220+
// enableIngress controls basic Route/Ingress creation (which may be disabled by webhooks in ODH)
221+
if r.options.IsOpenShift {
222+
if err := r.enforceEnableIngressFalseOnOpenShift(ctx, rayCluster, logger); err != nil {
223+
return err
224+
}
220225
}
221226

222227
// Add finalizer to ensure cleanup happens before cluster deletion
@@ -241,31 +246,6 @@ func (r *AuthenticationController) handleOIDCConfiguration(ctx context.Context,
241246
return nil
242247
}
243248

244-
// ensureIngressEnabled ensures that ingress is enabled for the RayCluster
245-
func (r *AuthenticationController) ensureIngressEnabled(ctx context.Context, cluster *rayv1.RayCluster, logger logr.Logger) error {
246-
// Check if ingress is already enabled
247-
if cluster.Spec.HeadGroupSpec.EnableIngress != nil && *cluster.Spec.HeadGroupSpec.EnableIngress {
248-
logger.Info("Ingress already enabled for cluster", "cluster", cluster.Name)
249-
return nil
250-
}
251-
252-
logger.Info("Enabling ingress for Auth-secured cluster", "cluster", cluster.Name)
253-
254-
// Create a copy and enable ingress
255-
updatedCluster := cluster.DeepCopy()
256-
trueValue := true
257-
updatedCluster.Spec.HeadGroupSpec.EnableIngress = &trueValue
258-
259-
// Update the cluster
260-
if err := r.Update(ctx, updatedCluster); err != nil {
261-
return fmt.Errorf("failed to enable ingress: %w", err)
262-
}
263-
264-
logger.Info("Successfully enabled ingress for cluster", "cluster", cluster.Name)
265-
r.Recorder.Event(cluster, "Normal", "IngressEnabled", "Automatically enabled ingress for Auth configuration")
266-
return nil
267-
}
268-
269249
func (r *AuthenticationController) ensureOIDCResources(ctx context.Context, cluster *rayv1.RayCluster, authMode utils.AuthenticationMode, logger logr.Logger) error {
270250
if err := r.ensureServiceAccount(ctx, cluster, authMode, logger); err != nil {
271251
return fmt.Errorf("failed to ensure service account: %w", err)
@@ -1016,6 +996,46 @@ func (r *AuthenticationController) cleanupOrphanedReferenceGrant(ctx context.Con
1016996
return nil
1017997
}
1018998

999+
// enforceEnableIngressFalseOnOpenShift ensures enableIngress is set to false on OpenShift
1000+
// This provides upgrade idempotency - handles existing clusters that weren't processed by webhook
1001+
// The webhook sets this for new/edited clusters, this handles clusters from before the webhook was updated
1002+
// Placed in Authentication controller because HTTPRoute requires Gateway access (not basic Routes)
1003+
func (r *AuthenticationController) enforceEnableIngressFalseOnOpenShift(ctx context.Context, rayCluster *rayv1.RayCluster, logger logr.Logger) error {
1004+
// Check if enableIngress is already false
1005+
if rayCluster.Spec.HeadGroupSpec.EnableIngress != nil && !*rayCluster.Spec.HeadGroupSpec.EnableIngress {
1006+
return nil // Already false, nothing to do
1007+
}
1008+
1009+
// Need to set to false
1010+
wasTrue := rayCluster.Spec.HeadGroupSpec.EnableIngress != nil && *rayCluster.Spec.HeadGroupSpec.EnableIngress
1011+
wasMissing := rayCluster.Spec.HeadGroupSpec.EnableIngress == nil
1012+
1013+
logger.Info("Enforcing enableIngress to false on OpenShift (Gateway-only access)",
1014+
"cluster", rayCluster.Name, "previousValue", rayCluster.Spec.HeadGroupSpec.EnableIngress)
1015+
1016+
// Update the cluster spec
1017+
rayCluster.Spec.HeadGroupSpec.EnableIngress = ptr.To(false)
1018+
if err := r.Update(ctx, rayCluster); err != nil {
1019+
logger.Error(err, "Failed to enforce enableIngress to false", "cluster", rayCluster.Name)
1020+
return err
1021+
}
1022+
1023+
if wasTrue {
1024+
logger.Info("Overrode user-specified enableIngress from true to false for Gateway-only access",
1025+
"cluster", rayCluster.Name)
1026+
r.Recorder.Eventf(rayCluster, corev1.EventTypeNormal,
1027+
"EnableIngressEnforced",
1028+
"Set enableIngress to false to enforce Gateway-only access (overrode user value)")
1029+
} else if wasMissing {
1030+
logger.Info("Set enableIngress to false for Gateway-only access (was not set)", "cluster", rayCluster.Name)
1031+
r.Recorder.Eventf(rayCluster, corev1.EventTypeNormal,
1032+
"EnableIngressSet",
1033+
"Set enableIngress to false for Gateway-only access")
1034+
}
1035+
1036+
return nil
1037+
}
1038+
10191039
// SetupWithManager sets up the controller with the Manager
10201040
func (r *AuthenticationController) SetupWithManager(mgr ctrl.Manager) error {
10211041
// Predicate to only reconcile RayClusters when relevant changes occur

ray-operator/controllers/ray/authentication_controller_integration_test.go

Lines changed: 0 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -38,103 +38,6 @@ import (
3838
"github.com/ray-project/kuberay/ray-operator/controllers/ray/utils"
3939
)
4040

41-
// TestEnsureIngressEnabled tests that ingress is automatically enabled when auth is configured
42-
func TestEnsureIngressEnabled(t *testing.T) {
43-
ctx := context.Background()
44-
s := setupScheme()
45-
46-
tests := []struct {
47-
cluster *rayv1.RayCluster
48-
name string
49-
expectUpdate bool
50-
expectedIngress bool
51-
}{
52-
{
53-
name: "Ingress not enabled - should enable",
54-
cluster: &rayv1.RayCluster{
55-
ObjectMeta: metav1.ObjectMeta{
56-
Name: "test-cluster",
57-
Namespace: "default",
58-
},
59-
Spec: rayv1.RayClusterSpec{
60-
HeadGroupSpec: rayv1.HeadGroupSpec{
61-
EnableIngress: nil, // Not set
62-
},
63-
},
64-
},
65-
expectUpdate: true,
66-
expectedIngress: true,
67-
},
68-
{
69-
name: "Ingress explicitly disabled - should enable",
70-
cluster: &rayv1.RayCluster{
71-
ObjectMeta: metav1.ObjectMeta{
72-
Name: "test-cluster",
73-
Namespace: "default",
74-
},
75-
Spec: rayv1.RayClusterSpec{
76-
HeadGroupSpec: rayv1.HeadGroupSpec{
77-
EnableIngress: ptr.To(false),
78-
},
79-
},
80-
},
81-
expectUpdate: true,
82-
expectedIngress: true,
83-
},
84-
{
85-
name: "Ingress already enabled - no update",
86-
cluster: &rayv1.RayCluster{
87-
ObjectMeta: metav1.ObjectMeta{
88-
Name: "test-cluster",
89-
Namespace: "default",
90-
},
91-
Spec: rayv1.RayClusterSpec{
92-
HeadGroupSpec: rayv1.HeadGroupSpec{
93-
EnableIngress: ptr.To(true),
94-
},
95-
},
96-
},
97-
expectUpdate: false,
98-
expectedIngress: true,
99-
},
100-
}
101-
102-
for _, tc := range tests {
103-
t.Run(tc.name, func(t *testing.T) {
104-
fakeClient := clientFake.NewClientBuilder().
105-
WithScheme(s).
106-
WithRuntimeObjects(tc.cluster).
107-
Build()
108-
109-
controller := &AuthenticationController{
110-
Client: fakeClient,
111-
Scheme: s,
112-
Recorder: record.NewFakeRecorder(10),
113-
options: RayClusterReconcilerOptions{
114-
IsOpenShift: true,
115-
},
116-
}
117-
118-
// Execute
119-
err := controller.ensureIngressEnabled(ctx, tc.cluster, ctrl.Log)
120-
require.NoError(t, err, "Should ensure ingress without error")
121-
122-
// Verify
123-
updatedCluster := &rayv1.RayCluster{}
124-
err = fakeClient.Get(ctx, types.NamespacedName{
125-
Name: tc.cluster.Name,
126-
Namespace: tc.cluster.Namespace,
127-
}, updatedCluster)
128-
require.NoError(t, err)
129-
130-
assert.NotNil(t, updatedCluster.Spec.HeadGroupSpec.EnableIngress,
131-
"EnableIngress should be set")
132-
assert.Equal(t, tc.expectedIngress, *updatedCluster.Spec.HeadGroupSpec.EnableIngress,
133-
"EnableIngress should match expected value")
134-
})
135-
}
136-
}
137-
13841
// TestHandleDeletion tests the finalizer-based deletion flow
13942
func TestHandleDeletion(t *testing.T) {
14043
ctx := context.Background()

ray-operator/controllers/ray/authentication_controller_unit_test.go

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1030,3 +1030,143 @@ func TestCleanupOIDCResources(t *testing.T) {
10301030
})
10311031
}
10321032
}
1033+
1034+
func TestEnforceEnableIngressFalseOnOpenShift(t *testing.T) {
1035+
s := setupScheme()
1036+
1037+
testCases := []struct {
1038+
initialValue *bool
1039+
name string
1040+
expectUpdate bool
1041+
}{
1042+
{
1043+
name: "enableIngress is nil - should set to false",
1044+
initialValue: nil,
1045+
expectUpdate: true,
1046+
},
1047+
{
1048+
name: "enableIngress is true - should override to false",
1049+
initialValue: ptr.To(true),
1050+
expectUpdate: true,
1051+
},
1052+
{
1053+
name: "enableIngress is already false - no update needed",
1054+
initialValue: ptr.To(false),
1055+
expectUpdate: false,
1056+
},
1057+
}
1058+
1059+
for _, tc := range testCases {
1060+
t.Run(tc.name, func(t *testing.T) {
1061+
// Create test cluster
1062+
rayCluster := &rayv1.RayCluster{
1063+
ObjectMeta: metav1.ObjectMeta{
1064+
Name: "test-cluster",
1065+
Namespace: "default",
1066+
},
1067+
Spec: rayv1.RayClusterSpec{
1068+
HeadGroupSpec: rayv1.HeadGroupSpec{
1069+
EnableIngress: tc.initialValue,
1070+
},
1071+
},
1072+
}
1073+
1074+
// Create fake client with the cluster
1075+
fakeClient := clientFake.NewClientBuilder().
1076+
WithScheme(s).
1077+
WithObjects(rayCluster).
1078+
Build()
1079+
1080+
controller := &AuthenticationController{
1081+
Client: fakeClient,
1082+
Scheme: s,
1083+
Recorder: record.NewFakeRecorder(10),
1084+
options: RayClusterReconcilerOptions{
1085+
IsOpenShift: true,
1086+
},
1087+
}
1088+
1089+
// Execute
1090+
err := controller.enforceEnableIngressFalseOnOpenShift(
1091+
context.Background(),
1092+
rayCluster,
1093+
ctrl.Log.WithName("test"))
1094+
1095+
// Verify no error
1096+
require.NoError(t, err, "Enforcement should not return error")
1097+
1098+
if tc.expectUpdate {
1099+
// Get updated cluster from fake client
1100+
updated := &rayv1.RayCluster{}
1101+
err = fakeClient.Get(context.Background(),
1102+
types.NamespacedName{Name: rayCluster.Name, Namespace: rayCluster.Namespace},
1103+
updated)
1104+
require.NoError(t, err, "Should be able to get updated cluster")
1105+
1106+
// Verify enableIngress is now false
1107+
require.NotNil(t, updated.Spec.HeadGroupSpec.EnableIngress,
1108+
"EnableIngress should be set")
1109+
assert.False(t, *updated.Spec.HeadGroupSpec.EnableIngress,
1110+
"EnableIngress should be false")
1111+
}
1112+
})
1113+
}
1114+
}
1115+
1116+
func TestEnforceEnableIngressFalseOnOpenShift_Idempotency(t *testing.T) {
1117+
s := setupScheme()
1118+
1119+
// Create test cluster with enableIngress: true
1120+
rayCluster := &rayv1.RayCluster{
1121+
ObjectMeta: metav1.ObjectMeta{
1122+
Name: "test-cluster",
1123+
Namespace: "default",
1124+
},
1125+
Spec: rayv1.RayClusterSpec{
1126+
HeadGroupSpec: rayv1.HeadGroupSpec{
1127+
EnableIngress: ptr.To(true),
1128+
},
1129+
},
1130+
}
1131+
1132+
fakeClient := clientFake.NewClientBuilder().
1133+
WithScheme(s).
1134+
WithObjects(rayCluster).
1135+
Build()
1136+
1137+
controller := &AuthenticationController{
1138+
Client: fakeClient,
1139+
Scheme: s,
1140+
Recorder: record.NewFakeRecorder(10),
1141+
options: RayClusterReconcilerOptions{
1142+
IsOpenShift: true,
1143+
},
1144+
}
1145+
1146+
// Call enforcement multiple times
1147+
for i := 0; i < 3; i++ {
1148+
// Get latest version
1149+
err := fakeClient.Get(context.Background(),
1150+
types.NamespacedName{Name: rayCluster.Name, Namespace: rayCluster.Namespace},
1151+
rayCluster)
1152+
require.NoError(t, err)
1153+
1154+
// Enforce
1155+
err = controller.enforceEnableIngressFalseOnOpenShift(
1156+
context.Background(),
1157+
rayCluster,
1158+
ctrl.Log.WithName("test"))
1159+
require.NoError(t, err, "Enforcement should not error on iteration %d", i)
1160+
}
1161+
1162+
// Verify final state
1163+
updated := &rayv1.RayCluster{}
1164+
err := fakeClient.Get(context.Background(),
1165+
types.NamespacedName{Name: rayCluster.Name, Namespace: rayCluster.Namespace},
1166+
updated)
1167+
require.NoError(t, err)
1168+
1169+
require.NotNil(t, updated.Spec.HeadGroupSpec.EnableIngress)
1170+
assert.False(t, *updated.Spec.HeadGroupSpec.EnableIngress,
1171+
"EnableIngress should be false after multiple enforcements")
1172+
}

0 commit comments

Comments
 (0)