Unverified Commit 6ed06bc0 authored by github-actions[bot]'s avatar github-actions[bot] Committed by GitHub
Browse files

Merge master into staging-next

parents 254356dd aad545b3
Loading
Loading
Loading
Loading
+58 −61
Original line number Diff line number Diff line
{ config, options, lib, pkgs, ... }:

with lib;

let

  name = "snapserver";
@@ -9,8 +6,8 @@ let
  cfg = config.services.snapserver;

  # Using types.nullOr to inherit upstream defaults.
  sampleFormat = mkOption {
    type = with types; nullOr str;
  sampleFormat = lib.mkOption {
    type = with lib.types; nullOr str;
    default = null;
    description = ''
      Default sample format.
@@ -18,8 +15,8 @@ let
    example = "48000:16:2";
  };

  codec = mkOption {
    type = with types; nullOr str;
  codec = lib.mkOption {
    type = with lib.types; nullOr str;
    default = null;
    description = ''
      Default audio compression method.
@@ -30,20 +27,20 @@ let
  streamToOption = name: opt:
    let
      os = val:
        optionalString (val != null) "${val}";
        lib.optionalString (val != null) "${val}";
      os' = prefix: val:
        optionalString (val != null) (prefix + "${val}");
        lib.optionalString (val != null) (prefix + "${val}");
      flatten = key: value:
        "&${key}=${value}";
    in
      "--stream.stream=\"${opt.type}://" + os opt.location + "?" + os' "name=" name
        + os' "&sampleformat=" opt.sampleFormat + os' "&codec=" opt.codec
        + concatStrings (mapAttrsToList flatten opt.query) + "\"";
        + lib.concatStrings (lib.mapAttrsToList lib.flatten opt.query) + "\"";

  optionalNull = val: ret:
    optional (val != null) ret;
    lib.optional (val != null) ret;

  optionString = concatStringsSep " " (mapAttrsToList streamToOption cfg.streams
  optionString = lib.concatStringsSep " " (lib.mapAttrsToList streamToOption cfg.streams
    # global options
    ++ [ "--stream.bind_to_address=${cfg.listenAddress}" ]
    ++ [ "--stream.port=${toString cfg.port}" ]
@@ -51,22 +48,22 @@ let
    ++ optionalNull cfg.codec "--stream.codec=${cfg.codec}"
    ++ optionalNull cfg.streamBuffer "--stream.stream_buffer=${toString cfg.streamBuffer}"
    ++ optionalNull cfg.buffer "--stream.buffer=${toString cfg.buffer}"
    ++ optional cfg.sendToMuted "--stream.send_to_muted"
    ++ lib.optional cfg.sendToMuted "--stream.send_to_muted"
    # tcp json rpc
    ++ [ "--tcp.enabled=${toString cfg.tcp.enable}" ]
    ++ optionals cfg.tcp.enable [
    ++ lib.optionals cfg.tcp.enable [
      "--tcp.bind_to_address=${cfg.tcp.listenAddress}"
      "--tcp.port=${toString cfg.tcp.port}" ]
     # http json rpc
    ++ [ "--http.enabled=${toString cfg.http.enable}" ]
    ++ optionals cfg.http.enable [
    ++ lib.optionals cfg.http.enable [
      "--http.bind_to_address=${cfg.http.listenAddress}"
      "--http.port=${toString cfg.http.port}"
    ] ++ optional (cfg.http.docRoot != null) "--http.doc_root=\"${toString cfg.http.docRoot}\"");
    ] ++ lib.optional (cfg.http.docRoot != null) "--http.doc_root=\"${toString cfg.http.docRoot}\"");

in {
  imports = [
    (mkRenamedOptionModule [ "services" "snapserver" "controlPort" ] [ "services" "snapserver" "tcp" "port" ])
    (lib.mkRenamedOptionModule [ "services" "snapserver" "controlPort" ] [ "services" "snapserver" "tcp" "port" ])
  ];

  ###### interface
@@ -75,16 +72,16 @@ in {

    services.snapserver = {

      enable = mkOption {
        type = types.bool;
      enable = lib.mkOption {
        type = lib.types.bool;
        default = false;
        description = ''
          Whether to enable snapserver.
        '';
      };

      listenAddress = mkOption {
        type = types.str;
      listenAddress = lib.mkOption {
        type = lib.types.str;
        default = "::";
        example = "0.0.0.0";
        description = ''
@@ -92,16 +89,16 @@ in {
        '';
      };

      port = mkOption {
        type = types.port;
      port = lib.mkOption {
        type = lib.types.port;
        default = 1704;
        description = ''
          The port that snapclients can connect to.
        '';
      };

      openFirewall = mkOption {
        type = types.bool;
      openFirewall = lib.mkOption {
        type = lib.types.bool;
        default = false;
        description = ''
          Whether to automatically open the specified ports in the firewall.
@@ -111,8 +108,8 @@ in {
      inherit sampleFormat;
      inherit codec;

      streamBuffer = mkOption {
        type = with types; nullOr int;
      streamBuffer = lib.mkOption {
        type = with lib.types; nullOr int;
        default = null;
        description = ''
          Stream read (input) buffer in ms.
@@ -120,8 +117,8 @@ in {
        example = 20;
      };

      buffer = mkOption {
        type = with types; nullOr int;
      buffer = lib.mkOption {
        type = with lib.types; nullOr int;
        default = null;
        description = ''
          Network buffer in ms.
@@ -129,24 +126,24 @@ in {
        example = 1000;
      };

      sendToMuted = mkOption {
        type = types.bool;
      sendToMuted = lib.mkOption {
        type = lib.types.bool;
        default = false;
        description = ''
          Send audio to muted clients.
        '';
      };

      tcp.enable = mkOption {
        type = types.bool;
      tcp.enable = lib.mkOption {
        type = lib.types.bool;
        default = true;
        description = ''
          Whether to enable the JSON-RPC via TCP.
        '';
      };

      tcp.listenAddress = mkOption {
        type = types.str;
      tcp.listenAddress = lib.mkOption {
        type = lib.types.str;
        default = "::";
        example = "0.0.0.0";
        description = ''
@@ -154,24 +151,24 @@ in {
        '';
      };

      tcp.port = mkOption {
        type = types.port;
      tcp.port = lib.mkOption {
        type = lib.types.port;
        default = 1705;
        description = ''
          The port where the TCP JSON-RPC listens on.
        '';
      };

      http.enable = mkOption {
        type = types.bool;
      http.enable = lib.mkOption {
        type = lib.types.bool;
        default = true;
        description = ''
          Whether to enable the JSON-RPC via HTTP.
        '';
      };

      http.listenAddress = mkOption {
        type = types.str;
      http.listenAddress = lib.mkOption {
        type = lib.types.str;
        default = "::";
        example = "0.0.0.0";
        description = ''
@@ -179,27 +176,27 @@ in {
        '';
      };

      http.port = mkOption {
        type = types.port;
      http.port = lib.mkOption {
        type = lib.types.port;
        default = 1780;
        description = ''
          The port where the HTTP JSON-RPC listens on.
        '';
      };

      http.docRoot = mkOption {
        type = with types; nullOr path;
      http.docRoot = lib.mkOption {
        type = with lib.types; nullOr path;
        default = null;
        description = ''
          Path to serve from the HTTP servers root.
        '';
      };

      streams = mkOption {
        type = with types; attrsOf (submodule {
      streams = lib.mkOption {
        type = with lib.types; attrsOf (submodule {
          options = {
            location = mkOption {
              type = types.oneOf [ types.path types.str ];
            location = lib.mkOption {
              type = lib.types.oneOf [ lib.types.path lib.types.str ];
              description = ''
                For type `pipe` or `file`, the path to the pipe or file.
                For type `librespot`, `airplay` or `process`, the path to the corresponding binary.
@@ -207,27 +204,27 @@ in {
                For type `meta`, a list of stream names in the form `/one/two/...`. Don't forget the leading slash.
                For type `alsa`, use an empty string.
              '';
              example = literalExpression ''
              example = lib.literalExpression ''
                "/path/to/pipe"
                "/path/to/librespot"
                "192.168.1.2:4444"
                "/MyTCP/Spotify/MyPipe"
              '';
            };
            type = mkOption {
              type = types.enum [ "pipe" "librespot" "airplay" "file" "process" "tcp" "alsa" "spotify" "meta" ];
            type = lib.mkOption {
              type = lib.types.enum [ "pipe" "librespot" "airplay" "file" "process" "tcp" "alsa" "spotify" "meta" ];
              default = "pipe";
              description = ''
                The type of input stream.
              '';
            };
            query = mkOption {
            query = lib.mkOption {
              type = attrsOf str;
              default = {};
              description = ''
                Key-value pairs that convey additional parameters about a stream.
              '';
              example = literalExpression ''
              example = lib.literalExpression ''
                # for type == "pipe":
                {
                  mode = "create";
@@ -255,7 +252,7 @@ in {
        description = ''
          The definition for an input source.
        '';
        example = literalExpression ''
        example = lib.literalExpression ''
          {
            mpd = {
              type = "pipe";
@@ -272,11 +269,11 @@ in {

  ###### implementation

  config = mkIf cfg.enable {
  config = lib.mkIf cfg.enable {

    warnings =
      # https://github.com/badaix/snapcast/blob/98ac8b2fb7305084376607b59173ce4097c620d8/server/streamreader/stream_manager.cpp#L85
      filter (w: w != "") (mapAttrsToList (k: v: optionalString (v.type == "spotify") ''
      lib.filter (w: w != "") (lib.mapAttrsToList (k: v: lib.optionalString (v.type == "spotify") ''
        services.snapserver.streams.${k}.type = "spotify" is deprecated, use services.snapserver.streams.${k}.type = "librespot" instead.
      '') cfg.streams);

@@ -305,13 +302,13 @@ in {
    };

    networking.firewall.allowedTCPPorts =
      optionals cfg.openFirewall [ cfg.port ]
      ++ optional (cfg.openFirewall && cfg.tcp.enable) cfg.tcp.port
      ++ optional (cfg.openFirewall && cfg.http.enable) cfg.http.port;
      lib.optionals cfg.openFirewall [ cfg.port ]
      ++ lib.optional (cfg.openFirewall && cfg.tcp.enable) cfg.tcp.port
      ++ lib.optional (cfg.openFirewall && cfg.http.enable) cfg.http.port;
  };

  meta = {
    maintainers = with maintainers; [ tobim ];
    maintainers = with lib.maintainers; [ tobim ];
  };

}
+134 −137

File changed.

Preview size limit exceeded, changes collapsed.

+49 −52
Original line number Diff line number Diff line
{ config, lib, pkgs, ... }:

with lib;

let
  cfg = config.services.portunus;

in
{
  options.services.portunus = {
    enable = mkEnableOption "Portunus, a self-contained user/group management and authentication service for LDAP";
    enable = lib.mkEnableOption "Portunus, a self-contained user/group management and authentication service for LDAP";

    domain = mkOption {
      type = types.str;
    domain = lib.mkOption {
      type = lib.types.str;
      example = "sso.example.com";
      description = "Subdomain which gets reverse proxied to Portunus webserver.";
    };

    port = mkOption {
      type = types.port;
    port = lib.mkOption {
      type = lib.types.port;
      default = 8080;
      description = ''
        Port where the Portunus webserver should listen on.
@@ -26,10 +23,10 @@ in
      '';
    };

    package = mkPackageOption pkgs "portunus" { };
    package = lib.mkPackageOption pkgs "portunus" { };

    seedPath = mkOption {
      type = types.nullOr types.path;
    seedPath = lib.mkOption {
      type = lib.types.nullOr lib.types.path;
      default = null;
      description = ''
        Path to a portunus seed file in json format.
@@ -46,26 +43,26 @@ in
      '';
    };

    stateDir = mkOption {
      type = types.path;
    stateDir = lib.mkOption {
      type = lib.types.path;
      default = "/var/lib/portunus";
      description = "Path where Portunus stores its state.";
    };

    user = mkOption {
      type = types.str;
    user = lib.mkOption {
      type = lib.types.str;
      default = "portunus";
      description = "User account under which Portunus runs its webserver.";
    };

    group = mkOption {
      type = types.str;
    group = lib.mkOption {
      type = lib.types.str;
      default = "portunus";
      description = "Group account under which Portunus runs its webserver.";
    };

    dex = {
      enable = mkEnableOption ''
      enable = lib.mkEnableOption ''
        Dex ldap connector.

        To activate dex, first a search user must be created in the Portunus web ui
@@ -73,15 +70,15 @@ in
        in the [](#opt-services.dex.environmentFile) setting
      '';

      oidcClients = mkOption {
        type = types.listOf (types.submodule {
      oidcClients = lib.mkOption {
        type = lib.types.listOf (lib.types.submodule {
          options = {
            callbackURL = mkOption {
              type = types.str;
            callbackURL = lib.mkOption {
              type = lib.types.str;
              description = "URL where the OIDC client should redirect";
            };
            id = mkOption {
              type = types.str;
            id = lib.mkOption {
              type = lib.types.str;
              description = "ID of the OIDC client";
            };
          };
@@ -105,23 +102,23 @@ in
        '';
      };

      port = mkOption {
        type = types.port;
      port = lib.mkOption {
        type = lib.types.port;
        default = 5556;
        description = "Port where dex should listen on.";
      };
    };

    ldap = {
      package = mkOption {
        type = types.package;
      package = lib.mkOption {
        type = lib.types.package;
        default = pkgs.openldap;
        defaultText = lib.literalExpression "pkgs.openldap.override { libxcrypt = pkgs.libxcrypt-legacy; }";
        description = "The OpenLDAP package to use.";
      };

      searchUserName = mkOption {
        type = types.str;
      searchUserName = lib.mkOption {
        type = lib.types.str;
        default = "";
        example = "admin";
        description = ''
@@ -130,8 +127,8 @@ in
        '';
      };

      suffix = mkOption {
        type = types.str;
      suffix = lib.mkOption {
        type = lib.types.str;
        example = "dc=example,dc=org";
        description = ''
          The DN of the topmost entry in your LDAP directory.
@@ -139,8 +136,8 @@ in
        '';
      };

      tls = mkOption {
        type = types.bool;
      tls = lib.mkOption {
        type = lib.types.bool;
        default = false;
        description = ''
          Whether to enable LDAPS protocol.
@@ -151,21 +148,21 @@ in
        '';
      };

      user = mkOption {
        type = types.str;
      user = lib.mkOption {
        type = lib.types.str;
        default = "openldap";
        description = "User account under which Portunus runs its LDAP server.";
      };

      group = mkOption {
        type = types.str;
      group = lib.mkOption {
        type = lib.types.str;
        default = "openldap";
        description = "Group account under which Portunus runs its LDAP server.";
      };
    };
  };

  config = mkIf cfg.enable {
  config = lib.mkIf cfg.enable {
    assertions = [
      {
        assertion = cfg.dex.enable -> cfg.ldap.searchUserName != "";
@@ -177,13 +174,13 @@ in
    environment.systemPackages = [ cfg.ldap.package ];

    # allow connecting via ldaps /w certificate without opening ports
    networking.hosts = mkIf cfg.ldap.tls {
    networking.hosts = lib.mkIf cfg.ldap.tls {
      "::1" = [ cfg.domain ];
      "127.0.0.1" = [ cfg.domain ];
    };

    services = {
      dex = mkIf cfg.dex.enable {
      dex = lib.mkIf cfg.dex.enable {
        enable = true;
        settings = {
          issuer = "https://${cfg.domain}/dex";
@@ -219,7 +216,7 @@ in
            };
          }];

          staticClients = forEach cfg.dex.oidcClients (client: {
          staticClients = lib.forEach cfg.dex.oidcClients (client: {
            inherit (client) id;
            redirectURIs = [ client.callbackURL ];
            name = "OIDC for ${client.id}";
@@ -232,7 +229,7 @@ in
    };

    systemd.services = {
      dex = mkIf cfg.dex.enable {
      dex = lib.mkIf cfg.dex.enable {
        serviceConfig = {
          # `dex.service` is super locked down out of the box, but we need some
          # place to write the SQLite database. This creates $STATE_DIRECTORY below
@@ -261,9 +258,9 @@ in
          PORTUNUS_SLAPD_GROUP = cfg.ldap.group;
          PORTUNUS_SLAPD_USER = cfg.ldap.user;
          PORTUNUS_SLAPD_SCHEMA_DIR = "${cfg.ldap.package}/etc/schema";
        } // (optionalAttrs (cfg.seedPath != null) ({
        } // (lib.optionalAttrs (cfg.seedPath != null) ({
          PORTUNUS_SEED_PATH = cfg.seedPath;
        })) // (optionalAttrs cfg.ldap.tls (
        })) // (lib.optionalAttrs cfg.ldap.tls (
          let
            acmeDirectory = config.security.acme.certs."${cfg.domain}".directory;
          in
@@ -277,14 +274,14 @@ in
      };
    };

    users.users = mkMerge [
      (mkIf (cfg.ldap.user == "openldap") {
    users.users = lib.mkMerge [
      (lib.mkIf (cfg.ldap.user == "openldap") {
        openldap = {
          group = cfg.ldap.group;
          isSystemUser = true;
        };
      })
      (mkIf (cfg.user == "portunus") {
      (lib.mkIf (cfg.user == "portunus") {
        portunus = {
          group = cfg.group;
          isSystemUser = true;
@@ -292,15 +289,15 @@ in
      })
    ];

    users.groups = mkMerge [
      (mkIf (cfg.ldap.user == "openldap") {
    users.groups = lib.mkMerge [
      (lib.mkIf (cfg.ldap.user == "openldap") {
        openldap = { };
      })
      (mkIf (cfg.user == "portunus") {
      (lib.mkIf (cfg.user == "portunus") {
        portunus = { };
      })
    ];
  };

  meta.maintainers = [ maintainers.majewsky ] ++ teams.c3d2.members;
  meta.maintainers = [ lib.maintainers.majewsky ] ++ lib.teams.c3d2.members;
}
+93 −96

File changed.

Preview size limit exceeded, changes collapsed.

+69 −72

File changed.

Preview size limit exceeded, changes collapsed.

Loading