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.
This commit is contained in:
Oleksii Kliukin 2018-01-09 18:36:42 +01:00
parent 23011bdf9a
commit aa517d13b4
7 changed files with 35 additions and 21 deletions

View File

@ -30,9 +30,9 @@ type controllerInformer interface {
GetOperatorConfig() *config.Config GetOperatorConfig() *config.Config
GetStatus() *spec.ControllerStatus GetStatus() *spec.ControllerStatus
TeamClusterList() map[string][]spec.NamespacedName TeamClusterList() map[string][]spec.NamespacedName
ClusterStatus(team, cluster string) (*spec.ClusterStatus, error) ClusterStatus(team, namespace, cluster string) (*spec.ClusterStatus, error)
ClusterLogs(team, cluster string) ([]*spec.LogEntry, error) ClusterLogs(team, namespace, cluster string) ([]*spec.LogEntry, error)
ClusterHistory(team, cluster string) ([]*spec.Diff, error) ClusterHistory(team, namespace, cluster string) ([]*spec.Diff, error)
ClusterDatabasesMap() map[string][]string ClusterDatabasesMap() map[string][]string
WorkerLogs(workerID uint32) ([]*spec.LogEntry, error) WorkerLogs(workerID uint32) ([]*spec.LogEntry, error)
ListQueue(workerID uint32) (*spec.QueueDump, error) ListQueue(workerID uint32) (*spec.QueueDump, error)
@ -48,9 +48,9 @@ type Server struct {
} }
var ( var (
clusterStatusURL = regexp.MustCompile(`^/clusters/(?P<team>[a-zA-Z][a-zA-Z0-9]*)/(?P<cluster>[a-zA-Z][a-zA-Z0-9-]*)/?$`) 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<cluster>[a-zA-Z][a-zA-Z0-9-]*)/logs/?$`) 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<cluster>[a-zA-Z][a-zA-Z0-9-]*)/history/?$`) 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]*)/?$`) teamURL = regexp.MustCompile(`^/clusters/(?P<team>[a-zA-Z][a-zA-Z0-9]*)/?$`)
workerLogsURL = regexp.MustCompile(`^/workers/(?P<id>\d+)/logs/?$`) workerLogsURL = regexp.MustCompile(`^/workers/(?P<id>\d+)/logs/?$`)
workerEventsQueueURL = regexp.MustCompile(`^/workers/(?P<id>\d+)/queue/?$`) 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 { 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 { } else if matches := util.FindNamedStringSubmatch(teamURL, req.URL.Path); matches != nil {
teamClusters := s.controller.TeamClusterList() teamClusters := s.controller.TeamClusterList()
clusters, found := teamClusters[matches["team"]] clusters, found := teamClusters[matches["team"]]
@ -166,9 +167,11 @@ func (s *Server) clusters(w http.ResponseWriter, req *http.Request) {
s.respond(clusterNames, nil, w) s.respond(clusterNames, nil, w)
return return
} else if matches := util.FindNamedStringSubmatch(clusterLogsURL, req.URL.Path); matches != nil { } 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 { } 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 { } else if req.URL.Path == clustersURL {
res := make(map[string][]string) res := make(map[string][]string)
for team, clusters := range s.controller.TeamClusterList() { for team, clusters := range s.controller.TeamClusterList() {

View File

@ -127,6 +127,10 @@ func (c *Cluster) clusterName() spec.NamespacedName {
return util.NameFromMeta(c.ObjectMeta) return util.NameFromMeta(c.ObjectMeta)
} }
func (c *Cluster) clusterNamespace() string {
return c.ObjectMeta.Namespace
}
func (c *Cluster) teamName() string { func (c *Cluster) teamName() string {
// TODO: check Teams API for the actual name (in case the user passes an integer Id). // TODO: check Teams API for the actual name (in case the user passes an integer Id).
return c.Spec.TeamID return c.Spec.TeamID

View File

@ -110,7 +110,7 @@ func (c *Cluster) preScaleDown(newStatefulSet *v1beta1.StatefulSet) error {
} }
podName := fmt.Sprintf("%s-0", c.Statefulset.Name) 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 { if err != nil {
return fmt.Errorf("could not get master candidate pod: %v", err) return fmt.Errorf("could not get master candidate pod: %v", err)
} }

View File

@ -80,7 +80,7 @@ func (c *Controller) moveMasterPodsOffNode(node *v1.Node) {
opts := metav1.ListOptions{ opts := metav1.ListOptions{
LabelSelector: labels.Set(c.opConfig.ClusterLabels).String(), 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 { if err != nil {
c.logger.Errorf("could not fetch list of the pods: %v", err) c.logger.Errorf("could not fetch list of the pods: %v", err)
return return

View File

@ -17,7 +17,7 @@ func (c *Controller) podListFunc(options metav1.ListOptions) (runtime.Object, er
TimeoutSeconds: options.TimeoutSeconds, 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) { 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, 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) { func (c *Controller) dispatchPodEvent(clusterName spec.NamespacedName, event spec.PodEvent) {

View File

@ -46,7 +46,6 @@ func (c *Controller) clusterListFunc(options metav1.ListOptions) (runtime.Object
req := c.KubeClient.CRDREST. req := c.KubeClient.CRDREST.
Get(). Get().
Namespace(c.opConfig.Namespace).
Resource(constants.CRDResource). Resource(constants.CRDResource).
VersionedParams(&options, metav1.ParameterCodec) VersionedParams(&options, metav1.ParameterCodec)
@ -110,7 +109,6 @@ func (c *Controller) clusterWatchFunc(options metav1.ListOptions) (watch.Interfa
options.Watch = true options.Watch = true
r, err := c.KubeClient.CRDREST. r, err := c.KubeClient.CRDREST.
Get(). Get().
Namespace(c.opConfig.Namespace).
Resource(constants.CRDResource). Resource(constants.CRDResource).
VersionedParams(&options, metav1.ParameterCodec). VersionedParams(&options, metav1.ParameterCodec).
FieldsSelectorParam(nil). FieldsSelectorParam(nil).

View File

@ -14,9 +14,12 @@ import (
) )
// ClusterStatus provides status of the cluster // 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{ clusterName := spec.NamespacedName{
Namespace: c.opConfig.Namespace, Namespace: namespace,
Name: team + "-" + cluster, Name: team + "-" + cluster,
} }
@ -90,9 +93,12 @@ func (c *Controller) GetStatus() *spec.ControllerStatus {
} }
// ClusterLogs dumps cluster ring logs // 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{ clusterName := spec.NamespacedName{
Namespace: c.opConfig.Namespace, Namespace: namespace,
Name: team + "-" + name, Name: team + "-" + name,
} }
@ -212,9 +218,12 @@ func (c *Controller) WorkerStatus(workerID uint32) (*spec.WorkerStatus, error) {
} }
// ClusterHistory dumps history of cluster changes // 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{ clusterName := spec.NamespacedName{
Namespace: c.opConfig.Namespace, Namespace: namespace,
Name: team + "-" + name, Name: team + "-" + name,
} }