Deploy service account for pod creation on demand
This commit is contained in:
parent
88c68712b6
commit
214ae04aa7
|
|
@ -256,6 +256,11 @@ func (c *Cluster) Create() error {
|
||||||
}
|
}
|
||||||
c.logger.Infof("pod disruption budget %q has been successfully created", util.NameFromMeta(pdb.ObjectMeta))
|
c.logger.Infof("pod disruption budget %q has been successfully created", util.NameFromMeta(pdb.ObjectMeta))
|
||||||
|
|
||||||
|
if err = c.syncPodServiceAccounts(); err != nil {
|
||||||
|
return fmt.Errorf("could not sync pod service accounts: %v", err)
|
||||||
|
}
|
||||||
|
c.logger.Infof("pod service accounts have been successfully synced")
|
||||||
|
|
||||||
if c.Statefulset != nil {
|
if c.Statefulset != nil {
|
||||||
return fmt.Errorf("statefulset already exists in the cluster")
|
return fmt.Errorf("statefulset already exists in the cluster")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,12 @@ func (c *Cluster) Sync(newSpec *spec.Postgresql) (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c.logger.Debugf("syncing service accounts")
|
||||||
|
if err = c.syncPodServiceAccounts(); err != nil {
|
||||||
|
err = fmt.Errorf("could not sync service accounts: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
c.logger.Debugf("syncing services")
|
c.logger.Debugf("syncing services")
|
||||||
if err = c.syncServices(); err != nil {
|
if err = c.syncServices(); err != nil {
|
||||||
err = fmt.Errorf("could not sync services: %v", err)
|
err = fmt.Errorf("could not sync services: %v", err)
|
||||||
|
|
@ -103,6 +109,34 @@ func (c *Cluster) syncServices() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Ensures the service account required by StatefulSets to create pods exists in all namespaces watched by the operator.
|
||||||
|
*/
|
||||||
|
func (c *Cluster) syncPodServiceAccounts() error {
|
||||||
|
|
||||||
|
podServiceAccount := c.Config.OpConfig.PodServiceAccountName
|
||||||
|
c.setProcessName("syncing pod service account in the watched namespaces")
|
||||||
|
|
||||||
|
_, err := c.KubeClient.ServiceAccounts(c.Namespace).Get(podServiceAccount, 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.OpConfig.PodServiceAccount.SetNamespace(c.Namespace)
|
||||||
|
|
||||||
|
_, 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)
|
||||||
|
} else {
|
||||||
|
c.logger.Infof("successfully deployed the pod service account %q to the %q namespace", podServiceAccount, c.Namespace)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
c.logger.Infof("successfully found the service account %q used to create pods to the namespace %q", podServiceAccount, c.Namespace)
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Cluster) syncService(role PostgresRole) error {
|
func (c *Cluster) syncService(role PostgresRole) error {
|
||||||
c.setProcessName("syncing %s service", role)
|
c.setProcessName("syncing %s service", role)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
"k8s.io/client-go/kubernetes/scheme"
|
||||||
"k8s.io/client-go/pkg/api/v1"
|
"k8s.io/client-go/pkg/api/v1"
|
||||||
"k8s.io/client-go/tools/cache"
|
"k8s.io/client-go/tools/cache"
|
||||||
|
|
||||||
|
|
@ -113,11 +114,30 @@ func (c *Controller) initOperatorConfig() {
|
||||||
if scalyrAPIKey != "" {
|
if scalyrAPIKey != "" {
|
||||||
c.opConfig.ScalyrAPIKey = scalyrAPIKey
|
c.opConfig.ScalyrAPIKey = scalyrAPIKey
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Controller) initPodServiceAccount() {
|
||||||
|
// re-uses k8s internal parsing. See k8s client-go issue #193 for explanation
|
||||||
|
decode := scheme.Codecs.UniversalDeserializer().Decode
|
||||||
|
obj, groupVersionKind, err := decode([]byte(c.opConfig.PodServiceAccountDefinition), nil, nil)
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case err != nil:
|
||||||
|
panic(fmt.Errorf("Unable to parse pod service account definiton from the operator config map: %v", err))
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// actual service accounts are deployed lazily at the time of cluster creation or sync
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) initController() {
|
func (c *Controller) initController() {
|
||||||
c.initClients()
|
c.initClients()
|
||||||
c.initOperatorConfig()
|
c.initOperatorConfig()
|
||||||
|
c.initPodServiceAccount()
|
||||||
|
|
||||||
c.initSharedInformers()
|
c.initSharedInformers()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/zalando-incubator/postgres-operator/pkg/spec"
|
"github.com/zalando-incubator/postgres-operator/pkg/spec"
|
||||||
|
"k8s.io/client-go/pkg/api/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CRD describes CustomResourceDefinition specific configuration parameters
|
// CRD describes CustomResourceDefinition specific configuration parameters
|
||||||
|
|
@ -67,10 +68,14 @@ type Config struct {
|
||||||
Resources
|
Resources
|
||||||
Auth
|
Auth
|
||||||
Scalyr
|
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'
|
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"`
|
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"`
|
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"`
|
ServiceAccountName string `name:"service_account_name" default:"operator"`
|
||||||
|
PodServiceAccountName string `name:"pod_service_account_name" default:"operator"`
|
||||||
|
PodServiceAccountDefinition string `name:"pod_service_account_definition" default:"apiVersion: v1\nkind: ServiceAccount\nmetadata:\n name: operator\n"`
|
||||||
DbHostedZone string `name:"db_hosted_zone" default:"db.example.com"`
|
DbHostedZone string `name:"db_hosted_zone" default:"db.example.com"`
|
||||||
EtcdScope string `name:"etcd_scope" default:"service"`
|
EtcdScope string `name:"etcd_scope" default:"service"`
|
||||||
WALES3Bucket string `name:"wal_s3_bucket"`
|
WALES3Bucket string `name:"wal_s3_bucket"`
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue