Skip to content

Commit

Permalink
Merge pull request #383 from olliewalsh/node_selectors
Browse files Browse the repository at this point in the history
Ensure nodeSelector logic is consistent for all operators
  • Loading branch information
openshift-merge-bot[bot] authored Nov 21, 2024
2 parents 2690cc1 + 39aa25e commit a34ad51
Show file tree
Hide file tree
Showing 11 changed files with 293 additions and 20 deletions.
2 changes: 1 addition & 1 deletion api/v1beta1/ovncontroller_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ type OVNControllerSpecCore struct {

// +kubebuilder:validation:Optional
// NodeSelector to target subset of worker nodes running this service
NodeSelector map[string]string `json:"nodeSelector,omitempty"`
NodeSelector *map[string]string `json:"nodeSelector,omitempty"`

// +kubebuilder:validation:Optional
// NetworkAttachment is a NetworkAttachment resource name to expose the service to the given network.
Expand Down
2 changes: 1 addition & 1 deletion api/v1beta1/ovndbcluster_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ type OVNDBClusterSpecCore struct {

// +kubebuilder:validation:Optional
// NodeSelector to target subset of worker nodes running this service
NodeSelector map[string]string `json:"nodeSelector,omitempty"`
NodeSelector *map[string]string `json:"nodeSelector,omitempty"`

// +kubebuilder:validation:Optional
// +kubebuilder:default=info
Expand Down
2 changes: 1 addition & 1 deletion api/v1beta1/ovnnorthd_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ type OVNNorthdSpecCore struct {

// +kubebuilder:validation:Optional
// NodeSelector to target subset of worker nodes running this service
NodeSelector map[string]string `json:"nodeSelector,omitempty"`
NodeSelector *map[string]string `json:"nodeSelector,omitempty"`

// +kubebuilder:validation:Optional
// +kubebuilder:default=info
Expand Down
30 changes: 21 additions & 9 deletions api/v1beta1/zz_generated.deepcopy.go

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

1 change: 1 addition & 0 deletions pkg/ovncontroller/configjob.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ func ConfigJob(
},
Volumes: GetOVNControllerVolumes(instance.Name, instance.Namespace),
NodeName: ovnPod.Spec.NodeName,
// ^ NodeSelector not required
},
},
},
Expand Down
8 changes: 4 additions & 4 deletions pkg/ovncontroller/daemonset.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,8 @@ func CreateOVNDaemonSet(
},
}

if instance.Spec.NodeSelector != nil && len(instance.Spec.NodeSelector) > 0 {
daemonset.Spec.Template.Spec.NodeSelector = instance.Spec.NodeSelector
if instance.Spec.NodeSelector != nil {
daemonset.Spec.Template.Spec.NodeSelector = *instance.Spec.NodeSelector
}

return daemonset
Expand Down Expand Up @@ -317,8 +317,8 @@ func CreateOVSDaemonSet(
},
}

if instance.Spec.NodeSelector != nil && len(instance.Spec.NodeSelector) > 0 {
daemonset.Spec.Template.Spec.NodeSelector = instance.Spec.NodeSelector
if instance.Spec.NodeSelector != nil {
daemonset.Spec.Template.Spec.NodeSelector = *instance.Spec.NodeSelector
}

if len(annotations) > 0 {
Expand Down
4 changes: 2 additions & 2 deletions pkg/ovndbcluster/statefulset.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,8 +219,8 @@ func StatefulSet(
},
corev1.LabelHostname,
)
if instance.Spec.NodeSelector != nil && len(instance.Spec.NodeSelector) > 0 {
statefulset.Spec.Template.Spec.NodeSelector = instance.Spec.NodeSelector
if instance.Spec.NodeSelector != nil {
statefulset.Spec.Template.Spec.NodeSelector = *instance.Spec.NodeSelector
}

return statefulset
Expand Down
4 changes: 2 additions & 2 deletions pkg/ovnnorthd/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,8 @@ func Deployment(
},
corev1.LabelHostname,
)
if instance.Spec.NodeSelector != nil && len(instance.Spec.NodeSelector) > 0 {
deployment.Spec.Template.Spec.NodeSelector = instance.Spec.NodeSelector
if instance.Spec.NodeSelector != nil {
deployment.Spec.Template.Spec.NodeSelector = *instance.Spec.NodeSelector
}

return deployment
Expand Down
100 changes: 100 additions & 0 deletions tests/functional/ovncontroller_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1085,4 +1085,104 @@ var _ = Describe("OVNController controller", func() {
}, timeout, interval).Should(Succeed())
})
})

When("OVNController is created with nodeSelector", func() {
var ovnControllerName types.NamespacedName
var daemonSetName types.NamespacedName
var daemonSetNameOVS types.NamespacedName

BeforeEach(func() {
dbs := CreateOVNDBClusters(namespace, map[string][]string{}, 1)
DeferCleanup(DeleteOVNDBClusters, dbs)

spec := GetDefaultOVNControllerSpec()
nodeSelector := map[string]string{
"foo": "bar",
}
spec.NodeSelector = &nodeSelector
instance := CreateOVNController(namespace, spec)
DeferCleanup(th.DeleteInstance, instance)

ovnControllerName = types.NamespacedName{Name: instance.GetName(), Namespace: instance.GetNamespace()}

daemonSetName = types.NamespacedName{
Namespace: namespace,
Name: "ovn-controller",
}

SimulateDaemonsetNumberReady(daemonSetName)

daemonSetNameOVS = types.NamespacedName{
Namespace: namespace,
Name: "ovn-controller-ovs",
}

SimulateDaemonsetNumberReady(daemonSetNameOVS)
})

It("sets nodeSelector in resource specs", func() {
Eventually(func(g Gomega) {
g.Expect(GetDaemonSet(daemonSetName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"}))
g.Expect(GetDaemonSet(daemonSetNameOVS).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"}))
}, timeout, interval).Should(Succeed())
})

It("updates nodeSelector in resource specs when changed", func() {
Eventually(func(g Gomega) {
g.Expect(GetDaemonSet(daemonSetName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"}))
g.Expect(GetDaemonSet(daemonSetNameOVS).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"}))
}, timeout, interval).Should(Succeed())

Eventually(func(g Gomega) {
ovnController := GetOVNController(ovnControllerName)
newNodeSelector := map[string]string{
"foo2": "bar2",
}
ovnController.Spec.NodeSelector = &newNodeSelector
g.Expect(k8sClient.Update(ctx, ovnController)).Should(Succeed())
}, timeout, interval).Should(Succeed())

Eventually(func(g Gomega) {
g.Expect(GetDaemonSet(daemonSetName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo2": "bar2"}))
g.Expect(GetDaemonSet(daemonSetNameOVS).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo2": "bar2"}))
}, timeout, interval).Should(Succeed())
})

It("removes nodeSelector from resource specs when cleared", func() {
Eventually(func(g Gomega) {
g.Expect(GetDaemonSet(daemonSetName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"}))
g.Expect(GetDaemonSet(daemonSetNameOVS).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"}))
}, timeout, interval).Should(Succeed())

Eventually(func(g Gomega) {
ovnController := GetOVNController(ovnControllerName)
emptyNodeSelector := map[string]string{}
ovnController.Spec.NodeSelector = &emptyNodeSelector
g.Expect(k8sClient.Update(ctx, ovnController)).Should(Succeed())
}, timeout, interval).Should(Succeed())

Eventually(func(g Gomega) {
g.Expect(GetDaemonSet(daemonSetName).Spec.Template.Spec.NodeSelector).To(BeNil())
g.Expect(GetDaemonSet(daemonSetNameOVS).Spec.Template.Spec.NodeSelector).To(BeNil())
}, timeout, interval).Should(Succeed())
})

It("removes nodeSelector from resource specs when nilled", func() {
Eventually(func(g Gomega) {
g.Expect(GetDaemonSet(daemonSetName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"}))
g.Expect(GetDaemonSet(daemonSetNameOVS).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"}))
}, timeout, interval).Should(Succeed())

Eventually(func(g Gomega) {
ovnController := GetOVNController(ovnControllerName)
ovnController.Spec.NodeSelector = nil
g.Expect(k8sClient.Update(ctx, ovnController)).Should(Succeed())
}, timeout, interval).Should(Succeed())

Eventually(func(g Gomega) {
g.Expect(GetDaemonSet(daemonSetName).Spec.Template.Spec.NodeSelector).To(BeNil())
g.Expect(GetDaemonSet(daemonSetNameOVS).Spec.Template.Spec.NodeSelector).To(BeNil())
}, timeout, interval).Should(Succeed())
})
})
})
80 changes: 80 additions & 0 deletions tests/functional/ovndbcluster_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,86 @@ var _ = Describe("OVNDBCluster controller", func() {
})
})

When("A OVNDBCluster instance is created with nodeSelector", func() {
var OVNDBClusterName types.NamespacedName
var statefulSetName types.NamespacedName

BeforeEach(func() {
spec := GetDefaultOVNDBClusterSpec()
nodeSelector := map[string]string{
"foo": "bar",
}
spec.NodeSelector = &nodeSelector
instance := CreateOVNDBCluster(namespace, spec)
OVNDBClusterName = types.NamespacedName{Name: instance.GetName(), Namespace: instance.GetNamespace()}
DeferCleanup(th.DeleteInstance, instance)

statefulSetName = types.NamespacedName{
Namespace: namespace,
Name: "ovsdbserver-nb",
}
th.SimulateStatefulSetReplicaReady(statefulSetName)
})

It("sets nodeSelector in resource specs", func() {
Eventually(func(g Gomega) {
g.Expect(th.GetStatefulSet(statefulSetName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"}))
}, timeout, interval).Should(Succeed())
})

It("updates nodeSelector in resource specs when changed", func() {
Eventually(func(g Gomega) {
g.Expect(th.GetStatefulSet(statefulSetName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"}))
}, timeout, interval).Should(Succeed())

Eventually(func(g Gomega) {
dbCluster := GetOVNDBCluster(OVNDBClusterName)
newNodeSelector := map[string]string{
"foo2": "bar2",
}
dbCluster.Spec.NodeSelector = &newNodeSelector
g.Expect(k8sClient.Update(ctx, dbCluster)).Should(Succeed())
}, timeout, interval).Should(Succeed())

Eventually(func(g Gomega) {
g.Expect(th.GetStatefulSet(statefulSetName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo2": "bar2"}))
}, timeout, interval).Should(Succeed())
})

It("removes nodeSelector from resource specs when cleared", func() {
Eventually(func(g Gomega) {
g.Expect(th.GetStatefulSet(statefulSetName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"}))
}, timeout, interval).Should(Succeed())

Eventually(func(g Gomega) {
dbCluster := GetOVNDBCluster(OVNDBClusterName)
emptyNodeSelector := map[string]string{}
dbCluster.Spec.NodeSelector = &emptyNodeSelector
g.Expect(k8sClient.Update(ctx, dbCluster)).Should(Succeed())
}, timeout, interval).Should(Succeed())

Eventually(func(g Gomega) {
g.Expect(th.GetStatefulSet(statefulSetName).Spec.Template.Spec.NodeSelector).To(BeNil())
}, timeout, interval).Should(Succeed())
})

It("removes nodeSelector from resource specs when nilled", func() {
Eventually(func(g Gomega) {
g.Expect(th.GetStatefulSet(statefulSetName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"}))
}, timeout, interval).Should(Succeed())

Eventually(func(g Gomega) {
dbCluster := GetOVNDBCluster(OVNDBClusterName)
dbCluster.Spec.NodeSelector = nil
g.Expect(k8sClient.Update(ctx, dbCluster)).Should(Succeed())
}, timeout, interval).Should(Succeed())

Eventually(func(g Gomega) {
g.Expect(th.GetStatefulSet(statefulSetName).Spec.Template.Spec.NodeSelector).To(BeNil())
}, timeout, interval).Should(Succeed())
})
})

When("OVNDBClusters are created with networkAttachments", func() {
It("does not break if pods are not created yet", func() {
// Create OVNDBCluster with 1 replica
Expand Down
Loading

0 comments on commit a34ad51

Please sign in to comment.