From aa517d13b4bbe6a89e6352e53617f18587ff451d Mon Sep 17 00:00:00 2001
From: Oleksii Kliukin <oleksii.kliukin@zalando.de>
Date: Tue, 9 Jan 2018 18:36:42 +0100
Subject: [PATCH] WIP: support multiple namespaces.

This particular commit makes the operator listen on all namespaces
and introduces an optional namespace to the clusters RESET API
endpoints.
---
 pkg/apiserver/apiserver.go   | 21 ++++++++++++---------
 pkg/cluster/cluster.go       |  4 ++++
 pkg/cluster/resources.go     |  2 +-
 pkg/controller/node.go       |  2 +-
 pkg/controller/pod.go        |  4 ++--
 pkg/controller/postgresql.go |  2 --
 pkg/controller/status.go     | 21 +++++++++++++++------
 7 files changed, 35 insertions(+), 21 deletions(-)

diff --git a/pkg/apiserver/apiserver.go b/pkg/apiserver/apiserver.go
index 2b0b2f98..41dfed1a 100644
--- a/pkg/apiserver/apiserver.go
+++ b/pkg/apiserver/apiserver.go
@@ -30,9 +30,9 @@ type controllerInformer interface {
 	GetOperatorConfig() *config.Config
 	GetStatus() *spec.ControllerStatus
 	TeamClusterList() map[string][]spec.NamespacedName
-	ClusterStatus(team, cluster string) (*spec.ClusterStatus, error)
-	ClusterLogs(team, cluster string) ([]*spec.LogEntry, error)
-	ClusterHistory(team, cluster string) ([]*spec.Diff, error)
+	ClusterStatus(team, namespace, cluster string) (*spec.ClusterStatus, error)
+	ClusterLogs(team, namespace, cluster string) ([]*spec.LogEntry, error)
+	ClusterHistory(team, namespace, cluster string) ([]*spec.Diff, error)
 	ClusterDatabasesMap() map[string][]string
 	WorkerLogs(workerID uint32) ([]*spec.LogEntry, error)
 	ListQueue(workerID uint32) (*spec.QueueDump, error)
@@ -48,9 +48,9 @@ type Server struct {
 }
 
 var (
-	clusterStatusURL     = regexp.MustCompile(`^/clusters/(?P<team>[a-zA-Z][a-zA-Z0-9]*)/(?P<cluster>[a-zA-Z][a-zA-Z0-9-]*)/?$`)
-	clusterLogsURL       = regexp.MustCompile(`^/clusters/(?P<team>[a-zA-Z][a-zA-Z0-9]*)/(?P<cluster>[a-zA-Z][a-zA-Z0-9-]*)/logs/?$`)
-	clusterHistoryURL    = regexp.MustCompile(`^/clusters/(?P<team>[a-zA-Z][a-zA-Z0-9]*)/(?P<cluster>[a-zA-Z][a-zA-Z0-9-]*)/history/?$`)
+	clusterStatusURL     = regexp.MustCompile(`^/clusters/(?P<team>[a-zA-Z][a-zA-Z0-9]*)(/(?P<namespace>[a-zA-Z][a-zA-Z0-9-]*))?/(?P<cluster>[a-zA-Z][a-zA-Z0-9-]*)/?$`)
+	clusterLogsURL       = regexp.MustCompile(`^/clusters/(?P<team>[a-zA-Z][a-zA-Z0-9]*)(/(?P<namespace>[a-zA-Z][a-zA-Z0-9-]*))?/(?P<cluster>[a-zA-Z][a-zA-Z0-9-]*)/logs/?$`)
+	clusterHistoryURL    = regexp.MustCompile(`^/clusters/(?P<team>[a-zA-Z][a-zA-Z0-9]*)(/(?P<namespace>[a-zA-Z][a-zA-Z0-9-]*))?/(?P<cluster>[a-zA-Z][a-zA-Z0-9-]*)/history/?$`)
 	teamURL              = regexp.MustCompile(`^/clusters/(?P<team>[a-zA-Z][a-zA-Z0-9]*)/?$`)
 	workerLogsURL        = regexp.MustCompile(`^/workers/(?P<id>\d+)/logs/?$`)
 	workerEventsQueueURL = regexp.MustCompile(`^/workers/(?P<id>\d+)/queue/?$`)
@@ -149,7 +149,8 @@ func (s *Server) clusters(w http.ResponseWriter, req *http.Request) {
 	)
 
 	if matches := util.FindNamedStringSubmatch(clusterStatusURL, req.URL.Path); matches != nil {
-		resp, err = s.controller.ClusterStatus(matches["team"], matches["cluster"])
+		namespace, _ := matches["namespace"]
+		resp, err = s.controller.ClusterStatus(matches["team"], namespace, matches["cluster"])
 	} else if matches := util.FindNamedStringSubmatch(teamURL, req.URL.Path); matches != nil {
 		teamClusters := s.controller.TeamClusterList()
 		clusters, found := teamClusters[matches["team"]]
@@ -166,9 +167,11 @@ func (s *Server) clusters(w http.ResponseWriter, req *http.Request) {
 		s.respond(clusterNames, nil, w)
 		return
 	} else if matches := util.FindNamedStringSubmatch(clusterLogsURL, req.URL.Path); matches != nil {
-		resp, err = s.controller.ClusterLogs(matches["team"], matches["cluster"])
+		namespace, _ := matches["namespace"]
+		resp, err = s.controller.ClusterLogs(matches["team"], namespace, matches["cluster"])
 	} else if matches := util.FindNamedStringSubmatch(clusterHistoryURL, req.URL.Path); matches != nil {
-		resp, err = s.controller.ClusterHistory(matches["team"], matches["cluster"])
+		namespace, _ := matches["namespace"]
+		resp, err = s.controller.ClusterHistory(matches["team"], namespace, matches["cluster"])
 	} else if req.URL.Path == clustersURL {
 		res := make(map[string][]string)
 		for team, clusters := range s.controller.TeamClusterList() {
diff --git a/pkg/cluster/cluster.go b/pkg/cluster/cluster.go
index 3ed4c156..00633789 100644
--- a/pkg/cluster/cluster.go
+++ b/pkg/cluster/cluster.go
@@ -127,6 +127,10 @@ func (c *Cluster) clusterName() spec.NamespacedName {
 	return util.NameFromMeta(c.ObjectMeta)
 }
 
+func (c *Cluster) clusterNamespace() string {
+	return c.ObjectMeta.Namespace
+}
+
 func (c *Cluster) teamName() string {
 	// TODO: check Teams API for the actual name (in case the user passes an integer Id).
 	return c.Spec.TeamID
diff --git a/pkg/cluster/resources.go b/pkg/cluster/resources.go
index 37b342b4..16d27b14 100644
--- a/pkg/cluster/resources.go
+++ b/pkg/cluster/resources.go
@@ -110,7 +110,7 @@ func (c *Cluster) preScaleDown(newStatefulSet *v1beta1.StatefulSet) error {
 	}
 
 	podName := fmt.Sprintf("%s-0", c.Statefulset.Name)
-	masterCandidatePod, err := c.KubeClient.Pods(c.OpConfig.Namespace).Get(podName, metav1.GetOptions{})
+	masterCandidatePod, err := c.KubeClient.Pods(c.clusterNamespace()).Get(podName, metav1.GetOptions{})
 	if err != nil {
 		return fmt.Errorf("could not get master candidate pod: %v", err)
 	}
diff --git a/pkg/controller/node.go b/pkg/controller/node.go
index 98e8f288..efa1ca5c 100644
--- a/pkg/controller/node.go
+++ b/pkg/controller/node.go
@@ -80,7 +80,7 @@ func (c *Controller) moveMasterPodsOffNode(node *v1.Node) {
 	opts := metav1.ListOptions{
 		LabelSelector: labels.Set(c.opConfig.ClusterLabels).String(),
 	}
-	podList, err := c.KubeClient.Pods(c.opConfig.Namespace).List(opts)
+	podList, err := c.KubeClient.Pods("").List(opts)
 	if err != nil {
 		c.logger.Errorf("could not fetch list of the pods: %v", err)
 		return
diff --git a/pkg/controller/pod.go b/pkg/controller/pod.go
index 24b9f868..35b23cc5 100644
--- a/pkg/controller/pod.go
+++ b/pkg/controller/pod.go
@@ -17,7 +17,7 @@ func (c *Controller) podListFunc(options metav1.ListOptions) (runtime.Object, er
 		TimeoutSeconds:  options.TimeoutSeconds,
 	}
 
-	return c.KubeClient.Pods(c.opConfig.Namespace).List(opts)
+	return c.KubeClient.Pods("").List(opts)
 }
 
 func (c *Controller) podWatchFunc(options metav1.ListOptions) (watch.Interface, error) {
@@ -27,7 +27,7 @@ func (c *Controller) podWatchFunc(options metav1.ListOptions) (watch.Interface,
 		TimeoutSeconds:  options.TimeoutSeconds,
 	}
 
-	return c.KubeClient.Pods(c.opConfig.Namespace).Watch(opts)
+	return c.KubeClient.Pods("").Watch(opts)
 }
 
 func (c *Controller) dispatchPodEvent(clusterName spec.NamespacedName, event spec.PodEvent) {
diff --git a/pkg/controller/postgresql.go b/pkg/controller/postgresql.go
index 96b2052b..104ea6db 100644
--- a/pkg/controller/postgresql.go
+++ b/pkg/controller/postgresql.go
@@ -46,7 +46,6 @@ func (c *Controller) clusterListFunc(options metav1.ListOptions) (runtime.Object
 
 	req := c.KubeClient.CRDREST.
 		Get().
-		Namespace(c.opConfig.Namespace).
 		Resource(constants.CRDResource).
 		VersionedParams(&options, metav1.ParameterCodec)
 
@@ -110,7 +109,6 @@ func (c *Controller) clusterWatchFunc(options metav1.ListOptions) (watch.Interfa
 	options.Watch = true
 	r, err := c.KubeClient.CRDREST.
 		Get().
-		Namespace(c.opConfig.Namespace).
 		Resource(constants.CRDResource).
 		VersionedParams(&options, metav1.ParameterCodec).
 		FieldsSelectorParam(nil).
diff --git a/pkg/controller/status.go b/pkg/controller/status.go
index bc9480e3..0d1faf3a 100644
--- a/pkg/controller/status.go
+++ b/pkg/controller/status.go
@@ -14,9 +14,12 @@ import (
 )
 
 // ClusterStatus provides status of the cluster
-func (c *Controller) ClusterStatus(team, cluster string) (*spec.ClusterStatus, error) {
+func (c *Controller) ClusterStatus(team, namespace, cluster string) (*spec.ClusterStatus, error) {
+	if namespace == "" {
+		namespace = c.opConfig.Namespace
+	}
 	clusterName := spec.NamespacedName{
-		Namespace: c.opConfig.Namespace,
+		Namespace: namespace,
 		Name:      team + "-" + cluster,
 	}
 
@@ -90,9 +93,12 @@ func (c *Controller) GetStatus() *spec.ControllerStatus {
 }
 
 // ClusterLogs dumps cluster ring logs
-func (c *Controller) ClusterLogs(team, name string) ([]*spec.LogEntry, error) {
+func (c *Controller) ClusterLogs(team, namespace, name string) ([]*spec.LogEntry, error) {
+	if namespace == "" {
+		namespace = c.opConfig.Namespace
+	}
 	clusterName := spec.NamespacedName{
-		Namespace: c.opConfig.Namespace,
+		Namespace: namespace,
 		Name:      team + "-" + name,
 	}
 
@@ -212,9 +218,12 @@ func (c *Controller) WorkerStatus(workerID uint32) (*spec.WorkerStatus, error) {
 }
 
 // ClusterHistory dumps history of cluster changes
-func (c *Controller) ClusterHistory(team, name string) ([]*spec.Diff, error) {
+func (c *Controller) ClusterHistory(team, namespace, name string) ([]*spec.Diff, error) {
+	if namespace == "" {
+		namespace = c.opConfig.Namespace
+	}
 	clusterName := spec.NamespacedName{
-		Namespace: c.opConfig.Namespace,
+		Namespace: namespace,
 		Name:      team + "-" + name,
 	}
 
-- 
GitLab