diff --git a/config/crd/bases/postgres-operator.crunchydata.com_postgresclusters.yaml b/config/crd/bases/postgres-operator.crunchydata.com_postgresclusters.yaml index 914440f580..0aa09e626e 100644 --- a/config/crd/bases/postgres-operator.crunchydata.com_postgresclusters.yaml +++ b/config/crd/bases/postgres-operator.crunchydata.com_postgresclusters.yaml @@ -14663,6 +14663,21 @@ spec: - Local maxLength: 10 type: string + ipFamilies: + items: + enum: + - IPv4 + - IPv6 + - foo + type: string + type: array + ipFamilyPolicy: + description: 'More info: https://kubernetes.io/docs/reference/kubernetes-api/service-resources/service-v1/' + enum: + - SingleStack + - PreferDualStack + - RequireDualStack + type: string metadata: description: Metadata contains metadata for custom resources properties: @@ -15005,6 +15020,21 @@ spec: - Local maxLength: 10 type: string + ipFamilies: + items: + enum: + - IPv4 + - IPv6 + - foo + type: string + type: array + ipFamilyPolicy: + description: 'More info: https://kubernetes.io/docs/reference/kubernetes-api/service-resources/service-v1/' + enum: + - SingleStack + - PreferDualStack + - RequireDualStack + type: string metadata: description: Metadata contains metadata for custom resources properties: @@ -15053,6 +15083,21 @@ spec: - Local maxLength: 10 type: string + ipFamilies: + items: + enum: + - IPv4 + - IPv6 + - foo + type: string + type: array + ipFamilyPolicy: + description: 'More info: https://kubernetes.io/docs/reference/kubernetes-api/service-resources/service-v1/' + enum: + - SingleStack + - PreferDualStack + - RequireDualStack + type: string metadata: description: Metadata contains metadata for custom resources properties: @@ -16749,6 +16794,21 @@ spec: - Local maxLength: 10 type: string + ipFamilies: + items: + enum: + - IPv4 + - IPv6 + - foo + type: string + type: array + ipFamilyPolicy: + description: 'More info: https://kubernetes.io/docs/reference/kubernetes-api/service-resources/service-v1/' + enum: + - SingleStack + - PreferDualStack + - RequireDualStack + type: string metadata: description: Metadata contains metadata for custom resources properties: diff --git a/internal/controller/postgrescluster/cluster.go b/internal/controller/postgrescluster/cluster.go index 7e863fdadf..b03b15048c 100644 --- a/internal/controller/postgrescluster/cluster.go +++ b/internal/controller/postgrescluster/cluster.go @@ -267,6 +267,19 @@ func (r *Reconciler) generateClusterReplicaService( } service.Spec.ExternalTrafficPolicy = initialize.FromPointer(spec.ExternalTrafficPolicy) service.Spec.InternalTrafficPolicy = spec.InternalTrafficPolicy + + // Set IPFamilyPolicy and IPFamilies + if spec.IPFamilyPolicy != "" { + policy := corev1.IPFamilyPolicyType(spec.IPFamilyPolicy) + service.Spec.IPFamilyPolicy = &policy + } + if len(spec.IPFamilies) > 0 { + service.Spec.IPFamilies = []corev1.IPFamily{} + for _, family := range spec.IPFamilies { + service.Spec.IPFamilies = append(service.Spec.IPFamilies, corev1.IPFamily(family)) + } + } + } service.Spec.Ports = []corev1.ServicePort{servicePort} diff --git a/internal/controller/postgrescluster/patroni.go b/internal/controller/postgrescluster/patroni.go index 293690a77b..5efb763314 100644 --- a/internal/controller/postgrescluster/patroni.go +++ b/internal/controller/postgrescluster/patroni.go @@ -271,6 +271,18 @@ func (r *Reconciler) generatePatroniLeaderLeaseService( } service.Spec.ExternalTrafficPolicy = initialize.FromPointer(spec.ExternalTrafficPolicy) service.Spec.InternalTrafficPolicy = spec.InternalTrafficPolicy + + // Set IPFamilyPolicy and IPFamilies + if spec.IPFamilyPolicy != "" { + policy := corev1.IPFamilyPolicyType(spec.IPFamilyPolicy) + service.Spec.IPFamilyPolicy = &policy + } + if len(spec.IPFamilies) > 0 { + service.Spec.IPFamilies = []corev1.IPFamily{} + for _, family := range spec.IPFamilies { + service.Spec.IPFamilies = append(service.Spec.IPFamilies, corev1.IPFamily(family)) + } + } } service.Spec.Ports = []corev1.ServicePort{servicePort} diff --git a/internal/controller/postgrescluster/pgadmin.go b/internal/controller/postgrescluster/pgadmin.go index f102405b47..4332b80189 100644 --- a/internal/controller/postgrescluster/pgadmin.go +++ b/internal/controller/postgrescluster/pgadmin.go @@ -183,6 +183,18 @@ func (r *Reconciler) generatePGAdminService( } service.Spec.ExternalTrafficPolicy = initialize.FromPointer(spec.ExternalTrafficPolicy) service.Spec.InternalTrafficPolicy = spec.InternalTrafficPolicy + + // Set IPFamilyPolicy and IPFamilies + if spec.IPFamilyPolicy != "" { + policy := corev1.IPFamilyPolicyType(spec.IPFamilyPolicy) + service.Spec.IPFamilyPolicy = &policy + } + if len(spec.IPFamilies) > 0 { + service.Spec.IPFamilies = []corev1.IPFamily{} + for _, family := range spec.IPFamilies { + service.Spec.IPFamilies = append(service.Spec.IPFamilies, corev1.IPFamily(family)) + } + } } service.Spec.Ports = []corev1.ServicePort{servicePort} diff --git a/internal/controller/postgrescluster/pgbouncer.go b/internal/controller/postgrescluster/pgbouncer.go index eb71c189f6..704f8b5f3d 100644 --- a/internal/controller/postgrescluster/pgbouncer.go +++ b/internal/controller/postgrescluster/pgbouncer.go @@ -306,6 +306,18 @@ func (r *Reconciler) generatePGBouncerService( } service.Spec.ExternalTrafficPolicy = initialize.FromPointer(spec.ExternalTrafficPolicy) service.Spec.InternalTrafficPolicy = spec.InternalTrafficPolicy + + // Set IPFamilyPolicy and IPFamilies + if spec.IPFamilyPolicy != "" { + policy := corev1.IPFamilyPolicyType(spec.IPFamilyPolicy) + service.Spec.IPFamilyPolicy = &policy + } + if len(spec.IPFamilies) > 0 { + service.Spec.IPFamilies = []corev1.IPFamily{} + for _, family := range spec.IPFamilies { + service.Spec.IPFamilies = append(service.Spec.IPFamilies, corev1.IPFamily(family)) + } + } } service.Spec.Ports = []corev1.ServicePort{servicePort} diff --git a/pkg/apis/postgres-operator.crunchydata.com/v1beta1/shared_types.go b/pkg/apis/postgres-operator.crunchydata.com/v1beta1/shared_types.go index 6de2b35336..2897c539a6 100644 --- a/pkg/apis/postgres-operator.crunchydata.com/v1beta1/shared_types.go +++ b/pkg/apis/postgres-operator.crunchydata.com/v1beta1/shared_types.go @@ -20,8 +20,12 @@ type SchemalessObject map[string]any // DeepCopy creates a new SchemalessObject by copying the receiver. func (in SchemalessObject) DeepCopy() SchemalessObject { return runtime.DeepCopyJSON(in) + } +// +kubebuilder:validation:Enum=IPv4;IPv6;foo +type IPFamily string + type ServiceSpec struct { // +optional Metadata *Metadata `json:"metadata,omitempty"` @@ -44,6 +48,15 @@ type ServiceSpec struct { // +kubebuilder:validation:Enum={ClusterIP,NodePort,LoadBalancer} Type string `json:"type"` + // More info: https://kubernetes.io/docs/reference/kubernetes-api/service-resources/service-v1/ + // --- + // +optional + // +kubebuilder:validation:Enum=SingleStack;PreferDualStack;RequireDualStack + IPFamilyPolicy string `json:"ipFamilyPolicy,omitempty"` + + // +optional + IPFamilies []IPFamily `json:"ipFamilies,omitempty"` + // More info: https://kubernetes.io/docs/concepts/services-networking/service/#traffic-policies // --- // Kubernetes assumes the evaluation cost of an enum value is very large. diff --git a/pkg/apis/postgres-operator.crunchydata.com/v1beta1/zz_generated.deepcopy.go b/pkg/apis/postgres-operator.crunchydata.com/v1beta1/zz_generated.deepcopy.go index 5eb63bd867..b632e4ac38 100644 --- a/pkg/apis/postgres-operator.crunchydata.com/v1beta1/zz_generated.deepcopy.go +++ b/pkg/apis/postgres-operator.crunchydata.com/v1beta1/zz_generated.deepcopy.go @@ -2213,6 +2213,11 @@ func (in *ServiceSpec) DeepCopyInto(out *ServiceSpec) { *out = new(int32) **out = **in } + if in.IPFamilies != nil { + in, out := &in.IPFamilies, &out.IPFamilies + *out = make([]IPFamily, len(*in)) + copy(*out, *in) + } if in.InternalTrafficPolicy != nil { in, out := &in.InternalTrafficPolicy, &out.InternalTrafficPolicy *out = new(corev1.ServiceInternalTrafficPolicy)