From 5e2cf888e770268e1d4a4438e2565662e14606cb Mon Sep 17 00:00:00 2001 From: root Date: Sun, 14 Sep 2025 20:15:58 -0400 Subject: [PATCH] Pull out service ports and volume variables better. --- config.go | 14 --- goolinux.json | 22 ++-- main.go | 35 +++--- scripted.go | 12 +- services/forgejo/docker.json | 8 +- services/forgejo/forgejo.template | 154 ++++++++++++-------------- services/linkding/docker.json | 5 +- services/linkding/env.template | 49 ++++++++ services/linkding/linkding.template | 84 +++----------- services/navidrome/docker.json | 6 +- services/navidrome/navidrome.template | 44 ++++---- services/proxy/system.json | 4 +- services/ssh/sshd.template | 2 +- services/ssh/system.json | 4 +- 14 files changed, 198 insertions(+), 245 deletions(-) create mode 100644 services/linkding/env.template diff --git a/config.go b/config.go index 98b8226..4de49c9 100644 --- a/config.go +++ b/config.go @@ -94,20 +94,6 @@ func ParseServiceConfig(file string) (ServiceConfig, error) { return c, nil } -// Get the first host port from a service -func (s ServiceConfig) GetHostPort() (string, error) { - if s.Ports == nil { - return "", undefinedError("ports") - } - - ports := strings.Split(s.Ports[0], ":") - if len(ports) == 0 { - return "", undefinedError("ports") - } - - return ports[0], nil -} - // Walk a tree of nested structures or maps until the node is found. // Node must be of type string or array. func GetValue(i interface{}, path string) (interface{}, error) { diff --git a/goolinux.json b/goolinux.json index ddef79f..35bde83 100644 --- a/goolinux.json +++ b/goolinux.json @@ -22,28 +22,24 @@ "navidrome": { "enable": "true", "provider": "docker", - "volumes": [ - "/data/docker/navidrome:/data", - "/data/music:/music:ro" - ], + "volumes": { + data: "/data/docker/navidrome", + music: "/data/music", + }, }, "forgejo": { "enable": "true", "provider": "docker", - "volumes": [ - "/data/docker/forgejo:/data", - ], - "config": { - "db": "postgres", - "db_path": "/data/docker/forgejo/postgres", + "volumes": { + data: "/data/docker/forgejo", + db: "/data/docker/forgejo/postgres", }, + "config": { "db": "postgres" }, }, "linkding": { "enable": "true", "provider": "docker", - "volumes": [ - "/data/docker/linkding:/etc/linkding/data", - ], + "volumes": { data: "/data/docker/linkding" }, }, } diff --git a/main.go b/main.go index ee643da..ffb7e2e 100644 --- a/main.go +++ b/main.go @@ -9,7 +9,7 @@ import ( "strings" "text/template" - "github.com/ghodss/yaml" + _ "github.com/ghodss/yaml" "dario.cat/mergo" "github.com/otiai10/copy" ) @@ -36,8 +36,10 @@ type ServiceConfig struct { ExtraConfig string Src string - Ports []string - Volumes []string + Ports map[string]string + ExtraPorts []string + Volumes map[string]string + ExtraVolumes []string Proxy string Provider string @@ -94,7 +96,9 @@ func main() { // Parse service config mergo.Merge(&s, ServiceConfig{ - Config: make(map[string]interface{}), + Config: make(map[string]interface{}), + Ports: make(map[string]string), + Volumes: make(map[string]string), }) mergo.Merge(&s, service, mergo.WithOverride) config.Services[name] = s @@ -108,15 +112,9 @@ func main() { s.Packages...) // If a proxy definition exists, append it + // Only look at services.ports.web for proxying if s.Proxy != "" { - port, err := s.GetHostPort() - if err != nil { - fmt.Println(err.Error()) - fmt.Println("Error in service", name) - return - } - - err = AddProxy(s.Proxy, port) + err = AddProxy(s.Proxy, s.Ports["web"]) if err != nil { fmt.Println(err.Error()) fmt.Println("Error adding proxy for service", name) @@ -133,6 +131,9 @@ func main() { // Generate service config templates for name, s := range config.Services { + // Skip services that aren't enabled + if s.Enable != "true" { continue } + for _, f := range s.ConfigFiles { f := strings.Split(f, ":") @@ -146,7 +147,7 @@ func main() { tmpl, err := template.New(name).Parse(string(t)) if err != nil { - fmt.Println("Error reading template") + fmt.Println("Error reading template", f[0]) fmt.Println(err) return } @@ -175,9 +176,10 @@ func main() { } } +/* // Convert service configs from JSON to YAML fmt.Println("Converting docker service configs to YAML") - servicesPath := "/config/services/docker/" + servicesPath := "/services" dirents, err := os.ReadDir(servicesPath) for _, d := range dirents { if d.IsDir() == true { continue } @@ -201,6 +203,7 @@ func main() { fd.Chmod(0444) fd.Write(y) } +*/ // Parse package list { @@ -255,9 +258,10 @@ func main() { // (Re)start services +/* // Handle docker services fmt.Println("Starting docker services") - servicesPath = "/config/services/docker/" + servicesPath = "/services/" dirents, err = os.ReadDir(servicesPath) for _, d := range dirents { if d.IsDir() == true { continue } @@ -277,4 +281,5 @@ func main() { return } } +*/ } diff --git a/scripted.go b/scripted.go index 00ae630..3ed3e54 100644 --- a/scripted.go +++ b/scripted.go @@ -8,6 +8,7 @@ import ( // Scripted proxy errors var ErrConversion = errors.New("port is not a number") +var ErrNoPort = errors.New("port is not defined for requested proxy") var ErrDuplicate = errors.New("duplicate entry") type ProxyError struct { @@ -27,6 +28,10 @@ func conversionError(domain, port string) *ProxyError { return &ProxyError{domain, port, ErrConversion} } +func noPortError(domain string) *ProxyError { + return &ProxyError{domain, "", ErrNoPort} +} + func duplicateError(domain, port string) *ProxyError { return &ProxyError{domain, port, ErrDuplicate} } @@ -51,10 +56,11 @@ func GetProxy() ([]Proxy) { } func AddProxy(domain, port string) (error) { + // If the port doesn't exist this is a no-op + if port == "" { return noPortError(domain) } + p, err := strconv.Atoi(port) - if err != nil { - return conversionError(domain, port) - } + if err != nil { return conversionError(domain, port) } conflict, exists := proxyList[p] if exists == true { diff --git a/services/forgejo/docker.json b/services/forgejo/docker.json index db376ec..671740d 100644 --- a/services/forgejo/docker.json +++ b/services/forgejo/docker.json @@ -1,14 +1,10 @@ { -ports: ["3000:3000", "222:22"], -volumes: [ - "/etc/timezone:/etc/timezone:ro", - "/etc/localtime:/etc/localtime:ro", -], +ports: { web: "3000", ssh: "222", }, provider: "docker", packages: [], src: "codeberg.org/forgejo/forgejo:10", configFiles: [ - "forgejo.template:/services/docker/forgejo.json", + "forgejo.template:/services/forgejo/compose.yaml", ] } diff --git a/services/forgejo/forgejo.template b/services/forgejo/forgejo.template index fcd803d..a6d10c4 100644 --- a/services/forgejo/forgejo.template +++ b/services/forgejo/forgejo.template @@ -1,88 +1,70 @@ -{ -"networks": { - "forgejo": { - "external": false - } -}, +networks: + forgejo: + external: false -"services": { - "server": { - "image": "{{.Src}}", - "container_name": "forgejo", - "environment": [ - "USER_UID=1000", - "USER_GID=1000", - {{if eq .Config.db "mysql"}} - FORGEJO__database__DB_TYPE=mysql, - FORGEJO__database__HOST=db:3306, - FORGEJO__database__NAME=forgejo, - FORGEJO__database__USER=forgejo, - FORGEJO__database__PASSWD=forgejo, - {{end}} - {{if eq .Config.db "postgres"}} - FORGEJO__database__DB_TYPE=postgres, - FORGEJO__database__HOST=db:5432, - FORGEJO__database__NAME=forgejo, - FORGEJO__database__USER=forgejo, - FORGEJO__database__PASSWD=forgejo, - {{end}} - ], - {{with .Config.Restart}}"restart": "{{.}}",{{end}} - "networks": [ - "forgejo" - ], - "volumes": [ - {{range .Volumes}} - "{{.}}", - {{end}} - ], - "ports": [ - {{range .Ports}} - "{{.}}", - {{end}} - ], - {{if .Config.db}} - "depends_on": [ - "db" - ], - {{end}} - }, +services: + server: + image: {{.Src}} + container_name: forgejo + environment: + - USER_UID=1000 + - USER_GID=1000 + {{- if eq .Config.db "mysql"}} + - FORGEJO__database__DB_TYPE=mysql + - FORGEJO__database__HOST=db:3306 + - FORGEJO__database__NAME=forgejo + - FORGEJO__database__USER=forgejo + - FORGEJO__database__PASSWD=forgejo + {{- end}} + {{- if eq .Config.db "postgres"}} + - FORGEJO__database__DB_TYPE=postgres + - FORGEJO__database__HOST=db:5432 + - FORGEJO__database__NAME=forgejo + - FORGEJO__database__USER=forgejo + - FORGEJO__database__PASSWD=forgejo + {{- end}} + restart: always + networks: + - forgejo + volumes: + - /etc/timezone:/etc/timezone:ro + - /etc/localtime:/etc/localtime:ro + - {{.Volumes.data}}:/data + {{- range .ExtraVolumes}} + - {{.}} + {{- end}} + ports: + - '{{.Ports.web}}:3000' + - '{{.Ports.ssh}}:22' + {{- if .Config.db}} + depends_on: + - db + {{- end}} - {{if eq .Config.db "mysql"}} - "db": { - "image": "mysql:8", - "restart": "always", - "environment": [ - "MYSQL_ROOT_PASSWORD=forgejo", - "MYSQL_USER=forgejo", - "MYSQL_PASSWORD=forgejo", - "MYSQL_DATABASE=forgejo" - ], - "networks": [ - "forgejo" - ], - "volumes": [ - "{{.Config.db_path}}:/var/lib/mysql" - ] - }, - {{end}} - - {{if eq .Config.db "postgres"}} - "db": { - "image": "postgres:14", - "restart": "always", - "environment": [ - "POSTGRES_USER=forgejo", - "POSTGRES_PASSWORD=forgejo", - "POSTGRES_DB=forgejo" - ], - "networks": [ - "forgejo" - ], - "volumes": [ - "{{.Config.db_path}}:/var/lib/postgresql/data" - ] - }, - {{end}} -} -} + {{- if eq .Config.db "mysql"}} + db: + image: mysql:8 + restart: always + environment: + - MYSQL_ROOT_PASSWORD=forgejo + - MYSQL_USER=forgejo + - MYSQL_PASSWORD=forgejo + - MYSQL_DATABASE=forgejo + networks: + - forgejo + volumes: + - {{.Volumes.db}}:/var/lib/mysql + {{- end}} + {{- if eq .Config.db "postgres"}} + db: + image: postgres:14 + restart: always + environment: + - POSTGRES_USER=forgejo + - POSTGRES_PASSWORD=forgejo + - POSTGRES_DB=forgejo + networks: + - forgejo + volumes: + - {{.Volumes.db}}:/var/lib/postgresql/data + {{- end}} diff --git a/services/linkding/docker.json b/services/linkding/docker.json index 655ec95..1cf132b 100644 --- a/services/linkding/docker.json +++ b/services/linkding/docker.json @@ -1,12 +1,13 @@ { # docker-compose -f exec linkding python manage.py createsuperuser --username=joe --email=joe@example.com -ports: ["9090:9090"], +ports: { web: "9090" }, provider: "docker", packages: [], src: "sissbruecker/linkding:latest", configFiles: [ - "linkding.template:/services/docker/linkding.json", + "linkding.template:/services/linkding/compose.yaml", + "env.template:/services/linkding/.env", ] } diff --git a/services/linkding/env.template b/services/linkding/env.template new file mode 100644 index 0000000..00aaf59 --- /dev/null +++ b/services/linkding/env.template @@ -0,0 +1,49 @@ +# Docker container name +LD_CONTAINER_NAME=linkding +# Port on the host system that the application should be published on +LD_HOST_PORT=9090 +# Directory on the host system that should be mounted as data dir into the Docker container +LD_HOST_DATA_DIR=./data + +# Can be used to run linkding under a context path, for example: linkding/ +# Must end with a slash `/` +LD_CONTEXT_PATH= +# Username of the initial superuser to create, leave empty to not create one +LD_SUPERUSER_NAME= +# Password for the initial superuser, leave empty to disable credentials authentication and rely on proxy authentication instead +LD_SUPERUSER_PASSWORD= +# Option to disable background tasks +LD_DISABLE_BACKGROUND_TASKS=False +# Option to disable URL validation for bookmarks completely +LD_DISABLE_URL_VALIDATION=False +# Enables support for authentication proxies such as Authelia +LD_ENABLE_AUTH_PROXY=False +# Name of the request header that the auth proxy passes to the application to identify the user +# See docs/Options.md for more details +LD_AUTH_PROXY_USERNAME_HEADER= +# The URL that linkding should redirect to after a logout, when using an auth proxy +# See docs/Options.md for more details +LD_AUTH_PROXY_LOGOUT_URL= +# List of trusted origins from which to accept POST requests +# See docs/Options.md for more details +LD_CSRF_TRUSTED_ORIGINS= + +# Database settings +# These are currently only required for configuring PostreSQL. +# By default, linkding uses SQLite for which you don't need to configure anything. + +# Database engine, can be sqlite (default) or postgres +LD_DB_ENGINE= +# Database name (default: linkding) +LD_DB_DATABASE= +# Username to connect to the database server (default: linkding) +LD_DB_USER= +# Password to connect to the database server +LD_DB_PASSWORD= +# The hostname where the database is hosted (default: localhost) +LD_DB_HOST= +# Port use to connect to the database server +# Should use the default port if not set +LD_DB_PORT= +# Any additional options to pass to the database (default: {}) +LD_DB_OPTIONS= diff --git a/services/linkding/linkding.template b/services/linkding/linkding.template index 58048eb..43c2d58 100644 --- a/services/linkding/linkding.template +++ b/services/linkding/linkding.template @@ -1,70 +1,14 @@ -{ -"services": { - "linkding": { - "container_name": "linkding", - "image": "{{.Src}}", - "ports": [ - {{range .Ports}} - "{{.}}", - {{end}} - ], - "volumes": [ - {{range .Volumes}} - "{{.}}", - {{end}} - ], - "environment": [ - ## Docker container name - #LD_CONTAINER_NAME=linkding - ## Port on the host system that the application should be published on - #LD_HOST_PORT=9090 - ## Directory on the host system that should be mounted as data dir into the Docker container - #LD_HOST_DATA_DIR=./data - - # Can be used to run linkding under a context path, for example: linkding/ - # Must end with a slash `/` - LD_CONTEXT_PATH=, - # Username of the initial superuser to create, leave empty to not create one - LD_SUPERUSER_NAME=, - # Password for the initial superuser, leave empty to disable credentials authentication and rely on proxy authentication instead - LD_SUPERUSER_PASSWORD=, - # Option to disable background tasks - LD_DISABLE_BACKGROUND_TASKS=False, - # Option to disable URL validation for bookmarks completely - LD_DISABLE_URL_VALIDATION=False, - # Enables support for authentication proxies such as Authelia - LD_ENABLE_AUTH_PROXY=False, - # Name of the request header that the auth proxy passes to the application to identify the user - # See docs/Options.md for more details - LD_AUTH_PROXY_USERNAME_HEADER=, - # The URL that linkding should redirect to after a logout, when using an auth proxy - # See docs/Options.md for more details - LD_AUTH_PROXY_LOGOUT_URL=, - # List of trusted origins from which to accept POST requests - # See docs/Options.md for more details - LD_CSRF_TRUSTED_ORIGINS=, - - # Database settings - # These are currently only required for configuring PostreSQL. - # By default, linkding uses SQLite for which you don't need to configure anything. - - # Database engine, can be sqlite (default) or postgres - LD_DB_ENGINE=, - # Database name (default: linkding) - LD_DB_DATABASE=, - # Username to connect to the database server (default: linkding) - LD_DB_USER=, - # Password to connect to the database server - LD_DB_PASSWORD=, - # The hostname where the database is hosted (default: localhost) - LD_DB_HOST=, - # Port use to connect to the database server - # Should use the default port if not set - LD_DB_PORT=, - # Any additional options to pass to the database (default: {}) - LD_DB_OPTIONS=, - ], - {{with .Config.Restart}}"restart": "{{.}}",{{end}} - } -} -} +services: + linkding: + container_name: linkding + image: {{.Src}} + ports: + - "{{.Ports.web}}}:9090" + volumes: + - "{{.Volumes.data}}:/etc/linkding/data" + {{- range .ExtraVolumes}} + - {{.}} + {{- end}} + env_file: + - .env + restart: always diff --git a/services/navidrome/docker.json b/services/navidrome/docker.json index deed881..5612884 100644 --- a/services/navidrome/docker.json +++ b/services/navidrome/docker.json @@ -1,12 +1,10 @@ { -enable: "false", - -ports: ["4533:4533"], +ports: { web: "4533" }, provider: "docker", packages: [], src: "deluan/navidrome:latest", configFiles: [ - "navidrome.template:/services/docker/navidrome.json", + "navidrome.template:/services/navidrome/compose.yaml", ] } diff --git a/services/navidrome/navidrome.template b/services/navidrome/navidrome.template index e67967b..2cbba99 100644 --- a/services/navidrome/navidrome.template +++ b/services/navidrome/navidrome.template @@ -1,25 +1,19 @@ -{ -"services": { - "navidrome": { - "image": "{{.Src}}", - {{with .Config.Id}}"user": "{{.}}:{{.}}",{{end}} - "ports": [ - {{range .Ports}} - "{{.}}", - {{end}} - ], - {{with .Config.Restart}}"restart": "{{.}}",{{end}} - "environment": { - "ND_SCANSCHEDULE": "1h", - "ND_LOGLEVEL": "info", - "ND_SESSIONTIMEOUT": "24h", - "ND_BASEURL": "", - }, - "volumes": [ - {{range .Volumes}} - "{{.}}", - {{end}} - ], - } -} -} +services: + navidrome: + image: {{.Src}} + user: 1000:1000 # should be owner of volumes + ports: + - "{{.Ports.web}}:4533" + restart: always + environment: + # Optional: put your config options customization here. Examples: + ND_SCANSCHEDULE: 1h + ND_LOGLEVEL: info + ND_SESSIONTIMEOUT: 24h + ND_BASEURL: "" + volumes: + - "{{.Volumes.data}}:/data" + - "{{.Volumes.music}}:/music:ro" + {{- range .ExtraVolumes}} + - {{.}} + {{- end}} diff --git a/services/proxy/system.json b/services/proxy/system.json index f629d81..3149b53 100644 --- a/services/proxy/system.json +++ b/services/proxy/system.json @@ -1,7 +1,5 @@ { -enable: "false", - -ports: [ "80", "443" ], +ports: { http: "80", https: "443" }, provider: "system", packages: [ "caddy" ], diff --git a/services/ssh/sshd.template b/services/ssh/sshd.template index 93f9979..cf6e3b1 100644 --- a/services/ssh/sshd.template +++ b/services/ssh/sshd.template @@ -1,4 +1,4 @@ -{{with .Ports}}Port {{index . 0}}{{end}} +{{with .Ports.ssh}}Port {{.}}{{end}} #AddressFamily any #ListenAddress 0.0.0.0 #ListenAddress :: diff --git a/services/ssh/system.json b/services/ssh/system.json index 0910a69..b8c68b0 100644 --- a/services/ssh/system.json +++ b/services/ssh/system.json @@ -1,7 +1,5 @@ { -enable: "true", - -ports: [ "22" ], +ports: { ssh: "22" }, provider: "system", packages: [ "openssh-server" ],