Repository navigation
Expand file tree
/
Copy pathnamespaced-service.nix
More file actions
95 lines (92 loc) · 3.64 KB
/
Copy pathnamespaced-service.nix
File metadata and controls
95 lines (92 loc) · 3.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
{
config,
lib,
pkgs,
...
}:
with lib;
let
cfg = config.custom.namespacedServices;
shortName = name: if stringLength name > 6 then substring 0 6 name else name;
in
{
options.custom.namespacedServices = {
enable = mkEnableOption "Enable namespaced services with veth networking";
services = mkOption {
type = types.attrsOf (
types.submodule {
options = {
ip = mkOption {
type = types.str;
description = "Static IP address for the service in the namespace";
example = "192.168.2.50";
};
mac = mkOption {
type = types.str;
description = "Static MAC address for the veth interface";
example = "12:17:52:a3:25:04";
};
serviceName = mkOption {
type = types.str;
description = "Name of the systemd service to run in the namespace";
example = "transmission";
};
};
}
);
default = { };
description = "Configuration for services running in network namespaces";
};
};
config = mkIf cfg.enable {
systemd.services = foldl' (acc: svc: acc // svc) { } (
mapAttrsToList (
name: svcCfg:
let
vethName = "veth-${shortName name}";
vethHostName = "veth-h-${shortName name}";
in
{
"setup-${name}-ns" = {
description = "Set up network namespace for ${name}";
wantedBy = [ "multi-user.target" ];
after = [ "network-online.target" ];
before = [ "${svcCfg.serviceName}.service" ];
requires = [ "network-online.target" ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
ExecStart = "${pkgs.writeShellScriptBin "setup-${name}-ns" ''
#!/bin/bash
set -e
${pkgs.iproute2}/bin/ip netns del ${name}-ns || true
${pkgs.iproute2}/bin/ip netns add ${name}-ns
${pkgs.iproute2}/bin/ip netns exec ${name}-ns ${pkgs.iproute2}/bin/ip link set lo up
${pkgs.iproute2}/bin/ip link add name ${vethName} type veth peer name ${vethHostName}
${pkgs.iproute2}/bin/ip link set ${vethHostName} master vmbr0
${pkgs.iproute2}/bin/ip link set ${vethHostName} up
${pkgs.iproute2}/bin/ip link set ${vethName} netns ${name}-ns
${pkgs.iproute2}/bin/ip netns exec ${name}-ns ${pkgs.iproute2}/bin/ip link set dev ${vethName} address ${svcCfg.mac}
${pkgs.iproute2}/bin/ip netns exec ${name}-ns ${pkgs.iproute2}/bin/ip addr add ${svcCfg.ip}/24 dev ${vethName}
${pkgs.iproute2}/bin/ip netns exec ${name}-ns ${pkgs.iproute2}/bin/ip link set ${vethName} up
${pkgs.iproute2}/bin/ip netns exec ${name}-ns ${pkgs.iproute2}/bin/ip route add default via 192.168.2.1
${pkgs.iproute2}/bin/ip netns exec ${name}-ns ${pkgs.bash}/bin/bash -c 'echo -e "nameserver 192.168.2.50" > /etc/resolv.conf && chmod 444 /etc/resolv.conf'
''}/bin/setup-${name}-ns";
ExecStop = [
"${pkgs.iproute2}/bin/ip netns del ${name}-ns"
"${pkgs.iproute2}/bin/ip link del ${vethHostName} || true"
];
};
};
"${svcCfg.serviceName}" = {
after = [ "setup-${name}-ns.service" ];
requires = [ "setup-${name}-ns.service" ];
serviceConfig = {
NetworkNamespacePath = "/var/run/netns/${name}-ns";
};
};
}
) cfg.services
);
};
}