mirror of
https://github.com/zalando/postgres-operator.git
synced 2026-09-30 18:33:02 +02:00
Make use of kubernetes client-go v4
* client-go v4.0.0-beta0 * remove unnecessary methods for tpr object * rest client: use interface instead of structure pointer * proper names for constants; some clean up for log messages * remove teams api client from controller and make it per cluster
This commit is contained in:
+123
-81
@@ -5,6 +5,7 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/pkg/api/v1"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
@@ -14,22 +15,25 @@ import (
|
||||
"github.com/zalando-incubator/postgres-operator/pkg/util/config"
|
||||
"github.com/zalando-incubator/postgres-operator/pkg/util/constants"
|
||||
"github.com/zalando-incubator/postgres-operator/pkg/util/k8sutil"
|
||||
"github.com/zalando-incubator/postgres-operator/pkg/util/teams"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
RestConfig *rest.Config
|
||||
KubeClient k8sutil.KubernetesClient
|
||||
RestClient *rest.RESTClient
|
||||
TeamsAPIClient *teams.API
|
||||
InfrastructureRoles map[string]spec.PgUser
|
||||
|
||||
NoDatabaseAccess bool
|
||||
NoTeamsAPI bool
|
||||
ConfigMapName spec.NamespacedName
|
||||
Namespace string
|
||||
}
|
||||
|
||||
type Controller struct {
|
||||
Config
|
||||
|
||||
config Config
|
||||
opConfig *config.Config
|
||||
logger *logrus.Entry
|
||||
|
||||
logger *logrus.Entry
|
||||
KubeClient k8sutil.KubernetesClient
|
||||
RestClient rest.Interface // kubernetes API group REST client
|
||||
|
||||
clustersMu sync.RWMutex
|
||||
clusters map[spec.NamespacedName]*cluster.Cluster
|
||||
@@ -39,23 +43,16 @@ type Controller struct {
|
||||
podInformer cache.SharedIndexInformer
|
||||
podCh chan spec.PodEvent
|
||||
|
||||
clusterEventQueues []*cache.FIFO
|
||||
|
||||
clusterEventQueues []*cache.FIFO
|
||||
lastClusterSyncTime int64
|
||||
}
|
||||
|
||||
func NewController(controllerConfig *Config, operatorConfig *config.Config) *Controller {
|
||||
func NewController(controllerConfig *Config) *Controller {
|
||||
logger := logrus.New()
|
||||
|
||||
if operatorConfig.DebugLogging {
|
||||
logger.Level = logrus.DebugLevel
|
||||
}
|
||||
|
||||
controllerConfig.TeamsAPIClient = teams.NewTeamsAPI(operatorConfig.TeamsAPIUrl, logger)
|
||||
|
||||
return &Controller{
|
||||
Config: *controllerConfig,
|
||||
opConfig: operatorConfig,
|
||||
config: *controllerConfig,
|
||||
opConfig: &config.Config{},
|
||||
logger: logger.WithField("pkg", "controller"),
|
||||
clusters: make(map[spec.NamespacedName]*cluster.Cluster),
|
||||
stopChs: make(map[spec.NamespacedName]chan struct{}),
|
||||
@@ -63,6 +60,114 @@ func NewController(controllerConfig *Config, operatorConfig *config.Config) *Con
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Controller) initClients() {
|
||||
client, err := k8sutil.ClientSet(c.config.RestConfig)
|
||||
if err != nil {
|
||||
c.logger.Fatalf("couldn't create client: %v", err)
|
||||
}
|
||||
c.KubeClient = k8sutil.NewFromKubernetesInterface(client)
|
||||
|
||||
c.RestClient, err = k8sutil.KubernetesRestClient(*c.config.RestConfig)
|
||||
if err != nil {
|
||||
c.logger.Fatalf("couldn't create rest client: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Controller) initOperatorConfig() {
|
||||
configMapData := make(map[string]string)
|
||||
|
||||
if c.config.ConfigMapName != (spec.NamespacedName{}) {
|
||||
configMap, err := c.KubeClient.ConfigMaps(c.config.ConfigMapName.Namespace).
|
||||
Get(c.config.ConfigMapName.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
configMapData = configMap.Data
|
||||
} else {
|
||||
c.logger.Infoln("No ConfigMap specified. Loading default values")
|
||||
}
|
||||
|
||||
if configMapData["namespace"] == "" { // Namespace in ConfigMap has priority over env var
|
||||
configMapData["namespace"] = c.config.Namespace
|
||||
}
|
||||
if c.config.NoDatabaseAccess {
|
||||
configMapData["enable_database_access"] = "false"
|
||||
}
|
||||
if c.config.NoTeamsAPI {
|
||||
configMapData["enable_teams_api"] = "false"
|
||||
}
|
||||
|
||||
c.opConfig = config.NewFromMap(configMapData)
|
||||
}
|
||||
|
||||
func (c *Controller) initController() {
|
||||
c.initClients()
|
||||
c.initOperatorConfig()
|
||||
|
||||
c.logger.Infof("Config: %s", c.opConfig.MustMarshal())
|
||||
|
||||
if c.opConfig.DebugLogging {
|
||||
c.logger.Level = logrus.DebugLevel
|
||||
}
|
||||
|
||||
if err := c.createTPR(); err != nil {
|
||||
c.logger.Fatalf("could not register ThirdPartyResource: %v", err)
|
||||
}
|
||||
|
||||
if infraRoles, err := c.getInfrastructureRoles(&c.opConfig.InfrastructureRolesSecretName); err != nil {
|
||||
c.logger.Warningf("could not get infrastructure roles: %v", err)
|
||||
} else {
|
||||
c.config.InfrastructureRoles = infraRoles
|
||||
}
|
||||
|
||||
// Postgresqls
|
||||
c.postgresqlInformer = cache.NewSharedIndexInformer(
|
||||
&cache.ListWatch{
|
||||
ListFunc: c.clusterListFunc,
|
||||
WatchFunc: c.clusterWatchFunc,
|
||||
},
|
||||
&spec.Postgresql{},
|
||||
constants.QueueResyncPeriodTPR,
|
||||
cache.Indexers{})
|
||||
|
||||
c.postgresqlInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
|
||||
AddFunc: c.postgresqlAdd,
|
||||
UpdateFunc: c.postgresqlUpdate,
|
||||
DeleteFunc: c.postgresqlDelete,
|
||||
})
|
||||
|
||||
// Pods
|
||||
podLw := &cache.ListWatch{
|
||||
ListFunc: c.podListFunc,
|
||||
WatchFunc: c.podWatchFunc,
|
||||
}
|
||||
|
||||
c.podInformer = cache.NewSharedIndexInformer(
|
||||
podLw,
|
||||
&v1.Pod{},
|
||||
constants.QueueResyncPeriodPod,
|
||||
cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc})
|
||||
|
||||
c.podInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
|
||||
AddFunc: c.podAdd,
|
||||
UpdateFunc: c.podUpdate,
|
||||
DeleteFunc: c.podDelete,
|
||||
})
|
||||
|
||||
c.clusterEventQueues = make([]*cache.FIFO, c.opConfig.Workers)
|
||||
for i := range c.clusterEventQueues {
|
||||
c.clusterEventQueues[i] = cache.NewFIFO(func(obj interface{}) (string, error) {
|
||||
e, ok := obj.(spec.ClusterEvent)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("could not cast to ClusterEvent")
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s-%s", e.EventType, e.UID), nil
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Controller) Run(stopCh <-chan struct{}, wg *sync.WaitGroup) {
|
||||
defer wg.Done()
|
||||
wg.Add(1)
|
||||
@@ -78,69 +183,6 @@ func (c *Controller) Run(stopCh <-chan struct{}, wg *sync.WaitGroup) {
|
||||
c.logger.Info("Started working in background")
|
||||
}
|
||||
|
||||
func (c *Controller) initController() {
|
||||
if err := c.createTPR(); err != nil {
|
||||
c.logger.Fatalf("could not register ThirdPartyResource: %v", err)
|
||||
}
|
||||
|
||||
if infraRoles, err := c.getInfrastructureRoles(&c.opConfig.InfrastructureRolesSecretName); err != nil {
|
||||
c.logger.Warningf("could not get infrastructure roles: %v", err)
|
||||
} else {
|
||||
c.InfrastructureRoles = infraRoles
|
||||
}
|
||||
|
||||
// Postgresqls
|
||||
clusterLw := &cache.ListWatch{
|
||||
ListFunc: c.clusterListFunc,
|
||||
WatchFunc: c.clusterWatchFunc,
|
||||
}
|
||||
c.postgresqlInformer = cache.NewSharedIndexInformer(
|
||||
clusterLw,
|
||||
&spec.Postgresql{},
|
||||
constants.QueueResyncPeriodTPR,
|
||||
cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc})
|
||||
|
||||
if err := c.postgresqlInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
|
||||
AddFunc: c.postgresqlAdd,
|
||||
UpdateFunc: c.postgresqlUpdate,
|
||||
DeleteFunc: c.postgresqlDelete,
|
||||
}); err != nil {
|
||||
c.logger.Fatalf("could not add event handlers: %v", err)
|
||||
}
|
||||
|
||||
// Pods
|
||||
podLw := &cache.ListWatch{
|
||||
ListFunc: c.podListFunc,
|
||||
WatchFunc: c.podWatchFunc,
|
||||
}
|
||||
|
||||
c.podInformer = cache.NewSharedIndexInformer(
|
||||
podLw,
|
||||
&v1.Pod{},
|
||||
constants.QueueResyncPeriodPod,
|
||||
cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc})
|
||||
|
||||
if err := c.podInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
|
||||
AddFunc: c.podAdd,
|
||||
UpdateFunc: c.podUpdate,
|
||||
DeleteFunc: c.podDelete,
|
||||
}); err != nil {
|
||||
c.logger.Fatalf("could not add event handlers: %v", err)
|
||||
}
|
||||
|
||||
c.clusterEventQueues = make([]*cache.FIFO, c.opConfig.Workers)
|
||||
for i := range c.clusterEventQueues {
|
||||
c.clusterEventQueues[i] = cache.NewFIFO(func(obj interface{}) (string, error) {
|
||||
e, ok := obj.(spec.ClusterEvent)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("could not cast to ClusterEvent")
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s-%s", e.EventType, e.UID), nil
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Controller) runInformers(stopCh <-chan struct{}) {
|
||||
go c.postgresqlInformer.Run(stopCh)
|
||||
go c.podInformer.Run(stopCh)
|
||||
|
||||
+8
-23
@@ -1,27 +1,20 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"k8s.io/client-go/pkg/api"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/pkg/api/v1"
|
||||
"k8s.io/client-go/pkg/runtime"
|
||||
"k8s.io/client-go/pkg/watch"
|
||||
|
||||
"github.com/zalando-incubator/postgres-operator/pkg/spec"
|
||||
"github.com/zalando-incubator/postgres-operator/pkg/util"
|
||||
)
|
||||
|
||||
func (c *Controller) podListFunc(options api.ListOptions) (runtime.Object, error) {
|
||||
func (c *Controller) podListFunc(options metav1.ListOptions) (runtime.Object, error) {
|
||||
var labelSelector string
|
||||
var fieldSelector string
|
||||
|
||||
if options.LabelSelector != nil {
|
||||
labelSelector = options.LabelSelector.String()
|
||||
}
|
||||
|
||||
if options.FieldSelector != nil {
|
||||
fieldSelector = options.FieldSelector.String()
|
||||
}
|
||||
opts := v1.ListOptions{
|
||||
opts := metav1.ListOptions{
|
||||
LabelSelector: labelSelector,
|
||||
FieldSelector: fieldSelector,
|
||||
Watch: options.Watch,
|
||||
@@ -32,19 +25,11 @@ func (c *Controller) podListFunc(options api.ListOptions) (runtime.Object, error
|
||||
return c.KubeClient.Pods(c.opConfig.Namespace).List(opts)
|
||||
}
|
||||
|
||||
func (c *Controller) podWatchFunc(options api.ListOptions) (watch.Interface, error) {
|
||||
func (c *Controller) podWatchFunc(options metav1.ListOptions) (watch.Interface, error) {
|
||||
var labelSelector string
|
||||
var fieldSelector string
|
||||
|
||||
if options.LabelSelector != nil {
|
||||
labelSelector = options.LabelSelector.String()
|
||||
}
|
||||
|
||||
if options.FieldSelector != nil {
|
||||
fieldSelector = options.FieldSelector.String()
|
||||
}
|
||||
|
||||
opts := v1.ListOptions{
|
||||
opts := metav1.ListOptions{
|
||||
LabelSelector: labelSelector,
|
||||
FieldSelector: fieldSelector,
|
||||
Watch: options.Watch,
|
||||
@@ -122,7 +107,7 @@ func (c *Controller) podEventsDispatcher(stopCh <-chan struct{}) {
|
||||
c.clustersMu.RUnlock()
|
||||
|
||||
if ok {
|
||||
c.logger.Debugf("Sending %s event of pod '%s' to the '%s' cluster channel", event.EventType, event.PodName, event.ClusterName)
|
||||
c.logger.Debugf("Sending %q event of pod %q to the %q cluster channel", event.EventType, event.PodName, event.ClusterName)
|
||||
cluster.ReceivePodEvent(event)
|
||||
}
|
||||
case <-stopCh:
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"k8s.io/client-go/pkg/api"
|
||||
"k8s.io/client-go/pkg/api/meta"
|
||||
"k8s.io/client-go/pkg/fields"
|
||||
"k8s.io/client-go/pkg/runtime"
|
||||
"k8s.io/client-go/pkg/types"
|
||||
"k8s.io/client-go/pkg/watch"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
|
||||
"github.com/zalando-incubator/postgres-operator/pkg/cluster"
|
||||
@@ -26,52 +25,43 @@ func (c *Controller) clusterResync(stopCh <-chan struct{}) {
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
c.clusterListFunc(api.ListOptions{ResourceVersion: "0"})
|
||||
c.clusterListFunc(metav1.ListOptions{ResourceVersion: "0"})
|
||||
case <-stopCh:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Controller) clusterListFunc(options api.ListOptions) (runtime.Object, error) {
|
||||
c.logger.Info("Getting list of currently running clusters")
|
||||
func (c *Controller) clusterListFunc(options metav1.ListOptions) (runtime.Object, error) {
|
||||
var list spec.PostgresqlList
|
||||
var activeClustersCnt, failedClustersCnt int
|
||||
|
||||
req := c.RestClient.Get().
|
||||
RequestURI(fmt.Sprintf(constants.ListClustersURITemplate, c.opConfig.Namespace)).
|
||||
VersionedParams(&options, api.ParameterCodec).
|
||||
FieldsSelectorParam(fields.Everything())
|
||||
|
||||
object, err := req.Do().Get()
|
||||
req := c.RestClient.
|
||||
Get().
|
||||
Namespace(c.opConfig.Namespace).
|
||||
Resource(constants.ResourceName).
|
||||
VersionedParams(&options, metav1.ParameterCodec)
|
||||
|
||||
b, err := req.DoRaw()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get list of postgresql objects: %v", err)
|
||||
}
|
||||
|
||||
objList, err := meta.ExtractList(object)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not extract list of postgresql objects: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
err = json.Unmarshal(b, &list)
|
||||
|
||||
if time.Now().Unix()-atomic.LoadInt64(&c.lastClusterSyncTime) <= int64(c.opConfig.ResyncPeriod.Seconds()) {
|
||||
c.logger.Debugln("skipping resync of clusters")
|
||||
return object, err
|
||||
return &list, err
|
||||
}
|
||||
|
||||
var activeClustersCnt, failedClustersCnt int
|
||||
for _, obj := range objList {
|
||||
pg, ok := obj.(*spec.Postgresql)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("could not cast object to postgresql")
|
||||
}
|
||||
|
||||
for _, pg := range list.Items {
|
||||
if pg.Error != nil {
|
||||
failedClustersCnt++
|
||||
continue
|
||||
}
|
||||
c.queueClusterEvent(nil, pg, spec.EventSync)
|
||||
c.queueClusterEvent(nil, &pg, spec.EventSync)
|
||||
activeClustersCnt++
|
||||
}
|
||||
if len(objList) > 0 {
|
||||
if len(list.Items) > 0 {
|
||||
if failedClustersCnt > 0 && activeClustersCnt == 0 {
|
||||
c.logger.Infof("There are no clusters running. %d are in the failed state", failedClustersCnt)
|
||||
} else if failedClustersCnt == 0 && activeClustersCnt > 0 {
|
||||
@@ -85,15 +75,48 @@ func (c *Controller) clusterListFunc(options api.ListOptions) (runtime.Object, e
|
||||
|
||||
atomic.StoreInt64(&c.lastClusterSyncTime, time.Now().Unix())
|
||||
|
||||
return object, err
|
||||
return &list, err
|
||||
}
|
||||
|
||||
func (c *Controller) clusterWatchFunc(options api.ListOptions) (watch.Interface, error) {
|
||||
req := c.RestClient.Get().
|
||||
RequestURI(fmt.Sprintf(constants.WatchClustersURITemplate, c.opConfig.Namespace)).
|
||||
VersionedParams(&options, api.ParameterCodec).
|
||||
FieldsSelectorParam(fields.Everything())
|
||||
return req.Watch()
|
||||
type tprDecoder struct {
|
||||
dec *json.Decoder
|
||||
close func() error
|
||||
}
|
||||
|
||||
func (d *tprDecoder) Close() {
|
||||
d.close()
|
||||
}
|
||||
|
||||
func (d *tprDecoder) Decode() (action watch.EventType, object runtime.Object, err error) {
|
||||
var e struct {
|
||||
Type watch.EventType
|
||||
Object spec.Postgresql
|
||||
}
|
||||
if err := d.dec.Decode(&e); err != nil {
|
||||
return watch.Error, nil, err
|
||||
}
|
||||
|
||||
return e.Type, &e.Object, nil
|
||||
}
|
||||
|
||||
func (c *Controller) clusterWatchFunc(options metav1.ListOptions) (watch.Interface, error) {
|
||||
options.Watch = true
|
||||
r, err := c.RestClient.
|
||||
Get().
|
||||
Namespace(c.opConfig.Namespace).
|
||||
Resource(constants.ResourceName).
|
||||
VersionedParams(&options, metav1.ParameterCodec).
|
||||
FieldsSelectorParam(nil).
|
||||
Stream()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return watch.NewStreamWatcher(&tprDecoder{
|
||||
dec: json.NewDecoder(r),
|
||||
close: r.Close,
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (c *Controller) processEvent(obj interface{}) error {
|
||||
@@ -106,9 +129,9 @@ func (c *Controller) processEvent(obj interface{}) error {
|
||||
logger := c.logger.WithField("worker", event.WorkerID)
|
||||
|
||||
if event.EventType == spec.EventAdd || event.EventType == spec.EventSync {
|
||||
clusterName = util.NameFromMeta(event.NewSpec.Metadata)
|
||||
clusterName = util.NameFromMeta(event.NewSpec.ObjectMeta)
|
||||
} else {
|
||||
clusterName = util.NameFromMeta(event.OldSpec.Metadata)
|
||||
clusterName = util.NameFromMeta(event.OldSpec.ObjectMeta)
|
||||
}
|
||||
|
||||
c.clustersMu.RLock()
|
||||
@@ -118,14 +141,14 @@ func (c *Controller) processEvent(obj interface{}) error {
|
||||
switch event.EventType {
|
||||
case spec.EventAdd:
|
||||
if clusterFound {
|
||||
logger.Debugf("Cluster '%s' already exists", clusterName)
|
||||
logger.Debugf("Cluster %q already exists", clusterName)
|
||||
return nil
|
||||
}
|
||||
|
||||
logger.Infof("Creation of the '%s' cluster started", clusterName)
|
||||
logger.Infof("Creation of the %q cluster started", clusterName)
|
||||
|
||||
stopCh := make(chan struct{})
|
||||
cl = cluster.New(c.makeClusterConfig(), *event.NewSpec, logger)
|
||||
cl = cluster.New(c.makeClusterConfig(), c.KubeClient, *event.NewSpec, logger)
|
||||
cl.Run(stopCh)
|
||||
|
||||
c.clustersMu.Lock()
|
||||
@@ -140,31 +163,31 @@ func (c *Controller) processEvent(obj interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
logger.Infof("Cluster '%s' has been created", clusterName)
|
||||
logger.Infof("Cluster %q has been created", clusterName)
|
||||
case spec.EventUpdate:
|
||||
logger.Infof("Update of the '%s' cluster started", clusterName)
|
||||
logger.Infof("Update of the %q cluster started", clusterName)
|
||||
|
||||
if !clusterFound {
|
||||
logger.Warnf("Cluster '%s' does not exist", clusterName)
|
||||
logger.Warnf("Cluster %q does not exist", clusterName)
|
||||
return nil
|
||||
}
|
||||
if err := cl.Update(event.NewSpec); err != nil {
|
||||
cl.Error = fmt.Errorf("could not update cluster: %s", err)
|
||||
cl.Error = fmt.Errorf("could not update cluster: %v", err)
|
||||
logger.Errorf("%v", cl.Error)
|
||||
|
||||
return nil
|
||||
}
|
||||
cl.Error = nil
|
||||
logger.Infof("Cluster '%s' has been updated", clusterName)
|
||||
logger.Infof("Cluster %q has been updated", clusterName)
|
||||
case spec.EventDelete:
|
||||
logger.Infof("Deletion of the '%s' cluster started", clusterName)
|
||||
logger.Infof("Deletion of the %q cluster started", clusterName)
|
||||
if !clusterFound {
|
||||
logger.Errorf("Unknown cluster: %s", clusterName)
|
||||
logger.Errorf("Unknown cluster: %q", clusterName)
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := cl.Delete(); err != nil {
|
||||
logger.Errorf("could not delete cluster '%s': %s", clusterName, err)
|
||||
logger.Errorf("could not delete cluster %q: %v", clusterName, err)
|
||||
return nil
|
||||
}
|
||||
close(c.stopChs[clusterName])
|
||||
@@ -174,14 +197,14 @@ func (c *Controller) processEvent(obj interface{}) error {
|
||||
delete(c.stopChs, clusterName)
|
||||
c.clustersMu.Unlock()
|
||||
|
||||
logger.Infof("Cluster '%s' has been deleted", clusterName)
|
||||
logger.Infof("Cluster %q has been deleted", clusterName)
|
||||
case spec.EventSync:
|
||||
logger.Infof("Syncing of the '%s' cluster started", clusterName)
|
||||
logger.Infof("Syncing of the %q cluster started", clusterName)
|
||||
|
||||
// no race condition because a cluster is always processed by single worker
|
||||
if !clusterFound {
|
||||
stopCh := make(chan struct{})
|
||||
cl = cluster.New(c.makeClusterConfig(), *event.NewSpec, logger)
|
||||
cl = cluster.New(c.makeClusterConfig(), c.KubeClient, *event.NewSpec, logger)
|
||||
cl.Run(stopCh)
|
||||
|
||||
c.clustersMu.Lock()
|
||||
@@ -191,13 +214,13 @@ func (c *Controller) processEvent(obj interface{}) error {
|
||||
}
|
||||
|
||||
if err := cl.Sync(); err != nil {
|
||||
cl.Error = fmt.Errorf("could not sync cluster '%s': %v", clusterName, err)
|
||||
cl.Error = fmt.Errorf("could not sync cluster %q: %v", clusterName, err)
|
||||
logger.Errorf("%v", cl.Error)
|
||||
return nil
|
||||
}
|
||||
cl.Error = nil
|
||||
|
||||
logger.Infof("Cluster '%s' has been synced", clusterName)
|
||||
logger.Infof("Cluster %q has been synced", clusterName)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -219,8 +242,8 @@ func (c *Controller) queueClusterEvent(old, new *spec.Postgresql, eventType spec
|
||||
)
|
||||
|
||||
if old != nil { //update, delete
|
||||
uid = old.Metadata.GetUID()
|
||||
clusterName = util.NameFromMeta(old.Metadata)
|
||||
uid = old.GetUID()
|
||||
clusterName = util.NameFromMeta(old.ObjectMeta)
|
||||
if eventType == spec.EventUpdate && new.Error == nil && old.Error != nil {
|
||||
eventType = spec.EventSync
|
||||
clusterError = new.Error
|
||||
@@ -228,13 +251,13 @@ func (c *Controller) queueClusterEvent(old, new *spec.Postgresql, eventType spec
|
||||
clusterError = old.Error
|
||||
}
|
||||
} else { //add, sync
|
||||
uid = new.Metadata.GetUID()
|
||||
clusterName = util.NameFromMeta(new.Metadata)
|
||||
uid = new.GetUID()
|
||||
clusterName = util.NameFromMeta(new.ObjectMeta)
|
||||
clusterError = new.Error
|
||||
}
|
||||
|
||||
if clusterError != nil && eventType != spec.EventDelete {
|
||||
c.logger.Debugf("Skipping %s event for invalid cluster %s (reason: %v)", eventType, clusterName, clusterError)
|
||||
c.logger.Debugf("Skipping %q event for invalid cluster %q (reason: %v)", eventType, clusterName, clusterError)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -251,7 +274,7 @@ func (c *Controller) queueClusterEvent(old, new *spec.Postgresql, eventType spec
|
||||
if err := c.clusterEventQueues[workerID].Add(clusterEvent); err != nil {
|
||||
c.logger.WithField("worker", workerID).Errorf("error when queueing cluster event: %v", clusterEvent)
|
||||
}
|
||||
c.logger.WithField("worker", workerID).Infof("%s of the '%s' cluster has been queued", eventType, clusterName)
|
||||
c.logger.WithField("worker", workerID).Infof("%q of the %q cluster has been queued", eventType, clusterName)
|
||||
}
|
||||
|
||||
func (c *Controller) postgresqlAdd(obj interface{}) {
|
||||
@@ -274,7 +297,7 @@ func (c *Controller) postgresqlUpdate(prev, cur interface{}) {
|
||||
if !ok {
|
||||
c.logger.Errorf("could not cast to postgresql spec")
|
||||
}
|
||||
if pgOld.Metadata.ResourceVersion == pgNew.Metadata.ResourceVersion {
|
||||
if pgOld.ResourceVersion == pgNew.ResourceVersion {
|
||||
return
|
||||
}
|
||||
if reflect.DeepEqual(pgOld.Spec, pgNew.Spec) {
|
||||
|
||||
+10
-13
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"hash/crc32"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/pkg/api/v1"
|
||||
extv1beta "k8s.io/client-go/pkg/apis/extensions/v1beta1"
|
||||
|
||||
@@ -16,15 +17,12 @@ import (
|
||||
|
||||
func (c *Controller) makeClusterConfig() cluster.Config {
|
||||
infrastructureRoles := make(map[string]spec.PgUser)
|
||||
for k, v := range c.InfrastructureRoles {
|
||||
for k, v := range c.config.InfrastructureRoles {
|
||||
infrastructureRoles[k] = v
|
||||
}
|
||||
|
||||
return cluster.Config{
|
||||
KubeClient: c.KubeClient,
|
||||
RestClient: c.RestClient,
|
||||
RestConfig: c.RestConfig,
|
||||
TeamsAPIClient: c.TeamsAPIClient,
|
||||
RestConfig: c.config.RestConfig,
|
||||
OpConfig: config.Copy(c.opConfig),
|
||||
InfrastructureRoles: infrastructureRoles,
|
||||
}
|
||||
@@ -32,7 +30,7 @@ func (c *Controller) makeClusterConfig() cluster.Config {
|
||||
|
||||
func thirdPartyResource(TPRName string) *extv1beta.ThirdPartyResource {
|
||||
return &extv1beta.ThirdPartyResource{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
//ThirdPartyResources are cluster-wide
|
||||
Name: TPRName,
|
||||
},
|
||||
@@ -48,17 +46,16 @@ func (c *Controller) clusterWorkerID(clusterName spec.NamespacedName) uint32 {
|
||||
}
|
||||
|
||||
func (c *Controller) createTPR() error {
|
||||
TPRName := fmt.Sprintf("%s.%s", constants.TPRName, constants.TPRVendor)
|
||||
tpr := thirdPartyResource(TPRName)
|
||||
tpr := thirdPartyResource(constants.TPRName)
|
||||
|
||||
_, err := c.KubeClient.ThirdPartyResources().Create(tpr)
|
||||
if err != nil {
|
||||
if !k8sutil.ResourceAlreadyExists(err) {
|
||||
return err
|
||||
}
|
||||
c.logger.Infof("ThirdPartyResource '%s' is already registered", TPRName)
|
||||
c.logger.Infof("ThirdPartyResource %q is already registered", constants.TPRName)
|
||||
} else {
|
||||
c.logger.Infof("ThirdPartyResource '%s' has been registered", TPRName)
|
||||
c.logger.Infof("ThirdPartyResource %q' has been registered", constants.TPRName)
|
||||
}
|
||||
|
||||
return k8sutil.WaitTPRReady(c.RestClient, c.opConfig.TPR.ReadyWaitInterval, c.opConfig.TPR.ReadyWaitTimeout, c.opConfig.Namespace)
|
||||
@@ -72,9 +69,9 @@ func (c *Controller) getInfrastructureRoles(rolesSecret *spec.NamespacedName) (r
|
||||
|
||||
infraRolesSecret, err := c.KubeClient.
|
||||
Secrets(rolesSecret.Namespace).
|
||||
Get(rolesSecret.Name)
|
||||
Get(rolesSecret.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
c.logger.Debugf("Infrastructure roles secret name: %s", *rolesSecret)
|
||||
c.logger.Debugf("Infrastructure roles secret name: %q", *rolesSecret)
|
||||
return nil, fmt.Errorf("could not get infrastructure roles secret: %v", err)
|
||||
}
|
||||
|
||||
@@ -102,7 +99,7 @@ Users:
|
||||
case "inrole":
|
||||
t.MemberOf = append(t.MemberOf, s)
|
||||
default:
|
||||
c.logger.Warnf("Unknown key %s", p)
|
||||
c.logger.Warnf("Unknown key %q", p)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,11 +5,11 @@ import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
v1core "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
"k8s.io/client-go/pkg/api/v1"
|
||||
|
||||
"github.com/zalando-incubator/postgres-operator/pkg/spec"
|
||||
"github.com/zalando-incubator/postgres-operator/pkg/util/config"
|
||||
"github.com/zalando-incubator/postgres-operator/pkg/util/k8sutil"
|
||||
)
|
||||
|
||||
@@ -21,7 +21,7 @@ type mockSecret struct {
|
||||
v1core.SecretInterface
|
||||
}
|
||||
|
||||
func (c *mockSecret) Get(name string) (*v1.Secret, error) {
|
||||
func (c *mockSecret) Get(name string, options metav1.GetOptions) (*v1.Secret, error) {
|
||||
if name != testInfrastructureRolesSecretName {
|
||||
return nil, fmt.Errorf("NotFound")
|
||||
}
|
||||
@@ -48,7 +48,7 @@ func newMockKubernetesClient() k8sutil.KubernetesClient {
|
||||
}
|
||||
|
||||
func newMockController() *Controller {
|
||||
controller := NewController(&Config{}, &config.Config{})
|
||||
controller := NewController(&Config{})
|
||||
controller.opConfig.ClusterNameLabel = "cluster-name"
|
||||
controller.opConfig.InfrastructureRolesSecretName =
|
||||
spec.NamespacedName{v1.NamespaceDefault, testInfrastructureRolesSecretName}
|
||||
@@ -70,7 +70,7 @@ func TestPodClusterName(t *testing.T) {
|
||||
},
|
||||
{
|
||||
&v1.Pod{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: v1.NamespaceDefault,
|
||||
Labels: map[string]string{
|
||||
mockController.opConfig.ClusterNameLabel: "testcluster",
|
||||
|
||||
Reference in New Issue
Block a user