@@ -33,6 +33,11 @@ import (
33
33
"github.com/project-codeflare/codeflare-operator/pkg/config"
34
34
)
35
35
36
+ const (
37
+ oauthProxyContainerName = "oauth-proxy"
38
+ oauthProxyVolumeName = "proxy-tls-secret"
39
+ )
40
+
36
41
// log is for logging in this package.
37
42
var rayclusterlog = logf .Log .WithName ("raycluster-resource" )
38
43
@@ -47,7 +52,7 @@ func SetupRayClusterWebhookWithManager(mgr ctrl.Manager, cfg *config.KubeRayConf
47
52
Complete ()
48
53
}
49
54
50
- // +kubebuilder:webhook:path=/mutate-ray-io-v1-raycluster,mutating=true,failurePolicy=fail,sideEffects=None,groups=ray.io,resources=rayclusters,verbs=create;update ,versions=v1,name=mraycluster.kb.io,admissionReviewVersions=v1
55
+ // +kubebuilder:webhook:path=/mutate-ray-io-v1-raycluster,mutating=true,failurePolicy=fail,sideEffects=None,groups=ray.io,resources=rayclusters,verbs=create,versions=v1,name=mraycluster.kb.io,admissionReviewVersions=v1
51
56
// +kubebuilder:webhook:path=/validate-ray-io-v1-raycluster,mutating=false,failurePolicy=fail,sideEffects=None,groups=ray.io,resources=rayclusters,verbs=create;update,versions=v1,name=vraycluster.kb.io,admissionReviewVersions=v1
52
57
53
58
type rayClusterWebhook struct {
@@ -65,18 +70,105 @@ func (w *rayClusterWebhook) Default(ctx context.Context, obj runtime.Object) err
65
70
return nil
66
71
}
67
72
68
- // Check and add OAuth proxy if it does not exist
69
- for _ , container := range rayCluster .Spec .HeadGroupSpec .Template .Spec .Containers {
70
- if container .Name == "oauth-proxy" {
71
- rayclusterlog .V (2 ).Info ("OAuth sidecar already exists, no patch needed" )
72
- return nil
73
- }
73
+ rayclusterlog .V (2 ).Info ("Adding OAuth sidecar container" )
74
+
75
+ rayCluster .Spec .HeadGroupSpec .Template .Spec .Containers = upsert (rayCluster .Spec .HeadGroupSpec .Template .Spec .Containers , oauthProxyContainer (rayCluster ), withContainerName (oauthProxyContainerName ))
76
+
77
+ rayCluster .Spec .HeadGroupSpec .Template .Spec .Volumes = upsert (rayCluster .Spec .HeadGroupSpec .Template .Spec .Volumes , oauthProxyTLSSecretVolume (rayCluster ), withVolumeName (oauthProxyVolumeName ))
78
+
79
+ rayCluster .Spec .HeadGroupSpec .Template .Spec .ServiceAccountName = rayCluster .Name + "-oauth-proxy"
80
+
81
+ return nil
82
+ }
83
+
84
+ func (w * rayClusterWebhook ) ValidateCreate (ctx context.Context , obj runtime.Object ) (admission.Warnings , error ) {
85
+ rayCluster := obj .(* rayv1.RayCluster )
86
+
87
+ var warnings admission.Warnings
88
+ var allErrors field.ErrorList
89
+
90
+ allErrors = append (allErrors , validateIngress (rayCluster )... )
91
+
92
+ return warnings , allErrors .ToAggregate ()
93
+ }
94
+
95
+ func (w * rayClusterWebhook ) ValidateUpdate (ctx context.Context , oldObj , newObj runtime.Object ) (admission.Warnings , error ) {
96
+ rayCluster := newObj .(* rayv1.RayCluster )
97
+
98
+ var warnings admission.Warnings
99
+ var allErrors field.ErrorList
100
+
101
+ if ! rayCluster .DeletionTimestamp .IsZero () {
102
+ // Object is being deleted, skip validations
103
+ return nil , nil
104
+ }
105
+
106
+ allErrors = append (allErrors , validateIngress (rayCluster )... )
107
+ allErrors = append (allErrors , validateOAuthProxyContainer (rayCluster )... )
108
+ allErrors = append (allErrors , validateOAuthProxyVolume (rayCluster )... )
109
+ allErrors = append (allErrors , validateHeadGroupServiceAccountName (rayCluster )... )
110
+
111
+ return warnings , allErrors .ToAggregate ()
112
+ }
113
+
114
+ func (w * rayClusterWebhook ) ValidateDelete (ctx context.Context , obj runtime.Object ) (admission.Warnings , error ) {
115
+ // Optional: Add delete validation logic here
116
+ return nil , nil
117
+ }
118
+
119
+ func validateOAuthProxyContainer (rayCluster * rayv1.RayCluster ) field.ErrorList {
120
+ var allErrors field.ErrorList
121
+
122
+ if err := contains (rayCluster .Spec .HeadGroupSpec .Template .Spec .Containers , oauthProxyContainer (rayCluster ), byContainerName ,
123
+ field .NewPath ("spec" , "headGroupSpec" , "template" , "spec" , "containers" ),
124
+ "OAuth Proxy container is immutable" ); err != nil {
125
+ allErrors = append (allErrors , err )
74
126
}
75
127
76
- rayclusterlog .V (2 ).Info ("Adding OAuth sidecar container" )
128
+ return allErrors
129
+ }
130
+
131
+ func validateOAuthProxyVolume (rayCluster * rayv1.RayCluster ) field.ErrorList {
132
+ var allErrors field.ErrorList
77
133
78
- newOAuthSidecar := corev1.Container {
79
- Name : "oauth-proxy" ,
134
+ if err := contains (rayCluster .Spec .HeadGroupSpec .Template .Spec .Volumes , oauthProxyTLSSecretVolume (rayCluster ), byVolumeName ,
135
+ field .NewPath ("spec" , "headGroupSpec" , "template" , "spec" , "volumes" ),
136
+ "OAuth Proxy TLS Secret volume is immutable" ); err != nil {
137
+ allErrors = append (allErrors , err )
138
+ }
139
+
140
+ return allErrors
141
+ }
142
+
143
+ func validateIngress (rayCluster * rayv1.RayCluster ) field.ErrorList {
144
+ var allErrors field.ErrorList
145
+
146
+ if pointer .BoolDeref (rayCluster .Spec .HeadGroupSpec .EnableIngress , false ) {
147
+ allErrors = append (allErrors , field .Invalid (
148
+ field .NewPath ("spec" , "headGroupSpec" , "enableIngress" ),
149
+ rayCluster .Spec .HeadGroupSpec .EnableIngress ,
150
+ "RayCluster resources with EnableIngress set to true or unspecified is not allowed" ))
151
+ }
152
+
153
+ return allErrors
154
+ }
155
+
156
+ func validateHeadGroupServiceAccountName (rayCluster * rayv1.RayCluster ) field.ErrorList {
157
+ var allErrors field.ErrorList
158
+
159
+ if rayCluster .Spec .HeadGroupSpec .Template .Spec .ServiceAccountName != rayCluster .Name + "-oauth-proxy" {
160
+ allErrors = append (allErrors , field .Invalid (
161
+ field .NewPath ("spec" , "headGroupSpec" , "template" , "spec" , "serviceAccountName" ),
162
+ rayCluster .Spec .HeadGroupSpec .Template .Spec .ServiceAccountName ,
163
+ "RayCluster head group service account is immutable" ))
164
+ }
165
+
166
+ return allErrors
167
+ }
168
+
169
+ func oauthProxyContainer (rayCluster * rayv1.RayCluster ) corev1.Container {
170
+ return corev1.Container {
171
+ Name : oauthProxyContainerName ,
80
172
Image : "registry.redhat.io/openshift4/ose-oauth-proxy@sha256:1ea6a01bf3e63cdcf125c6064cbd4a4a270deaf0f157b3eabb78f60556840366" ,
81
173
Ports : []corev1.ContainerPort {
82
174
{ContainerPort : 8443 , Name : "oauth-proxy" },
@@ -106,59 +198,21 @@ func (w *rayClusterWebhook) Default(ctx context.Context, obj runtime.Object) err
106
198
},
107
199
VolumeMounts : []corev1.VolumeMount {
108
200
{
109
- Name : "proxy-tls-secret" ,
201
+ Name : oauthProxyVolumeName ,
110
202
MountPath : "/etc/tls/private" ,
111
203
ReadOnly : true ,
112
204
},
113
205
},
114
206
}
207
+ }
115
208
116
- rayCluster .Spec .HeadGroupSpec .Template .Spec .Containers = append (rayCluster .Spec .HeadGroupSpec .Template .Spec .Containers , newOAuthSidecar )
117
-
118
- tlsSecretVolume := corev1.Volume {
119
- Name : "proxy-tls-secret" ,
209
+ func oauthProxyTLSSecretVolume (rayCluster * rayv1.RayCluster ) corev1.Volume {
210
+ return corev1.Volume {
211
+ Name : oauthProxyVolumeName ,
120
212
VolumeSource : corev1.VolumeSource {
121
213
Secret : & corev1.SecretVolumeSource {
122
214
SecretName : rayCluster .Name + "-proxy-tls-secret" ,
123
215
},
124
216
},
125
217
}
126
-
127
- rayCluster .Spec .HeadGroupSpec .Template .Spec .Volumes = append (rayCluster .Spec .HeadGroupSpec .Template .Spec .Volumes , tlsSecretVolume )
128
-
129
- // Ensure the service account is set
130
- if rayCluster .Spec .HeadGroupSpec .Template .Spec .ServiceAccountName == "" {
131
- rayCluster .Spec .HeadGroupSpec .Template .Spec .ServiceAccountName = rayCluster .Name + "-oauth-proxy"
132
- }
133
-
134
- return nil
135
- }
136
-
137
- func (w * rayClusterWebhook ) ValidateCreate (ctx context.Context , obj runtime.Object ) (admission.Warnings , error ) {
138
- raycluster := obj .(* rayv1.RayCluster )
139
- var warnings admission.Warnings
140
- var allErrors field.ErrorList
141
- specPath := field .NewPath ("spec" )
142
-
143
- if pointer .BoolDeref (raycluster .Spec .HeadGroupSpec .EnableIngress , false ) {
144
- rayclusterlog .Info ("Creating RayCluster resources with EnableIngress set to true or unspecified is not allowed" )
145
- allErrors = append (allErrors , field .Invalid (specPath .Child ("headGroupSpec" ).Child ("enableIngress" ), raycluster .Spec .HeadGroupSpec .EnableIngress , "creating RayCluster resources with EnableIngress set to true or unspecified is not allowed" ))
146
- }
147
-
148
- return warnings , allErrors .ToAggregate ()
149
- }
150
-
151
- func (w * rayClusterWebhook ) ValidateUpdate (ctx context.Context , oldObj , newObj runtime.Object ) (admission.Warnings , error ) {
152
- newRayCluster := newObj .(* rayv1.RayCluster )
153
- if ! newRayCluster .DeletionTimestamp .IsZero () {
154
- // Object is being deleted, skip validations
155
- return nil , nil
156
- }
157
- warnings , err := w .ValidateCreate (ctx , newRayCluster )
158
- return warnings , err
159
- }
160
-
161
- func (w * rayClusterWebhook ) ValidateDelete (ctx context.Context , obj runtime.Object ) (admission.Warnings , error ) {
162
- // Optional: Add delete validation logic here
163
- return nil , nil
164
218
}
0 commit comments