summary refs log tree commit diff
path: root/nixos/modules/services/network-filesystems
diff options
context:
space:
mode:
authorMichael Raitza <spacefrogg-github@meterriblecrew.net>2018-01-24 17:28:31 +0100
committerMichael Raitza <spacefrogg-github@meterriblecrew.net>2018-02-01 16:35:24 +0100
commitce74e1cc3681b1607822ba84184cde84b057ab32 (patch)
tree4c326c543cd259976737347106621d2b42a72327 /nixos/modules/services/network-filesystems
parentc389d705f3b50d88ec46ad6dccf028efa660edad (diff)
downloadnixlib-ce74e1cc3681b1607822ba84184cde84b057ab32.tar
nixlib-ce74e1cc3681b1607822ba84184cde84b057ab32.tar.gz
nixlib-ce74e1cc3681b1607822ba84184cde84b057ab32.tar.bz2
nixlib-ce74e1cc3681b1607822ba84184cde84b057ab32.tar.lz
nixlib-ce74e1cc3681b1607822ba84184cde84b057ab32.tar.xz
nixlib-ce74e1cc3681b1607822ba84184cde84b057ab32.tar.zst
nixlib-ce74e1cc3681b1607822ba84184cde84b057ab32.zip
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.
Diffstat (limited to 'nixos/modules/services/network-filesystems')
-rw-r--r--nixos/modules/services/network-filesystems/openafs/client.nix192
-rw-r--r--nixos/modules/services/network-filesystems/openafs/lib.nix28
2 files changed, 194 insertions, 26 deletions
diff --git a/nixos/modules/services/network-filesystems/openafs/client.nix b/nixos/modules/services/network-filesystems/openafs/client.nix
index e5f89a9a0d20..3826fe3edfd0 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
+          <literal>afsdb</literal> is set to <literal>true</literal>.
+        '';
+        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. <literal>0</literal> 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 <literal>true</literal>,
+          always do so. If <literal>false</literal>, 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. <literal>compat</literal> is
+          computationally less expensive, but <literal>md5</literal> 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
+          <literal>/afs</literal>. 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
+          <literal>fs disco online</literal> (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 000000000000..ecfc72d2eaf9
--- /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";
+    };
+  };
+}