blob: 7f168dcbed6b17c1ead407cb60a3cb675a6f5c36 [file] [log] [blame]
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +04001package welcome
2
3import (
Giorgi Lekveishvilid2f3dca2023-12-20 09:31:30 +04004 "context"
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +04005 "embed"
6 "encoding/json"
7 "fmt"
8 "html/template"
9 "io/ioutil"
10 "log"
11 "net/http"
Giorgi Lekveishvilid2f3dca2023-12-20 09:31:30 +040012 "time"
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +040013
14 "github.com/Masterminds/sprig/v3"
gioaa0fcdb2024-06-10 22:19:25 +040015 "github.com/gorilla/mux"
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +040016
17 "github.com/giolekva/pcloud/core/installer"
Giorgi Lekveishvilid2f3dca2023-12-20 09:31:30 +040018 "github.com/giolekva/pcloud/core/installer/tasks"
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +040019)
20
Davit Tabidze3ec24cf2024-05-22 14:06:02 +040021//go:embed appmanager-tmpl/*
22var appTmpls embed.FS
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +040023
24type AppManagerServer struct {
Giorgi Lekveishvilid2f3dca2023-12-20 09:31:30 +040025 port int
26 m *installer.AppManager
Giorgi Lekveishvili08af67a2024-01-18 08:53:05 +040027 r installer.AppRepository
gio43b0f422024-08-21 10:40:13 +040028 reconciler *tasks.FixedReconciler
gio778577f2024-04-29 09:44:38 +040029 h installer.HelmReleaseMonitor
30 tasks map[string]tasks.Task
gio1cd65152024-08-16 08:18:49 +040031 ta map[string]installer.EnvApp
Davit Tabidze3ec24cf2024-05-22 14:06:02 +040032 tmpl tmplts
33}
34
35type tmplts struct {
36 index *template.Template
37 app *template.Template
38}
39
40func parseTemplatesAppManager(fs embed.FS) (tmplts, error) {
41 base, err := template.New("base.html").Funcs(template.FuncMap(sprig.FuncMap())).ParseFS(fs, "appmanager-tmpl/base.html")
42 if err != nil {
43 return tmplts{}, err
44 }
45 parse := func(path string) (*template.Template, error) {
46 if b, err := base.Clone(); err != nil {
47 return nil, err
48 } else {
49 return b.ParseFS(fs, path)
50 }
51 }
52 index, err := parse("appmanager-tmpl/index.html")
53 if err != nil {
54 return tmplts{}, err
55 }
56 app, err := parse("appmanager-tmpl/app.html")
57 if err != nil {
58 return tmplts{}, err
59 }
60 return tmplts{index, app}, nil
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +040061}
62
63func NewAppManagerServer(
64 port int,
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +040065 m *installer.AppManager,
Giorgi Lekveishvili08af67a2024-01-18 08:53:05 +040066 r installer.AppRepository,
gio43b0f422024-08-21 10:40:13 +040067 reconciler *tasks.FixedReconciler,
gio778577f2024-04-29 09:44:38 +040068 h installer.HelmReleaseMonitor,
Davit Tabidze3ec24cf2024-05-22 14:06:02 +040069) (*AppManagerServer, error) {
70 tmpl, err := parseTemplatesAppManager(appTmpls)
71 if err != nil {
72 return nil, err
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +040073 }
Davit Tabidze3ec24cf2024-05-22 14:06:02 +040074 return &AppManagerServer{
75 port: port,
76 m: m,
77 r: r,
78 reconciler: reconciler,
79 h: h,
80 tasks: make(map[string]tasks.Task),
gio1cd65152024-08-16 08:18:49 +040081 ta: make(map[string]installer.EnvApp),
Davit Tabidze3ec24cf2024-05-22 14:06:02 +040082 tmpl: tmpl,
83 }, nil
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +040084}
85
gio09f8efa2024-06-10 22:35:24 +040086type cachingHandler struct {
87 h http.Handler
88}
89
90func (h cachingHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
91 w.Header().Set("Cache-Control", "max-age=604800")
92 h.h.ServeHTTP(w, r)
93}
94
Giorgi Lekveishvili743fb432023-11-08 17:19:40 +040095func (s *AppManagerServer) Start() error {
gioaa0fcdb2024-06-10 22:19:25 +040096 r := mux.NewRouter()
gio1bf00802024-08-17 12:31:41 +040097 r.PathPrefix("/stat/").Handler(cachingHandler{http.FileServer(http.FS(statAssets))})
giocb34ad22024-07-11 08:01:13 +040098 r.HandleFunc("/api/networks", s.handleNetworks).Methods(http.MethodGet)
gioaa0fcdb2024-06-10 22:19:25 +040099 r.HandleFunc("/api/app-repo", s.handleAppRepo)
100 r.HandleFunc("/api/app/{slug}/install", s.handleAppInstall).Methods(http.MethodPost)
101 r.HandleFunc("/api/app/{slug}", s.handleApp).Methods(http.MethodGet)
102 r.HandleFunc("/api/instance/{slug}", s.handleInstance).Methods(http.MethodGet)
103 r.HandleFunc("/api/instance/{slug}/update", s.handleAppUpdate).Methods(http.MethodPost)
104 r.HandleFunc("/api/instance/{slug}/remove", s.handleAppRemove).Methods(http.MethodPost)
gioaa0fcdb2024-06-10 22:19:25 +0400105 r.HandleFunc("/app/{slug}", s.handleAppUI).Methods(http.MethodGet)
106 r.HandleFunc("/instance/{slug}", s.handleInstanceUI).Methods(http.MethodGet)
Davit Tabidze780a0d02024-08-05 20:53:26 +0400107 r.HandleFunc("/{pageType}", s.handleAppsList).Methods(http.MethodGet)
108 r.HandleFunc("/", s.handleAppsList).Methods(http.MethodGet)
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400109 fmt.Printf("Starting HTTP server on port: %d\n", s.port)
gioaa0fcdb2024-06-10 22:19:25 +0400110 return http.ListenAndServe(fmt.Sprintf(":%d", s.port), r)
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400111}
112
113type app struct {
gio3cdee592024-04-17 10:15:56 +0400114 Name string `json:"name"`
115 Icon template.HTML `json:"icon"`
116 ShortDescription string `json:"shortDescription"`
117 Slug string `json:"slug"`
118 Instances []installer.AppInstanceConfig `json:"instances,omitempty"`
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400119}
120
giocb34ad22024-07-11 08:01:13 +0400121func (s *AppManagerServer) handleNetworks(w http.ResponseWriter, r *http.Request) {
122 env, err := s.m.Config()
123 if err != nil {
124 http.Error(w, err.Error(), http.StatusInternalServerError)
125 return
126 }
127 networks, err := s.m.CreateNetworks(env)
128 if err != nil {
129 http.Error(w, err.Error(), http.StatusInternalServerError)
130 return
131 }
132 if err := json.NewEncoder(w).Encode(networks); err != nil {
133 http.Error(w, err.Error(), http.StatusInternalServerError)
134 return
135 }
136}
137
gioaa0fcdb2024-06-10 22:19:25 +0400138func (s *AppManagerServer) handleAppRepo(w http.ResponseWriter, r *http.Request) {
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400139 all, err := s.r.GetAll()
140 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400141 http.Error(w, err.Error(), http.StatusInternalServerError)
142 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400143 }
144 resp := make([]app, len(all))
145 for i, a := range all {
gio44f621b2024-04-29 09:44:38 +0400146 resp[i] = app{a.Name(), a.Icon(), a.Description(), a.Slug(), nil}
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400147 }
gioaa0fcdb2024-06-10 22:19:25 +0400148 w.Header().Set("Content-Type", "application/json")
149 if err := json.NewEncoder(w).Encode(resp); err != nil {
150 http.Error(w, err.Error(), http.StatusInternalServerError)
151 return
152 }
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400153}
154
gioaa0fcdb2024-06-10 22:19:25 +0400155func (s *AppManagerServer) handleApp(w http.ResponseWriter, r *http.Request) {
156 slug, ok := mux.Vars(r)["slug"]
157 if !ok {
158 http.Error(w, "empty slug", http.StatusBadRequest)
159 return
160 }
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400161 a, err := s.r.Find(slug)
162 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400163 http.Error(w, err.Error(), http.StatusInternalServerError)
164 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400165 }
gio7fbd4ad2024-08-27 10:06:39 +0400166 instances, err := s.m.GetAllAppInstances(slug)
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400167 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400168 http.Error(w, err.Error(), http.StatusInternalServerError)
169 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400170 }
gioaa0fcdb2024-06-10 22:19:25 +0400171 resp := app{a.Name(), a.Icon(), a.Description(), a.Slug(), instances}
172 w.Header().Set("Content-Type", "application/json")
173 if err := json.NewEncoder(w).Encode(resp); err != nil {
174 http.Error(w, err.Error(), http.StatusInternalServerError)
175 return
176 }
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400177}
178
gioaa0fcdb2024-06-10 22:19:25 +0400179func (s *AppManagerServer) handleInstance(w http.ResponseWriter, r *http.Request) {
180 slug, ok := mux.Vars(r)["slug"]
181 if !ok {
182 http.Error(w, "empty slug", http.StatusBadRequest)
183 return
184 }
gio7fbd4ad2024-08-27 10:06:39 +0400185 instance, err := s.m.GetInstance(slug)
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400186 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400187 http.Error(w, err.Error(), http.StatusInternalServerError)
188 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400189 }
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400190 a, err := s.r.Find(instance.AppId)
191 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400192 http.Error(w, err.Error(), http.StatusInternalServerError)
193 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400194 }
gioaa0fcdb2024-06-10 22:19:25 +0400195 resp := app{a.Name(), a.Icon(), a.Description(), a.Slug(), []installer.AppInstanceConfig{*instance}}
196 w.Header().Set("Content-Type", "application/json")
197 if err := json.NewEncoder(w).Encode(resp); err != nil {
198 http.Error(w, err.Error(), http.StatusInternalServerError)
199 return
200 }
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400201}
202
gioaa0fcdb2024-06-10 22:19:25 +0400203func (s *AppManagerServer) handleAppInstall(w http.ResponseWriter, r *http.Request) {
204 slug, ok := mux.Vars(r)["slug"]
205 if !ok {
206 http.Error(w, "empty slug", http.StatusBadRequest)
207 return
208 }
209 contents, err := ioutil.ReadAll(r.Body)
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400210 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400211 http.Error(w, err.Error(), http.StatusInternalServerError)
212 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400213 }
214 var values map[string]any
215 if err := json.Unmarshal(contents, &values); err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400216 http.Error(w, err.Error(), http.StatusInternalServerError)
217 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400218 }
Giorgi Lekveishvili743fb432023-11-08 17:19:40 +0400219 log.Printf("Values: %+v\n", values)
gio3cdee592024-04-17 10:15:56 +0400220 a, err := installer.FindEnvApp(s.r, slug)
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400221 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400222 http.Error(w, err.Error(), http.StatusInternalServerError)
223 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400224 }
Giorgi Lekveishvili743fb432023-11-08 17:19:40 +0400225 log.Printf("Found application: %s\n", slug)
gio3cdee592024-04-17 10:15:56 +0400226 env, err := s.m.Config()
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400227 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400228 http.Error(w, err.Error(), http.StatusInternalServerError)
229 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400230 }
gio3cdee592024-04-17 10:15:56 +0400231 log.Printf("Configuration: %+v\n", env)
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400232 suffixGen := installer.NewFixedLengthRandomSuffixGenerator(3)
gio3af43942024-04-16 08:13:50 +0400233 suffix, err := suffixGen.Generate()
234 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400235 http.Error(w, err.Error(), http.StatusInternalServerError)
236 return
gio3af43942024-04-16 08:13:50 +0400237 }
gio44f621b2024-04-29 09:44:38 +0400238 instanceId := a.Slug() + suffix
gio3cdee592024-04-17 10:15:56 +0400239 appDir := fmt.Sprintf("/apps/%s", instanceId)
240 namespace := fmt.Sprintf("%s%s%s", env.NamespacePrefix, a.Namespace(), suffix)
gio1cd65152024-08-16 08:18:49 +0400241 t := tasks.NewInstallTask(s.h, func() (installer.ReleaseResources, error) {
gio43b0f422024-08-21 10:40:13 +0400242 rr, err := s.m.Install(a, instanceId, appDir, namespace, values)
243 if err == nil {
244 ctx, _ := context.WithTimeout(context.Background(), 5*time.Second)
245 go s.reconciler.Reconcile(ctx)
246 }
247 return rr, err
gio1cd65152024-08-16 08:18:49 +0400248 })
gio778577f2024-04-29 09:44:38 +0400249 if _, ok := s.tasks[instanceId]; ok {
250 panic("MUST NOT REACH!")
251 }
gio1cd65152024-08-16 08:18:49 +0400252 s.tasks[instanceId] = t
253 s.ta[instanceId] = a
gio778577f2024-04-29 09:44:38 +0400254 t.OnDone(func(err error) {
255 delete(s.tasks, instanceId)
gio1cd65152024-08-16 08:18:49 +0400256 delete(s.ta, instanceId)
gio778577f2024-04-29 09:44:38 +0400257 })
gio778577f2024-04-29 09:44:38 +0400258 go t.Start()
gioaa0fcdb2024-06-10 22:19:25 +0400259 if _, err := fmt.Fprintf(w, "/instance/%s", instanceId); err != nil {
260 http.Error(w, err.Error(), http.StatusInternalServerError)
261 return
262 }
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400263}
264
gioaa0fcdb2024-06-10 22:19:25 +0400265func (s *AppManagerServer) handleAppUpdate(w http.ResponseWriter, r *http.Request) {
266 slug, ok := mux.Vars(r)["slug"]
267 if !ok {
268 http.Error(w, "empty slug", http.StatusBadRequest)
269 return
270 }
gioaa0fcdb2024-06-10 22:19:25 +0400271 contents, err := ioutil.ReadAll(r.Body)
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400272 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400273 http.Error(w, err.Error(), http.StatusInternalServerError)
274 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400275 }
276 var values map[string]any
277 if err := json.Unmarshal(contents, &values); err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400278 http.Error(w, err.Error(), http.StatusInternalServerError)
279 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400280 }
gio778577f2024-04-29 09:44:38 +0400281 if _, ok := s.tasks[slug]; ok {
gioaa0fcdb2024-06-10 22:19:25 +0400282 http.Error(w, "Update already in progress", http.StatusBadRequest)
283 return
gio778577f2024-04-29 09:44:38 +0400284 }
giof8843412024-05-22 16:38:05 +0400285 rr, err := s.m.Update(slug, values)
gio778577f2024-04-29 09:44:38 +0400286 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400287 http.Error(w, err.Error(), http.StatusInternalServerError)
288 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400289 }
Giorgi Lekveishvilid2f3dca2023-12-20 09:31:30 +0400290 ctx, _ := context.WithTimeout(context.Background(), 2*time.Minute)
291 go s.reconciler.Reconcile(ctx)
gio778577f2024-04-29 09:44:38 +0400292 t := tasks.NewMonitorRelease(s.h, rr)
293 t.OnDone(func(err error) {
294 delete(s.tasks, slug)
295 })
296 s.tasks[slug] = t
297 go t.Start()
gioaa0fcdb2024-06-10 22:19:25 +0400298 if _, err := fmt.Fprintf(w, "/instance/%s", slug); err != nil {
299 http.Error(w, err.Error(), http.StatusInternalServerError)
300 return
301 }
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400302}
303
gioaa0fcdb2024-06-10 22:19:25 +0400304func (s *AppManagerServer) handleAppRemove(w http.ResponseWriter, r *http.Request) {
305 slug, ok := mux.Vars(r)["slug"]
306 if !ok {
307 http.Error(w, "empty slug", http.StatusBadRequest)
308 return
309 }
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400310 if err := s.m.Remove(slug); err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400311 http.Error(w, err.Error(), http.StatusInternalServerError)
312 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400313 }
Giorgi Lekveishvilid2f3dca2023-12-20 09:31:30 +0400314 ctx, _ := context.WithTimeout(context.Background(), 2*time.Minute)
315 go s.reconciler.Reconcile(ctx)
gioaa0fcdb2024-06-10 22:19:25 +0400316 if _, err := fmt.Fprint(w, "/"); err != nil {
317 http.Error(w, err.Error(), http.StatusInternalServerError)
318 return
319 }
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400320}
321
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400322type PageData struct {
Davit Tabidze780a0d02024-08-05 20:53:26 +0400323 Apps []app
324 CurrentPage string
325 SearchTarget string
326 SearchValue string
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400327}
328
Davit Tabidze780a0d02024-08-05 20:53:26 +0400329func (s *AppManagerServer) handleAppsList(w http.ResponseWriter, r *http.Request) {
330 pageType := mux.Vars(r)["pageType"]
331 if pageType == "" {
332 pageType = "all"
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400333 }
Davit Tabidze780a0d02024-08-05 20:53:26 +0400334 searchQuery := r.FormValue("query")
335 apps, err := s.r.Filter(searchQuery)
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400336 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400337 http.Error(w, err.Error(), http.StatusInternalServerError)
338 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400339 }
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400340 resp := make([]app, 0)
Davit Tabidze780a0d02024-08-05 20:53:26 +0400341 for _, a := range apps {
gio7fbd4ad2024-08-27 10:06:39 +0400342 instances, err := s.m.GetAllAppInstances(a.Slug())
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400343 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400344 http.Error(w, err.Error(), http.StatusInternalServerError)
345 return
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400346 }
Davit Tabidze780a0d02024-08-05 20:53:26 +0400347 switch pageType {
348 case "installed":
349 if len(instances) != 0 {
350 resp = append(resp, app{a.Name(), a.Icon(), a.Description(), a.Slug(), instances})
351 }
352 case "not-installed":
353 if len(instances) == 0 {
354 resp = append(resp, app{a.Name(), a.Icon(), a.Description(), a.Slug(), nil})
355 }
356 default:
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400357 resp = append(resp, app{a.Name(), a.Icon(), a.Description(), a.Slug(), instances})
358 }
359 }
360 data := PageData{
Davit Tabidze780a0d02024-08-05 20:53:26 +0400361 Apps: resp,
362 CurrentPage: pageType,
363 SearchTarget: pageType,
364 SearchValue: searchQuery,
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400365 }
gioaa0fcdb2024-06-10 22:19:25 +0400366 if err := s.tmpl.index.Execute(w, data); err != nil {
367 http.Error(w, err.Error(), http.StatusInternalServerError)
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400368 }
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400369}
370
371type appPageData struct {
gio3cdee592024-04-17 10:15:56 +0400372 App installer.EnvApp
373 Instance *installer.AppInstanceConfig
374 Instances []installer.AppInstanceConfig
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400375 AvailableNetworks []installer.Network
gio778577f2024-04-29 09:44:38 +0400376 Task tasks.Task
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400377 CurrentPage string
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400378}
379
gioaa0fcdb2024-06-10 22:19:25 +0400380func (s *AppManagerServer) handleAppUI(w http.ResponseWriter, r *http.Request) {
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400381 global, err := s.m.Config()
382 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400383 http.Error(w, err.Error(), http.StatusInternalServerError)
384 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400385 }
gioaa0fcdb2024-06-10 22:19:25 +0400386 slug, ok := mux.Vars(r)["slug"]
387 if !ok {
388 http.Error(w, "empty slug", http.StatusBadRequest)
389 return
390 }
gio3cdee592024-04-17 10:15:56 +0400391 a, err := installer.FindEnvApp(s.r, slug)
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400392 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400393 http.Error(w, err.Error(), http.StatusInternalServerError)
394 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400395 }
gio7fbd4ad2024-08-27 10:06:39 +0400396 instances, err := s.m.GetAllAppInstances(slug)
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400397 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400398 http.Error(w, err.Error(), http.StatusInternalServerError)
399 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400400 }
giocb34ad22024-07-11 08:01:13 +0400401 networks, err := s.m.CreateNetworks(global)
402 if err != nil {
403 http.Error(w, err.Error(), http.StatusInternalServerError)
404 return
405 }
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400406 data := appPageData{
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400407 App: a,
408 Instances: instances,
giocb34ad22024-07-11 08:01:13 +0400409 AvailableNetworks: networks,
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400410 CurrentPage: a.Name(),
411 }
gioaa0fcdb2024-06-10 22:19:25 +0400412 if err := s.tmpl.app.Execute(w, data); err != nil {
413 http.Error(w, err.Error(), http.StatusInternalServerError)
414 return
415 }
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400416}
417
gioaa0fcdb2024-06-10 22:19:25 +0400418func (s *AppManagerServer) handleInstanceUI(w http.ResponseWriter, r *http.Request) {
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400419 global, err := s.m.Config()
420 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400421 http.Error(w, err.Error(), http.StatusInternalServerError)
422 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400423 }
gioaa0fcdb2024-06-10 22:19:25 +0400424 slug, ok := mux.Vars(r)["slug"]
425 if !ok {
426 http.Error(w, "empty slug", http.StatusBadRequest)
427 return
428 }
gio1cd65152024-08-16 08:18:49 +0400429 t, ok := s.tasks[slug]
gio7fbd4ad2024-08-27 10:06:39 +0400430 instance, err := s.m.GetInstance(slug)
gio1cd65152024-08-16 08:18:49 +0400431 if err != nil && !ok {
gioaa0fcdb2024-06-10 22:19:25 +0400432 http.Error(w, err.Error(), http.StatusInternalServerError)
433 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400434 }
gio1cd65152024-08-16 08:18:49 +0400435 var a installer.EnvApp
436 if instance != nil {
437 a, err = s.m.GetInstanceApp(instance.Id)
438 if err != nil {
439 http.Error(w, err.Error(), http.StatusInternalServerError)
440 return
441 }
442 } else {
443 var ok bool
444 a, ok = s.ta[slug]
445 if !ok {
446 panic("MUST NOT REACH!")
447 }
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400448 }
gio7fbd4ad2024-08-27 10:06:39 +0400449 instances, err := s.m.GetAllAppInstances(a.Slug())
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400450 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400451 http.Error(w, err.Error(), http.StatusInternalServerError)
452 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400453 }
giocb34ad22024-07-11 08:01:13 +0400454 networks, err := s.m.CreateNetworks(global)
455 if err != nil {
456 http.Error(w, err.Error(), http.StatusInternalServerError)
457 return
458 }
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400459 data := appPageData{
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400460 App: a,
gio778577f2024-04-29 09:44:38 +0400461 Instance: instance,
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400462 Instances: instances,
giocb34ad22024-07-11 08:01:13 +0400463 AvailableNetworks: networks,
gio778577f2024-04-29 09:44:38 +0400464 Task: t,
gio1cd65152024-08-16 08:18:49 +0400465 CurrentPage: slug,
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400466 }
gioaa0fcdb2024-06-10 22:19:25 +0400467 if err := s.tmpl.app.Execute(w, data); err != nil {
468 http.Error(w, err.Error(), http.StatusInternalServerError)
469 return
470 }
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400471}