summaryrefslogtreecommitdiffstats
path: root/cmd/deploy/webui.go
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/deploy/webui.go')
-rw-r--r--cmd/deploy/webui.go228
1 files changed, 0 insertions, 228 deletions
diff --git a/cmd/deploy/webui.go b/cmd/deploy/webui.go
deleted file mode 100644
index f57400e..0000000
--- a/cmd/deploy/webui.go
+++ /dev/null
@@ -1,228 +0,0 @@
1package main
2
3import (
4 "embed"
5 "encoding/json"
6 "flag"
7 "fmt"
8 "html/template"
9 "net/http"
10 "os"
11 "sort"
12 "strconv"
13
14 "github.com/bdw/deploy/internal/state"
15 "github.com/bdw/deploy/internal/templates"
16)
17
18//go:embed templates/*.html
19var templatesFS embed.FS
20
21func runWebUI(args []string) {
22 fs := flag.NewFlagSet("webui", flag.ExitOnError)
23 port := fs.String("port", "8080", "Port to run the web UI on")
24 help := fs.Bool("h", false, "Show help")
25
26 fs.Parse(args)
27
28 if *help {
29 fmt.Fprintf(os.Stderr, `Usage: deploy webui [flags]
30
31Launch a web interface to view and manage deployments.
32
33FLAGS:
34 -port string
35 Port to run the web UI on (default "8080")
36 -h Show this help message
37
38EXAMPLE:
39 # Launch web UI on default port (8080)
40 deploy webui
41
42 # Launch on custom port
43 deploy webui -port 3000
44`)
45 os.Exit(0)
46 }
47
48 // Parse template
49 tmpl, err := template.ParseFS(templatesFS, "templates/webui.html")
50 if err != nil {
51 fmt.Fprintf(os.Stderr, "Error parsing template: %v\n", err)
52 os.Exit(1)
53 }
54
55 // Handler for the main page
56 http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
57 // Reload state on each request to show latest changes
58 st, err := state.Load()
59 if err != nil {
60 http.Error(w, fmt.Sprintf("Error loading state: %v", err), http.StatusInternalServerError)
61 return
62 }
63
64 // Prepare data for template
65 type AppData struct {
66 Name string
67 Type string
68 Domain string
69 Port int
70 Env map[string]string
71 Host string
72 }
73
74 type HostData struct {
75 Host string
76 Apps []AppData
77 }
78
79 var hosts []HostData
80 for hostName, host := range st.Hosts {
81 var apps []AppData
82 for appName, app := range host.Apps {
83 apps = append(apps, AppData{
84 Name: appName,
85 Type: app.Type,
86 Domain: app.Domain,
87 Port: app.Port,
88 Env: app.Env,
89 Host: hostName,
90 })
91 }
92
93 // Sort apps by name
94 sort.Slice(apps, func(i, j int) bool {
95 return apps[i].Name < apps[j].Name
96 })
97
98 hosts = append(hosts, HostData{
99 Host: hostName,
100 Apps: apps,
101 })
102 }
103
104 // Sort hosts by name
105 sort.Slice(hosts, func(i, j int) bool {
106 return hosts[i].Host < hosts[j].Host
107 })
108
109 data := struct {
110 Hosts []HostData
111 }{
112 Hosts: hosts,
113 }
114
115 if err := tmpl.Execute(w, data); err != nil {
116 http.Error(w, fmt.Sprintf("Error rendering template: %v", err), http.StatusInternalServerError)
117 return
118 }
119 })
120
121 // API endpoint to get state as JSON
122 http.HandleFunc("/api/state", func(w http.ResponseWriter, r *http.Request) {
123 st, err := state.Load()
124 if err != nil {
125 http.Error(w, fmt.Sprintf("Error loading state: %v", err), http.StatusInternalServerError)
126 return
127 }
128
129 w.Header().Set("Content-Type", "application/json")
130 json.NewEncoder(w).Encode(st)
131 })
132
133 // API endpoint to get rendered configs for an app
134 http.HandleFunc("/api/configs", func(w http.ResponseWriter, r *http.Request) {
135 host := r.URL.Query().Get("host")
136 appName := r.URL.Query().Get("app")
137
138 if host == "" || appName == "" {
139 http.Error(w, "Missing host or app parameter", http.StatusBadRequest)
140 return
141 }
142
143 st, err := state.Load()
144 if err != nil {
145 http.Error(w, fmt.Sprintf("Error loading state: %v", err), http.StatusInternalServerError)
146 return
147 }
148
149 app, err := st.GetApp(host, appName)
150 if err != nil {
151 http.Error(w, fmt.Sprintf("App not found: %v", err), http.StatusNotFound)
152 return
153 }
154
155 configs := make(map[string]string)
156
157 // Render environment file
158 if app.Env != nil && len(app.Env) > 0 {
159 envContent := ""
160 for k, v := range app.Env {
161 envContent += fmt.Sprintf("%s=%s\n", k, v)
162 }
163 configs["env"] = envContent
164 configs["envPath"] = fmt.Sprintf("/etc/deploy/env/%s.env", appName)
165 }
166
167 // Render configs based on app type
168 if app.Type == "app" {
169 // Render systemd service
170 workDir := fmt.Sprintf("/var/lib/%s", appName)
171 binaryPath := fmt.Sprintf("/usr/local/bin/%s", appName)
172 envFilePath := fmt.Sprintf("/etc/deploy/env/%s.env", appName)
173
174 serviceContent, err := templates.SystemdService(map[string]string{
175 "Name": appName,
176 "User": appName,
177 "WorkDir": workDir,
178 "BinaryPath": binaryPath,
179 "Port": strconv.Itoa(app.Port),
180 "EnvFile": envFilePath,
181 "Args": app.Args,
182 })
183 if err != nil {
184 http.Error(w, fmt.Sprintf("Error rendering systemd service: %v", err), http.StatusInternalServerError)
185 return
186 }
187 configs["systemd"] = serviceContent
188 configs["systemdPath"] = fmt.Sprintf("/etc/systemd/system/%s.service", appName)
189
190 // Render Caddy config
191 caddyContent, err := templates.AppCaddy(map[string]string{
192 "Domain": app.Domain,
193 "Port": strconv.Itoa(app.Port),
194 })
195 if err != nil {
196 http.Error(w, fmt.Sprintf("Error rendering Caddy config: %v", err), http.StatusInternalServerError)
197 return
198 }
199 configs["caddy"] = caddyContent
200 configs["caddyPath"] = fmt.Sprintf("/etc/caddy/sites-enabled/%s.caddy", appName)
201 } else if app.Type == "static" {
202 // Render Caddy config for static site
203 remoteDir := fmt.Sprintf("/var/www/%s", appName)
204 caddyContent, err := templates.StaticCaddy(map[string]string{
205 "Domain": app.Domain,
206 "RootDir": remoteDir,
207 })
208 if err != nil {
209 http.Error(w, fmt.Sprintf("Error rendering Caddy config: %v", err), http.StatusInternalServerError)
210 return
211 }
212 configs["caddy"] = caddyContent
213 configs["caddyPath"] = fmt.Sprintf("/etc/caddy/sites-enabled/%s.caddy", appName)
214 }
215
216 w.Header().Set("Content-Type", "application/json")
217 json.NewEncoder(w).Encode(configs)
218 })
219
220 addr := fmt.Sprintf("localhost:%s", *port)
221 fmt.Printf("Starting web UI on http://%s\n", addr)
222 fmt.Printf("Press Ctrl+C to stop\n")
223
224 if err := http.ListenAndServe(addr, nil); err != nil {
225 fmt.Fprintf(os.Stderr, "Error starting server: %v\n", err)
226 os.Exit(1)
227 }
228}