feat: add CPU and memory resource limits per app
All checks were successful
Check / check (pull_request) Successful in 3m24s

- Add cpu_limit (REAL) and memory_limit (INTEGER) columns to apps table
  via migration 007
- Add CPULimit and MemoryLimit fields to App model with full CRUD support
- Add resource limits fields to app edit form with human-friendly
  memory input (e.g. 256m, 1g, 512k)
- Pass CPU and memory limits to Docker container creation via
  NanoCPUs and Memory host config fields
- Extract Docker container creation helpers (buildEnvSlice, buildMounts,
  buildResources) for cleaner code
- Add formatMemoryBytes template function for display
- Add comprehensive tests for parsing, formatting, model persistence,
  and container options
This commit is contained in:
user
2026-03-17 02:10:51 -07:00
parent fd110e69db
commit d6f6cc3670
13 changed files with 738 additions and 58 deletions

View File

@@ -6,6 +6,7 @@ import (
"fmt"
"html/template"
"io"
"strconv"
"sync"
)
@@ -23,6 +24,34 @@ var (
templatesMutex sync.RWMutex
)
// templateFuncs returns the custom template function map.
func templateFuncs() template.FuncMap {
return template.FuncMap{
"formatMemoryBytes": formatMemoryBytes,
}
}
// Memory unit constants.
const (
memGigabyte = 1024 * 1024 * 1024
memMegabyte = 1024 * 1024
memKilobyte = 1024
)
// formatMemoryBytes formats bytes into a human-readable string with unit suffix.
func formatMemoryBytes(bytes int64) string {
switch {
case bytes >= memGigabyte && bytes%memGigabyte == 0:
return strconv.FormatInt(bytes/memGigabyte, 10) + "g"
case bytes >= memMegabyte && bytes%memMegabyte == 0:
return strconv.FormatInt(bytes/memMegabyte, 10) + "m"
case bytes >= memKilobyte && bytes%memKilobyte == 0:
return strconv.FormatInt(bytes/memKilobyte, 10) + "k"
default:
return strconv.FormatInt(bytes, 10)
}
}
// initTemplates parses base template and creates cloned templates for each page.
func initTemplates() {
templatesMutex.Lock()
@@ -32,8 +61,10 @@ func initTemplates() {
return
}
// Parse base template with shared components
baseTemplate = template.Must(template.ParseFS(templatesRaw, "base.html"))
// Parse base template with shared components and custom functions
baseTemplate = template.Must(
template.New("base.html").Funcs(templateFuncs()).ParseFS(templatesRaw, "base.html"),
)
// Pages that extend base
pages := []string{