Pull out service ports and volume variables better.

This commit is contained in:
root 2025-09-14 20:15:58 -04:00
parent 1262869fcc
commit 5e2cf888e7
14 changed files with 198 additions and 245 deletions

View file

@ -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) {

View file

@ -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" },
},
}

35
main.go
View file

@ -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
}
}
*/
}

View file

@ -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 {

View file

@ -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",
]
}

View file

@ -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}}

View file

@ -1,12 +1,13 @@
{
# docker-compose -f <linkding.yaml> 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",
]
}

View file

@ -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=

View file

@ -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

View file

@ -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",
]
}

View file

@ -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}}

View file

@ -1,7 +1,5 @@
{
enable: "false",
ports: [ "80", "443" ],
ports: { http: "80", https: "443" },
provider: "system",
packages: [ "caddy" ],

View file

@ -1,4 +1,4 @@
{{with .Ports}}Port {{index . 0}}{{end}}
{{with .Ports.ssh}}Port {{.}}{{end}}
#AddressFamily any
#ListenAddress 0.0.0.0
#ListenAddress ::

View file

@ -1,7 +1,5 @@
{
enable: "true",
ports: [ "22" ],
ports: { ssh: "22" },
provider: "system",
packages: [ "openssh-server" ],