1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6 cfg = config.services.pixiecore;
7in
8{
9 meta.maintainers = with maintainers; [ bbigras danderson ];
10
11 options = {
12 services.pixiecore = {
13 enable = mkEnableOption (lib.mdDoc "Pixiecore");
14
15 openFirewall = mkOption {
16 type = types.bool;
17 default = false;
18 description = lib.mdDoc ''
19 Open ports (67, 69 UDP and 4011, 'port', 'statusPort' TCP) in the firewall for Pixiecore.
20 '';
21 };
22
23 mode = mkOption {
24 description = lib.mdDoc "Which mode to use";
25 default = "boot";
26 type = types.enum [ "api" "boot" "quick" ];
27 };
28
29 debug = mkOption {
30 type = types.bool;
31 default = false;
32 description = lib.mdDoc "Log more things that aren't directly related to booting a recognized client";
33 };
34
35 dhcpNoBind = mkOption {
36 type = types.bool;
37 default = false;
38 description = lib.mdDoc "Handle DHCP traffic without binding to the DHCP server port";
39 };
40
41 quick = mkOption {
42 description = lib.mdDoc "Which quick option to use";
43 default = "xyz";
44 type = types.enum [ "arch" "centos" "coreos" "debian" "fedora" "ubuntu" "xyz" ];
45 };
46
47 kernel = mkOption {
48 type = types.str or types.path;
49 default = "";
50 description = lib.mdDoc "Kernel path. Ignored unless mode is set to 'boot'";
51 };
52
53 initrd = mkOption {
54 type = types.str or types.path;
55 default = "";
56 description = lib.mdDoc "Initrd path. Ignored unless mode is set to 'boot'";
57 };
58
59 cmdLine = mkOption {
60 type = types.str;
61 default = "";
62 description = lib.mdDoc "Kernel commandline arguments. Ignored unless mode is set to 'boot'";
63 };
64
65 listen = mkOption {
66 type = types.str;
67 default = "0.0.0.0";
68 description = lib.mdDoc "IPv4 address to listen on";
69 };
70
71 port = mkOption {
72 type = types.port;
73 default = 80;
74 description = lib.mdDoc "Port to listen on for HTTP";
75 };
76
77 statusPort = mkOption {
78 type = types.port;
79 default = 80;
80 description = lib.mdDoc "HTTP port for status information (can be the same as --port)";
81 };
82
83 apiServer = mkOption {
84 type = types.str;
85 example = "localhost:8080";
86 description = lib.mdDoc "host:port to connect to the API. Ignored unless mode is set to 'api'";
87 };
88
89 extraArguments = mkOption {
90 type = types.listOf types.str;
91 default = [];
92 description = lib.mdDoc "Additional command line arguments to pass to Pixiecore";
93 };
94 };
95 };
96
97 config = mkIf cfg.enable {
98 users.groups.pixiecore = {};
99 users.users.pixiecore = {
100 description = "Pixiecore daemon user";
101 group = "pixiecore";
102 isSystemUser = true;
103 };
104
105 networking.firewall = mkIf cfg.openFirewall {
106 allowedTCPPorts = [ 4011 cfg.port cfg.statusPort ];
107 allowedUDPPorts = [ 67 69 ];
108 };
109
110 systemd.services.pixiecore = {
111 description = "Pixiecore server";
112 after = [ "network.target"];
113 wants = [ "network.target"];
114 wantedBy = [ "multi-user.target"];
115 serviceConfig = {
116 User = "pixiecore";
117 Restart = "always";
118 AmbientCapabilities = [ "cap_net_bind_service" ] ++ optional cfg.dhcpNoBind "cap_net_raw";
119 ExecStart =
120 let
121 argString =
122 if cfg.mode == "boot"
123 then [ "boot" cfg.kernel ]
124 ++ optional (cfg.initrd != "") cfg.initrd
125 ++ optionals (cfg.cmdLine != "") [ "--cmdline" cfg.cmdLine ]
126 else if cfg.mode == "quick"
127 then [ "quick" cfg.quick ]
128 else [ "api" cfg.apiServer ];
129 in
130 ''
131 ${pkgs.pixiecore}/bin/pixiecore \
132 ${lib.escapeShellArgs argString} \
133 ${optionalString cfg.debug "--debug"} \
134 ${optionalString cfg.dhcpNoBind "--dhcp-no-bind"} \
135 --listen-addr ${lib.escapeShellArg cfg.listen} \
136 --port ${toString cfg.port} \
137 --status-port ${toString cfg.statusPort} \
138 ${escapeShellArgs cfg.extraArguments}
139 '';
140 };
141 };
142 };
143}