forked from fediversity/fediversity
		
	
		
			
				
	
	
		
			406 lines
		
	
	
	
		
			15 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
			
		
		
	
	
			406 lines
		
	
	
	
		
			15 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
{
 | 
						|
  config,
 | 
						|
  system,
 | 
						|
  inputs ? (import ../../../default.nix { }).inputs, # XXX can't be serialized
 | 
						|
  sources ? import ../../../npins,
 | 
						|
  ...
 | 
						|
}@args:
 | 
						|
# FIXME allow default values for `config` module parameters?
 | 
						|
 | 
						|
let
 | 
						|
  # having this module's location (`self`) and (serializable) `args`, we know
 | 
						|
  # enough to make it re-call itself to extract different info elsewhere later.
 | 
						|
  # we use this to make a deployment script using the desired nixos config,
 | 
						|
  # which would otherwise not be serializable, while nix also makes it hard to
 | 
						|
  # produce its derivation to pass thru without a `nix-instantiate` call,
 | 
						|
  # which in turn would need to be passed the (unserializable) nixos config.
 | 
						|
  self = "deployment/check/common/data-model.nix";
 | 
						|
  inherit (sources) nixpkgs;
 | 
						|
  pkgs = import nixpkgs { inherit system; };
 | 
						|
  inherit (pkgs) lib;
 | 
						|
  deployment-config = config;
 | 
						|
  inherit (deployment-config)
 | 
						|
    nodeName
 | 
						|
    pathToRoot
 | 
						|
    targetSystem
 | 
						|
    sshOpts
 | 
						|
    httpBackend
 | 
						|
    proxmox-user
 | 
						|
    proxmox-password
 | 
						|
    node-name
 | 
						|
    ;
 | 
						|
  inherit (lib) mkOption types;
 | 
						|
  eval =
 | 
						|
    module:
 | 
						|
    (lib.evalModules {
 | 
						|
      specialArgs = {
 | 
						|
        inherit pkgs inputs sources;
 | 
						|
      };
 | 
						|
      modules = [
 | 
						|
        module
 | 
						|
        ../../data-model.nix
 | 
						|
      ];
 | 
						|
    }).config;
 | 
						|
  fediversity = eval (
 | 
						|
    { config, ... }:
 | 
						|
    {
 | 
						|
      config = {
 | 
						|
        resources.login-shell = {
 | 
						|
          description = "The operator needs to be able to log into the shell";
 | 
						|
          request =
 | 
						|
            { ... }:
 | 
						|
            {
 | 
						|
              _class = "fediversity-resource-request";
 | 
						|
              options = {
 | 
						|
                wheel = mkOption {
 | 
						|
                  description = "Whether the login user needs root permissions";
 | 
						|
                  type = types.bool;
 | 
						|
                  default = false;
 | 
						|
                };
 | 
						|
                packages = mkOption {
 | 
						|
                  description = "Packages that need to be available in the user environment";
 | 
						|
                  type = with types; attrsOf package;
 | 
						|
                };
 | 
						|
              };
 | 
						|
            };
 | 
						|
          policy =
 | 
						|
            { config, ... }:
 | 
						|
            {
 | 
						|
              _class = "fediversity-resource-policy";
 | 
						|
              options = {
 | 
						|
                username = mkOption {
 | 
						|
                  description = "Username for the operator";
 | 
						|
                  type = types.str; # TODO: use the proper constraints from NixOS
 | 
						|
                };
 | 
						|
                wheel = mkOption {
 | 
						|
                  description = "Whether to allow login with root permissions";
 | 
						|
                  type = types.bool;
 | 
						|
                  default = false;
 | 
						|
                };
 | 
						|
              };
 | 
						|
              config = {
 | 
						|
                resource-type = types.raw; # TODO: splice out the user type from NixOS
 | 
						|
                apply =
 | 
						|
                  requests:
 | 
						|
                  let
 | 
						|
                    # Filter out requests that need wheel if policy doesn't allow it
 | 
						|
                    validRequests = lib.filterAttrs (
 | 
						|
                      _name: req: !req.login-shell.wheel || config.wheel
 | 
						|
                    ) requests.resources;
 | 
						|
                  in
 | 
						|
                  lib.optionalAttrs (validRequests != { }) {
 | 
						|
                    ${config.username} = {
 | 
						|
                      isNormalUser = true;
 | 
						|
                      packages =
 | 
						|
                        with lib;
 | 
						|
                        attrValues (concatMapAttrs (_name: request: request.login-shell.packages) validRequests);
 | 
						|
                      extraGroups = lib.optional config.wheel "wheel";
 | 
						|
                      password = "password";
 | 
						|
                    };
 | 
						|
                  };
 | 
						|
              };
 | 
						|
            };
 | 
						|
        };
 | 
						|
        applications.hello =
 | 
						|
          { ... }:
 | 
						|
          {
 | 
						|
            description = ''Command-line tool that will print "Hello, world!" on the terminal'';
 | 
						|
            module =
 | 
						|
              { ... }:
 | 
						|
              {
 | 
						|
                options.enable = lib.mkEnableOption "Hello in the shell";
 | 
						|
              };
 | 
						|
            implementation = cfg: {
 | 
						|
              resources = lib.optionalAttrs cfg.enable {
 | 
						|
                hello.login-shell = {
 | 
						|
                  wheel = true;
 | 
						|
                  packages.hello = pkgs.hello;
 | 
						|
                };
 | 
						|
              };
 | 
						|
            };
 | 
						|
          };
 | 
						|
        environments =
 | 
						|
          let
 | 
						|
            mkNixosConfiguration =
 | 
						|
              environment: requests:
 | 
						|
              { ... }:
 | 
						|
              {
 | 
						|
                imports = [
 | 
						|
                  ./data-model-options.nix
 | 
						|
                  ../common/sharedOptions.nix
 | 
						|
                  # tests need this, however outside tests this (and esp its import nixos-test-base) must not be used
 | 
						|
                  ../common/targetNode.nix
 | 
						|
                  "${nixpkgs}/nixos/modules/profiles/minimal.nix"
 | 
						|
                  # "${nixpkgs}/nixos/modules/profiles/perlless.nix" # failed under disko
 | 
						|
                  "${nixpkgs}/nixos/modules/profiles/qemu-guest.nix"
 | 
						|
                  # systemd-repart
 | 
						|
                  # ../../../infra/common/nixos/repart.nix
 | 
						|
                  # disko
 | 
						|
                  "${sources.disko}/module.nix"
 | 
						|
                  ../../../infra/common/proxmox-qemu-vm.nix
 | 
						|
                ];
 | 
						|
 | 
						|
                # # non-disko
 | 
						|
                # boot.loader.grub.enable = false;
 | 
						|
                # boot.loader.systemd-boot.enable = true;
 | 
						|
 | 
						|
                # boot.loader.efi.efiSysMountPoint = "/boot";
 | 
						|
                # boot.loader.systemd-boot.edk2-uefi-shell.enable = true;
 | 
						|
                # boot.loader.efi.canTouchEfiVariables = true;
 | 
						|
                # # proxmox.qemuConf.bios == "ovmf";
 | 
						|
 | 
						|
                # boot.growPartition = true;
 | 
						|
                # boot.loader.timeout = 1;
 | 
						|
 | 
						|
                nixpkgs.hostPlatform = "x86_64-linux";
 | 
						|
 | 
						|
                system.stateVersion = "25.05";
 | 
						|
                services.qemuGuest.enable = true;
 | 
						|
                systemd.services.qemu-guest-agent = {
 | 
						|
                  wants = [ "network-online.target" ];
 | 
						|
                  after = [ "network-online.target" ];
 | 
						|
                };
 | 
						|
 | 
						|
                services.openssh = {
 | 
						|
                  enable = true;
 | 
						|
                  settings.PasswordAuthentication = false;
 | 
						|
                };
 | 
						|
                networking = {
 | 
						|
                  firewall.enable = false;
 | 
						|
                  usePredictableInterfaceNames = false;
 | 
						|
                  interfaces.eth0.ipv4.addresses = [
 | 
						|
                    {
 | 
						|
                      address = "95.215.187.101";
 | 
						|
                      prefixLength = 24;
 | 
						|
                    }
 | 
						|
                  ];
 | 
						|
                  interfaces.eth0.ipv6.addresses = [
 | 
						|
                    {
 | 
						|
                      address = "2a00:51c0:13:1305::101";
 | 
						|
                      prefixLength = 64;
 | 
						|
                    }
 | 
						|
                  ];
 | 
						|
                  defaultGateway = {
 | 
						|
                    address = "95.215.187.1";
 | 
						|
                    interface = "eth0";
 | 
						|
                  };
 | 
						|
                  defaultGateway6 = {
 | 
						|
                    address = "2a00:51c0:13:1305::1";
 | 
						|
                    interface = "eth0";
 | 
						|
                  };
 | 
						|
                  nameservers = [
 | 
						|
                    "95.215.185.6"
 | 
						|
                    "95.215.185.7"
 | 
						|
                    "2a00:51c0::5fd7:b906"
 | 
						|
                    "2a00:51c0::5fd7:b907"
 | 
						|
                  ];
 | 
						|
                };
 | 
						|
 | 
						|
                security.sudo.wheelNeedsPassword = false;
 | 
						|
                nix.settings.trusted-users = [ "@wheel" ];
 | 
						|
 | 
						|
                users.mutableUsers = false;
 | 
						|
                users.users =
 | 
						|
                  {
 | 
						|
                    root = {
 | 
						|
                      # password = "password"; # cannot log in
 | 
						|
                      hashedPassword = "$y$j9T$QoArNaV2VrjPhQ6BMG1AA.$uq8jw0.g.dJwIfepqipxzeUD1ochgUs8A5QmVe4qbJ6"; # cannot log in
 | 
						|
                      # hashedPasswordFile = pkgs.writeText "root-password" "$y$j9T$QoArNaV2VrjPhQ6BMG1AA.$uq8jw0.g.dJwIfepqipxzeUD1ochgUs8A5QmVe4qbJ6"; # type not null/string
 | 
						|
                      openssh.authorizedKeys.keys = [
 | 
						|
                        "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDHTIqF4CAylSxKPiSo5JOPuocn0y2z38wOSsQ1MUaZ2"
 | 
						|
                      ];
 | 
						|
                    };
 | 
						|
                    # can log in
 | 
						|
                    kiara = {
 | 
						|
                      isNormalUser = true;
 | 
						|
                      extraGroups = [ "wheel" ];
 | 
						|
                      password = "password";
 | 
						|
                      openssh.authorizedKeys.keys = [
 | 
						|
                        "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDHTIqF4CAylSxKPiSo5JOPuocn0y2z38wOSsQ1MUaZ2"
 | 
						|
                      ];
 | 
						|
                    };
 | 
						|
                    # cannot log in
 | 
						|
                    operator = {
 | 
						|
                      isNormalUser = true;
 | 
						|
                      extraGroups = [ "wheel" ];
 | 
						|
                      password = "password";
 | 
						|
                      openssh.authorizedKeys.keys = [
 | 
						|
                        "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDHTIqF4CAylSxKPiSo5JOPuocn0y2z38wOSsQ1MUaZ2"
 | 
						|
                      ];
 | 
						|
                    };
 | 
						|
                  }
 | 
						|
                  // environment.config.resources."operator-environment".login-shell.apply {
 | 
						|
                    resources = lib.filterAttrs (_name: value: value ? login-shell) (
 | 
						|
                      lib.concatMapAttrs (
 | 
						|
                        k': req: lib.mapAttrs' (k: lib.nameValuePair "${k'}.${k}") req.resources
 | 
						|
                      ) requests
 | 
						|
                    );
 | 
						|
                  };
 | 
						|
              };
 | 
						|
          in
 | 
						|
          {
 | 
						|
            single-nixos-vm-ssh = environment: {
 | 
						|
              resources."operator-environment".login-shell.username = "operator";
 | 
						|
              implementation =
 | 
						|
                {
 | 
						|
                  required-resources,
 | 
						|
                  deployment-name,
 | 
						|
                }:
 | 
						|
                {
 | 
						|
                  ssh-host = {
 | 
						|
                    nixos-configuration = mkNixosConfiguration environment required-resources;
 | 
						|
                    system = targetSystem;
 | 
						|
                    ssh = {
 | 
						|
                      username = "root";
 | 
						|
                      host = nodeName;
 | 
						|
                      key-file = null;
 | 
						|
                      inherit sshOpts;
 | 
						|
                    };
 | 
						|
                    module = self;
 | 
						|
                    inherit args deployment-name;
 | 
						|
                    root-path = pathToRoot;
 | 
						|
                  };
 | 
						|
                };
 | 
						|
            };
 | 
						|
            single-nixos-vm-nixops4 = environment: {
 | 
						|
              resources."operator-environment".login-shell.username = "operator";
 | 
						|
              implementation =
 | 
						|
                {
 | 
						|
                  required-resources,
 | 
						|
                  ...
 | 
						|
                }:
 | 
						|
                {
 | 
						|
                  nixops4 =
 | 
						|
                    { providers, ... }:
 | 
						|
                    {
 | 
						|
                      providers = {
 | 
						|
                        inherit (inputs.nixops4.modules.nixops4Provider) local;
 | 
						|
                      };
 | 
						|
                      resources.${nodeName} = {
 | 
						|
                        type = providers.local.exec;
 | 
						|
                        imports = [
 | 
						|
                          inputs.nixops4-nixos.modules.nixops4Resource.nixos
 | 
						|
                          ../common/targetResource.nix
 | 
						|
                        ];
 | 
						|
                        nixos.module = mkNixosConfiguration environment required-resources;
 | 
						|
                        _module.args = { inherit inputs sources; };
 | 
						|
                        inherit (deployment-config) nodeName pathToRoot pathFromRoot;
 | 
						|
                      };
 | 
						|
                    };
 | 
						|
                };
 | 
						|
            };
 | 
						|
            single-nixos-vm-tf = environment: {
 | 
						|
              resources."operator-environment".login-shell.username = "operator";
 | 
						|
              implementation =
 | 
						|
                {
 | 
						|
                  required-resources,
 | 
						|
                  deployment-name,
 | 
						|
                }:
 | 
						|
                {
 | 
						|
                  tf-host = {
 | 
						|
                    nixos-configuration = mkNixosConfiguration environment required-resources;
 | 
						|
                    system = targetSystem;
 | 
						|
                    ssh = {
 | 
						|
                      username = "root";
 | 
						|
                      host = nodeName;
 | 
						|
                      key-file = null;
 | 
						|
                      inherit sshOpts;
 | 
						|
                    };
 | 
						|
                    module = self;
 | 
						|
                    inherit args deployment-name httpBackend;
 | 
						|
                    root-path = pathToRoot;
 | 
						|
                  };
 | 
						|
                };
 | 
						|
            };
 | 
						|
            single-nixos-vm-tf-proxmox = environment: {
 | 
						|
              resources."operator-environment".login-shell = {
 | 
						|
                wheel = true;
 | 
						|
                username = "operator";
 | 
						|
              };
 | 
						|
              implementation =
 | 
						|
                {
 | 
						|
                  required-resources,
 | 
						|
                  deployment-name,
 | 
						|
                }:
 | 
						|
                {
 | 
						|
                  tf-proxmox-host = {
 | 
						|
                    nixos-configuration = mkNixosConfiguration environment required-resources;
 | 
						|
                    system = targetSystem;
 | 
						|
                    ssh = {
 | 
						|
                      username = "root";
 | 
						|
                      host = nodeName;
 | 
						|
                      key-file = null;
 | 
						|
                      inherit sshOpts;
 | 
						|
                    };
 | 
						|
                    module = self;
 | 
						|
                    inherit
 | 
						|
                      args
 | 
						|
                      deployment-name
 | 
						|
                      httpBackend
 | 
						|
                      proxmox-user
 | 
						|
                      proxmox-password
 | 
						|
                      node-name
 | 
						|
                      ;
 | 
						|
                    root-path = pathToRoot;
 | 
						|
                  };
 | 
						|
                };
 | 
						|
            };
 | 
						|
          };
 | 
						|
      };
 | 
						|
      options = {
 | 
						|
        "example-configuration" = mkOption {
 | 
						|
          type = config.configuration;
 | 
						|
          default = {
 | 
						|
            enable = true;
 | 
						|
            applications.hello.enable = true;
 | 
						|
          };
 | 
						|
        };
 | 
						|
        "ssh-deployment" =
 | 
						|
          let
 | 
						|
            env = config.environments."single-nixos-vm-ssh";
 | 
						|
          in
 | 
						|
          mkOption {
 | 
						|
            type = env.resource-mapping.output-type;
 | 
						|
            default = env.deployment {
 | 
						|
              deployment-name = "ssh-deployment";
 | 
						|
              configuration = config."example-configuration";
 | 
						|
            };
 | 
						|
          };
 | 
						|
        "nixops4-deployment" =
 | 
						|
          let
 | 
						|
            env = config.environments."single-nixos-vm-nixops4";
 | 
						|
          in
 | 
						|
          mkOption {
 | 
						|
            type = env.resource-mapping.output-type;
 | 
						|
            default = env.deployment {
 | 
						|
              deployment-name = "nixops4-deployment";
 | 
						|
              configuration = config."example-configuration";
 | 
						|
            };
 | 
						|
          };
 | 
						|
        "tf-deployment" =
 | 
						|
          let
 | 
						|
            env = config.environments."single-nixos-vm-tf";
 | 
						|
          in
 | 
						|
          mkOption {
 | 
						|
            type = env.resource-mapping.output-type;
 | 
						|
            default = env.deployment {
 | 
						|
              deployment-name = "tf-deployment";
 | 
						|
              configuration = config."example-configuration";
 | 
						|
            };
 | 
						|
          };
 | 
						|
        "tf-proxmox-deployment" =
 | 
						|
          let
 | 
						|
            env = config.environments."single-nixos-vm-tf-proxmox";
 | 
						|
          in
 | 
						|
          mkOption {
 | 
						|
            type = env.resource-mapping.output-type;
 | 
						|
            default = env.deployment {
 | 
						|
              deployment-name = "tf-proxmox-deployment";
 | 
						|
              configuration = config."example-configuration";
 | 
						|
            };
 | 
						|
          };
 | 
						|
      };
 | 
						|
    }
 | 
						|
  );
 | 
						|
in
 | 
						|
fediversity
 |