Skip to content

Commit

Permalink
Refactor(trait): affinity
Browse files Browse the repository at this point in the history
* Introduced the trait for Knative and CronJob

Closes apache#2047
  • Loading branch information
squakez committed Mar 1, 2021
1 parent 640ae45 commit 6740f60
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 73 deletions.
45 changes: 14 additions & 31 deletions pkg/trait/affinity.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import (
"fmt"
"strings"

appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
Expand Down Expand Up @@ -74,28 +73,27 @@ func (t *affinityTrait) Configure(e *Environment) (bool, error) {
}

func (t *affinityTrait) Apply(e *Environment) (err error) {
var deployment *appsv1.Deployment
e.Resources.VisitDeployment(func(d *appsv1.Deployment) {
if d.Name == e.Integration.Name {
deployment = d
podSpec := e.GetIntegrationPodSpec()

if podSpec != nil {
if podSpec.Affinity == nil {
podSpec.Affinity = &corev1.Affinity{}
}
})
if deployment != nil {
if err := t.addNodeAffinity(e, deployment); err != nil {
if err := t.addNodeAffinity(e, podSpec); err != nil {
return err
}
if err := t.addPodAffinity(e, deployment); err != nil {
if err := t.addPodAffinity(e, podSpec); err != nil {
return err
}
if err := t.addPodAntiAffinity(e, deployment); err != nil {
if err := t.addPodAntiAffinity(e, podSpec); err != nil {
return err
}
}

return nil
}

func (t *affinityTrait) addNodeAffinity(_ *Environment, deployment *appsv1.Deployment) error {
func (t *affinityTrait) addNodeAffinity(_ *Environment, podSpec *corev1.PodSpec) error {
if len(t.NodeAffinityLabels) == 0 {
return nil
}
Expand Down Expand Up @@ -129,16 +127,11 @@ func (t *affinityTrait) addNodeAffinity(_ *Environment, deployment *appsv1.Deplo
},
}

if deployment.Spec.Template.Spec.Affinity == nil {
deployment.Spec.Template.Spec.Affinity = &corev1.Affinity{}
}

deployment.Spec.Template.Spec.Affinity.NodeAffinity = nodeAffinity

podSpec.Affinity.NodeAffinity = nodeAffinity
return nil
}

func (t *affinityTrait) addPodAffinity(e *Environment, deployment *appsv1.Deployment) error {
func (t *affinityTrait) addPodAffinity(e *Environment, podSpec *corev1.PodSpec) error {
if util.IsNilOrFalse(t.PodAffinity) && len(t.PodAffinityLabels) == 0 {
return nil
}
Expand Down Expand Up @@ -185,16 +178,11 @@ func (t *affinityTrait) addPodAffinity(e *Environment, deployment *appsv1.Deploy
},
}

if deployment.Spec.Template.Spec.Affinity == nil {
deployment.Spec.Template.Spec.Affinity = &corev1.Affinity{}
}

deployment.Spec.Template.Spec.Affinity.PodAffinity = podAffinity

podSpec.Affinity.PodAffinity = podAffinity
return nil
}

func (t *affinityTrait) addPodAntiAffinity(e *Environment, deployment *appsv1.Deployment) error {
func (t *affinityTrait) addPodAntiAffinity(e *Environment, podSpec *corev1.PodSpec) error {
if util.IsNilOrFalse(t.PodAntiAffinity) && len(t.PodAntiAffinityLabels) == 0 {
return nil
}
Expand Down Expand Up @@ -241,12 +229,7 @@ func (t *affinityTrait) addPodAntiAffinity(e *Environment, deployment *appsv1.De
},
}

if deployment.Spec.Template.Spec.Affinity == nil {
deployment.Spec.Template.Spec.Affinity = &corev1.Affinity{}
}

deployment.Spec.Template.Spec.Affinity.PodAntiAffinity = podAntiAffinity

podSpec.Affinity.PodAntiAffinity = podAntiAffinity
return nil
}

Expand Down
109 changes: 67 additions & 42 deletions pkg/trait/affinity_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,25 +22,25 @@ import (

"github.com/stretchr/testify/assert"

appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
"github.com/apache/camel-k/pkg/util"
"github.com/apache/camel-k/pkg/util/kubernetes"
)

func TestConfigureAffinityTraitDoesSucceed(t *testing.T) {
affinityTrait, environment, _ := createNominalAffinityTest()
affinityTrait := createNominalAffinityTest()
environment, _ := createNominalDeploymentTraitTest()
configured, err := affinityTrait.Configure(environment)

assert.True(t, configured)
assert.Nil(t, err)
}

func TestConfigureAffinityTraitWithConflictingAffinitiesFails(t *testing.T) {
affinityTrait, environment, _ := createNominalAffinityTest()
affinityTrait := createNominalAffinityTest()
environment, _ := createNominalDeploymentTraitTest()
affinityTrait.PodAffinity = util.BoolP(true)
affinityTrait.PodAntiAffinity = util.BoolP(true)
configured, err := affinityTrait.Configure(environment)
Expand All @@ -50,31 +50,55 @@ func TestConfigureAffinityTraitWithConflictingAffinitiesFails(t *testing.T) {
}

func TestConfigureDisabledAffinityTraitFails(t *testing.T) {
affinityTrait, environment, _ := createNominalAffinityTest()
affinityTrait := createNominalAffinityTest()
affinityTrait.Enabled = new(bool)
environment, _ := createNominalDeploymentTraitTest()
configured, err := affinityTrait.Configure(environment)

assert.False(t, configured)
assert.Nil(t, err)
}

func TestApplyEmptyAffinityLabelsDoesSucceed(t *testing.T) {
affinityTrait, environment, _ := createNominalAffinityTest()
affinityTrait := createNominalAffinityTest()

err := affinityTrait.Apply(environment)
environment, deployment := createNominalDeploymentTraitTest()
testApplyEmptyAffinityLabelsDoesSucceed(t, affinityTrait, environment, deployment.Spec.Template.Spec.Affinity)

environment, knativeService := createNominalKnativeServiceTraitTest()
testApplyEmptyAffinityLabelsDoesSucceed(t, affinityTrait, environment, knativeService.Spec.Template.Spec.Affinity)

environment, cronJob := createNominalCronJobTraitTest()
testApplyEmptyAffinityLabelsDoesSucceed(t, affinityTrait, environment, cronJob.Spec.JobTemplate.Spec.Template.Spec.Affinity)
}

func testApplyEmptyAffinityLabelsDoesSucceed(t *testing.T, trait *affinityTrait, environment *Environment, affinity *corev1.Affinity) {
err := trait.Apply(environment)

assert.Nil(t, err)
assert.Nil(t, affinity)
}

func TestApplyNodeAffinityLabelsDoesSucceed(t *testing.T) {
affinityTrait, environment, deployment := createNominalAffinityTest()
affinityTrait := createNominalAffinityTest()
affinityTrait.NodeAffinityLabels = []string{"criteria = value"}

err := affinityTrait.Apply(environment)
environment, deployment := createNominalDeploymentTraitTest()
testApplyNodeAffinityLabelsDoesSucceed(t, affinityTrait, environment, &deployment.Spec.Template.Spec)

environment, knativeService := createNominalKnativeServiceTraitTest()
testApplyNodeAffinityLabelsDoesSucceed(t, affinityTrait, environment, &knativeService.Spec.Template.Spec.PodSpec)

environment, cronJob := createNominalCronJobTraitTest()
testApplyNodeAffinityLabelsDoesSucceed(t, affinityTrait, environment, &cronJob.Spec.JobTemplate.Spec.Template.Spec)
}

func testApplyNodeAffinityLabelsDoesSucceed(t *testing.T, trait *affinityTrait, environment *Environment, podSpec *corev1.PodSpec) {
err := trait.Apply(environment)

assert.Nil(t, err)
assert.NotNil(t, deployment.Spec.Template.Spec.Affinity.NodeAffinity)
nodeAffinity := deployment.Spec.Template.Spec.Affinity.NodeAffinity
assert.NotNil(t, podSpec.Affinity.NodeAffinity)
nodeAffinity := podSpec.Affinity.NodeAffinity
assert.NotNil(t, nodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms[0].MatchExpressions[0])
nodeSelectorRequirement := nodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms[0].MatchExpressions[0]
assert.Equal(t, "criteria", nodeSelectorRequirement.Key)
Expand All @@ -83,15 +107,26 @@ func TestApplyNodeAffinityLabelsDoesSucceed(t *testing.T) {
}

func TestApplyPodAntiAffinityLabelsDoesSucceed(t *testing.T) {
affinityTrait, environment, deployment := createNominalAffinityTest()
affinityTrait := createNominalAffinityTest()
affinityTrait.PodAntiAffinity = util.BoolP(true)
affinityTrait.PodAntiAffinityLabels = []string{"criteria != value"}

err := affinityTrait.Apply(environment)
environment, deployment := createNominalDeploymentTraitTest()
testApplyPodAntiAffinityLabelsDoesSucceed(t, affinityTrait, environment, &deployment.Spec.Template.Spec)

environment, knativeService := createNominalKnativeServiceTraitTest()
testApplyPodAntiAffinityLabelsDoesSucceed(t, affinityTrait, environment, &knativeService.Spec.Template.Spec.PodSpec)

environment, cronJob := createNominalCronJobTraitTest()
testApplyPodAntiAffinityLabelsDoesSucceed(t, affinityTrait, environment, &cronJob.Spec.JobTemplate.Spec.Template.Spec)
}

func testApplyPodAntiAffinityLabelsDoesSucceed(t *testing.T, trait *affinityTrait, environment *Environment, podSpec *corev1.PodSpec) {
err := trait.Apply(environment)

assert.Nil(t, err)
assert.NotNil(t, deployment.Spec.Template.Spec.Affinity.PodAntiAffinity)
podAntiAffinity := deployment.Spec.Template.Spec.Affinity.PodAntiAffinity
assert.NotNil(t, podSpec.Affinity.PodAntiAffinity)
podAntiAffinity := podSpec.Affinity.PodAntiAffinity
assert.NotNil(t, podAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution[0].LabelSelector.MatchExpressions[0])
userRequirement := podAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution[0].LabelSelector.MatchExpressions[0]
assert.Equal(t, "criteria", userRequirement.Key)
Expand All @@ -105,15 +140,26 @@ func TestApplyPodAntiAffinityLabelsDoesSucceed(t *testing.T) {
}

func TestApplyPodAffinityLabelsDoesSucceed(t *testing.T) {
affinityTrait, environment, deployment := createNominalAffinityTest()
affinityTrait := createNominalAffinityTest()
affinityTrait.PodAffinity = util.BoolP(true)
affinityTrait.PodAffinityLabels = []string{"!criteria"}

err := affinityTrait.Apply(environment)
environment, deployment := createNominalDeploymentTraitTest()
testApplyPodAffinityLabelsDoesSucceed(t, affinityTrait, environment, &deployment.Spec.Template.Spec)

environment, knativeService := createNominalKnativeServiceTraitTest()
testApplyPodAffinityLabelsDoesSucceed(t, affinityTrait, environment, &knativeService.Spec.Template.Spec.PodSpec)

environment, cronJob := createNominalCronJobTraitTest()
testApplyPodAffinityLabelsDoesSucceed(t, affinityTrait, environment, &cronJob.Spec.JobTemplate.Spec.Template.Spec)
}

func testApplyPodAffinityLabelsDoesSucceed(t *testing.T, trait *affinityTrait, environment *Environment, podSpec *corev1.PodSpec) {
err := trait.Apply(environment)

assert.Nil(t, err)
assert.NotNil(t, deployment.Spec.Template.Spec.Affinity.PodAffinity)
podAffinity := deployment.Spec.Template.Spec.Affinity.PodAffinity
assert.NotNil(t, podSpec.Affinity.PodAffinity)
podAffinity := podSpec.Affinity.PodAffinity
assert.NotNil(t, podAffinity.RequiredDuringSchedulingIgnoredDuringExecution[0].LabelSelector.MatchExpressions[0])
userRequirement := podAffinity.RequiredDuringSchedulingIgnoredDuringExecution[0].LabelSelector.MatchExpressions[0]
assert.Equal(t, "criteria", userRequirement.Key)
Expand All @@ -125,31 +171,10 @@ func TestApplyPodAffinityLabelsDoesSucceed(t *testing.T) {
assert.ElementsMatch(t, [1]string{"integration-name"}, integrationRequirement.Values)
}

func createNominalAffinityTest() (*affinityTrait, *Environment, *appsv1.Deployment) {
func createNominalAffinityTest() *affinityTrait {
trait := newAffinityTrait().(*affinityTrait)
enabled := true
trait.Enabled = &enabled

deployment := &appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: "integration-name",
},
Spec: appsv1.DeploymentSpec{
Template: corev1.PodTemplateSpec{},
},
}

environment := &Environment{
Integration: &v1.Integration{
ObjectMeta: metav1.ObjectMeta{
Name: "integration-name",
},
Status: v1.IntegrationStatus{
Phase: v1.IntegrationPhaseDeploying,
},
},
Resources: kubernetes.NewCollection(deployment),
}

return trait, environment, deployment
return trait
}

0 comments on commit 6740f60

Please sign in to comment.