Pour déployer le programme readeck2rm sous nixos j’ai écrit un module.

Le module va installer readeck2rm et rmapi, un service et un timer systemd.

Pour fonctionner readeck2rm a besoin de rmapi et d’un fichier de configuration. rmapi a aussi besoin d’un fichier de configuration.

Un exemple d’appel du module :

readeck2rm = {
  enable = true;
  url = "https://readeck.montfort.fr";
  #api_key = "XXX";
  sync_label = "remarkable";
  marker_label = "sync_remarkable";
  dest_path = "readeck";
  num_articles = 12;
  reading_time_prefix = true;
  delay = 0;
  environmentfile = config.age.secrets.readeck2rm-environmentfile.path;
  rmapi = "{lib.getExe pkgs-unstable.rmapi}";
  rampi-config = config.age.secrets.rmapi-config.path;
  log_level = "debug";
};

La définition du service :

systemd.services.readeck2rm = {
   enable = true;
   description = "Service pour readeck2rm";
   after = [ "network.target" ];
   wantedBy = [ "multi-user.target" ];
   environment = {
     RMAPI_CONFIG = "/var/lib/private/readeck2rm/rmapi.conf";
     XDG_CACHE_HOME = "/var/cache/readeck2rm";
   };
   script = ''
 ${pkgs.coreutils}/bin/cp -n ${config.readeck2rm.rmapi-config} /var/lib/private/readeck2rm/rmapi.conf
 ${pkgs.coreutils}/bin/chown -R $(${pkgs.coreutils}/bin/stat -c %u /var/lib/private/readeck2rm) /var/lib/private/readeck2rm/rmapi.conf
 ${pkgs.coreutils}/bin/chown -R $(${pkgs.coreutils}/bin/stat -c %g /var/lib/private/readeck2rm) /var/lib/private/readeck2rm/rmapi.conf
 ${pkgs.coreutils}/bin/chmod 600 /var/lib/private/readeck2rm/rmapi.conf
 ${pkgs.coreutils}/bin/ls -l /var/lib/private/readeck2rm/rmapi.conf
 ${pkgs.coreutils}/bin/env
 ${lib.getExe readeck2rm-app}
   '';

   serviceConfig = {
     Type = "oneshot";
     Restart = "no";
     DynamicUser = true;
     EnvironmentFile = "${config.readeck2rm.environmentfile}";
     RuntimeDirectory = "readeck2rm";
     StateDirectory = "readeck2rm";
     CacheDirectory = "readeck2rm";
   };
 };

Le service utilise DynamicUser pour créer un utilisateur système temporaire à chaque démarrage du service. Ce compte est supprimé à l’arrêt du service. Le service charge un fichier d’environnement contenant des variables. On l’utilise pour passer la clef d’api pour ne pas la mettre dans le code.

Des répertoires sont créés par systemd pour le service.

  • RuntimeDirectory est un répertoire temporaire (/run), accessible uniquement par le service et supprimé à l’arrêt.
  • StateDirectory est un répertoire persistant (/var/lib) qui va contenir les données d’état de notre service.
  • Enfin CacheDirectory et un répertoire (/var/cache) de cache.

Pour démarrer le service nous utilisons un script. Outre exécuter le programme lui-même, ce script va recopier le fichier de configuration de rmapi dans le répertoire temporaire. Ce fichier contient la clef d’api d’accès au service. Dans notre cas le fichier source est chiffré par age et est accessible uniquement par root. La recopie dans le répertoire permet de le rendre accessible au service et uniquement à lui.

Remarkable ayant encore changé son API, rmapi ne fonctionne plus. Heureusement la communauté a déjà corrigé le code. La version à jour de rmapi n’est pas encore disponible dans nixpkgs unstable (mais arrive vite dans master), mais il me suffit d’appliquer les patchs nécessaires et de reconstruire le paquet.

Pour avoir le patch il suffit d’ajouter .patch à l’url github du commit.

Le paramètre rmapi d’appel du module sera l’exécutable de notre paquet rmapi et plus celui du dépôt unstable.

Il n’est pas nécessaire de changer la version, je le fais pour garder une trace de mes modifications.

rmapi = pkgs-unstable.rmapi.overrideAttrs (old : {
  version = "0.0.31-patch";
  patches = (old.patches or []) ++ [
    (pkgs.fetchpatch {
      url = "https://github.com/ddvk/rmapi/commit/6ffeacbbdcaf3b744b03426a22ae6724dda4ba64.patch";
      sha256 = "sha256-W/Ah1370DIvMHcg4cPQ04hrolAzwvUbXuJXpuNQ4tFs";
    })
    (pkgs.fetchpatch {
      url = "https://github.com/ddvk/rmapi/commit/9cec4a5caddcb6d950252a6710eaaa57514f88a7.patch";
      sha256 = "sha256-z7v2znIRlPDVHgGI1vI2i+/Kf/hSdhKW3XP5Y6VhK8Q=";
    })
    (pkgs.fetchpatch {
      url = "https://github.com/ddvk/rmapi/commit/f5c7b9c2a32c503802c4fdc231e946eb4242574d.patch";
      sha256 = "sha256-xWyPDckTft61VTVbbFDBo1AP6tTZhaPeGMMErDMqqUo=";
    })
  ];
});

Je n’ai pas encore publié le module, il me reste quelques détails à corriger.