mirror of
https://github.com/nix-community/nix-on-droid.git
synced 2025-12-07 17:41:05 +01:00
Merge ba1526a6ba into 1c306c07b3
This commit is contained in:
commit
a1b13abe90
4 changed files with 358 additions and 0 deletions
|
|
@ -25,6 +25,12 @@ writeText "login-inner" ''
|
||||||
fi
|
fi
|
||||||
''}
|
''}
|
||||||
|
|
||||||
|
${lib.optionalString config.supervisord.enable ''
|
||||||
|
(if [ ! -e "${config.supervisord.socketPath}" ]; then
|
||||||
|
${config.supervisord.package}/bin/supervisord -c /etc/supervisord.conf || echo "Warning: supervisord failed to start"
|
||||||
|
fi&)
|
||||||
|
''}
|
||||||
|
|
||||||
${lib.optionalString config.build.initialBuild ''
|
${lib.optionalString config.build.initialBuild ''
|
||||||
if [ -e /etc/UNINTIALISED ]; then
|
if [ -e /etc/UNINTIALISED ]; then
|
||||||
export HOME="${config.user.home}"
|
export HOME="${config.user.home}"
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,8 @@
|
||||||
./environment/shell.nix
|
./environment/shell.nix
|
||||||
./home-manager.nix
|
./home-manager.nix
|
||||||
./nixpkgs/options.nix
|
./nixpkgs/options.nix
|
||||||
|
./services/openssh.nix
|
||||||
|
./supervisord.nix
|
||||||
./terminal.nix
|
./terminal.nix
|
||||||
./time.nix
|
./time.nix
|
||||||
./upgrade.nix
|
./upgrade.nix
|
||||||
|
|
|
||||||
141
modules/services/openssh.nix
Normal file
141
modules/services/openssh.nix
Normal file
|
|
@ -0,0 +1,141 @@
|
||||||
|
# Copyright (c) 2019-2022, see AUTHORS. Licensed under MIT License, see LICENSE.
|
||||||
|
|
||||||
|
# Parts from nixpkgs/nixos/modules/services/networking/ssh/sshd.nix
|
||||||
|
# MIT Licensed. Copyright (c) 2003-2022 Eelco Dolstra and the Nixpkgs/NixOS contributors
|
||||||
|
|
||||||
|
{ pkgs, lib, config, ... }:
|
||||||
|
let
|
||||||
|
inherit (lib) types;
|
||||||
|
|
||||||
|
cfg = config.services.openssh;
|
||||||
|
|
||||||
|
uncheckedConf = ''
|
||||||
|
${lib.concatMapStrings (port: ''
|
||||||
|
Port ${toString port}
|
||||||
|
'') cfg.ports}
|
||||||
|
PasswordAuthentication no
|
||||||
|
${lib.flip lib.concatMapStrings cfg.hostKeys (k: ''
|
||||||
|
HostKey ${k.path}
|
||||||
|
'')}
|
||||||
|
${lib.optionalString cfg.allowSFTP ''
|
||||||
|
Subsystem sftp ${cfg.package}/libexec/sftp-server
|
||||||
|
''}
|
||||||
|
SetEnv PATH=${config.user.home}/.nix-profile/bin:/usr/bin:/bin
|
||||||
|
${cfg.extraConfig}
|
||||||
|
'';
|
||||||
|
|
||||||
|
sshdConf = pkgs.runCommand "sshd.conf-validated" {
|
||||||
|
nativeBuildInputs = [ cfg.package ];
|
||||||
|
} ''
|
||||||
|
cat >$out <<EOL
|
||||||
|
${uncheckedConf}
|
||||||
|
EOL
|
||||||
|
|
||||||
|
ssh-keygen -q -f mock-hostkey -N ""
|
||||||
|
sshd -t -f $out -h mock-hostkey
|
||||||
|
'';
|
||||||
|
in {
|
||||||
|
options = {
|
||||||
|
services.openssh = {
|
||||||
|
enable = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Whether to enable the OpenSSH secure shell daemon, which
|
||||||
|
allows secure remote logins.
|
||||||
|
'';
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
};
|
||||||
|
autostart = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Whether to automatically start the OpenSSH daemon.
|
||||||
|
|
||||||
|
If false, the server has to be manually started using
|
||||||
|
`supervisorctl`.
|
||||||
|
'';
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
};
|
||||||
|
package = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
The package to use for OpenSSH.
|
||||||
|
'';
|
||||||
|
type = types.package;
|
||||||
|
default = pkgs.openssh;
|
||||||
|
defaultText = lib.literalExpression "pkgs.openssh";
|
||||||
|
};
|
||||||
|
ports = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Specifies on which ports the SSH daemon listens.
|
||||||
|
'';
|
||||||
|
type = types.listOf types.port;
|
||||||
|
default = [ 8022 ];
|
||||||
|
};
|
||||||
|
allowSFTP = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Whether to enable the SFTP subsystem in the SSH daemon. This
|
||||||
|
enables the use of commands such as {command}`sftp` and
|
||||||
|
{command}`sshfs`.
|
||||||
|
'';
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
};
|
||||||
|
hostKeys = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Nix-on-Droid can automatically generate SSH host keys. This option
|
||||||
|
specifies the path, type and size of each key. See
|
||||||
|
{manpage}`ssh-keygen(1)` for supported types
|
||||||
|
and sizes.
|
||||||
|
'';
|
||||||
|
type = types.listOf types.attrs;
|
||||||
|
default =
|
||||||
|
[ { type = "rsa"; bits = 4096; path = "/etc/ssh/ssh_host_rsa_key"; }
|
||||||
|
{ type = "ed25519"; path = "/etc/ssh/ssh_host_ed25519_key"; }
|
||||||
|
];
|
||||||
|
example =
|
||||||
|
[ { type = "rsa"; bits = 4096; path = "/etc/ssh/ssh_host_rsa_key"; rounds = 100; openSSHFormat = true; }
|
||||||
|
{ type = "ed25519"; path = "/etc/ssh/ssh_host_ed25519_key"; rounds = 100; comment = "key comment"; }
|
||||||
|
];
|
||||||
|
};
|
||||||
|
extraConfig = lib.mkOption {
|
||||||
|
description = "Verbatim contents of {file}`sshd_config`.";
|
||||||
|
type = types.lines;
|
||||||
|
default = "";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
environment.etc = {
|
||||||
|
"ssh/sshd_config".source = sshdConf;
|
||||||
|
"ssh/moduli".source = "${cfg.package}/etc/ssh/moduli";
|
||||||
|
};
|
||||||
|
|
||||||
|
supervisord.programs.sshd = {
|
||||||
|
inherit (cfg) autostart;
|
||||||
|
path = [ cfg.package pkgs.coreutils ];
|
||||||
|
autoRestart = true;
|
||||||
|
script = ''
|
||||||
|
# don't write to stdout
|
||||||
|
exec >&2
|
||||||
|
|
||||||
|
${lib.flip lib.concatMapStrings cfg.hostKeys (k: ''
|
||||||
|
if ! [ -s "${k.path}" ]; then
|
||||||
|
if ! [ -h "${k.path}" ]; then
|
||||||
|
rm -f "${k.path}"
|
||||||
|
fi
|
||||||
|
mkdir -m 0755 -p "$(dirname '${k.path}')"
|
||||||
|
ssh-keygen \
|
||||||
|
-t "${k.type}" \
|
||||||
|
${if k ? bits then "-b ${toString k.bits}" else ""} \
|
||||||
|
${if k ? rounds then "-a ${toString k.rounds}" else ""} \
|
||||||
|
${if k ? comment then "-C '${k.comment}'" else ""} \
|
||||||
|
${if k ? openSSHFormat && k.openSSHFormat then "-o" else ""} \
|
||||||
|
-f "${k.path}" \
|
||||||
|
-N ""
|
||||||
|
fi
|
||||||
|
'')}
|
||||||
|
|
||||||
|
exec ${cfg.package}/bin/sshd -D -f /etc/ssh/sshd_config
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
209
modules/supervisord.nix
Normal file
209
modules/supervisord.nix
Normal file
|
|
@ -0,0 +1,209 @@
|
||||||
|
# Copyright (c) 2019-2022, see AUTHORS. Licensed under MIT License, see LICENSE.
|
||||||
|
|
||||||
|
{ pkgs, lib, config, ... }:
|
||||||
|
let
|
||||||
|
inherit (lib) types;
|
||||||
|
|
||||||
|
cfg = config.supervisord;
|
||||||
|
|
||||||
|
format = pkgs.formats.ini {};
|
||||||
|
|
||||||
|
programType = types.submodule ({ name, config, ... }: {
|
||||||
|
options = {
|
||||||
|
enable = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Whether to enable this program.
|
||||||
|
'';
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
};
|
||||||
|
command = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
The command that will be run as the service's main process.
|
||||||
|
'';
|
||||||
|
type = types.str;
|
||||||
|
};
|
||||||
|
script = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Shell commands executed as the service's main process.
|
||||||
|
'';
|
||||||
|
type = types.lines;
|
||||||
|
default = "";
|
||||||
|
};
|
||||||
|
path = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Packages added to the service's PATH environment variable.
|
||||||
|
'';
|
||||||
|
type = types.listOf (types.either types.package types.str);
|
||||||
|
default = [];
|
||||||
|
};
|
||||||
|
autostart = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Whether to automatically start the process.
|
||||||
|
|
||||||
|
If false, the process has to be manually started using
|
||||||
|
`supervisorctl`.
|
||||||
|
'';
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
};
|
||||||
|
autoRestart = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Whether to automatically restart the process if it exits.
|
||||||
|
|
||||||
|
If `unexpected`, the process will be restarted if it exits
|
||||||
|
with an exit code not listed in the programs's `exitcodes`
|
||||||
|
configuration.
|
||||||
|
'';
|
||||||
|
type = types.either types.bool (types.enum [ "unexpected" ]);
|
||||||
|
default = "unexpected";
|
||||||
|
};
|
||||||
|
environment = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Environment variables passed to the service's process.
|
||||||
|
'';
|
||||||
|
type = types.attrsOf types.str;
|
||||||
|
default = {};
|
||||||
|
};
|
||||||
|
extraConfig = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Extra structured configurations to add to the [program:x] section.
|
||||||
|
'';
|
||||||
|
type = types.attrsOf (types.either types.str types.bool);
|
||||||
|
default = {};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config = {
|
||||||
|
command = lib.mkIf (config.script != "")
|
||||||
|
(toString (pkgs.writeShellScript "${name}-script.sh" ''
|
||||||
|
set -e
|
||||||
|
${config.script}
|
||||||
|
''));
|
||||||
|
|
||||||
|
environment.PATH = lib.mkDefault (lib.makeBinPath config.path);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
renderAtom = val:
|
||||||
|
if builtins.isBool val then if val then "true" else "false"
|
||||||
|
else toString val;
|
||||||
|
|
||||||
|
renderProgram = program: let
|
||||||
|
section = {
|
||||||
|
inherit (program) command autostart;
|
||||||
|
autorestart = program.autoRestart;
|
||||||
|
environment = let
|
||||||
|
# FIXME: Make more robust
|
||||||
|
escape = s: builtins.replaceStrings [ "%" ] [ "%%" ] s;
|
||||||
|
envs = lib.mapAttrsToList (k: v: "${k}=\"${escape v}\"") program.environment;
|
||||||
|
in builtins.concatStringsSep "," envs;
|
||||||
|
} // program.extraConfig;
|
||||||
|
in lib.mapAttrs (_: v: renderAtom v) section;
|
||||||
|
|
||||||
|
numPrograms = builtins.length (builtins.attrNames enabledPrograms);
|
||||||
|
enabledPrograms = lib.filterAttrs (_: program: program.enable) cfg.programs;
|
||||||
|
|
||||||
|
structuredConfig = {
|
||||||
|
supervisord = {
|
||||||
|
logfile = cfg.logPath;
|
||||||
|
pidfile = cfg.pidPath;
|
||||||
|
};
|
||||||
|
supervisorctl = {
|
||||||
|
serverurl = "unix://${cfg.socketPath}";
|
||||||
|
};
|
||||||
|
unix_http_server = {
|
||||||
|
file = cfg.socketPath;
|
||||||
|
};
|
||||||
|
"rpcinterface:supervisor" = {
|
||||||
|
"supervisor.rpcinterface_factory" = "supervisor.rpcinterface:make_main_rpcinterface";
|
||||||
|
};
|
||||||
|
} // (lib.mapAttrs' (k: v: {
|
||||||
|
name = "program:${k}";
|
||||||
|
value = renderProgram v;
|
||||||
|
}) enabledPrograms);
|
||||||
|
|
||||||
|
configFile = format.generate "supervisord.conf" structuredConfig;
|
||||||
|
|
||||||
|
# Only expose the "supervisorctl" executable
|
||||||
|
supervisorctl = pkgs.runCommand "supervisorctl" {} ''
|
||||||
|
mkdir -p $out/bin
|
||||||
|
ln -s ${cfg.package}/bin/supervisorctl $out/bin/supervisorctl
|
||||||
|
'';
|
||||||
|
in {
|
||||||
|
options = {
|
||||||
|
supervisord = {
|
||||||
|
enable = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Whether to enable the supervisord process control system.
|
||||||
|
|
||||||
|
This allows you to define long-running services in Nix-on-Droid.
|
||||||
|
'';
|
||||||
|
type = types.bool;
|
||||||
|
default = numPrograms != 0;
|
||||||
|
};
|
||||||
|
package = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
The supervisord package to use.
|
||||||
|
'';
|
||||||
|
type = types.package;
|
||||||
|
default = pkgs.python3Packages.supervisor;
|
||||||
|
defaultText = lib.literalExpression "pkgs.python3Packages.supervisor";
|
||||||
|
};
|
||||||
|
socketPath = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Path to the UNIX domain socket on which supervisord will listen on.
|
||||||
|
'';
|
||||||
|
type = types.path;
|
||||||
|
default = "/tmp/supervisor.sock";
|
||||||
|
};
|
||||||
|
pidPath = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Path to the file in which supervisord saves its PID.
|
||||||
|
'';
|
||||||
|
type = types.path;
|
||||||
|
default = "/tmp/supervisor.pid";
|
||||||
|
};
|
||||||
|
logPath = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Path to the log file.
|
||||||
|
'';
|
||||||
|
type = types.path;
|
||||||
|
default = "/tmp/supervisor.log";
|
||||||
|
};
|
||||||
|
programs = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Definition of supervisord programs.
|
||||||
|
|
||||||
|
Upstream documentations are available at <http://supervisord.org/configuration.html#program-x-section-settings>.
|
||||||
|
'';
|
||||||
|
type = types.attrsOf programType;
|
||||||
|
default = {};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
assertions = lib.flatten (lib.mapAttrsToList (name: program: let
|
||||||
|
envAsserts = lib.mapAttrsToList (k: v: {
|
||||||
|
assertion = !(lib.hasInfix "\"" v);
|
||||||
|
message = "supervisord.programs.${name}.environment.${k}: Value cannot have double quotes at the moment (${v})";
|
||||||
|
}) program.environment;
|
||||||
|
in envAsserts) cfg.programs);
|
||||||
|
|
||||||
|
environment.etc."supervisord.conf" = {
|
||||||
|
source = configFile;
|
||||||
|
};
|
||||||
|
|
||||||
|
environment.packages = [ supervisorctl ];
|
||||||
|
|
||||||
|
build.activationAfter.reloadSupervisord = ''
|
||||||
|
if [ ! -e "${config.supervisord.socketPath}" ]; then
|
||||||
|
echo "Starting supervisord..."
|
||||||
|
$DRY_RUN_CMD ${cfg.package}/bin/supervisord -c /etc/supervisord.conf
|
||||||
|
else
|
||||||
|
echo "Reloading supervisord..."
|
||||||
|
$DRY_RUN_CMD ${cfg.package}/bin/supervisorctl -c /etc/supervisord.conf update
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue