AppManager: Recursively monitor dodo resources

Change-Id: I23f3014e416f5b68f8909dbfbcba27db66eaee3f
diff --git a/core/installer/server/appmanager/server.go b/core/installer/server/appmanager/server.go
index 80f076a..e0aeab2 100644
--- a/core/installer/server/appmanager/server.go
+++ b/core/installer/server/appmanager/server.go
@@ -39,21 +39,20 @@
 }
 
 type Server struct {
-	l             sync.Locker
-	port          int
-	ssClient      soft.Client
-	repo          soft.RepoIO
-	m             *installer.AppManager
-	r             installer.AppRepository
-	fr            installer.AppRepository
-	reconciler    *tasks.FixedReconciler
-	h             status.ResourceMonitor
-	im            *status.InstanceMonitor
-	cnc           installer.ClusterNetworkConfigurator
-	vpnAPIClient  installer.VPNAPIClient
-	tasks         map[string]*taskForward
-	tmpl          tmplts
-	idToResources map[string]map[string][]status.Resource
+	l            sync.Locker
+	port         int
+	ssClient     soft.Client
+	repo         soft.RepoIO
+	m            *installer.AppManager
+	r            installer.AppRepository
+	fr           installer.AppRepository
+	reconciler   *tasks.FixedReconciler
+	h            status.ResourceMonitor
+	im           *status.InstanceMonitor
+	cnc          installer.ClusterNetworkConfigurator
+	vpnAPIClient installer.VPNAPIClient
+	tasks        map[string]*taskForward
+	tmpl         tmplts
 }
 
 type tmplts struct {
@@ -117,21 +116,20 @@
 		return nil, err
 	}
 	return &Server{
-		l:             &sync.Mutex{},
-		port:          port,
-		ssClient:      ssClient,
-		repo:          repo,
-		m:             m,
-		r:             r,
-		fr:            fr,
-		reconciler:    reconciler,
-		h:             h,
-		im:            im,
-		cnc:           cnc,
-		vpnAPIClient:  vpnAPIClient,
-		tasks:         make(map[string]*taskForward),
-		tmpl:          tmpl,
-		idToResources: make(map[string]map[string][]status.Resource),
+		l:            &sync.Mutex{},
+		port:         port,
+		ssClient:     ssClient,
+		repo:         repo,
+		m:            m,
+		r:            r,
+		fr:           fr,
+		reconciler:   reconciler,
+		h:            h,
+		im:           im,
+		cnc:          cnc,
+		vpnAPIClient: vpnAPIClient,
+		tasks:        make(map[string]*taskForward),
+		tmpl:         tmpl,
 	}, nil
 }
 
@@ -213,24 +211,12 @@
 		http.Error(w, err.Error(), http.StatusInternalServerError)
 		return
 	} else {
-		var toMonitor []status.Resource
-		s.idToResources[instanceId] = map[string][]status.Resource{}
-		for _, r := range rr.Helm {
-			resource := status.Resource{
-				Type: status.ResourceHelmRelease,
-				ResourceRef: status.ResourceRef{
-					Name:      r.Name,
-					Namespace: r.Namespace,
-				},
-			}
-			toMonitor = append(toMonitor, resource)
-			if tmp, ok := s.idToResources[instanceId][r.Id]; ok {
-				s.idToResources[instanceId][r.Id] = append(tmp, resource)
-			} else {
-				s.idToResources[instanceId][r.Id] = []status.Resource{resource}
-			}
+		outs, err := status.DecodeResourceOuts(rr.RenderedRaw)
+		if err != nil {
+			http.Error(w, err.Error(), http.StatusInternalServerError)
+			return
 		}
-		s.im.Monitor(instanceId, toMonitor)
+		s.im.Monitor(instanceId, outs)
 		var cfg dodoAppRendered
 		if err := json.NewDecoder(bytes.NewReader(rr.RenderedRaw)).Decode(&cfg); err != nil {
 			http.Error(w, err.Error(), http.StatusInternalServerError)
@@ -278,25 +264,14 @@
 	rr, err := s.m.Update(instanceId, nil, overrides)
 	if err != nil {
 		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
 	}
-	var toMonitor []status.Resource
-	s.idToResources[instanceId] = map[string][]status.Resource{}
-	for _, r := range rr.Helm {
-		resource := status.Resource{
-			Type: status.ResourceHelmRelease,
-			ResourceRef: status.ResourceRef{
-				Name:      r.Name,
-				Namespace: r.Namespace,
-			},
-		}
-		toMonitor = append(toMonitor, resource)
-		if tmp, ok := s.idToResources[instanceId][r.Id]; ok {
-			s.idToResources[instanceId][r.Id] = append(tmp, resource)
-		} else {
-			s.idToResources[instanceId][r.Id] = []status.Resource{resource}
-		}
+	outs, err := status.DecodeResourceOuts(rr.RenderedRaw)
+	if err != nil {
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
 	}
-	s.im.Monitor(instanceId, toMonitor)
+	s.im.Monitor(instanceId, outs)
 	t := tasks.NewInstallTask(s.h, func() (installer.ReleaseResources, error) {
 		if err == nil {
 			ctx, _ := context.WithTimeout(context.Background(), 5*time.Second)
@@ -767,68 +742,6 @@
 	return ret
 }
 
-type IdName struct {
-	Id   string
-	Name string
-}
-
-type IdNameMap map[string]IdName
-
-type resourceOuts struct {
-	Outs map[string]struct {
-		PostgreSQL IdNameMap `json:"postgresql"`
-		MongoDB    IdNameMap `json:"mongodb"`
-		Volume     IdNameMap `json:"volume"`
-		Ingress    IdNameMap `json:"ingress"`
-	} `json:"outs"`
-}
-
-type DodoResource struct {
-	Type string
-	Name string
-}
-
-type DodoResourceStatus struct {
-	Type   string `json:"type"`
-	Name   string `json:"name"`
-	Status string `json:"status"`
-}
-
-func orginize(raw []byte) (map[string]DodoResource, error) {
-	var outs resourceOuts
-	if err := json.NewDecoder(bytes.NewReader(raw)).Decode(&outs); err != nil {
-		return nil, err
-	}
-	ret := map[string]DodoResource{}
-	for _, out := range outs.Outs {
-		for _, r := range out.PostgreSQL {
-			ret[r.Id] = DodoResource{
-				Type: "postgresql",
-				Name: r.Name,
-			}
-		}
-		for _, r := range out.MongoDB {
-			ret[r.Id] = DodoResource{
-				Type: "mongodb",
-				Name: r.Name,
-			}
-		}
-		for _, r := range out.Volume {
-			ret[r.Id] = DodoResource{
-				Type: "volume",
-				Name: r.Name,
-			}
-		}
-		for _, r := range out.Ingress {
-			ret[r.Id] = DodoResource{
-				Type: "ingress",
-				Name: r.Name,
-			}
-		}
-	}
-	return ret, nil
-}
-
 func (s *Server) handleInstanceStatusAPI(w http.ResponseWriter, r *http.Request) {
 	s.l.Lock()
 	defer s.l.Unlock()
@@ -842,36 +755,15 @@
 		http.Error(w, err.Error(), http.StatusInternalServerError)
 		return
 	}
-	idStatus := map[string]status.Status{}
-	for id, resources := range s.idToResources[instanceId] {
-		st := status.StatusNoStatus
-		for _, resource := range resources {
-			if st < statuses[resource] {
-				st = statuses[resource]
-			}
-		}
-		idStatus[id] = st
-	}
-	s.repo.Pull()
-	rendered, err := s.m.AppRendered(instanceId)
-	if err != nil {
-		http.Error(w, err.Error(), http.StatusInternalServerError)
-		return
-	}
-	idToResource, err := orginize(rendered)
-	if err != nil {
-		http.Error(w, err.Error(), http.StatusInternalServerError)
-		return
-	}
-	resources := []DodoResourceStatus{}
-	for id, st := range idStatus {
-		resources = append(resources, DodoResourceStatus{
-			Type:   idToResource[id].Type,
-			Name:   idToResource[id].Name,
-			Status: status.StatusString(st),
+	ret := []resourceStatus{}
+	for r, s := range statuses {
+		ret = append(ret, resourceStatus{
+			Type:   r.Type,
+			Name:   r.Name,
+			Status: status.StatusString(s),
 		})
 	}
-	json.NewEncoder(w).Encode(resources)
+	json.NewEncoder(w).Encode(ret)
 }
 
 type clustersData struct {