blob: 2c434c6e91544c7e2c809cb6a2d42a080de4ef9d [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))})
giocb34ad22024-07-11 08:01:13 +040096 r.HandleFunc("/api/networks", s.handleNetworks).Methods(http.MethodGet)
gioaa0fcdb2024-06-10 22:19:25 +040097 r.HandleFunc("/api/app-repo", s.handleAppRepo)
98 r.HandleFunc("/api/app/{slug}/install", s.handleAppInstall).Methods(http.MethodPost)
99 r.HandleFunc("/api/app/{slug}", s.handleApp).Methods(http.MethodGet)
100 r.HandleFunc("/api/instance/{slug}", s.handleInstance).Methods(http.MethodGet)
101 r.HandleFunc("/api/instance/{slug}/update", s.handleAppUpdate).Methods(http.MethodPost)
102 r.HandleFunc("/api/instance/{slug}/remove", s.handleAppRemove).Methods(http.MethodPost)
103 r.HandleFunc("/", s.handleIndex).Methods(http.MethodGet)
104 r.HandleFunc("/not-installed", s.handleNotInstalledApps).Methods(http.MethodGet)
105 r.HandleFunc("/installed", s.handleInstalledApps).Methods(http.MethodGet)
106 r.HandleFunc("/app/{slug}", s.handleAppUI).Methods(http.MethodGet)
107 r.HandleFunc("/instance/{slug}", s.handleInstanceUI).Methods(http.MethodGet)
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400108 fmt.Printf("Starting HTTP server on port: %d\n", s.port)
gioaa0fcdb2024-06-10 22:19:25 +0400109 return http.ListenAndServe(fmt.Sprintf(":%d", s.port), r)
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400110}
111
112type app struct {
gio3cdee592024-04-17 10:15:56 +0400113 Name string `json:"name"`
114 Icon template.HTML `json:"icon"`
115 ShortDescription string `json:"shortDescription"`
116 Slug string `json:"slug"`
117 Instances []installer.AppInstanceConfig `json:"instances,omitempty"`
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400118}
119
giocb34ad22024-07-11 08:01:13 +0400120func (s *AppManagerServer) handleNetworks(w http.ResponseWriter, r *http.Request) {
121 env, err := s.m.Config()
122 if err != nil {
123 http.Error(w, err.Error(), http.StatusInternalServerError)
124 return
125 }
126 networks, err := s.m.CreateNetworks(env)
127 if err != nil {
128 http.Error(w, err.Error(), http.StatusInternalServerError)
129 return
130 }
131 if err := json.NewEncoder(w).Encode(networks); err != nil {
132 http.Error(w, err.Error(), http.StatusInternalServerError)
133 return
134 }
135}
136
gioaa0fcdb2024-06-10 22:19:25 +0400137func (s *AppManagerServer) handleAppRepo(w http.ResponseWriter, r *http.Request) {
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400138 all, err := s.r.GetAll()
139 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400140 http.Error(w, err.Error(), http.StatusInternalServerError)
141 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400142 }
143 resp := make([]app, len(all))
144 for i, a := range all {
gio44f621b2024-04-29 09:44:38 +0400145 resp[i] = app{a.Name(), a.Icon(), a.Description(), a.Slug(), nil}
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400146 }
gioaa0fcdb2024-06-10 22:19:25 +0400147 w.Header().Set("Content-Type", "application/json")
148 if err := json.NewEncoder(w).Encode(resp); err != nil {
149 http.Error(w, err.Error(), http.StatusInternalServerError)
150 return
151 }
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400152}
153
gioaa0fcdb2024-06-10 22:19:25 +0400154func (s *AppManagerServer) handleApp(w http.ResponseWriter, r *http.Request) {
155 slug, ok := mux.Vars(r)["slug"]
156 if !ok {
157 http.Error(w, "empty slug", http.StatusBadRequest)
158 return
159 }
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400160 a, err := s.r.Find(slug)
161 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400162 http.Error(w, err.Error(), http.StatusInternalServerError)
163 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400164 }
gio308105e2024-04-19 13:12:13 +0400165 instances, err := s.m.FindAllAppInstances(slug)
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400166 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400167 http.Error(w, err.Error(), http.StatusInternalServerError)
168 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400169 }
gioaa0fcdb2024-06-10 22:19:25 +0400170 resp := app{a.Name(), a.Icon(), a.Description(), a.Slug(), instances}
171 w.Header().Set("Content-Type", "application/json")
172 if err := json.NewEncoder(w).Encode(resp); err != nil {
173 http.Error(w, err.Error(), http.StatusInternalServerError)
174 return
175 }
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400176}
177
gioaa0fcdb2024-06-10 22:19:25 +0400178func (s *AppManagerServer) handleInstance(w http.ResponseWriter, r *http.Request) {
179 slug, ok := mux.Vars(r)["slug"]
180 if !ok {
181 http.Error(w, "empty slug", http.StatusBadRequest)
182 return
183 }
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400184 instance, err := s.m.FindInstance(slug)
185 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400186 http.Error(w, err.Error(), http.StatusInternalServerError)
187 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400188 }
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400189 a, err := s.r.Find(instance.AppId)
190 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400191 http.Error(w, err.Error(), http.StatusInternalServerError)
192 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400193 }
gioaa0fcdb2024-06-10 22:19:25 +0400194 resp := app{a.Name(), a.Icon(), a.Description(), a.Slug(), []installer.AppInstanceConfig{*instance}}
195 w.Header().Set("Content-Type", "application/json")
196 if err := json.NewEncoder(w).Encode(resp); err != nil {
197 http.Error(w, err.Error(), http.StatusInternalServerError)
198 return
199 }
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400200}
201
gioaa0fcdb2024-06-10 22:19:25 +0400202func (s *AppManagerServer) handleAppInstall(w http.ResponseWriter, r *http.Request) {
203 slug, ok := mux.Vars(r)["slug"]
204 if !ok {
205 http.Error(w, "empty slug", http.StatusBadRequest)
206 return
207 }
208 contents, err := ioutil.ReadAll(r.Body)
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400209 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400210 http.Error(w, err.Error(), http.StatusInternalServerError)
211 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400212 }
213 var values map[string]any
214 if err := json.Unmarshal(contents, &values); err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400215 http.Error(w, err.Error(), http.StatusInternalServerError)
216 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400217 }
Giorgi Lekveishvili743fb432023-11-08 17:19:40 +0400218 log.Printf("Values: %+v\n", values)
gio3cdee592024-04-17 10:15:56 +0400219 a, err := installer.FindEnvApp(s.r, slug)
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400220 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400221 http.Error(w, err.Error(), http.StatusInternalServerError)
222 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400223 }
Giorgi Lekveishvili743fb432023-11-08 17:19:40 +0400224 log.Printf("Found application: %s\n", slug)
gio3cdee592024-04-17 10:15:56 +0400225 env, err := s.m.Config()
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400226 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400227 http.Error(w, err.Error(), http.StatusInternalServerError)
228 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400229 }
gio3cdee592024-04-17 10:15:56 +0400230 log.Printf("Configuration: %+v\n", env)
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400231 suffixGen := installer.NewFixedLengthRandomSuffixGenerator(3)
gio3af43942024-04-16 08:13:50 +0400232 suffix, err := suffixGen.Generate()
233 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400234 http.Error(w, err.Error(), http.StatusInternalServerError)
235 return
gio3af43942024-04-16 08:13:50 +0400236 }
gio44f621b2024-04-29 09:44:38 +0400237 instanceId := a.Slug() + suffix
gio3cdee592024-04-17 10:15:56 +0400238 appDir := fmt.Sprintf("/apps/%s", instanceId)
239 namespace := fmt.Sprintf("%s%s%s", env.NamespacePrefix, a.Namespace(), suffix)
gio778577f2024-04-29 09:44:38 +0400240 rr, err := s.m.Install(a, instanceId, appDir, namespace, values)
241 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400242 http.Error(w, err.Error(), http.StatusInternalServerError)
243 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400244 }
Giorgi Lekveishvilid2f3dca2023-12-20 09:31:30 +0400245 ctx, _ := context.WithTimeout(context.Background(), 2*time.Minute)
246 go s.reconciler.Reconcile(ctx)
gio778577f2024-04-29 09:44:38 +0400247 if _, ok := s.tasks[instanceId]; ok {
248 panic("MUST NOT REACH!")
249 }
250 t := tasks.NewMonitorRelease(s.h, rr)
251 t.OnDone(func(err error) {
252 delete(s.tasks, instanceId)
253 })
254 s.tasks[instanceId] = t
255 go t.Start()
gioaa0fcdb2024-06-10 22:19:25 +0400256 if _, err := fmt.Fprintf(w, "/instance/%s", instanceId); err != nil {
257 http.Error(w, err.Error(), http.StatusInternalServerError)
258 return
259 }
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400260}
261
gioaa0fcdb2024-06-10 22:19:25 +0400262func (s *AppManagerServer) handleAppUpdate(w http.ResponseWriter, r *http.Request) {
263 slug, ok := mux.Vars(r)["slug"]
264 if !ok {
265 http.Error(w, "empty slug", http.StatusBadRequest)
266 return
267 }
gioaa0fcdb2024-06-10 22:19:25 +0400268 contents, err := ioutil.ReadAll(r.Body)
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400269 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400270 http.Error(w, err.Error(), http.StatusInternalServerError)
271 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400272 }
273 var values map[string]any
274 if err := json.Unmarshal(contents, &values); err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400275 http.Error(w, err.Error(), http.StatusInternalServerError)
276 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400277 }
gio778577f2024-04-29 09:44:38 +0400278 if _, ok := s.tasks[slug]; ok {
gioaa0fcdb2024-06-10 22:19:25 +0400279 http.Error(w, "Update already in progress", http.StatusBadRequest)
280 return
gio778577f2024-04-29 09:44:38 +0400281 }
giof8843412024-05-22 16:38:05 +0400282 rr, err := s.m.Update(slug, values)
gio778577f2024-04-29 09:44:38 +0400283 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400284 http.Error(w, err.Error(), http.StatusInternalServerError)
285 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400286 }
Giorgi Lekveishvilid2f3dca2023-12-20 09:31:30 +0400287 ctx, _ := context.WithTimeout(context.Background(), 2*time.Minute)
288 go s.reconciler.Reconcile(ctx)
gio778577f2024-04-29 09:44:38 +0400289 t := tasks.NewMonitorRelease(s.h, rr)
290 t.OnDone(func(err error) {
291 delete(s.tasks, slug)
292 })
293 s.tasks[slug] = t
294 go t.Start()
gioaa0fcdb2024-06-10 22:19:25 +0400295 if _, err := fmt.Fprintf(w, "/instance/%s", slug); err != nil {
296 http.Error(w, err.Error(), http.StatusInternalServerError)
297 return
298 }
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400299}
300
gioaa0fcdb2024-06-10 22:19:25 +0400301func (s *AppManagerServer) handleAppRemove(w http.ResponseWriter, r *http.Request) {
302 slug, ok := mux.Vars(r)["slug"]
303 if !ok {
304 http.Error(w, "empty slug", http.StatusBadRequest)
305 return
306 }
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400307 if err := s.m.Remove(slug); err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400308 http.Error(w, err.Error(), http.StatusInternalServerError)
309 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400310 }
Giorgi Lekveishvilid2f3dca2023-12-20 09:31:30 +0400311 ctx, _ := context.WithTimeout(context.Background(), 2*time.Minute)
312 go s.reconciler.Reconcile(ctx)
gioaa0fcdb2024-06-10 22:19:25 +0400313 if _, err := fmt.Fprint(w, "/"); err != nil {
314 http.Error(w, err.Error(), http.StatusInternalServerError)
315 return
316 }
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400317}
318
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400319type PageData struct {
320 Apps []app
321 CurrentPage string
322}
323
gioaa0fcdb2024-06-10 22:19:25 +0400324func (s *AppManagerServer) handleIndex(w http.ResponseWriter, r *http.Request) {
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400325 all, err := s.r.GetAll()
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400326 if err != nil {
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400327 log.Printf("all apps: %v", err)
gioaa0fcdb2024-06-10 22:19:25 +0400328 http.Error(w, err.Error(), http.StatusInternalServerError)
329 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400330 }
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400331 resp := make([]app, 0)
332 for _, a := range all {
333 instances, err := s.m.FindAllAppInstances(a.Slug())
334 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400335 http.Error(w, err.Error(), http.StatusInternalServerError)
336 return
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400337 }
338 resp = append(resp, app{a.Name(), a.Icon(), a.Description(), a.Slug(), instances})
339 }
340 data := PageData{
341 Apps: resp,
342 CurrentPage: "ALL",
343 }
gioaa0fcdb2024-06-10 22:19:25 +0400344 if err := s.tmpl.index.Execute(w, data); err != nil {
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400345 log.Printf("executing template: %v", err)
gioaa0fcdb2024-06-10 22:19:25 +0400346 http.Error(w, err.Error(), http.StatusInternalServerError)
347 return
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400348 }
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400349}
350
gioaa0fcdb2024-06-10 22:19:25 +0400351func (s *AppManagerServer) handleNotInstalledApps(w http.ResponseWriter, r *http.Request) {
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400352 all, err := s.r.GetAll()
353 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400354 http.Error(w, err.Error(), http.StatusInternalServerError)
355 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400356 }
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400357 resp := make([]app, 0)
358 for _, a := range all {
359 instances, err := s.m.FindAllAppInstances(a.Slug())
360 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400361 http.Error(w, err.Error(), http.StatusInternalServerError)
362 return
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400363 }
364 if len(instances) == 0 {
365 resp = append(resp, app{a.Name(), a.Icon(), a.Description(), a.Slug(), nil})
366 }
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400367 }
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400368 data := PageData{
369 Apps: resp,
370 CurrentPage: "NOT_INSTALLED",
371 }
gioaa0fcdb2024-06-10 22:19:25 +0400372 if err := s.tmpl.index.Execute(w, data); err != nil {
373 http.Error(w, err.Error(), http.StatusInternalServerError)
374 return
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400375 }
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400376}
377
gioaa0fcdb2024-06-10 22:19:25 +0400378func (s *AppManagerServer) handleInstalledApps(w http.ResponseWriter, r *http.Request) {
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400379 all, err := s.r.GetAll()
380 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400381 http.Error(w, err.Error(), http.StatusInternalServerError)
382 return
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400383 }
384 resp := make([]app, 0)
385 for _, a := range all {
386 instances, err := s.m.FindAllAppInstances(a.Slug())
387 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400388 http.Error(w, err.Error(), http.StatusInternalServerError)
389 return
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400390 }
391 if len(instances) != 0 {
392 resp = append(resp, app{a.Name(), a.Icon(), a.Description(), a.Slug(), instances})
393 }
394 }
395 data := PageData{
396 Apps: resp,
397 CurrentPage: "INSTALLED",
398 }
gioaa0fcdb2024-06-10 22:19:25 +0400399 if err := s.tmpl.index.Execute(w, data); err != nil {
400 http.Error(w, err.Error(), http.StatusInternalServerError)
401 return
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400402 }
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400403}
404
405type appPageData struct {
gio3cdee592024-04-17 10:15:56 +0400406 App installer.EnvApp
407 Instance *installer.AppInstanceConfig
408 Instances []installer.AppInstanceConfig
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400409 AvailableNetworks []installer.Network
gio778577f2024-04-29 09:44:38 +0400410 Task tasks.Task
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400411 CurrentPage string
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400412}
413
gioaa0fcdb2024-06-10 22:19:25 +0400414func (s *AppManagerServer) handleAppUI(w http.ResponseWriter, r *http.Request) {
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400415 global, err := s.m.Config()
416 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400417 http.Error(w, err.Error(), http.StatusInternalServerError)
418 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400419 }
gioaa0fcdb2024-06-10 22:19:25 +0400420 slug, ok := mux.Vars(r)["slug"]
421 if !ok {
422 http.Error(w, "empty slug", http.StatusBadRequest)
423 return
424 }
gio3cdee592024-04-17 10:15:56 +0400425 a, err := installer.FindEnvApp(s.r, slug)
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400426 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400427 http.Error(w, err.Error(), http.StatusInternalServerError)
428 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400429 }
gio308105e2024-04-19 13:12:13 +0400430 instances, err := s.m.FindAllAppInstances(slug)
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400431 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400432 http.Error(w, err.Error(), http.StatusInternalServerError)
433 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400434 }
giocb34ad22024-07-11 08:01:13 +0400435 networks, err := s.m.CreateNetworks(global)
436 if err != nil {
437 http.Error(w, err.Error(), http.StatusInternalServerError)
438 return
439 }
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400440 data := appPageData{
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400441 App: a,
442 Instances: instances,
giocb34ad22024-07-11 08:01:13 +0400443 AvailableNetworks: networks,
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400444 CurrentPage: a.Name(),
445 }
gioaa0fcdb2024-06-10 22:19:25 +0400446 if err := s.tmpl.app.Execute(w, data); err != nil {
447 http.Error(w, err.Error(), http.StatusInternalServerError)
448 return
449 }
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400450}
451
gioaa0fcdb2024-06-10 22:19:25 +0400452func (s *AppManagerServer) handleInstanceUI(w http.ResponseWriter, r *http.Request) {
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400453 global, err := s.m.Config()
454 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400455 http.Error(w, err.Error(), http.StatusInternalServerError)
456 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400457 }
gioaa0fcdb2024-06-10 22:19:25 +0400458 slug, ok := mux.Vars(r)["slug"]
459 if !ok {
460 http.Error(w, "empty slug", http.StatusBadRequest)
461 return
462 }
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400463 instance, err := s.m.FindInstance(slug)
464 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400465 http.Error(w, err.Error(), http.StatusInternalServerError)
466 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400467 }
giof8843412024-05-22 16:38:05 +0400468 a, err := s.m.GetInstanceApp(instance.Id)
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400469 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400470 http.Error(w, err.Error(), http.StatusInternalServerError)
471 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400472 }
gio44f621b2024-04-29 09:44:38 +0400473 instances, err := s.m.FindAllAppInstances(a.Slug())
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400474 if err != nil {
gioaa0fcdb2024-06-10 22:19:25 +0400475 http.Error(w, err.Error(), http.StatusInternalServerError)
476 return
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400477 }
giocb34ad22024-07-11 08:01:13 +0400478 networks, err := s.m.CreateNetworks(global)
479 if err != nil {
480 http.Error(w, err.Error(), http.StatusInternalServerError)
481 return
482 }
gio778577f2024-04-29 09:44:38 +0400483 t := s.tasks[slug]
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400484 data := appPageData{
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400485 App: a,
gio778577f2024-04-29 09:44:38 +0400486 Instance: instance,
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400487 Instances: instances,
giocb34ad22024-07-11 08:01:13 +0400488 AvailableNetworks: networks,
gio778577f2024-04-29 09:44:38 +0400489 Task: t,
Davit Tabidze3ec24cf2024-05-22 14:06:02 +0400490 CurrentPage: instance.Id,
491 }
gioaa0fcdb2024-06-10 22:19:25 +0400492 if err := s.tmpl.app.Execute(w, data); err != nil {
493 http.Error(w, err.Error(), http.StatusInternalServerError)
494 return
495 }
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400496}