Skip to content

Commit

Permalink
Set nodeSelector on jobs and allow empty nodeSelector
Browse files Browse the repository at this point in the history
Switch to a pointer for nodeSelector to allow different logic for empty vs unset
  • Loading branch information
olliewalsh committed Nov 20, 2024
1 parent 5c05397 commit 89d93a5
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 20 deletions.
4 changes: 2 additions & 2 deletions api/v1beta1/neutronapi_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ type NeutronAPISpecCore 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=false
Expand Down Expand Up @@ -297,7 +297,7 @@ func SetupDefaults() {
// Acquire environmental defaults and initialize Neutron defaults with them
neutronDefaults := NeutronAPIDefaults{
ContainerImageURL: util.GetEnvVar("RELATED_IMAGE_NEUTRON_API_IMAGE_URL_DEFAULT", NeutronAPIContainerImage),
APITimeout: 120,
APITimeout: 120,
}

SetupNeutronAPIDefaults(neutronDefaults)
Expand Down
10 changes: 7 additions & 3 deletions api/v1beta1/zz_generated.deepcopy.go

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

5 changes: 5 additions & 0 deletions pkg/neutronapi/dbsync.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,5 +54,10 @@ func DbSyncJob(
},
},
}

if cr.Spec.NodeSelector != nil {
job.Spec.Template.Spec.NodeSelector = *cr.Spec.NodeSelector
}

return job
}
4 changes: 2 additions & 2 deletions pkg/neutronapi/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,8 +186,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, nil
Expand Down
132 changes: 119 additions & 13 deletions test/functional/neutronapi_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ func getNeutronAPIControllerSuite(ml2MechanismDrivers []string) func() {
var internalCertSecretName types.NamespacedName
var publicCertSecretName types.NamespacedName
var ovnDbCertSecretName types.NamespacedName
var neutronDeploymentName types.NamespacedName
var neutronDBSyncJobName types.NamespacedName

BeforeEach(func() {
name = fmt.Sprintf("neutron-%s", uuid.New().String())
Expand Down Expand Up @@ -109,6 +111,14 @@ func getNeutronAPIControllerSuite(ml2MechanismDrivers []string) func() {
Name: OVNDbCertSecretName,
Namespace: namespace,
}
neutronDeploymentName = types.NamespacedName{
Name: neutronapi.ServiceName,
Namespace: namespace,
}
neutronDBSyncJobName = types.NamespacedName{
Name: neutronAPIName.Name + "-db-sync",
Namespace: namespace,
}
})

When("A NeutronAPI instance is created", func() {
Expand Down Expand Up @@ -838,7 +848,7 @@ func getNeutronAPIControllerSuite(ml2MechanismDrivers []string) func() {
It("Should set DBReady Condition and set DatabaseHostname Status when DB is Created", func() {
mariadb.SimulateMariaDBAccountCompleted(types.NamespacedName{Namespace: namespace, Name: GetNeutronAPI(neutronAPIName).Spec.DatabaseAccount})
mariadb.SimulateMariaDBDatabaseCompleted(types.NamespacedName{Namespace: namespace, Name: neutronapi.DatabaseCRName})
th.SimulateJobSuccess(types.NamespacedName{Namespace: namespace, Name: neutronAPIName.Name + "-db-sync"})
th.SimulateJobSuccess(neutronDBSyncJobName)
NeutronAPI := GetNeutronAPI(neutronAPIName)
hostname := "hostname-for-" + NeutronAPI.Spec.DatabaseInstance + "." + namespace + ".svc"
Expect(NeutronAPI.Status.DatabaseHostname).To(Equal(hostname))
Expand Down Expand Up @@ -878,7 +888,7 @@ func getNeutronAPIControllerSuite(ml2MechanismDrivers []string) func() {
DeferCleanup(keystone.DeleteKeystoneAPI, keystone.CreateKeystoneAPI(namespace))
mariadb.SimulateMariaDBAccountCompleted(types.NamespacedName{Namespace: namespace, Name: GetNeutronAPI(neutronAPIName).Spec.DatabaseAccount})
mariadb.SimulateMariaDBDatabaseCompleted(types.NamespacedName{Namespace: namespace, Name: neutronapi.DatabaseCRName})
th.SimulateJobSuccess(types.NamespacedName{Namespace: namespace, Name: neutronAPIName.Name + "-db-sync"})
th.SimulateJobSuccess(neutronDBSyncJobName)
keystone.SimulateKeystoneServiceReady(types.NamespacedName{Namespace: namespace, Name: "neutron"})
keystone.SimulateKeystoneEndpointReady(types.NamespacedName{Namespace: namespace, Name: "neutron"})
})
Expand Down Expand Up @@ -975,7 +985,7 @@ func getNeutronAPIControllerSuite(ml2MechanismDrivers []string) func() {
DeferCleanup(th.DeleteInstance, nad)
mariadb.SimulateMariaDBAccountCompleted(types.NamespacedName{Namespace: namespace, Name: GetNeutronAPI(neutronAPIName).Spec.DatabaseAccount})
mariadb.SimulateMariaDBDatabaseCompleted(types.NamespacedName{Namespace: namespace, Name: neutronapi.DatabaseCRName})
th.SimulateJobSuccess(types.NamespacedName{Namespace: namespace, Name: neutronAPIName.Name + "-db-sync"})
th.SimulateJobSuccess(neutronDBSyncJobName)
keystone.SimulateKeystoneServiceReady(types.NamespacedName{Namespace: namespace, Name: "neutron"})
keystone.SimulateKeystoneEndpointReady(types.NamespacedName{Namespace: namespace, Name: "neutron"})

Expand Down Expand Up @@ -1019,7 +1029,7 @@ func getNeutronAPIControllerSuite(ml2MechanismDrivers []string) func() {
DeferCleanup(th.DeleteInstance, nad)
mariadb.SimulateMariaDBAccountCompleted(types.NamespacedName{Namespace: namespace, Name: GetNeutronAPI(neutronAPIName).Spec.DatabaseAccount})
mariadb.SimulateMariaDBDatabaseCompleted(types.NamespacedName{Namespace: namespace, Name: neutronapi.DatabaseCRName})
th.SimulateJobSuccess(types.NamespacedName{Namespace: namespace, Name: neutronAPIName.Name + "-db-sync"})
th.SimulateJobSuccess(neutronDBSyncJobName)
keystone.SimulateKeystoneServiceReady(types.NamespacedName{Namespace: namespace, Name: "neutron"})
keystone.SimulateKeystoneEndpointReady(types.NamespacedName{Namespace: namespace, Name: "neutron"})
deplName := types.NamespacedName{
Expand Down Expand Up @@ -1064,7 +1074,7 @@ func getNeutronAPIControllerSuite(ml2MechanismDrivers []string) func() {
DeferCleanup(th.DeleteInstance, nad)
mariadb.SimulateMariaDBAccountCompleted(types.NamespacedName{Namespace: namespace, Name: GetNeutronAPI(neutronAPIName).Spec.DatabaseAccount})
mariadb.SimulateMariaDBDatabaseCompleted(types.NamespacedName{Namespace: namespace, Name: neutronapi.DatabaseCRName})
th.SimulateJobSuccess(types.NamespacedName{Namespace: namespace, Name: neutronAPIName.Name + "-db-sync"})
th.SimulateJobSuccess(neutronDBSyncJobName)
keystone.SimulateKeystoneServiceReady(types.NamespacedName{Namespace: namespace, Name: "neutron"})
keystone.SimulateKeystoneEndpointReady(types.NamespacedName{Namespace: namespace, Name: "neutron"})

Expand Down Expand Up @@ -1132,7 +1142,7 @@ func getNeutronAPIControllerSuite(ml2MechanismDrivers []string) func() {
DeferCleanup(keystone.DeleteKeystoneAPI, keystone.CreateKeystoneAPI(namespace))
mariadb.SimulateMariaDBAccountCompleted(types.NamespacedName{Namespace: namespace, Name: GetNeutronAPI(neutronAPIName).Spec.DatabaseAccount})
mariadb.SimulateMariaDBTLSDatabaseCompleted(types.NamespacedName{Namespace: namespace, Name: neutronapi.Database})
th.SimulateJobSuccess(types.NamespacedName{Namespace: namespace, Name: neutronAPIName.Name + "-db-sync"})
th.SimulateJobSuccess(neutronDBSyncJobName)
keystone.SimulateKeystoneServiceReady(types.NamespacedName{Namespace: namespace, Name: "neutron"})
keystone.SimulateKeystoneEndpointReady(types.NamespacedName{Namespace: namespace, Name: "neutron"})
})
Expand Down Expand Up @@ -1320,7 +1330,7 @@ func getNeutronAPIControllerSuite(ml2MechanismDrivers []string) func() {
DeferCleanup(keystone.DeleteKeystoneAPI, keystone.CreateKeystoneAPI(namespace))
mariadb.SimulateMariaDBAccountCompleted(types.NamespacedName{Namespace: namespace, Name: GetNeutronAPI(neutronAPIName).Spec.DatabaseAccount})
mariadb.SimulateMariaDBDatabaseCompleted(types.NamespacedName{Namespace: namespace, Name: neutronapi.DatabaseCRName})
th.SimulateJobSuccess(types.NamespacedName{Namespace: namespace, Name: neutronAPIName.Name + "-db-sync"})
th.SimulateJobSuccess(neutronDBSyncJobName)
keystone.SimulateKeystoneServiceReady(types.NamespacedName{Namespace: namespace, Name: "neutron"})
keystone.SimulateKeystoneEndpointReady(types.NamespacedName{Namespace: namespace, Name: "neutron"})
})
Expand All @@ -1340,6 +1350,106 @@ func getNeutronAPIControllerSuite(ml2MechanismDrivers []string) func() {
})
})

When("A NeutronAPI is created with nodeSelector", func() {
BeforeEach(func() {
spec["nodeSelector"] = map[string]interface{}{
"foo": "bar",
}

DeferCleanup(th.DeleteInstance, CreateNeutronAPI(neutronAPIName.Namespace, neutronAPIName.Name, spec))
DeferCleanup(k8sClient.Delete, ctx, CreateNeutronAPISecret(namespace, SecretName))
DeferCleanup(
mariadb.DeleteDBService,
mariadb.CreateDBService(
namespace,
GetNeutronAPI(neutronAPIName).Spec.DatabaseInstance,
corev1.ServiceSpec{
Ports: []corev1.ServicePort{{Port: 3306}},
},
),
)
SimulateTransportURLReady(apiTransportURLName)
DeferCleanup(infra.DeleteMemcached, infra.CreateMemcached(namespace, "memcached", memcachedSpec))
infra.SimulateMemcachedReady(memcachedName)
DeferCleanup(DeleteOVNDBClusters, CreateOVNDBClusters(namespace))
DeferCleanup(keystone.DeleteKeystoneAPI, keystone.CreateKeystoneAPI(namespace))
mariadb.SimulateMariaDBAccountCompleted(types.NamespacedName{Namespace: namespace, Name: GetNeutronAPI(neutronAPIName).Spec.DatabaseAccount})
mariadb.SimulateMariaDBDatabaseCompleted(types.NamespacedName{Namespace: namespace, Name: neutronapi.DatabaseCRName})
th.SimulateJobSuccess(neutronDBSyncJobName)
keystone.SimulateKeystoneServiceReady(types.NamespacedName{Namespace: namespace, Name: "neutron"})
keystone.SimulateKeystoneEndpointReady(types.NamespacedName{Namespace: namespace, Name: "neutron"})
})

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

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

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

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

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

Eventually(func(g Gomega) {
neutron := GetNeutronAPI(neutronAPIName)
neutron.Spec.NodeSelector = nil
g.Expect(k8sClient.Update(ctx, neutron)).Should(Succeed())
}, timeout, interval).Should(Succeed())

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

})

// Run MariaDBAccount suite tests. these are pre-packaged ginkgo tests
// that exercise standard account create / update patterns that should be
// common to all controllers that ensure MariaDBAccount CRs.
Expand Down Expand Up @@ -1397,16 +1507,12 @@ func getNeutronAPIControllerSuite(ml2MechanismDrivers []string) func() {

mariadb.SimulateMariaDBAccountCompleted(accountName)
mariadb.SimulateMariaDBDatabaseCompleted(types.NamespacedName{Namespace: namespace, Name: neutronapi.DatabaseCRName})
th.SimulateJobSuccess(types.NamespacedName{Namespace: namespace, Name: neutronAPIName.Name + "-db-sync"})
th.SimulateJobSuccess(neutronDBSyncJobName)
keystone.SimulateKeystoneServiceReady(types.NamespacedName{Namespace: namespace, Name: "neutron"})
keystone.SimulateKeystoneEndpointReady(types.NamespacedName{Namespace: namespace, Name: "neutron"})
deplName := types.NamespacedName{
Namespace: namespace,
Name: "neutron",
}

th.SimulateDeploymentReadyWithPods(
deplName,
neutronDeploymentName,
map[string][]string{namespace + "/internalapi": {}},
)

Expand Down

0 comments on commit 89d93a5

Please sign in to comment.