AppManager: Let client override config files during update

Take old input and merge with the new one.

Change-Id: I2d8ad0e5f0cef97a3efa23aa9ca0c7f9163e703b
diff --git a/core/installer/server/appmanager/server.go b/core/installer/server/appmanager/server.go
index 7621213..cb372f3 100644
--- a/core/installer/server/appmanager/server.go
+++ b/core/installer/server/appmanager/server.go
@@ -142,6 +142,7 @@
 	r.HandleFunc("/api/instance/{slug}", s.handleInstance).Methods(http.MethodGet)
 	r.HandleFunc("/api/instance/{slug}/update", s.handleAppUpdate).Methods(http.MethodPost)
 	r.HandleFunc("/api/instance/{slug}/remove", s.handleAppRemove).Methods(http.MethodPost)
+	r.HandleFunc("/api/dodo-app/{instanceId}", s.handleDodoAppUpdate).Methods(http.MethodPut)
 	r.HandleFunc("/api/dodo-app", s.handleDodoAppInstall).Methods(http.MethodPost)
 	r.HandleFunc("/clusters/{cluster}/servers/{server}/remove", s.handleClusterRemoveServer).Methods(http.MethodPost)
 	r.HandleFunc("/clusters/{cluster}/servers", s.handleClusterAddServer).Methods(http.MethodPost)
@@ -216,6 +217,37 @@
 	}
 }
 
+func (s *Server) handleDodoAppUpdate(w http.ResponseWriter, r *http.Request) {
+	instanceId, ok := mux.Vars(r)["instanceId"]
+	if !ok {
+		http.Error(w, "missing instance id", http.StatusBadRequest)
+	}
+	var req dodoAppInstallReq
+	// TODO(gio): validate that no internal fields are overridden by request
+	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
+		http.Error(w, err.Error(), http.StatusBadRequest)
+		return
+	}
+	clusters, err := s.m.GetClusters()
+	if err != nil {
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
+	}
+	req.Config["clusters"] = installer.ToAccessConfigs(clusters)
+	var cfg bytes.Buffer
+	if err := json.NewEncoder(&cfg).Encode(req.Config); err != nil {
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
+	}
+	overrides := installer.CueAppData{
+		"app.cue": cfg.Bytes(),
+	}
+	// TODO(gio): return monitoring info
+	if _, err := s.m.Update(instanceId, nil, overrides); err != nil {
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+	}
+}
+
 func (s *Server) handleNetworks(w http.ResponseWriter, r *http.Request) {
 	env, err := s.m.Config()
 	if err != nil {
@@ -424,7 +456,7 @@
 		}
 		tid = t.id + 1
 	}
-	rr, err := s.m.Update(slug, values)
+	rr, err := s.m.Update(slug, values, nil)
 	if err != nil {
 		http.Error(w, err.Error(), http.StatusInternalServerError)
 		return
@@ -583,7 +615,7 @@
 		http.Error(w, err.Error(), http.StatusInternalServerError)
 		return
 	}
-	a, err := s.m.GetInstanceApp(instance.Id)
+	a, err := s.m.GetInstanceApp(instance.Id, nil)
 	if err != nil {
 		http.Error(w, err.Error(), http.StatusInternalServerError)
 		return