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.
This commit is contained in:
parent
c389d705f3
commit
ce74e1cc36
|
@ -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
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
|
28
nixos/modules/services/network-filesystems/openafs/lib.nix
Normal file
28
nixos/modules/services/network-filesystems/openafs/lib.nix
Normal file
|
@ -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";
|
||||
};
|
||||
};
|
||||
}
|
Loading…
Reference in a new issue