97 lines
2.8 KiB
Plaintext
97 lines
2.8 KiB
Plaintext
local optional(object, field) = std.get(object, field, {});
|
|
|
|
local dockerSocket = '/var/run/docker.sock:/var/run/docker.sock';
|
|
|
|
local mediaEnv = {
|
|
PUID: 1000,
|
|
PGID: 1000,
|
|
TZ: 'America/New_York',
|
|
};
|
|
|
|
local formatHelper(fmt) = function(name, option) fmt % [name, option];
|
|
local toList(fmt) = function(object) std.objectValues(std.mapWithKey(formatHelper(fmt), object));
|
|
local toLabels = toList('%s=%s');
|
|
local toVolumes = toList('%s:%s');
|
|
|
|
local homelabDomain = '0w0.casa';
|
|
local traefikLabels(name, host, port, extras) = toLabels({
|
|
'traefik.enable': 'true',
|
|
['traefik.http.routers.%s.rule' % name]: 'Host(`%s.mat`)' % host,
|
|
['traefik.http.routers.%s.entrypoints' % name]: 'web',
|
|
['traefik.http.routers.%s-tls.rule' % name]: 'Host(`%s.%s`)' % [host, homelabDomain],
|
|
['traefik.http.routers.%s-tls.entrypoints' % name]: 'web-tls',
|
|
'traefik.docker.network': 'traefik',
|
|
} + extras + if port == null then {} else {
|
|
['traefik.http.services.%s.loadbalancer.server.port' % name]: port
|
|
});
|
|
|
|
local mkNetwork(svc) = if std.get(svc, 'gluetun', false) then {
|
|
network_mode: 'service:gluetun',
|
|
} else {
|
|
networks: ['traefik'],
|
|
};
|
|
|
|
local mkService(name, svc) = svc {
|
|
container_name: name,
|
|
volumes: toVolumes(optional(svc, 'volumes'))
|
|
+ toVolumes(optional(svc, 'mounts'))
|
|
+ if std.get(svc, 'docker', false)
|
|
then [dockerSocket]
|
|
else [],
|
|
labels: traefikLabels(
|
|
name,
|
|
std.get(svc, 'host', name),
|
|
svc.webPort,
|
|
optional(svc, 'traefik')
|
|
),
|
|
restart: std.get(svc, 'restart', 'always'),
|
|
} + mkNetwork(svc);
|
|
|
|
local extractVolumes(cfg) = {
|
|
[name]: {
|
|
// this is very ugly, a data driven approach would be better but very verbose
|
|
external: std.length(std.findSubstr('_', name)) >= 2,
|
|
}
|
|
for name in std.flattenArrays([
|
|
std.objectFields(optional(svc, 'volumes'))
|
|
for svc in std.objectValues(cfg)
|
|
])
|
|
};
|
|
|
|
local mediaVolumes(name, external) =
|
|
local volume = if external then 'media_%s_config' else '%s_config';
|
|
{
|
|
[volume % name]: '/config',
|
|
};
|
|
local mediaMounts(mounts) = {
|
|
['/media/mat/%s' % path]: mounts[path]
|
|
for path in std.objectFields(mounts)
|
|
};
|
|
|
|
{
|
|
Compose(cfg):: {
|
|
services: std.mapWithKey(mkService, cfg),
|
|
volumes: extractVolumes(cfg),
|
|
networks: { traefik: { external: true } },
|
|
},
|
|
|
|
Port(port, src=port, kind='tcp')::
|
|
local mapped = '%d:%d' % [port, src];
|
|
'%s/%s' % [mapped, kind],
|
|
|
|
Command:: toList('--%s=%s'),
|
|
|
|
MediaMounts:: mediaMounts,
|
|
|
|
MediaService(name, tag='latest', env={}, mounts={}, webPort=null, ports=[], extras={}, external=false):: {
|
|
image: 'lscr.io/linuxserver/%s:%s' % [name, tag],
|
|
environment: mediaEnv + env,
|
|
volumes: mediaVolumes(name, external),
|
|
mounts:: mediaMounts(mounts),
|
|
webPort:: webPort,
|
|
ports: ports,
|
|
} + extras,
|
|
|
|
HomelabDomain:: homelabDomain,
|
|
}
|