From 39b1989b0d3351aa999478ff0b65afadeb44ed45 Mon Sep 17 00:00:00 2001 From: Andrii Dema Date: Fri, 26 Sep 2025 10:43:56 +0300 Subject: [PATCH 1/3] K8SPS-550: apply `serviceAccountName` for haproxy pods https://perconadev.atlassian.net/browse/K8SPS-550 --- api/v1/perconaservermysql_types.go | 21 +++++++++++++++++++++ pkg/binlogserver/binlog_server.go | 24 ++++++------------------ pkg/haproxy/haproxy.go | 22 ++++++---------------- pkg/mysql/mysql.go | 27 ++++++--------------------- pkg/orchestrator/orchestrator.go | 24 ++++++------------------ pkg/router/router.go | 23 ++++++----------------- 6 files changed, 51 insertions(+), 90 deletions(-) diff --git a/api/v1/perconaservermysql_types.go b/api/v1/perconaservermysql_types.go index 2b1428912..3c317f4b6 100644 --- a/api/v1/perconaservermysql_types.go +++ b/api/v1/perconaservermysql_types.go @@ -216,6 +216,27 @@ type PodSpec struct { ContainerSpec `json:",inline"` } +func (s *PodSpec) Core(selector map[string]string, volumes []corev1.Volume, initContainers []corev1.Container, containers []corev1.Container) corev1.PodSpec { + return corev1.PodSpec{ + Volumes: volumes, + InitContainers: initContainers, + Containers: containers, + RestartPolicy: corev1.RestartPolicyAlways, + TerminationGracePeriodSeconds: s.GetTerminationGracePeriodSeconds(), + DNSPolicy: corev1.DNSClusterFirst, + NodeSelector: s.NodeSelector, + ServiceAccountName: s.ServiceAccountName, + SecurityContext: s.PodSecurityContext, + ImagePullSecrets: s.ImagePullSecrets, + Affinity: s.GetAffinity(selector), + SchedulerName: s.SchedulerName, + Tolerations: s.Tolerations, + PriorityClassName: s.PriorityClassName, + RuntimeClassName: s.RuntimeClassName, + TopologySpreadConstraints: s.GetTopologySpreadConstraints(selector), + } +} + type Metadata struct { // Map of string keys and values that can be used to organize and categorize // (scope and select) objects. May match selectors of replication controllers diff --git a/pkg/binlogserver/binlog_server.go b/pkg/binlogserver/binlog_server.go index d8e68db0b..5c488f1c0 100644 --- a/pkg/binlogserver/binlog_server.go +++ b/pkg/binlogserver/binlog_server.go @@ -76,8 +76,10 @@ func StatefulSet(cr *apiv1.PerconaServerMySQL, initImage, configHash string) *ap Labels: labels, Annotations: util.SSMapMerge(cr.GlobalAnnotations(), annotations), }, - Spec: corev1.PodSpec{ - InitContainers: []corev1.Container{ + Spec: spec.Core( + labels, + volumes(cr), + []corev1.Container{ k8s.InitContainer( cr, AppName, @@ -89,22 +91,8 @@ func StatefulSet(cr *apiv1.PerconaServerMySQL, initImage, configHash string) *ap nil, ), }, - Containers: containers(cr), - ServiceAccountName: spec.ServiceAccountName, - NodeSelector: spec.NodeSelector, - Tolerations: spec.Tolerations, - Affinity: spec.GetAffinity(labels), - TopologySpreadConstraints: spec.GetTopologySpreadConstraints(labels), - ImagePullSecrets: spec.ImagePullSecrets, - TerminationGracePeriodSeconds: spec.GetTerminationGracePeriodSeconds(), - PriorityClassName: spec.PriorityClassName, - RuntimeClassName: spec.RuntimeClassName, - RestartPolicy: corev1.RestartPolicyAlways, - SchedulerName: spec.SchedulerName, - DNSPolicy: corev1.DNSClusterFirst, - Volumes: volumes(cr), - SecurityContext: spec.PodSecurityContext, - }, + containers(cr), + ), }, }, } diff --git a/pkg/haproxy/haproxy.go b/pkg/haproxy/haproxy.go index aa3a09645..1a5454015 100644 --- a/pkg/haproxy/haproxy.go +++ b/pkg/haproxy/haproxy.go @@ -164,11 +164,10 @@ func StatefulSet(cr *apiv1.PerconaServerMySQL, initImage, configHash, tlsHash st Labels: Labels(cr), Annotations: util.SSMapMerge(cr.GlobalAnnotations(), annotations), }, - Spec: corev1.PodSpec{ - NodeSelector: cr.Spec.Proxy.HAProxy.NodeSelector, - Tolerations: cr.Spec.Proxy.HAProxy.Tolerations, - RuntimeClassName: cr.Spec.Proxy.HAProxy.RuntimeClassName, - InitContainers: []corev1.Container{ + Spec: cr.Spec.Proxy.HAProxy.Core( + selector, + volumes(cr), + []corev1.Container{ k8s.InitContainer( cr, AppName, @@ -180,17 +179,8 @@ func StatefulSet(cr *apiv1.PerconaServerMySQL, initImage, configHash, tlsHash st nil, ), }, - Containers: containers(cr, secret), - Affinity: cr.Spec.Proxy.HAProxy.GetAffinity(selector), - TopologySpreadConstraints: cr.Spec.Proxy.HAProxy.GetTopologySpreadConstraints(selector), - ImagePullSecrets: cr.Spec.Proxy.HAProxy.ImagePullSecrets, - TerminationGracePeriodSeconds: cr.Spec.Proxy.HAProxy.GetTerminationGracePeriodSeconds(), - RestartPolicy: corev1.RestartPolicyAlways, - SchedulerName: "default-scheduler", - DNSPolicy: corev1.DNSClusterFirst, - Volumes: volumes(cr), - SecurityContext: cr.Spec.Proxy.HAProxy.PodSecurityContext, - }, + containers(cr, secret), + ), }, }, } diff --git a/pkg/mysql/mysql.go b/pkg/mysql/mysql.go index 69a835b00..5c2dfa54e 100644 --- a/pkg/mysql/mysql.go +++ b/pkg/mysql/mysql.go @@ -167,8 +167,10 @@ func StatefulSet(cr *apiv1.PerconaServerMySQL, initImage, configHash, tlsHash st Labels: Labels(cr), Annotations: util.SSMapMerge(cr.GlobalAnnotations(), annotations), }, - Spec: corev1.PodSpec{ - InitContainers: []corev1.Container{ + Spec: spec.Core( + selector, + append(volumes(cr), spec.SidecarVolumes...), + []corev1.Container{ k8s.InitContainer( cr, AppName, @@ -180,25 +182,8 @@ func StatefulSet(cr *apiv1.PerconaServerMySQL, initImage, configHash, tlsHash st nil, ), }, - Containers: containers(cr, secret), - ServiceAccountName: cr.Spec.MySQL.ServiceAccountName, - NodeSelector: cr.Spec.MySQL.NodeSelector, - Tolerations: cr.Spec.MySQL.Tolerations, - Affinity: spec.GetAffinity(selector), - TopologySpreadConstraints: spec.GetTopologySpreadConstraints(selector), - ImagePullSecrets: spec.ImagePullSecrets, - TerminationGracePeriodSeconds: spec.GetTerminationGracePeriodSeconds(), - PriorityClassName: spec.PriorityClassName, - RuntimeClassName: spec.RuntimeClassName, - RestartPolicy: corev1.RestartPolicyAlways, - SchedulerName: spec.SchedulerName, - DNSPolicy: corev1.DNSClusterFirst, - Volumes: append( - volumes(cr), - spec.SidecarVolumes..., - ), - SecurityContext: spec.PodSecurityContext, - }, + containers(cr, secret), + ), }, }, } diff --git a/pkg/orchestrator/orchestrator.go b/pkg/orchestrator/orchestrator.go index db1557eca..206d41eb2 100644 --- a/pkg/orchestrator/orchestrator.go +++ b/pkg/orchestrator/orchestrator.go @@ -140,8 +140,10 @@ func StatefulSet(cr *apiv1.PerconaServerMySQL, initImage, configHash, tlsHash st Labels: Labels(cr), Annotations: util.SSMapMerge(cr.GlobalAnnotations(), annotations), }, - Spec: corev1.PodSpec{ - InitContainers: []corev1.Container{ + Spec: spec.Core( + selector, + volumes(cr), + []corev1.Container{ k8s.InitContainer( cr, AppName, @@ -153,22 +155,8 @@ func StatefulSet(cr *apiv1.PerconaServerMySQL, initImage, configHash, tlsHash st nil, ), }, - NodeSelector: cr.Spec.Orchestrator.NodeSelector, - Tolerations: cr.Spec.Orchestrator.Tolerations, - Containers: containers(cr), - Affinity: spec.GetAffinity(selector), - TopologySpreadConstraints: spec.GetTopologySpreadConstraints(selector), - ImagePullSecrets: spec.ImagePullSecrets, - TerminationGracePeriodSeconds: spec.GetTerminationGracePeriodSeconds(), - PriorityClassName: spec.PriorityClassName, - RuntimeClassName: spec.RuntimeClassName, - ServiceAccountName: spec.ServiceAccountName, - RestartPolicy: corev1.RestartPolicyAlways, - SchedulerName: spec.SchedulerName, - DNSPolicy: corev1.DNSClusterFirst, - Volumes: volumes(cr), - SecurityContext: spec.PodSecurityContext, - }, + containers(cr), + ), }, }, } diff --git a/pkg/router/router.go b/pkg/router/router.go index 9f4a48238..b34f1fd25 100644 --- a/pkg/router/router.go +++ b/pkg/router/router.go @@ -140,8 +140,10 @@ func Deployment(cr *apiv1.PerconaServerMySQL, initImage, configHash, tlsHash str Labels: Labels(cr), Annotations: util.SSMapMerge(cr.GlobalAnnotations(), annotations), }, - Spec: corev1.PodSpec{ - InitContainers: []corev1.Container{ + Spec: spec.Core( + selector, + volumes(cr), + []corev1.Container{ k8s.InitContainer( cr, AppName, @@ -153,21 +155,8 @@ func Deployment(cr *apiv1.PerconaServerMySQL, initImage, configHash, tlsHash str nil, ), }, - Containers: containers(cr), - NodeSelector: cr.Spec.Proxy.Router.NodeSelector, - Tolerations: cr.Spec.Proxy.Router.Tolerations, - Affinity: spec.GetAffinity(selector), - TopologySpreadConstraints: spec.GetTopologySpreadConstraints(selector), - ImagePullSecrets: spec.ImagePullSecrets, - TerminationGracePeriodSeconds: spec.GetTerminationGracePeriodSeconds(), - RestartPolicy: corev1.RestartPolicyAlways, - SchedulerName: spec.SchedulerName, - RuntimeClassName: spec.RuntimeClassName, - ServiceAccountName: spec.ServiceAccountName, - DNSPolicy: corev1.DNSClusterFirst, - SecurityContext: spec.PodSecurityContext, - Volumes: volumes(cr), - }, + containers(cr), + ), }, }, } From d8e7195896f787bc77c08d4f3b7685c38da7a740 Mon Sep 17 00:00:00 2001 From: Andrii Dema Date: Tue, 30 Sep 2025 12:57:53 +0300 Subject: [PATCH 2/3] add unit-tests --- pkg/haproxy/haproxy_test.go | 13 +++++++++++++ pkg/mysql/mysql_test.go | 13 +++++++++++++ pkg/orchestrator/orchestrator_test.go | 13 +++++++++++++ pkg/router/router_test.go | 13 +++++++++++++ 4 files changed, 52 insertions(+) diff --git a/pkg/haproxy/haproxy_test.go b/pkg/haproxy/haproxy_test.go index 881ad47c5..28c8e7377 100644 --- a/pkg/haproxy/haproxy_test.go +++ b/pkg/haproxy/haproxy_test.go @@ -113,6 +113,19 @@ func TestStatefulset(t *testing.T) { assert.Equal(t, runtimeClassName, *sts.Spec.Template.Spec.RuntimeClassName) }) + t.Run("service account name", func(t *testing.T) { + cluster := cr.DeepCopy() + sts := StatefulSet(cluster, initImage, configHash, tlsHash, secret) + var e string + assert.Equal(t, e, sts.Spec.Template.Spec.ServiceAccountName) + + const serviceAccountName = "service" + cluster.Spec.Proxy.HAProxy.ServiceAccountName = serviceAccountName + + sts = StatefulSet(cluster, initImage, configHash, tlsHash, secret) + assert.Equal(t, serviceAccountName, sts.Spec.Template.Spec.ServiceAccountName) + }) + t.Run("tolerations", func(t *testing.T) { cluster := cr.DeepCopy() sts := StatefulSet(cluster, initImage, configHash, tlsHash, secret) diff --git a/pkg/mysql/mysql_test.go b/pkg/mysql/mysql_test.go index ffab5e2e9..4acdc17c5 100644 --- a/pkg/mysql/mysql_test.go +++ b/pkg/mysql/mysql_test.go @@ -119,6 +119,19 @@ func TestStatefulSet(t *testing.T) { assert.Equal(t, runtimeClassName, *sts.Spec.Template.Spec.RuntimeClassName) }) + t.Run("service account name", func(t *testing.T) { + cluster := cr.DeepCopy() + sts := StatefulSet(cluster, initImage, configHash, tlsHash, secret) + var e string + assert.Equal(t, e, sts.Spec.Template.Spec.ServiceAccountName) + + const serviceAccountName = "service" + cluster.Spec.MySQL.ServiceAccountName = serviceAccountName + + sts = StatefulSet(cluster, initImage, configHash, tlsHash, secret) + assert.Equal(t, serviceAccountName, sts.Spec.Template.Spec.ServiceAccountName) + }) + t.Run("tolerations", func(t *testing.T) { cluster := cr.DeepCopy() sts := StatefulSet(cluster, initImage, configHash, tlsHash, secret) diff --git a/pkg/orchestrator/orchestrator_test.go b/pkg/orchestrator/orchestrator_test.go index cf763d390..15b30a78c 100644 --- a/pkg/orchestrator/orchestrator_test.go +++ b/pkg/orchestrator/orchestrator_test.go @@ -124,6 +124,19 @@ func TestStatefulSet(t *testing.T) { assert.Equal(t, runtimeClassName, *sts.Spec.Template.Spec.RuntimeClassName) }) + t.Run("service account name", func(t *testing.T) { + cluster := cr.DeepCopy() + cluster.Spec.Orchestrator.ServiceAccountName = "" + sts := StatefulSet(cluster, initImage, configHash, tlsHash) + assert.Equal(t, "", sts.Spec.Template.Spec.ServiceAccountName) + + const serviceAccountName = "service" + cluster.Spec.Orchestrator.ServiceAccountName = serviceAccountName + + sts = StatefulSet(cluster, initImage, configHash, tlsHash) + assert.Equal(t, serviceAccountName, sts.Spec.Template.Spec.ServiceAccountName) + }) + t.Run("tolerations", func(t *testing.T) { cluster := cr.DeepCopy() sts := StatefulSet(cluster, initImage, configHash, tlsHash) diff --git a/pkg/router/router_test.go b/pkg/router/router_test.go index 2a0c8a8b5..64d652de5 100644 --- a/pkg/router/router_test.go +++ b/pkg/router/router_test.go @@ -97,6 +97,19 @@ func TestDeployment(t *testing.T) { assert.Equal(t, runtimeClassName, *deployment.Spec.Template.Spec.RuntimeClassName) }) + t.Run("service account name", func(t *testing.T) { + cluster := cr.DeepCopy() + deployment := Deployment(cluster, initImage, configHash, tlsHash) + var e string + assert.Equal(t, e, deployment.Spec.Template.Spec.ServiceAccountName) + + const serviceAccountName = "service" + cluster.Spec.Proxy.Router.ServiceAccountName = serviceAccountName + + deployment = Deployment(cluster, initImage, configHash, tlsHash) + assert.Equal(t, serviceAccountName, deployment.Spec.Template.Spec.ServiceAccountName) + }) + t.Run("tolerations", func(t *testing.T) { cluster := cr.DeepCopy() deployment := Deployment(cluster, initImage, configHash, tlsHash) From 1050a29935205943c98e8ecd858bfa8f301debd0 Mon Sep 17 00:00:00 2001 From: Andrii Dema Date: Fri, 3 Oct 2025 17:49:00 +0300 Subject: [PATCH 3/3] address comments --- pkg/haproxy/haproxy_test.go | 6 ++---- pkg/mysql/mysql_test.go | 6 ++---- pkg/orchestrator/orchestrator_test.go | 5 ++--- pkg/router/router_test.go | 6 ++---- 4 files changed, 8 insertions(+), 15 deletions(-) diff --git a/pkg/haproxy/haproxy_test.go b/pkg/haproxy/haproxy_test.go index 28c8e7377..8ffebbc6b 100644 --- a/pkg/haproxy/haproxy_test.go +++ b/pkg/haproxy/haproxy_test.go @@ -103,8 +103,7 @@ func TestStatefulset(t *testing.T) { t.Run("runtime class name", func(t *testing.T) { cluster := cr.DeepCopy() sts := StatefulSet(cluster, initImage, configHash, tlsHash, secret) - var e *string - assert.Equal(t, e, sts.Spec.Template.Spec.RuntimeClassName) + assert.Empty(t, sts.Spec.Template.Spec.RuntimeClassName) const runtimeClassName = "runtimeClassName" cluster.Spec.Proxy.HAProxy.RuntimeClassName = ptr.To(runtimeClassName) @@ -116,8 +115,7 @@ func TestStatefulset(t *testing.T) { t.Run("service account name", func(t *testing.T) { cluster := cr.DeepCopy() sts := StatefulSet(cluster, initImage, configHash, tlsHash, secret) - var e string - assert.Equal(t, e, sts.Spec.Template.Spec.ServiceAccountName) + assert.Empty(t, sts.Spec.Template.Spec.ServiceAccountName) const serviceAccountName = "service" cluster.Spec.Proxy.HAProxy.ServiceAccountName = serviceAccountName diff --git a/pkg/mysql/mysql_test.go b/pkg/mysql/mysql_test.go index 4acdc17c5..67177c9b8 100644 --- a/pkg/mysql/mysql_test.go +++ b/pkg/mysql/mysql_test.go @@ -109,8 +109,7 @@ func TestStatefulSet(t *testing.T) { t.Run("runtime class name", func(t *testing.T) { cluster := cr.DeepCopy() sts := StatefulSet(cluster, initImage, configHash, tlsHash, secret) - var e *string - assert.Equal(t, e, sts.Spec.Template.Spec.RuntimeClassName) + assert.Empty(t, sts.Spec.Template.Spec.RuntimeClassName) const runtimeClassName = "runtimeClassName" cluster.Spec.MySQL.RuntimeClassName = ptr.To(runtimeClassName) @@ -122,8 +121,7 @@ func TestStatefulSet(t *testing.T) { t.Run("service account name", func(t *testing.T) { cluster := cr.DeepCopy() sts := StatefulSet(cluster, initImage, configHash, tlsHash, secret) - var e string - assert.Equal(t, e, sts.Spec.Template.Spec.ServiceAccountName) + assert.Empty(t, sts.Spec.Template.Spec.ServiceAccountName) const serviceAccountName = "service" cluster.Spec.MySQL.ServiceAccountName = serviceAccountName diff --git a/pkg/orchestrator/orchestrator_test.go b/pkg/orchestrator/orchestrator_test.go index 15b30a78c..29eb40c01 100644 --- a/pkg/orchestrator/orchestrator_test.go +++ b/pkg/orchestrator/orchestrator_test.go @@ -114,8 +114,7 @@ func TestStatefulSet(t *testing.T) { t.Run("runtime class name", func(t *testing.T) { cluster := cr.DeepCopy() sts := StatefulSet(cluster, initImage, configHash, tlsHash) - var e *string - assert.Equal(t, e, sts.Spec.Template.Spec.RuntimeClassName) + assert.Empty(t, sts.Spec.Template.Spec.RuntimeClassName) const runtimeClassName = "runtimeClassName" cluster.Spec.Orchestrator.RuntimeClassName = ptr.To(runtimeClassName) @@ -128,7 +127,7 @@ func TestStatefulSet(t *testing.T) { cluster := cr.DeepCopy() cluster.Spec.Orchestrator.ServiceAccountName = "" sts := StatefulSet(cluster, initImage, configHash, tlsHash) - assert.Equal(t, "", sts.Spec.Template.Spec.ServiceAccountName) + assert.Empty(t, sts.Spec.Template.Spec.ServiceAccountName) const serviceAccountName = "service" cluster.Spec.Orchestrator.ServiceAccountName = serviceAccountName diff --git a/pkg/router/router_test.go b/pkg/router/router_test.go index 64d652de5..14fe920f0 100644 --- a/pkg/router/router_test.go +++ b/pkg/router/router_test.go @@ -87,8 +87,7 @@ func TestDeployment(t *testing.T) { t.Run("runtime class name", func(t *testing.T) { cluster := cr.DeepCopy() deployment := Deployment(cluster, initImage, configHash, tlsHash) - var e *string - assert.Equal(t, e, deployment.Spec.Template.Spec.RuntimeClassName) + assert.Empty(t, deployment.Spec.Template.Spec.RuntimeClassName) const runtimeClassName = "runtimeClassName" cluster.Spec.Proxy.Router.RuntimeClassName = ptr.To(runtimeClassName) @@ -100,8 +99,7 @@ func TestDeployment(t *testing.T) { t.Run("service account name", func(t *testing.T) { cluster := cr.DeepCopy() deployment := Deployment(cluster, initImage, configHash, tlsHash) - var e string - assert.Equal(t, e, deployment.Spec.Template.Spec.ServiceAccountName) + assert.Empty(t, deployment.Spec.Template.Spec.ServiceAccountName) const serviceAccountName = "service" cluster.Spec.Proxy.Router.ServiceAccountName = serviceAccountName