feat: additional service ports (#999)

* feat: additional service ports

Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>

* docs: additional service ports

Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>

---------

Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>
This commit is contained in:
Dario Tranchitella
2025-10-30 13:22:15 +01:00
committed by GitHub
parent cb8086754b
commit 081b4c72b3
6 changed files with 263 additions and 5 deletions

View File

@@ -7,6 +7,7 @@ import (
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
)
// NetworkProfileSpec defines the desired state of NetworkProfile.
@@ -89,6 +90,32 @@ type KubernetesSpec struct {
AdmissionControllers AdmissionControllers `json:"admissionControllers,omitempty"`
}
type AdditionalPort struct {
// The name of this port within the Service created by Kamaji.
// This must be a DNS_LABEL, must have unique names, and cannot be `kube-apiserver`, or `konnectivity-server`.
Name string `json:"name"`
// The IP protocol for this port. Supports "TCP", "UDP", and "SCTP".
//+kubebuilder:validation:Enum=TCP;UDP;SCTP
//+kubebuilder:default=TCP
Protocol corev1.Protocol `json:"protocol,omitempty"`
// The application protocol for this port.
// This is used as a hint for implementations to offer richer behavior for protocols that they understand.
// This field follows standard Kubernetes label syntax.
// Valid values are either:
//
// * Un-prefixed protocol names - reserved for IANA standard service names (as per
// RFC-6335 and https://www.iana.org/assignments/service-names).
AppProtocol *string `json:"appProtocol,omitempty"`
// The port that will be exposed by this service.
Port int32 `json:"port"`
// Number or name of the port to access on the pods of the Tenant Control Plane.
// Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME.
// If this is a string, it will be looked up as a named port in the
// target Pod's container ports. If this is not specified, the value
// of the 'port' field is used (an identity map).
TargetPort intstr.IntOrString `json:"targetPort"`
}
// AdditionalMetadata defines which additional metadata, such as labels and annotations, must be attached to the created resource.
type AdditionalMetadata struct {
Labels map[string]string `json:"labels,omitempty"`
@@ -198,6 +225,9 @@ type ControlPlaneExtraArgs struct {
type ServiceSpec struct {
AdditionalMetadata AdditionalMetadata `json:"additionalMetadata,omitempty"`
// AdditionalPorts allows adding additional ports to the Service generated Kamaji
// which targets the Tenant Control Plane pods.
AdditionalPorts []AdditionalPort `json:"additionalPorts,omitempty"`
// ServiceType allows specifying how to expose the Tenant Control Plane.
ServiceType ServiceType `json:"serviceType"`
}

View File

@@ -57,6 +57,27 @@ func (in *AdditionalMetadata) DeepCopy() *AdditionalMetadata {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *AdditionalPort) DeepCopyInto(out *AdditionalPort) {
*out = *in
if in.AppProtocol != nil {
in, out := &in.AppProtocol, &out.AppProtocol
*out = new(string)
**out = **in
}
out.TargetPort = in.TargetPort
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AdditionalPort.
func (in *AdditionalPort) DeepCopy() *AdditionalPort {
if in == nil {
return nil
}
out := new(AdditionalPort)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *AdditionalVolumeMounts) DeepCopyInto(out *AdditionalVolumeMounts) {
*out = *in
@@ -1351,6 +1372,13 @@ func (in *SecretReference) DeepCopy() *SecretReference {
func (in *ServiceSpec) DeepCopyInto(out *ServiceSpec) {
*out = *in
in.AdditionalMetadata.DeepCopyInto(&out.AdditionalMetadata)
if in.AdditionalPorts != nil {
in, out := &in.AdditionalPorts, &out.AdditionalPorts
*out = make([]AdditionalPort, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceSpec.

View File

@@ -6738,6 +6738,56 @@ versions:
type: string
type: object
type: object
additionalPorts:
description: |-
AdditionalPorts allows adding additional ports to the Service generated Kamaji
which targets the Tenant Control Plane pods.
items:
properties:
appProtocol:
description: |-
The application protocol for this port.
This is used as a hint for implementations to offer richer behavior for protocols that they understand.
This field follows standard Kubernetes label syntax.
Valid values are either:
* Un-prefixed protocol names - reserved for IANA standard service names (as per
RFC-6335 and https://www.iana.org/assignments/service-names).
type: string
name:
description: |-
The name of this port within the Service created by Kamaji.
This must be a DNS_LABEL, must have unique names, and cannot be `kube-apiserver`, or `konnectivity-server`.
type: string
port:
description: The port that will be exposed by this service.
format: int32
type: integer
protocol:
default: TCP
description: The IP protocol for this port. Supports "TCP", "UDP", and "SCTP".
enum:
- TCP
- UDP
- SCTP
type: string
targetPort:
anyOf:
- type: integer
- type: string
description: |-
Number or name of the port to access on the pods of the Tenant Control Plane.
Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME.
If this is a string, it will be looked up as a named port in the
target Pod's container ports. If this is not specified, the value
of the 'port' field is used (an identity map).
x-kubernetes-int-or-string: true
required:
- name
- port
- targetPort
type: object
type: array
serviceType:
description: ServiceType allows specifying how to expose the Tenant Control Plane.
enum:

View File

@@ -6746,6 +6746,56 @@ spec:
type: string
type: object
type: object
additionalPorts:
description: |-
AdditionalPorts allows adding additional ports to the Service generated Kamaji
which targets the Tenant Control Plane pods.
items:
properties:
appProtocol:
description: |-
The application protocol for this port.
This is used as a hint for implementations to offer richer behavior for protocols that they understand.
This field follows standard Kubernetes label syntax.
Valid values are either:
* Un-prefixed protocol names - reserved for IANA standard service names (as per
RFC-6335 and https://www.iana.org/assignments/service-names).
type: string
name:
description: |-
The name of this port within the Service created by Kamaji.
This must be a DNS_LABEL, must have unique names, and cannot be `kube-apiserver`, or `konnectivity-server`.
type: string
port:
description: The port that will be exposed by this service.
format: int32
type: integer
protocol:
default: TCP
description: The IP protocol for this port. Supports "TCP", "UDP", and "SCTP".
enum:
- TCP
- UDP
- SCTP
type: string
targetPort:
anyOf:
- type: integer
- type: string
description: |-
Number or name of the port to access on the pods of the Tenant Control Plane.
Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME.
If this is a string, it will be looked up as a named port in the
target Pod's container ports. If this is not specified, the value
of the 'port' field is used (an identity map).
x-kubernetes-int-or-string: true
required:
- name
- port
- targetPort
type: object
type: array
serviceType:
description: ServiceType allows specifying how to expose the Tenant Control Plane.
enum:

View File

@@ -28609,6 +28609,14 @@ Defining the options for the Tenant Control Plane Service resource.
AdditionalMetadata defines which additional metadata, such as labels and annotations, must be attached to the created resource.<br/>
</td>
<td>false</td>
</tr><tr>
<td><b><a href="#tenantcontrolplanespeccontrolplaneserviceadditionalportsindex">additionalPorts</a></b></td>
<td>[]object</td>
<td>
AdditionalPorts allows adding additional ports to the Service generated Kamaji
which targets the Tenant Control Plane pods.<br/>
</td>
<td>false</td>
</tr></tbody>
</table>
@@ -28645,6 +28653,75 @@ AdditionalMetadata defines which additional metadata, such as labels and annotat
</table>
<span id="tenantcontrolplanespeccontrolplaneserviceadditionalportsindex">`TenantControlPlane.spec.controlPlane.service.additionalPorts[index]`</span>
<table>
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Description</th>
<th>Required</th>
</tr>
</thead>
<tbody><tr>
<td><b>name</b></td>
<td>string</td>
<td>
The name of this port within the Service created by Kamaji.
This must be a DNS_LABEL, must have unique names, and cannot be `kube-apiserver`, or `konnectivity-server`.<br/>
</td>
<td>true</td>
</tr><tr>
<td><b>port</b></td>
<td>integer</td>
<td>
The port that will be exposed by this service.<br/>
<br/>
<i>Format</i>: int32<br/>
</td>
<td>true</td>
</tr><tr>
<td><b>targetPort</b></td>
<td>int or string</td>
<td>
Number or name of the port to access on the pods of the Tenant Control Plane.
Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME.
If this is a string, it will be looked up as a named port in the
target Pod's container ports. If this is not specified, the value
of the 'port' field is used (an identity map).<br/>
</td>
<td>true</td>
</tr><tr>
<td><b>appProtocol</b></td>
<td>string</td>
<td>
The application protocol for this port.
This is used as a hint for implementations to offer richer behavior for protocols that they understand.
This field follows standard Kubernetes label syntax.
Valid values are either:
* Un-prefixed protocol names - reserved for IANA standard service names (as per
RFC-6335 and https://www.iana.org/assignments/service-names).<br/>
</td>
<td>false</td>
</tr><tr>
<td><b>protocol</b></td>
<td>enum</td>
<td>
The IP protocol for this port. Supports "TCP", "UDP", and "SCTP".<br/>
<br/>
<i>Enum</i>: TCP, UDP, SCTP<br/>
<i>Default</i>: TCP<br/>
</td>
<td>false</td>
</tr></tbody>
</table>
<span id="tenantcontrolplanespeccontrolplanedeployment">`TenantControlPlane.spec.controlPlane.deployment`</span>

View File

@@ -98,14 +98,37 @@ func (r *KubernetesServiceResource) mutate(ctx context.Context, tenantControlPla
"kamaji.clastix.io/name": tenantControlPlane.GetName(),
}
if len(r.resource.Spec.Ports) == 0 {
if r.resource.Spec.Ports == nil {
r.resource.Spec.Ports = make([]corev1.ServicePort, 1)
}
r.resource.Spec.Ports[0].Name = "kube-apiserver"
r.resource.Spec.Ports[0].Protocol = corev1.ProtocolTCP
r.resource.Spec.Ports[0].Port = tenantControlPlane.Spec.NetworkProfile.Port
r.resource.Spec.Ports[0].TargetPort = intstr.FromInt32(tenantControlPlane.Spec.NetworkProfile.Port)
var ports []corev1.ServicePort
for i, port := range r.resource.Spec.Ports {
switch {
case i == 0:
port.Name = "kube-apiserver"
port.Protocol = corev1.ProtocolTCP
port.Port = tenantControlPlane.Spec.NetworkProfile.Port
port.TargetPort = intstr.FromInt32(tenantControlPlane.Spec.NetworkProfile.Port)
ports = append(ports, port)
case i == 1 && port.Name == "konnectivity-server":
ports = append(ports, port)
}
}
for _, port := range tenantControlPlane.Spec.ControlPlane.Service.AdditionalPorts {
ports = append(ports, corev1.ServicePort{
Name: port.Name,
Protocol: port.Protocol,
AppProtocol: port.AppProtocol,
Port: port.Port,
TargetPort: port.TargetPort,
NodePort: 0,
})
}
r.resource.Spec.Ports = ports
switch tenantControlPlane.Spec.ControlPlane.Service.ServiceType {
case kamajiv1alpha1.ServiceTypeLoadBalancer: