blob: 5da26ef749cefa376b0f0763f2564d04466a3951 [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
Giorgi Lekveishvilid2f3dca2023-12-20 09:31:30 +040028 reconciler tasks.Reconciler
gio778577f2024-04-29 09:44:38 +040029 h installer.HelmReleaseMonitor
30 tasks map[string]tasks.Task
Davit Tabidze3ec24cf2024-05-22 14:06:02 +040031 tmpl tmplts
32}
33
34type tmplts struct {
35 index *template.Template
36 app *template.Template
37}
38
39func parseTemplatesAppManager(fs embed.FS) (tmplts, error) {
40 base, err := template.New("base.html").Funcs(template.FuncMap(sprig.FuncMap())).ParseFS(fs, "appmanager-tmpl/base.html")
41 if err != nil {
42 return tmplts{}, err
43 }
44 parse := func(path string) (*template.Template, error) {
45 if b, err := base.Clone(); err != nil {
46 return nil, err
47 } else {
48 return b.ParseFS(fs, path)
49 }
50 }
51 index, err := parse("appmanager-tmpl/index.html")
52 if err != nil {
53 return tmplts{}, err
54 }
55 app, err := parse("appmanager-tmpl/app.html")
56 if err != nil {
57 return tmplts{}, err
58 }
59 return tmplts{index, app}, nil
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +040060}
61
62func NewAppManagerServer(
63 port int,
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +040064 m *installer.AppManager,
Giorgi Lekveishvili08af67a2024-01-18 08:53:05 +040065 r installer.AppRepository,
Giorgi Lekveishvilid2f3dca2023-12-20 09:31:30 +040066 reconciler tasks.Reconciler,
gio778577f2024-04-29 09:44:38 +040067 h installer.HelmReleaseMonitor,
Davit Tabidze3ec24cf2024-05-22 14:06:02 +040068) (*AppManagerServer, error) {
69 tmpl, err := parseTemplatesAppManager(appTmpls)
70 if err != nil {
71 return nil, err
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +040072 }
Davit Tabidze3ec24cf2024-05-22 14:06:02 +040073 return &AppManagerServer{
74 port: port,
75 m: m,
76 r: r,
77 reconciler: reconciler,
78 h: h,
79 tasks: make(map[string]tasks.Task),
80 tmpl: tmpl,
81 }, nil
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +040082}
83
gio09f8efa2024-06-10 22:35:24 +040084type cachingHandler struct {
85 h http.Handler
86}
87
88func (h cachingHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
89 w.Header().Set("Cache-Control", "max-age=604800")
90 h.h.ServeHTTP(w, r)
91}
92
Giorgi Lekveishvili743fb432023-11-08 17:19:40 +040093func (s *AppManagerServer) Start() error {
gioaa0fcdb2024-06-10 22:19:25 +040094 r := mux.NewRouter()
gio09f8efa2024-06-10 22:35:24 +040095 r.PathPrefix("/static/").Handler(cachingHandler{http.FileServer(http.FS(staticAssets))})
gioaa0fcdb2024-06-10 22:19:25 +040096 r.HandleFunc("/api/app-repo", s.handleAppRepo)
97 r.HandleFunc("/api/app/{slug}/install", s.handleAppInstall).Methods(http.MethodPost)
98 r.HandleFunc("/api/app/{slug}", s.handleApp).Methods(http.MethodGet)
99 r.HandleFunc("/api/instance/{slug}", s.handleInstance).Methods(http.MethodGet)
100 r.HandleFunc("/api/instance/{slug}/update", s.handleAppUpdate).Methods(http.MethodPost)
101 r.HandleFunc("/api/instance/{slug}/remove", s.handleAppRemove).Methods(http.MethodPost)
102 r.HandleFunc("/", s.handleIndex).Methods(http.MethodGet)
103 r.HandleFunc("/not-installed", s.handleNotInstalledApps).Methods(http.MethodGet)
104 r.HandleFunc("/installed", s.handleInstalledApps).Methods(http.MethodGet)
105 r.HandleFunc("/app/{slug}", s.handleAppUI).Methods(http.MethodGet)
106 r.HandleFunc("/instance/{slug}", s.handleInstanceUI).Methods(http.MethodGet)
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400107 fmt.Printf("Starting HTTP server on port: %d\n", s.port)
gioaa0fcdb2024-06-10 22:19:25 +0400108 return http.ListenAndServe(fmt.Sprintf(":%d", s.port), r)
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400109}
110
111type app struct {
gio3cdee592024-04-17 10:15:56 +0400112 Name string `json:"name"`
113 Icon template.HTML `json:"icon"`
114 ShortDescription string `json:"shortDescription"`
115 Slug string `json:"slug"`
116 Instances []installer.AppInstanceConfig `json:"instances,omitempty"`
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400117}
118
gioaa0fcdb2024-06-10 22:19:25 +0400119func (s *AppManagerServer) handleAppRepo(w http.ResponseWriter, r *http.Request) {
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400120 all, err := s.r.GetAll()
121 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400122 http.Error(w, err.Error(), http.StatusInternalServerError)
123 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400124 }
125 resp := make([]app, len(all))
126 for i, a := range all {
gio44f621b2024-04-29 09:44:38 +0400127 resp[i] = app{a.Name(), a.Icon(), a.Description(), a.Slug(), nil}
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400128 }
gioaa0fcdb2024-06-10 22:19:25 +0400129 w.Header().Set("Content-Type", "application/json")
130 if err := json.NewEncoder(w).Encode(resp); err != nil {
131 http.Error(w, err.Error(), http.StatusInternalServerError)
132 return
133 }
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400134}
135
gioaa0fcdb2024-06-10 22:19:25 +0400136func (s *AppManagerServer) handleApp(w http.ResponseWriter, r *http.Request) {
137 slug, ok := mux.Vars(r)["slug"]
138 if !ok {
139 http.Error(w, "empty slug", http.StatusBadRequest)
140 return
141 }
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400142 a, err := s.r.Find(slug)
143 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400144 http.Error(w, err.Error(), http.StatusInternalServerError)
145 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400146 }
gio308105e2024-04-19 13:12:13 +0400147 instances, err := s.m.FindAllAppInstances(slug)
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400148 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400149 http.Error(w, err.Error(), http.StatusInternalServerError)
150 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400151 }
gioaa0fcdb2024-06-10 22:19:25 +0400152 resp := app{a.Name(), a.Icon(), a.Description(), a.Slug(), instances}
153 w.Header().Set("Content-Type", "application/json")
154 if err := json.NewEncoder(w).Encode(resp); err != nil {
155 http.Error(w, err.Error(), http.StatusInternalServerError)
156 return
157 }
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400158}
159
gioaa0fcdb2024-06-10 22:19:25 +0400160func (s *AppManagerServer) handleInstance(w http.ResponseWriter, r *http.Request) {
161 slug, ok := mux.Vars(r)["slug"]
162 if !ok {
163 http.Error(w, "empty slug", http.StatusBadRequest)
164 return
165 }
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400166 instance, err := s.m.FindInstance(slug)
167 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 }
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400171 a, err := s.r.Find(instance.AppId)
172 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400173 http.Error(w, err.Error(), http.StatusInternalServerError)
174 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400175 }
gioaa0fcdb2024-06-10 22:19:25 +0400176 resp := app{a.Name(), a.Icon(), a.Description(), a.Slug(), []installer.AppInstanceConfig{*instance}}
177 w.Header().Set("Content-Type", "application/json")
178 if err := json.NewEncoder(w).Encode(resp); err != nil {
179 http.Error(w, err.Error(), http.StatusInternalServerError)
180 return
181 }
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400182}
183
gioaa0fcdb2024-06-10 22:19:25 +0400184func (s *AppManagerServer) handleAppInstall(w http.ResponseWriter, r *http.Request) {
185 slug, ok := mux.Vars(r)["slug"]
186 if !ok {
187 http.Error(w, "empty slug", http.StatusBadRequest)
188 return
189 }
190 contents, err := ioutil.ReadAll(r.Body)
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400191 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 }
195 var values map[string]any
196 if err := json.Unmarshal(contents, &values); err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400197 http.Error(w, err.Error(), http.StatusInternalServerError)
198 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400199 }
Giorgi Lekveishvili743fb432023-11-08 17:19:40 +0400200 log.Printf("Values: %+v\n", values)
gio3cdee592024-04-17 10:15:56 +0400201 a, err := installer.FindEnvApp(s.r, slug)
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400202 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400203 http.Error(w, err.Error(), http.StatusInternalServerError)
204 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400205 }
Giorgi Lekveishvili743fb432023-11-08 17:19:40 +0400206 log.Printf("Found application: %s\n", slug)
gio3cdee592024-04-17 10:15:56 +0400207 env, err := s.m.Config()
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400208 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400209 http.Error(w, err.Error(), http.StatusInternalServerError)
210 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400211 }
gio3cdee592024-04-17 10:15:56 +0400212 log.Printf("Configuration: %+v\n", env)
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400213 suffixGen := installer.NewFixedLengthRandomSuffixGenerator(3)
gio3af43942024-04-16 08:13:50 +0400214 suffix, err := suffixGen.Generate()
215 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400216 http.Error(w, err.Error(), http.StatusInternalServerError)
217 return
gio3af43942024-04-16 08:13:50 +0400218 }
gio44f621b2024-04-29 09:44:38 +0400219 instanceId := a.Slug() + suffix
gio3cdee592024-04-17 10:15:56 +0400220 appDir := fmt.Sprintf("/apps/%s", instanceId)
221 namespace := fmt.Sprintf("%s%s%s", env.NamespacePrefix, a.Namespace(), suffix)
gio778577f2024-04-29 09:44:38 +0400222 rr, err := s.m.Install(a, instanceId, appDir, namespace, values)
223 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400224 http.Error(w, err.Error(), http.StatusInternalServerError)
225 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400226 }
Giorgi Lekveishvilid2f3dca2023-12-20 09:31:30 +0400227 ctx, _ := context.WithTimeout(context.Background(), 2*time.Minute)
228 go s.reconciler.Reconcile(ctx)
gio778577f2024-04-29 09:44:38 +0400229 if _, ok := s.tasks[instanceId]; ok {
230 panic("MUST NOT REACH!")
231 }
232 t := tasks.NewMonitorRelease(s.h, rr)
233 t.OnDone(func(err error) {
234 delete(s.tasks, instanceId)
235 })
236 s.tasks[instanceId] = t
237 go t.Start()
gioaa0fcdb2024-06-10 22:19:25 +0400238 if _, err := fmt.Fprintf(w, "/instance/%s", instanceId); err != nil {
239 http.Error(w, err.Error(), http.StatusInternalServerError)
240 return
241 }
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400242}
243
gioaa0fcdb2024-06-10 22:19:25 +0400244func (s *AppManagerServer) handleAppUpdate(w http.ResponseWriter, r *http.Request) {
245 slug, ok := mux.Vars(r)["slug"]
246 if !ok {
247 http.Error(w, "empty slug", http.StatusBadRequest)
248 return
249 }
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400250 appConfig, err := s.m.AppConfig(slug)
251 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400252 http.Error(w, err.Error(), http.StatusInternalServerError)
253 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400254 }
gioaa0fcdb2024-06-10 22:19:25 +0400255 contents, err := ioutil.ReadAll(r.Body)
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400256 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400257 http.Error(w, err.Error(), http.StatusInternalServerError)
258 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400259 }
260 var values map[string]any
261 if err := json.Unmarshal(contents, &values); err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400262 http.Error(w, err.Error(), http.StatusInternalServerError)
263 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400264 }
gio3cdee592024-04-17 10:15:56 +0400265 a, err := installer.FindEnvApp(s.r, appConfig.AppId)
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400266 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400267 http.Error(w, err.Error(), http.StatusInternalServerError)
268 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400269 }
gio778577f2024-04-29 09:44:38 +0400270 if _, ok := s.tasks[slug]; ok {
gioaa0fcdb2024-06-10 22:19:25 +0400271 http.Error(w, "Update already in progress", http.StatusBadRequest)
272 return
gio778577f2024-04-29 09:44:38 +0400273 }
274 rr, err := s.m.Update(a, slug, values)
275 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400276 http.Error(w, err.Error(), http.StatusInternalServerError)
277 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400278 }
Giorgi Lekveishvilid2f3dca2023-12-20 09:31:30 +0400279 ctx, _ := context.WithTimeout(context.Background(), 2*time.Minute)
280 go s.reconciler.Reconcile(ctx)
gio778577f2024-04-29 09:44:38 +0400281 t := tasks.NewMonitorRelease(s.h, rr)
282 t.OnDone(func(err error) {
283 delete(s.tasks, slug)
284 })
285 s.tasks[slug] = t
286 go t.Start()
gioaa0fcdb2024-06-10 22:19:25 +0400287 if _, err := fmt.Fprintf(w, "/instance/%s", slug); err != nil {
288 http.Error(w, err.Error(), http.StatusInternalServerError)
289 return
290 }
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400291}
292
gioaa0fcdb2024-06-10 22:19:25 +0400293func (s *AppManagerServer) handleAppRemove(w http.ResponseWriter, r *http.Request) {
294 slug, ok := mux.Vars(r)["slug"]
295 if !ok {
296 http.Error(w, "empty slug", http.StatusBadRequest)
297 return
298 }
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400299 if err := s.m.Remove(slug); err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400300 http.Error(w, err.Error(), http.StatusInternalServerError)
301 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400302 }
Giorgi Lekveishvilid2f3dca2023-12-20 09:31:30 +0400303 ctx, _ := context.WithTimeout(context.Background(), 2*time.Minute)
304 go s.reconciler.Reconcile(ctx)
gioaa0fcdb2024-06-10 22:19:25 +0400305 if _, err := fmt.Fprint(w, "/"); err != nil {
306 http.Error(w, err.Error(), http.StatusInternalServerError)
307 return
308 }
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400309}
310
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400311type PageData struct {
312 Apps []app
313 CurrentPage string
314}
315
gioaa0fcdb2024-06-10 22:19:25 +0400316func (s *AppManagerServer) handleIndex(w http.ResponseWriter, r *http.Request) {
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400317 all, err := s.r.GetAll()
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400318 if err != nil {
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400319 log.Printf("all apps: %v", err)
gioaa0fcdb2024-06-10 22:19:25 +0400320 http.Error(w, err.Error(), http.StatusInternalServerError)
321 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400322 }
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400323 resp := make([]app, 0)
324 for _, a := range all {
325 instances, err := s.m.FindAllAppInstances(a.Slug())
326 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400327 http.Error(w, err.Error(), http.StatusInternalServerError)
328 return
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400329 }
330 resp = append(resp, app{a.Name(), a.Icon(), a.Description(), a.Slug(), instances})
331 }
332 data := PageData{
333 Apps: resp,
334 CurrentPage: "ALL",
335 }
gioaa0fcdb2024-06-10 22:19:25 +0400336 if err := s.tmpl.index.Execute(w, data); err != nil {
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400337 log.Printf("executing template: %v", err)
gioaa0fcdb2024-06-10 22:19:25 +0400338 http.Error(w, err.Error(), http.StatusInternalServerError)
339 return
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400340 }
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400341}
342
gioaa0fcdb2024-06-10 22:19:25 +0400343func (s *AppManagerServer) handleNotInstalledApps(w http.ResponseWriter, r *http.Request) {
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400344 all, err := s.r.GetAll()
345 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400346 http.Error(w, err.Error(), http.StatusInternalServerError)
347 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400348 }
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400349 resp := make([]app, 0)
350 for _, a := range all {
351 instances, err := s.m.FindAllAppInstances(a.Slug())
352 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400353 http.Error(w, err.Error(), http.StatusInternalServerError)
354 return
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400355 }
356 if len(instances) == 0 {
357 resp = append(resp, app{a.Name(), a.Icon(), a.Description(), a.Slug(), nil})
358 }
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400359 }
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400360 data := PageData{
361 Apps: resp,
362 CurrentPage: "NOT_INSTALLED",
363 }
gioaa0fcdb2024-06-10 22:19:25 +0400364 if err := s.tmpl.index.Execute(w, data); err != nil {
365 http.Error(w, err.Error(), http.StatusInternalServerError)
366 return
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400367 }
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400368}
369
gioaa0fcdb2024-06-10 22:19:25 +0400370func (s *AppManagerServer) handleInstalledApps(w http.ResponseWriter, r *http.Request) {
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400371 all, err := s.r.GetAll()
372 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400373 http.Error(w, err.Error(), http.StatusInternalServerError)
374 return
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400375 }
376 resp := make([]app, 0)
377 for _, a := range all {
378 instances, err := s.m.FindAllAppInstances(a.Slug())
379 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400380 http.Error(w, err.Error(), http.StatusInternalServerError)
381 return
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400382 }
383 if len(instances) != 0 {
384 resp = append(resp, app{a.Name(), a.Icon(), a.Description(), a.Slug(), instances})
385 }
386 }
387 data := PageData{
388 Apps: resp,
389 CurrentPage: "INSTALLED",
390 }
gioaa0fcdb2024-06-10 22:19:25 +0400391 if err := s.tmpl.index.Execute(w, data); err != nil {
392 http.Error(w, err.Error(), http.StatusInternalServerError)
393 return
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400394 }
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400395}
396
397type appPageData struct {
gio3cdee592024-04-17 10:15:56 +0400398 App installer.EnvApp
399 Instance *installer.AppInstanceConfig
400 Instances []installer.AppInstanceConfig
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400401 AvailableNetworks []installer.Network
gio778577f2024-04-29 09:44:38 +0400402 Task tasks.Task
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400403 CurrentPage string
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400404}
405
gioaa0fcdb2024-06-10 22:19:25 +0400406func (s *AppManagerServer) handleAppUI(w http.ResponseWriter, r *http.Request) {
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400407 global, err := s.m.Config()
408 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400409 http.Error(w, err.Error(), http.StatusInternalServerError)
410 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400411 }
gioaa0fcdb2024-06-10 22:19:25 +0400412 slug, ok := mux.Vars(r)["slug"]
413 if !ok {
414 http.Error(w, "empty slug", http.StatusBadRequest)
415 return
416 }
gio3cdee592024-04-17 10:15:56 +0400417 a, err := installer.FindEnvApp(s.r, slug)
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400418 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400419 http.Error(w, err.Error(), http.StatusInternalServerError)
420 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400421 }
gio308105e2024-04-19 13:12:13 +0400422 instances, err := s.m.FindAllAppInstances(slug)
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400423 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400424 http.Error(w, err.Error(), http.StatusInternalServerError)
425 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400426 }
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400427 data := appPageData{
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400428 App: a,
429 Instances: instances,
430 AvailableNetworks: installer.CreateNetworks(global),
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400431 CurrentPage: a.Name(),
432 }
gioaa0fcdb2024-06-10 22:19:25 +0400433 if err := s.tmpl.app.Execute(w, data); err != nil {
434 http.Error(w, err.Error(), http.StatusInternalServerError)
435 return
436 }
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400437}
438
gioaa0fcdb2024-06-10 22:19:25 +0400439func (s *AppManagerServer) handleInstanceUI(w http.ResponseWriter, r *http.Request) {
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400440 global, err := s.m.Config()
441 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400442 http.Error(w, err.Error(), http.StatusInternalServerError)
443 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400444 }
gioaa0fcdb2024-06-10 22:19:25 +0400445 slug, ok := mux.Vars(r)["slug"]
446 if !ok {
447 http.Error(w, "empty slug", http.StatusBadRequest)
448 return
449 }
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400450 instance, err := s.m.FindInstance(slug)
451 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400452 http.Error(w, err.Error(), http.StatusInternalServerError)
453 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400454 }
gio3cdee592024-04-17 10:15:56 +0400455 a, err := installer.FindEnvApp(s.r, instance.AppId)
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400456 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400457 http.Error(w, err.Error(), http.StatusInternalServerError)
458 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400459 }
gio44f621b2024-04-29 09:44:38 +0400460 instances, err := s.m.FindAllAppInstances(a.Slug())
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400461 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400462 http.Error(w, err.Error(), http.StatusInternalServerError)
463 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400464 }
gio778577f2024-04-29 09:44:38 +0400465 t := s.tasks[slug]
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400466 data := appPageData{
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400467 App: a,
gio778577f2024-04-29 09:44:38 +0400468 Instance: instance,
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400469 Instances: instances,
470 AvailableNetworks: installer.CreateNetworks(global),
gio778577f2024-04-29 09:44:38 +0400471 Task: t,
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400472 CurrentPage: instance.Id,
473 }
gioaa0fcdb2024-06-10 22:19:25 +0400474 if err := s.tmpl.app.Execute(w, data); err != nil {
475 http.Error(w, err.Error(), http.StatusInternalServerError)
476 return
477 }
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400478}