Skip to content

Commit

Permalink
Expose PodAffinity and PodAntiAffinity struct and build overrides
Browse files Browse the repository at this point in the history
This patch introduces a very basic struct to expose Pod Affinity/Antiaffinity
interfaces as part of the Topology CR spec and allows to patch the
(opinionated) default that is currently applied to the services.

Signed-off-by: Francesco Pantano <[email protected]>
  • Loading branch information
fmount committed Dec 16, 2024
1 parent d172b3a commit 7534df7
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 4 deletions.
49 changes: 48 additions & 1 deletion modules/common/affinity/affinity.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,12 @@ limitations under the License.
package affinity

import (
"encoding/json"
"fmt"
corev1 "k8s.io/api/core/v1"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/strategicpatch"
)

// DistributePods - returns rule to ensure that two replicas of the same selector
Expand All @@ -27,8 +31,9 @@ func DistributePods(
selectorKey string,
selectorValues []string,
topologyKey string,
overrides *OverrideSpec,
) *corev1.Affinity {
return &corev1.Affinity{
defaultAffinity := &corev1.Affinity{
PodAntiAffinity: &corev1.PodAntiAffinity{
// This rule ensures that two replicas of the same selector
// should not run if possible on the same worker node
Expand All @@ -53,4 +58,46 @@ func DistributePods(
},
},
}
// patch the default affinity Object with the data passed as input
if overrides != nil {
patchedAffinity, _ := toCoreAffinity(defaultAffinity, overrides)
return patchedAffinity
}
return defaultAffinity
}

func toCoreAffinity(
affinity *v1.Affinity,
override *OverrideSpec,
) (*v1.Affinity, error) {

aff := &v1.Affinity{
PodAntiAffinity: affinity.PodAntiAffinity,
PodAffinity: affinity.PodAffinity,
}
if override != nil {
if override != nil {
origAffinit, err := json.Marshal(affinity)
if err != nil {
return aff, fmt.Errorf("error marshalling Affinity Spec: %w", err)
}
patch, err := json.Marshal(override)
if err != nil {
return aff, fmt.Errorf("error marshalling Affinity Spec: %w", err)
}

patchedJSON, err := strategicpatch.StrategicMergePatch(origAffinit, patch, v1.Affinity{})
if err != nil {
return aff, fmt.Errorf("error patching Affinity Spec: %w", err)
}

patchedSpec := v1.Affinity{}
err = json.Unmarshal(patchedJSON, &patchedSpec)
if err != nil {
return aff, fmt.Errorf("error unmarshalling patched Service Spec: %w", err)
}
aff = &patchedSpec
}
}
return aff, nil
}
4 changes: 1 addition & 3 deletions modules/common/affinity/affinity_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,7 @@ func TestDistributePods(t *testing.T) {

t.Run("Default pod distribution", func(t *testing.T) {
g := NewWithT(t)

d := DistributePods("ThisSelector", []string{"selectorValue1", "selectorValue2"}, "ThisTopologyKey")

d := DistributePods("ThisSelector", []string{"selectorValue1", "selectorValue2"}, "ThisTopologyKey", nil)
g.Expect(d).To(BeEquivalentTo(affinityObj))
})
}
36 changes: 36 additions & 0 deletions modules/common/affinity/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
Copyright 2024 Red Hat
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// +kubebuilder:object:generate:=true

package affinity

import (
corev1 "k8s.io/api/core/v1"
)

// OverrideSpec -
type OverrideSpec struct {
// Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)).
// +optional
PodAffinity *corev1.PodAffinity `json:"podAffinity,omitempty" protobuf:"bytes,2,opt,name=podAffinity"`
// Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)).
// +optional
PodAntiAffinity *corev1.PodAntiAffinity `json:"podAntiAffinity,omitempty" protobuf:"bytes,3,opt,name=podAntiAffinity"`
// Describes node affinity scheduling rules for the pod.
// +optional
NodeAffinity *corev1.NodeAffinity `json:"nodeAffinity,omitempty" protobuf:"bytes,1,opt,name=nodeAffinity"`
}
51 changes: 51 additions & 0 deletions modules/common/affinity/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 7534df7

Please sign in to comment.