DodoApp: Support remote clusters

Change-Id: I6f4e6a0a32cc723b47c96518d83b1ffdb5169f14
diff --git a/core/installer/welcome/appmanager.go b/core/installer/welcome/appmanager.go
index 3016190..808bf7e 100644
--- a/core/installer/welcome/appmanager.go
+++ b/core/installer/welcome/appmanager.go
@@ -137,6 +137,9 @@
 	r := mux.NewRouter()
 	r.PathPrefix("/stat/").Handler(cachingHandler{http.FileServer(http.FS(statAssets))})
 	r.HandleFunc("/api/networks", s.handleNetworks).Methods(http.MethodGet)
+	r.HandleFunc("/api/clusters", s.handleClusters).Methods(http.MethodGet)
+	r.HandleFunc("/api/proxy/add", s.handleProxyAdd).Methods(http.MethodPost)
+	r.HandleFunc("/api/proxy/remove", s.handleProxyRemove).Methods(http.MethodPost)
 	r.HandleFunc("/api/app-repo", s.handleAppRepo)
 	r.HandleFunc("/api/app/{slug}/install", s.handleAppInstall).Methods(http.MethodPost)
 	r.HandleFunc("/api/app/{slug}", s.handleApp).Methods(http.MethodGet)
@@ -158,14 +161,6 @@
 	return http.ListenAndServe(fmt.Sprintf(":%d", s.port), r)
 }
 
-type app struct {
-	Name             string                        `json:"name"`
-	Icon             template.HTML                 `json:"icon"`
-	ShortDescription string                        `json:"shortDescription"`
-	Slug             string                        `json:"slug"`
-	Instances        []installer.AppInstanceConfig `json:"instances,omitempty"`
-}
-
 func (s *AppManagerServer) handleNetworks(w http.ResponseWriter, r *http.Request) {
 	env, err := s.m.Config()
 	if err != nil {
@@ -183,6 +178,55 @@
 	}
 }
 
+func (s *AppManagerServer) handleClusters(w http.ResponseWriter, r *http.Request) {
+	clusters, err := s.m.GetClusters()
+	if err != nil {
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
+	}
+	if err := json.NewEncoder(w).Encode(installer.ToAccessConfigs(clusters)); err != nil {
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
+	}
+}
+
+type proxyPair struct {
+	From string `json:"from"`
+	To   string `json:"to"`
+}
+
+func (s *AppManagerServer) handleProxyAdd(w http.ResponseWriter, r *http.Request) {
+	var req proxyPair
+	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
+		http.Error(w, err.Error(), http.StatusBadRequest)
+		return
+	}
+	if err := s.cnc.AddProxy(req.From, req.To); err != nil {
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
+	}
+}
+
+func (s *AppManagerServer) handleProxyRemove(w http.ResponseWriter, r *http.Request) {
+	var req proxyPair
+	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
+		http.Error(w, err.Error(), http.StatusBadRequest)
+		return
+	}
+	if err := s.cnc.RemoveProxy(req.From, req.To); err != nil {
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
+	}
+}
+
+type app struct {
+	Name             string                        `json:"name"`
+	Icon             template.HTML                 `json:"icon"`
+	ShortDescription string                        `json:"shortDescription"`
+	Slug             string                        `json:"slug"`
+	Instances        []installer.AppInstanceConfig `json:"instances,omitempty"`
+}
+
 func (s *AppManagerServer) handleAppRepo(w http.ResponseWriter, r *http.Request) {
 	all, err := s.r.GetAll()
 	if err != nil {
diff --git a/core/installer/welcome/dodo_app.go b/core/installer/welcome/dodo_app.go
index 9a93afd..4307866 100644
--- a/core/installer/welcome/dodo_app.go
+++ b/core/installer/welcome/dodo_app.go
@@ -748,6 +748,11 @@
 		if err != nil {
 			return
 		}
+		// TODO(gio): get only available ones by owner
+		clusters, err := s.getClusters()
+		if err != nil {
+			return
+		}
 		apps := installer.NewInMemoryAppRepository(installer.CreateAllApps())
 		instanceAppStatus, err := installer.FindEnvApp(apps, "dodo-app-instance-status")
 		if err != nil {
@@ -768,7 +773,7 @@
 		}
 		s.l.Lock()
 		defer s.l.Unlock()
-		resources, err := s.updateDodoApp(instanceAppStatus, req.Repository.Name, branch, s.getAppConfig(req.Repository.Name, branch).Namespace, networks, owner)
+		resources, err := s.updateDodoApp(instanceAppStatus, req.Repository.Name, branch, s.getAppConfig(req.Repository.Name, branch).Namespace, networks, clusters, owner)
 		if err = s.createCommit(req.Repository.Name, branch, req.After, commitMsg, err, resources); err != nil {
 			fmt.Printf("Error: %s\n", err.Error())
 			return
@@ -1046,6 +1051,11 @@
 	if err != nil {
 		return err
 	}
+	// TODO(gio): get only available ones by owner
+	clusters, err := s.getClusters()
+	if err != nil {
+		return err
+	}
 	apps := installer.NewInMemoryAppRepository(installer.CreateAllApps())
 	instanceApp, err := installer.FindEnvApp(apps, "dodo-app-instance")
 	if err != nil {
@@ -1062,7 +1072,7 @@
 	}
 	namespace := fmt.Sprintf("%s%s%s", s.env.NamespacePrefix, instanceApp.Namespace(), suffix)
 	s.setAppConfig(appName, branch, appConfig{namespace, network})
-	resources, err := s.updateDodoApp(instanceAppStatus, appName, branch, namespace, networks, user)
+	resources, err := s.updateDodoApp(instanceAppStatus, appName, branch, namespace, networks, clusters, user)
 	if err != nil {
 		fmt.Printf("Error: %s\n", err.Error())
 		return err
@@ -1216,6 +1226,7 @@
 	branch string,
 	namespace string,
 	networks []installer.Network,
+	clusters []installer.Cluster,
 	owner string,
 ) (installer.ReleaseResources, error) {
 	repo, err := s.client.GetRepoBranch(name, branch)
@@ -1256,6 +1267,7 @@
 			installer.WithNoPublish(),
 			installer.WithConfig(&s.env),
 			installer.WithNetworks(networks),
+			installer.WithClusters(clusters),
 			installer.WithLocalChartGenerator(lg),
 			installer.WithNoLock(),
 		)
@@ -1280,6 +1292,7 @@
 			installer.WithNoPublish(),
 			installer.WithConfig(&s.env),
 			installer.WithNetworks(networks),
+			installer.WithClusters(clusters),
 			installer.WithLocalChartGenerator(lg),
 			installer.WithNoLock(),
 		); err != nil {
@@ -1323,6 +1336,20 @@
 	return s.nf.Filter(user, networks)
 }
 
+func (s *DodoAppServer) getClusters() ([]installer.Cluster, error) {
+	addr := fmt.Sprintf("%s/api/clusters", s.envAppManagerAddr)
+	resp, err := http.Get(addr)
+	if err != nil {
+		return nil, err
+	}
+	clusters := []installer.Cluster{}
+	if json.NewDecoder(resp.Body).Decode(&clusters); err != nil {
+		return nil, err
+	}
+	fmt.Printf("CLUSTERS %+v\n", clusters)
+	return clusters, nil
+}
+
 type publicNetworkData struct {
 	Name   string `json:"name"`
 	Domain string `json:"domain"`