nixnixos

Loop over a list in NixOS using the value as an identifier?


In vhost.nix I want to add the users in a loop like the working example in httpd.virtualHosts.

This is the configuration.nix I am using in a virtual machine:

# vm.nix
{ lib, config, ... }:
{
  imports = [
    ./vhosts.nix
  ];

  services.httpd.enable = true;

  vhosts = {
    "test.example.de" = {
      customer = "web2";
      phpuser = "web2www1";
    };
    "test2.example.de" = {
      customer = "web3";
      phpuser = "web3www1";
    };
  };

}

this my module vhost.nix

{ config, pkgs, lib, ... }: 
with lib;
let
  cfg = config.vhosts;
in
  {
    options.vhosts = lib.mkOption {
      type = with lib.types; attrsOf (submodule ({domain, ... }: {
        options = {
          customer = mkOption {
            type = str;
          };
          phpuser = mkOption {
            type = str;
          };
        };
      }));
    };
    config = {
      services.httpd.virtualHosts = lib.mapAttrs (domain: cfg: {
        documentRoot = "/srv/www/${cfg.customer}/${domain}";
      }) cfg;

      # how do I solve this in a loop like above ?
      users.users.web2www1.isNormalUser = true;  
      users.users.web3www1.isNormalUser = true;
    };
  }

how do I solve this in a loop like above ?


Solution

  • Attribute sets supports string interpolation.

    You can write:

        users.users = lib.mapAttrs (domain: vhostCfg: {
          ${vhostCfg.phpuser} = { isNormalUser = true; };
        }) config.vhosts;
    

    It use lib.mapAttrs builtin to call a function on each attributes in config.vhosts :

    1. take the key (attribute name) as ${domain} argument,
    2. take the value (the vhost attribute set) as ${vhostCfg} argument,
    3. assign an attributes set to users.users NixOS configuration option that set config.users.users.${vhostCfg.phpuser}.isNormalUser to true.

    please note that this is untested, and mostly guess work.