Packaging pixiefairy

Hi all!

I’m looking to build a server hall with PXE booted hosts. My goal is to have individual kernel and initrd for each node, so I tried to use pixiefairy (not in nixpkgs) which is an API component to the excellent pixiecore (in nixpkgs).

I have created a repository for packaging it with Nix, and would be interested in getting it merged in nixpkgs. However, I had to make some changes to the code, but I don’t want to steal/claim ownership of the project. What should I do?

In addition I have a minimal NixOS module system for configuring pixiefairy as a systemd service, and would like to contribute it to NixOS as well. Here is the module Nix code:

{
  config,
  lib,
  pkgs,
  ...
}:
let
  cfg = config.services.pixiefairy;

  pixiefairyYaml = lib.generators.toYAML { } {
    api_key = cfg.apiKey;
    listen_address = cfg.listenAddress;
    listen_port = cfg.listenPort;
    external_url = if cfg.externalUrl == null then null else cfg.externalUrl;
    defaults = cfg.defaults;
    mapping = cfg.mapping;
  };

  configFilePath =
    if cfg.configFile != null then
      cfg.configFile
    else
      (pkgs.writeText "pixiefairy-config.yaml" (lib.traceVal pixiefairyYaml));
in
{
  options.services.pixiefairy = with lib; {
    enable = mkEnableOption "Pixiefairy PXE API daemon";

    package = mkOption {
      type = types.package;
      default = pkgs.pixiefairy;
      description = "The pixiefairy package to install and run";
    };

    apiKey = mkOption {
      type = types.nullOr types.str;
      default = null;
      description = "Static API key to use (auto-generated if null)";
    };

    listenAddress = mkOption {
      type = types.str;
      default = "0.0.0.0";
      description = "Address on which pixiefairy listens";
    };

    listenPort = mkOption {
      type = types.int;
      default = 5000;
      description = "Port on which pixiefairy listens";
    };

    externalUrl = mkOption {
      type = types.nullOr types.str;
      default = null;
      description = "External URL (for callbacks, defaults to http://<host>:<port>)";
    };

    openFirewall = mkOption {
      type = types.bool;
      default = false;
      description = "Automatically open firewall for the listenPort";
    };

    configFile = mkOption {
      type = types.nullOr types.str;
      default = null;
      description = "Path to the generated YAML config file";
    };

    defaults = mkOption {
      type = types.attrsOf types.anything;
      default = { };
      description = "Arbitrary default settings as attribute set";
    };

    mapping = mkOption {
      type = types.attrsOf types.anything;
      description = "Per-MAC override mapping";
      default = { };
    };
  };

  config = lib.mkIf cfg.enable {
    environment.systemPackages = [ cfg.package ];

    # Optionally open firewall port
    networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall [ cfg.listenPort ];

    # Systemd service
    systemd.services.pixiefairy = {
      description = "Pixiefairy PXE API daemon";
      after = [
        "network.target"
        "network-online.target"
      ];
      wantedBy = [ "multi-user.target" ];

      serviceConfig = {
        ExecStart = ''${cfg.package}/bin/pixiefairy start --config ${configFilePath}'';
        Restart = "on-failure";
        AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ];
      };
    };
  };
}

EDIT: This is my PR to merge my changes upstream

1 Like