From ce74e1cc3681b1607822ba84184cde84b057ab32 Mon Sep 17 00:00:00 2001 From: Michael Raitza Date: Wed, 24 Jan 2018 17:28:31 +0100 Subject: nixos/openafsClient: Extend client service functionality Add a lot of options to the client to make it more usable and compatible with the OpenAFS server module. --- .../network-filesystems/openafs/client.nix | 192 ++++++++++++++++++--- .../services/network-filesystems/openafs/lib.nix | 28 +++ 2 files changed, 194 insertions(+), 26 deletions(-) create mode 100644 nixos/modules/services/network-filesystems/openafs/lib.nix (limited to 'nixos/modules/services/network-filesystems/openafs') diff --git a/nixos/modules/services/network-filesystems/openafs/client.nix b/nixos/modules/services/network-filesystems/openafs/client.nix index e5f89a9a0d2..3826fe3edfd 100644 --- a/nixos/modules/services/network-filesystems/openafs/client.nix +++ b/nixos/modules/services/network-filesystems/openafs/client.nix @@ -1,7 +1,9 @@ { config, pkgs, lib, ... }: +with import ./lib.nix { inherit lib; }; + let - inherit (lib) mkOption mkIf; + inherit (lib) getBin mkOption mkIf optionalString singleton types; cfg = config.services.openafsClient; @@ -10,14 +12,17 @@ let sha256 = "1197z6c5xrijgf66rhaymnm5cvyg2yiy1i20y4ah4mrzmjx0m7sc"; }; + clientServDB = pkgs.writeText "client-cellServDB-${cfg.cellName}" (mkCellServDB cfg.cellName cfg.cellServDB); + afsConfig = pkgs.runCommand "afsconfig" {} '' mkdir -p $out echo ${cfg.cellName} > $out/ThisCell - cp ${cellServDB} $out/CellServDB - echo "/afs:${cfg.cacheDirectory}:${cfg.cacheSize}" > $out/cacheinfo + cat ${cellServDB} ${clientServDB} > $out/CellServDB + echo "${cfg.mountPoint}:${cfg.cache.directory}:${toString cfg.cache.blocks}" > $out/cacheinfo ''; - openafsPkgs = config.boot.kernelPackages.openafs; + openafsMod = config.boot.kernelPackages.openafs; + openafsBin = lib.getBin pkgs.openafs; in { ###### interface @@ -28,34 +33,136 @@ in enable = mkOption { default = false; + type = types.bool; description = "Whether to enable the OpenAFS client."; }; + afsdb = mkOption { + default = true; + type = types.bool; + description = "Resolve cells via AFSDB DNS records."; + }; + cellName = mkOption { - default = "grand.central.org"; + default = ""; + type = types.str; description = "Cell name."; + example = "grand.central.org"; }; - cacheSize = mkOption { - default = "100000"; - description = "Cache size."; + cellServDB = mkOption { + default = []; + type = with types; listOf (submodule { options = cellServDBConfig; }); + description = '' + This cell's database server records, added to the global + CellServDB. See CellServDB(5) man page for syntax. Ignored when + afsdb is set to true. + ''; + example = '' + [ { ip = "1.2.3.4"; dnsname = "first.afsdb.server.dns.fqdn.org"; } + { ip = "2.3.4.5"; dnsname = "second.afsdb.server.dns.fqdn.org"; } + ] + ''; }; - cacheDirectory = mkOption { - default = "/var/cache/openafs"; - description = "Cache directory."; + cache = { + blocks = mkOption { + default = 100000; + type = types.int; + description = "Cache size in 1KB blocks."; + }; + + chunksize = mkOption { + default = 0; + type = types.ints.between 0 30; + description = '' + Size of each cache chunk given in powers of + 2. 0 resets the chunk size to its default + values (13 (8 KB) for memcache, 18-20 (256 KB to 1 MB) for + diskcache). Maximum value is 30. Important performance + parameter. Set to higher values when dealing with large files. + ''; + }; + + directory = mkOption { + default = "/var/cache/openafs"; + type = types.str; + description = "Cache directory."; + }; + + diskless = mkOption { + default = false; + type = types.bool; + description = '' + Use in-memory cache for diskless machines. Has no real + performance benefit anymore. + ''; + }; }; crypt = mkOption { - default = false; + default = true; + type = types.bool; description = "Whether to enable (weak) protocol encryption."; }; - sparse = mkOption { + daemons = mkOption { + default = 2; + type = types.int; + description = '' + Number of daemons to serve user requests. Numbers higher than 6 + usually do no increase performance. Default is sufficient for up + to five concurrent users. + ''; + }; + + fakestat = mkOption { default = false; + type = types.bool; + description = '' + Return fake data on stat() calls. If true, + always do so. If false, only do so for + cross-cell mounts (as these are potentially expensive). + ''; + }; + + inumcalc = mkOption { + default = "compat"; + type = types.strMatching "compat|md5"; + description = '' + Inode calculation method. compat is + computationally less expensive, but md5 greatly + reduces the likelihood of inode collisions in larger scenarios + involving multiple cells mounted into one AFS space. + ''; + }; + + mountPoint = mkOption { + default = "/afs"; + type = types.str; + description = '' + Mountpoint of the AFS file tree, conventionally + /afs. When set to a different value, only + cross-cells that use the same value can be accessed. + ''; + }; + + sparse = mkOption { + default = true; + type = types.bool; description = "Minimal cell list in /afs."; }; + startDisconnected = mkOption { + default = false; + type = types.bool; + description = '' + Start up in disconnected mode. You need to execute + fs disco online (as root) to switch to + connected mode. Useful for roaming devices. + ''; + }; + }; }; @@ -64,26 +171,58 @@ in config = mkIf cfg.enable { - environment.systemPackages = [ openafsPkgs ]; - - environment.etc = [ - { source = afsConfig; - target = "openafs"; + assertions = [ + { assertion = cfg.afsdb || cfg.cellServDB != []; + message = "You should specify all cell-local database servers in config.services.openafsClient.cellServDB or set config.services.openafsClient.afsdb."; + } + { assertion = cfg.cellName != ""; + message = "You must specify the local cell name in config.services.openafsClient.cellName."; } ]; + environment.systemPackages = [ pkgs.openafs ]; + + environment.etc = { + clientCellServDB = { + source = pkgs.runCommand "CellServDB" {} '' + cat ${cellServDB} ${clientServDB} > $out + ''; + target = "openafs/CellServDB"; + mode = "0644"; + }; + clientCell = { + text = '' + ${cfg.cellName} + ''; + target = "openafs/ThisCell"; + mode = "0644"; + }; + }; + systemd.services.afsd = { description = "AFS client"; wantedBy = [ "multi-user.target" ]; - after = [ "network.target" ]; + after = singleton (if cfg.startDisconnected then "network.target" else "network-online.target"); serviceConfig = { RemainAfterExit = true; }; + restartIfChanged = false; preStart = '' - mkdir -p -m 0755 /afs - mkdir -m 0700 -p ${cfg.cacheDirectory} - ${pkgs.kmod}/bin/insmod ${openafsPkgs}/lib/openafs/libafs-*.ko || true - ${openafsPkgs}/sbin/afsd -confdir ${afsConfig} -cachedir ${cfg.cacheDirectory} ${if cfg.sparse then "-dynroot-sparse" else "-dynroot"} -fakestat -afsdb - ${openafsPkgs}/bin/fs setcrypt ${if cfg.crypt then "on" else "off"} + mkdir -p -m 0755 ${cfg.mountPoint} + mkdir -m 0700 -p ${cfg.cache.directory} + ${pkgs.kmod}/bin/insmod ${openafsMod}/lib/modules/*/extra/openafs/libafs.ko.xz + ${openafsBin}/sbin/afsd \ + -mountdir ${cfg.mountPoint} \ + -confdir ${afsConfig} \ + ${optionalString (!cfg.cache.diskless) "-cachedir ${cfg.cache.directory}"} \ + -blocks ${toString cfg.cache.blocks} \ + -chunksize ${toString cfg.cache.chunksize} \ + ${optionalString cfg.cache.diskless "-memcache"} \ + -inumcalc ${cfg.inumcalc} \ + ${if cfg.fakestat then "-fakestat-all" else "-fakestat"} \ + ${if cfg.sparse then "-dynroot-sparse" else "-dynroot"} \ + ${optionalString cfg.afsdb "-afsdb"} + ${openafsBin}/bin/fs setcrypt ${if cfg.crypt then "on" else "off"} + ${optionalString cfg.startDisconnected "${openafsBin}/bin/fs discon offline"} ''; # Doing this in preStop, because after these commands AFS is basically @@ -91,8 +230,9 @@ in # postStop, then we get a hang + kernel oops, because AFS can't be # stopped simply by sending signals to processes. preStop = '' - ${pkgs.utillinux}/bin/umount /afs - ${openafsPkgs}/sbin/afsd -shutdown + ${pkgs.utillinux}/bin/umount ${cfg.mountPoint} + ${openafsBin}/sbin/afsd -shutdown + ${pkgs.kmod}/sbin/rmmod libafs ''; }; }; diff --git a/nixos/modules/services/network-filesystems/openafs/lib.nix b/nixos/modules/services/network-filesystems/openafs/lib.nix new file mode 100644 index 00000000000..ecfc72d2eaf --- /dev/null +++ b/nixos/modules/services/network-filesystems/openafs/lib.nix @@ -0,0 +1,28 @@ +{ lib, ...}: + +let + inherit (lib) concatStringsSep mkOption types; + +in rec { + + mkCellServDB = cellName: db: '' + >${cellName} + '' + (concatStringsSep "\n" (map (dbm: if (dbm.ip != "" && dbm.dnsname != "") then dbm.ip + " #" + dbm.dnsname else "") + db)); + + # CellServDB configuration type + cellServDBConfig = { + ip = mkOption { + type = types.str; + default = ""; + example = "1.2.3.4"; + description = "IP Address of a database server"; + }; + dnsname = mkOption { + type = types.str; + default = ""; + example = "afs.example.org"; + description = "DNS full-qualified domain name of a database server"; + }; + }; +} -- cgit 1.4.1