aboutsummaryrefslogblamecommitdiff
path: root/flakes/mediagoblin/flake.nix
blob: 2e821d52691a3a82cab149c37fd84c6856581d72 (plain) (tree)














































































































































































































































































                                                                                                                                      
{
  description = "a free software media publishing platform that anyone can run.";
  inputs.myuids = {
    url = "path:../myuids";
  };
  inputs.flake-utils.url = "github:numtide/flake-utils";
  inputs.nixpkgs = {
    url = "github:NixOS/nixpkgs/840c782d507d60aaa49aa9e3f6d0b0e780912742";
    flake = false;
  };
  inputs.mediagoblin = {
    url = "git+https://git.savannah.gnu.org/git/mediagoblin.git?submodules=1&ref=stable&rev=cd465ebfec837a75a44c4ebd727dffe2fff6d850";
    flake = false;
  };

  outputs = { self, myuids, nixpkgs, mediagoblin, flake-utils }: flake-utils.lib.eachSystem ["x86_64-linux"] (system:
    let
      pkgs = import nixpkgs { inherit system; overlays = []; };
      version = (builtins.fromJSON (builtins.readFile ./flake.lock)).nodes.mediagoblin.original.ref;
      inherit (pkgs) callPackage;
    in rec {
      packages.mediagoblin = callPackage ./. { src = mediagoblin // { inherit version; }; };
      defaultPackage = packages.mediagoblin;
      legacyPackages.mediagoblin = packages.mediagoblin;
      checks = {
        build = defaultPackage;
      };
    }
  ) // rec {
    overlays = {
      mediagoblin = final: prev: {
        mediagoblin = self.defaultPackage."${final.system}";
      };
    };
    overlay = overlays.mediagoblin;
    nixosModule = { lib, pkgs, config, ... }:
      let
        name = "mediagoblin";
        cfg = config.services.mediagoblin;

        uid = config.ids.uids.mediagoblin;
        gid = config.ids.gids.mediagoblin;

        paste_local = pkgs.writeText "paste_local.ini" ''
          [DEFAULT]
          debug = false

          [pipeline:main]
          pipeline = mediagoblin

          [app:mediagoblin]
          use = egg:mediagoblin#app
          config = ${cfg.configFile} ${cfg.package}/mediagoblin.ini
          /mgoblin_static = ${cfg.package}/mediagoblin/static

          [loggers]
          keys = root

          [handlers]
          keys = console

          [formatters]
          keys = generic

          [logger_root]
          level = INFO
          handlers = console

          [handler_console]
          class = StreamHandler
          args = (sys.stderr,)
          level = NOTSET
          formatter = generic

          [formatter_generic]
          format = %(levelname)-7.7s [%(name)s] %(message)s

          [filter:errors]
          use = egg:mediagoblin#errors
          debug = false

          [server:main]
          use = egg:waitress#main
          unix_socket = ${cfg.sockets.paster}
          unix_socket_perms = 777
          url_scheme = https
          '';
      in
      {
        options.services.mediagoblin = {
          enable = lib.mkEnableOption "Enable Mediagoblin’s service";
          user = lib.mkOption {
            type = lib.types.str;
            default = name;
            description = "User account under which Mediagoblin runs";
          };
          group = lib.mkOption {
            type = lib.types.str;
            default = name;
            description = "Group under which Mediagoblin runs";
          };
          dataDir = lib.mkOption {
            type = lib.types.path;
            default = "/var/lib/${name}";
            description = ''
              The directory where Mediagoblin stores its data.
            '';
          };
          socketsDir = lib.mkOption {
            type = lib.types.path;
            default = "/run/${name}";
            description = ''
              The directory where Mediagoblin puts runtime files and sockets.
              '';
          };
          configFile = lib.mkOption {
            type = lib.types.path;
            description = ''
              The configuration file path for Mediagoblin.
              '';
          };
          package = lib.mkOption {
            type = lib.types.package;
            default = pkgs.mediagoblin;
            example = lib.literalExample ''
              pkgs.webapps.mediagoblin.withPlugins (p: [p.basicsearch])
            '';
            description = ''
              Mediagoblin package to use.
              '';
          };
          systemdStateDirectory = lib.mkOption {
            type = lib.types.str;
            # Use ReadWritePaths= instead if varDir is outside of /var/lib
            default = assert lib.strings.hasPrefix "/var/lib/" cfg.dataDir;
              lib.strings.removePrefix "/var/lib/" cfg.dataDir;
            description = ''
            Adjusted Mediagoblin data directory for systemd
            '';
            readOnly = true;
          };
          systemdRuntimeDirectory = lib.mkOption {
            type = lib.types.str;
            # Use ReadWritePaths= instead if socketsDir is outside of /run
            default = assert lib.strings.hasPrefix "/run/" cfg.socketsDir;
              lib.strings.removePrefix "/run/" cfg.socketsDir;
            description = ''
            Adjusted Mediagoblin sockets directory for systemd
            '';
            readOnly = true;
          };
          sockets = lib.mkOption {
            type = lib.types.attrsOf lib.types.path;
            default = {
              paster = "${cfg.socketsDir}/mediagoblin.sock";
            };
            readOnly = true;
            description = ''
              Mediagoblin sockets
              '';
          };
          pids = lib.mkOption {
            type = lib.types.attrsOf lib.types.path;
            default = {
              paster = "${cfg.socketsDir}/mediagoblin.pid";
              celery = "${cfg.socketsDir}/mediagoblin-celeryd.pid";
            };
            readOnly = true;
            description = ''
              Mediagoblin pid files
              '';
          };
        };

        config = lib.mkIf cfg.enable {
          nixpkgs.overlays = [ self.overlay ];
          users.users = lib.optionalAttrs (cfg.user == name) {
            "${name}" = {
              inherit uid;
              group = cfg.group;
              description = "Mediagoblin user";
              home = cfg.dataDir;
              useDefaultShell = true;
            };
          };
          users.groups = lib.optionalAttrs (cfg.group == name) {
            "${name}" = {
              inherit gid;
            };
          };

          systemd.slices.mediagoblin = {
            description = "Mediagoblin slice";
          };
          systemd.services.mediagoblin-web = {
            description = "Mediagoblin service";
            wantedBy = [ "multi-user.target" ];
            after = [ "network.target" ];
            wants = [ "postgresql.service" "redis.service" ];

            environment.SCRIPT_NAME = "/mediagoblin/";

            script = ''
              exec ./bin/paster serve \
                ${paste_local} \
                --pid-file=${cfg.pids.paster}
              '';
            preStop = ''
              exec ./bin/paster serve \
                --pid-file=${cfg.pids.paster} \
                ${paste_local} stop
              '';
            preStart = ''
              if [ -d ${cfg.dataDir}/plugin_static/ ]; then
                rm ${cfg.dataDir}/plugin_static/coreplugin_basic_auth
                ln -sf ${cfg.package}/mediagoblin/plugins/basic_auth/static ${cfg.dataDir}/plugin_static/coreplugin_basic_auth
              fi
              ./bin/gmg -cf ${cfg.configFile} dbupdate
              '';

            serviceConfig = {
              Slice = "mediagoblin.slice";
              User = cfg.user;
              PrivateTmp = true;
              Restart = "always";
              TimeoutSec = 15;
              Type = "simple";
              WorkingDirectory = cfg.package;
              RuntimeDirectory = cfg.systemdRuntimeDirectory;
              StateDirectory= cfg.systemdStateDirectory;
              PIDFile = cfg.pids.paster;
            };

            unitConfig.RequiresMountsFor = cfg.dataDir;
          };

          systemd.services.mediagoblin-celeryd = {
            description = "Mediagoblin service";
            wantedBy = [ "multi-user.target" ];
            after = [ "network.target" "mediagoblin-web.service" ];

            environment.MEDIAGOBLIN_CONFIG = cfg.configFile;
            environment.CELERY_CONFIG_MODULE = "mediagoblin.init.celery.from_celery";

            script = ''
              exec ./bin/celery worker \
                --logfile=${cfg.dataDir}/celery.log \
                --loglevel=INFO
              '';

            serviceConfig = {
              Slice = "mediagoblin.slice";
              User = cfg.user;
              PrivateTmp = true;
              Restart = "always";
              TimeoutSec = 60;
              Type = "simple";
              WorkingDirectory = cfg.package;
              RuntimeDirectory = cfg.systemdRuntimeDirectory;
              StateDirectory= cfg.systemdStateDirectory;
              PIDFile = cfg.pids.celery;
            };

            unitConfig.RequiresMountsFor = cfg.dataDir;
          };
        };
      };
  };
}