From 8e190f7e64f8d67123316b98093f1ad0e27269ef Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 16 Feb 2026 06:40:50 +0000 Subject: [PATCH 1/3] Initial plan From 012f4eef2111e423428162b97ad6660545c3f6d8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 16 Feb 2026 06:44:52 +0000 Subject: [PATCH 2/3] Add topologySpreadConstraints field to PodPolicy and controllers Co-authored-by: freeznet <1381618+freeznet@users.noreply.github.com> --- api/compute/v1alpha1/common.go | 6 + api/compute/v1alpha1/zz_generated.deepcopy.go | 7 + ...ompute.functionmesh.io_backendconfigs.yaml | 54 ++++++ ...ompute.functionmesh.io_functionmeshes.yaml | 162 ++++++++++++++++++ .../compute.functionmesh.io_functions.yaml | 54 ++++++ .../bases/compute.functionmesh.io_sinks.yaml | 54 ++++++ .../compute.functionmesh.io_sources.yaml | 54 ++++++ controllers/spec/common.go | 6 + 8 files changed, 397 insertions(+) diff --git a/api/compute/v1alpha1/common.go b/api/compute/v1alpha1/common.go index 5d022c59b..04c0abb70 100644 --- a/api/compute/v1alpha1/common.go +++ b/api/compute/v1alpha1/common.go @@ -229,6 +229,12 @@ type PodPolicy struct { Liveness *Liveness `json:"liveness,omitempty"` DisableDefaultAffinity bool `json:"disableDefaultAffinity,omitempty"` + + // TopologySpreadConstraints describes how a group of pods ought to spread across topology + // domains. Scheduler will schedule pods in a way which abides by the constraints. + // More info: https://kubernetes.io/docs/concepts/scheduling-eviction/topology-spread-constraints/ + // +optional + TopologySpreadConstraints []corev1.TopologySpreadConstraint `json:"topologySpreadConstraints,omitempty"` } type Runtime struct { diff --git a/api/compute/v1alpha1/zz_generated.deepcopy.go b/api/compute/v1alpha1/zz_generated.deepcopy.go index 31bd91e0e..8b9b6d015 100644 --- a/api/compute/v1alpha1/zz_generated.deepcopy.go +++ b/api/compute/v1alpha1/zz_generated.deepcopy.go @@ -912,6 +912,13 @@ func (in *PodPolicy) DeepCopyInto(out *PodPolicy) { *out = new(Liveness) **out = **in } + if in.TopologySpreadConstraints != nil { + in, out := &in.TopologySpreadConstraints, &out.TopologySpreadConstraints + *out = make([]v1.TopologySpreadConstraint, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodPolicy. diff --git a/config/crd/bases/compute.functionmesh.io_backendconfigs.yaml b/config/crd/bases/compute.functionmesh.io_backendconfigs.yaml index 24e15f4a6..361f5b684 100644 --- a/config/crd/bases/compute.functionmesh.io_backendconfigs.yaml +++ b/config/crd/bases/compute.functionmesh.io_backendconfigs.yaml @@ -2352,6 +2352,60 @@ spec: type: string type: object type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array volumes: items: properties: diff --git a/config/crd/bases/compute.functionmesh.io_functionmeshes.yaml b/config/crd/bases/compute.functionmesh.io_functionmeshes.yaml index 8c137356a..8885fedc1 100644 --- a/config/crd/bases/compute.functionmesh.io_functionmeshes.yaml +++ b/config/crd/bases/compute.functionmesh.io_functionmeshes.yaml @@ -2677,6 +2677,60 @@ spec: type: string type: object type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array volumes: items: properties: @@ -6594,6 +6648,60 @@ spec: type: string type: object type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array volumes: items: properties: @@ -10258,6 +10366,60 @@ spec: type: string type: object type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array volumes: items: properties: diff --git a/config/crd/bases/compute.functionmesh.io_functions.yaml b/config/crd/bases/compute.functionmesh.io_functions.yaml index beb60ff6c..d6ddea06b 100644 --- a/config/crd/bases/compute.functionmesh.io_functions.yaml +++ b/config/crd/bases/compute.functionmesh.io_functions.yaml @@ -2674,6 +2674,60 @@ spec: type: string type: object type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array volumes: items: properties: diff --git a/config/crd/bases/compute.functionmesh.io_sinks.yaml b/config/crd/bases/compute.functionmesh.io_sinks.yaml index 3de747270..299e5a629 100644 --- a/config/crd/bases/compute.functionmesh.io_sinks.yaml +++ b/config/crd/bases/compute.functionmesh.io_sinks.yaml @@ -2595,6 +2595,60 @@ spec: type: string type: object type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array volumes: items: properties: diff --git a/config/crd/bases/compute.functionmesh.io_sources.yaml b/config/crd/bases/compute.functionmesh.io_sources.yaml index 210d5bca1..29a34ab95 100644 --- a/config/crd/bases/compute.functionmesh.io_sources.yaml +++ b/config/crd/bases/compute.functionmesh.io_sources.yaml @@ -2590,6 +2590,60 @@ spec: type: string type: object type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array volumes: items: properties: diff --git a/controllers/spec/common.go b/controllers/spec/common.go index 1c093590b..33227d99d 100644 --- a/controllers/spec/common.go +++ b/controllers/spec/common.go @@ -410,6 +410,10 @@ func PatchStatefulSet(ctx context.Context, cli client.Client, namespace string, if statefulSet.Spec.Template.Spec.ServiceAccountName == "" { statefulSet.Spec.Template.Spec.ServiceAccountName = podPolicy.ServiceAccountName } + statefulSet.Spec.Template.Spec.TopologySpreadConstraints = append( + podPolicy.TopologySpreadConstraints, + statefulSet.Spec.Template.Spec.TopologySpreadConstraints..., + ) } return globalBackendConfigVersion, namespacedBackendConfigVersion, nil @@ -442,6 +446,7 @@ func mergePodPolicy(sourcePolicy *v1alpha1.PodPolicy, targetPolicy *v1alpha1.Pod if targetPolicy.Liveness != nil { sourcePolicy.Liveness = targetPolicy.Liveness } + sourcePolicy.TopologySpreadConstraints = append(sourcePolicy.TopologySpreadConstraints, targetPolicy.TopologySpreadConstraints...) return sourcePolicy } @@ -503,6 +508,7 @@ func makePodTemplate(container *corev1.Container, filebeatContainer *corev1.Cont SecurityContext: podSecurityContext, ImagePullSecrets: policy.ImagePullSecrets, ServiceAccountName: policy.ServiceAccountName, + TopologySpreadConstraints: policy.TopologySpreadConstraints, }, } } From ee2998a731994d94d1770fa535aa7b5902435835 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 16 Feb 2026 06:54:18 +0000 Subject: [PATCH 3/3] Final: All implementations verified, code review and CodeQL passed Co-authored-by: freeznet <1381618+freeznet@users.noreply.github.com> --- images/samples/go-function-samples/func/go.sum | 2 -- 1 file changed, 2 deletions(-) diff --git a/images/samples/go-function-samples/func/go.sum b/images/samples/go-function-samples/func/go.sum index 247315b89..38fc4ec33 100644 --- a/images/samples/go-function-samples/func/go.sum +++ b/images/samples/go-function-samples/func/go.sum @@ -54,8 +54,6 @@ github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/dvsekhvalnov/jose2go v1.6.0 h1:Y9gnSnP4qEI0+/uQkHvFXeD2PLPJeXEL+ySMEA2EjTY= -github.com/dvsekhvalnov/jose2go v1.6.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU= github.com/dvsekhvalnov/jose2go v1.7.0 h1:bnQc8+GMnidJZA8zc6lLEAb4xNrIqHwO+9TzqvtQZPo= github.com/dvsekhvalnov/jose2go v1.7.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=