summaryrefslogtreecommitdiffstats
path: root/krebs/3modules/syncthing.nix
blob: 389da81d4c61e26ea61fe066b5a60b35dc19fe61 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
{ config, pkgs, ... }: with import <stockholm/lib>;

let

  cfg = config.krebs.syncthing;

  devices = mapAttrsToList (name: peer: {
    name = name;
    deviceID = peer.id;
    addresses = peer.addresses;
  }) cfg.peers;

  folders = map (folder: {
    inherit (folder) path type;
    id = folder.path;
    devices = map (peer: { deviceId = cfg.peers.${peer}.id; }) folder.peers;
    rescanIntervalS = folder.rescanInterval;
  }) cfg.folders;

  getApiKey = pkgs.writeDash "getAPIKey" ''
    ${pkgs.libxml2}/bin/xmllint \
      --xpath 'string(configuration/gui/apikey)'\
      ${config.services.syncthing.dataDir}/config.xml
  '';

  updateConfig = pkgs.writeDash "merge-syncthing-config" ''
    set -efu
    API_KEY=$(${getApiKey})
    CFG=$(${pkgs.curl}/bin/curl -Ss -H "X-API-Key: $API_KEY" localhost:8384/rest/system/config)
    echo "$CFG" | ${pkgs.jq}/bin/jq -s '.[] * {
      "devices": ${builtins.toJSON devices},
      "folders": ${builtins.toJSON folders}
    }' | ${pkgs.curl}/bin/curl -Ss -H "X-API-Key: $API_KEY" localhost:8384/rest/system/config -d @-
    ${pkgs.curl}/bin/curl -Ss -H "X-API-Key: $API_KEY" localhost:8384/rest/system/restart -X POST
  '';

in

{
  options.krebs.syncthing = {

    enable = mkEnableOption "syncthing-init";

    id = mkOption {
      type = types.str;
      default = config.krebs.build.host.name;
    };

    cert = mkOption {
      type = types.nullOr types.absolute-pathname;
      default = null;
    };

    key = mkOption {
      type = types.nullOr types.absolute-pathname;
      default = null;
    };

    peers = mkOption {
      default = {};
      type = types.attrsOf (types.submodule ({
        options = {

          # TODO make into addr + port submodule
          addresses = mkOption {
            type = types.listOf types.str;
            default = [];
          };

          #TODO check
          id = mkOption {
            type = types.str;
          };

        };
      }));
    };

    folders = mkOption {
      default = [];
      type = types.listOf (types.submodule ({
        options = {

          path = mkOption {
            type = types.absolute-pathname;
          };

          peers = mkOption {
            type = types.listOf types.str;
            default = [];
          };

          rescanInterval = mkOption {
            type = types.int;
            default = 60;
          };

          type = mkOption {
            type = types.enum [ "sendreceive" "sendonly" "receiveonly" ];
            default = "sendreceive";
          };

        };
      }));
    };
  };

  config = (mkIf cfg.enable) {

    systemd.services.syncthing = mkIf (cfg.cert != null || cfg.key != null) {
      preStart = ''
        ${optionalString (cfg.cert != null) "cp ${toString cfg.cert} ${config.services.syncthing.dataDir}/cert.pem"}
        ${optionalString (cfg.key != null) "cp ${toString cfg.key} ${config.services.syncthing.dataDir}/key.pem"}
      '';
    };

    systemd.services.syncthing-init = {
      after = [ "syncthing.service" ];
      wantedBy = [ "multi-user.target" ];

      serviceConfig = {
        User = config.services.syncthing.user;
        RemainAfterExit = true;
        Type = "oneshot";
        ExecStart = updateConfig;
      };
    };
  };
}