Skip to content

Commit 512dd9b

Browse files
authored
Merge branch 'main' into clean-up
2 parents 70241e2 + 3ff2e94 commit 512dd9b

File tree

129 files changed

+12127
-2488
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

129 files changed

+12127
-2488
lines changed

api/apps/v1alpha1/common_types.go

Lines changed: 153 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,14 @@ limitations under the License.
1717
package v1alpha1
1818

1919
import (
20+
"fmt"
21+
2022
promv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
2123
autoscalingv2 "k8s.io/api/autoscaling/v2"
2224
corev1 "k8s.io/api/core/v1"
2325
networkingv1 "k8s.io/api/networking/v1"
2426
"k8s.io/utils/ptr"
27+
gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
2528
)
2629

2730
const (
@@ -38,9 +41,58 @@ const (
3841
// Expose defines attributes to expose the service.
3942
type Expose struct {
4043
Service Service `json:"service,omitempty"`
44+
// Deprecated: Use .spec.router instead.
4145
Ingress Ingress `json:"ingress,omitempty"`
4246
}
4347

48+
// +kubebuilder:validation:XValidation:rule="!(has(self.gateway) && has(self.ingress))", message="ingress and gateway cannot be specified together"
49+
type Router struct {
50+
// HostDomainName is the domain name of the hostname matched by the router.
51+
// The hostname is constructed as "<nimServiceName>.<namespace>.<hostDomainName>", where the <nimServiceName> a subdomain of the matched hostname.
52+
// eg. example.com for "<nimServiceName>.<namespace>.example.com"
53+
// +kubebuilder:validation:MinLength=1
54+
// +kubebuilder:validation:MaxLength=63
55+
// +kubebuilder:validation:Pattern=`^(([a-z0-9][a-z0-9\-]*[a-z0-9])|[a-z0-9]+\.)*([a-z]+|xn\-\-[a-z0-9]+)\.?$`
56+
HostDomainName string `json:"hostDomainName,omitempty"`
57+
58+
// Annotations for the router, e.g. for ingress class or gateway
59+
Annotations map[string]string `json:"annotations,omitempty"`
60+
61+
// Ingress is the ingress controller to use for the created ingress.
62+
Ingress *RouterIngress `json:"ingress,omitempty"`
63+
64+
// Gateway is the gateway to use for the created HTTPRoute.
65+
Gateway *Gateway `json:"gateway,omitempty"`
66+
}
67+
68+
type RouterIngress struct {
69+
// +kubebuilder:validation:MinLength=1
70+
// IngressClass is the ingress class to use for the created ingress.
71+
IngressClass string `json:"ingressClass"`
72+
73+
// TLSSecretName is the name of the secret containing the TLS certificate and key.
74+
TLSSecretName string `json:"tlsSecretName,omitempty"`
75+
}
76+
77+
type Gateway struct {
78+
// +kubebuilder:validation:MinLength=1
79+
// Namespace of the gateway
80+
Namespace string `json:"namespace"`
81+
// +kubebuilder:validation:MinLength=1
82+
// Name of the gateway
83+
Name string `json:"name"`
84+
85+
// +kubebuilder:default:=true
86+
// HTTPRoutesEnabled is a flag to enable HTTPRoutes for the created gateway.
87+
HTTPRoutesEnabled bool `json:"httpRoutesEnabled,omitempty"`
88+
}
89+
90+
// DEPRECATED ExposeV1 defines attributes to expose the service.
91+
type ExposeV1 struct {
92+
Service Service `json:"service,omitempty"`
93+
Ingress IngressV1 `json:"ingress,omitempty"`
94+
}
95+
4496
// Service defines attributes to create a service.
4597
type Service struct {
4698
Type corev1.ServiceType `json:"type,omitempty"`
@@ -67,10 +119,13 @@ type Service struct {
67119
Annotations map[string]string `json:"annotations,omitempty"`
68120
}
69121

70-
// ExposeV1 defines attributes to expose the service.
71-
type ExposeV1 struct {
72-
Service Service `json:"service,omitempty"`
73-
Ingress IngressV1 `json:"ingress,omitempty"`
122+
// Deprecated: Use .spec.router.ingress instead.
123+
// IngressV1 defines attributes for ingress
124+
// +kubebuilder:validation:XValidation:rule="(has(self.spec) && has(self.enabled) && self.enabled) || !has(self.enabled) || !self.enabled", message="spec cannot be nil when ingress is enabled"
125+
type IngressV1 struct {
126+
Enabled *bool `json:"enabled,omitempty"`
127+
Annotations map[string]string `json:"annotations,omitempty"`
128+
Spec *IngressSpec `json:"spec,omitempty"`
74129
}
75130

76131
// Metrics defines attributes to setup metrics collection.
@@ -119,15 +174,6 @@ type Ingress struct {
119174
Spec networkingv1.IngressSpec `json:"spec,omitempty"`
120175
}
121176

122-
// IngressV1 defines attributes for ingress
123-
//
124-
// +kubebuilder:validation:XValidation:rule="(has(self.spec) && has(self.enabled) && self.enabled) || !has(self.enabled) || !self.enabled", message="spec cannot be nil when ingress is enabled"
125-
type IngressV1 struct {
126-
Enabled *bool `json:"enabled,omitempty"`
127-
Annotations map[string]string `json:"annotations,omitempty"`
128-
Spec *IngressSpec `json:"spec,omitempty"`
129-
}
130-
131177
// ResourceRequirements defines the resources required for a container.
132178
type ResourceRequirements struct {
133179
// Limits describes the maximum amount of compute resources allowed.
@@ -184,6 +230,100 @@ func (i *IngressV1) GenerateNetworkingV1IngressSpec(name string) networkingv1.In
184230
return ingressSpec
185231
}
186232

233+
func (r *Router) GenerateGatewayHTTPRouteSpec(namespace, name string, port int32) gatewayv1.HTTPRouteSpec {
234+
if r.Gateway == nil || !r.Gateway.HTTPRoutesEnabled {
235+
return gatewayv1.HTTPRouteSpec{}
236+
}
237+
238+
return gatewayv1.HTTPRouteSpec{
239+
CommonRouteSpec: gatewayv1.CommonRouteSpec{
240+
ParentRefs: []gatewayv1.ParentReference{
241+
{
242+
Name: gatewayv1.ObjectName(r.Gateway.Name),
243+
Namespace: ptr.To(gatewayv1.Namespace(r.Gateway.Namespace)),
244+
},
245+
},
246+
},
247+
Hostnames: []gatewayv1.Hostname{gatewayv1.Hostname(r.getHostname(namespace, name))},
248+
Rules: []gatewayv1.HTTPRouteRule{
249+
{
250+
BackendRefs: []gatewayv1.HTTPBackendRef{
251+
{
252+
BackendRef: gatewayv1.BackendRef{
253+
BackendObjectReference: gatewayv1.BackendObjectReference{
254+
Name: gatewayv1.ObjectName(name),
255+
Port: ptr.To(gatewayv1.PortNumber(port)),
256+
},
257+
},
258+
},
259+
},
260+
Matches: []gatewayv1.HTTPRouteMatch{
261+
{
262+
Path: &gatewayv1.HTTPPathMatch{
263+
Type: ptr.To(gatewayv1.PathMatchPathPrefix),
264+
Value: ptr.To("/"),
265+
},
266+
},
267+
},
268+
},
269+
},
270+
}
271+
}
272+
273+
func (r *Router) getHostname(namespace, name string) string {
274+
return fmt.Sprintf("%s.%s.%s", name, namespace, r.HostDomainName)
275+
}
276+
277+
func (r *Router) GenerateIngressSpec(namespace, name string) networkingv1.IngressSpec {
278+
if r.Ingress == nil {
279+
return networkingv1.IngressSpec{}
280+
}
281+
282+
ingressSpec := networkingv1.IngressSpec{
283+
IngressClassName: ptr.To(r.Ingress.IngressClass),
284+
Rules: []networkingv1.IngressRule{
285+
{
286+
Host: r.getHostname(namespace, name),
287+
IngressRuleValue: networkingv1.IngressRuleValue{
288+
HTTP: &networkingv1.HTTPIngressRuleValue{
289+
Paths: []networkingv1.HTTPIngressPath{
290+
{
291+
Path: "/",
292+
PathType: ptr.To(networkingv1.PathTypePrefix),
293+
Backend: networkingv1.IngressBackend{
294+
Service: &networkingv1.IngressServiceBackend{
295+
Name: name,
296+
Port: networkingv1.ServiceBackendPort{
297+
Name: DefaultNamedPortAPI,
298+
},
299+
},
300+
},
301+
},
302+
},
303+
},
304+
},
305+
},
306+
},
307+
}
308+
309+
if r.Ingress.TLSSecretName != "" {
310+
ingressSpec.TLS = []networkingv1.IngressTLS{
311+
{
312+
Hosts: []string{r.getHostname(namespace, name)},
313+
SecretName: r.Ingress.TLSSecretName,
314+
},
315+
}
316+
}
317+
return ingressSpec
318+
}
319+
320+
func (r *Expose) GenerateIngressSpec(name string) networkingv1.IngressSpec {
321+
if r.Ingress.Enabled == nil || !*r.Ingress.Enabled {
322+
return networkingv1.IngressSpec{}
323+
}
324+
return r.Ingress.Spec
325+
}
326+
187327
type IngressSpec struct {
188328
// +kubebuilder:validation:Pattern=`[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*`
189329
IngressClassName string `json:"ingressClassName"`

api/apps/v1alpha1/nemo_customizer_types.go

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import (
3333
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3434
"k8s.io/apimachinery/pkg/util/intstr"
3535
"k8s.io/utils/ptr"
36+
gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
3637

3738
rendertypes "github.com/NVIDIA/k8s-nim-operator/internal/render/types"
3839
utils "github.com/NVIDIA/k8s-nim-operator/internal/utils"
@@ -66,6 +67,7 @@ const (
6667
)
6768

6869
// NemoCustomizerSpec defines the desired state of NemoCustomizer.
70+
// +kubebuilder:validation:XValidation:rule="!(has(self.expose.ingress) && has(self.expose.ingress.enabled) && self.expose.ingress.enabled && has(self.router) && has(self.router.ingress))", message=".spec.expose.ingress is deprecated, and will be removed in a future release. If .spec.expose.ingress is set, please do not set .spec.router.ingress."
6971
type NemoCustomizerSpec struct {
7072
Image Image `json:"image"`
7173
Command []string `json:"command,omitempty"`
@@ -80,6 +82,7 @@ type NemoCustomizerSpec struct {
8082
// +kubebuilder:validation:XValidation:rule="!(has(self.service.grpcPort))", message="unsupported field: spec.expose.service.grpcPort"
8183
// +kubebuilder:validation:XValidation:rule="!(has(self.service.metricsPort))", message="unsupported field: spec.expose.service.metricsPort"
8284
Expose ExposeV1 `json:"expose,omitempty"`
85+
Router Router `json:"router,omitempty"`
8386
Scale Autoscaling `json:"scale,omitempty"`
8487
Metrics Metrics `json:"metrics,omitempty"`
8588

@@ -635,12 +638,25 @@ func (n *NemoCustomizer) IsAutoScalingEnabled() bool {
635638

636639
// IsIngressEnabled returns true if ingress is enabled for NemoCustomizer deployment.
637640
func (n *NemoCustomizer) IsIngressEnabled() bool {
638-
return n.Spec.Expose.Ingress.Enabled != nil && *n.Spec.Expose.Ingress.Enabled
641+
return (n.Spec.Router.Ingress != nil && n.Spec.Router.Ingress.IngressClass != "") ||
642+
(n.Spec.Expose.Ingress.Enabled != nil && *n.Spec.Expose.Ingress.Enabled) // TODO deprecate this once we have removed the .spec.expose.ingress field from the spec
639643
}
640644

641645
// GetIngressSpec returns the Ingress spec NemoCustomizer deployment.
642646
func (n *NemoCustomizer) GetIngressSpec() networkingv1.IngressSpec {
643-
return n.Spec.Expose.Ingress.GenerateNetworkingV1IngressSpec(n.GetName())
647+
// TODO deprecate this once we have removed the .spec.expose.ingress field from the spec
648+
if n.Spec.Expose.Ingress.Enabled != nil && *n.Spec.Expose.Ingress.Enabled {
649+
return n.Spec.Expose.Ingress.GenerateNetworkingV1IngressSpec(n.GetName())
650+
}
651+
return n.Spec.Router.GenerateIngressSpec(n.GetNamespace(), n.GetName())
652+
}
653+
654+
func (n *NemoCustomizer) IsHTTPRouteEnabled() bool {
655+
return n.Spec.Router.Gateway != nil && n.Spec.Router.Gateway.HTTPRoutesEnabled
656+
}
657+
658+
func (n *NemoCustomizer) GetHTTPRouteSpec() gatewayv1.HTTPRouteSpec {
659+
return n.Spec.Router.GenerateGatewayHTTPRouteSpec(n.GetNamespace(), n.GetName(), n.GetServicePort())
644660
}
645661

646662
// IsServiceMonitorEnabled returns true if servicemonitor is enabled for NemoCustomizer deployment.
@@ -839,6 +855,20 @@ func (n *NemoCustomizer) GetIngressParams() *rendertypes.IngressParams {
839855
return params
840856
}
841857

858+
// GetHTTPRouteParams returns params to render HTTPRoute from templates.
859+
func (n *NemoCustomizer) GetHTTPRouteParams() *rendertypes.HTTPRouteParams {
860+
params := &rendertypes.HTTPRouteParams{}
861+
params.Enabled = n.IsHTTPRouteEnabled()
862+
863+
// Set metadata
864+
params.Name = n.GetName()
865+
params.Namespace = n.GetNamespace()
866+
params.Labels = n.GetServiceLabels()
867+
params.Annotations = n.GetHTTPRouteAnnotations()
868+
params.Spec = n.GetHTTPRouteSpec()
869+
return params
870+
}
871+
842872
// GetRoleParams returns params to render Role from templates.
843873
func (n *NemoCustomizer) GetRoleParams() *rendertypes.RoleParams {
844874
params := &rendertypes.RoleParams{}
@@ -1017,12 +1047,25 @@ func (n *NemoCustomizer) GetServicePort() int32 {
10171047
func (n *NemoCustomizer) GetIngressAnnotations() map[string]string {
10181048
NemoCustomizerAnnotations := n.GetNemoCustomizerAnnotations()
10191049

1020-
if n.Spec.Expose.Ingress.Annotations != nil {
1050+
// TODO deprecate this once we have removed the .spec.expose.ingress field from the spec
1051+
if n.Spec.Expose.Ingress.Enabled != nil && *n.Spec.Expose.Ingress.Enabled {
10211052
return utils.MergeMaps(NemoCustomizerAnnotations, n.Spec.Expose.Ingress.Annotations)
10221053
}
1054+
if n.Spec.Router.Annotations != nil {
1055+
return utils.MergeMaps(NemoCustomizerAnnotations, n.Spec.Router.Annotations)
1056+
}
10231057
return NemoCustomizerAnnotations
10241058
}
10251059

1060+
func (n *NemoCustomizer) GetHTTPRouteAnnotations() map[string]string {
1061+
annotations := n.GetNemoCustomizerAnnotations()
1062+
1063+
if n.Spec.Router.Annotations != nil {
1064+
return utils.MergeMaps(annotations, n.Spec.Router.Annotations)
1065+
}
1066+
return annotations
1067+
}
1068+
10261069
// GetServiceAnnotations return standard and customized service annotations.
10271070
func (n *NemoCustomizer) GetServiceAnnotations() map[string]string {
10281071
NemoCustomizerAnnotations := n.GetNemoCustomizerAnnotations()

0 commit comments

Comments
 (0)