commit
4007aa201b
@ -0,0 +1,14 @@ |
||||
{ lib, ... }: { |
||||
options.dummy = lib.mkOption { type = lib.types.anything; default = {}; }; |
||||
freeformType = |
||||
let |
||||
a = lib.types.attrsOf (lib.types.submodule { options.bar = lib.mkOption { }; }); |
||||
in |
||||
# modifying types like this breaks type merging. |
||||
# This test makes sure that type merging is not performed when only a single declaration exists. |
||||
# Don't modify types in practice! |
||||
a // { |
||||
merge = loc: defs: { freeformItems = a.merge loc defs; }; |
||||
}; |
||||
config.foo.bar = "ok"; |
||||
} |
@ -0,0 +1,10 @@ |
||||
{ lib, ... }: |
||||
let |
||||
inherit (lib) mkOption types; |
||||
in |
||||
{ |
||||
options.bare-submodule.deep = mkOption { |
||||
type = types.int; |
||||
default = 2; |
||||
}; |
||||
} |
@ -0,0 +1,10 @@ |
||||
{ lib, ... }: |
||||
let |
||||
inherit (lib) mkOption types; |
||||
in |
||||
{ |
||||
options.bare-submodule.deep = mkOption { |
||||
type = types.int; |
||||
default = 2; |
||||
}; |
||||
} |
@ -0,0 +1,19 @@ |
||||
{ config, lib, ... }: |
||||
let |
||||
inherit (lib) mkOption types; |
||||
in |
||||
{ |
||||
options.bare-submodule = mkOption { |
||||
type = types.submoduleWith { |
||||
shorthandOnlyDefinesConfig = config.shorthandOnlyDefinesConfig; |
||||
modules = [ |
||||
{ |
||||
options.nested = mkOption { |
||||
type = types.int; |
||||
default = 1; |
||||
}; |
||||
} |
||||
]; |
||||
}; |
||||
}; |
||||
} |
@ -0,0 +1,18 @@ |
||||
{ config, lib, ... }: |
||||
let |
||||
inherit (lib) mkOption types; |
||||
in |
||||
{ |
||||
options.bare-submodule = mkOption { |
||||
type = types.submoduleWith { |
||||
modules = [ ]; |
||||
shorthandOnlyDefinesConfig = config.shorthandOnlyDefinesConfig; |
||||
}; |
||||
default = {}; |
||||
}; |
||||
|
||||
# config-dependent options: won't recommend, but useful for making this test parameterized |
||||
options.shorthandOnlyDefinesConfig = mkOption { |
||||
default = false; |
||||
}; |
||||
} |
@ -0,0 +1,12 @@ |
||||
{ lib, ... }: |
||||
|
||||
{ |
||||
options.set = lib.mkOption { |
||||
default = { }; |
||||
example = { a = 1; }; |
||||
type = lib.types.attrsOf lib.types.int; |
||||
description = '' |
||||
Some descriptive text |
||||
''; |
||||
}; |
||||
} |
@ -0,0 +1,4 @@ |
||||
{ |
||||
bare-submodule.nested = 42; |
||||
bare-submodule.deep = 420; |
||||
} |
@ -0,0 +1 @@ |
||||
{ shorthandOnlyDefinesConfig = true; } |
@ -0,0 +1,19 @@ |
||||
{ config, lib, pkgs, ... }: |
||||
|
||||
with lib; |
||||
|
||||
let |
||||
cfg = config.programs.nbd; |
||||
in |
||||
{ |
||||
options = { |
||||
programs.nbd = { |
||||
enable = mkEnableOption "Network Block Device (nbd) support"; |
||||
}; |
||||
}; |
||||
|
||||
config = mkIf cfg.enable { |
||||
environment.systemPackages = with pkgs; [ nbd ]; |
||||
boot.kernelModules = [ "nbd" ]; |
||||
}; |
||||
} |
@ -1,50 +1,46 @@ |
||||
{ config, lib, pkgs, ... }: |
||||
|
||||
with lib; |
||||
|
||||
let |
||||
inherit (lib) mkEnableOption mkIf mkOption optionalString types; |
||||
|
||||
dataDir = "/var/lib/squeezelite"; |
||||
cfg = config.services.squeezelite; |
||||
pkg = if cfg.pulseAudio then pkgs.squeezelite-pulse else pkgs.squeezelite; |
||||
bin = "${pkg}/bin/${pkg.pname}"; |
||||
|
||||
in { |
||||
in |
||||
{ |
||||
|
||||
###### interface |
||||
|
||||
options = { |
||||
|
||||
services.squeezelite= { |
||||
options.services.squeezelite = { |
||||
enable = mkEnableOption "Squeezelite, a software Squeezebox emulator"; |
||||
|
||||
enable = mkEnableOption "Squeezelite, a software Squeezebox emulator"; |
||||
|
||||
extraArguments = mkOption { |
||||
default = ""; |
||||
type = types.str; |
||||
description = '' |
||||
Additional command line arguments to pass to Squeezelite. |
||||
''; |
||||
}; |
||||
pulseAudio = mkEnableOption "pulseaudio support"; |
||||
|
||||
extraArguments = mkOption { |
||||
default = ""; |
||||
type = types.str; |
||||
description = '' |
||||
Additional command line arguments to pass to Squeezelite. |
||||
''; |
||||
}; |
||||
|
||||
}; |
||||
|
||||
|
||||
###### implementation |
||||
|
||||
config = mkIf cfg.enable { |
||||
|
||||
systemd.services.squeezelite= { |
||||
systemd.services.squeezelite = { |
||||
wantedBy = [ "multi-user.target" ]; |
||||
after = [ "network.target" "sound.target" ]; |
||||
description = "Software Squeezebox emulator"; |
||||
serviceConfig = { |
||||
DynamicUser = true; |
||||
ExecStart = "${pkgs.squeezelite}/bin/squeezelite -N ${dataDir}/player-name ${cfg.extraArguments}"; |
||||
ExecStart = "${bin} -N ${dataDir}/player-name ${cfg.extraArguments}"; |
||||
StateDirectory = builtins.baseNameOf dataDir; |
||||
SupplementaryGroups = "audio"; |
||||
}; |
||||
}; |
||||
|
||||
}; |
||||
|
||||
} |
||||
|
@ -0,0 +1,112 @@ |
||||
{ config, lib, pkgs, ... }: |
||||
|
||||
with lib; |
||||
let |
||||
cfg = config.services.corosync; |
||||
in |
||||
{ |
||||
# interface |
||||
options.services.corosync = { |
||||
enable = mkEnableOption "corosync"; |
||||
|
||||
package = mkOption { |
||||
type = types.package; |
||||
default = pkgs.corosync; |
||||
defaultText = literalExpression "pkgs.corosync"; |
||||
description = "Package that should be used for corosync."; |
||||
}; |
||||
|
||||
clusterName = mkOption { |
||||
type = types.str; |
||||
default = "nixcluster"; |
||||
description = "Name of the corosync cluster."; |
||||
}; |
||||
|
||||
extraOptions = mkOption { |
||||
type = with types; listOf str; |
||||
default = []; |
||||
description = "Additional options with which to start corosync."; |
||||
}; |
||||
|
||||
nodelist = mkOption { |
||||
description = "Corosync nodelist: all cluster members."; |
||||
default = []; |
||||
type = with types; listOf (submodule { |
||||
options = { |
||||
nodeid = mkOption { |
||||
type = int; |
||||
description = "Node ID number"; |
||||
}; |
||||
name = mkOption { |
||||
type = str; |
||||
description = "Node name"; |
||||
}; |
||||
ring_addrs = mkOption { |
||||
type = listOf str; |
||||
description = "List of addresses, one for each ring."; |
||||
}; |
||||
}; |
||||
}); |
||||
}; |
||||
}; |
||||
|
||||
# implementation |
||||
config = mkIf cfg.enable { |
||||
environment.systemPackages = [ cfg.package ]; |
||||
|
||||
environment.etc."corosync/corosync.conf".text = '' |
||||
totem { |
||||
version: 2 |
||||
secauth: on |
||||
cluster_name: ${cfg.clusterName} |
||||
transport: knet |
||||
} |
||||
|
||||
nodelist { |
||||
${concatMapStrings ({ nodeid, name, ring_addrs }: '' |
||||
node { |
||||
nodeid: ${toString nodeid} |
||||
name: ${name} |
||||
${concatStrings (imap0 (i: addr: '' |
||||
ring${toString i}_addr: ${addr} |
||||
'') ring_addrs)} |
||||
} |
||||
'') cfg.nodelist} |
||||
} |
||||
|
||||
quorum { |
||||
# only corosync_votequorum is supported |
||||
provider: corosync_votequorum |
||||
wait_for_all: 0 |
||||
${optionalString (builtins.length cfg.nodelist < 3) '' |
||||
two_node: 1 |
||||
''} |
||||
} |
||||
|
||||
logging { |
||||
to_syslog: yes |
||||
} |
||||
''; |
||||
|
||||
environment.etc."corosync/uidgid.d/root".text = '' |
||||
# allow pacemaker connection by root |
||||
uidgid { |
||||
uid: 0 |
||||
gid: 0 |
||||
} |
||||
''; |
||||
|
||||
systemd.packages = [ cfg.package ]; |
||||
systemd.services.corosync = { |
||||
wantedBy = [ "multi-user.target" ]; |
||||
serviceConfig = { |
||||
StateDirectory = "corosync"; |
||||
StateDirectoryMode = "0700"; |
||||
}; |
||||
}; |
||||
|
||||
environment.etc."sysconfig/corosync".text = lib.optionalString (cfg.extraOptions != []) '' |
||||
COROSYNC_OPTIONS="${lib.escapeShellArgs cfg.extraOptions}" |
||||
''; |
||||
}; |
||||
} |
@ -0,0 +1,52 @@ |
||||
{ config, lib, pkgs, ... }: |
||||
|
||||
with lib; |
||||
let |
||||
cfg = config.services.pacemaker; |
||||
in |
||||
{ |
||||
# interface |
||||
options.services.pacemaker = { |
||||
enable = mkEnableOption "pacemaker"; |
||||
|
||||
package = mkOption { |
||||
type = types.package; |
||||
default = pkgs.pacemaker; |
||||
defaultText = literalExpression "pkgs.pacemaker"; |
||||
description = "Package that should be used for pacemaker."; |
||||
}; |
||||
}; |
||||
|
||||
# implementation |
||||
config = mkIf cfg.enable { |
||||
assertions = [ { |
||||
assertion = config.services.corosync.enable; |
||||
message = '' |
||||
Enabling services.pacemaker requires a services.corosync configuration. |
||||
''; |
||||
} ]; |
||||
|
||||
environment.systemPackages = [ cfg.package ]; |
||||
|
||||
# required by pacemaker |
||||
users.users.hacluster = { |
||||
isSystemUser = true; |
||||
group = "pacemaker"; |
||||
home = "/var/lib/pacemaker"; |
||||
}; |
||||
users.groups.pacemaker = {}; |
||||
|
||||
systemd.tmpfiles.rules = [ |
||||
"d /var/log/pacemaker 0700 hacluster pacemaker -" |
||||
]; |
||||
|
||||
systemd.packages = [ cfg.package ]; |
||||
systemd.services.pacemaker = { |
||||
wantedBy = [ "multi-user.target" ]; |
||||
serviceConfig = { |
||||
StateDirectory = "pacemaker"; |
||||
StateDirectoryMode = "0700"; |
||||
}; |
||||
}; |
||||
}; |
||||
} |
@ -0,0 +1,117 @@ |
||||
{ config, lib, pkgs, options }: |
||||
|
||||
with lib; |
||||
|
||||
let |
||||
cfg = config.services.prometheus.exporters.dmarc; |
||||
|
||||
json = builtins.toJSON { |
||||
inherit (cfg) folders port; |
||||
listen_addr = cfg.listenAddress; |
||||
storage_path = "$STATE_DIRECTORY"; |
||||
imap = (builtins.removeAttrs cfg.imap [ "passwordFile" ]) // { password = "$IMAP_PASSWORD"; use_ssl = true; }; |
||||
poll_interval_seconds = cfg.pollIntervalSeconds; |
||||
deduplication_max_seconds = cfg.deduplicationMaxSeconds; |
||||
logging = { |
||||
version = 1; |
||||
disable_existing_loggers = false; |
||||
}; |
||||
}; |
||||
in { |
||||
port = 9797; |
||||
extraOpts = { |
||||
imap = { |
||||
host = mkOption { |
||||
type = types.str; |
||||
default = "localhost"; |
||||
description = '' |
||||
Hostname of IMAP server to connect to. |
||||
''; |
||||
}; |
||||
port = mkOption { |
||||
type = types.port; |
||||
default = 993; |
||||
description = '' |
||||
Port of the IMAP server to connect to. |
||||
''; |
||||
}; |
||||
username = mkOption { |
||||
type = types.str; |
||||
example = "postmaster@example.org"; |
||||
description = '' |
||||
Login username for the IMAP connection. |
||||
''; |
||||
}; |
||||
passwordFile = mkOption { |
||||
type = types.str; |
||||
example = "/run/secrets/dovecot_pw"; |
||||
description = '' |
||||
File containing the login password for the IMAP connection. |
||||
''; |
||||
}; |
||||
}; |
||||
folders = { |
||||
inbox = mkOption { |
||||
type = types.str; |
||||
default = "INBOX"; |
||||
description = '' |
||||
IMAP mailbox that is checked for incoming DMARC aggregate reports |
||||
''; |
||||
}; |
||||
done = mkOption { |
||||
type = types.str; |
||||
default = "Archive"; |
||||
description = '' |
||||
IMAP mailbox that successfully processed reports are moved to. |
||||
''; |
||||
}; |
||||
error = mkOption { |
||||
type = types.str; |
||||
default = "Invalid"; |
||||
description = '' |
||||
IMAP mailbox that emails are moved to that could not be processed. |
||||
''; |
||||
}; |
||||
}; |
||||
pollIntervalSeconds = mkOption { |
||||
type = types.ints.unsigned; |
||||
default = 60; |
||||
description = '' |
||||
How often to poll the IMAP server in seconds. |
||||
''; |
||||
}; |
||||
deduplicationMaxSeconds = mkOption { |
||||
type = types.ints.unsigned; |
||||
default = 604800; |
||||
defaultText = "7 days (in seconds)"; |
||||
description = '' |
||||
How long individual report IDs will be remembered to avoid |
||||
counting double delivered reports twice. |
||||
''; |
||||
}; |
||||
debug = mkOption { |
||||
type = types.bool; |
||||
default = false; |
||||
description = '' |
||||
Whether to declare enable <literal>--debug</literal>. |
||||
''; |
||||
}; |
||||
}; |
||||
serviceOpts = { |
||||
path = with pkgs; [ envsubst coreutils ]; |
||||
serviceConfig = { |
||||
StateDirectory = "prometheus-dmarc-exporter"; |
||||
WorkingDirectory = "/var/lib/prometheus-dmarc-exporter"; |
||||
ExecStart = "${pkgs.writeShellScript "setup-cfg" '' |
||||
export IMAP_PASSWORD="$(<${cfg.imap.passwordFile})" |
||||
envsubst \ |
||||
-i ${pkgs.writeText "dmarc-exporter.json.template" json} \ |
||||
-o ''${STATE_DIRECTORY}/dmarc-exporter.json |
||||
|
||||
exec ${pkgs.prometheus-dmarc-exporter}/bin/prometheus-dmarc-exporter \ |
||||
--configuration /var/lib/prometheus-dmarc-exporter/dmarc-exporter.json \ |
||||
${optionalString cfg.debug "--debug"} |
||||
''}"; |
||||
}; |
||||
}; |
||||
} |
@ -0,0 +1,118 @@ |
||||
{ config, lib, pkgs, options }: |
||||
|
||||
with lib; |
||||
let |
||||
cfg = config.services.prometheus.exporters.pve; |
||||
|
||||
# pve exporter requires a config file so create an empty one if configFile is not provided |
||||
emptyConfigFile = pkgs.writeTextFile { |
||||
name = "pve.yml"; |
||||
text = "default:"; |
||||
}; |
||||
|
||||
computedConfigFile = "${if cfg.configFile == null then emptyConfigFile else cfg.configFile}"; |
||||
in |
||||
{ |
||||
port = 9221; |
||||
extraOpts = { |
||||
package = mkOption { |
||||
type = types.package; |
||||
default = pkgs.prometheus-pve-exporter; |
||||
defaultText = literalExpression "pkgs.prometheus-pve-exporter"; |
||||
example = literalExpression "pkgs.prometheus-pve-exporter"; |
||||
description = '' |
||||
The package to use for prometheus-pve-exporter |
||||
''; |
||||
}; |
||||
|
||||
environmentFile = mkOption { |
||||
type = with types; nullOr path; |
||||
default = null; |
||||
example = "/etc/prometheus-pve-exporter/pve.env"; |
||||
description = '' |
||||
Path to the service's environment file. This path can either be a computed path in /nix/store or a path in the local filesystem. |
||||
|
||||
The environment file should NOT be stored in /nix/store as it contains passwords and/or keys in plain text. |
||||
|
||||
Environment reference: https://github.com/prometheus-pve/prometheus-pve-exporter#authentication |
||||
''; |
||||
}; |
||||
|
||||
configFile = mkOption { |
||||
type = with types; nullOr path; |
||||
default = null; |
||||
example = "/etc/prometheus-pve-exporter/pve.yml"; |
||||
description = '' |
||||
Path to the service's config file. This path can either be a computed path in /nix/store or a path in the local filesystem. |
||||
|
||||
The config file should NOT be stored in /nix/store as it will contain passwords and/or keys in plain text. |
||||
|
||||
If both configFile and environmentFile are provided, the configFile option will be ignored. |
||||
|
||||
Configuration reference: https://github.com/prometheus-pve/prometheus-pve-exporter/#authentication |
||||
''; |
||||
}; |
||||
|
||||
collectors = { |
||||
status = mkOption { |
||||
type = types.bool; |
||||
default = true; |
||||
description = '' |
||||
Collect Node/VM/CT status |
||||
''; |
||||
}; |
||||
version = mkOption { |
||||
type = types.bool; |
||||
default = true; |
||||
description = '' |
||||
Collect PVE version info |
||||
''; |
||||
}; |
||||
node = mkOption { |
||||
type = types.bool; |
||||
default = true; |
||||
description = '' |
||||
Collect PVE node info |
||||
''; |
||||
}; |
||||
cluster = mkOption { |
||||
type = types.bool; |
||||
default = true; |
||||
description = '' |
||||
Collect PVE cluster info |
||||
''; |
||||
}; |
||||
resources = mkOption { |
||||
type = types.bool; |
||||
default = true; |
||||
description = '' |
||||
Collect PVE resources info |
||||
''; |
||||
}; |
||||
config = mkOption { |
||||
type = types.bool; |
||||
default = true; |
||||
description = '' |
||||
Collect PVE onboot status |
||||
''; |
||||
}; |
||||
}; |
||||
}; |
||||
serviceOpts = { |
||||
serviceConfig = { |
||||
ExecStart = '' |
||||
${cfg.package}/bin/pve_exporter \ |
||||
--${if cfg.collectors.status == true then "" else "no-"}collector.status \ |
||||
--${if cfg.collectors.version == true then "" else "no-"}collector.version \ |
||||
--${if cfg.collectors.node == true then "" else "no-"}collector.node \ |
||||
--${if cfg.collectors.cluster == true then "" else "no-"}collector.cluster \ |
||||
--${if cfg.collectors.resources == true then "" else "no-"}collector.resources \ |
||||
--${if cfg.collectors.config == true then "" else "no-"}collector.config \ |
||||
${computedConfigFile} \ |
||||
${toString cfg.port} ${cfg.listenAddress} |
||||
''; |
||||
} // optionalAttrs (cfg.environmentFile != null) { |
||||
EnvironmentFile = cfg.environmentFile; |
||||
}; |
||||
}; |
||||
} |
@ -0,0 +1,146 @@ |
||||
{ config, lib, pkgs, ... }: |
||||
|
||||
with lib; |
||||
|
||||
let |
||||
cfg = config.services.nbd; |
||||
configFormat = pkgs.formats.ini { }; |
||||
iniFields = with types; attrsOf (oneOf [ bool int float str ]); |
||||
serverConfig = configFormat.generate "nbd-server-config" |
||||
({ |
||||
generic = |
||||
(cfg.server.extraOptions // { |
||||
user = "root"; |
||||
group = "root"; |
||||
port = cfg.server.listenPort; |
||||
} // (optionalAttrs (cfg.server.listenAddress != null) { |
||||
listenaddr = cfg.server.listenAddress; |
||||
})); |
||||
} |
||||
// (mapAttrs |
||||
(_: { path, allowAddresses, extraOptions }: |
||||
extraOptions // { |
||||
exportname = path; |
||||
} // (optionalAttrs (allowAddresses != null) { |
||||
authfile = pkgs.writeText "authfile" (concatStringsSep "\n" allowAddresses); |
||||
})) |
||||
cfg.server.exports) |
||||
); |
||||
splitLists = |
||||
partition |
||||
(path: hasPrefix "/dev/" path) |
||||
(mapAttrsToList (_: { path, ... }: path) cfg.server.exports); |
||||
allowedDevices = splitLists.right; |
||||
boundPaths = splitLists.wrong; |
||||
in |
||||
{ |
||||
options = { |
||||
services.nbd = { |
||||
server = { |
||||
enable = mkEnableOption "the Network Block Device (nbd) server"; |
||||
|
||||
listenPort = mkOption { |
||||
type = types.port; |
||||
default = 10809; |
||||
description = "Port to listen on. The port is NOT automatically opened in the firewall."; |
||||
}; |
||||
|
||||
extraOptions = mkOption { |
||||
type = iniFields; |
||||
default = { |
||||
allowlist = false; |
||||
}; |
||||
description = '' |
||||
Extra options for the server. See |
||||
<citerefentry><refentrytitle>nbd-server</refentrytitle> |
||||
<manvolnum>5</manvolnum></citerefentry>. |
||||
''; |
||||
}; |
||||
|
||||
exports = mkOption { |
||||
description = "Files or block devices to make available over the network."; |
||||
default = { }; |
||||
type = with types; attrsOf |
||||
(submodule { |
||||
options = { |
||||
path = mkOption { |
||||
type = str; |
||||
description = "File or block device to export."; |
||||
example = "/dev/sdb1"; |
||||
}; |
||||
|
||||
allowAddresses = mkOption { |
||||
type = nullOr (listOf str); |
||||
default = null; |
||||
example = [ "10.10.0.0/24" "127.0.0.1" ]; |
||||
description = "IPs and subnets that are authorized to connect for this device. If not specified, the server will allow all connections."; |
||||
}; |
||||
|
||||
extraOptions = mkOption { |
||||
type = iniFields; |
||||
default = { |
||||
flush = true; |
||||
fua = true; |
||||
}; |
||||
description = '' |
||||
Extra options for this export. See |
||||
<citerefentry><refentrytitle>nbd-server</refentrytitle> |
||||
<manvolnum>5</manvolnum></citerefentry>. |
||||
''; |
||||
}; |
||||
}; |
||||
}); |
||||
}; |
||||
|
||||
listenAddress = mkOption { |
||||
type = with types; nullOr str; |
||||
description = "Address to listen on. If not specified, the server will listen on all interfaces."; |
||||
default = null; |
||||
example = "10.10.0.1"; |
||||
}; |
||||
}; |
||||
}; |
||||
}; |
||||
|
||||
config = mkIf cfg.server.enable { |
||||
boot.kernelModules = [ "nbd" ]; |
||||
|
||||
systemd.services.nbd-server = { |
||||
after = [ "network-online.target" ]; |
||||
before = [ "multi-user.target" ]; |
||||
wantedBy = [ "multi-user.target" ]; |
||||
serviceConfig = { |
||||
ExecStart = "${pkgs.nbd}/bin/nbd-server -C ${serverConfig}"; |
||||
Type = "forking"; |
||||
|
||||
DeviceAllow = map (path: "${path} rw") allowedDevices; |
||||
BindPaths = boundPaths; |
||||
|
||||
CapabilityBoundingSet = ""; |
||||
DevicePolicy = "closed"; |
||||
LockPersonality = true; |
||||
MemoryDenyWriteExecute = true; |
||||
NoNewPrivileges = true; |
||||
PrivateDevices = false; |
||||
PrivateMounts = true; |
||||
PrivateTmp = true; |
||||
PrivateUsers = true; |
||||
ProcSubset = "pid"; |
||||
ProtectClock = true; |
||||
ProtectControlGroups = true; |
||||
ProtectHome = true; |
||||
ProtectHostname = true; |
||||
ProtectKernelLogs = true; |
||||
ProtectKernelModules = true; |
||||
ProtectKernelTunables = true; |
||||
ProtectProc = "noaccess"; |
||||
ProtectSystem = "strict"; |
||||
RestrictAddressFamilies = "AF_INET AF_INET6"; |
||||
RestrictNamespaces = true; |
||||
RestrictRealtime = true; |
||||
RestrictSUIDSGID = true; |
||||
UMask = "0077"; |
||||
}; |
||||
}; |
||||
}; |
||||
} |
@ -0,0 +1,27 @@ |
||||
{ config, lib, pkgs, ... }: |
||||
|
||||
let |
||||
cfg = config.services.systembus-notify; |
||||
|
||||
inherit (lib) mkEnableOption mkIf; |
||||
|
||||
in |
||||
{ |
||||
options.services.systembus-notify = { |
||||
enable = mkEnableOption '' |
||||
System bus notification support |
||||
|
||||
WARNING: enabling this option (while convenient) should *not* be done on a |
||||
machine where you do not trust the other users as it allows any other |
||||
local user to DoS your session by spamming notifications. |
||||
''; |
||||
}; |
||||
|
||||
config = mkIf cfg.enable { |
||||
systemd = { |
||||
packages = with pkgs; [ systembus-notify ]; |
||||
|
||||
user.services.systembus-notify.wantedBy = [ "graphical-session.target" ]; |
||||
}; |
||||
}; |
||||
} |
@ -1,119 +1,140 @@ |
||||
{ |
||||
"liveHLS": [ |
||||
{ |
||||
"name": "720p", |
||||
"cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -map 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 17 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -preset veryfast -flags +loop-global_header %OUTPUT%" |
||||
"urlscheme": { |
||||
"m2ts": { |
||||
"ios": "vlc-x-callback://x-callback-url/stream?url=PROTOCOL://ADDRESS", |
||||
"android": "intent://ADDRESS#Intent;package=org.videolan.vlc;type=video;scheme=PROTOCOL;end" |
||||
}, |
||||
{ |
||||
"name": "480p", |
||||
"cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -map 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 17 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -preset veryfast -flags +loop-global_header %OUTPUT%" |
||||
"video": { |
||||
"ios": "infuse://x-callback-url/play?url=PROTOCOL://ADDRESS", |
||||
"android": "intent://ADDRESS#Intent;package=com.mxtech.videoplayer.ad;type=video;scheme=PROTOCOL;end" |
||||
}, |
||||
{ |
||||
"name": "180p", |
||||
"cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -map 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 17 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -c:a aac -ar 48000 -b:a 48k -ac 2 -c:v libx264 -vf yadif,scale=-2:180 -b:v 100k -preset veryfast -maxrate 110k -bufsize 1000k -flags +loop-global_header %OUTPUT%" |
||||
"download": { |
||||
"ios": "vlc-x-callback://x-callback-url/download?url=PROTOCOL://ADDRESS&filename=FILENAME" |
||||
} |
||||
], |
||||
"liveMP4": [ |
||||
{ |
||||
"name": "720p", |
||||
"cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1" |
||||
}, |
||||
{ |
||||
"name": "480p", |
||||
"cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1" |
||||
} |
||||
], |
||||
"liveWebM": [ |
||||
{ |
||||
"name": "720p", |
||||
"cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 3 -c:a libvorbis -ar 48000 -b:a 192k -ac 2 -c:v libvpx-vp9 -vf yadif,scale=-2:720 -b:v 3000k -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1" |
||||
}, |
||||
{ |
||||
"name": "480p", |
||||
"cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 2 -c:a libvorbis -ar 48000 -b:a 128k -ac 2 -c:v libvpx-vp9 -vf yadif,scale=-2:480 -b:v 1500k -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1" |
||||
} |
||||
], |
||||
"mpegTsStreaming": [ |
||||
{ |
||||
"name": "720p", |
||||
"cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -preset veryfast -y -f mpegts pipe:1" |
||||
}, |
||||
{ |
||||
"name": "480p", |
||||
"cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -preset veryfast -y -f mpegts pipe:1" |
||||
}, |
||||
{ |
||||
"name": "Original" |
||||
} |
||||
], |
||||
"mpegTsViewer": { |
||||
"ios": "vlc-x-callback://x-callback-url/stream?url=http://ADDRESS", |
||||
"android": "intent://ADDRESS#Intent;package=com.mxtech.videoplayer.ad;type=video;scheme=http;end" |
||||
}, |
||||
"recordedDownloader": { |
||||
"ios": "vlc-x-callback://x-callback-url/download?url=http://ADDRESS&filename=FILENAME", |
||||
"android": "intent://ADDRESS#Intent;package=com.dv.adm;type=video;scheme=http;end" |
||||
}, |
||||
"recordedStreaming": { |
||||
"webm": [ |
||||
{ |
||||
"name": "720p", |
||||
"cmd": "%FFMPEG% -dual_mono_mode main %RE% -i pipe:0 -sn -threads 3 -c:a libvorbis -ar 48000 -ac 2 -c:v libvpx-vp9 -vf yadif,scale=-2:720 %VB% %VBUFFER% %AB% %ABUFFER% -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1", |
||||
"vb": "3000k", |
||||
"ab": "192k" |
||||
}, |
||||
{ |
||||
"name": "360p", |
||||
"cmd": "%FFMPEG% -dual_mono_mode main %RE% -i pipe:0 -sn -threads 2 -c:a libvorbis -ar 48000 -ac 2 -c:v libvpx-vp9 -vf yadif,scale=-2:360 %VB% %VBUFFER% %AB% %ABUFFER% -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1", |
||||
"vb": "1500k", |
||||
"ab": "128k" |
||||
} |
||||
], |
||||
"mp4": [ |
||||
{ |
||||
"name": "720p", |
||||
"cmd": "%FFMPEG% -dual_mono_mode main %RE% -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -ac 2 -c:v libx264 -vf yadif,scale=-2:720 %VB% %VBUFFER% %AB% %ABUFFER% -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1", |
||||
"vb": "3000k", |
||||
"ab": "192k" |
||||
}, |
||||
{ |
||||
"name": "360p", |
||||
"cmd": "%FFMPEG% -dual_mono_mode main %RE% -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -ac 2 -c:v libx264 -vf yadif,scale=-2:360 %VB% %VBUFFER% %AB% %ABUFFER% -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1", |
||||
"vb": "1500k", |
||||
"ab": "128k" |
||||
"stream": { |
||||
"live": { |
||||
"ts": { |
||||
"m2ts": [ |
||||
{ |
||||
"name": "720p", |
||||
"cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -preset veryfast -y -f mpegts pipe:1" |
||||
}, |
||||
{ |
||||
"name": "480p", |
||||
"cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -preset veryfast -y -f mpegts pipe:1" |
||||
}, |
||||
{ |
||||
"name": "無変換" |
||||
} |
||||
], |
||||
"m2tsll": [ |
||||
{ |
||||
"name": "720p", |
||||
"cmd": "%FFMPEG% -dual_mono_mode main -f mpegts -analyzeduration 500000 -i pipe:0 -map 0 -c:s copy -c:d copy -ignore_unknown -fflags nobuffer -flags low_delay -max_delay 250000 -max_interleave_delta 1 -threads 0 -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -flags +cgop -vf yadif,scale=-2:720 -b:v 3000k -preset veryfast -y -f mpegts pipe:1" |
||||
}, |
||||
{ |
||||
"name": "480p", |
||||
"cmd": "%FFMPEG% -dual_mono_mode main -f mpegts -analyzeduration 500000 -i pipe:0 -map 0 -c:s copy -c:d copy -ignore_unknown -fflags nobuffer -flags low_delay -max_delay 250000 -max_interleave_delta 1 -threads 0 -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -flags +cgop -vf yadif,scale=-2:480 -b:v 1500k -preset veryfast -y -f mpegts pipe:1" |
||||
} |
||||
], |
||||
"webm": [ |
||||
{ |
||||
"name": "720p", |
||||
"cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 3 -c:a libvorbis -ar 48000 -b:a 192k -ac 2 -c:v libvpx-vp9 -vf yadif,scale=-2:720 -b:v 3000k -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1" |
||||
}, |
||||
{ |
||||
"name": "480p", |
||||
"cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 2 -c:a libvorbis -ar 48000 -b:a 128k -ac 2 -c:v libvpx-vp9 -vf yadif,scale=-2:480 -b:v 1500k -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1" |
||||
} |
||||
], |
||||
"mp4": [ |
||||
{ |
||||
"name": "720p", |
||||
"cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1" |
||||
}, |
||||
{ |
||||
"name": "480p", |
||||
"cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1" |
||||
} |
||||
], |
||||
"hls": [ |
||||
{ |
||||
"name": "720p", |
||||
"cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -map 0 -threads 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 17 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -hls_flags delete_segments -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -preset veryfast -flags +loop-global_header %OUTPUT%" |
||||
}, |
||||
{ |
||||
"name": "480p", |
||||
"cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -map 0 -threads 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 17 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -hls_flags delete_segments -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -preset veryfast -flags +loop-global_header %OUTPUT%" |
||||
} |
||||
] |
||||
} |
||||
], |
||||
"mpegTs": [ |
||||
{ |
||||
"name": "720p (H.264)", |
||||
"cmd": "%FFMPEG% -dual_mono_mode main %RE% -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -ac 2 -c:v libx264 -vf yadif,scale=-2:720 %VB% %VBUFFER% %AB% %ABUFFER% -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -y -f mpegts pipe:1", |
||||
"vb": "3000k", |
||||
"ab": "192k" |
||||
}, |
||||
"recorded": { |
||||
"ts": { |
||||
"webm": [ |
||||
{ |
||||
"name": "720p", |
||||
"cmd": "%FFMPEG% -dual_mono_mode main -i pipe:0 -sn -threads 3 -c:a libvorbis -ar 48000 -b:a 192k -ac 2 -c:v libvpx-vp9 -vf yadif,scale=-2:720 -b:v 3000k -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1" |
||||
}, |
||||
{ |
||||
"name": "480p", |
||||
"cmd": "%FFMPEG% -dual_mono_mode main -i pipe:0 -sn -threads 3 -c:a libvorbis -ar 48000 -b:a 128k -ac 2 -c:v libvpx-vp9 -vf yadif,scale=-2:480 -b:v 1500k -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1" |
||||
} |
||||
], |
||||
"mp4": [ |
||||
{ |
||||
"name": "720p", |
||||
"cmd": "%FFMPEG% -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1" |
||||
}, |
||||
{ |
||||
"name": "480p", |
||||
"cmd": "%FFMPEG% -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1" |
||||
} |
||||
], |
||||
"hls": [ |
||||
{ |
||||
"name": "720p", |
||||
"cmd": "%FFMPEG% -dual_mono_mode main -i pipe:0 -sn -map 0 -threads 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 0 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -hls_flags delete_segments -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -preset veryfast -flags +loop-global_header %OUTPUT%" |
||||
}, |
||||
{ |
||||
"name": "480p", |
||||
"cmd": "%FFMPEG% -dual_mono_mode main -i pipe:0 -sn -map 0 -threads 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 0 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -hls_flags delete_segments -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -preset veryfast -flags +loop-global_header %OUTPUT%" |
||||
} |
||||
] |
||||
}, |
||||
{ |
||||
"name": "360p (H.264)", |
||||
"cmd": "%FFMPEG% -dual_mono_mode main %RE% -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -ac 2 -c:v libx264 -vf yadif,scale=-2:360 %VB% %VBUFFER% %AB% %ABUFFER% -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -y -f mpegts pipe:1", |
||||
"vb": "1500k", |
||||
"ab": "128k" |
||||
"encoded": { |
||||
"webm": [ |
||||
{ |
||||
"name": "720p", |
||||
"cmd": "%FFMPEG% -dual_mono_mode main -ss %SS% -i %INPUT% -sn -threads 3 -c:a libvorbis -ar 48000 -b:a 192k -ac 2 -c:v libvpx-vp9 -vf scale=-2:720 -b:v 3000k -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1" |
||||
}, |
||||
{ |
||||
"name": "480p", |
||||
"cmd": "%FFMPEG% -dual_mono_mode main -ss %SS% -i %INPUT% -sn -threads 3 -c:a libvorbis -ar 48000 -b:a 128k -ac 2 -c:v libvpx-vp9 -vf scale=-2:480 -b:v 1500k -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1" |
||||
} |
||||
], |
||||
"mp4": [ |
||||
{ |
||||
"name": "720p", |
||||
"cmd": "%FFMPEG% -dual_mono_mode main -ss %SS% -i %INPUT% -sn -threads 0 -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf scale=-2:720 -b:v 3000k -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1" |
||||
}, |
||||
{ |
||||
"name": "480p", |
||||
"cmd": "%FFMPEG% -dual_mono_mode main -ss %SS% -i %INPUT% -sn -threads 0 -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf scale=-2:480 -b:v 1500k -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1" |
||||
} |
||||
], |
||||
"hls": [ |
||||
{ |
||||
"name": "720p", |
||||
"cmd": "%FFMPEG% -dual_mono_mode main -ss %SS% -i %INPUT% -sn -threads 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 0 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -hls_flags delete_segments -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf scale=-2:720 -b:v 3000k -preset veryfast -flags +loop-global_header %OUTPUT%" |
||||
}, |
||||
{ |
||||
"name": "480p", |
||||
"cmd": "%FFMPEG% -dual_mono_mode main -ss %SS% -i %INPUT% -sn -threads 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 0 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -hls_flags delete_segments -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf scale=-2:480 -b:v 3000k -preset veryfast -flags +loop-global_header %OUTPUT%" |
||||
} |
||||
] |
||||
} |
||||
] |
||||
}, |
||||
"recordedHLS": [ |
||||
{ |
||||
"name": "720p", |
||||
"cmd": "%FFMPEG% -dual_mono_mode main -i %INPUT% -sn -threads 0 -map 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 0 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -preset veryfast -flags +loop-global_header %OUTPUT%" |
||||
}, |
||||
{ |
||||
"name": "480p", |
||||
"cmd": "%FFMPEG% -dual_mono_mode main -i %INPUT% -sn -threads 0 -map 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 0 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -preset veryfast -flags +loop-global_header %OUTPUT%" |
||||
}, |
||||
{ |
||||
"name": "480p(h265)", |
||||
"cmd": "%FFMPEG% -dual_mono_mode main -i %INPUT% -sn -map 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 0 -hls_allow_cache 1 -hls_segment_type fmp4 -hls_fmp4_init_filename stream%streamNum%-init.mp4 -hls_segment_filename stream%streamNum%-%09d.m4s -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx265 -vf yadif,scale=-2:480 -b:v 350k -preset veryfast -tag:v hvc1 %OUTPUT%" |
||||
} |
||||
], |
||||
"recordedViewer": { |
||||
"ios": "infuse://x-callback-url/play?url=http://ADDRESS", |
||||
"android": "intent://ADDRESS#Intent;package=com.mxtech.videoplayer.ad;type=video;scheme=http;end" |
||||
} |
||||
} |
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue