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/app.go b/core/installer/app.go
index 538e2ff..f8e6d6f 100644
--- a/core/installer/app.go
+++ b/core/installer/app.go
@@ -482,7 +482,6 @@
if vv, ok := v[k]; ok && vv != nil {
if mv, ok := val.(map[string]any); ok {
// TODO(gio): check that it is actually map
- fmt.Println(vv)
ret[k] = merge(mv, vv.(map[string]any))
} else {
ret[k] = vv
diff --git a/core/installer/app_manager.go b/core/installer/app_manager.go
index d95e640..e6133c1 100644
--- a/core/installer/app_manager.go
+++ b/core/installer/app_manager.go
@@ -136,7 +136,7 @@
return &cfg, err
}
-func GetCueAppData(fs soft.RepoFS, dir string) (CueAppData, error) {
+func GetCueAppData(fs soft.RepoFS, dir string, overrides CueAppData) (CueAppData, error) {
files, err := fs.ListDir(dir)
if err != nil {
return nil, err
@@ -151,11 +151,14 @@
cfg[f.Name()] = contents
}
}
+ for k, v := range overrides {
+ cfg[k] = v
+ }
return cfg, nil
}
-func (m *AppManager) GetInstanceApp(id string) (EnvApp, error) {
- cfg, err := GetCueAppData(m.repo, filepath.Join(m.appDirRoot, id))
+func (m *AppManager) GetInstanceApp(id string, overrides CueAppData) (EnvApp, error) {
+ cfg, err := GetCueAppData(m.repo, filepath.Join(m.appDirRoot, id), overrides)
if err != nil {
return nil, err
}
@@ -615,6 +618,8 @@
func (m *AppManager) Update(
instanceId string,
values map[string]any,
+ // TODO(gio): this should not be cue specific
+ overrides CueAppData,
opts ...InstallOption,
) (ReleaseResources, error) {
m.l.Lock()
@@ -627,7 +632,7 @@
return ReleaseResources{}, err
}
instanceDir := filepath.Join(m.appDirRoot, instanceId)
- app, err := m.GetInstanceApp(instanceId)
+ app, err := m.GetInstanceApp(instanceId, overrides)
if err != nil {
return ReleaseResources{}, err
}
@@ -648,7 +653,7 @@
if err != nil {
return ReleaseResources{}, err
}
- rendered, err := app.Render(config.Release, env, networks, ToAccessConfigs(clusters), values, renderedCfg.LocalCharts, m.vpnAPIClient)
+ rendered, err := app.Render(config.Release, env, networks, ToAccessConfigs(clusters), merge(config.Input, values), renderedCfg.LocalCharts, m.vpnAPIClient)
if err != nil {
return ReleaseResources{}, err
}
@@ -1035,7 +1040,7 @@
return ReleaseResources{}, err
}
instanceDir := filepath.Join("/infrastructure", instanceId)
- appCfg, err := GetCueAppData(m.repoIO, instanceDir)
+ appCfg, err := GetCueAppData(m.repoIO, instanceDir, nil)
if err != nil {
return ReleaseResources{}, err
}
diff --git a/core/installer/samples/blog.rest b/core/installer/samples/blog.rest
index 0a8606d..2a0b95c 100644
--- a/core/installer/samples/blog.rest
+++ b/core/installer/samples/blog.rest
@@ -1,4 +1,4 @@
-POST http://appmanager.hgrz-appmanager.svc.cluster.local/api/dodo-app
+PUT http://appmanager.hgrz-appmanager.svc.cluster.local/api/dodo-app/dodo-app-snd
Content-Type: application/json
{
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