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

500 views Asked by At

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 ?

1

There are 1 answers

0
VonC On BEST ANSWER

As noted by Chris, in Nix, traditional imperative programming constructs like for-loops are not used. Instead, functional programming paradigms are employed, specifically functions like map, fold, and filter that operate on lists or attribute sets.

You can use mapAttrs f attrset:

{ 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;

      users.users = lib.foldl' (acc: domain: let
                                  user = cfg.${domain}.phpuser;
                                in acc // { "${user}".isNormalUser = true; }
                                ) {} (lib.attrNames cfg);
    };
  }

lib.foldl' is used to iterate over the vhosts attribute set.
For each domain in vhosts, it extracts the phpuser and sets isNormalUser to true in the user's configuration.