at master 3.7 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 options, 6 ... 7}: 8let 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 ]; 16in 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}