diff --git a/pkg/cluster/cluster.go b/pkg/cluster/cluster.go index 389af8e8c..4a5db1331 100644 --- a/pkg/cluster/cluster.go +++ b/pkg/cluster/cluster.go @@ -197,28 +197,30 @@ func (c *Cluster) initUsers() error { /* Ensures the service account required by StatefulSets to create pods exists in a namespace before a PG cluster is created there so that a user does not have to deploy the account manually. - The operator does not sync these accounts. + The operator does not sync these accounts after creation. */ func (c *Cluster) createPodServiceAccounts() error { - podServiceAccount := c.Config.OpConfig.PodServiceAccountName + podServiceAccountName := c.Config.OpConfig.PodServiceAccountName c.setProcessName("creating pod service account in the watched namespaces") - _, err := c.KubeClient.ServiceAccounts(c.Namespace).Get(podServiceAccount, metav1.GetOptions{}) + _, err := c.KubeClient.ServiceAccounts(c.Namespace).Get(podServiceAccountName, metav1.GetOptions{}) if err != nil { - c.logger.Warnf("the pod service account %q is absent from the namespace %q. Stateful sets in the namespace are unable to create pods.", podServiceAccount, c.Namespace) + c.logger.Warnf("the pod service account %q is absent from the namespace %q. Stateful sets in the namespace are unable to create pods.", podServiceAccountName, c.Namespace) + // when created, each Cluster struct gets a separate copy of OpConfig + // including the nested PodServiceAccount struct, so no race condition here c.OpConfig.PodServiceAccount.SetNamespace(c.Namespace) - _, err = c.KubeClient.ServiceAccounts(c.Namespace).Create(c.OpConfig.PodServiceAccount) + _, err = c.KubeClient.ServiceAccounts(c.Namespace).Create(&c.OpConfig.PodServiceAccount) if err != nil { - c.logger.Warnf("cannot deploy the pod service account %q defined in the config map to the %q namespace: %v", podServiceAccount, c.Namespace, err) + c.logger.Warnf("cannot deploy the pod service account %q defined in the config map to the %q namespace: %v", podServiceAccountName, c.Namespace, err) } else { - c.logger.Infof("successfully deployed the pod service account %q to the %q namespace", podServiceAccount, c.Namespace) + c.logger.Infof("successfully deployed the pod service account %q to the %q namespace", podServiceAccountName, c.Namespace) } } else { - c.logger.Infof("successfully found the service account %q used to create pods to the namespace %q", podServiceAccount, c.Namespace) + c.logger.Infof("successfully found the service account %q used to create pods to the namespace %q", podServiceAccountName, c.Namespace) } return err diff --git a/pkg/controller/controller.go b/pkg/controller/controller.go index b50dc43ad..ab22f1359 100644 --- a/pkg/controller/controller.go +++ b/pkg/controller/controller.go @@ -128,7 +128,7 @@ func (c *Controller) initPodServiceAccount() { case groupVersionKind.Kind != "ServiceAccount": panic(fmt.Errorf("pod service account definiton in the operator config map defines another type of resource: %v", groupVersionKind.Kind)) default: - c.opConfig.PodServiceAccount = obj.(*v1.ServiceAccount) + c.opConfig.PodServiceAccount = *obj.(*v1.ServiceAccount) // ensure consistent naming of the account c.opConfig.PodServiceAccount.Name = c.opConfig.PodServiceAccountName } diff --git a/pkg/util/config/config.go b/pkg/util/config/config.go index 15a4738b4..b3392065d 100644 --- a/pkg/util/config/config.go +++ b/pkg/util/config/config.go @@ -68,10 +68,10 @@ type Config struct { Resources Auth Scalyr - PodServiceAccount *v1.ServiceAccount - WatchedNamespace string `name:"watched_namespace"` // special values: "*" means 'watch all namespaces', the empty string "" means 'watch a namespace where operator is deployed to' - EtcdHost string `name:"etcd_host" default:"etcd-client.default.svc.cluster.local:2379"` - DockerImage string `name:"docker_image" default:"registry.opensource.zalan.do/acid/spiloprivate-9.6:1.2-p4"` + PodServiceAccount v1.ServiceAccount // has to be struct value, not a pointer + WatchedNamespace string `name:"watched_namespace"` // special values: "*" means 'watch all namespaces', the empty string "" means 'watch a namespace where operator is deployed to' + EtcdHost string `name:"etcd_host" default:"etcd-client.default.svc.cluster.local:2379"` + DockerImage string `name:"docker_image" default:"registry.opensource.zalan.do/acid/spiloprivate-9.6:1.2-p4"` // re-use one account for both Spilo pods and the operator; this grants extra privileges to pods ServiceAccountName string `name:"service_account_name" default:"operator"` PodServiceAccountName string `name:"pod_service_account_name" default:"operator"`