Skip to content

Commit

Permalink
Merge pull request #312 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 20, 2024
2 parents 9f976c1 + ca8d569 commit b225194
Show file tree
Hide file tree
Showing 17 changed files with 176 additions and 27 deletions.
3 changes: 1 addition & 2 deletions apis/bases/instanceha.openstack.org_instancehas.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,7 @@ spec:
additionalProperties:
type: string
description: NodeSelector to target subset of worker nodes running
control plane services (currently only applies to KeystoneAPI and
PlacementAPI)
control plane services
type: object
openStackCloud:
default: default
Expand Down
6 changes: 6 additions & 0 deletions apis/bases/redis.openstack.org_redises.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ spec:
description: Name of the redis container image to run (will be set
to environmental default if empty)
type: string
nodeSelector:
additionalProperties:
type: string
description: NodeSelector to target subset of worker nodes running
this service
type: object
replicas:
default: 1
description: Size of the redis cluster
Expand Down
14 changes: 7 additions & 7 deletions apis/instanceha/v1beta1/instanceha_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const (

// InstanceHaContainerImage is the fall-back container image for InstanceHa
InstanceHaContainerImage = "quay.io/podified-antelope-centos9/openstack-openstackclient:current-podified"
OpenStackCloud = "default"
OpenStackCloud = "default"
)

// InstanceHaSpec defines the desired state of InstanceHa
Expand All @@ -38,10 +38,10 @@ type InstanceHaSpec struct {
// ContainerImage for the the InstanceHa container (will be set to environmental default if empty)
ContainerImage string `json:"containerImage"`

// +kubebuilder:validation:Required
// +kubebuilder:default="default"
// OpenStackClould is the name of the Cloud to use as per clouds.yaml (will be set to "default" if empty)
OpenStackCloud string `json:"openStackCloud"`
// +kubebuilder:validation:Required
// +kubebuilder:default="default"
// OpenStackClould is the name of the Cloud to use as per clouds.yaml (will be set to "default" if empty)
OpenStackCloud string `json:"openStackCloud"`

// +kubebuilder:validation:Required
// +kubebuilder:default=openstack-config
Expand All @@ -68,8 +68,8 @@ type InstanceHaSpec struct {
InstanceHaKdumpPort int32 `json:"instanceHaKdumpPort"`

// +kubebuilder:validation:Optional
// NodeSelector to target subset of worker nodes running control plane services (currently only applies to KeystoneAPI and PlacementAPI)
NodeSelector map[string]string `json:"nodeSelector,omitempty"`
// NodeSelector to target subset of worker nodes running control plane services
NodeSelector *map[string]string `json:"nodeSelector,omitempty"`

// +kubebuilder:validation:Optional
// NetworkAttachments is a list of NetworkAttachment resource names to expose
Expand Down
10 changes: 7 additions & 3 deletions apis/instanceha/v1beta1/zz_generated.deepcopy.go

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

2 changes: 1 addition & 1 deletion apis/memcached/v1beta1/memcached_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ type MemcachedSpecCore 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
// +operator-sdk:csv:customresourcedefinitions:type=spec
Expand Down
10 changes: 7 additions & 3 deletions apis/memcached/v1beta1/zz_generated.deepcopy.go

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

2 changes: 1 addition & 1 deletion apis/network/v1beta1/dnsmasq_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ type DNSMasqSpecCore struct {
// NodeSelector to target subset of worker nodes running this service. Setting
// NodeSelector here acts as a default value and can be overridden by service
// specific NodeSelector Settings.
NodeSelector map[string]string `json:"nodeSelector,omitempty"`
NodeSelector *map[string]string `json:"nodeSelector,omitempty"`

// +kubebuilder:validation:Optional
// +kubebuilder:default="dnsdata"
Expand Down
10 changes: 7 additions & 3 deletions apis/network/v1beta1/zz_generated.deepcopy.go

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

3 changes: 3 additions & 0 deletions apis/redis/v1beta1/redis_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ type RedisSpecCore struct {
// +operator-sdk:csv:customresourcedefinitions:type=spec
// TLS settings for Redis service and internal Redis replication
TLS tls.SimpleService `json:"tls,omitempty"`
// +kubebuilder:validation:Optional
// NodeSelector to target subset of worker nodes running this service
NodeSelector *map[string]string `json:"nodeSelector,omitempty"`
}

// RedisStatus defines the observed state of Redis
Expand Down
11 changes: 11 additions & 0 deletions apis/redis/v1beta1/zz_generated.deepcopy.go

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

3 changes: 1 addition & 2 deletions config/crd/bases/instanceha.openstack.org_instancehas.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,7 @@ spec:
additionalProperties:
type: string
description: NodeSelector to target subset of worker nodes running
control plane services (currently only applies to KeystoneAPI and
PlacementAPI)
control plane services
type: object
openStackCloud:
default: default
Expand Down
6 changes: 6 additions & 0 deletions config/crd/bases/redis.openstack.org_redises.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ spec:
description: Name of the redis container image to run (will be set
to environmental default if empty)
type: string
nodeSelector:
additionalProperties:
type: string
description: NodeSelector to target subset of worker nodes running
this service
type: object
replicas:
default: 1
description: Size of the redis cluster
Expand Down
4 changes: 2 additions & 2 deletions pkg/dnsmasq/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,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
5 changes: 4 additions & 1 deletion pkg/instanceha/funcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ func Deployment(
ServiceAccountName: instance.RbacResourceName(),
Volumes: volumes,
TerminationGracePeriodSeconds: ptr.To[int64](0),
NodeSelector: instance.Spec.NodeSelector,
Containers: []corev1.Container{{
Name: "instanceha",
Image: containerImage,
Expand Down Expand Up @@ -112,6 +111,10 @@ func Deployment(
},
}

if instance.Spec.NodeSelector != nil {
dep.Spec.Template.Spec.NodeSelector = *instance.Spec.NodeSelector
}

return dep
}

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

return sfs
Expand Down
4 changes: 4 additions & 0 deletions pkg/redis/statefulset.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,5 +141,9 @@ func StatefulSet(
},
}

if r.Spec.NodeSelector != nil {
sts.Spec.Template.Spec.NodeSelector = *r.Spec.NodeSelector
}

return sts
}
106 changes: 106 additions & 0 deletions tests/functional/dnsmasq_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,4 +266,110 @@ var _ = Describe("DNSMasq controller", func() {
})
})
})

When("A DNSMasq is created with nodeSelector", func() {
BeforeEach(func() {
spec := GetDefaultDNSMasqSpec()
spec["nodeSelector"] = map[string]interface{}{
"foo": "bar",
}
instance := CreateDNSMasq(namespace, spec)
dnsMasqName = types.NamespacedName{
Name: instance.GetName(),
Namespace: namespace,
}
dnsMasqServiceAccountName = types.NamespacedName{
Namespace: namespace,
Name: "dnsmasq-" + dnsMasqName.Name,
}
dnsMasqRoleName = types.NamespacedName{
Namespace: namespace,
Name: dnsMasqServiceAccountName.Name + "-role",
}
dnsMasqRoleBindingName = types.NamespacedName{
Namespace: namespace,
Name: dnsMasqServiceAccountName.Name + "-rolebinding",
}
deploymentName = types.NamespacedName{
Namespace: namespace,
Name: "dnsmasq-" + dnsMasqName.Name,
}

dnsDataCM = types.NamespacedName{
Namespace: namespace,
Name: "some-dnsdata",
}

th.CreateConfigMap(dnsDataCM, map[string]interface{}{
dnsDataCM.Name: "172.20.0.80 keystone-internal.openstack.svc",
})
cm := th.GetConfigMap(dnsDataCM)
cm.Labels = util.MergeStringMaps(cm.Labels, map[string]string{
"dnsmasqhosts": "dnsdata",
})
Expect(th.K8sClient.Update(ctx, cm)).Should(Succeed())

DeferCleanup(th.DeleteConfigMap, dnsDataCM)
DeferCleanup(th.DeleteInstance, instance)
th.SimulateLoadBalancerServiceIP(deploymentName)
})

It("sets nodeSelector in resource specs", func() {
Eventually(func(g Gomega) {
g.Expect(th.GetDeployment(deploymentName).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.GetDeployment(deploymentName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"}))
}, timeout, interval).Should(Succeed())

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

Eventually(func(g Gomega) {
g.Expect(th.GetDeployment(deploymentName).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.GetDeployment(deploymentName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"}))
}, timeout, interval).Should(Succeed())

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

Eventually(func(g Gomega) {
g.Expect(th.GetDeployment(deploymentName).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.GetDeployment(deploymentName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"}))
}, timeout, interval).Should(Succeed())

Eventually(func(g Gomega) {
dnsmasq := GetDNSMasq(dnsMasqName)
dnsmasq.Spec.NodeSelector = nil
g.Expect(k8sClient.Update(ctx, dnsmasq)).Should(Succeed())
}, timeout, interval).Should(Succeed())

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

0 comments on commit b225194

Please sign in to comment.