diff --git a/api/v1alpha/groupversion_info.go b/api/v1alpha/groupversion_info.go index c63cb446..4f890ace 100644 --- a/api/v1alpha/groupversion_info.go +++ b/api/v1alpha/groupversion_info.go @@ -42,6 +42,10 @@ func addKnownTypes(scheme *runtime.Scheme) error { &NetworkInterfaceList{}, &NetworkInterfaceClaim{}, &NetworkInterfaceClaimList{}, + &NetworkLoadBalancer{}, + &NetworkLoadBalancerList{}, + &NetworkLoadBalancerRoute{}, + &NetworkLoadBalancerRouteList{}, &NetworkPolicy{}, &NetworkPolicyList{}, &NetworkService{}, diff --git a/api/v1alpha/networkloadbalancer_schema_test.go b/api/v1alpha/networkloadbalancer_schema_test.go new file mode 100644 index 00000000..125d7f01 --- /dev/null +++ b/api/v1alpha/networkloadbalancer_schema_test.go @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +package v1alpha_test + +import ( + "context" + "fmt" + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/require" + networkingv1alpha "go.datum.net/network-services-operator/api/v1alpha" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/envtest" + "sigs.k8s.io/yaml" +) + +func TestNetworkLoadBalancerAdmission(t *testing.T) { + if os.Getenv("KUBEBUILDER_ASSETS") == "" { + t.Skip("envtest assets are required") + } + + crds := make([]*apiextensionsv1.CustomResourceDefinition, 0, 2) + for _, name := range []string{"networkloadbalancers", "networkloadbalancerroutes"} { + data, err := os.ReadFile(filepath.Join("..", "..", "config", "crd", "bases", "networking.datumapis.com_"+name+".yaml")) + require.NoError(t, err) + var crd apiextensionsv1.CustomResourceDefinition + require.NoError(t, yaml.Unmarshal(data, &crd)) + crds = append(crds, &crd) + } + + env := &envtest.Environment{CRDs: crds} + cfg, err := env.Start() + require.NoError(t, err) + t.Cleanup(func() { require.NoError(t, env.Stop()) }) + + scheme := runtime.NewScheme() + require.NoError(t, networkingv1alpha.AddToScheme(scheme)) + k8sClient, err := client.New(cfg, client.Options{Scheme: scheme}) + require.NoError(t, err) + + base := &networkingv1alpha.NetworkLoadBalancer{ + ObjectMeta: metav1.ObjectMeta{Name: "valid", Namespace: "default"}, + Spec: networkingv1alpha.NetworkLoadBalancerSpec{ + NetworkRef: networkingv1alpha.LocalNetworkRef{Name: "default"}, + Exposure: networkingv1alpha.NetworkLoadBalancerExposure{Addresses: []networkingv1alpha.NetworkLoadBalancerAddressRequest{{ + Name: "regional", + Families: []networkingv1alpha.IPFamily{networkingv1alpha.IPv6Protocol}, + }}}, + Listeners: []networkingv1alpha.NetworkLoadBalancerListener{ + {Name: "tcp", Protocol: networkingv1alpha.NetworkLoadBalancerProtocolTCP, Port: 443, AddressRefs: []string{"regional"}}, + {Name: "udp", Protocol: networkingv1alpha.NetworkLoadBalancerProtocolUDP, Port: 443, AddressRefs: []string{"regional"}}, + }, + }, + } + + tests := []struct { + name string + mutate func(*networkingv1alpha.NetworkLoadBalancer) + valid bool + }{ + {name: "TCP and UDP share a port", valid: true}, + {name: "IPv4 retained in API for capability gating", valid: true, mutate: func(lb *networkingv1alpha.NetworkLoadBalancer) { + lb.Spec.Exposure.Addresses[0].Families = []networkingv1alpha.IPFamily{networkingv1alpha.IPv4Protocol, networkingv1alpha.IPv6Protocol} + }}, + {name: "duplicate family rejected", mutate: func(lb *networkingv1alpha.NetworkLoadBalancer) { + lb.Spec.Exposure.Addresses[0].Families = []networkingv1alpha.IPFamily{networkingv1alpha.IPv6Protocol, networkingv1alpha.IPv6Protocol} + }}, + {name: "missing address reference", mutate: func(lb *networkingv1alpha.NetworkLoadBalancer) { + lb.Spec.Listeners[0].AddressRefs = []string{"missing"} + }}, + {name: "same transport and port conflict", mutate: func(lb *networkingv1alpha.NetworkLoadBalancer) { + lb.Spec.Listeners = append(lb.Spec.Listeners, networkingv1alpha.NetworkLoadBalancerListener{Name: "second-tcp", Protocol: networkingv1alpha.NetworkLoadBalancerProtocolTCP, Port: 443, AddressRefs: []string{"regional"}}) + }}, + {name: "Names requires location names", mutate: func(lb *networkingv1alpha.NetworkLoadBalancer) { + lb.Spec.Exposure.Addresses[0].Locations = &networkingv1alpha.NetworkLoadBalancerLocationSelection{From: networkingv1alpha.NetworkLoadBalancerLocationSourceNames} + }}, + {name: "All excludes location names", mutate: func(lb *networkingv1alpha.NetworkLoadBalancer) { + lb.Spec.Exposure.Addresses[0].Locations = &networkingv1alpha.NetworkLoadBalancerLocationSelection{From: networkingv1alpha.NetworkLoadBalancerLocationSourceAll, Names: []string{"us-east-1"}} + }}, + } + for i, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + lb := base.DeepCopy() + lb.Name = fmt.Sprintf("case-%d", i) + if tt.mutate != nil { + tt.mutate(lb) + } + err := k8sClient.Create(context.Background(), lb) + if tt.valid { + require.NoError(t, err) + lb.Status.Endpoints = []networkingv1alpha.NetworkLoadBalancerEndpointStatus{ + {RequestName: "regional", Location: "us-east-1", Addresses: []networkingv1alpha.NetworkLoadBalancerAddressStatus{{Family: networkingv1alpha.IPv6Protocol, Value: "2001:db8::10"}}}, + {RequestName: "regional", Location: "us-west-1", Addresses: []networkingv1alpha.NetworkLoadBalancerAddressStatus{{Family: networkingv1alpha.IPv6Protocol, Value: "2001:db8::20"}}}, + } + require.NoError(t, k8sClient.Status().Update(context.Background(), lb)) + } else { + require.Error(t, err) + } + }) + } + + route := &networkingv1alpha.NetworkLoadBalancerRoute{ + ObjectMeta: metav1.ObjectMeta{Namespace: "default"}, + Spec: networkingv1alpha.NetworkLoadBalancerRouteSpec{ + ParentRefs: []networkingv1alpha.NetworkLoadBalancerRouteParentRef{{Name: "valid", Listener: "tcp"}}, + Backends: []networkingv1alpha.NetworkLoadBalancerRouteBackend{{ + NetworkService: networkingv1alpha.NetworkLoadBalancerNetworkServiceRef{Name: "app", Port: "main"}, + }}, + }, + } + + routeTests := []struct { + name string + mutate func(*networkingv1alpha.NetworkLoadBalancerRoute) + valid bool + }{ + {name: "valid route", valid: true}, + {name: "multiple backends retained in API", valid: true, mutate: func(r *networkingv1alpha.NetworkLoadBalancerRoute) { + r.Spec.Backends = append(r.Spec.Backends, networkingv1alpha.NetworkLoadBalancerRouteBackend{NetworkService: networkingv1alpha.NetworkLoadBalancerNetworkServiceRef{Name: "other", Port: "main"}}) + }}, + {name: "TCP path rejected", mutate: func(r *networkingv1alpha.NetworkLoadBalancerRoute) { + r.Spec.Backends[0].HealthCheck = &networkingv1alpha.NetworkLoadBalancerHealthCheck{Protocol: "TCP", Path: "/health"} + }}, + {name: "HTTP probe requires port", mutate: func(r *networkingv1alpha.NetworkLoadBalancerRoute) { + r.Spec.Backends[0].HealthCheck = &networkingv1alpha.NetworkLoadBalancerHealthCheck{Protocol: "HTTP", Path: "/health"} + }}, + } + for i, tt := range routeTests { + t.Run(tt.name, func(t *testing.T) { + r := route.DeepCopy() + r.Name = fmt.Sprintf("route-%d", i) + if tt.mutate != nil { + tt.mutate(r) + } + err := k8sClient.Create(context.Background(), r) + if tt.valid { + require.NoError(t, err) + } else { + require.Error(t, err) + } + }) + } +} diff --git a/api/v1alpha/networkloadbalancer_types.go b/api/v1alpha/networkloadbalancer_types.go new file mode 100644 index 00000000..12840fb0 --- /dev/null +++ b/api/v1alpha/networkloadbalancer_types.go @@ -0,0 +1,240 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +package v1alpha + +import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + +const ( + NetworkLoadBalancerAllocated = "Allocated" + NetworkLoadBalancerProgrammed = "Programmed" + NetworkLoadBalancerReady = "Ready" + NetworkLoadBalancerAnnounced = "Announced" + NetworkLoadBalancerDNSPublished = "DNSPublished" +) + +// NetworkLoadBalancerLocationSource selects locations by name or follows all +// eligible locations as they become available. +// +kubebuilder:validation:Enum=Backends;All;Names +type NetworkLoadBalancerLocationSource string + +const ( + NetworkLoadBalancerLocationSourceBackends NetworkLoadBalancerLocationSource = "Backends" + NetworkLoadBalancerLocationSourceAll NetworkLoadBalancerLocationSource = "All" + NetworkLoadBalancerLocationSourceNames NetworkLoadBalancerLocationSource = "Names" +) + +// NetworkLoadBalancerProtocol is the transport accepted by a listener. +// +kubebuilder:validation:Enum=TCP;UDP;TLS +type NetworkLoadBalancerProtocol string + +const ( + NetworkLoadBalancerProtocolTCP NetworkLoadBalancerProtocol = "TCP" + NetworkLoadBalancerProtocolUDP NetworkLoadBalancerProtocol = "UDP" + NetworkLoadBalancerProtocolTLS NetworkLoadBalancerProtocol = "TLS" +) + +// NetworkLoadBalancerLocationSelection chooses where an address may be served. +// +kubebuilder:validation:XValidation:message="names must be set only when from is Names",rule="self.from == 'Names' ? has(self.names) && size(self.names) > 0 : !has(self.names)" +type NetworkLoadBalancerLocationSelection struct { + // +kubebuilder:validation:Required + From NetworkLoadBalancerLocationSource `json:"from"` + + // +kubebuilder:validation:Optional + // +kubebuilder:validation:MinItems=1 + // +kubebuilder:validation:MaxItems=64 + // +listType=set + Names []string `json:"names,omitempty"` +} + +// NetworkLoadBalancerAddressRequest reserves one public address per selected +// location, independently of whether a route has healthy backends. +type NetworkLoadBalancerAddressRequest struct { + // +kubebuilder:validation:Required + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=63 + // +kubebuilder:validation:Pattern=`^[a-z0-9]([-a-z0-9]*[a-z0-9])?$` + Name string `json:"name"` + + // +kubebuilder:validation:Required + // +kubebuilder:validation:MinItems=1 + // +kubebuilder:validation:MaxItems=2 + // +listType=set + Families []IPFamily `json:"families"` + + // Omission follows the effective backends' network interfaces. + // +kubebuilder:validation:Optional + Locations *NetworkLoadBalancerLocationSelection `json:"locations,omitempty"` +} + +type NetworkLoadBalancerTLSMode string + +const ( + NetworkLoadBalancerTLSModePassthrough NetworkLoadBalancerTLSMode = "Passthrough" + NetworkLoadBalancerTLSModeTerminate NetworkLoadBalancerTLSMode = "Terminate" +) + +// +kubebuilder:validation:XValidation:message="Terminate requires a certificate; Passthrough omits it",rule="self.mode == 'Terminate' ? has(self.certificateRef) : !has(self.certificateRef)" +type NetworkLoadBalancerTLS struct { + // +kubebuilder:validation:Enum=Passthrough;Terminate + Mode NetworkLoadBalancerTLSMode `json:"mode"` + // Secret references are admitted only after TLS termination is supported. + CertificateRef *LocalSecretRef `json:"certificateRef,omitempty"` +} + +type LocalSecretRef struct { + // Name identifies a Secret in the listener's namespace. + Name string `json:"name"` + // Cross-namespace access is capability-gated until grants are supported. + Namespace string `json:"namespace,omitempty"` +} + +// NetworkLoadBalancerExposure contains the load balancer's address requests. +type NetworkLoadBalancerExposure struct { + // +kubebuilder:validation:Required + // +kubebuilder:validation:MinItems=1 + // +kubebuilder:validation:MaxItems=16 + // +listType=map + // +listMapKey=name + Addresses []NetworkLoadBalancerAddressRequest `json:"addresses"` +} + +// NetworkLoadBalancerListener accepts one transport and port on its named +// address requests. TCP and UDP may use the same port. +type NetworkLoadBalancerListener struct { + // +kubebuilder:validation:Required + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=63 + // +kubebuilder:validation:Pattern=`^[a-z0-9]([-a-z0-9]*[a-z0-9])?$` + Name string `json:"name"` + + // +kubebuilder:validation:Required + Protocol NetworkLoadBalancerProtocol `json:"protocol"` + + // +kubebuilder:validation:Required + // +kubebuilder:validation:Minimum=1 + // +kubebuilder:validation:Maximum=65535 + Port int32 `json:"port"` + + // +kubebuilder:validation:Required + // +kubebuilder:validation:MinItems=1 + // +kubebuilder:validation:MaxItems=16 + // +listType=set + AddressRefs []string `json:"addressRefs"` + + // +kubebuilder:validation:Optional + Hostname string `json:"hostname,omitempty"` + + // +kubebuilder:validation:Optional + TLS *NetworkLoadBalancerTLS `json:"tls,omitempty"` +} + +// NetworkLoadBalancerSpec defines the network, public addresses, and listeners. +// +kubebuilder:validation:XValidation:message="each listener address reference must name an address request",rule="self.listeners.all(l, l.addressRefs.all(r, r in self.exposure.addresses.map(a, a.name)))" +// +kubebuilder:validation:XValidation:message="listeners sharing an address cannot use the same protocol and port",rule="self.listeners.all(l1, self.listeners.all(l2, l1.name == l2.name || l1.protocol != l2.protocol || l1.port != l2.port || !l1.addressRefs.exists(r, r in l2.addressRefs)))" +// +kubebuilder:validation:XValidation:message="TLS configuration is required only for TLS listeners",rule="self.listeners.all(l, l.protocol == 'TLS' ? has(l.tls) : !has(l.tls))" +type NetworkLoadBalancerSpec struct { + // The network must exist in the load balancer's namespace. + // +kubebuilder:validation:Required + // +kubebuilder:validation:XValidation:message="networkRef is immutable",rule="self == oldSelf" + NetworkRef LocalNetworkRef `json:"networkRef"` + + // +kubebuilder:validation:Required + Exposure NetworkLoadBalancerExposure `json:"exposure"` + + // +kubebuilder:validation:Required + // +kubebuilder:validation:MinItems=1 + // +kubebuilder:validation:MaxItems=16 + // +listType=map + // +listMapKey=name + Listeners []NetworkLoadBalancerListener `json:"listeners"` +} + +// NetworkLoadBalancerIPClaimRef identifies the claim holding an allocated IP. +type NetworkLoadBalancerIPClaimRef struct { + Project string `json:"project"` + Namespace string `json:"namespace"` + Name string `json:"name"` + // UID distinguishes a recreated claim with the same name from the old allocation. + UID string `json:"uid,omitempty"` +} + +// NetworkLoadBalancerAddressStatus describes one family at a location. +type NetworkLoadBalancerAddressStatus struct { + Family IPFamily `json:"family"` + Value string `json:"value,omitempty"` + ClaimRef *NetworkLoadBalancerIPClaimRef `json:"claimRef,omitempty"` + Announced bool `json:"announced,omitempty"` + DNSPublished bool `json:"dnsPublished,omitempty"` + Reason string `json:"reason,omitempty"` + Message string `json:"message,omitempty"` + + // Conditions include Allocated, Programmed, and Announced with + // observedGeneration. An entry with no value reports a pending or failed + // allocation for this request/location. + // +listType=map + // +listMapKey=type + Conditions []metav1.Condition `json:"conditions,omitempty"` +} + +// NetworkLoadBalancerEndpointStatus is stable for one address request and +// location, even while individual address families are unavailable. +type NetworkLoadBalancerEndpointStatus struct { + RequestName string `json:"requestName"` + Location string `json:"location"` + CanonicalHostname string `json:"canonicalHostname,omitempty"` + // +listType=map + // +listMapKey=family + Addresses []NetworkLoadBalancerAddressStatus `json:"addresses,omitempty"` +} + +type NetworkLoadBalancerAddressRequestStatus struct { + Name string `json:"name"` + LocationSource NetworkLoadBalancerLocationSource `json:"locationSource"` + // +listType=set + ResolvedLocations []string `json:"resolvedLocations,omitempty"` +} + +// NetworkLoadBalancerStatus distinguishes address allocation from programming +// and announcement. Allocated IPs remain here during backend failures. +type NetworkLoadBalancerStatus struct { + // Conditions include Allocated, Programmed, and Ready with observedGeneration. + // +listType=map + // +listMapKey=type + Conditions []metav1.Condition `json:"conditions,omitempty"` + + // +kubebuilder:validation:MaxItems=16 + // +listType=map + // +listMapKey=name + AddressRequests []NetworkLoadBalancerAddressRequestStatus `json:"addressRequests,omitempty"` + + // +kubebuilder:validation:MaxItems=1024 + // +listType=map + // +listMapKey=requestName + // +listMapKey=location + Endpoints []NetworkLoadBalancerEndpointStatus `json:"endpoints,omitempty"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:printcolumn:name="Ready",type=string,JSONPath=`.status.conditions[?(@.type=="Ready")].status` +// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=".metadata.creationTimestamp" + +// NetworkLoadBalancer reserves public IPs and accepts TCP or UDP traffic on +// named listeners. Route objects attach backends to those listeners. +type NetworkLoadBalancer struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + // +kubebuilder:validation:Required + Spec NetworkLoadBalancerSpec `json:"spec"` + Status NetworkLoadBalancerStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// NetworkLoadBalancerList contains a list of NetworkLoadBalancer objects. +type NetworkLoadBalancerList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []NetworkLoadBalancer `json:"items"` +} diff --git a/api/v1alpha/networkloadbalancerroute_types.go b/api/v1alpha/networkloadbalancerroute_types.go new file mode 100644 index 00000000..fd24b0d9 --- /dev/null +++ b/api/v1alpha/networkloadbalancerroute_types.go @@ -0,0 +1,153 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +package v1alpha + +import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + +const ( + NetworkLoadBalancerRouteAccepted = "Accepted" + NetworkLoadBalancerRouteResolvedRefs = "ResolvedRefs" + NetworkLoadBalancerRouteProgrammed = "Programmed" +) + +// NetworkLoadBalancerRouteParentRef attaches a route to a listener. Cross- +// namespace references are capability-gated initially. Either listener name or +// port selects a listener; status always reports its resolved name. +// +kubebuilder:validation:XValidation:message="exactly one of listener or port is required",rule="has(self.listener) != has(self.port)" +type NetworkLoadBalancerRouteParentRef struct { + // +kubebuilder:validation:Required + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=253 + Name string `json:"name"` + + // One of listener or port selects the parent listener. + // +kubebuilder:validation:Optional + Listener string `json:"listener,omitempty"` + // +kubebuilder:validation:Optional + Port *int32 `json:"port,omitempty"` + // +kubebuilder:validation:Optional + Namespace string `json:"namespace,omitempty"` +} + +// NetworkLoadBalancerNetworkServiceRef names a backend service and one of its +// named ports in the route's namespace. +type NetworkLoadBalancerNetworkServiceRef struct { + // +kubebuilder:validation:Required + Name string `json:"name"` + + // +kubebuilder:validation:Required + Port string `json:"port"` + // +kubebuilder:validation:Optional + Namespace string `json:"namespace,omitempty"` +} + +// NetworkLoadBalancerHealthCheck checks an individual backend endpoint. UDP +// backends require a separate TCP, HTTP, or HTTPS health endpoint. +// +kubebuilder:validation:XValidation:message="path is only valid for HTTP and HTTPS probes",rule="has(self.path) ? self.protocol in ['HTTP', 'HTTPS'] : true" +// +kubebuilder:validation:XValidation:message="HTTP and HTTPS probes require a port",rule="self.protocol == 'TCP' || has(self.port)" +type NetworkLoadBalancerHealthCheck struct { + // +kubebuilder:validation:Required + // +kubebuilder:validation:Enum=TCP;HTTP;HTTPS + Protocol string `json:"protocol"` + + // Name of the probe port on the referenced NetworkService. When omitted, + // TCP probes use the backend's serving port. + // +kubebuilder:validation:Optional + Port string `json:"port,omitempty"` + + // +kubebuilder:validation:Optional + // +kubebuilder:validation:Pattern=`^/.*$` + Path string `json:"path,omitempty"` + // +kubebuilder:validation:Minimum=1 + IntervalSeconds *int32 `json:"intervalSeconds,omitempty"` + // +kubebuilder:validation:Minimum=1 + TimeoutSeconds *int32 `json:"timeoutSeconds,omitempty"` + // +kubebuilder:validation:Minimum=1 + HealthyThreshold *int32 `json:"healthyThreshold,omitempty"` + // +kubebuilder:validation:Minimum=1 + UnhealthyThreshold *int32 `json:"unhealthyThreshold,omitempty"` +} + +// NetworkLoadBalancerRouteBackend forwards new connections or flows to a +// named NetworkService port. +type NetworkLoadBalancerRouteBackend struct { + // +kubebuilder:validation:Required + NetworkService NetworkLoadBalancerNetworkServiceRef `json:"networkService"` + + // +kubebuilder:validation:Optional + HealthCheck *NetworkLoadBalancerHealthCheck `json:"healthCheck,omitempty"` + // Backend TLS requires a proxy-capable serving path. + // +kubebuilder:validation:Optional + Transport *NetworkLoadBalancerBackendTransport `json:"transport,omitempty"` +} + +type NetworkLoadBalancerBackendTransport struct { + // +kubebuilder:validation:Enum=TCP;TLS + Protocol string `json:"protocol"` + ServerName string `json:"serverName,omitempty"` + CABundleRef *LocalSecretRef `json:"caBundleRef,omitempty"` +} + +// NetworkLoadBalancerRouteSpec attaches backends to named listeners. +type NetworkLoadBalancerRouteSpec struct { + // +kubebuilder:validation:Required + // +kubebuilder:validation:MinItems=1 + // +kubebuilder:validation:MaxItems=16 + // +listType=atomic + ParentRefs []NetworkLoadBalancerRouteParentRef `json:"parentRefs"` + + // +kubebuilder:validation:Required + // +kubebuilder:validation:MinItems=1 + // +kubebuilder:validation:MaxItems=16 + Backends []NetworkLoadBalancerRouteBackend `json:"backends"` + + // SNI routing is capability-gated until TLS listeners are served. + // +kubebuilder:validation:Optional + SNIHostnames []string `json:"sniHostnames,omitempty"` +} + +// NetworkLoadBalancerRouteParentStatus reports attachment and effectiveness +// for one parent listener. The oldest accepted catch-all route is effective. +type NetworkLoadBalancerRouteParentStatus struct { + Name string `json:"name"` + Listener string `json:"listener"` + Effective bool `json:"effective"` + + // Conditions include Accepted, ResolvedRefs, and Programmed with + // observedGeneration. + // +listType=map + // +listMapKey=type + Conditions []metav1.Condition `json:"conditions,omitempty"` +} + +type NetworkLoadBalancerRouteStatus struct { + // +kubebuilder:validation:MaxItems=16 + // +listType=map + // +listMapKey=name + // +listMapKey=listener + Parents []NetworkLoadBalancerRouteParentStatus `json:"parents,omitempty"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=".metadata.creationTimestamp" + +// NetworkLoadBalancerRoute connects load balancer listeners to NetworkService +// backends. References are restricted to the route's namespace. +type NetworkLoadBalancerRoute struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + // +kubebuilder:validation:Required + Spec NetworkLoadBalancerRouteSpec `json:"spec"` + Status NetworkLoadBalancerRouteStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// NetworkLoadBalancerRouteList contains a list of NetworkLoadBalancerRoute objects. +type NetworkLoadBalancerRouteList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []NetworkLoadBalancerRoute `json:"items"` +} diff --git a/api/v1alpha/zz_generated.deepcopy.go b/api/v1alpha/zz_generated.deepcopy.go index 5572dbc4..f46f7b34 100644 --- a/api/v1alpha/zz_generated.deepcopy.go +++ b/api/v1alpha/zz_generated.deepcopy.go @@ -835,6 +835,21 @@ func (in *LocalNetworkRef) DeepCopy() *LocalNetworkRef { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LocalSecretRef) DeepCopyInto(out *LocalSecretRef) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LocalSecretRef. +func (in *LocalSecretRef) DeepCopy() *LocalSecretRef { + if in == nil { + return nil + } + out := new(LocalSecretRef) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *LocalSubnetReference) DeepCopyInto(out *LocalSubnetReference) { *out = *in @@ -1834,6 +1849,574 @@ func (in *NetworkList) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkLoadBalancer) DeepCopyInto(out *NetworkLoadBalancer) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkLoadBalancer. +func (in *NetworkLoadBalancer) DeepCopy() *NetworkLoadBalancer { + if in == nil { + return nil + } + out := new(NetworkLoadBalancer) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *NetworkLoadBalancer) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkLoadBalancerAddressRequest) DeepCopyInto(out *NetworkLoadBalancerAddressRequest) { + *out = *in + if in.Families != nil { + in, out := &in.Families, &out.Families + *out = make([]IPFamily, len(*in)) + copy(*out, *in) + } + if in.Locations != nil { + in, out := &in.Locations, &out.Locations + *out = new(NetworkLoadBalancerLocationSelection) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkLoadBalancerAddressRequest. +func (in *NetworkLoadBalancerAddressRequest) DeepCopy() *NetworkLoadBalancerAddressRequest { + if in == nil { + return nil + } + out := new(NetworkLoadBalancerAddressRequest) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkLoadBalancerAddressRequestStatus) DeepCopyInto(out *NetworkLoadBalancerAddressRequestStatus) { + *out = *in + if in.ResolvedLocations != nil { + in, out := &in.ResolvedLocations, &out.ResolvedLocations + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkLoadBalancerAddressRequestStatus. +func (in *NetworkLoadBalancerAddressRequestStatus) DeepCopy() *NetworkLoadBalancerAddressRequestStatus { + if in == nil { + return nil + } + out := new(NetworkLoadBalancerAddressRequestStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkLoadBalancerAddressStatus) DeepCopyInto(out *NetworkLoadBalancerAddressStatus) { + *out = *in + if in.ClaimRef != nil { + in, out := &in.ClaimRef, &out.ClaimRef + *out = new(NetworkLoadBalancerIPClaimRef) + **out = **in + } + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkLoadBalancerAddressStatus. +func (in *NetworkLoadBalancerAddressStatus) DeepCopy() *NetworkLoadBalancerAddressStatus { + if in == nil { + return nil + } + out := new(NetworkLoadBalancerAddressStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkLoadBalancerBackendTransport) DeepCopyInto(out *NetworkLoadBalancerBackendTransport) { + *out = *in + if in.CABundleRef != nil { + in, out := &in.CABundleRef, &out.CABundleRef + *out = new(LocalSecretRef) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkLoadBalancerBackendTransport. +func (in *NetworkLoadBalancerBackendTransport) DeepCopy() *NetworkLoadBalancerBackendTransport { + if in == nil { + return nil + } + out := new(NetworkLoadBalancerBackendTransport) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkLoadBalancerEndpointStatus) DeepCopyInto(out *NetworkLoadBalancerEndpointStatus) { + *out = *in + if in.Addresses != nil { + in, out := &in.Addresses, &out.Addresses + *out = make([]NetworkLoadBalancerAddressStatus, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkLoadBalancerEndpointStatus. +func (in *NetworkLoadBalancerEndpointStatus) DeepCopy() *NetworkLoadBalancerEndpointStatus { + if in == nil { + return nil + } + out := new(NetworkLoadBalancerEndpointStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkLoadBalancerExposure) DeepCopyInto(out *NetworkLoadBalancerExposure) { + *out = *in + if in.Addresses != nil { + in, out := &in.Addresses, &out.Addresses + *out = make([]NetworkLoadBalancerAddressRequest, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkLoadBalancerExposure. +func (in *NetworkLoadBalancerExposure) DeepCopy() *NetworkLoadBalancerExposure { + if in == nil { + return nil + } + out := new(NetworkLoadBalancerExposure) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkLoadBalancerHealthCheck) DeepCopyInto(out *NetworkLoadBalancerHealthCheck) { + *out = *in + if in.IntervalSeconds != nil { + in, out := &in.IntervalSeconds, &out.IntervalSeconds + *out = new(int32) + **out = **in + } + if in.TimeoutSeconds != nil { + in, out := &in.TimeoutSeconds, &out.TimeoutSeconds + *out = new(int32) + **out = **in + } + if in.HealthyThreshold != nil { + in, out := &in.HealthyThreshold, &out.HealthyThreshold + *out = new(int32) + **out = **in + } + if in.UnhealthyThreshold != nil { + in, out := &in.UnhealthyThreshold, &out.UnhealthyThreshold + *out = new(int32) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkLoadBalancerHealthCheck. +func (in *NetworkLoadBalancerHealthCheck) DeepCopy() *NetworkLoadBalancerHealthCheck { + if in == nil { + return nil + } + out := new(NetworkLoadBalancerHealthCheck) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkLoadBalancerIPClaimRef) DeepCopyInto(out *NetworkLoadBalancerIPClaimRef) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkLoadBalancerIPClaimRef. +func (in *NetworkLoadBalancerIPClaimRef) DeepCopy() *NetworkLoadBalancerIPClaimRef { + if in == nil { + return nil + } + out := new(NetworkLoadBalancerIPClaimRef) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkLoadBalancerList) DeepCopyInto(out *NetworkLoadBalancerList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]NetworkLoadBalancer, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkLoadBalancerList. +func (in *NetworkLoadBalancerList) DeepCopy() *NetworkLoadBalancerList { + if in == nil { + return nil + } + out := new(NetworkLoadBalancerList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *NetworkLoadBalancerList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkLoadBalancerListener) DeepCopyInto(out *NetworkLoadBalancerListener) { + *out = *in + if in.AddressRefs != nil { + in, out := &in.AddressRefs, &out.AddressRefs + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.TLS != nil { + in, out := &in.TLS, &out.TLS + *out = new(NetworkLoadBalancerTLS) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkLoadBalancerListener. +func (in *NetworkLoadBalancerListener) DeepCopy() *NetworkLoadBalancerListener { + if in == nil { + return nil + } + out := new(NetworkLoadBalancerListener) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkLoadBalancerLocationSelection) DeepCopyInto(out *NetworkLoadBalancerLocationSelection) { + *out = *in + if in.Names != nil { + in, out := &in.Names, &out.Names + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkLoadBalancerLocationSelection. +func (in *NetworkLoadBalancerLocationSelection) DeepCopy() *NetworkLoadBalancerLocationSelection { + if in == nil { + return nil + } + out := new(NetworkLoadBalancerLocationSelection) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkLoadBalancerNetworkServiceRef) DeepCopyInto(out *NetworkLoadBalancerNetworkServiceRef) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkLoadBalancerNetworkServiceRef. +func (in *NetworkLoadBalancerNetworkServiceRef) DeepCopy() *NetworkLoadBalancerNetworkServiceRef { + if in == nil { + return nil + } + out := new(NetworkLoadBalancerNetworkServiceRef) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkLoadBalancerRoute) DeepCopyInto(out *NetworkLoadBalancerRoute) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkLoadBalancerRoute. +func (in *NetworkLoadBalancerRoute) DeepCopy() *NetworkLoadBalancerRoute { + if in == nil { + return nil + } + out := new(NetworkLoadBalancerRoute) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *NetworkLoadBalancerRoute) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkLoadBalancerRouteBackend) DeepCopyInto(out *NetworkLoadBalancerRouteBackend) { + *out = *in + out.NetworkService = in.NetworkService + if in.HealthCheck != nil { + in, out := &in.HealthCheck, &out.HealthCheck + *out = new(NetworkLoadBalancerHealthCheck) + (*in).DeepCopyInto(*out) + } + if in.Transport != nil { + in, out := &in.Transport, &out.Transport + *out = new(NetworkLoadBalancerBackendTransport) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkLoadBalancerRouteBackend. +func (in *NetworkLoadBalancerRouteBackend) DeepCopy() *NetworkLoadBalancerRouteBackend { + if in == nil { + return nil + } + out := new(NetworkLoadBalancerRouteBackend) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkLoadBalancerRouteList) DeepCopyInto(out *NetworkLoadBalancerRouteList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]NetworkLoadBalancerRoute, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkLoadBalancerRouteList. +func (in *NetworkLoadBalancerRouteList) DeepCopy() *NetworkLoadBalancerRouteList { + if in == nil { + return nil + } + out := new(NetworkLoadBalancerRouteList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *NetworkLoadBalancerRouteList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkLoadBalancerRouteParentRef) DeepCopyInto(out *NetworkLoadBalancerRouteParentRef) { + *out = *in + if in.Port != nil { + in, out := &in.Port, &out.Port + *out = new(int32) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkLoadBalancerRouteParentRef. +func (in *NetworkLoadBalancerRouteParentRef) DeepCopy() *NetworkLoadBalancerRouteParentRef { + if in == nil { + return nil + } + out := new(NetworkLoadBalancerRouteParentRef) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkLoadBalancerRouteParentStatus) DeepCopyInto(out *NetworkLoadBalancerRouteParentStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkLoadBalancerRouteParentStatus. +func (in *NetworkLoadBalancerRouteParentStatus) DeepCopy() *NetworkLoadBalancerRouteParentStatus { + if in == nil { + return nil + } + out := new(NetworkLoadBalancerRouteParentStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkLoadBalancerRouteSpec) DeepCopyInto(out *NetworkLoadBalancerRouteSpec) { + *out = *in + if in.ParentRefs != nil { + in, out := &in.ParentRefs, &out.ParentRefs + *out = make([]NetworkLoadBalancerRouteParentRef, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Backends != nil { + in, out := &in.Backends, &out.Backends + *out = make([]NetworkLoadBalancerRouteBackend, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.SNIHostnames != nil { + in, out := &in.SNIHostnames, &out.SNIHostnames + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkLoadBalancerRouteSpec. +func (in *NetworkLoadBalancerRouteSpec) DeepCopy() *NetworkLoadBalancerRouteSpec { + if in == nil { + return nil + } + out := new(NetworkLoadBalancerRouteSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkLoadBalancerRouteStatus) DeepCopyInto(out *NetworkLoadBalancerRouteStatus) { + *out = *in + if in.Parents != nil { + in, out := &in.Parents, &out.Parents + *out = make([]NetworkLoadBalancerRouteParentStatus, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkLoadBalancerRouteStatus. +func (in *NetworkLoadBalancerRouteStatus) DeepCopy() *NetworkLoadBalancerRouteStatus { + if in == nil { + return nil + } + out := new(NetworkLoadBalancerRouteStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkLoadBalancerSpec) DeepCopyInto(out *NetworkLoadBalancerSpec) { + *out = *in + out.NetworkRef = in.NetworkRef + in.Exposure.DeepCopyInto(&out.Exposure) + if in.Listeners != nil { + in, out := &in.Listeners, &out.Listeners + *out = make([]NetworkLoadBalancerListener, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkLoadBalancerSpec. +func (in *NetworkLoadBalancerSpec) DeepCopy() *NetworkLoadBalancerSpec { + if in == nil { + return nil + } + out := new(NetworkLoadBalancerSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkLoadBalancerStatus) DeepCopyInto(out *NetworkLoadBalancerStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.AddressRequests != nil { + in, out := &in.AddressRequests, &out.AddressRequests + *out = make([]NetworkLoadBalancerAddressRequestStatus, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Endpoints != nil { + in, out := &in.Endpoints, &out.Endpoints + *out = make([]NetworkLoadBalancerEndpointStatus, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkLoadBalancerStatus. +func (in *NetworkLoadBalancerStatus) DeepCopy() *NetworkLoadBalancerStatus { + if in == nil { + return nil + } + out := new(NetworkLoadBalancerStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkLoadBalancerTLS) DeepCopyInto(out *NetworkLoadBalancerTLS) { + *out = *in + if in.CertificateRef != nil { + in, out := &in.CertificateRef, &out.CertificateRef + *out = new(LocalSecretRef) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkLoadBalancerTLS. +func (in *NetworkLoadBalancerTLS) DeepCopy() *NetworkLoadBalancerTLS { + if in == nil { + return nil + } + out := new(NetworkLoadBalancerTLS) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *NetworkPolicy) DeepCopyInto(out *NetworkPolicy) { *out = *in diff --git a/config/crd/bases/networking.datumapis.com_networkloadbalancerroutes.yaml b/config/crd/bases/networking.datumapis.com_networkloadbalancerroutes.yaml new file mode 100644 index 00000000..7ad7a26c --- /dev/null +++ b/config/crd/bases/networking.datumapis.com_networkloadbalancerroutes.yaml @@ -0,0 +1,279 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.4 + name: networkloadbalancerroutes.networking.datumapis.com +spec: + group: networking.datumapis.com + names: + kind: NetworkLoadBalancerRoute + listKind: NetworkLoadBalancerRouteList + plural: networkloadbalancerroutes + singular: networkloadbalancerroute + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha + schema: + openAPIV3Schema: + description: |- + NetworkLoadBalancerRoute connects load balancer listeners to NetworkService + backends. References are restricted to the route's namespace. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: NetworkLoadBalancerRouteSpec attaches backends to named listeners. + properties: + backends: + items: + description: |- + NetworkLoadBalancerRouteBackend forwards new connections or flows to a + named NetworkService port. + properties: + healthCheck: + description: |- + NetworkLoadBalancerHealthCheck checks an individual backend endpoint. UDP + backends require a separate TCP, HTTP, or HTTPS health endpoint. + properties: + healthyThreshold: + format: int32 + minimum: 1 + type: integer + intervalSeconds: + format: int32 + minimum: 1 + type: integer + path: + pattern: ^/.*$ + type: string + port: + description: |- + Name of the probe port on the referenced NetworkService. When omitted, + TCP probes use the backend's serving port. + type: string + protocol: + enum: + - TCP + - HTTP + - HTTPS + type: string + timeoutSeconds: + format: int32 + minimum: 1 + type: integer + unhealthyThreshold: + format: int32 + minimum: 1 + type: integer + required: + - protocol + type: object + x-kubernetes-validations: + - message: path is only valid for HTTP and HTTPS probes + rule: 'has(self.path) ? self.protocol in [''HTTP'', ''HTTPS''] + : true' + - message: HTTP and HTTPS probes require a port + rule: self.protocol == 'TCP' || has(self.port) + networkService: + description: |- + NetworkLoadBalancerNetworkServiceRef names a backend service and one of its + named ports in the route's namespace. + properties: + name: + type: string + namespace: + type: string + port: + type: string + required: + - name + - port + type: object + transport: + description: Backend TLS requires a proxy-capable serving path. + properties: + caBundleRef: + properties: + name: + description: Name identifies a Secret in the listener's + namespace. + type: string + namespace: + description: Cross-namespace access is capability-gated + until grants are supported. + type: string + required: + - name + type: object + protocol: + enum: + - TCP + - TLS + type: string + serverName: + type: string + required: + - protocol + type: object + required: + - networkService + type: object + maxItems: 16 + minItems: 1 + type: array + parentRefs: + items: + description: |- + NetworkLoadBalancerRouteParentRef attaches a route to a listener. Cross- + namespace references are capability-gated initially. Either listener name or + port selects a listener; status always reports its resolved name. + properties: + listener: + description: One of listener or port selects the parent listener. + type: string + name: + maxLength: 253 + minLength: 1 + type: string + namespace: + type: string + port: + format: int32 + type: integer + required: + - name + type: object + x-kubernetes-validations: + - message: exactly one of listener or port is required + rule: has(self.listener) != has(self.port) + maxItems: 16 + minItems: 1 + type: array + x-kubernetes-list-type: atomic + sniHostnames: + description: SNI routing is capability-gated until TLS listeners are + served. + items: + type: string + type: array + required: + - backends + - parentRefs + type: object + status: + properties: + parents: + items: + description: |- + NetworkLoadBalancerRouteParentStatus reports attachment and effectiveness + for one parent listener. The oldest accepted catch-all route is effective. + properties: + conditions: + description: |- + Conditions include Accepted, ResolvedRefs, and Programmed with + observedGeneration. + items: + description: Condition contains details for one aspect of + the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, + Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + effective: + type: boolean + listener: + type: string + name: + type: string + required: + - effective + - listener + - name + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + - listener + x-kubernetes-list-type: map + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/bases/networking.datumapis.com_networkloadbalancers.yaml b/config/crd/bases/networking.datumapis.com_networkloadbalancers.yaml new file mode 100644 index 00000000..13680d0a --- /dev/null +++ b/config/crd/bases/networking.datumapis.com_networkloadbalancers.yaml @@ -0,0 +1,454 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.4 + name: networkloadbalancers.networking.datumapis.com +spec: + group: networking.datumapis.com + names: + kind: NetworkLoadBalancer + listKind: NetworkLoadBalancerList + plural: networkloadbalancers + singular: networkloadbalancer + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha + schema: + openAPIV3Schema: + description: |- + NetworkLoadBalancer reserves public IPs and accepts TCP or UDP traffic on + named listeners. Route objects attach backends to those listeners. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: NetworkLoadBalancerSpec defines the network, public addresses, + and listeners. + properties: + exposure: + description: NetworkLoadBalancerExposure contains the load balancer's + address requests. + properties: + addresses: + items: + description: |- + NetworkLoadBalancerAddressRequest reserves one public address per selected + location, independently of whether a route has healthy backends. + properties: + families: + items: + enum: + - IPv4 + - IPv6 + type: string + maxItems: 2 + minItems: 1 + type: array + x-kubernetes-list-type: set + locations: + description: Omission follows the effective backends' network + interfaces. + properties: + from: + description: |- + NetworkLoadBalancerLocationSource selects locations by name or follows all + eligible locations as they become available. + enum: + - Backends + - All + - Names + type: string + names: + items: + type: string + maxItems: 64 + minItems: 1 + type: array + x-kubernetes-list-type: set + required: + - from + type: object + x-kubernetes-validations: + - message: names must be set only when from is Names + rule: 'self.from == ''Names'' ? has(self.names) && size(self.names) + > 0 : !has(self.names)' + name: + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - families + - name + type: object + maxItems: 16 + minItems: 1 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + required: + - addresses + type: object + listeners: + items: + description: |- + NetworkLoadBalancerListener accepts one transport and port on its named + address requests. TCP and UDP may use the same port. + properties: + addressRefs: + items: + type: string + maxItems: 16 + minItems: 1 + type: array + x-kubernetes-list-type: set + hostname: + type: string + name: + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + format: int32 + maximum: 65535 + minimum: 1 + type: integer + protocol: + description: NetworkLoadBalancerProtocol is the transport accepted + by a listener. + enum: + - TCP + - UDP + - TLS + type: string + tls: + properties: + certificateRef: + description: Secret references are admitted only after TLS + termination is supported. + properties: + name: + description: Name identifies a Secret in the listener's + namespace. + type: string + namespace: + description: Cross-namespace access is capability-gated + until grants are supported. + type: string + required: + - name + type: object + mode: + enum: + - Passthrough + - Terminate + type: string + required: + - mode + type: object + x-kubernetes-validations: + - message: Terminate requires a certificate; Passthrough omits + it + rule: 'self.mode == ''Terminate'' ? has(self.certificateRef) + : !has(self.certificateRef)' + required: + - addressRefs + - name + - port + - protocol + type: object + maxItems: 16 + minItems: 1 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + networkRef: + description: The network must exist in the load balancer's namespace. + properties: + name: + description: The network name + type: string + required: + - name + type: object + x-kubernetes-validations: + - message: networkRef is immutable + rule: self == oldSelf + required: + - exposure + - listeners + - networkRef + type: object + x-kubernetes-validations: + - message: each listener address reference must name an address request + rule: self.listeners.all(l, l.addressRefs.all(r, r in self.exposure.addresses.map(a, + a.name))) + - message: listeners sharing an address cannot use the same protocol and + port + rule: self.listeners.all(l1, self.listeners.all(l2, l1.name == l2.name + || l1.protocol != l2.protocol || l1.port != l2.port || !l1.addressRefs.exists(r, + r in l2.addressRefs))) + - message: TLS configuration is required only for TLS listeners + rule: 'self.listeners.all(l, l.protocol == ''TLS'' ? has(l.tls) : !has(l.tls))' + status: + description: |- + NetworkLoadBalancerStatus distinguishes address allocation from programming + and announcement. Allocated IPs remain here during backend failures. + properties: + addressRequests: + items: + properties: + locationSource: + description: |- + NetworkLoadBalancerLocationSource selects locations by name or follows all + eligible locations as they become available. + enum: + - Backends + - All + - Names + type: string + name: + type: string + resolvedLocations: + items: + type: string + type: array + x-kubernetes-list-type: set + required: + - locationSource + - name + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + conditions: + description: Conditions include Allocated, Programmed, and Ready with + observedGeneration. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + endpoints: + items: + description: |- + NetworkLoadBalancerEndpointStatus is stable for one address request and + location, even while individual address families are unavailable. + properties: + addresses: + items: + description: NetworkLoadBalancerAddressStatus describes one + family at a location. + properties: + announced: + type: boolean + claimRef: + description: NetworkLoadBalancerIPClaimRef identifies + the claim holding an allocated IP. + properties: + name: + type: string + namespace: + type: string + project: + type: string + uid: + description: UID distinguishes a recreated claim with + the same name from the old allocation. + type: string + required: + - name + - namespace + - project + type: object + conditions: + description: |- + Conditions include Allocated, Programmed, and Announced with + observedGeneration. An entry with no value reports a pending or failed + allocation for this request/location. + items: + description: Condition contains details for one aspect + of the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, + False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in + foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + dnsPublished: + type: boolean + family: + enum: + - IPv4 + - IPv6 + type: string + message: + type: string + reason: + type: string + value: + type: string + required: + - family + type: object + type: array + x-kubernetes-list-map-keys: + - family + x-kubernetes-list-type: map + canonicalHostname: + type: string + location: + type: string + requestName: + type: string + required: + - location + - requestName + type: object + maxItems: 1024 + type: array + x-kubernetes-list-map-keys: + - requestName + - location + x-kubernetes-list-type: map + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index 4e7487d9..cedb4a3a 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -18,6 +18,8 @@ resources: - bases/networking.datumapis.com_networkinterfaces.yaml - bases/networking.datumapis.com_networkinterfaceclaims.yaml - bases/networking.datumapis.com_networkservices.yaml +- bases/networking.datumapis.com_networkloadbalancers.yaml +- bases/networking.datumapis.com_networkloadbalancerroutes.yaml # +kubebuilder:scaffold:crdkustomizeresource patches: diff --git a/config/quota/claim-policies/kustomization.yaml b/config/quota/claim-policies/kustomization.yaml index 85216a89..16c37530 100644 --- a/config/quota/claim-policies/kustomization.yaml +++ b/config/quota/claim-policies/kustomization.yaml @@ -16,5 +16,7 @@ resources: - httpproxy-claim-policy.yaml - httproute-claim-policy.yaml - httproutefilter-claim-policy.yaml + - networkloadbalancer-claim-policy.yaml + - networkloadbalancerroute-claim-policy.yaml - securitypolicy-claim-policy.yaml - trafficprotectionpolicy-claim-policy.yaml diff --git a/config/quota/claim-policies/networkloadbalancer-claim-policy.yaml b/config/quota/claim-policies/networkloadbalancer-claim-policy.yaml new file mode 100644 index 00000000..5f759557 --- /dev/null +++ b/config/quota/claim-policies/networkloadbalancer-claim-policy.yaml @@ -0,0 +1,26 @@ +apiVersion: quota.miloapis.com/v1alpha1 +kind: ClaimCreationPolicy +metadata: + name: project-networkloadbalancer-claim-policy + labels: + app.kubernetes.io/name: network-services-operator + app.kubernetes.io/component: quota-system +spec: + trigger: + resource: + apiVersion: networking.datumapis.com/v1alpha + kind: NetworkLoadBalancer + target: + resourceClaimTemplate: + metadata: + name: "networkloadbalancer-{{ trigger.metadata.name }}" + namespace: "{{requestInfo.namespace}}" + labels: + app.kubernetes.io/name: network-services-operator + app.kubernetes.io/component: quota-system + annotations: + kubernetes.io/description: "Automatic quota claim for NetworkLoadBalancer creation" + spec: + requests: + - resourceType: networking.datumapis.com/networkloadbalancers + amount: 1 diff --git a/config/quota/claim-policies/networkloadbalancerroute-claim-policy.yaml b/config/quota/claim-policies/networkloadbalancerroute-claim-policy.yaml new file mode 100644 index 00000000..76318b66 --- /dev/null +++ b/config/quota/claim-policies/networkloadbalancerroute-claim-policy.yaml @@ -0,0 +1,26 @@ +apiVersion: quota.miloapis.com/v1alpha1 +kind: ClaimCreationPolicy +metadata: + name: project-networkloadbalancerroute-claim-policy + labels: + app.kubernetes.io/name: network-services-operator + app.kubernetes.io/component: quota-system +spec: + trigger: + resource: + apiVersion: networking.datumapis.com/v1alpha + kind: NetworkLoadBalancerRoute + target: + resourceClaimTemplate: + metadata: + name: "networkloadbalancerroute-{{ trigger.metadata.name }}" + namespace: "{{requestInfo.namespace}}" + labels: + app.kubernetes.io/name: network-services-operator + app.kubernetes.io/component: quota-system + annotations: + kubernetes.io/description: "Automatic quota claim for NetworkLoadBalancerRoute creation" + spec: + requests: + - resourceType: networking.datumapis.com/networkloadbalancerroutes + amount: 1 diff --git a/config/quota/registrations/kustomization.yaml b/config/quota/registrations/kustomization.yaml index 7f720cd2..fa20dcb2 100644 --- a/config/quota/registrations/kustomization.yaml +++ b/config/quota/registrations/kustomization.yaml @@ -16,5 +16,7 @@ resources: - httpproxy-registration.yaml - httproute-registration.yaml - httproutefilter-registration.yaml + - networkloadbalancer-registration.yaml + - networkloadbalancerroute-registration.yaml - securitypolicy-registration.yaml - trafficprotectionpolicy-registration.yaml diff --git a/config/quota/registrations/networkloadbalancer-registration.yaml b/config/quota/registrations/networkloadbalancer-registration.yaml new file mode 100644 index 00000000..ddc1031e --- /dev/null +++ b/config/quota/registrations/networkloadbalancer-registration.yaml @@ -0,0 +1,24 @@ +apiVersion: quota.miloapis.com/v1alpha1 +kind: ResourceRegistration +metadata: + name: networkloadbalancers-per-project + labels: + app.kubernetes.io/name: network-services-operator + app.kubernetes.io/component: quota-system + services.miloapis.com/owner: networking.datumapis.com + annotations: + kubernetes.io/display-name: "Network Load Balancers" + kubernetes.io/description: "Maximum number of network load balancers in a project" +spec: + consumerType: + apiGroup: resourcemanager.miloapis.com + kind: Project + type: Entity + resourceType: networking.datumapis.com/networkloadbalancers + description: "Maximum number of network load balancers in a project" + baseUnit: load balancer + displayUnit: load balancers + unitConversionFactor: 1 + claimingResources: + - apiGroup: networking.datumapis.com + kind: NetworkLoadBalancer diff --git a/config/quota/registrations/networkloadbalancerroute-registration.yaml b/config/quota/registrations/networkloadbalancerroute-registration.yaml new file mode 100644 index 00000000..9a6109f7 --- /dev/null +++ b/config/quota/registrations/networkloadbalancerroute-registration.yaml @@ -0,0 +1,24 @@ +apiVersion: quota.miloapis.com/v1alpha1 +kind: ResourceRegistration +metadata: + name: networkloadbalancerroutes-per-project + labels: + app.kubernetes.io/name: network-services-operator + app.kubernetes.io/component: quota-system + services.miloapis.com/owner: networking.datumapis.com + annotations: + kubernetes.io/display-name: "Network Load Balancer Routes" + kubernetes.io/description: "Maximum number of network load balancer routes in a project" +spec: + consumerType: + apiGroup: resourcemanager.miloapis.com + kind: Project + type: Entity + resourceType: networking.datumapis.com/networkloadbalancerroutes + description: "Maximum number of network load balancer routes in a project" + baseUnit: route + displayUnit: routes + unitConversionFactor: 1 + claimingResources: + - apiGroup: networking.datumapis.com + kind: NetworkLoadBalancerRoute diff --git a/config/webhook/manifests.yaml b/config/webhook/manifests.yaml index 8615607d..c2e8e2f8 100644 --- a/config/webhook/manifests.yaml +++ b/config/webhook/manifests.yaml @@ -190,6 +190,46 @@ webhooks: resources: - networks sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /validate-networking-datumapis-com-v1alpha-networkloadbalancer + failurePolicy: Fail + name: vnetworkloadbalancer-v1alpha.kb.io + rules: + - apiGroups: + - networking.datumapis.com + apiVersions: + - v1alpha + operations: + - CREATE + - UPDATE + resources: + - networkloadbalancers + sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /validate-networking-datumapis-com-v1alpha-networkloadbalancerroute + failurePolicy: Fail + name: vnetworkloadbalancerroute-v1alpha.kb.io + rules: + - apiGroups: + - networking.datumapis.com + apiVersions: + - v1alpha + operations: + - CREATE + - UPDATE + resources: + - networkloadbalancerroutes + sideEffects: None - admissionReviewVersions: - v1 clientConfig: diff --git a/docs/api/networkloadbalancerroutes.md b/docs/api/networkloadbalancerroutes.md new file mode 100644 index 00000000..d22e2350 --- /dev/null +++ b/docs/api/networkloadbalancerroutes.md @@ -0,0 +1,565 @@ +# API Reference + +Packages: + +- [networking.datumapis.com/v1alpha](#networkingdatumapiscomv1alpha) + +# networking.datumapis.com/v1alpha + +Resource Types: + +- [NetworkLoadBalancerRoute](#networkloadbalancerroute) + + + + +## NetworkLoadBalancerRoute +[↩ Parent](#networkingdatumapiscomv1alpha ) + + + + + + +NetworkLoadBalancerRoute connects load balancer listeners to NetworkService +backends. References are restricted to the route's namespace. + +
| Name | +Type | +Description | +Required | +
|---|---|---|---|
| apiVersion | +string | +networking.datumapis.com/v1alpha | +true | +
| kind | +string | +NetworkLoadBalancerRoute | +true | +
| metadata | +object | +Refer to the Kubernetes API documentation for the fields of the `metadata` field. | +true | +
| spec | +object | +
+ NetworkLoadBalancerRouteSpec attaches backends to named listeners. + |
+ true | +
| status | +object | +
+ + |
+ false | +
| Name | +Type | +Description | +Required | +
|---|---|---|---|
| backends | +[]object | +
+ + |
+ true | +
| parentRefs | +[]object | +
+ + |
+ true | +
| sniHostnames | +[]string | +
+ SNI routing is capability-gated until TLS listeners are served. + |
+ false | +
| Name | +Type | +Description | +Required | +
|---|---|---|---|
| networkService | +object | +
+ NetworkLoadBalancerNetworkServiceRef names a backend service and one of its
+named ports in the route's namespace. + |
+ true | +
| healthCheck | +object | +
+ NetworkLoadBalancerHealthCheck checks an individual backend endpoint. UDP
+backends require a separate TCP, HTTP, or HTTPS health endpoint. + + Validations: |
+ false | +
| transport | +object | +
+ Backend TLS requires a proxy-capable serving path. + |
+ false | +
| Name | +Type | +Description | +Required | +
|---|---|---|---|
| name | +string | +
+ + |
+ true | +
| port | +string | +
+ + |
+ true | +
| namespace | +string | +
+ + |
+ false | +
| Name | +Type | +Description | +Required | +
|---|---|---|---|
| protocol | +enum | +
+ + + Enum: TCP, HTTP, HTTPS + |
+ true | +
| healthyThreshold | +integer | +
+ + + Format: int32 + Minimum: 1 + |
+ false | +
| intervalSeconds | +integer | +
+ + + Format: int32 + Minimum: 1 + |
+ false | +
| path | +string | +
+ + |
+ false | +
| port | +string | +
+ Name of the probe port on the referenced NetworkService. When omitted,
+TCP probes use the backend's serving port. + |
+ false | +
| timeoutSeconds | +integer | +
+ + + Format: int32 + Minimum: 1 + |
+ false | +
| unhealthyThreshold | +integer | +
+ + + Format: int32 + Minimum: 1 + |
+ false | +
| Name | +Type | +Description | +Required | +
|---|---|---|---|
| protocol | +enum | +
+ + + Enum: TCP, TLS + |
+ true | +
| caBundleRef | +object | +
+ + |
+ false | +
| serverName | +string | +
+ + |
+ false | +
| Name | +Type | +Description | +Required | +
|---|---|---|---|
| name | +string | +
+ Name identifies a Secret in the listener's namespace. + |
+ true | +
| namespace | +string | +
+ Cross-namespace access is capability-gated until grants are supported. + |
+ false | +
| Name | +Type | +Description | +Required | +
|---|---|---|---|
| name | +string | +
+ + |
+ true | +
| listener | +string | +
+ One of listener or port selects the parent listener. + |
+ false | +
| namespace | +string | +
+ + |
+ false | +
| port | +integer | +
+ + + Format: int32 + |
+ false | +
| Name | +Type | +Description | +Required | +
|---|---|---|---|
| parents | +[]object | +
+ + |
+ false | +
| Name | +Type | +Description | +Required | +
|---|---|---|---|
| effective | +boolean | +
+ + |
+ true | +
| listener | +string | +
+ + |
+ true | +
| name | +string | +
+ + |
+ true | +
| conditions | +[]object | +
+ Conditions include Accepted, ResolvedRefs, and Programmed with
+observedGeneration. + |
+ false | +
| Name | +Type | +Description | +Required | +
|---|---|---|---|
| lastTransitionTime | +string | +
+ lastTransitionTime is the last time the condition transitioned from one status to another.
+This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + + Format: date-time + |
+ true | +
| message | +string | +
+ message is a human readable message indicating details about the transition.
+This may be an empty string. + |
+ true | +
| reason | +string | +
+ reason contains a programmatic identifier indicating the reason for the condition's last transition.
+Producers of specific condition types may define expected values and meanings for this field,
+and whether the values are considered a guaranteed API.
+The value should be a CamelCase string.
+This field may not be empty. + |
+ true | +
| status | +enum | +
+ status of the condition, one of True, False, Unknown. + + Enum: True, False, Unknown + |
+ true | +
| type | +string | +
+ type of condition in CamelCase or in foo.example.com/CamelCase. + |
+ true | +
| observedGeneration | +integer | +
+ observedGeneration represents the .metadata.generation that the condition was set based upon.
+For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
+with respect to the current state of the instance. + + Format: int64 + Minimum: 0 + |
+ false | +
| Name | +Type | +Description | +Required | +
|---|---|---|---|
| apiVersion | +string | +networking.datumapis.com/v1alpha | +true | +
| kind | +string | +NetworkLoadBalancer | +true | +
| metadata | +object | +Refer to the Kubernetes API documentation for the fields of the `metadata` field. | +true | +
| spec | +object | +
+ NetworkLoadBalancerSpec defines the network, public addresses, and listeners. + + Validations: |
+ true | +
| status | +object | +
+ NetworkLoadBalancerStatus distinguishes address allocation from programming
+and announcement. Allocated IPs remain here during backend failures. + |
+ false | +
| Name | +Type | +Description | +Required | +
|---|---|---|---|
| exposure | +object | +
+ NetworkLoadBalancerExposure contains the load balancer's address requests. + |
+ true | +
| listeners | +[]object | +
+ + |
+ true | +
| networkRef | +object | +
+ The network must exist in the load balancer's namespace. + + Validations: |
+ true | +
| Name | +Type | +Description | +Required | +
|---|---|---|---|
| addresses | +[]object | +
+ + |
+ true | +
| Name | +Type | +Description | +Required | +
|---|---|---|---|
| families | +[]enum | +
+ + + Enum: IPv4, IPv6 + |
+ true | +
| name | +string | +
+ + |
+ true | +
| locations | +object | +
+ Omission follows the effective backends' network interfaces. + + Validations: |
+ false | +
| Name | +Type | +Description | +Required | +
|---|---|---|---|
| from | +enum | +
+ NetworkLoadBalancerLocationSource selects locations by name or follows all
+eligible locations as they become available. + + Enum: Backends, All, Names + |
+ true | +
| names | +[]string | +
+ + |
+ false | +
| Name | +Type | +Description | +Required | +
|---|---|---|---|
| addressRefs | +[]string | +
+ + |
+ true | +
| name | +string | +
+ + |
+ true | +
| port | +integer | +
+ + + Format: int32 + Minimum: 1 + Maximum: 65535 + |
+ true | +
| protocol | +enum | +
+ NetworkLoadBalancerProtocol is the transport accepted by a listener. + + Enum: TCP, UDP, TLS + |
+ true | +
| hostname | +string | +
+ + |
+ false | +
| tls | +object | +
+ + + Validations: |
+ false | +
| Name | +Type | +Description | +Required | +
|---|---|---|---|
| mode | +enum | +
+ + + Enum: Passthrough, Terminate + |
+ true | +
| certificateRef | +object | +
+ Secret references are admitted only after TLS termination is supported. + |
+ false | +
| Name | +Type | +Description | +Required | +
|---|---|---|---|
| name | +string | +
+ Name identifies a Secret in the listener's namespace. + |
+ true | +
| namespace | +string | +
+ Cross-namespace access is capability-gated until grants are supported. + |
+ false | +
| Name | +Type | +Description | +Required | +
|---|---|---|---|
| name | +string | +
+ The network name + |
+ true | +
| Name | +Type | +Description | +Required | +
|---|---|---|---|
| addressRequests | +[]object | +
+ + |
+ false | +
| conditions | +[]object | +
+ Conditions include Allocated, Programmed, and Ready with observedGeneration. + |
+ false | +
| endpoints | +[]object | +
+ + |
+ false | +
| Name | +Type | +Description | +Required | +
|---|---|---|---|
| locationSource | +enum | +
+ NetworkLoadBalancerLocationSource selects locations by name or follows all
+eligible locations as they become available. + + Enum: Backends, All, Names + |
+ true | +
| name | +string | +
+ + |
+ true | +
| resolvedLocations | +[]string | +
+ + |
+ false | +
| Name | +Type | +Description | +Required | +
|---|---|---|---|
| lastTransitionTime | +string | +
+ lastTransitionTime is the last time the condition transitioned from one status to another.
+This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + + Format: date-time + |
+ true | +
| message | +string | +
+ message is a human readable message indicating details about the transition.
+This may be an empty string. + |
+ true | +
| reason | +string | +
+ reason contains a programmatic identifier indicating the reason for the condition's last transition.
+Producers of specific condition types may define expected values and meanings for this field,
+and whether the values are considered a guaranteed API.
+The value should be a CamelCase string.
+This field may not be empty. + |
+ true | +
| status | +enum | +
+ status of the condition, one of True, False, Unknown. + + Enum: True, False, Unknown + |
+ true | +
| type | +string | +
+ type of condition in CamelCase or in foo.example.com/CamelCase. + |
+ true | +
| observedGeneration | +integer | +
+ observedGeneration represents the .metadata.generation that the condition was set based upon.
+For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
+with respect to the current state of the instance. + + Format: int64 + Minimum: 0 + |
+ false | +
| Name | +Type | +Description | +Required | +
|---|---|---|---|
| location | +string | +
+ + |
+ true | +
| requestName | +string | +
+ + |
+ true | +
| addresses | +[]object | +
+ + |
+ false | +
| canonicalHostname | +string | +
+ + |
+ false | +
| Name | +Type | +Description | +Required | +
|---|---|---|---|
| family | +enum | +
+ + + Enum: IPv4, IPv6 + |
+ true | +
| announced | +boolean | +
+ + |
+ false | +
| claimRef | +object | +
+ NetworkLoadBalancerIPClaimRef identifies the claim holding an allocated IP. + |
+ false | +
| conditions | +[]object | +
+ Conditions include Allocated, Programmed, and Announced with
+observedGeneration. An entry with no value reports a pending or failed
+allocation for this request/location. + |
+ false | +
| dnsPublished | +boolean | +
+ + |
+ false | +
| message | +string | +
+ + |
+ false | +
| reason | +string | +
+ + |
+ false | +
| value | +string | +
+ + |
+ false | +
| Name | +Type | +Description | +Required | +
|---|---|---|---|
| name | +string | +
+ + |
+ true | +
| namespace | +string | +
+ + |
+ true | +
| project | +string | +
+ + |
+ true | +
| uid | +string | +
+ UID distinguishes a recreated claim with the same name from the old allocation. + |
+ false | +
| Name | +Type | +Description | +Required | +
|---|---|---|---|
| lastTransitionTime | +string | +
+ lastTransitionTime is the last time the condition transitioned from one status to another.
+This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + + Format: date-time + |
+ true | +
| message | +string | +
+ message is a human readable message indicating details about the transition.
+This may be an empty string. + |
+ true | +
| reason | +string | +
+ reason contains a programmatic identifier indicating the reason for the condition's last transition.
+Producers of specific condition types may define expected values and meanings for this field,
+and whether the values are considered a guaranteed API.
+The value should be a CamelCase string.
+This field may not be empty. + |
+ true | +
| status | +enum | +
+ status of the condition, one of True, False, Unknown. + + Enum: True, False, Unknown + |
+ true | +
| type | +string | +
+ type of condition in CamelCase or in foo.example.com/CamelCase. + |
+ true | +
| observedGeneration | +integer | +
+ observedGeneration represents the .metadata.generation that the condition was set based upon.
+For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
+with respect to the current state of the instance. + + Format: int64 + Minimum: 0 + |
+ false | +