nixos/openldap: Allow declarativeContents for multiple databases

This commit is contained in:
Kai Wohlfahrt 2020-08-24 00:07:24 +01:00
parent 057cb570be
commit 9528faf182
2 changed files with 38 additions and 22 deletions

View File

@ -5,7 +5,6 @@ let
cfg = config.services.openldap; cfg = config.services.openldap;
openldap = cfg.package; openldap = cfg.package;
dataFile = pkgs.writeText "ldap-contents.ldif" cfg.declarativeContents;
configFile = pkgs.writeText "slapd.conf" ((optionalString (cfg.defaultSchemas != null && cfg.defaultSchemas) '' configFile = pkgs.writeText "slapd.conf" ((optionalString (cfg.defaultSchemas != null && cfg.defaultSchemas) ''
include ${openldap}/etc/schema/core.schema include ${openldap}/etc/schema/core.schema
include ${openldap}/etc/schema/cosine.schema include ${openldap}/etc/schema/cosine.schema
@ -26,7 +25,7 @@ let
${if cfg.extraDatabaseConfig != null then cfg.extraDatabaseConfig else ""} ${if cfg.extraDatabaseConfig != null then cfg.extraDatabaseConfig else ""}
''); '');
configDir = if cfg.configDir != null then cfg.configDir else "/etc/openldap/slapd.d"; configDir = lib.escapeShellArg (if cfg.configDir != null then cfg.configDir else "/etc/openldap/slapd.d");
ldapValueType = let ldapValueType = let
singleLdapValueType = types.either types.str (types.submodule { singleLdapValueType = types.either types.str (types.submodule {
@ -209,7 +208,7 @@ in {
example = "dc=example,dc=org"; example = "dc=example,dc=org";
description = '' description = ''
Specify the DN suffix of queries that will be passed to the first Specify the DN suffix of queries that will be passed to the first
database database. backend database.
''; '';
}; };
@ -292,10 +291,10 @@ in {
}; };
declarativeContents = mkOption { declarativeContents = mkOption {
type = with types; nullOr lines; type = with types; either lines (attrsOf lines);
default = null; default = {};
description = '' description = ''
Declarative contents for the LDAP database, in LDIF format. Declarative contents for the first LDAP database, in LDIF format.
Note a few facts when using it. First, the database Note a few facts when using it. First, the database
<emphasis>must</emphasis> be stored in the directory defined by <emphasis>must</emphasis> be stored in the directory defined by
@ -359,6 +358,10 @@ in {
maintainers = with lib.maintainters; [ mic92 kwohlfahrt ]; maintainers = with lib.maintainters; [ mic92 kwohlfahrt ];
}; };
# TODO: Check that dataDir/declarativeContents/configDir all match
# - deprecate declarativeContents = ''...'';
# - no declarativeContents = ''...'' if dataDir == null;
# - no declarativeContents = { ... } if configDir != null
config = mkIf cfg.enable { config = mkIf cfg.enable {
warnings = let warnings = let
deprecations = [ deprecations = [
@ -458,32 +461,45 @@ in {
after = [ "network.target" ]; after = [ "network.target" ];
preStart = let preStart = let
dbSettings = lib.filterAttrs (name: value: lib.hasPrefix "olcDatabase=" name) cfg.settings.children; dbSettings = lib.filterAttrs (name: value: lib.hasPrefix "olcDatabase=" name) cfg.settings.children;
dataDirs = lib.mapAttrsToList (name: value: value.attrs.olcDbDirectory) dbSettings; dataDirs = lib.mapAttrs' (name: value: lib.nameValuePair value.attrs.olcSuffix value.attrs.olcDbDirectory)
(lib.filterAttrs (_: value: value.attrs ? olcDbDirectory) dbSettings);
settingsFile = pkgs.writeText "config.ldif" (lib.concatStringsSep "\n" (attrsToLdif "cn=config" cfg.settings)); settingsFile = pkgs.writeText "config.ldif" (lib.concatStringsSep "\n" (attrsToLdif "cn=config" cfg.settings));
in '' in ''
mkdir -p /run/slapd mkdir -p /run/slapd
chown -R "${cfg.user}:${cfg.group}" /run/slapd chown -R "${cfg.user}:${cfg.group}" /run/slapd
mkdir -p '${configDir}' ${lib.escapeShellArgs dataDirs} mkdir -p ${configDir} ${lib.escapeShellArgs (lib.attrValues dataDirs)}
chown "${cfg.user}:${cfg.group}" '${configDir}' ${lib.escapeShellArgs dataDirs} chown "${cfg.user}:${cfg.group}" ${configDir} ${lib.escapeShellArgs (lib.attrValues dataDirs)}
${lib.optionalString (cfg.configDir == null) ( ${lib.optionalString (cfg.configDir == null) (
if (cfg.extraConfig != "" || cfg.extraDatabaseConfig != "") then '' if (cfg.extraConfig != "" || cfg.extraDatabaseConfig != "") then ''
rm -Rf '${configDir}'/* rm -Rf ${configDir}/*
# -u disables config generation, so just ignore the return code # -u disables config generation, so just ignore the return code
${openldap}/bin/slaptest -f ${configFile} -F ${configDir} || true ${openldap}/bin/slaptest -f ${configFile} -F ${configDir} || true
'' else '' '' else ''
rm -Rf '${configDir}'/* rm -Rf ${configDir}/*
${openldap}/bin/slapadd -F ${configDir} -bcn=config -l ${settingsFile} ${openldap}/bin/slapadd -F ${configDir} -bcn=config -l ${settingsFile}
'' ''
)} )}
chown -R "${cfg.user}:${cfg.group}" '${configDir}' chown -R "${cfg.user}:${cfg.group}" ${configDir}
${optionalString (cfg.declarativeContents != null) '' ${if types.lines.check cfg.declarativeContents then (let
rm -Rf '${lib.head dataDirs}'/* dataFile = pkgs.writeText "ldap-contents.ldif" cfg.declarativeContents;
${openldap}/bin/slapadd -F ${configDir} -b${cfg.suffix} -l ${dataFile} in ''
chown -R "${cfg.user}:${cfg.group}" ${lib.escapeShellArgs dataDirs} rm -rf ${lib.escapeShellArg cfg.dataDir}/*
''} ${openldap}/bin/slapadd -F ${configDir} -l ${dataFile}
chown -R "${cfg.user}:${cfg.group}" ${lib.escapeShellArg cfg.dataDir}
'') else (let
dataFiles = lib.mapAttrs (dn: contents: pkgs.writeText "${dn}.ldif" contents) cfg.declarativeContents;
in ''
${lib.concatStrings (lib.mapAttrsToList (dn: file: let
dataDir = lib.escapeShellArg (getAttr dn dataDirs);
in ''
rm -rf ${dataDir}/*
${openldap}/bin/slapadd -F ${configDir} -b ${dn} -l ${file}
chown -R "${cfg.user}:${cfg.group}" ${dataDir}
'') dataFiles)}
'')}
${openldap}/bin/slaptest -u -F ${configDir} ${openldap}/bin/slaptest -u -F ${configDir}
''; '';

View File

@ -1,5 +1,5 @@
{ pkgs, system ? builtins.currentSystem, ... }: let { pkgs, system ? builtins.currentSystem, ... }: let
declarativeContents = '' dbContents = ''
dn: dc=example dn: dc=example
objectClass: domain objectClass: domain
dc: example dc: example
@ -22,7 +22,6 @@ in {
machine = { pkgs, ... }: { machine = { pkgs, ... }: {
services.openldap = { services.openldap = {
inherit declarativeContents;
enable = true; enable = true;
defaultSchemas = null; defaultSchemas = null;
dataDir = null; dataDir = null;
@ -49,6 +48,7 @@ in {
}; };
}; };
}; };
declarativeContents."dc=example" = dbContents;
}; };
}; };
}; };
@ -60,11 +60,11 @@ in {
machine = { pkgs, ... }: { machine = { pkgs, ... }: {
services.openldap = { services.openldap = {
inherit declarativeContents;
enable = true; enable = true;
suffix = "dc=example"; suffix = "dc=example";
rootdn = "cn=root,dc=example"; rootdn = "cn=root,dc=example";
rootpw = "notapassword"; rootpw = "notapassword";
declarativeContents = dbContents;
}; };
}; };
}; };
@ -85,7 +85,7 @@ in {
}; };
testScript = let testScript = let
contents = pkgs.writeText "data.ldif" declarativeContents; contents = pkgs.writeText "data.ldif" dbContents;
config = pkgs.writeText "config.ldif" '' config = pkgs.writeText "config.ldif" ''
dn: cn=config dn: cn=config
cn: config cn: config
@ -129,7 +129,6 @@ in {
machine = { pkgs, ... }: { machine = { pkgs, ... }: {
services.openldap = { services.openldap = {
inherit declarativeContents;
enable = true; enable = true;
suffix = "dc=example"; suffix = "dc=example";
rootdn = "cn=root,dc=example"; rootdn = "cn=root,dc=example";
@ -140,6 +139,7 @@ in {
extraDatabaseConfig = '' extraDatabaseConfig = ''
# No-op # No-op
''; '';
declarativeContents = dbContents;
}; };
}; };
}; };