From 6f28852e1bb25b56780f5ece9544a37a93444db9 Mon Sep 17 00:00:00 2001
From: Milos Gajdos <milosgajdos83@gmail.com>
Date: Thu, 7 Nov 2019 07:44:57 +0000
Subject: [PATCH] K8s list deployments (#921)

* Outline of ListDeployments method

* Added implementation of DeploymentList
---
 runtime/kubernetes/client/api/request.go |  2 +-
 runtime/kubernetes/client/client.go      | 15 +++++++-
 runtime/kubernetes/client/kubernetes.go  | 21 ++++++++++
 runtime/kubernetes/kubernetes.go         | 49 ++++++++++++++++++------
 4 files changed, 73 insertions(+), 14 deletions(-)

diff --git a/runtime/kubernetes/client/api/request.go b/runtime/kubernetes/client/api/request.go
index b40ed72a..20158806 100644
--- a/runtime/kubernetes/client/api/request.go
+++ b/runtime/kubernetes/client/api/request.go
@@ -103,7 +103,7 @@ func (r *Request) Body(in interface{}) *Request {
 // Params isused to set paramters on a request
 func (r *Request) Params(p *Params) *Request {
 	for k, v := range p.LabelSelector {
-		r.params.Add("labelSelectors", k+"="+v)
+		r.params.Add("labelSelector", k+"="+v)
 	}
 
 	return r
diff --git a/runtime/kubernetes/client/client.go b/runtime/kubernetes/client/client.go
index 695ecd65..d201604e 100644
--- a/runtime/kubernetes/client/client.go
+++ b/runtime/kubernetes/client/client.go
@@ -90,7 +90,7 @@ func detectNamespace() (string, error) {
 	}
 }
 
-// UpdateDeployment
+// UpdateDeployment patches kubernetes deployment with metadata provided in body
 func (c *client) UpdateDeployment(name string, body interface{}) error {
 	return api.NewRequest(c.opts).
 		Patch().
@@ -100,3 +100,16 @@ func (c *client) UpdateDeployment(name string, body interface{}) error {
 		Do().
 		Error()
 }
+
+// ListDeployments lists all kubernetes deployments with given labels
+func (c *client) ListDeployments(labels map[string]string) (*DeploymentList, error) {
+	var deployments DeploymentList
+	err := api.NewRequest(c.opts).
+		Get().
+		Resource("deployments").
+		Params(&api.Params{LabelSelector: labels}).
+		Do().
+		Into(&deployments)
+
+	return &deployments, err
+}
diff --git a/runtime/kubernetes/client/kubernetes.go b/runtime/kubernetes/client/kubernetes.go
index 565d2243..82a626f2 100644
--- a/runtime/kubernetes/client/kubernetes.go
+++ b/runtime/kubernetes/client/kubernetes.go
@@ -4,9 +4,30 @@ package client
 type Kubernetes interface {
 	// UpdateDeployment patches deployment annotations with new metadata
 	UpdateDeployment(string, interface{}) error
+	// ListDeployments lists all micro deployments
+	ListDeployments(labels map[string]string) (*DeploymentList, error)
 }
 
 // Metadata defines api request metadata
 type Metadata struct {
+	Name        string            `json:"name,omitempty"`
+	Labels      map[string]string `json:"labels,omitempty"`
 	Annotations map[string]string `json:"annotations,omitempty"`
 }
+
+// DeploymentList
+type DeploymentList struct {
+	Items []Deployment `json:"items"`
+}
+
+// Deployment is Kubernetes deployment
+type Deployment struct {
+	Metadata *Metadata `json:"metadata"`
+	Status   *Status   `json:"status"`
+}
+
+// Status is Kubernetes deployment status
+type Status struct {
+	Replicas          int `json:"replicas"`
+	AvailableReplicas int `json:"availablereplicas"`
+}
diff --git a/runtime/kubernetes/kubernetes.go b/runtime/kubernetes/kubernetes.go
index 15f0fcb1..99cc9437 100644
--- a/runtime/kubernetes/kubernetes.go
+++ b/runtime/kubernetes/kubernetes.go
@@ -137,14 +137,31 @@ func (k *kubernetes) Update(s *runtime.Service) error {
 
 // List the managed services
 func (k *kubernetes) List() ([]*runtime.Service, error) {
-	// TODO: this should list the k8s deployments
-	// but for now we return in-memory tracked services
-	services := make([]*runtime.Service, 0, len(k.services))
-	k.RLock()
-	defer k.RUnlock()
+	labels := map[string]string{
+		"micro": "service",
+	}
+	// list all micro core deployments
+	deployments, err := k.client.ListDeployments(labels)
+	if err != nil {
+		return nil, err
+	}
 
-	for _, service := range k.services {
-		services = append(services, service)
+	log.Debugf("Runtime found %d micro deployments with labels %v", len(deployments.Items), labels)
+
+	services := make([]*runtime.Service, 0, len(deployments.Items))
+
+	for _, service := range deployments.Items {
+		buildTime, err := time.Parse(time.RFC3339, service.Metadata.Annotations["build"])
+		if err != nil {
+			log.Debugf("Runtime error parsing build time: %v", err)
+			continue
+		}
+		// add the service to the list of services
+		svc := &runtime.Service{
+			Name:    service.Metadata.Name,
+			Version: fmt.Sprintf("%d", buildTime.Unix()),
+		}
+		services = append(services, svc)
 	}
 
 	return services, nil
@@ -152,18 +169,26 @@ func (k *kubernetes) List() ([]*runtime.Service, error) {
 
 // run runs the runtime management loop
 func (k *kubernetes) run(events <-chan runtime.Event) {
-	t := time.NewTicker(time.Second * 5)
+	t := time.NewTicker(time.Second * 10)
 	defer t.Stop()
 
 	for {
 		select {
 		case <-t.C:
-			// TODO: noop for now
 			// check running services
-			// * deployments exist
-			// * service is exposed
+			services, err := k.List()
+			if err != nil {
+				log.Debugf("Runtime failed listing running services: %v", err)
+				continue
+			}
+			// TODO: for now we just log the running services
+			// * make sure all core deployments exist
+			// * make sure all core services are exposed
+			for _, service := range services {
+				log.Debugf("Runtime found running service: %v", service)
+			}
 		case service := <-k.start:
-			// TODO: following might have to be done
+			// TODO: this is a noop for now
 			// * create a deployment
 			// * expose a service
 			log.Debugf("Runtime starting service: %s", service.Name)