forked from fediversity/fediversity
		
	
		
			
				
	
	
		
			201 lines
		
	
	
	
		
			7.9 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
			
		
		
	
	
			201 lines
		
	
	
	
		
			7.9 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
let
 | 
						|
  inherit (import ../default.nix { }) pkgs inputs;
 | 
						|
  inherit (pkgs) lib;
 | 
						|
  inherit (lib) mkOption types;
 | 
						|
  inherit (pkgs.callPackage ./utils.nix { inherit inputs; }) evalModel;
 | 
						|
  inherit (inputs.nixops4.lib) mkDeployment;
 | 
						|
in
 | 
						|
{
 | 
						|
  _class = "nix-unit";
 | 
						|
 | 
						|
  test-eval = {
 | 
						|
    /**
 | 
						|
      This tests a very simple arrangement that features all ingredients of the Fediversity business logic:
 | 
						|
      application, resource, environment, deployment; and wires it all up in one end-to-end exercise.
 | 
						|
      - The dummy resource is a login shell made available for some user.
 | 
						|
      - The dummy application is `hello` that requires a shell to be deployed.
 | 
						|
      - The dummy environment is a single NixOS VM that hosts one login shell, for the operator.
 | 
						|
      - The dummy configuration enables the `hello` application.
 | 
						|
      This will produce a NixOps4 deployment for a NixOS VM with a login shell for the operator and `hello` available.
 | 
						|
    */
 | 
						|
    expr =
 | 
						|
      let
 | 
						|
        fediversity = evalModel (
 | 
						|
          { 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";
 | 
						|
                          };
 | 
						|
                        };
 | 
						|
                    };
 | 
						|
                  };
 | 
						|
              };
 | 
						|
              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.packages.hello = pkgs.hello;
 | 
						|
                    };
 | 
						|
                  };
 | 
						|
                };
 | 
						|
              environments.single-nixos-vm =
 | 
						|
                { config, ... }:
 | 
						|
                {
 | 
						|
                  resources."operator-environment".login-shell.username = "operator";
 | 
						|
                  implementation = requests: {
 | 
						|
                    nixops4 = (
 | 
						|
                      { providers, ... }:
 | 
						|
                      {
 | 
						|
                        providers = {
 | 
						|
                          inherit (inputs.nixops4.modules.nixops4Provider) local;
 | 
						|
                        };
 | 
						|
                        resources.the-machine = {
 | 
						|
                          type = providers.local.exec;
 | 
						|
                          imports = [
 | 
						|
                            inputs.nixops4-nixos.modules.nixops4Resource.nixos
 | 
						|
                          ];
 | 
						|
                          nixos.module =
 | 
						|
                            { ... }:
 | 
						|
                            {
 | 
						|
                              users.users = 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
 | 
						|
                                );
 | 
						|
                              };
 | 
						|
                            };
 | 
						|
                        };
 | 
						|
                      }
 | 
						|
                    );
 | 
						|
                  };
 | 
						|
                };
 | 
						|
            };
 | 
						|
            options = {
 | 
						|
              "example-configuration" = mkOption {
 | 
						|
                type = config.configuration;
 | 
						|
                readOnly = true;
 | 
						|
                default = {
 | 
						|
                  enable = true;
 | 
						|
                  applications.hello.enable = true;
 | 
						|
                };
 | 
						|
              };
 | 
						|
              "example-deployment" = mkOption {
 | 
						|
                type = config.environments.single-nixos-vm.resource-mapping.output-type;
 | 
						|
                readOnly = true;
 | 
						|
                default = config.environments.single-nixos-vm.deployment config."example-configuration";
 | 
						|
              };
 | 
						|
            };
 | 
						|
          }
 | 
						|
        );
 | 
						|
        resources =
 | 
						|
          fediversity.applications.hello.resources
 | 
						|
            fediversity."example-configuration".applications.hello;
 | 
						|
        hello-shell = resources.resources.hello.login-shell;
 | 
						|
        environment = fediversity.environments.single-nixos-vm.resources."operator-environment".login-shell;
 | 
						|
        result = mkDeployment {
 | 
						|
          modules = [
 | 
						|
            (fediversity.environments.single-nixos-vm.deployment fediversity."example-configuration")
 | 
						|
          ];
 | 
						|
        };
 | 
						|
 | 
						|
      in
 | 
						|
      {
 | 
						|
        number-of-resources = with lib; length (attrNames fediversity.resources);
 | 
						|
        inherit (fediversity) example-configuration;
 | 
						|
        hello-package-exists = hello-shell.packages ? hello;
 | 
						|
        wheel-required = hello-shell.wheel;
 | 
						|
        wheel-allowed = environment.wheel;
 | 
						|
        operator-shell =
 | 
						|
          let
 | 
						|
            operator = (environment.apply resources).operator;
 | 
						|
          in
 | 
						|
          {
 | 
						|
            inherit (operator) isNormalUser;
 | 
						|
            packages = map (p: "${p.pname}") operator.packages;
 | 
						|
            extraGroups = operator.extraGroups;
 | 
						|
          };
 | 
						|
        deployment = {
 | 
						|
          inherit (result) _type;
 | 
						|
          deploymentFunction = lib.isFunction result.deploymentFunction;
 | 
						|
          getProviders = lib.isFunction result.getProviders;
 | 
						|
        };
 | 
						|
      };
 | 
						|
    expected = {
 | 
						|
      number-of-resources = 1;
 | 
						|
      example-configuration = {
 | 
						|
        enable = true;
 | 
						|
        applications.hello.enable = true;
 | 
						|
      };
 | 
						|
      hello-package-exists = true;
 | 
						|
      wheel-required = false;
 | 
						|
      wheel-allowed = false;
 | 
						|
      operator-shell = {
 | 
						|
        isNormalUser = true;
 | 
						|
        packages = [ "hello" ];
 | 
						|
        extraGroups = [ ];
 | 
						|
      };
 | 
						|
      deployment = {
 | 
						|
        _type = "nixops4Deployment";
 | 
						|
        deploymentFunction = true;
 | 
						|
        getProviders = true;
 | 
						|
      };
 | 
						|
    };
 | 
						|
  };
 | 
						|
}
 |