nixos/ipfs-cluster: init (#292290)

authored by

Arne Keller and committed by
GitHub
657dd8d7 194d448a

+129
+2
nixos/doc/manual/release-notes/rl-2505.section.md
··· 206 206 207 207 - [Pareto Security](https://paretosecurity.com/) is an alternative to corporate compliance solutions for companies that care about security but know it doesn't have to be invasive. Available as [services.paretosecurity](#opt-services.paretosecurity.enable) 208 208 209 + - [ipfs-cluster](https://ipfscluster.io/), Pinset orchestration for IPFS. Available as [services.ipfs-cluster](#opt-services.ipfs-cluster.enable) 210 + 209 211 <!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. --> 210 212 211 213 ## Backward Incompatibilities {#sec-release-25.05-incompatibilities}
+1
nixos/modules/module-list.nix
··· 1019 1019 ./services/network-filesystems/kubo.nix 1020 1020 ./services/network-filesystems/litestream/default.nix 1021 1021 ./services/network-filesystems/moosefs.nix 1022 + ./services/network-filesystems/ipfs-cluster.nix 1022 1023 ./services/network-filesystems/netatalk.nix 1023 1024 ./services/network-filesystems/nfsd.nix 1024 1025 ./services/network-filesystems/openafs/client.nix
+126
nixos/modules/services/network-filesystems/ipfs-cluster.nix
··· 1 + { 2 + config, 3 + lib, 4 + pkgs, 5 + options, 6 + ... 7 + }: 8 + let 9 + cfg = config.services.ipfs-cluster; 10 + 11 + # secret is by envvar, not flag 12 + initFlags = toString [ 13 + (lib.optionalString (cfg.initPeers != [ ]) "--peers") 14 + (lib.strings.concatStringsSep "," cfg.initPeers) 15 + ]; 16 + in 17 + { 18 + options = { 19 + 20 + services.ipfs-cluster = { 21 + 22 + enable = lib.mkEnableOption "Pinset orchestration for IPFS - requires ipfs daemon to be useful"; 23 + 24 + consensus = lib.mkOption { 25 + type = lib.types.enum [ 26 + "raft" 27 + "crdt" 28 + ]; 29 + description = "Consensus protocol - 'raft' or 'crdt'. https://cluster.ipfs.io/documentation/guides/consensus/"; 30 + }; 31 + 32 + dataDir = lib.mkOption { 33 + type = lib.types.str; 34 + default = "/var/lib/ipfs-cluster"; 35 + description = "The data dir for ipfs-cluster."; 36 + }; 37 + 38 + initPeers = lib.mkOption { 39 + type = lib.types.listOf lib.types.str; 40 + default = [ ]; 41 + description = "Peer addresses to initialize with on first run."; 42 + }; 43 + 44 + openSwarmPort = lib.mkOption { 45 + type = lib.types.bool; 46 + default = false; 47 + description = "Open swarm port, secured by the cluster secret. This does not expose the API or proxy. https://cluster.ipfs.io/documentation/guides/security/"; 48 + }; 49 + 50 + secretFile = lib.mkOption { 51 + type = lib.types.nullOr lib.types.path; 52 + default = null; 53 + description = '' 54 + File containing the cluster secret in the format of EnvironmentFile as described by 55 + {manpage}`systemd.exec(5)`. For example: 56 + <programlisting> 57 + CLUSTER_SECRET=<replaceable>...</replaceable> 58 + </programlisting> 59 + 60 + If null, a new secret will be generated on first run and stored in the data directory. 61 + A secret in the correct format can also be generated by: `openssl rand -hex 32` 62 + ''; 63 + }; 64 + }; 65 + }; 66 + 67 + config = lib.mkIf cfg.enable { 68 + assertions = [ 69 + { 70 + assertion = cfg.enable -> config.services.kubo.enable; 71 + message = "ipfs-cluster requires ipfs - configure and enable services.kubo"; 72 + } 73 + ]; 74 + 75 + environment.systemPackages = [ pkgs.ipfs-cluster ]; 76 + 77 + systemd.tmpfiles.rules = [ 78 + "d '${cfg.dataDir}' - ${config.services.kubo.user} ${config.services.kubo.group} - -" 79 + ]; 80 + 81 + systemd.services.ipfs-cluster-init = { 82 + path = [ 83 + "/run/wrappers" 84 + pkgs.ipfs-cluster 85 + ]; 86 + environment.IPFS_CLUSTER_PATH = cfg.dataDir; 87 + wantedBy = [ "default.target" ]; 88 + 89 + serviceConfig = { 90 + ExecStart = [ 91 + "${lib.getExe' pkgs.ipfs-cluster "ipfs-cluster-service"} init --consensus ${cfg.consensus} ${initFlags}" 92 + ]; 93 + Type = "oneshot"; 94 + RemainAfterExit = true; 95 + User = config.services.kubo.user; 96 + Group = config.services.kubo.group; 97 + EnvironmentFile = lib.mkIf (cfg.secretFile != null) cfg.secretFile; 98 + }; 99 + # only run once (= when the data directory is empty) 100 + unitConfig.ConditionDirectoryNotEmpty = "!${cfg.dataDir}"; 101 + }; 102 + 103 + systemd.services.ipfs-cluster = { 104 + environment.IPFS_CLUSTER_PATH = cfg.dataDir; 105 + wantedBy = [ "multi-user.target" ]; 106 + 107 + wants = [ "ipfs-cluster-init.service" ]; 108 + after = [ "ipfs-cluster-init.service" ]; 109 + 110 + serviceConfig = { 111 + Type = "notify"; 112 + ExecStart = [ "${lib.getExe' pkgs.ipfs-cluster "ipfs-cluster-service"} daemon" ]; 113 + User = config.services.kubo.user; 114 + Group = config.services.kubo.group; 115 + }; 116 + }; 117 + 118 + networking.firewall.allowedTCPPorts = lib.mkIf cfg.openSwarmPort [ 9096 ]; 119 + }; 120 + 121 + meta = { 122 + maintainers = with lib.maintainers; [ 123 + sorki 124 + ]; 125 + }; 126 + }