Split out compose.libsonnet, add to-docker-compose helper
parent
43b3db3a1d
commit
97b214e0ea
|
@ -0,0 +1,73 @@
|
||||||
|
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 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.services.%s.loadbalancer.server.port' % name]: port,
|
||||||
|
['traefik.http.routers.%s.service' % name]: '%s' % name,
|
||||||
|
'traefik.docker.network': 'traefik',
|
||||||
|
} + extras);
|
||||||
|
|
||||||
|
local mkService(name, svc) = svc {
|
||||||
|
container_name: name,
|
||||||
|
networks: ['traefik'],
|
||||||
|
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: 'always',
|
||||||
|
};
|
||||||
|
|
||||||
|
local extractVolumes(cfg) = {
|
||||||
|
[name]: { external: true }
|
||||||
|
for name in std.flattenArrays([
|
||||||
|
std.objectFields(optional(svc, 'volumes'))
|
||||||
|
for svc in std.objectValues(cfg)
|
||||||
|
])
|
||||||
|
};
|
||||||
|
|
||||||
|
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, ports=[]):: {
|
||||||
|
image: 'lscr.io/linuxserver/%s:%s' % [name, tag],
|
||||||
|
environment: mediaEnv + env,
|
||||||
|
volumes: { ['%s_config' % name]: '/config' },
|
||||||
|
mounts:: mediaMounts(mounts),
|
||||||
|
webPort:: webPort,
|
||||||
|
ports: ports,
|
||||||
|
},
|
||||||
|
}
|
22
flake.nix
22
flake.nix
|
@ -9,10 +9,24 @@
|
||||||
outputs = { self, flake-parts, ... }:
|
outputs = { self, flake-parts, ... }:
|
||||||
flake-parts.lib.mkFlake { inherit self; } {
|
flake-parts.lib.mkFlake { inherit self; } {
|
||||||
systems = [ "x86_64-linux" "aarch64-darwin" ];
|
systems = [ "x86_64-linux" "aarch64-darwin" ];
|
||||||
perSystem = { config, self', inputs', pkgs, system, ... }: {
|
perSystem = { config, self', inputs', pkgs, system, ... }:
|
||||||
devShells.default = pkgs.mkShell {
|
let
|
||||||
buildInputs = with pkgs; [ jsonnet ];
|
to-docker-compose = pkgs.writeShellApplication {
|
||||||
|
name = "to-docker-compose";
|
||||||
|
runtimeInputs = [ pkgs.jsonnet ];
|
||||||
|
text = ''
|
||||||
|
jsonnet services.jsonnet \
|
||||||
|
--tla-code secrets="{
|
||||||
|
PLEX_CLAIM: '$PLEX_CLAIM',
|
||||||
|
ADVERTISE_IP: '$ADVERTISE_IP',
|
||||||
|
}"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
devShells.default = pkgs.mkShell {
|
||||||
|
buildInputs = with pkgs; [ jsonnet to-docker-compose ];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,78 +1,15 @@
|
||||||
local optional(object, field) = std.get(object, field, {});
|
local compose = import 'compose.libsonnet';
|
||||||
|
local Compose = compose.Compose;
|
||||||
local dockerSocket = '/var/run/docker.sock:/var/run/docker.sock';
|
local Command = compose.Command;
|
||||||
|
local Port = compose.Port;
|
||||||
local tz = 'America/New_York';
|
local MediaService = compose.MediaService;
|
||||||
local mediaEnv = {
|
local MediaMounts = compose.MediaMounts;
|
||||||
PUID: 1000,
|
|
||||||
PGID: 1000,
|
|
||||||
TZ: tz,
|
|
||||||
};
|
|
||||||
|
|
||||||
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 toCommand = toList('--%s=%s');
|
|
||||||
|
|
||||||
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.services.%s.loadbalancer.server.port' % name]: port,
|
|
||||||
['traefik.http.routers.%s.service' % name]: '%s' % name,
|
|
||||||
'traefik.docker.network': 'traefik',
|
|
||||||
} + extras);
|
|
||||||
|
|
||||||
local mkService(name, svc) = svc {
|
|
||||||
container_name: name,
|
|
||||||
networks: ['traefik'],
|
|
||||||
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: 'always',
|
|
||||||
};
|
|
||||||
|
|
||||||
local extractVolumes(cfg) = {
|
|
||||||
[name]: { external: true }
|
|
||||||
for name in std.flattenArrays([
|
|
||||||
std.objectFields(optional(svc, 'volumes'))
|
|
||||||
for svc in std.objectValues(cfg)
|
|
||||||
])
|
|
||||||
};
|
|
||||||
|
|
||||||
local Compose(cfg) = {
|
|
||||||
services: std.mapWithKey(mkService, cfg),
|
|
||||||
volumes: extractVolumes(cfg),
|
|
||||||
networks: { traefik: { external: true } },
|
|
||||||
};
|
|
||||||
|
|
||||||
local Port(port, src=port, kind='tcp') =
|
|
||||||
local mapped = '%d:%d' % [port, src];
|
|
||||||
'%s/%s' % [mapped, kind];
|
|
||||||
|
|
||||||
local MediaMounts(mounts) = {
|
|
||||||
['/media/mat/%s' % path]: mounts[path]
|
|
||||||
for path in std.objectFields(mounts)
|
|
||||||
};
|
|
||||||
|
|
||||||
local MediaService(name, tag='latest', env={}, mounts={}, webPort, ports=[]) = {
|
|
||||||
image: 'lscr.io/linuxserver/%s:%s' % [name, tag],
|
|
||||||
environment: mediaEnv + env,
|
|
||||||
volumes: { ['%s_config' % name]: '/config' },
|
|
||||||
mounts:: MediaMounts(mounts),
|
|
||||||
webPort:: webPort,
|
|
||||||
ports: ports,
|
|
||||||
};
|
|
||||||
|
|
||||||
function(secrets={})
|
function(secrets={})
|
||||||
Compose({
|
Compose({
|
||||||
traefik: {
|
traefik: {
|
||||||
image: 'traefik:latest',
|
image: 'traefik:latest',
|
||||||
command: toCommand({
|
command: Command({
|
||||||
'log.level': 'ERROR',
|
'log.level': 'ERROR',
|
||||||
'api.insecure': 'true',
|
'api.insecure': 'true',
|
||||||
'providers.docker': 'true',
|
'providers.docker': 'true',
|
||||||
|
@ -143,7 +80,7 @@ function(secrets={})
|
||||||
plex: {
|
plex: {
|
||||||
image: 'plexinc/pms-docker',
|
image: 'plexinc/pms-docker',
|
||||||
environment: {
|
environment: {
|
||||||
TZ: tz,
|
TZ: 'America/New_York',
|
||||||
PLEX_CLAIM: std.get(secrets, 'PLEX_CLAIM'),
|
PLEX_CLAIM: std.get(secrets, 'PLEX_CLAIM'),
|
||||||
ADVERTISE_IP: std.get(secrets, 'ADVERTISE_IP'),
|
ADVERTISE_IP: std.get(secrets, 'ADVERTISE_IP'),
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue