From 1d4c8455eeae304d597531dbdf084a9630a03ba4 Mon Sep 17 00:00:00 2001 From: fwastring Date: Thu, 2 Apr 2026 10:58:37 +0200 Subject: [PATCH] huge refactor --- maskiner/archive/alloy-systemd.yaml | 20 -- maskiner/archive/configuration.nix | 83 ------- maskiner/archive/hardware-configuration.nix | 39 ---- maskiner/core/configuration.nix | 11 +- maskiner/gammal/configuration.nix | 122 ---------- maskiner/gammal/hardware-configuration.nix | 18 -- maskiner/gammal/laptop-disk.nix | 35 --- maskiner/laptop/configuration.nix | 7 +- maskiner/legacy/hardware-configuration.nix | 18 -- maskiner/node/configuration.nix | 11 +- maskiner/styrelsen/configuration.nix | 11 +- maskiner/styrelsen/laptop-disk.nix | 35 --- moduler/dev.nix | 33 +-- moduler/features/README.md | 108 +++++++++ moduler/features/default.nix | 81 +++++++ moduler/features/standard/default.nix | 13 ++ moduler/git.nix | 20 +- moduler/network.nix | 36 +-- moduler/programs.nix | 146 +----------- moduler/programs/base/default.nix | 245 ++++++++++++++++++++ moduler/programs/dev/default.nix | 109 +++++++++ moduler/programs/git/default.nix | 45 ++++ moduler/services/network/default.nix | 69 ++++++ moduler/services/sound/default.nix | 71 ++++++ moduler/services/system/default.nix | 78 +++++++ moduler/services/users/default.nix | 62 +++++ moduler/services/webcam-rtsp/default.nix | 38 +++ moduler/sound.nix | 29 +-- moduler/system.nix | 41 +--- moduler/users.nix | 35 +-- 30 files changed, 972 insertions(+), 697 deletions(-) delete mode 100644 maskiner/archive/alloy-systemd.yaml delete mode 100644 maskiner/archive/configuration.nix delete mode 100644 maskiner/archive/hardware-configuration.nix delete mode 100644 maskiner/gammal/configuration.nix delete mode 100644 maskiner/gammal/hardware-configuration.nix delete mode 100644 maskiner/gammal/laptop-disk.nix delete mode 100644 maskiner/legacy/hardware-configuration.nix delete mode 100644 maskiner/styrelsen/laptop-disk.nix create mode 100644 moduler/features/README.md create mode 100644 moduler/features/default.nix create mode 100644 moduler/features/standard/default.nix create mode 100644 moduler/programs/base/default.nix create mode 100644 moduler/programs/dev/default.nix create mode 100644 moduler/programs/git/default.nix create mode 100644 moduler/services/network/default.nix create mode 100644 moduler/services/sound/default.nix create mode 100644 moduler/services/system/default.nix create mode 100644 moduler/services/users/default.nix diff --git a/maskiner/archive/alloy-systemd.yaml b/maskiner/archive/alloy-systemd.yaml deleted file mode 100644 index 07588f5..0000000 --- a/maskiner/archive/alloy-systemd.yaml +++ /dev/null @@ -1,20 +0,0 @@ -loki.relabel "journal" { - forward_to = [] - - rule { - source_labels = ["__journal__systemd_unit"] - target_label = "unit" - } -} - -loki.source.journal "read" { - forward_to = [loki.write.endpoint.receiver] - relabel_rules = loki.relabel.journal.rules - labels = {component = "macmini"} -} - -loki.write "endpoint" { - endpoint { - url ="http://192.168.1.143:3100/loki/api/v1/push" - } -} diff --git a/maskiner/archive/configuration.nix b/maskiner/archive/configuration.nix deleted file mode 100644 index 1382797..0000000 --- a/maskiner/archive/configuration.nix +++ /dev/null @@ -1,83 +0,0 @@ -# This is your system's configuration file. -# Use this to configure your system environment (it replaces /etc/nixos/configuration.nix) -{ - inputs, - lib, - config, - pkgs, - myhostname, - ... -}: -let - modulesDirectory = ../../moduler; -in -{ - # You can import other NixOS modules here - imports = [ - ./hardware-configuration.nix - - (modulesDirectory + /services/base) - - ../../moduler/users.nix - ../../moduler/services/monitoring - ]; - - alloy = { - enable = true; - configPath = ./alloy-systemd.yaml; - }; - - nixpkgs.config.permittedInsecurePackages = [ - "broadcom-sta-6.30.223.271-59-6.12.58" - ]; - - nix.settings = { - trusted-public-keys = [ - "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=" - "hyprland.cachix.org-1:a7pgxzMz7+chwVL3/pzj6jIBMioiJM7ypFP8PwtkuGc=" - ]; - }; - - security.sudo.wheelNeedsPassword = false; - users.users.root.openssh.authorizedKeys.keys = [ - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDALsdpwvC0w/Aj+1fWtzJyyWoUrGkdh8o2thVHeQQBNo0D7cmVberYmi4Cv9gWGX6PaElrnOl0KRdGyro2wxOYokSxgk2VgWW67BFITAQAbKyG2NhXXPbhb4jccDo7WH7TtOG8IofuJTPRu1Duda6k4RN0I0CkyAN6LGX+zy49cq0qKf9ijXYhCDYNih3+Fu/ig0aW/SYmsVoUl2VFTWdI5x5/wLvIjTEZhmAtYIeYADaLnom356cFrUysZa++FUujQAz3Ow236BvP95XZdTsqvfWNZFNIpC9VYF72JeIDCs5wDIr0GFmanF2On1nar+jJpoOE8SdHt357p5g/PqXV5TisN2xQRkqVwO9tWtMl4sF84jA4ULnY2gQWv9jErMxymUQ1IwuPUzDDlbRHCtfexAtkBy7wv6xslKAzG1QahvF/btNs5Caj3LN31rgAuxyooCbKGKTeBP3kHPKcz1iupgidfbO/QqVXBRQJTEdGyAKa8hVmLQZZPC/XUhxESAk= fw@fw-nix" - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC8ku8iCb7tXd/tfxYDW+Tj8K9kpfrYZciYUZ6tBpO80inm4EImtfyEeJTuqDWMKov2BftUKs8brNeTBCXUEvU1P0+cpOP9RtYA5tfBXf3su+iVSswJJStIxNboXHrEGKdJJRNsTv/9agshDSUBy6G5TI1cXhv/updornfA4fwOMqOmtlYEn6XCRnsrO6NBLc/uLckdbF75HOsoLvezRvuqTLjpapjaUKGVPrgNXiclIKHmuOx71kgD4FX3rSz9FgKjnfu3a7DBbrHsf/g+N9PjNF1muN9UOV6nK3WwiO9BMWi7NpAWfzJOeZg9chqzI+U6CcsqYVeESgL41so+dnv3 fw@laptop" - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIP34dnsZSnWdDvd+3BXDwcw7wP0PjPEx2eCdBQJyGD6O fw@laptop" - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII60tdNsG0z9q2jHmoTKvkeLQE6OF0bmTsDX1bpqpoG7 fw@jobb" - ]; - - # Restic - users.users.restic = { - isNormalUser = true; - createHome = true; - home = "/home/restic"; - openssh.authorizedKeys.keys = [ - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIP34dnsZSnWdDvd+3BXDwcw7wP0PjPEx2eCdBQJyGD6O fw@laptop" - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII60tdNsG0z9q2jHmoTKvkeLQE6OF0bmTsDX1bpqpoG7 fw@jobb" - ]; - }; - - # Where repos will live (you can choose a different path/disk) - systemd.tmpfiles.rules = [ - "d /srv/restic 0750 restic restic -" - ]; - - networking.firewall.allowedUDPPorts = [ - 22000 - 21027 - ]; - - services = { - openssh = { - enable = true; - allowSFTP = true; - }; - }; - - security.rtkit.enable = true; - networking.hostName = myhostname; - - services.xserver.dpi = 100; - - system.stateVersion = "24.11"; -} diff --git a/maskiner/archive/hardware-configuration.nix b/maskiner/archive/hardware-configuration.nix deleted file mode 100644 index 57c3ec5..0000000 --- a/maskiner/archive/hardware-configuration.nix +++ /dev/null @@ -1,39 +0,0 @@ -# Do not modify this file! It was generated by ‘nixos-generate-config’ -# and may be overwritten by future invocations. Please make changes -# to /etc/nixos/configuration.nix instead. -{ config, lib, pkgs, modulesPath, ... }: - -{ - imports = - [ (modulesPath + "/installer/scan/not-detected.nix") - ]; - - boot.initrd.availableKernelModules = [ "ohci_pci" "ehci_pci" "ahci" "firewire_ohci" "usb_storage" "usbhid" "sd_mod" "sr_mod" ]; - boot.initrd.kernelModules = [ ]; - boot.kernelModules = [ "kvm-intel" "wl" ]; - boot.extraModulePackages = [ config.boot.kernelPackages.broadcom_sta ]; - - fileSystems."/" = - { device = "/dev/disk/by-uuid/1c7e7116-3486-45a8-90c0-d3deea8e96b0"; - fsType = "ext4"; - }; - - fileSystems."/boot" = - { device = "/dev/disk/by-uuid/B70D-941F"; - fsType = "vfat"; - options = [ "fmask=0077" "dmask=0077" ]; - }; - - swapDevices = [ ]; - - # Enables DHCP on each ethernet and wireless interface. In case of scripted networking - # (the default) this is the recommended approach. When using systemd-networkd it's - # still possible to use this option, but it's recommended to use it in conjunction - # with explicit per-interface declarations with `networking.interfaces..useDHCP`. - networking.useDHCP = lib.mkDefault true; - # networking.interfaces.enp4s0.useDHCP = lib.mkDefault true; - # networking.interfaces.wlp3s0b1.useDHCP = lib.mkDefault true; - - nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; - hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; -} diff --git a/maskiner/core/configuration.nix b/maskiner/core/configuration.nix index 62ae60d..dff60a8 100644 --- a/maskiner/core/configuration.nix +++ b/maskiner/core/configuration.nix @@ -12,14 +12,7 @@ in { imports = [ ./hardware-configuration.nix - - (modulesDirectory + /users.nix) - (modulesDirectory + /git.nix) - (modulesDirectory + /network.nix) - (modulesDirectory + /programs.nix) - (modulesDirectory + /system.nix) - (modulesDirectory + /dev.nix) - (modulesDirectory + /sound.nix) + (modulesDirectory + /features/standard) (modulesDirectory + /programs/kubernetes-tools.nix) (modulesDirectory + /services/base) @@ -30,6 +23,8 @@ in ]; kubernetes-tools.enable = true; + features.profile = "desktop"; + networking.hostName = myhostname; security.pki.certificateFiles = [ diff --git a/maskiner/gammal/configuration.nix b/maskiner/gammal/configuration.nix deleted file mode 100644 index 7ec0f19..0000000 --- a/maskiner/gammal/configuration.nix +++ /dev/null @@ -1,122 +0,0 @@ -# Edit this configuration file to define what should be installed on -# your system. Help is available in the configuration.nix(5) man page -# and in the NixOS manual (accessible by running ‘nixos-help’). - -{ - inputs, - pkgs, - myhostname, - ... -}: -let - theme = "mocha"; - modulesDirectory = ../../moduler; -in -{ - imports = [ - ./hardware-configuration.nix - - (modulesDirectory + /users.nix) - (modulesDirectory + /git.nix) - (modulesDirectory + /network.nix) - (modulesDirectory + /programs.nix) - (modulesDirectory + /system.nix) - (modulesDirectory + /dev.nix) - (modulesDirectory + /sound.nix) - - (modulesDirectory + /services/base) - - (modulesDirectory + /programs/hyprland) - (modulesDirectory + /programs/nixvim) - ]; - - networking.networkmanager = { - enable = true; - plugins = with pkgs; [ - networkmanager-openvpn - ]; - }; - - stylix = { - enable = true; - base16Scheme = "${pkgs.base16-schemes}/share/themes/catppuccin-${theme}.yaml"; - }; - - nixvim = { - enable = true; - theme = theme; - }; - - hyprland = { - enable = true; - theme = theme; - }; - - home-manager.extraSpecialArgs = { inherit inputs pkgs; }; - home-manager.users.fw = { - imports = [ - ./../../moduler/home.nix - ./../../moduler/programs/waybar - inputs.catppuccin.homeModules.catppuccin - ]; - waybar = { - enable = true; - profile = "laptop"; - theme = theme; - }; - gtk = { - enable = true; - iconTheme = { - name = "oomox-gruvbox-dark"; - package = pkgs.gruvbox-dark-icons-gtk; - }; - }; - kitty = { - enable = true; - theme = theme; - }; - fish = { - theme = theme; - }; - k9s = { - enable = true; - theme = theme; - }; - oh-my-posh = { - enable = true; - theme = theme; - }; - catppuccin = { - librewolf = { - enable = true; - flavor = theme; - accent = "peach"; - }; - }; - programs.ranger.enable = true; - stylix.targets = { - lazygit.enable = false; - fish.enable = false; - kitty.enable = false; - waybar.enable = false; - tmux.enable = false; - k9s.enable = false; - }; - }; - - security.sudo.wheelNeedsPassword = false; - users.users.root.openssh.authorizedKeys.keys = [ - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII60tdNsG0z9q2jHmoTKvkeLQE6OF0bmTsDX1bpqpoG7 fw@jobb" - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFpJBGPIfPB1BwSG7aoKqwfccyZSaU7J3xpJ8behMp9N fw@core" - ]; - - services.upower = { - enable = true; - }; - - boot.kernelPackages = pkgs.linuxPackages_latest; - - networking.hostName = myhostname; - - system.stateVersion = "25.05"; -} diff --git a/maskiner/gammal/hardware-configuration.nix b/maskiner/gammal/hardware-configuration.nix deleted file mode 100644 index e41d1fc..0000000 --- a/maskiner/gammal/hardware-configuration.nix +++ /dev/null @@ -1,18 +0,0 @@ -# Do not modify this file! It was generated by ‘nixos-generate-config’ -# and may be overwritten by future invocations. Please make changes -# to /etc/nixos/configuration.nix instead. -{ config, lib, pkgs, modulesPath, ... }: - -{ - imports = - [ (modulesPath + "/installer/scan/not-detected.nix") - ]; - - boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "nvme" "usb_storage" "sd_mod" ]; - boot.initrd.kernelModules = [ ]; - boot.kernelModules = [ "kvm-intel" ]; - boot.extraModulePackages = [ ]; - - nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; - hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; -} diff --git a/maskiner/gammal/laptop-disk.nix b/maskiner/gammal/laptop-disk.nix deleted file mode 100644 index 2b12574..0000000 --- a/maskiner/gammal/laptop-disk.nix +++ /dev/null @@ -1,35 +0,0 @@ -{ lib, ... }: - -{ - disko.devices = { - disk = { - main = { - device = lib.mkDefault "/dev/sda"; - type = "disk"; - content = { - type = "gpt"; - partitions = { - ESP = { - type = "EF00"; - size = "1G"; - content = { - type = "filesystem"; - format = "vfat"; - mountpoint = "/boot"; - mountOptions = [ "umask=0077" ]; - }; - }; - root = { - size = "100%"; - content = { - type = "filesystem"; - format = "ext4"; - mountpoint = "/"; - }; - }; - }; - }; - }; - }; - }; -} diff --git a/maskiner/laptop/configuration.nix b/maskiner/laptop/configuration.nix index 77054b2..1141248 100644 --- a/maskiner/laptop/configuration.nix +++ b/maskiner/laptop/configuration.nix @@ -13,10 +13,7 @@ in { imports = [ ./hardware-configuration.nix - - (modulesDirectory + /users.nix) - (modulesDirectory + /network.nix) - (modulesDirectory + /system.nix) + (modulesDirectory + /features/standard) (modulesDirectory + /services/base) (modulesDirectory + /services/webcam-rtsp) @@ -26,6 +23,8 @@ in enable = true; }; + features.profile = "camera"; + hardware.graphics = { enable = true; extraPackages = with pkgs; [ diff --git a/maskiner/legacy/hardware-configuration.nix b/maskiner/legacy/hardware-configuration.nix deleted file mode 100644 index 3870e49..0000000 --- a/maskiner/legacy/hardware-configuration.nix +++ /dev/null @@ -1,18 +0,0 @@ -# Do not modify this file! It was generated by ‘nixos-generate-config’ -# and may be overwritten by future invocations. Please make changes -# to /etc/nixos/configuration.nix instead. -{ config, lib, pkgs, modulesPath, ... }: - -{ - imports = - [ (modulesPath + "/installer/scan/not-detected.nix") - ]; - - boot.initrd.availableKernelModules = [ "xhci_pci" "nvme" "usb_storage" "sd_mod" ]; - boot.initrd.kernelModules = [ ]; - boot.kernelModules = [ ]; - boot.extraModulePackages = [ ]; - - nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; - hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; -} diff --git a/maskiner/node/configuration.nix b/maskiner/node/configuration.nix index 09723f2..918563a 100644 --- a/maskiner/node/configuration.nix +++ b/maskiner/node/configuration.nix @@ -48,8 +48,7 @@ in # You can import other NixOS modules here imports = [ ./hardware-configuration.nix - - (modulesDirectory + /users.nix) + (modulesDirectory + /features/standard) (modulesDirectory + /kitchenowl.nix) # (modulesDirectory + /radicale.nix) (modulesDirectory + /vaultwarden.nix) @@ -73,6 +72,8 @@ in ]; sops.defaultSopsFile = ../../secrets/sops.yaml; + features.profile = "server"; + sops.age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ]; sops.secrets.gandi_key = { path = "/run/secrets/gandi_key"; @@ -140,9 +141,9 @@ in }; home-manager.users.fw = { - # imports = [ - # (modulesDirectory + /programs/beets) - # ]; + imports = [ + (modulesDirectory + /programs/beets) + ]; home.username = "fw"; home.homeDirectory = "/home/fw"; diff --git a/maskiner/styrelsen/configuration.nix b/maskiner/styrelsen/configuration.nix index 2e6096d..422265b 100644 --- a/maskiner/styrelsen/configuration.nix +++ b/maskiner/styrelsen/configuration.nix @@ -16,14 +16,7 @@ in { imports = [ ./hardware-configuration.nix - - (modulesDirectory + /users.nix) - (modulesDirectory + /git.nix) - (modulesDirectory + /network.nix) - (modulesDirectory + /programs.nix) - (modulesDirectory + /system.nix) - (modulesDirectory + /dev.nix) - (modulesDirectory + /sound.nix) + (modulesDirectory + /features/standard) (modulesDirectory + /services/base) @@ -33,6 +26,8 @@ in ]; kubernetes-tools.enable = true; + features.profile = "laptop"; + networking.networkmanager = { enable = true; }; diff --git a/maskiner/styrelsen/laptop-disk.nix b/maskiner/styrelsen/laptop-disk.nix deleted file mode 100644 index aaddc32..0000000 --- a/maskiner/styrelsen/laptop-disk.nix +++ /dev/null @@ -1,35 +0,0 @@ -{ lib, ... }: - -{ - disko.devices = { - disk = { - main = { - device = lib.mkDefault "/dev/nvme0n1"; - type = "disk"; - content = { - type = "gpt"; - partitions = { - ESP = { - type = "EF00"; - size = "1G"; - content = { - type = "filesystem"; - format = "vfat"; - mountpoint = "/boot"; - mountOptions = [ "umask=0077" ]; - }; - }; - root = { - size = "100%"; - content = { - type = "filesystem"; - format = "ext4"; - mountpoint = "/"; - }; - }; - }; - }; - }; - }; - }; -} diff --git a/moduler/dev.nix b/moduler/dev.nix index 2eb48df..cf7a33b 100644 --- a/moduler/dev.nix +++ b/moduler/dev.nix @@ -1,31 +1,8 @@ +{ lib, ... }: { - inputs, - pkgs, - ... -}: -let - azPkgs = inputs.nixpkgs-azure-cli.legacyPackages.${pkgs.stdenv.hostPlatform.system}; -in -{ - - environment.systemPackages = with pkgs; [ - nixfmt-rfc-style - lazydocker - gh - awscli - minio-client - opentofu - python3 - (azPkgs.azure-cli.withExtensions ( - with azPkgs.azure-cli.extensions; - [ - # aks-preview - # ssh - fzf - ] - )) - yq - jq - git + imports = [ + ./programs/dev ]; + + features.dev.enable = lib.mkDefault true; } diff --git a/moduler/features/README.md b/moduler/features/README.md new file mode 100644 index 0000000..3e83449 --- /dev/null +++ b/moduler/features/README.md @@ -0,0 +1,108 @@ +# Feature Profiles + +This directory provides a profile + overrides model for host configuration. + +## Imports + +Use this in host `imports`: + +```nix +(modulesDirectory + /features/standard) +``` + +`features/standard` imports: + +- `features` profile module +- `services/users` +- `services/network` +- `services/system` +- `services/sound` +- `programs/base` +- `programs/git` +- `programs/dev` + +## Profile Selection + +Set one profile per host: + +```nix +features.profile = "desktop"; +``` + +Supported values: + +- `custom` +- `desktop` +- `laptop` +- `server` +- `camera` + +Profiles set `mkDefault` values, so you can override any option per host. + +## Common Overrides + +### Base packages + +```nix +features.base = { + enable = true; + preset = "minimal"; + packages.captureEnable = true; +}; +``` + +### Dev tools + +```nix +features.dev = { + enable = true; + preset = "minimal"; + cloud.aws.enable = false; + cloud.azure.enable = false; +}; +``` + +### Network + +```nix +features.network = { + enable = true; + netbird.enable = false; + tooling.enable = false; +}; +``` + +### Sound/Bluetooth + +```nix +features.sound = { + enable = true; + bluetooth.enable = false; +}; +``` + +### Git defaults + +```nix +features.git = { + enable = true; + userName = "myuser"; + userEmail = "me@example.com"; +}; +``` + +### Users + +```nix +features.users = { + enable = true; + name = "fw"; + fullName = "Fredrik Wastring"; + extraGroups = [ "wheel" "networkmanager" ]; +}; +``` + +## Notes + +- If you only import `features/default.nix`, profile defaults are applied only for options that exist in imported modules. +- `features/standard` is the easiest option for hosts that should expose all common feature knobs. diff --git a/moduler/features/default.nix b/moduler/features/default.nix new file mode 100644 index 0000000..5bebaaf --- /dev/null +++ b/moduler/features/default.nix @@ -0,0 +1,81 @@ +{ + lib, + config, + options, + ... +}: +with lib; +let + profile = config.features.profile; + has = path: lib.hasAttrByPath path options; + setIf = path: value: lib.optionalAttrs (has path) (lib.setAttrByPath path value); +in +{ + options.features.profile = mkOption { + type = types.enum [ + "custom" + "desktop" + "laptop" + "server" + "camera" + ]; + default = "custom"; + description = "Host feature profile. Use custom for fully explicit per-feature settings."; + }; + + config = mkMerge [ + (mkIf (profile == "desktop") (mkMerge [ + (setIf [ "features" "base" "enable" ] (mkDefault true)) + (setIf [ "features" "base" "preset" ] (mkDefault "full")) + (setIf [ "features" "git" "enable" ] (mkDefault true)) + (setIf [ "features" "dev" "enable" ] (mkDefault true)) + (setIf [ "features" "dev" "preset" ] (mkDefault "full")) + (setIf [ "features" "users" "enable" ] (mkDefault true)) + (setIf [ "features" "network" "enable" ] (mkDefault true)) + (setIf [ "features" "network" "tooling" "enable" ] (mkDefault true)) + (setIf [ "features" "system" "enable" ] (mkDefault true)) + (setIf [ "features" "system" "preset" ] (mkDefault "desktop")) + (setIf [ "features" "sound" "enable" ] (mkDefault true)) + ])) + + (mkIf (profile == "laptop") (mkMerge [ + (setIf [ "features" "base" "enable" ] (mkDefault true)) + (setIf [ "features" "base" "preset" ] (mkDefault "standard")) + (setIf [ "features" "git" "enable" ] (mkDefault true)) + (setIf [ "features" "dev" "enable" ] (mkDefault true)) + (setIf [ "features" "dev" "preset" ] (mkDefault "standard")) + (setIf [ "features" "users" "enable" ] (mkDefault true)) + (setIf [ "features" "network" "enable" ] (mkDefault true)) + (setIf [ "features" "network" "tooling" "enable" ] (mkDefault true)) + (setIf [ "features" "system" "enable" ] (mkDefault true)) + (setIf [ "features" "system" "preset" ] (mkDefault "desktop")) + (setIf [ "features" "sound" "enable" ] (mkDefault true)) + ])) + + (mkIf (profile == "server") (mkMerge [ + (setIf [ "features" "users" "enable" ] (mkDefault true)) + (setIf [ "features" "network" "enable" ] (mkDefault true)) + (setIf [ "features" "network" "netbird" "enable" ] (mkDefault false)) + (setIf [ "features" "network" "tooling" "enable" ] (mkDefault false)) + (setIf [ "features" "system" "enable" ] (mkDefault true)) + (setIf [ "features" "system" "preset" ] (mkDefault "minimal")) + (setIf [ "features" "base" "enable" ] (mkDefault false)) + (setIf [ "features" "git" "enable" ] (mkDefault false)) + (setIf [ "features" "dev" "enable" ] (mkDefault false)) + (setIf [ "features" "sound" "enable" ] (mkDefault false)) + ])) + + (mkIf (profile == "camera") (mkMerge [ + (setIf [ "features" "users" "enable" ] (mkDefault true)) + (setIf [ "features" "network" "enable" ] (mkDefault true)) + (setIf [ "features" "network" "netbird" "enable" ] (mkDefault false)) + (setIf [ "features" "network" "tooling" "enable" ] (mkDefault false)) + (setIf [ "features" "system" "enable" ] (mkDefault true)) + (setIf [ "features" "system" "preset" ] (mkDefault "minimal")) + (setIf [ "features" "base" "enable" ] (mkDefault false)) + (setIf [ "features" "git" "enable" ] (mkDefault false)) + (setIf [ "features" "dev" "enable" ] (mkDefault false)) + (setIf [ "features" "sound" "enable" ] (mkDefault false)) + ])) + ]; +} diff --git a/moduler/features/standard/default.nix b/moduler/features/standard/default.nix new file mode 100644 index 0000000..9eddafd --- /dev/null +++ b/moduler/features/standard/default.nix @@ -0,0 +1,13 @@ +{ ... }: +{ + imports = [ + ../default.nix + ../../services/users + ../../services/network + ../../services/system + ../../services/sound + ../../programs/base + ../../programs/git + ../../programs/dev + ]; +} diff --git a/moduler/git.nix b/moduler/git.nix index 3b0af92..c64d60a 100644 --- a/moduler/git.nix +++ b/moduler/git.nix @@ -1,16 +1,8 @@ -{ pkgs, lib, ... }: +{ lib, ... }: { - programs.git = { - enable = true; - config = { - user = { - name = "fwastring"; - email = "fredrik@wastring.com"; - }; - pull = { - rebase = true; - }; - url."git@github.com:".insteadOf = "https://github.com/"; - }; - }; + imports = [ + ./programs/git + ]; + + features.git.enable = lib.mkDefault true; } diff --git a/moduler/network.nix b/moduler/network.nix index 421dfba..aeefc6e 100644 --- a/moduler/network.nix +++ b/moduler/network.nix @@ -1,34 +1,8 @@ -# This is your system's configuration file. -# Use this to configure your system environment (it replaces /etc/nixos/configuration.nix) +{ lib, ... }: { - inputs, - lib, - config, - pkgs, - ... -}: -{ - - services.netbird = { - enable = true; - ui.enable = true; - }; - - systemd.services.tailscaled = { - after = [ "netbird.service" "network-online.target" ]; - wants = [ "netbird.service" "network-online.target" ]; - }; - - environment.systemPackages = with pkgs; [ - # networkmanager - dnsutils - nmap - ipcalc - # iperf3 - # networkmanagerapplet - - # (octodns.withProviders (ps: [ - # octodns-providers.gandi - # ])) + imports = [ + ./services/network ]; + + features.network.enable = lib.mkDefault true; } diff --git a/moduler/programs.nix b/moduler/programs.nix index 0cc8b58..2a840e6 100644 --- a/moduler/programs.nix +++ b/moduler/programs.nix @@ -1,144 +1,8 @@ +{ lib, ... }: { - inputs, - lib, - config, - pkgs, - ... -}: -{ - services.udev = { - extraRules = '' - KERNEL=="ttyACM0", MODE:="666" - ACTION=="add", KERNEL=="sd[a-e][0-9]", ENV{ID_FS_UUID}=="3039-3932", RUN+="${pkgs.systemd}/bin/systemd-mount --no-block -A -G -o gid=users,fmask=113,dmask=002 /dev/%k /mnt/sdcard" - ACTION=="add", KERNEL=="sd[a-e]", ENV{ID_FS_UUID}=="66BA-4EBA", RUN+="${pkgs.systemd}/bin/systemd-mount --no-block -A -G -o gid=users,fmask=113,dmask=002 /dev/%k /mnt/kobo" - KERNEL=="uinput", GROUP="input", MODE="0660", OPTIONS+="static_node=uinput" - ''; - packages = with pkgs; [ - vial - via - ]; - }; - home-manager.users.fw = { - xdg.mimeApps = { - enable = true; - defaultApplications = { - "text/html" = "librewolf.desktop"; - "x-scheme-handler/http" = "librewolf.desktop"; - "x-scheme-handler/https" = "librewolf.desktop"; - "x-scheme-handler/about" = "librewolf.desktop"; - "x-scheme-handler/unknown" = "librewolf.desktop"; - "text/plain" = "nvim.desktop"; - "text/markdown" = "nvim.desktop"; - "text/x-markdown" = "nvim.desktop"; - "application/json" = "nvim.desktop"; - "application/x-ndjson" = "nvim.desktop"; - "application/x-yaml" = "nvim.desktop"; - "text/yaml" = "nvim.desktop"; - "text/x-shellscript" = "nvim.desktop"; - "text/x-python" = "nvim.desktop"; - "text/x-csrc" = "nvim.desktop"; - "text/x-c++src" = "nvim.desktop"; - "application/x-sql" = "nvim.desktop"; - "text/xml" = "nvim.desktop"; - "application/xml" = "nvim.desktop"; - "application/pdf" = "org.gnome.Evince.desktop"; - "image/jpeg" = "feh.desktop"; - "image/png" = "feh.desktop"; - "image/gif" = "feh.desktop"; - "image/webp" = "feh.desktop"; - "image/tiff" = "feh.desktop"; - "image/bmp" = "feh.desktop"; - "image/svg+xml" = "feh.desktop"; - }; - }; - }; - environment.sessionVariables.DEFAULT_BROWSER = "${pkgs.librewolf}/bin/librewolf"; - - environment.systemPackages = with pkgs; [ - # GUI - feishin - vscode - signal-desktop - thunderbird - discord - slack - evince - spotify - firefox - ipcalc - vial - via - remmina - brightnessctl - speedcrunch - opencode - quickemu - virt-viewer - go-passbolt-cli - wf-recorder - slurp - bitwarden-desktop - bitwarden-cli - lagrange - jujutsu - rclone - - - dbeaver-bin - ( - let - base = pkgs.appimageTools.defaultFhsEnvArgs; - in - pkgs.buildFHSEnv ( - base - // { - name = "fhs"; - targetPkgs = - pkgs: - # pkgs.buildFHSUserEnv provides only a minimal FHS environment, - # lacking many basic packages needed by most software. - # Therefore, we need to add them manually. - # - # pkgs.appimageTools provides basic packages required by most software. - (base.targetPkgs pkgs) - ++ (with pkgs; [ - pkg-config - ncurses - icu - # Feel free to add more packages here if needed. - ]); - profile = "export FHS=1"; - runScript = "bash"; - extraOutputsToInstall = [ "dev" ]; - } - ) - ) - - # TUI - codex - - # Browsers - librewolf - - # Displaying - zathura - feh - mpv - - # System - pavucontrol - pulseaudio - devour - caligula - ptouch-print - - # Transforms - yt-dlp - imagemagick - pandoc - pinta - pastel - ffmpeg - # darktable + imports = [ + ./programs/base ]; + + features.base.enable = lib.mkDefault true; } diff --git a/moduler/programs/base/default.nix b/moduler/programs/base/default.nix new file mode 100644 index 0000000..5a9b257 --- /dev/null +++ b/moduler/programs/base/default.nix @@ -0,0 +1,245 @@ +{ + lib, + config, + pkgs, + ... +}: +with lib; +let + fhsEnv = + let + base = pkgs.appimageTools.defaultFhsEnvArgs; + in + pkgs.buildFHSEnv ( + base + // { + name = "fhs"; + targetPkgs = + pkgs: + (base.targetPkgs pkgs) + ++ (with pkgs; [ + pkg-config + ncurses + icu + ]); + profile = "export FHS=1"; + runScript = "bash"; + extraOutputsToInstall = [ "dev" ]; + } + ); +in +{ + options.features.base = { + enable = mkEnableOption "enable shared base programs"; + preset = mkOption { + type = types.enum [ + "minimal" + "standard" + "full" + ]; + default = "standard"; + description = "Preset for desktop package groups."; + }; + udevEnable = mkOption { + type = types.bool; + default = true; + description = "Enable custom udev rules and device packages."; + }; + mimeEnable = mkOption { + type = types.bool; + default = true; + description = "Enable Home Manager MIME defaults."; + }; + packages = { + communicationEnable = mkOption { + type = types.bool; + default = true; + description = "Install communication desktop apps."; + }; + mediaEnable = mkOption { + type = types.bool; + default = true; + description = "Install media apps."; + }; + browsersEnable = mkOption { + type = types.bool; + default = true; + description = "Install browsers."; + }; + captureEnable = mkOption { + type = types.bool; + default = true; + description = "Install screen capture tools."; + }; + creativeEnable = mkOption { + type = types.bool; + default = true; + description = "Install conversion/creative tools."; + }; + devDesktopEnable = mkOption { + type = types.bool; + default = true; + description = "Install desktop dev helper tools and VMs."; + }; + dbeaverEnable = mkOption { + type = types.bool; + default = true; + description = "Install dbeaver and FHS shell."; + }; + }; + }; + + config = mkMerge [ + (mkIf (config.features.base.preset == "minimal") { + features.base.packages.communicationEnable = mkDefault false; + features.base.packages.mediaEnable = mkDefault false; + features.base.packages.browsersEnable = mkDefault true; + features.base.packages.captureEnable = mkDefault false; + features.base.packages.creativeEnable = mkDefault false; + features.base.packages.devDesktopEnable = mkDefault false; + features.base.packages.dbeaverEnable = mkDefault false; + }) + + (mkIf (config.features.base.preset == "full") { + features.base.packages.communicationEnable = mkDefault true; + features.base.packages.mediaEnable = mkDefault true; + features.base.packages.browsersEnable = mkDefault true; + features.base.packages.captureEnable = mkDefault true; + features.base.packages.creativeEnable = mkDefault true; + features.base.packages.devDesktopEnable = mkDefault true; + features.base.packages.dbeaverEnable = mkDefault true; + }) + + (mkIf config.features.base.enable { + services.udev = mkIf config.features.base.udevEnable { + extraRules = '' + KERNEL=="ttyACM0", MODE:="666" + ACTION=="add", KERNEL=="sd[a-e][0-9]", ENV{ID_FS_UUID}=="3039-3932", RUN+="${pkgs.systemd}/bin/systemd-mount --no-block -A -G -o gid=users,fmask=113,dmask=002 /dev/%k /mnt/sdcard" + ACTION=="add", KERNEL=="sd[a-e]", ENV{ID_FS_UUID}=="66BA-4EBA", RUN+="${pkgs.systemd}/bin/systemd-mount --no-block -A -G -o gid=users,fmask=113,dmask=002 /dev/%k /mnt/kobo" + KERNEL=="uinput", GROUP="input", MODE="0660", OPTIONS+="static_node=uinput" + ''; + packages = with pkgs; [ + vial + via + ]; + }; + + home-manager.users.fw = mkIf config.features.base.mimeEnable { + xdg.mimeApps = { + enable = true; + defaultApplications = { + "text/html" = "librewolf.desktop"; + "x-scheme-handler/http" = "librewolf.desktop"; + "x-scheme-handler/https" = "librewolf.desktop"; + "x-scheme-handler/about" = "librewolf.desktop"; + "x-scheme-handler/unknown" = "librewolf.desktop"; + "text/plain" = "nvim.desktop"; + "text/markdown" = "nvim.desktop"; + "text/x-markdown" = "nvim.desktop"; + "application/json" = "nvim.desktop"; + "application/x-ndjson" = "nvim.desktop"; + "application/x-yaml" = "nvim.desktop"; + "text/yaml" = "nvim.desktop"; + "text/x-shellscript" = "nvim.desktop"; + "text/x-python" = "nvim.desktop"; + "text/x-csrc" = "nvim.desktop"; + "text/x-c++src" = "nvim.desktop"; + "application/x-sql" = "nvim.desktop"; + "text/xml" = "nvim.desktop"; + "application/xml" = "nvim.desktop"; + "application/pdf" = "org.gnome.Evince.desktop"; + "image/jpeg" = "feh.desktop"; + "image/png" = "feh.desktop"; + "image/gif" = "feh.desktop"; + "image/webp" = "feh.desktop"; + "image/tiff" = "feh.desktop"; + "image/bmp" = "feh.desktop"; + "image/svg+xml" = "feh.desktop"; + }; + }; + }; + + environment.sessionVariables.DEFAULT_BROWSER = "${pkgs.librewolf}/bin/librewolf"; + + environment.systemPackages = + (with pkgs; [ + codex + ipcalc + remmina + brightnessctl + speedcrunch + lagrange + jujutsu + rclone + zathura + feh + pavucontrol + pulseaudio + devour + caligula + ptouch-print + ]) + ++ optionals config.features.base.packages.communicationEnable ( + with pkgs; + [ + signal-desktop + thunderbird + discord + slack + ] + ) + ++ optionals config.features.base.packages.mediaEnable ( + with pkgs; + [ + feishin + spotify + mpv + ] + ) + ++ optionals config.features.base.packages.browsersEnable ( + with pkgs; + [ + librewolf + firefox + ] + ) + ++ optionals config.features.base.packages.captureEnable ( + with pkgs; + [ + wf-recorder + slurp + ] + ) + ++ optionals config.features.base.packages.creativeEnable ( + with pkgs; + [ + yt-dlp + imagemagick + pandoc + pinta + pastel + ffmpeg + ] + ) + ++ optionals config.features.base.packages.devDesktopEnable ( + with pkgs; + [ + vscode + opencode + quickemu + virt-viewer + go-passbolt-cli + bitwarden-desktop + bitwarden-cli + ] + ) + ++ optionals config.features.base.packages.dbeaverEnable ( + with pkgs; + [ + dbeaver-bin + fhsEnv + ] + ); + }) + ]; +} diff --git a/moduler/programs/dev/default.nix b/moduler/programs/dev/default.nix new file mode 100644 index 0000000..1185332 --- /dev/null +++ b/moduler/programs/dev/default.nix @@ -0,0 +1,109 @@ +{ + inputs, + pkgs, + lib, + config, + ... +}: +let + azPkgs = inputs.nixpkgs-azure-cli.legacyPackages.${pkgs.stdenv.hostPlatform.system}; +in +with lib; +{ + options.features.dev = { + enable = mkEnableOption "enable development toolchain"; + preset = mkOption { + type = types.enum [ + "minimal" + "standard" + "full" + ]; + default = "standard"; + description = "Preset for development package groups."; + }; + cloud = { + aws.enable = mkOption { + type = types.bool; + default = true; + description = "Enable AWS CLI tools."; + }; + azure.enable = mkOption { + type = types.bool; + default = true; + description = "Enable Azure CLI tools."; + }; + minio.enable = mkOption { + type = types.bool; + default = true; + description = "Enable MinIO client."; + }; + }; + tools = { + docker.enable = mkOption { + type = types.bool; + default = true; + description = "Enable lazydocker."; + }; + python.enable = mkOption { + type = types.bool; + default = true; + description = "Enable Python runtime package."; + }; + opentofu.enable = mkOption { + type = types.bool; + default = true; + description = "Enable OpenTofu package."; + }; + git.enable = mkOption { + type = types.bool; + default = true; + description = "Enable git package in dev toolchain."; + }; + }; + }; + + config = mkMerge [ + (mkIf config.features.dev.enable { + environment.systemPackages = + (with pkgs; [ + nixfmt-rfc-style + gh + yq + jq + ]) + ++ optionals config.features.dev.tools.docker.enable (with pkgs; [ lazydocker ]) + ++ optionals config.features.dev.cloud.aws.enable (with pkgs; [ awscli ]) + ++ optionals config.features.dev.cloud.minio.enable (with pkgs; [ minio-client ]) + ++ optionals config.features.dev.tools.opentofu.enable (with pkgs; [ opentofu ]) + ++ optionals config.features.dev.tools.python.enable (with pkgs; [ python3 ]) + ++ optionals config.features.dev.cloud.azure.enable [ + (azPkgs.azure-cli.withExtensions ( + with azPkgs.azure-cli.extensions; + [ + fzf + ] + )) + ] + ++ optionals config.features.dev.tools.git.enable (with pkgs; [ git ]); + }) + + (mkIf (config.features.dev.preset == "minimal") { + features.dev.cloud.aws.enable = mkDefault false; + features.dev.cloud.azure.enable = mkDefault false; + features.dev.cloud.minio.enable = mkDefault false; + features.dev.tools.docker.enable = mkDefault false; + features.dev.tools.opentofu.enable = mkDefault false; + features.dev.tools.python.enable = mkDefault false; + }) + + (mkIf (config.features.dev.preset == "full") { + features.dev.cloud.aws.enable = mkDefault true; + features.dev.cloud.azure.enable = mkDefault true; + features.dev.cloud.minio.enable = mkDefault true; + features.dev.tools.docker.enable = mkDefault true; + features.dev.tools.opentofu.enable = mkDefault true; + features.dev.tools.python.enable = mkDefault true; + features.dev.tools.git.enable = mkDefault true; + }) + ]; +} diff --git a/moduler/programs/git/default.nix b/moduler/programs/git/default.nix new file mode 100644 index 0000000..ce2ffed --- /dev/null +++ b/moduler/programs/git/default.nix @@ -0,0 +1,45 @@ +{ lib, config, ... }: +with lib; +{ + options.features.git = { + enable = mkEnableOption "enable git defaults"; + userName = mkOption { + type = types.str; + default = "fwastring"; + description = "Default git user.name."; + }; + userEmail = mkOption { + type = types.str; + default = "fredrik@wastring.com"; + description = "Default git user.email."; + }; + pullRebase = mkOption { + type = types.bool; + default = true; + description = "Enable pull.rebase by default."; + }; + githubSshInsteadOfHttps = mkOption { + type = types.bool; + default = true; + description = "Use SSH for GitHub remotes when cloning with HTTPS URLs."; + }; + }; + + config = mkIf config.features.git.enable { + programs.git = { + enable = true; + config = { + user = { + name = config.features.git.userName; + email = config.features.git.userEmail; + }; + pull = { + rebase = config.features.git.pullRebase; + }; + } + // optionalAttrs config.features.git.githubSshInsteadOfHttps { + url."git@github.com:".insteadOf = "https://github.com/"; + }; + }; + }; +} diff --git a/moduler/services/network/default.nix b/moduler/services/network/default.nix new file mode 100644 index 0000000..29844bf --- /dev/null +++ b/moduler/services/network/default.nix @@ -0,0 +1,69 @@ +{ + lib, + config, + pkgs, + ... +}: +with lib; +{ + options.features.network = { + enable = mkEnableOption "enable network tooling and VPN services"; + netbird = { + enable = mkOption { + type = types.bool; + default = true; + description = "Enable NetBird service."; + }; + uiEnable = mkOption { + type = types.bool; + default = true; + description = "Enable NetBird UI component."; + }; + }; + tailscale = { + waitForNetbird = mkOption { + type = types.bool; + default = true; + description = "Add netbird ordering to tailscaled unit."; + }; + }; + tooling = { + enable = mkOption { + type = types.bool; + default = true; + description = "Install network troubleshooting CLI tools."; + }; + packages = mkOption { + type = types.listOf types.package; + default = with pkgs; [ + dnsutils + nmap + ipcalc + ]; + description = "Packages installed when network tooling is enabled."; + }; + }; + }; + + config = mkIf config.features.network.enable { + services.netbird = mkIf config.features.network.netbird.enable { + enable = true; + ui.enable = config.features.network.netbird.uiEnable; + }; + + systemd.services.tailscaled = + mkIf (config.features.network.tailscale.waitForNetbird && config.features.network.netbird.enable) + { + after = [ + "netbird.service" + "network-online.target" + ]; + wants = [ + "netbird.service" + "network-online.target" + ]; + }; + + environment.systemPackages = mkIf config.features.network.tooling.enable config.features.network.tooling.packages; + }; +} diff --git a/moduler/services/sound/default.nix b/moduler/services/sound/default.nix new file mode 100644 index 0000000..5108aaf --- /dev/null +++ b/moduler/services/sound/default.nix @@ -0,0 +1,71 @@ +{ lib, config, ... }: +with lib; +{ + options.features.sound = { + enable = mkEnableOption "enable sound and bluetooth stack"; + pipewire = { + enable = mkOption { + type = types.bool; + default = true; + description = "Enable PipeWire audio stack."; + }; + alsa32Bit = mkOption { + type = types.bool; + default = true; + description = "Enable 32-bit ALSA support."; + }; + pulseCompat = mkOption { + type = types.bool; + default = true; + description = "Enable PulseAudio compatibility through PipeWire."; + }; + }; + bluetooth = { + enable = mkOption { + type = types.bool; + default = true; + description = "Enable Bluetooth subsystem."; + }; + powerOnBoot = mkOption { + type = types.bool; + default = true; + description = "Power on Bluetooth at boot."; + }; + disableHeadsetProfile = mkOption { + type = types.bool; + default = true; + description = "Disable headset profile for Bluetooth devices."; + }; + bluemanEnable = mkOption { + type = types.bool; + default = true; + description = "Enable Blueman service."; + }; + }; + }; + + config = mkIf config.features.sound.enable { + services.pulseaudio.enable = false; + security.rtkit.enable = true; + services = { + pipewire = { + enable = config.features.sound.pipewire.enable; + alsa.enable = config.features.sound.pipewire.enable; + alsa.support32Bit = config.features.sound.pipewire.alsa32Bit; + pulse.enable = config.features.sound.pipewire.pulseCompat; + }; + blueman.enable = config.features.sound.bluetooth.bluemanEnable; + }; + hardware = { + bluetooth = mkIf config.features.sound.bluetooth.enable { + enable = config.features.sound.bluetooth.enable; + powerOnBoot = config.features.sound.bluetooth.powerOnBoot; + settings = { + General = mkIf config.features.sound.bluetooth.disableHeadsetProfile { + Disable = "Headset"; + }; + }; + }; + }; + }; +} diff --git a/moduler/services/system/default.nix b/moduler/services/system/default.nix new file mode 100644 index 0000000..cec687e --- /dev/null +++ b/moduler/services/system/default.nix @@ -0,0 +1,78 @@ +{ + pkgs, + lib, + config, + ... +}: +with lib; +{ + options.features.system = { + enable = mkEnableOption "enable shared system utilities"; + preset = mkOption { + type = types.enum [ + "minimal" + "desktop" + "ops" + ]; + default = "desktop"; + description = "Package profile for shared system tooling."; + }; + corePackages = mkOption { + type = types.listOf types.package; + default = with pkgs; [ + sops + unzip + zip + wget + htop + procps + fastfetch + bc + fzf + eza + rsync + ripgrep + fd + ]; + description = "Always-installed core system packages."; + }; + desktopPackages = mkOption { + type = types.listOf types.package; + default = with pkgs; [ + bluez + bluez-tools + poppler-utils + alsa-utils + libnotify + hyprpicker + ]; + description = "Additional packages for desktop-oriented hosts."; + }; + opsPackages = mkOption { + type = types.listOf types.package; + default = with pkgs; [ + grc + lazygit + ]; + description = "Additional packages for operations-heavy hosts."; + }; + extras = mkOption { + type = types.listOf types.package; + default = with pkgs; [ + lolcat + fortune + cowsay + typst + ]; + description = "Additional optional packages for all presets except minimal."; + }; + }; + + config = mkIf config.features.system.enable { + environment.systemPackages = + config.features.system.corePackages + ++ optionals (config.features.system.preset != "minimal") config.features.system.extras + ++ optionals (config.features.system.preset == "desktop") config.features.system.desktopPackages + ++ optionals (config.features.system.preset == "ops") config.features.system.opsPackages; + }; +} diff --git a/moduler/services/users/default.nix b/moduler/services/users/default.nix new file mode 100644 index 0000000..e7f3863 --- /dev/null +++ b/moduler/services/users/default.nix @@ -0,0 +1,62 @@ +{ + config, + pkgs, + lib, + ... +}: +with lib; +{ + options.features.users = { + enable = mkEnableOption "enable default users"; + name = mkOption { + type = types.str; + default = "fw"; + description = "Primary user account name."; + }; + fullName = mkOption { + type = types.str; + default = "Fredrik Wastring"; + description = "Primary user full name."; + }; + initialPassword = mkOption { + type = types.str; + default = "password"; + description = "Initial password for the primary user."; + }; + extraGroups = mkOption { + type = types.listOf types.str; + default = [ + "networkmanager" + "wheel" + "audio" + "docker" + "input" + ]; + description = "Additional groups for the primary user."; + }; + sshAuthorizedKeys = mkOption { + type = types.listOf types.str; + default = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFpJBGPIfPB1BwSG7aoKqwfccyZSaU7J3xpJ8behMp9N fw@core" + ]; + description = "SSH authorized keys for the primary user."; + }; + }; + + config = mkIf config.features.users.enable { + users = { + defaultUserShell = pkgs.bash; + users = { + ${config.features.users.name} = { + initialPassword = config.features.users.initialPassword; + isNormalUser = true; + description = config.features.users.fullName; + extraGroups = config.features.users.extraGroups; + openssh.authorizedKeys = { + keys = config.features.users.sshAuthorizedKeys; + }; + }; + }; + }; + }; +} diff --git a/moduler/services/webcam-rtsp/default.nix b/moduler/services/webcam-rtsp/default.nix index 25a9324..b0af354 100644 --- a/moduler/services/webcam-rtsp/default.nix +++ b/moduler/services/webcam-rtsp/default.nix @@ -100,6 +100,21 @@ in default = 24; description = "VAAPI quality parameter (lower means better quality, higher CPU/bitrate)."; }; + waitForRtsp = mkOption { + type = types.bool; + default = true; + description = "Wait for the RTSP destination to accept TCP connections before ffmpeg starts."; + }; + waitForRtspTimeoutSec = mkOption { + type = types.int; + default = 30; + description = "Maximum seconds to wait for RTSP destination availability."; + }; + waitForRtspIntervalSec = mkOption { + type = types.int; + default = 1; + description = "Seconds between RTSP availability checks."; + }; vaapiDriver = mkOption { type = types.nullOr types.str; default = null; @@ -209,6 +224,13 @@ in "-rc_mode VBR -b:v ${toString streamCfg.bitrateKbps}k -maxrate ${toString maxrateKbps}k -bufsize ${toString bufsizeKbps}k" else "-rc_mode CQP -qp ${toString streamCfg.vaapiQp}"; + rtspUrlMatch = builtins.match "rtsp://([^/:]+)(:([0-9]+))?/.*" streamCfg.rtspUrl; + rtspHost = if rtspUrlMatch != null then builtins.elemAt rtspUrlMatch 0 else "127.0.0.1"; + rtspPort = + if rtspUrlMatch != null && builtins.elemAt rtspUrlMatch 2 != null then + builtins.elemAt rtspUrlMatch 2 + else + "8554"; videoCodecArgs = if streamCfg.useVaapi then "-vaapi_device ${streamCfg.vaapiDevice} -vf format=nv12,hwupload -c:v h264_vaapi -profile:v main -level:v 4.1 ${vaapiRateControlArgs} -g ${ @@ -230,6 +252,22 @@ in Restart = "always"; RestartSec = "2"; Environment = optional (streamCfg.vaapiDriver != null) "LIBVA_DRIVER_NAME=${streamCfg.vaapiDriver}"; + ExecStartPre = optional cfg.waitForRtsp ( + pkgs.writeShellScript "wait-for-rtsp-${sanitizeName streamName}" '' + set -eu + retries=${toString cfg.waitForRtspTimeoutSec} + interval=${toString cfg.waitForRtspIntervalSec} + i=0 + until ${pkgs.netcat-openbsd}/bin/nc -z -w1 ${rtspHost} ${rtspPort}; do + i=$((i + 1)) + if [ "$i" -ge "$retries" ]; then + echo "Timed out waiting for RTSP server at ${rtspHost}:${rtspPort}" >&2 + exit 1 + fi + sleep "$interval" + done + '' + ); ExecStart = "${pkgs.ffmpeg}/bin/ffmpeg -hide_banner -loglevel warning -f v4l2 -framerate ${toString streamCfg.framerate} -video_size ${streamCfg.videoSize} -i ${streamCfg.device} ${videoCodecArgs} -f rtsp -rtsp_transport tcp ${streamCfg.rtspUrl}"; }; } diff --git a/moduler/sound.nix b/moduler/sound.nix index cc48455..66a6f3f 100644 --- a/moduler/sound.nix +++ b/moduler/sound.nix @@ -1,25 +1,8 @@ -{ pkgs, lib, ... }: +{ lib, ... }: { - services.pulseaudio.enable = false; - security.rtkit.enable = true; - services = { - pipewire = { - enable = true; - alsa.enable = true; - alsa.support32Bit = true; - pulse.enable = true; - }; - blueman.enable = true; - }; - hardware = { - bluetooth = { - enable = true; - powerOnBoot = true; - settings = { - General = { - Disable = "Headset"; - }; - }; - }; - }; + imports = [ + ./services/sound + ]; + + features.sound.enable = lib.mkDefault true; } diff --git a/moduler/system.nix b/moduler/system.nix index 1d4421d..c7c7ec4 100644 --- a/moduler/system.nix +++ b/moduler/system.nix @@ -1,39 +1,8 @@ +{ lib, ... }: { - pkgs, - ... -}: -{ - - - environment.systemPackages = with pkgs; [ - bluez - bluez-tools - poppler-utils - alsa-utils - - sops - libnotify - unzip - zip - wget - htop - procps - grc - fastfetch - bc - - fzf - eza - rsync - ripgrep - fd - - lolcat - fortune - cowsay - - lazygit - hyprpicker - typst + imports = [ + ./services/system ]; + + features.system.enable = lib.mkDefault true; } diff --git a/moduler/users.nix b/moduler/users.nix index cc8b6f5..11b4d2c 100644 --- a/moduler/users.nix +++ b/moduler/users.nix @@ -1,31 +1,8 @@ +{ lib, ... }: { - config, - pkgs, - ... -}: -{ - # sops.secrets.user-password = { }; - users = { - defaultUserShell = pkgs.bash; - users = { - fw = { - # hashedPasswordFile = config.sops.secrets.user-password.path; - initialPassword = "password"; - isNormalUser = true; - description = "Fredrik Wastring"; - extraGroups = [ - "networkmanager" - "wheel" - "audio" - "docker" - "input" - ]; - openssh.authorizedKeys = { - keys = [ - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFpJBGPIfPB1BwSG7aoKqwfccyZSaU7J3xpJ8behMp9N fw@core" - ]; - }; - }; - }; - }; + imports = [ + ./services/users + ]; + + features.users.enable = lib.mkDefault true; }