diff options
Diffstat (limited to 'nix')
63 files changed, 4234 insertions, 1605 deletions
diff --git a/nix/hosts/caladan/aliases.nix b/nix/hosts/caladan/aliases.nix index d65bc14..6738589 100644 --- a/nix/hosts/caladan/aliases.nix +++ b/nix/hosts/caladan/aliases.nix @@ -4,6 +4,7 @@ # short forms tf = "terraform"; + m = "multipass"; r2help = ''r2 -qq -c "?*~..." --''; mosh = "mosh --no-init"; diff --git a/nix/hosts/caladan/darwin-configuration.nix b/nix/hosts/caladan/darwin-configuration.nix index ef18642..e581cb8 100644 --- a/nix/hosts/caladan/darwin-configuration.nix +++ b/nix/hosts/caladan/darwin-configuration.nix @@ -1,7 +1,9 @@ { pkgs, lib, ... }: { - imports = [ ./overlay.nix ]; + imports = [ + ./overlay.nix + ]; system.stateVersion = 5; @@ -27,9 +29,17 @@ # users.users."_nixbld3".uid = 307; # users.users."_nixbld4".uid = 308; # users.users."_nixbld5".uid = 309; + + # virtualisation.multipass = { + # enable = true; + # package = pkgs.multipass; + # logLevel = "debug"; + # }; + + ids.gids.nixbld = 30000; nix = { - useDaemon = true; + # useDaemon = true; # package = pkgs.nixFlakes; extraOptions = '' @@ -85,10 +95,10 @@ { hostName = "corrino.emile.space"; system = "x86_64-linux"; - maxJobs = 16; + maxJobs = 10; speedFactor = 2; - # Feature | Derivations requiring it + # Feature | Derivations requiring it # ----------------|----------------------------------------------------- # kvm | Everything which builds inside a vm, like NixOS tests # nixos-test | Machine can run NixOS tests @@ -110,14 +120,16 @@ ]; }; - nixpkgs = { - config.allowUnfree = true; + nixpkgs.config = { + allowUnfree = true; + allowUnsupportedSystem = true; }; - services.nix-daemon.enable = true; + # services.nix-daemon.enable = true; # <3 - security.pam.enableSudoTouchIdAuth = true; + # security.pam.enableSudoTouchIdAuth = true; + security.pam.services.sudo_local.touchIdAuth = true; environment = { systemPackages = [ ]; # set via home-manager diff --git a/nix/hosts/caladan/emacs_config.el b/nix/hosts/caladan/emacs_config.el index 0ed5786..01cf5bd 100644 --- a/nix/hosts/caladan/emacs_config.el +++ b/nix/hosts/caladan/emacs_config.el @@ -17,10 +17,7 @@ (unless (package-installed-p package) (package-install package))) -(when (display-graphic-p) - (tool-bar-mode 0) - (scroll-bar-mode 'left)) - +(scroll-bar-mode -1) (load-theme 'leuven) ;; light theme (setq pixel-scroll-precision-mode 1) (xterm-mouse-mode 1) @@ -42,9 +39,6 @@ (display-buffer-no-window) (allow-no-window . t))) -(when (not (display-graphic-p)) - (menu-bar-mode -1)) - ;; general purpose emacs settings (use-package emacs :init @@ -148,7 +142,6 @@ completion-category-overrides '((file (styles partial-completion))))) - ;; markdown mode ;; https://jblevins.org/projects/markdown-mode/ (defvar markdown-command) @@ -181,7 +174,7 @@ :ensure nil ; no need to install it as it is built-in, but needs to be activated :hook (after-init . delete-selection-mode)) -;; Configure the Lisp program for SLIME +;; Configure the Lisp program for SLY (add-to-list 'exec-path "/Users/emile/.nix-profile/bin") (defvar inferior-lisp-program "sbcl") @@ -206,14 +199,5 @@ (use-package breadcrumb :ensure t) -;(setq circe-network-options -; '(("Libera Chat" -; :tls t -; :tls-keylist (("/Users/emile/libera.crt" -; "/Users/emile/libera.key")) -; :sasl-external t -; :nick "hanemile" -; :channels ("#test")))) - (provide '.emacs) ;;; emacs_config.el ends here diff --git a/nix/hosts/caladan/home_emile.nix b/nix/hosts/caladan/home_emile.nix index 86d6965..704b73b 100644 --- a/nix/hosts/caladan/home_emile.nix +++ b/nix/hosts/caladan/home_emile.nix @@ -1,4 +1,4 @@ -{ pkgs, ... }: +{ pkgs, lib, ... }: { home = { @@ -50,7 +50,7 @@ fi ''; - initExtraBeforeCompInit = '' + initContent = lib.mkOrder 550 '' ${builtins.readFile ./session_variables.zsh} ${builtins.readFile ./functions.zsh} @@ -60,6 +60,18 @@ ''; }; + neovim = let + custom_plugins = pkgs.callPackage ./nvim_plugins.nix { }; + in { + enable = true; + plugins = with pkgs.vimPlugins // custom_plugins; [ + neovim-ayu + lisp.vlime + ]; + extraConfig = '' + ''; + }; + emacs = { enable = true; package = pkgs.emacs; @@ -76,10 +88,8 @@ kitty = { enable = true; - # package = pkgs.kitty; - font = { - name = "Iosevka Nerd Font"; + name = "Berkeley Mono"; size = 13; }; @@ -92,9 +102,6 @@ tab_bar_edge = "top"; tab_bar_style = "slant"; tab_bar_min_tabs = 1; - - # tab_title_template = "{index}[{layout_name[0:2]}]: {title.replace('emile', 'e')[title.rfind('/')+1:]}"; - # tab_title_template = "{index}[{layout_name[0:2]}]: {title.replace('emile', 'e')}"; tab_title_template = "{index} {title.replace('emile', 'e')}"; editor = "/Users/emile/.cargo/bin/hx"; @@ -182,9 +189,9 @@ ## language server # nodePackages_latest.typescript-language-server # js / typescript nil # nix - nodePackages.yaml-language-server # yaml + # nodePackages.yaml-language-server # yaml python312Packages.python-lsp-server # python - gopls # golang + # gopls # golang # binary foo radare2 @@ -199,7 +206,8 @@ # go foo go - delve + # delve + # gotools # c foo cmake @@ -247,9 +255,23 @@ taskwarrior3 - drawio + # drawio + + # cargo rustup + cargo + + utm + + #nmap ffuf + #typst + #age + #ffmpeg + #exiftool + + # custom + # libc-database - libc-database + # unstable.duckdb # blender diff --git a/nix/hosts/caladan/nvim_plugins.nix b/nix/hosts/caladan/nvim_plugins.nix new file mode 100644 index 0000000..7f07816 --- /dev/null +++ b/nix/hosts/caladan/nvim_plugins.nix @@ -0,0 +1,21 @@ +{ vimUtils, fetchgit, ... }: + +let + build = ({name, owner, rev, sha256}: vimUtils.buildVimPlugin { + inherit name; + src = fetchgit { + inherit rev sha256; + url = "https://github.com/${owner}/${name}"; + }; + dependencies = []; + }); +in { + lisp = { + vlime = build { + name = "vlime"; + owner = "l04m33"; + rev = "065b95f3ac7a455314c2bdefeb2b792f290034df"; + sha256 = "1bmmskdwvbl6lvbnjp9lls86rz0vzmk73y644bjb9ix9ygmjbia4"; + }; + }; +} diff --git a/nix/hosts/caladan/overlay.nix b/nix/hosts/caladan/overlay.nix index c9bdd79..8295339 100644 --- a/nix/hosts/caladan/overlay.nix +++ b/nix/hosts/caladan/overlay.nix @@ -3,42 +3,37 @@ { nixpkgs = { overlays = [ - (self: super: { - kitty = super.kitty.overrideAttrs (old: { - preCheck = '' - # skip failing tests due to darwin sandbox - substituteInPlace kitty_tests/file_transmission.py \ - --replace test_file_get dont_test_file_get \ - --replace test_path_mapping_receive dont_test_path_mapping_receive \ - --replace test_transfer_send dont_test_transfer_send - substituteInPlace kitty_tests/shell_integration.py \ - --replace test_fish_integration dont_test_fish_integration - substituteInPlace kitty_tests/shell_integration.py \ - --replace test_bash_integration dont_test_bash_integration - substituteInPlace kitty_tests/open_actions.py \ - --replace test_parsing_of_open_actions dont_test_parsing_of_open_actions - substituteInPlace kitty_tests/ssh.py \ - --replace test_ssh_connection_data dont_test_ssh_connection_data - substituteInPlace kitty_tests/fonts.py \ - --replace 'class Rendering(BaseTest)' 'class Rendering' + #(self: super: { + # kitty = super.kitty.overrideAttrs (old: { + # preCheck = '' + # # skip failing tests due to darwin sandbox + # substituteInPlace kitty_tests/file_transmission.py \ + # --replace test_file_get dont_test_file_get \ + # --replace test_path_mapping_receive dont_test_path_mapping_receive \ + # --replace test_transfer_send dont_test_transfer_send + # substituteInPlace kitty_tests/shell_integration.py \ + # --replace test_fish_integration dont_test_fish_integration + # substituteInPlace kitty_tests/shell_integration.py \ + # --replace test_bash_integration dont_test_bash_integration + # substituteInPlace kitty_tests/open_actions.py \ + # --replace test_parsing_of_open_actions dont_test_parsing_of_open_actions + # substituteInPlace kitty_tests/ssh.py \ + # --replace test_ssh_connection_data dont_test_ssh_connection_data + # substituteInPlace kitty_tests/fonts.py \ + # --replace 'class Rendering(BaseTest)' 'class Rendering' - # TODO(emile): figure out why this test is failing and activate it - # again. - substituteInPlace kittens/hyperlinked_grep/main_test.go \ - --replace TestRgArgParsing DontTestRgArgParsing \ + # # TODO(emile): figure out why this test is failing and activate it + # # again. + # substituteInPlace kittens/hyperlinked_grep/main_test.go \ + # --replace TestRgArgParsing DontTestRgArgParsing \ - # theme collection test starts an http server - rm tools/themes/collection_test.go - # passwd_test tries to exec /usr/bin/dscl - rm tools/utils/passwd_test.go - ''; - }); - - # helix-2303 = self.callPackage ../../pkgs/helix-2303 { }; - # r2 = self.callPackage ../../pkgs/radare2-5.8.4 { }; - # ansel = self.callPackage ../../pkgs/ansel { }; - # typst = self.callPackage ../pkgs/radare2-5.8.4 { }; - }) + # # theme collection test starts an http server + # rm tools/themes/collection_test.go + # # passwd_test tries to exec /usr/bin/dscl + # rm tools/utils/passwd_test.go + # ''; + # }); + #}) ]; config = { allowUnfree = true; diff --git a/nix/hosts/corrino/configuration.nix b/nix/hosts/corrino/configuration.nix index 52e9ecf..7683630 100644 --- a/nix/hosts/corrino/configuration.nix +++ b/nix/hosts/corrino/configuration.nix @@ -25,9 +25,11 @@ in # ./vm.nix ./www/git - ./www/nix-cache + #./www/nix-cache - ./www/goapp.emile.space.nix + # doesn't find the goapp-frontend package, some issue with the overlay being applied, at least + # thats what I think the problem is + # ./www/goapp.emile.space.nix # screego @@ -35,36 +37,38 @@ in ./www/emile.space.nix ./www/tmp.emile.space.nix ./www/hydra.emile.space.nix - ./www/netbox.emile.space.nix + # ./www/netbox.emile.space.nix ./www/stats.emile.space.nix - # ./www/grafana.emile.space.nix + ./www/grafana.emile.space.nix # ./www/prometheus.emile.space.nix - # ./www/loki.emile.space.nix - # ./www/promtail.emile.space.nix ./www/photo ./www/tickets.emile.space.nix # ./www/talks.emile.space.nix + ./www/miniflux.emile.space.nix # ./www/stream.emile.space.nix ./www/md.emile.space.nix ./www/social.emile.space.nix ./www/sso.emile.space.nix - ./www/s3.emile.space.nix + # ./www/s3.emile.space.nix # ./www/cs.emile.space.nix - ./www/irc.emile.space.nix + # ./www/irc.emile.space.nix + # ./www/cl.emile.space.nix # ./www/db.emile.space.nix - # ./www/ctf.emile.space.nix + #./www/ctf.emile.space.nix # ./www/magic-hash.emile.space.nix + # ./www/mc.emile.space.nix + # gemini - ./gemini/emile.space.nix + # ./gemini/emile.space.nix # general purpose modules # r2wars - ./www/r2wa.rs.nix + # ./www/r2wa.rs.nix # milliways # ./remarvin.nix @@ -159,9 +163,7 @@ in ''; }; - supportedFilesystems = { - "cifs" = true; - }; + supportedFilesystems = [ "cifs" ]; }; time.timeZone = "Europe/Berlin"; @@ -220,40 +222,40 @@ in }; # create a oneshot job to authenticate to Tailscale - systemd.services.tailscale-autoconnect = { - description = "Automatic connection to Tailscale"; - - # make sure tailscale is running before trying to connect to tailscale - after = [ - "network-pre.target" - "tailscale.service" - ]; - wants = [ - "network-pre.target" - "tailscale.service" - ]; - wantedBy = [ "multi-user.target" ]; - - # set this service as a oneshot job - serviceConfig.Type = "oneshot"; - - # have the job run this shell script - script = with pkgs; '' - # wait for tailscaled to settle - sleep 2 - - # check if we are already authenticated to tailscale - status="$(${tailscale}/bin/tailscale status -json | ${jq}/bin/jq -r .BackendState)" - if [ $status = "Running" ]; then # if so, then do nothing - exit 0 - fi - - # otherwise authenticate with tailscale - ${tailscale}/bin/tailscale up \ - --advertise-exit-node --exit-node - ''; - # -authkey ${config.age.secrets.tailscale_authkey} - }; + # systemd.services.tailscale-autoconnect = { + # description = "Automatic connection to Tailscale"; + + # # make sure tailscale is running before trying to connect to tailscale + # after = [ + # "network-pre.target" + # "tailscale.service" + # ]; + # wants = [ + # "network-pre.target" + # "tailscale.service" + # ]; + # wantedBy = [ "multi-user.target" ]; + + # # set this service as a oneshot job + # serviceConfig.Type = "oneshot"; + + # # have the job run this shell script + # script = with pkgs; '' + # # wait for tailscaled to settle + # sleep 2 + + # # check if we are already authenticated to tailscale + # status="$(${tailscale}/bin/tailscale status -json | ${jq}/bin/jq -r .BackendState)" + # if [ $status = "Running" ]; then # if so, then do nothing + # exit 0 + # fi + + # # otherwise authenticate with tailscale + # ${tailscale}/bin/tailscale up \ + # --advertise-exit-node --exit-node + # ''; + # # -authkey ${config.age.secrets.tailscale_authkey} + # }; networking = { hostName = "corrino"; @@ -314,6 +316,7 @@ in 80 443 # normal web config.emile.ports.gitDaemon + 8085 ]; allowedUDPPorts = [ # 51820 # wireguard @@ -405,6 +408,9 @@ in "docker" "libvirtd" ]; + packages = with pkgs; [ + docker + ]; }; tmpuser1 = { @@ -440,6 +446,27 @@ in # use corrino as a subnet router and an exit node useRoutingFeatures = "both"; }; + + restic.backups."corrino" = { + repository = "/mnt/storagebox-bx11/corrino"; + passwordFile = config.age.secrets.restic_password.path; + initialize = true; + pruneOpts = [ + "--keep-daily 7" + "--keep-weekly 5" + "--keep-monthly 12" + "--keep-yearly 75" + ]; + }; + # restic.server = { + # enable = true; + # prometheus = true; + # package = pkgs.restic-rest-server; + # extraFlags = [ "--no-auth" ]; + # listenAddress = "127.0.0.1:${toString config.emile.ports.restic}"; + # dataDir = "/var/lib/restic"; + # appendOnly = true; + # }; }; nix = { @@ -469,38 +496,38 @@ in allowed-uris = https://github.com/ https://git.emile.space/ git+https://github.com/ ''; - buildMachines = [ - { - hostName = "localhost"; - system = "x86_64-linux"; - protocol = "ssh-ng"; - maxJobs = 8; - supportedFeatures = [ - "nixos-test" - "benchmark" - "big-parallel" - "kvm" - ]; - } - { - hostName = "caladan.pinto-pike.ts.net"; - sshUser = "hydra"; - sshKey = "/var/lib/hydra/.ssh/id_ed25519"; - system = "aarch64-darwin"; - protocol = "ssh-ng"; - maxJobs = 1; - speedFactor = 2; - supportedFeatures = [ - "nixos-test" - "benchmark" - "big-parallel" - "kvm" - ]; - mandatoryFeatures = [ ]; - } - ]; + # buildMachines = [ + # { + # hostName = "localhost"; + # system = "x86_64-linux"; + # protocol = "ssh-ng"; + # maxJobs = 8; + # supportedFeatures = [ + # "nixos-test" + # "benchmark" + # "big-parallel" + # "kvm" + # ]; + # } + # { + # hostName = "caladan.pinto-pike.ts.net"; + # sshUser = "hydra"; + # sshKey = "/var/lib/hydra/.ssh/id_ed25519"; + # system = "aarch64-darwin"; + # protocol = "ssh-ng"; + # maxJobs = 1; + # speedFactor = 2; + # supportedFeatures = [ + # "nixos-test" + # "benchmark" + # "big-parallel" + # "kvm" + # ]; + # mandatoryFeatures = [ ]; + # } + # ]; - distributedBuilds = true; + # distributedBuilds = true; }; nixpkgs.config = { @@ -518,7 +545,7 @@ in }; virtualisation = { - # docker.enable = true; + docker.enable = true; libvirtd = { enable = true; qemu = { @@ -526,12 +553,14 @@ in runAsRoot = true; swtpm.enable = true; ovmf = { - enable = true; - packages = [ - (pkgs.unstable.OVMF.override { + enable = true; + packages = [ + ( + pkgs.OVMF.override { secureBoot = true; tpmSupport = true; - }).fd + } + ).fd ]; }; }; @@ -556,13 +585,25 @@ in }; "/mnt/storagebox-bx11" = { - device = "//u331921.your-storagebox.de/backup"; - fsType = "cifs"; - options = - let - automount_opts = "_netdev,x-systemd.automount,noauto,x-systemd.idle-timeout=60,x-systemd.device-timeout=5s,x-systemd.mount-timeout=5s"; - in - [ "${automount_opts},credentials=${config.age.secrets.storage_box_bx11_password.path}" ]; + device = "u331921@u331921.your-storagebox.de:/home/backup"; + fsType = "sshfs"; + options = [ # Filesystem options + "allow_other" # for non-root access + "_netdev" # this is a network fs + + # We don't mount on demand, as that will cause services like navidrome to fail + # as the share doesn't yet exist. + #"x-systemd.automount" # mount on demand, rather than boot + + #"debug" # print debug logging + # warning: this causes the one-shot service to never exit + + # SSH options + "StrictHostKeyChecking=no" # prevent the connection from failing if the host's key hasn't been trusted yet + "ServerAliveInterval=15" # keep connections alive + "Port=23" + "IdentityFile=/root/.ssh/id_ed25519" + ]; }; }; diff --git a/nix/hosts/corrino/ports.nix b/nix/hosts/corrino/ports.nix index bb64934..483ab7f 100644 --- a/nix/hosts/corrino/ports.nix +++ b/nix/hosts/corrino/ports.nix @@ -5,16 +5,24 @@ photo = { photoprism = 2342; immich = 2343; + immich-public-proxy = 2344; }; git = 3000; hydra = 3001; grafana = 3002; md = 3003; gotosocial = 3004; - immich = 3005; monica = 3006; + miniflux = 3007; harmonia = 5000; + garage = { + s3 = 6001; + web = 6002; + rpc = 6003; + admin = 6004; + }; irc = { + bouncer = 6666; clear = 6667; ssl = 6697; }; @@ -34,8 +42,6 @@ s3 = 9000; web = 9001; }; - promtail = 9033; - loki = 9034; authelia = 9091; gitDaemon = 9418; prometheus = { @@ -45,6 +51,7 @@ nginx = 9913; systemd = 9558; smartctl = 9633; + restic = 9634; }; }; }; diff --git a/nix/hosts/corrino/secrets/garage_admin_metrics_secret.age b/nix/hosts/corrino/secrets/garage_admin_metrics_secret.age new file mode 100644 index 0000000..e1af7da --- /dev/null +++ b/nix/hosts/corrino/secrets/garage_admin_metrics_secret.age @@ -0,0 +1,7 @@ +age-encryption.org/v1 +-> ssh-ed25519 gvwQ2Q 7QkcpYGeeMsbW0GcXzNGPTc0jUf4ydpMiTO6ZxEIKGY +OOxq2hMORsmUzBuoqOIPNJeLqJB0seve9PhorS6PKNs +-> ssh-ed25519 m8VklA pF7mWG6tviFC6qD88dxoQRnXGfR0AuanVyY+bh8XgV0 +mrk4HgEs3i8y5P+BSGM1psweXpY/xO+8vK/DsXyhyiY +--- zqEl/ZN/3jEgMZ/IbPbyTHGZJDDENLOnoQezaACeoSs +íóõÃ÷ÔþlÉé…”,±ÿ‚W`£…\6éyh†Ž. ÏéÞoVÐ(€?äEmå¶,Ü;Á(@¬0dVƒ£A=4©v¡É \ No newline at end of file diff --git a/nix/hosts/corrino/secrets/garage_admin_token_secret.age b/nix/hosts/corrino/secrets/garage_admin_token_secret.age new file mode 100644 index 0000000..2a18a6b --- /dev/null +++ b/nix/hosts/corrino/secrets/garage_admin_token_secret.age @@ -0,0 +1,7 @@ +age-encryption.org/v1 +-> ssh-ed25519 gvwQ2Q hcMMVkZSsObrOFjetml2z4eH+EfnuSsna+GaXEeMUA4 +y6lFBj49cMhOGuJBpILHsykpBMpKDHZpFXR4E4zZEbg +-> ssh-ed25519 m8VklA Z6zLilTWlGWG17Q6jBx13m3KYs3gE93TPLq0CidHeTA +eqMN5mDMasi/Nw2y5Kgwy2COna+3zbbFTTUrD/O26ls +--- QdVyqrTLmEcGSB37Ft3Ur0Ry9Jk9DyHFI6fo88tnsgI +X`w•YšÙ,ç<ˆçùŸA›Á$XeêDGe´ ;±àµ†¿Âô>ü1n¥s€ª’‰±äÁNr_Y\µ`¬Á„)ü„F#{çãß´<Œ \ No newline at end of file diff --git a/nix/hosts/corrino/secrets/garage_env.age b/nix/hosts/corrino/secrets/garage_env.age new file mode 100644 index 0000000..becb511 --- /dev/null +++ b/nix/hosts/corrino/secrets/garage_env.age Binary files differdiff --git a/nix/hosts/corrino/secrets/garage_rpc_secret.age b/nix/hosts/corrino/secrets/garage_rpc_secret.age index e228d0d..ce8a65a 100644 --- a/nix/hosts/corrino/secrets/garage_rpc_secret.age +++ b/nix/hosts/corrino/secrets/garage_rpc_secret.age Binary files differdiff --git a/nix/hosts/corrino/secrets/goapp_oidc_client_secret.age b/nix/hosts/corrino/secrets/goapp_oidc_client_secret.age new file mode 100644 index 0000000..1477d56 --- /dev/null +++ b/nix/hosts/corrino/secrets/goapp_oidc_client_secret.age @@ -0,0 +1,7 @@ +age-encryption.org/v1 +-> ssh-ed25519 gvwQ2Q wi3/W2UnB/8kCTeJ8shGpBQ21uvSQlbtZBAbocbQ+zY +6RQGQss6B6uvq4yFXGVQtbHgDKGzMVO2xDgUDlBV5Es +-> ssh-ed25519 m8VklA oFBut6nQ5Er9YQWpCb+2j3JKsNIjBRjwuQ7ERVekVyM +ccR/5J5g1D11iNieF/BXtzxcusF1Zaq04iifOFk6Q/U +--- r2E/KdtXa9/j5ecWhjzLsztBG8W+if2MeOPya6KJDxY +êCª7p}ôÞÿVjíàüÍ4|³EWëá].kÊ~ìÒÎXŠe:ñ(r¯õ2:ù‹”$}®Ñ~wÒÎ0Æ»Pð`+ ¡X¨g@¸PFXÁ/iú%Š;˜!$Ï ƒ"ªIÔúi¹ñ_Î#¬*Ó|Oà„Œ†d;ZÓò£twDº F»¶l–Ðd„¨F¦6дÎJøä©a4®ýq2ây 8¿ÞT \ No newline at end of file diff --git a/nix/hosts/corrino/secrets/goapp_oidc_secret.age b/nix/hosts/corrino/secrets/goapp_oidc_secret.age index ca96981..4ca657b 100644 --- a/nix/hosts/corrino/secrets/goapp_oidc_secret.age +++ b/nix/hosts/corrino/secrets/goapp_oidc_secret.age Binary files differdiff --git a/nix/hosts/corrino/secrets/gotosocial_environment_file.age b/nix/hosts/corrino/secrets/gotosocial_environment_file.age index 7211c12..d2b6b90 100644 --- a/nix/hosts/corrino/secrets/gotosocial_environment_file.age +++ b/nix/hosts/corrino/secrets/gotosocial_environment_file.age Binary files differdiff --git a/nix/hosts/corrino/secrets/gotosocial_oidc_client_secret.age b/nix/hosts/corrino/secrets/gotosocial_oidc_client_secret.age new file mode 100644 index 0000000..bd6a14a --- /dev/null +++ b/nix/hosts/corrino/secrets/gotosocial_oidc_client_secret.age @@ -0,0 +1,7 @@ +age-encryption.org/v1 +-> ssh-ed25519 gvwQ2Q PoCUbJ4Pg2ZCYy3HCI4w7J/vu5gh6d257Q/PlOBEEG4 +Hisdtymy8i3cN0LVuXpY8duCBMLlTT8QoOEYVmLy+n8 +-> ssh-ed25519 m8VklA i01UwKFor55UM6dL7glsMP6PQM9fcoa9EV3RRXPwRnE +9fJ9nWhhwyEXclzaYAszUTLTNH/xkM3u9uw0BgY8FOg +--- 8MUr5xLS5Rt1yXNPfIQwfF6ZGJwNOe/RVtlX0MaGMZ8 +ãYéòàì^쌛 ¯ôØhÅ#®‡üÿÂß2¿¢ñ·ÎN°‚tغ¢BêFÖX“Æoˆ“.eœ¼Cv%‘·1/•ýÌO%.‰GíÌþ×Ϥ%fÛÿ·¨šô]žä_2²ªeo~p ÇÜ{ýëbÝšý ðSH±Ó݆RÃnkôßcŽ‘jm‡º<?Ëk’%ÑnÙÈ:ˆFBJ#‰÷& \ No newline at end of file diff --git a/nix/hosts/corrino/secrets/grafana_env_vars.age b/nix/hosts/corrino/secrets/grafana_env_vars.age index 0365676..7ad889e 100644 --- a/nix/hosts/corrino/secrets/grafana_env_vars.age +++ b/nix/hosts/corrino/secrets/grafana_env_vars.age Binary files differdiff --git a/nix/hosts/corrino/secrets/grafana_oidc_client_secret.age b/nix/hosts/corrino/secrets/grafana_oidc_client_secret.age new file mode 100644 index 0000000..91d87e8 --- /dev/null +++ b/nix/hosts/corrino/secrets/grafana_oidc_client_secret.age @@ -0,0 +1,7 @@ +age-encryption.org/v1 +-> ssh-ed25519 gvwQ2Q YdFGe2zYgdQDdW9tZG/VPlV6ZnWCv1u2hIg3AiBVwU0 +7PXZNJR5HszD2IqVJX3Rw2VfI1Anf3fuOQTFNq58raU +-> ssh-ed25519 m8VklA LP+D7xz1SbSPT+6lEfaRjxNPSsBfyN7pE2LAe7ErVCA +wQeekB+chF01SCX8+BNcKk7o6jN8sT5uic+Oe/od9yc +--- ZG36Lj4tUALxjMb1+86Y3tdH1KMEw+Teeks0UbB2Zvk +¼.² „öií0èÓ.X®¬âúýðNÝâ)¡Â`ÁçuPˆ&4ÌÒÊôšpHTDöžþB‹¾aCŽ—µ>}q…”Q’–QÐã“´¤˜ÅŠ“·‘>T¡È<„þÙ‡+'€zeÞ{©ÅÊÁS؃› IØxîÆˆŸ$mO…Ö¨‹÷¹yÄPÛþvyAš´íUg¦f4$oW¾gýˆ³× \ No newline at end of file diff --git a/nix/hosts/corrino/secrets/hedgedoc_environment_variables.age b/nix/hosts/corrino/secrets/hedgedoc_environment_variables.age index cf3cac2..a5fe67e 100644 --- a/nix/hosts/corrino/secrets/hedgedoc_environment_variables.age +++ b/nix/hosts/corrino/secrets/hedgedoc_environment_variables.age Binary files differdiff --git a/nix/hosts/corrino/secrets/hedgedoc_oidc_client_secret.age b/nix/hosts/corrino/secrets/hedgedoc_oidc_client_secret.age new file mode 100644 index 0000000..46d39fd --- /dev/null +++ b/nix/hosts/corrino/secrets/hedgedoc_oidc_client_secret.age Binary files differdiff --git a/nix/hosts/corrino/secrets/immich_oidc_client_secret.age b/nix/hosts/corrino/secrets/immich_oidc_client_secret.age new file mode 100644 index 0000000..be7429d --- /dev/null +++ b/nix/hosts/corrino/secrets/immich_oidc_client_secret.age Binary files differdiff --git a/nix/hosts/corrino/secrets/miniflux_admin_file.age b/nix/hosts/corrino/secrets/miniflux_admin_file.age new file mode 100644 index 0000000..3e00b9b --- /dev/null +++ b/nix/hosts/corrino/secrets/miniflux_admin_file.age @@ -0,0 +1,7 @@ +age-encryption.org/v1 +-> ssh-ed25519 gvwQ2Q OGds4NLmRiMmVjPTORP3jLe3iEkqrDyTqW4V7ceFfRk +FFdZcsT9ZruNhpY5cb674qpQpK0qzHNwRPCfHvYaKcE +-> ssh-ed25519 m8VklA 84XSPja8dzJEUVR5olwNONVzNn5QrsX+R+WeBHqxXDo +5CVpnTDcO0EG3NsHdFsSABWNBIe3Xe16me13JIOlfos +--- rlIUU/0gYwxIXmpRI5/3mmZXJ+JrG/tE/3IBtpo4uT4 +²Ý-9J¬N™ÌVŸëªG.l‚.eÈ?Á©&¾§rõ;V˜#®ahSJWjh‰ôèv˜Ñ³t;3è¸É‚ϫk Ž(^QU ‹ö*ºcz·ßF°bwPZ¼uqãšÄ‰Û \ No newline at end of file diff --git a/nix/hosts/corrino/secrets/miniflux_oidc_client_secret.age b/nix/hosts/corrino/secrets/miniflux_oidc_client_secret.age new file mode 100644 index 0000000..85879a9 --- /dev/null +++ b/nix/hosts/corrino/secrets/miniflux_oidc_client_secret.age Binary files differdiff --git a/nix/hosts/corrino/secrets/miniflux_oidc_secret.age b/nix/hosts/corrino/secrets/miniflux_oidc_secret.age new file mode 100644 index 0000000..668c429 --- /dev/null +++ b/nix/hosts/corrino/secrets/miniflux_oidc_secret.age @@ -0,0 +1,8 @@ +age-encryption.org/v1 +-> ssh-ed25519 gvwQ2Q Xjrf8ip0AwW6b77m4XJupjfszP3echG2XQULubcQO14 +A2RZ+dWnrbS83yw5krGr3QuHzdxUo8RLbqstO7PqdzY +-> ssh-ed25519 m8VklA RHSeMlhwrnG433aw1Hggck8kaVlSL94TVvn68PIS3W8 +ymqenUy96rBZnCaLzrgcAW67s4WkHUv/xRPLw3Viy9g +--- iJRJrTP0vx6h7/uHO09JlKmq5Z/IfcrYxlIe+ZGFFlI +-SàJ¢%·îÄ1ÃdÙZŒÛ"ž5xˆZâ5gsŒ%ã{}uÄnôÅö/›p¶Ûw¦Â€Jò(É3…!Å1nE2„QQMJ™Œs[Ao{t½®¾rð‰Ñëç/Ä +‰vK`Šã¨rúœD» \ No newline at end of file diff --git a/nix/hosts/corrino/secrets/tailscale-corrino-cert.age b/nix/hosts/corrino/secrets/tailscale-corrino-cert.age new file mode 100644 index 0000000..ecb9e6e --- /dev/null +++ b/nix/hosts/corrino/secrets/tailscale-corrino-cert.age Binary files differdiff --git a/nix/hosts/corrino/secrets/tailscale-corrino-key.age b/nix/hosts/corrino/secrets/tailscale-corrino-key.age new file mode 100644 index 0000000..5226883 --- /dev/null +++ b/nix/hosts/corrino/secrets/tailscale-corrino-key.age Binary files differdiff --git a/nix/hosts/corrino/www/ctf.emile.space.nix b/nix/hosts/corrino/www/ctf.emile.space.nix index 28c9419..a6ebd05 100644 --- a/nix/hosts/corrino/www/ctf.emile.space.nix +++ b/nix/hosts/corrino/www/ctf.emile.space.nix @@ -7,18 +7,19 @@ locations = { "/" = { - proxyPass = "http://127.0.0.1:${toString config.emile.ports.ctf}"; + # proxyPass = "http://127.0.0.1:${toString config.emile.ports.ctf}"; + proxyPass = "http://138.199.213.51"; }; }; }; - virtualisation.oci-containers = { - # backend = "docker"; - containers = { - "ctfd" = { - image = "ctfd/ctfd"; - ports = [ "${toString config.emile.ports.ctf}:8000" ]; - }; - }; - }; + # virtualisation.oci-containers = { + # # backend = "docker"; + # containers = { + # "ctfd" = { + # image = "ctfd/ctfd"; + # ports = [ "${toString config.emile.ports.ctf}:8000" ]; + # }; + # }; + # }; } diff --git a/nix/hosts/corrino/www/git/cgit.nix b/nix/hosts/corrino/www/git/cgit.nix index 68304db..44f5996 100644 --- a/nix/hosts/corrino/www/git/cgit.nix +++ b/nix/hosts/corrino/www/git/cgit.nix @@ -630,7 +630,13 @@ in extraGroups = [ "gitea" ]; home = "/var/lib/git"; uid = lib.mkForce 127; + # shell = "${pkgs.git}/bin/git-shell"; + # openssh.authorizedKeys.keys = [ + # "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPZi43zHEsoWaQomLGaftPE5k0RqVrZyiTtGqZlpWsew emile@caladan + # " + # ]; }; + users.groups.git = { gid = lib.mkForce 127; }; diff --git a/nix/hosts/corrino/www/git/git.nix b/nix/hosts/corrino/www/git/git.nix deleted file mode 100644 index 3a2b9da..0000000 --- a/nix/hosts/corrino/www/git/git.nix +++ /dev/null @@ -1,106 +0,0 @@ -{ - lib, - pkgs, - config, - ... -}: - -let - cfg = config.services.gitea; -in -{ - services.nginx.virtualHosts."git.emile.space" = { - forceSSL = true; - enableACME = true; - - # TODO(emile): figure out why this doesn't work when enabled, has to do with authelia - # extraConfig = authelia-location; - - locations = { - "/" = { - # proxyPass = "http://127.0.0.1:3000"; - proxyPass = "http://127.0.0.1:${toString config.services.gitea.settings.server.HTTP_PORT}"; - - # TODO(emile): figure out why this doesn't work when enabled, has to do with authelia - # extraConfig = authelia-authrequest; - }; - }; - }; - - # auth via authelia - services.authelia.instances.main.settings.identity_providers.oidc.clients = [ - { - id = "git"; - - # ; nix run nixpkgs#authelia -- crypto hash generate pbkdf2 --variant sha512 --random --random.length 72 --random.charset rfc3986 - secret = "$pbkdf2-sha512$310000$4bi9wRkfcqnjbdmgt7rU.g$pQ2mC6GW4.BQwanGKKFhFyIx6Y.WY80xd/YpmlYOPnlnGBWpp0dSOTv6a/2yqSA5D.EuRkGCyeexSE5FdCK2TA"; - public = false; - authorization_policy = "two_factor"; - redirect_uris = [ "https://git.emile.space/user/oauth2/authelia/callback" ]; - scopes = [ - "openid" - "email" - "profile" - ]; - } - ]; - - services.gitea = rec { - enable = true; - - appName = "git.emile.space"; - - # unstable in order to use the 1.20... version - #package = pkgs.forgejo; - package = pkgs.unstable.forgejo; - - stateDir = "/var/lib/gitea"; - repositoryRoot = "${stateDir}/repositories"; - - settings = { - service.DISABLE_REGISTRATION = true; - - DEFAULT = { - WORK_PATH = "/var/lib/gitea"; - }; - - server = { - DOMAIN = pkgs.lib.mkForce "git.emile.space"; - ROOT_URL = pkgs.lib.mkForce "https://git.emile.space"; - HTTP_PORT = config.emile.ports.git; - - #START_SSH_SERVER = true; - BUILTIN_SSH_SERVER_USER = "git"; - SSH_USER = "gitea"; - SSH_DOMAIN = "git.emile.space"; - - REPO_INDEXER_ENABLED = true; - }; - - indexer = { - REPO_INDEXER_ENABLED = true; - ISSUE_INDEXER_PATH = "${stateDir}/indexers/issues.bleve"; - REPO_INDEXER_PATH = "${stateDir}/indexers/repos.bleve"; - MAX_FILE_SIZE = 1048576; - REPO_INDEXER_INCLUDE = ""; - REPO_INDEXER_EXCLUDE = "resources/bin/**"; - }; - - #federation = { - # enable = true; - # share_user_statistics = true; - # max_size = 4; - #}; - }; - }; - - users.users.git = { - isSystemUser = true; - useDefaultShell = true; - group = "git"; - extraGroups = [ "gitea" ]; - home = cfg.stateDir; - uid = 127; - }; - users.groups.git = { }; -} diff --git a/nix/hosts/corrino/www/goapp.emile.space.nix b/nix/hosts/corrino/www/goapp.emile.space.nix index 361e95a..e31079e 100644 --- a/nix/hosts/corrino/www/goapp.emile.space.nix +++ b/nix/hosts/corrino/www/goapp.emile.space.nix @@ -12,12 +12,16 @@ }; }; + age.secrets.goapp_oidc_client_secret.owner = "authelia-main"; + age.secrets.goapp_oidc_client_secret.group = "authelia-main"; + services.authelia.instances.main.settings.identity_providers.oidc.clients = [ { - id = "goapp"; + client_id = "goapp"; # ; nix run nixpkgs#authelia -- crypto hash generate pbkdf2 --variant sha512 --random --random.length 72 --random.charset rfc3986 - secret = "$pbkdf2-sha512$310000$LPXJRoGR9RyTcaT6cADljg$FK8RV5CnKj5ano4fXmRzzvXcX/00F7k/G6nd67t.8iewpwyq8FntV4JgYZSV8AynYMxz1qnL4j3BzITLCM0KgQ"; + client_secret = "{{ secret \"${config.age.secrets.goapp_oidc_client_secret.path}\" }}"; + public = false; authorization_policy = "two_factor"; redirect_uris = [ diff --git a/nix/hosts/corrino/www/grafana.emile.space.nix b/nix/hosts/corrino/www/grafana.emile.space.nix index 22b444f..2caa4d4 100644 --- a/nix/hosts/corrino/www/grafana.emile.space.nix +++ b/nix/hosts/corrino/www/grafana.emile.space.nix @@ -3,134 +3,143 @@ { systemd.services.grafana.serviceConfig.EnvironmentFile = config.age.secrets.grafana_env_vars.path; - services = { - nginx.virtualHosts = { - "grafana.emile.space" = { - addSSL = true; - enableACME = true; - locations."/" = { - proxyPass = "http://${toString config.services.grafana.settings.server.http_addr}:${toString config.services.grafana.settings.server.http_port}/"; - proxyWebsockets = true; - }; + + services.nginx.virtualHosts = { + "grafana.emile.space" = { + addSSL = true; + enableACME = true; + locations."/" = { + proxyPass = "http://${toString config.services.grafana.settings.server.http_addr}:${toString config.services.grafana.settings.server.http_port}/"; + proxyWebsockets = true; }; }; + }; - authelia.instances.main.settings.identity_providers.oidc.clients = [ - { - id = "Grafana"; - - # ; nix run nixpkgs#authelia -- crypto hash generate pbkdf2 --variant sha512 --random --random.length 72 --random.charset rfc3986 - secret = "$pbkdf2-sha512$310000$S.RE0jcmr7Sn/tjJDNxV/A$1tsYhQ/YEcVfE4JyzszHemrcUqy.84Fb6xVSmz87if5C9N46Mz2lRWB5l8s4EIrLsiumPnt4HQMkYZ4MoovJzA"; - public = false; - authorization_policy = "two_factor"; - redirect_uris = [ "https://grafana.emile.space/login/generic_oauth" ]; - scopes = [ - "openid" - "email" - "profile" - "groups" - ]; - grant_types = [ - "refresh_token" - "authorization_code" - ]; - response_types = [ "code" ]; - response_modes = [ - "form_post" - "query" - "fragment" - ]; - } - ]; - - grafana = { - enable = true; - settings = { - server = { - http_addr = "127.0.0.1"; - http_port = config.emile.ports.grafana; - domain = "grafana.emile.space"; - root_url = "https://grafana.emile.space/"; - }; + age.secrets.grafana_oidc_client_secret.owner = "authelia-main"; + age.secrets.grafana_oidc_client_secret.group = "authelia-main"; - "auth.generic_oauth" = - let - sso = "https://sso.emile.space/api/oidc"; - in - { - enabled = true; - client_id = "Grafana"; - - # [auth.generic_oauth] - # client_secret = ... - # set in env var as - # GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET - client_secret = "set in env var this is just a placeholder"; - - use_refresh_token = true; - token_url = "${sso}/token"; - auth_url = "${sso}/authorization"; - api_url = "${sso}/userinfo"; - - scopes = [ - "openid" - "email" - "profile" - "groups" - ]; - - email_attribute_path = "email"; - login_attribute_path = "preferred_username"; - name_attribute_path = "name"; - - role_attribute_path = "contains(groups[*], 'grafana_server_admin') && 'GrafanaAdmin' || contains(groups[*], 'grafana_admin') && 'Admin' || contains(groups[*], 'grafana_editor') && 'Editor' || 'Viewer'"; - - }; + services.authelia.instances.main.settings.identity_providers.oidc.clients = [ + { + client_id = "Grafana"; + + # ; nix run nixpkgs#authelia -- crypto hash generate pbkdf2 --variant sha512 --random --random.length 72 --random.charset rfc3986 + client_secret = "{{ secret \"${config.age.secrets.grafana_oidc_client_secret.path}\" }}"; + + public = false; + authorization_policy = "two_factor"; + redirect_uris = [ "https://grafana.emile.space/login/generic_oauth" ]; + scopes = [ + "openid" + "email" + "profile" + "groups" + ]; + grant_types = [ + "refresh_token" + "authorization_code" + ]; + response_types = [ "code" ]; + response_modes = [ + "form_post" + "query" + "fragment" + ]; + } + ]; + + services.grafana = { + enable = true; + settings = { + server = { + http_addr = "127.0.0.1"; + http_port = config.emile.ports.grafana; + domain = "grafana.emile.space"; + root_url = "https://grafana.emile.space/"; }; - provision = { - dashboards.settings = { }; - datasources.settings = { - datasources = [ - { - url = "http://localhost:${toString config.services.prometheus.port}"; - type = "prometheus"; - name = "Prometheus"; - editable = false; - access = "proxy"; # server = "proxy", browser = "direct" - } - { - name = "loki"; - url = "http://${config.services.loki.configuration.common.instance_addr}:${toString config.services.loki.configuration.server.http_listen_port}"; - type = "loki"; - } + "auth.generic_oauth" = + let + sso = "https://sso.emile.space/api/oidc"; + in + { + enabled = true; + client_id = "Grafana"; + + # [auth.generic_oauth] + # client_secret = ... + # set in env var as + # GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET + client_secret = "set in env var this is just a placeholder"; + + use_refresh_token = true; + token_url = "${sso}/token"; + auth_url = "${sso}/authorization"; + api_url = "${sso}/userinfo"; + + scopes = [ + "openid" + "email" + "profile" + "groups" ]; + + email_attribute_path = "email"; + login_attribute_path = "preferred_username"; + name_attribute_path = "name"; + + role_attribute_path = "contains(groups[*], 'grafana_server_admin') && 'GrafanaAdmin' || contains(groups[*], 'grafana_admin') && 'Admin' || contains(groups[*], 'grafana_editor') && 'Editor' || 'Viewer'"; + }; + }; - # TODO(emile): finish setting up the grafana notifier filling out the settings section - # notifiers = [ - # { - # uid = "2ad1c1d1-bcd9-4cb8-8897-c89c5820ffb1"; - # type = "email"; - # settings = {}; - # org_name = "Main Org."; - # org_id = 1; - # name = "email"; - # id_default = true; - # frequency = "5m"; - # disable_resolve_message = false; - # } - # ]; - - # TODO(emile): finish setting up the alerting stuff within here - # alerting = { - # templates.settings = { }; - # rules.settings = {}; - # policies.settings = {}; - # muteTimings.settings = {}; - # contactPoints.settings = {}; - # }; + provision = { + dashboards.settings = { }; + datasources.settings = { + deleteDatasources = [ + { name = "Prometheus"; orgId = 1; } + { name = "Lampadas"; orgId = 1; } + ]; + datasources = [ + { + url = "http://localhost:${toString config.services.prometheus.port}"; + type = "prometheus"; + name = "Prometheus Corrino"; + editable = false; + access = "proxy"; # server = "proxy", browser = "direct" + } + { + url = "http://lampadas:9009"; + type = "prometheus"; + name = "Prometheus Lampadas"; + editable = false; + access = "proxy"; # server = "proxy", browser = "direct" + } + ]; }; + + # TODO(emile): finish setting up the grafana notifier filling out the settings section + # notifiers = [ + # { + # uid = "2ad1c1d1-bcd9-4cb8-8897-c89c5820ffb1"; + # type = "email"; + # settings = {}; + # org_name = "Main Org."; + # org_id = 1; + # name = "email"; + # id_default = true; + # frequency = "5m"; + # disable_resolve_message = false; + # } + # ]; + + # TODO(emile): finish setting up the alerting stuff within here + # alerting = { + # templates.settings = { }; + # rules.settings = {}; + # policies.settings = {}; + # muteTimings.settings = {}; + # contactPoints.settings = {}; + # }; }; }; } diff --git a/nix/hosts/corrino/www/hydra.emile.space.nix b/nix/hosts/corrino/www/hydra.emile.space.nix index a5cdb53..fe70bf4 100644 --- a/nix/hosts/corrino/www/hydra.emile.space.nix +++ b/nix/hosts/corrino/www/hydra.emile.space.nix @@ -21,9 +21,10 @@ services.hydra = { enable = true; - package = pkgs.hydra_unstable.overrideAttrs (old: { - patches = (if old ? patches then old.patches else [ ]) ++ [ ./hydra.patch ]; - }); + #package = pkgs.hydra_unstable.overrideAttrs (old: { + # patches = (if old ? patches then old.patches else [ ]) ++ [ ./hydra.patch ]; + #}); + package = pkgs.hydra; listenHost = "*"; port = config.emile.ports.hydra; diff --git a/nix/hosts/corrino/www/irc.emile.space.nix b/nix/hosts/corrino/www/irc.emile.space.nix index ac00445..7653cb4 100644 --- a/nix/hosts/corrino/www/irc.emile.space.nix +++ b/nix/hosts/corrino/www/irc.emile.space.nix @@ -1,155 +1,198 @@ -{ config, ... }: +{ config, pkgs, ... }: { + ############################################################################## + # Client + ############################################################################## + # gamja web client + # https://codeberg.org/emersion/gamja + # + # nah, let's just use the commaond line "senpai" client, from the same person + + ############################################################################## + # Bouncer + ############################################################################## + # soju bouncer + # https://soju.im + + # services.soju = { + # enable = true; + # listen = [ "127.0.0.1:${toString config.emile.ports.irc.bouncer}" ]; + + # hostName = "irc.emile.space"; + # httpOrigins = [ "127.0.0.1" "irc.emile.space" ]; + + # # tlsCertificateKey = "/var/lib/acme/irc.emile.space/key.pem"; + # # tlsCertificate = "/var/lib/acme/irc.emile.space/cert.pem"; + # }; + + # services.soju = { + # enable = true; + # package = pkgs.soju; + # listen = [ "127.0.0.1:${toString config.emile.ports.irc.bouncer}" ]; + # adminSocket.enable = true; + # # tlsCertificateKey = "/var/lib/acme/irc.emile.space/key.pem"; + # # tlsCertificate = "/var/lib/acme/irc.emile.space/cert.pem"; + # httpOrigins = [ "127.0.0.1" "irc.emile.space" ]; + # hostName = "irc.emile.space"; + # extraConfig = ""; + # enableMessageLogging = true; + # acceptProxyIP = []; + # }; + + ############################################################################## + # Server + ############################################################################## + # Create a tls cert for the irc server - security.acme.certs = { - "irc.emile.space" = { - webroot = "/var/lib/acme/acme-challenge/"; - email = "acme@emile.space"; - postRun = "cp fullchain.pem /home/ergo/ && cp key.pem /home/ergo && chown ergo:ergo /home/ergo/*.pem && systemctl reload ergo.service"; - }; - }; - - # Allow ergo to access the created cert - # The systemd server runs using a dynamic user, so the below inserts the .pem files - # into "/run/credentials/ergochat.service/key.pem" - systemd.services.ergochat.serviceConfig = { - LoadCredential = [ - "fullchain.pem:/var/lib/acme/irc.emile.space/fullchain.pem" - "key.pem:/var/lib/acme/irc.emile.space/key.pem" - ]; - }; - - # allow connections to the port from the "outside" - networking.firewall.allowedTCPPorts = [ config.emile.ports.irc.ssl ]; - - services.ergochat = { - enable = true; - - # https://raw.githubusercontent.com/ergochat/ergo/master/default.yaml - settings = { - accounts = { - authentication-enabled = true; - multiclient = { - allowed-by-default = true; - always-on = "opt-out"; - auto-away = "opt-out"; - enabled = true; - }; - registration = { - enabled = true; - allow-before-connect = true; - bcrypt-cost = 4; - email-verification = { - enabled = false; - }; - throttling = { - duration = "10m"; - enabled = true; - max-attempts = 30; - }; - }; - }; - channels = { - default-modes = "+ntC"; - registration = { - enabled = true; - }; - }; - datastore = { - autoupgrade = true; - path = "/var/lib/ergo/ircd.db"; - }; - history = { - enabled = true; - autoreplay-on-join = 0; - autoresize-window = "3d"; - channel-length = 2048; - chathistory-maxmessages = 100; - client-length = 256; - restrictions = { - expire-time = "1w"; - grace-period = "1h"; - query-cutoff = "none"; - }; - retention = { - allow-individual-delete = false; - enable-account-indexing = false; - }; - tagmsg-storage = { - default = false; - whitelist = [ - "+draft/react" - "+react" - ]; - }; - znc-maxmessages = 2048; - }; - limits = { - awaylen = 390; - channellen = 64; - identlen = 20; - kicklen = 390; - nicklen = 32; - topiclen = 390; - }; - network = { - name = "emilespace"; - }; - server = { - casemapping = "permissive"; - check-ident = false; - enforce-utf = true; - forward-confirm-hostnames = false; - ip-cloaking = { - enabled = false; - }; - ip-limits = { - count = false; - throttle = false; - }; - listeners = { - # sts only port - ":6667".sts-only = true; - - # loopback listeners - # "127.0.0.1:6668" = {}; - # "[::]:6668" = {}; - - ":${toString config.emile.ports.irc.ssl}" = { - tls = { - cert = "/run/credentials/ergochat.service/fullchain.pem"; - key = "/run/credentials/ergochat.service/key.pem"; - }; - - # for cloud load balancers setting a PROXY header, NOT reverse proxies... - proxy = false; - - min-tls-version = 1.2; - }; - }; - lookup-hostnames = false; - max-sendq = "1M"; - name = "emile.space"; - relaymsg = { - enabled = false; - }; - sts = { - enabled = true; # redirect from plain to tls if supported - - # how long clients should be forced to use TLS for. - # (Emile): no clue why, can I set something like \infty here? - duration = "12m"; - - }; - }; - logging = [ - { - method = "stderr"; - type = "* -userinput -useroutput"; - level = "debug"; - } - ]; - }; - }; + # security.acme.certs = { + # "irc.emile.space" = { + # webroot = "/var/lib/acme/acme-challenge/"; + # email = "acme@emile.space"; + # # postRun = "cp fullchain.pem /home/ergo/ && cp key.pem /home/ergo && chown ergo:ergo /home/ergo/*.pem && systemctl reload ergo.service"; + # }; + # }; + + # # Allow ergo to access the created cert + # # The systemd server runs using a dynamic user, so the below inserts the .pem files + # # into "/run/credentials/ergochat.service/key.pem" + # systemd.services.ergochat.serviceConfig = { + # LoadCredential = [ + # "fullchain.pem:/var/lib/acme/irc.emile.space/fullchain.pem" + # "key.pem:/var/lib/acme/irc.emile.space/key.pem" + # ]; + # }; + + # # allow connections to the port from the "outside" + # networking.firewall.allowedTCPPorts = [ config.emile.ports.irc.ssl ]; + + # services.ergochat = { + # enable = true; + + # # https://raw.githubusercontent.com/ergochat/ergo/master/default.yaml + # settings = { + # accounts = { + # authentication-enabled = true; + # multiclient = { + # allowed-by-default = true; + # always-on = "opt-out"; + # auto-away = "opt-out"; + # enabled = true; + # }; + # registration = { + # enabled = true; + # allow-before-connect = true; + # bcrypt-cost = 4; + # email-verification = { + # enabled = false; + # }; + # throttling = { + # duration = "10m"; + # enabled = true; + # max-attempts = 30; + # }; + # }; + # }; + # channels = { + # default-modes = "+ntC"; + # registration = { + # enabled = true; + # }; + # }; + # datastore = { + # autoupgrade = true; + # path = "/var/lib/ergo/ircd.db"; + # }; + # history = { + # enabled = true; + # autoreplay-on-join = 0; + # autoresize-window = "3d"; + # channel-length = 2048; + # chathistory-maxmessages = 100; + # client-length = 256; + # restrictions = { + # expire-time = "1w"; + # grace-period = "1h"; + # query-cutoff = "none"; + # }; + # retention = { + # allow-individual-delete = false; + # enable-account-indexing = false; + # }; + # tagmsg-storage = { + # default = false; + # whitelist = [ + # "+draft/react" + # "+react" + # ]; + # }; + # znc-maxmessages = 2048; + # }; + # limits = { + # awaylen = 390; + # channellen = 64; + # identlen = 20; + # kicklen = 390; + # nicklen = 32; + # topiclen = 390; + # }; + # network = { + # name = "emilespace"; + # }; + # server = { + # casemapping = "permissive"; + # check-ident = false; + # enforce-utf = true; + # forward-confirm-hostnames = false; + # ip-cloaking = { + # enabled = false; + # }; + # ip-limits = { + # count = false; + # throttle = false; + # }; + # listeners = { + # # sts only port + # ":6667".sts-only = true; + + # # loopback listeners + # # "127.0.0.1:6668" = {}; + # # "[::]:6668" = {}; + + # ":${toString config.emile.ports.irc.ssl}" = { + # tls = { + # cert = "/run/credentials/ergochat.service/fullchain.pem"; + # key = "/run/credentials/ergochat.service/key.pem"; + # }; + + # # for cloud load balancers setting a PROXY header, NOT reverse proxies... + # proxy = false; + + # min-tls-version = 1.2; + # }; + # }; + # lookup-hostnames = false; + # max-sendq = "1M"; + # name = "emile.space"; + # relaymsg = { + # enabled = false; + # }; + # sts = { + # enabled = true; # redirect from plain to tls if supported + + # # how long clients should be forced to use TLS for. + # # (Emile): no clue why, can I set something like \infty here? + # duration = "12m"; + + # }; + # }; + # logging = [ + # { + # method = "stderr"; + # type = "* -userinput -useroutput"; + # level = "debug"; + # } + # ]; + # }; + # }; } diff --git a/nix/hosts/corrino/www/loki.emile.space.nix b/nix/hosts/corrino/www/loki.emile.space.nix deleted file mode 100644 index e5bfe24..0000000 --- a/nix/hosts/corrino/www/loki.emile.space.nix +++ /dev/null @@ -1,64 +0,0 @@ -{ config, ... }: - -{ - services = { - loki = { - enable = false; - configuration = { - auth_enabled = false; - server = { - http_listen_port = config.emile.ports.loki; - }; - - limits_config = { - reject_old_samples = false; - reject_old_samples_max_age = "7d"; - max_global_streams_per_user = 100000; - max_streams_per_user = 100000; - - retention_period = "10m"; - }; - - compactor = { - retention_enabled = true; - delete_request_store = "tsdb"; - }; - - common = { - instance_addr = "127.0.0.1"; - ring = { - instance_addr = "127.0.0.1"; - kvstore.store = "inmemory"; - }; - replication_factor = 1; - path_prefix = "/tmp/loki"; - }; - - # limits_config.allow_structured_metadata = false; - - schema_config.configs = [ - { - from = "2023-05-09"; - store = "tsdb"; - object_store = "filesystem"; - schema = "v13"; - index = { - prefix = "index_"; - period = "24h"; - }; - } - { - from = "2024-10-18"; - store = "tsdb"; - object_store = "filesystem"; - schema = "v13"; - index = { - prefix = "index_"; - period = "24h"; - }; - } - ]; - }; - }; - }; -} diff --git a/nix/hosts/corrino/www/mc.emile.space.nix b/nix/hosts/corrino/www/mc.emile.space.nix new file mode 100644 index 0000000..1a081bc --- /dev/null +++ b/nix/hosts/corrino/www/mc.emile.space.nix @@ -0,0 +1,153 @@ +{ config, pkgs, ... }: + +{ + services.minecraft-server = { + package = pkgs.minecraft-server; + serverProperties = { + server-port = 43000; + + # 0 peaceful + # 1 easy + # 2 normal + # 3 hard + difficulty = 1; + + # 0 survival + # 1 creative + # 2 adventure + # 5 default + # "spectator" spectator + # gamemode = "survival"; + gamemode = 0; + + max-players = 10; + motd = "Neurodivergenter Hexenzirkel"; + enable-rcon = true; + "rcon.password" = "hunter2"; + enable-command-block = false; + enable-query = false; + spawn-protection = 0; + + white-list = true; + }; + openFirewall = true; + + whitelist = { + "emileemail" = "a7614a53-b8b8-47b7-91cf-860e7c7f325f"; + "dodonator23" = "f93506b6-76e8-437d-927d-dceeb833a33f"; + "ChaosAyumi" = "223040ec-ca30-4238-8b58-c81597c30426"; + "xerunala" = "962e41c8-1da8-4592-9a2f-e36cdb20d5a6"; + "rappet" = "588377a5-362f-4ea1-8195-9cf97dd7a884"; + }; + + jvmOpts = "-Xms4092M -Xmx4092M"; + eula = true; + enable = true; + declarative = true; + dataDir = "/var/lib/minecraft"; + }; + + services.nginx.virtualHosts."mc.emile.space" = { + forceSSL = true; + enableACME = true; + }; + + services.bluemap = { + enable = true; + + enableNginx = true; + host = "mc.emile.space"; + + webappSettings = { + enabled = true; + webroot = config.services.bluemap.webRoot; + }; + + # webserverSettings = {}; + webserverSettings.enabled = false; # using nginx; + webRoot = "/var/lib/bluemap/web"; + + # coreSettings = {}; + coreSettings.data = "/var/lib/bluemap"; + coreSettings.metrics = false; # don't send data to the devs + + storage = { + "file" = { + root = "${config.services.bluemap.webRoot}/maps"; + }; + }; + # storage.<name>.storage-type + + maps = let + worldpath = "/var/lib/minecraft/world"; + in { + "overworld" = { + world = "${worldpath}"; + ambient-light = 0.1; + cave-detection-ocean-floor = -5; + dimension = "minecraft:overworld"; + }; + + "nether" = { + world = "${worldpath}/DIM-1"; + sorting = 100; + sky-color = "#290000"; + void-color = "#150000"; + ambient-light = 0.6; + world-sky-light = 0; + remove-caves-below-y = -10000; + cave-detection-ocean-floor = -5; + cave-detection-uses-block-light = true; + max-y = 90; + dimension = "minecraft:the_nether"; + }; + + "end" = { + world = "${worldpath}/DIM1"; + sorting = 200; + sky-color = "#080010"; + void-color = "#080010"; + ambient-light = 0.6; + world-sky-light = 0; + remove-caves-below-y = -10000; + cave-detection-ocean-floor = -5; + dimension = "minecraft:the_end"; + }; + }; + + # A set of resourcepacks, datapacks, and mods to extract resources from, loaded in alphabetical order. + packs = {}; + + # How often to trigger rendering the map, in the format of a systemd timer onCalendar configuration. See systemd.timer(5). + # + # This one means "every three hours": + # *-*-* */3:00:00 + onCalendar = "*-*-* *:00:00"; + + eula = true; + + enableRender = true; + + # The world used by the default map ruleset. If you configure your own maps you do not need to set this. + # defaultWorld = "${config.services.minecraft.dataDir}/world"; + + addons = {}; + }; + + services.restic.backups."corrino" = { + paths = [ "/var/lib/minecraft" ]; + }; + + services.restic.backups."minecraft" = { + repository = "/mnt/storagebox-bx11/minecraft"; + paths = [ "/var/lib/minecraft" ]; + passwordFile = config.age.secrets.restic_password.path; + initialize = true; + pruneOpts = [ + "--keep-daily 7" + "--keep-weekly 5" + "--keep-monthly 12" + "--keep-yearly 75" + ]; + }; +} diff --git a/nix/hosts/corrino/www/md.emile.space.nix b/nix/hosts/corrino/www/md.emile.space.nix index 6088ea0..1ee46fd 100644 --- a/nix/hosts/corrino/www/md.emile.space.nix +++ b/nix/hosts/corrino/www/md.emile.space.nix @@ -6,18 +6,21 @@ enableACME = true; locations = { "/" = { - proxyPass = "http://127.0.0.1:${toString config.services.hedgedoc.settings.port}"; + proxyPass = "http://[${config.services.hedgedoc.settings.host}]:${toString config.services.hedgedoc.settings.port}"; }; }; }; + age.secrets.hedgedoc_oidc_client_secret.owner = "authelia-main"; + age.secrets.hedgedoc_oidc_client_secret.group = "authelia-main"; + # auth via authelia services.authelia.instances.main.settings.identity_providers.oidc.clients = [ { - id = "HedgeDoc"; + client_id = "HedgeDoc"; # ; nix run nixpkgs#authelia -- crypto hash generate pbkdf2 --variant sha512 --random --random.length 72 --random.charset rfc3986 - secret = "$pbkdf2-sha512$310000$l4Kyec7Q9oY2GAhWA/xMig$P/MYFmulfgsDNyyiclUzd6le0oSiOvqCIvl4op5DkXtVTxLWlMA3ZwhJ6Z7u.OfIREuEM2htH6asxWPhBhkpNQ"; + client_secret = "{{ secret \"${config.age.secrets.hedgedoc_oidc_client_secret.path}\" }}"; public = false; authorization_policy = "two_factor"; redirect_uris = [ "https://md.emile.space/auth/oauth2/callback" ]; @@ -47,7 +50,7 @@ environmentFile = config.age.secrets.hedgedoc_environment_variables.path; settings = { - host = "127.0.0.1"; + host = "::1"; port = config.emile.ports.md; domain = "md.emile.space"; @@ -85,28 +88,20 @@ }; }; - # backups - # services.restic.backups."hedgedoc" = { - # user = "u331921"; - # timerConfig = { - # OnCalendar = "daily"; - # Persistent = true; - # }; - # # repository = "stfp:u331921@u331921.your-storagebox-de:23/restic"; - # repository = "/mnt/storagebox-bx11/backup/hedgedoc"; - # initialize = true; # initializes the repo, don't set if you want manual control - # passwordFile = config.age.secrets.restic_password.path; - # paths = [ "/var/lib/hedgedoc/" ]; - # pruneOpts = [ - # "--keep-daily 7" - # "--keep-weekly 5" - # "--keep-monthly 12" - # "--keep-yearly 75" - # ]; - - # # extraOpts = [ - # # "sftp.command='ssh backup@192.168.1.100 -i /home/user/.ssh/id_rsa -s sftp'" - # # ]; - # }; + services.restic.backups."corrino" = { + paths = [ "/var/lib/hedgedoc" ]; + }; + services.restic.backups."hedgedoc" = { + repository = "/mnt/storagebox-bx11/hedgedoc"; + paths = [ "/var/lib/hedgedoc" ]; + passwordFile = config.age.secrets.restic_password.path; + initialize = true; + pruneOpts = [ + "--keep-daily 7" + "--keep-weekly 5" + "--keep-monthly 12" + "--keep-yearly 75" + ]; + }; } diff --git a/nix/hosts/corrino/www/miniflux.emile.space.nix b/nix/hosts/corrino/www/miniflux.emile.space.nix new file mode 100644 index 0000000..90cb8f2 --- /dev/null +++ b/nix/hosts/corrino/www/miniflux.emile.space.nix @@ -0,0 +1,81 @@ +{ config, pkgs, ... }: + +{ + services.nginx.virtualHosts."miniflux.emile.space" = { + forceSSL = true; + enableACME = true; + locations = { + "/" = { + proxyPass = "http://${config.services.miniflux.config.LISTEN_ADDR}"; + }; + }; + }; + + # oidc not working and I can't bother to continue debugging it now + # + # Apr 12 15:37:38 corrino authelia[3693799]: {"level":"error","method":"POST","msg":"Access Request failed with error: Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method). The request was determined to be using 'token_endpoint_auth_method' method 'none', however the OAuth 2.0 client registration does not allow this method. The registered client with id 'miniflux' is configured to only support 'token_endpoint_auth_method' method 'client_secret_basic'. Either the Authorization Server client registration will need to have the 'token_endpoint_auth_method' updated to 'none' or the Relying Party will need to be configured to use 'client_secret_basic'. + # + # age.secrets.miniflux_oidc_client_secret.owner = "authelia-main"; + # age.secrets.miniflux_oidc_client_secret.group = "authelia-main"; + # + # auth via authelia + # services.authelia.instances.main.settings.identity_providers.oidc.clients = [ + # { + # client_id = "miniflux"; + + # # ; nix run nixpkgs#authelia -- crypto hash generate pbkdf2 --variant sha512 --random --random.length 72 --random.charset rfc3986 + # client_secret = "{{ secret \"${config.age.secrets.miniflux_oidc_client_secret.path}\" }}"; + # public = false; + # authorization_policy = "two_factor"; + # redirect_uris = [ "https://miniflux.emile.space/oauth2/oidc/callback" ]; + # scopes = [ + # "openid" + # "email" + # "profile" + # ]; + # # grant_types = [ + # # "refresh_token" + # # "authorization_code" + # # ]; + # # response_types = [ "code" ]; + # # response_modes = [ + # # "form_post" + # # "query" + # # "fragment" + # # ]; + # # token_endpoint_auth_method = "client_secret_post"; + # # token_endpoint_auth_method = "none"; + # } + # ]; + + services.miniflux = { + enable = true; + package = pkgs.miniflux; + config = { + LISTEN_ADDR = "[::1]:${toString config.emile.ports.miniflux}"; + BASE_URL = "https://miniflux.emile.space"; + + # Cleanup job frequency to remove old sessions and archive entries. + CLEANUP_FREQUENCY = 48; + + # Set to 1 to enable maintenance mode. Maintenance mode disables the web ui and show a text message to the users. + # MAINTENANCE_MODE = 1; + # MAINTENANCE_MESSAGE = "updating foo"; + + # DISABLE_LOCAL_AUTH = "true"; + # OAUTH2_CLIENT_ID = "miniflux"; + # OAUTH2_USER_CREATION = 1; + # OAUTH2_CLIENT_SECRET_FILE = config.age.secrets.miniflux_oidc_secret.path; + # OAUTH2_OIDC_DISCOVERY_ENDPOINT = "https://sso.emile.space"; + # OAUTH2_OIDC_PROVIDER_NAME = "authelia"; + # OAUTH2_PROVIDER = "oidc"; + # OAUTH2_REDIRECT_URL = "https://miniflux.emile.space/oauth2/oidc/callback"; + + LOG_LEVEL = "debug"; + }; + createDatabaseLocally = true; + + # File containing the ADMIN_USERNAME and ADMIN_PASSWORD (length >= 6) in the format of an EnvironmentFile=, as described by systemd.exec(5). + adminCredentialsFile = config.age.secrets.miniflux_admin_file.path; + }; +} diff --git a/nix/hosts/corrino/www/photo/immich.nix b/nix/hosts/corrino/www/photo/immich.nix index 92a3a64..3e1bf48 100644 --- a/nix/hosts/corrino/www/photo/immich.nix +++ b/nix/hosts/corrino/www/photo/immich.nix @@ -6,6 +6,15 @@ forceSSL = true; enableACME = true; locations = { + # # immich private proxy + # "/share" = { + # proxyPass = "http://${config.services.immich.host}:${toString config.services.immich-public-proxy.port}"; + # }; + # "/share/*" = { + # proxyPass = "http://${config.services.immich.host}:${toString config.services.immich-public-proxy.port}"; + # }; + + # immich "/" = { proxyPass = "http://${config.services.immich.host}:${toString config.services.immich.port}"; proxyWebsockets = true; @@ -13,13 +22,17 @@ }; }; + age.secrets.immich_oidc_client_secret.owner = "authelia-main"; + age.secrets.immich_oidc_client_secret.group = "authelia-main"; + # auth via authelia services.authelia.instances.main.settings.identity_providers.oidc.clients = [ { - id = "Immich"; + client_id = "Immich"; # ; nix run nixpkgs#authelia -- crypto hash generate pbkdf2 --variant sha512 --random --random.length 72 --random.charset rfc3986 - secret = "$pbkdf2-sha512$310000$iCgyAKjoYH9UKADProvbgw$LjrYkX1MjjtSXWDkxDjyp3NkLLuLVvKVwy3o8/Rw.8Z8b6yCkPWdBCothuCMlaGcgfG/zLWM6lRV4BrXVZpkig"; + client_secret = "{{ secret \"${config.age.secrets.immich_oidc_client_secret.path}\" }}"; + public = false; authorization_policy = "two_factor"; redirect_uris = [ @@ -43,15 +56,14 @@ # "fragment" #]; - token_endpoint_auth_method = "client_secret_basic"; + # token_endpoint_auth_method = "client_secret_basic"; # might be needed since the upgrade to nixos-24.11 and the resulting # 4.37.5 -> 4.38.17 upgrade - # token_endpoint_auth_method = "client_secret_post"; + token_endpoint_auth_method = "client_secret_post"; } ]; - services.immich = { enable = true; package = pkgs.immich; @@ -59,7 +71,7 @@ secretsFile = config.age.secrets.immich_secrets_file.path; host = "127.0.0.1"; - port = config.emile.ports.immich; + port = config.emile.ports.photo.immich; machine-learning = { enable = false; @@ -68,4 +80,19 @@ }; }; }; + + # services.immich-public-proxy = { + # enable = true; + # package = pkgs.immich-public-proxy; + # settings = { + # downloadOriginalPhoto = true; + # showGalleryTitle = true; + # allowDownloadAll = 1; + # showHomePage = true; + # showMetadata = true; + # }; + # port = config.emile.ports.photo.immich-public-proxy; + # openFirewall = false; + # immichUrl = "photo.emile.space"; + # }; } diff --git a/nix/hosts/corrino/www/prometheus.emile.space.nix b/nix/hosts/corrino/www/prometheus.emile.space.nix index 898f3b2..ec13dfa 100644 --- a/nix/hosts/corrino/www/prometheus.emile.space.nix +++ b/nix/hosts/corrino/www/prometheus.emile.space.nix @@ -38,15 +38,43 @@ enable = true; port = config.emile.ports.prometheus.exporter.nginx; }; + restic = { + enable = true; + # repository = "sftp:u331921@u331921.your-storagebox.de:/home/backup"; + repository = "/mnt/storagebox-bx11/corrino"; + port = config.emile.ports.prometheus.exporter.restic; + passwordFile = config.age.secrets.restic_password.path; + }; }; scrapeConfigs = [ { job_name = "corrino"; static_configs = [ - { targets = [ "127.0.0.1:${toString config.services.prometheus.exporters.node.port}" ]; } - { targets = [ "127.0.0.1:${toString config.services.prometheus.exporters.systemd.port}" ]; } - { targets = [ "127.0.0.1:${toString config.services.prometheus.exporters.smartctl.port}" ]; } - { targets = [ "127.0.0.1:${toString config.services.prometheus.exporters.nginx.port}" ]; } + { + targets = [ + "127.0.0.1:${toString config.services.prometheus.exporters.node.port}" + ]; + } + { + targets = [ + "127.0.0.1:${toString config.services.prometheus.exporters.systemd.port}" + ]; + } + { + targets = [ + "127.0.0.1:${toString config.services.prometheus.exporters.smartctl.port}" + ]; + } + { + targets = [ + "127.0.0.1:${toString config.services.prometheus.exporters.nginx.port}" + ]; + } + { + targets = [ + "127.0.0.1:${toString config.services.prometheus.exporters.restic.port}" + ]; + } ]; } { diff --git a/nix/hosts/corrino/www/promtail.emile.space.nix b/nix/hosts/corrino/www/promtail.emile.space.nix deleted file mode 100644 index 654414c..0000000 --- a/nix/hosts/corrino/www/promtail.emile.space.nix +++ /dev/null @@ -1,114 +0,0 @@ -{ config, ... }: - -{ - # allow the promtail user to read the nginx access files - users.users.promtail.extraGroups = [ "nginx" ]; - - services = { - promtail = { - enable = true; - configuration = { - server = { - http_listen_port = config.emile.ports.promtail; - grpc_listen_port = 0; - }; - positions.filename = "/tmp/positions.yml"; - clients = [{ - url = "http://localhost:${toString config.services.loki.configuration.server.http_listen_port}/loki/api/v1/push"; - }]; - scrape_configs = [ - - # systemd - { - job_name = "journal"; - journal = { - max_age = "12h"; - labels = { - job = "systemd-journal"; - host = config.networking.hostName; - }; - }; - relabel_configs = [ - { - source_labels = [ "__journal__systemd_unit" ]; - target_label = "unit"; - } - ]; - } - - # nginx error log - { - job_name = "nginx-error-logs"; - static_configs = [{ - targets = [ "localhost" ]; - labels = { - job = "nginx-error-logs"; - host = "corrino"; - __path__ = "/var/log/nginx/*error.log"; - }; - }]; - } - - # nginx - { - job_name = "nginx"; - static_configs = [ - { - targets = [ "localhost" ]; - labels = { - job = "nginx"; - host = "corrino"; - __path__ = "/var/log/nginx/*access.log"; - }; - } - ]; - pipeline_stages = [ - # { - # regex = { - # expression = "(?:[0-9]{1,3}\.){3}([0-9]{1,3})"; - # replace = "***"; - # }; - # } - { - regex = { - expression = ''(?P<remote_addr>.+) - - \[(?P<time_local>.+)\] "(?P<method>.+) (?P<url>.+) (HTTP\/(?P<version>\d.\d))" (?P<status>\d{3}) (?P<body_bytes_sent>\d+) (["](?P<http_referer>(\-)|(.+))["]) (["](?P<http_user_agent>.+)["])''; - }; - } - { - labels = { - remote_addr = null; - time_local = null; - method = null; - url = null; - status = null; - body_bytes_sent = null; - http_referer = null; - http_user_agent = null; - }; - } - { - timestamp = { - source = "time_local"; - format = "02/Jan/2006:15:04:05 -0700"; - }; - } - { - drop = { - source = "url"; - expression = ''/(_matrix|.well-known|notifications|api|identity).*''; - }; - } - { - drop = { - source = "url"; - expression = ''grafana.*''; - }; - } - ]; - } - - ]; - }; - }; - }; -} diff --git a/nix/hosts/corrino/www/s3.emile.space.nix b/nix/hosts/corrino/www/s3.emile.space.nix index b4646ad..ae33542 100644 --- a/nix/hosts/corrino/www/s3.emile.space.nix +++ b/nix/hosts/corrino/www/s3.emile.space.nix @@ -1,12 +1,21 @@ -{ config, ... }: +{ config, pkgs, ... }: { + security.acme.certs."s3.emile.space" = { + group = "nginx"; + domain = "s3.emile.space"; + extraDomainNames = [ + "*.s3.emile.space" + "*.s3-web.emile.space" + ]; + }; + services.nginx.virtualHosts."s3.emile.space" = { forceSSL = true; enableACME = true; locations = { "/" = { - proxyPass = "http://[::1]:${toString config.emile.ports.minio.s3}"; + proxyPass = "http://[::1]:${toString config.emile.ports.garage.s3}"; }; }; }; @@ -16,24 +25,96 @@ enableACME = true; locations = { "/" = { - proxyPass = "http://[::1]:${toString config.emile.ports.minio.web}"; + proxyPass = "http://[::1]:${toString config.emile.ports.garage.web}"; }; }; }; - services.minio = { + services.garage = { enable = true; - region = "eu-north-1-hel-1a"; # corrino is in the helsinki hetzner dc + package = pkgs.garage_1_x; + settings = { + data_dir = [ + { capacity = "50G"; path = "/var/lib/garage/data"; } + ]; - listenAddress = "[::1]:${toString config.emile.ports.minio.s3}"; + db_engine = "sqlite"; + replication_factor = 3; - browser = true; - consoleAddress = "[::1]:${toString config.emile.ports.minio.web}"; + s3_api = { + s3_region = "garage"; + api_bind_addr = "[::]:${toString config.emile.ports.garage.s3}"; + root_domain = "s3.emile.space"; + }; + s3_web = { + bind_addr = "[::]:${toString config.emile.ports.garage.web}"; + root_domain = "s3-web.emile.space"; + index = "index.html"; + }; + admin = { + api_bind_addr = "[::]:${toString config.emile.ports.garage.admin}"; + # metrics_token = config.age.secrets.garage_admin_metrics_secret.path; + # admin_token = config.age.secrets.garage_admin_token_secret.path; + }; - dataDir = [ "/minio/data" ]; - configDir = "/minio/config"; + # rpc_secret_file = config.age.secrets.garage_rpc_secret.path; + rpc_bind_addr = "[::]:${toString config.emile.ports.garage.rpc}"; + rpc_bind_outgoing = false; + rpc_public_addr = "[fc00:1::1]:${toString config.emile.ports.garage.rpc}"; + }; - rootCredentialsFile = config.age.secrets.minio_root_credz.path; - # accessKey + environmentFile = config.age.secrets.garage_env.path; }; +# metrics_token = config.age.secrets.garage_admin_metrics_secret.path; +# admin_token = config.age.secrets.garage_admin_token_secret.path; +# rpc_secret_file = config.age.secrets.garage_rpc_secret.path; + +# nix/hosts/corrino/secrets/garage_admin_metrics_secret.age +# nix/hosts/corrino/secrets/garage_admin_token_secret.age +# nix/hosts/corrino/secrets/garage_admin_token.age +# nix/hosts/corrino/secrets/garage_metrics_token.age +# nix/hosts/corrino/secrets/garage_rpc_secret.age + + # services.garage = { + # enable = true; + # package = pkgs.garage_1_x; + # settings = { + # db_engine = "sqlite"; + # replication_factor = 2; + + # data_dir = [ + # { capacity = "50G"; path = dataDir; } + # ]; + + # compression_level = 1; + + # rpc_secret_file = config.age.secrets.garage_rpc_secret.path; + # rpc_bind_addr = "[::]:${toString config.emile.ports.garage.rpc}"; + # rpc_bind_outgoing = false; + # rpc_public_addr = "[fc00:1::1]:${toString config.emile.ports.garage.rpc}"; + + # allow_world_readable_secrets = false; + + # s3_api = { + # api_bind_addr = "[::]:${toString config.emile.ports.garage.s3}"; + # s3_region = "garage"; + # root_domain = "s3.emile.space"; + # }; + + # s3_web = { + # bind_addr = "[::]:${toString config.emile.ports.garage.web}"; + # root_domain = "s3-web.emile.space"; + # add_host_to_metrics = true; + # }; + + # admin = { + # api_bind_addr = "[::]:${toString config.emile.ports.garage.admin}"; + # metrics_token = config.age.secrets.garage_admin_metrics_secret.path; + # admin_token = config.age.secrets.garage_admin_token_secret.path; + # trace_sink = "http://localhost:4317"; + # }; + + # }; + # logLevel = "trace"; # info + # }; } diff --git a/nix/hosts/corrino/www/sb.emile.space.nix b/nix/hosts/corrino/www/sb.emile.space.nix deleted file mode 100644 index 1854f0e..0000000 --- a/nix/hosts/corrino/www/sb.emile.space.nix +++ /dev/null @@ -1,114 +0,0 @@ -{ pkgs, ... }: - -{ - services.nginx.virtualHosts."sb.emile.space" = { - forceSSL = true; - enableACME = true; - locations = { - "/" = { - proxyPass = "http://${config.services.silverbullet.listenSddress}:${toString config.services.silverbullet.listenPort}"; - extraConfig = '' - ## Send a subrequest to Authelia to verify if the user is authenticated and has permission to access the resource. - auth_request /internal/authelia/authz; - - ## Save the upstream metadata response headers from Authelia to variables. - auth_request_set $user $upstream_http_remote_user; - auth_request_set $groups $upstream_http_remote_groups; - auth_request_set $name $upstream_http_remote_name; - auth_request_set $email $upstream_http_remote_email; - - ## Inject the metadata response headers from the variables into the request made to the backend. - proxy_set_header Remote-User $user; - proxy_set_header Remote-Groups $groups; - proxy_set_header Remote-Email $email; - proxy_set_header Remote-Name $name; - - ## Configure the redirection when the authz failure occurs. Lines starting with 'Modern Method' and 'Legacy Method' - ## should be commented / uncommented as pairs. The modern method uses the session cookies configuration's authelia_url - ## value to determine the redirection URL here. It's much simpler and compatible with the mutli-cookie domain easily. - - ## Modern Method: Set the $redirection_url to the Location header of the response to the Authz endpoint. - auth_request_set $redirection_url $upstream_http_location; - - ## Modern Method: When there is a 401 response code from the authz endpoint redirect to the $redirection_url. - error_page 401 =302 $redirection_url; - - ## Legacy Method: Set $target_url to the original requested URL. - ## This requires http_set_misc module, replace 'set_escape_uri' with 'set' if you don't have this module. - # set $target_url $scheme://$http_host$request_uri; - - ## Legacy Method: When there is a 401 response code from the authz endpoint redirect to the portal with the 'rd' - ## URL parameter set to $target_url. This requires users update 'auth.example.com/' with their external authelia URL. - # error_page 401 =302 https://sso.emile.space/?rd=$target_url; - ''; - }; - "/internal/authelia/authz" = { - extraConfig = '' - ## Essential Proxy Configuration - internal; - proxy_pass https://sso.emile.space/api/authz/auth-request; - - ## Headers - ## The headers starting with X-* are required. - proxy_set_header X-Original-Method $request_method; - proxy_set_header X-Original-URL $scheme://$http_host$request_uri; - proxy_set_header X-Forwarded-For $remote_addr; - proxy_set_header Content-Length ""; - proxy_set_header Connection ""; - - ## Basic Proxy Configuration - proxy_pass_request_body off; - proxy_next_upstream error timeout invalid_header http_500 http_502 http_503; # Timeout if the real server is dead - proxy_redirect http:// $scheme://; - proxy_http_version 1.1; - proxy_cache_bypass $cookie_session; - proxy_no_cache $cookie_session; - proxy_buffers 4 32k; - client_body_buffer_size 128k; - - ## Advanced Proxy Configuration - send_timeout 5m; - proxy_read_timeout 240; - proxy_send_timeout 240; - proxy_connect_timeout 240; - ''; - }; - - }; - - # auth via authelia - # services.authelia.instances.main.settings.identity_providers.oidc.clients = [ - # { - # id = "silverbullet"; - - # # ; nix run nixpkgs#authelia -- crypto hash generate pbkdf2 --variant sha512 --random --random.length 72 --random.charset rfc3986 - # secret = "$pbkdf2-sha512$310000$mxk7uITQOZNYEqeinigQnw$wsF2S6RPL2zVRg1X0bAuINh8Lu5PuA/2/FYJSy3i/Ig5vtCzaIFb0xYEcus4jkqTIgyp3aBxtgSzAKjQKC.QKg"; - # public = false; - # authorization_policy = "two_factor"; - # redirect_uris = [ "https://md.emile.space/auth/oauth2/callback" ]; - # scopes = [ - # "openid" - # "email" - # "profile" - # ]; - # grant_types = [ - # "refresh_token" - # "authorization_code" - # ]; - # response_types = [ "code" ]; - # response_modes = [ - # "form_post" - # "query" - # "fragment" - # ]; - # token_endpoint_auth_method = "client_secret_post"; - # } - # ]; - - services.silverbullet = { - enable = true; - spaceDir = "/var/lib/silverbullet"; - listenPort = 3000; - listenAddress = "[::1]"; - }; -} diff --git a/nix/hosts/corrino/www/social.emile.space.nix b/nix/hosts/corrino/www/social.emile.space.nix index 210f0be..d9d30f7 100644 --- a/nix/hosts/corrino/www/social.emile.space.nix +++ b/nix/hosts/corrino/www/social.emile.space.nix @@ -38,13 +38,17 @@ }; }; + age.secrets.gotosocial_oidc_client_secret.owner = "authelia-main"; + age.secrets.gotosocial_oidc_client_secret.group = "authelia-main"; + # auth via authelia services.authelia.instances.main.settings.identity_providers.oidc.clients = [ { - id = "gotosocial"; + client_id = "gotosocial"; # ; nix run nixpkgs#authelia -- crypto hash generate pbkdf2 --variant sha512 --random --random.length 72 --random.charset rfc3986 - secret = "$pbkdf2-sha512$310000$oDpZ5FuO965TbjPoophJXw$dbkAwWFvLN1h1Zh9US2ZOE5ilPRdEHMdGF/x0uorou2UqURrXF0KQmXxsV38F2yYMS7u/ecramKlvfMwsqHOcg"; + client_secret = "{{ secret \"${config.age.secrets.gotosocial_oidc_client_secret.path}\" }}"; + public = false; authorization_policy = "two_factor"; redirect_uris = [ "https://social.emile.space/auth/callback" ]; @@ -93,4 +97,21 @@ Restart = "on-failure"; }; }; + + services.restic.backups."corrino" = { + paths = [ "/var/lib/gotosocial" ]; + }; + + services.restic.backups."gotosocial" = { + repository = "/mnt/storagebox-bx11/gotosocial"; + paths = [ "/var/lib/gotosocial" ]; + passwordFile = config.age.secrets.restic_password.path; + initialize = true; + pruneOpts = [ + "--keep-daily 7" + "--keep-weekly 5" + "--keep-monthly 12" + "--keep-yearly 75" + ]; + }; } diff --git a/nix/hosts/corrino/www/sso.emile.space.nix b/nix/hosts/corrino/www/sso.emile.space.nix index 44e30bb..6ffff80 100644 --- a/nix/hosts/corrino/www/sso.emile.space.nix +++ b/nix/hosts/corrino/www/sso.emile.space.nix @@ -141,9 +141,22 @@ in storage.local.path = "/var/lib/authelia-main/db.sqlite"; session = { - domain = "sso.emile.space"; - expiration = 3600; # 1 hour - inactivity = 300; # 5 minutes + # domain = "sso.emile.space"; + # expiration = 3600; # 1 hour + # inactivity = 300; # 5 minutes + + cookies = [ + { + domain = "emile.space"; + authelia_url = "https://sso.emile.space"; + # The period of time the user can be inactive for until the session is destroyed. Useful if you want long session timers but don’t want unused devices to be vulnerable. + inactivity = "1h"; + # The period of time before the cookie expires and the session is destroyed. This is overridden by remember_me when the remember me box is checked. + expiration = "1d"; + # The period of time before the cookie expires and the session is destroyed when the remember me box is checked. Setting this to -1 disables this feature entirely for this session cookie domain + remember_me = "3M"; + } + ]; }; notifier = { @@ -196,6 +209,16 @@ in default_policy = "deny"; rules = [ { + # silverbullet needs access to these without auth + domain = "sb.emile.space"; + policy = "bypass"; + resources = [ + "/.client/manifest.json$" + "/.client/[a-zA-Z0-9_-]+.png$" + "/service_worker.js$" + ]; + } + { domain = "*.emile.space"; policy = "two_factor"; } diff --git a/nix/hosts/corrino/www/tickets.emile.space.nix b/nix/hosts/corrino/www/tickets.emile.space.nix index fb12961..08f23d3 100644 --- a/nix/hosts/corrino/www/tickets.emile.space.nix +++ b/nix/hosts/corrino/www/tickets.emile.space.nix @@ -18,7 +18,7 @@ enable = true; package = pkgs.pretix; plugins = with config.services.pretix.package.plugins; [ - passbook + # passbook pages ]; user = "pretix"; diff --git a/nix/hosts/lampadas/configuration.nix b/nix/hosts/lampadas/configuration.nix index cc829d8..d2630a8 100644 --- a/nix/hosts/lampadas/configuration.nix +++ b/nix/hosts/lampadas/configuration.nix @@ -2,7 +2,7 @@ # your system. Help is available in the configuration.nix(5) man page, on # https://search.nixos.org/options and in the NixOS manual (`nixos-help`). -{ pkgs, lib, ... }: +{ config, pkgs, lib, ... }: let emile_keys = [ @@ -17,12 +17,34 @@ in ./hardware-configuration.nix ]; + hardware.fancontrol = { + enable = true; + config = '' + # Configuration file generated by pwmconfig, changes will be lost + INTERVAL=10 + DEVPATH=hwmon0=devices/platform/coretemp.0 hwmon1=devices/platform/nct6775.672 + DEVNAME=hwmon0=coretemp hwmon1=nct6798 + FCTEMPS=hwmon1/pwm3=hwmon0/temp2_input hwmon1/pwm2=hwmon1/temp2_input + FCFANS=hwmon1/pwm3=hwmon1/fan3_input hwmon1/pwm2=hwmon1/fan2_input + MINTEMP=hwmon1/pwm3=35 hwmon1/pwm2=35 + MAXTEMP=hwmon1/pwm3=75 hwmon1/pwm2=75 + MINSTART=hwmon1/pwm3=255 hwmon1/pwm2=255 + MINSTOP=hwmon1/pwm3=30 hwmon1/pwm2=30 + MINPWM=hwmon1/pwm3=30 hwmon1/pwm2=30 + MAXPWM=hwmon1/pwm3=255 hwmon1/pwm2=255 + ''; + }; + boot = { loader = { systemd-boot.enable = true; efi.canTouchEfiVariables = true; }; kernelParams = [ "ip=dhcp" ]; + kernelModules = [ + # fan speed modules, detected using `sensors-detect` + "coretemp" "nct6775" + ]; initrd = { availableKernelModules = [ "r8169" ]; systemd.users.root.shell = "/bin/cryptsetup-askpass"; @@ -159,10 +181,41 @@ in }; # metric exporters - prometheus.exporters = { - node.enable = true; # port 9100 - systemd.enable = true; # port 9558 - smartctl.enable = true; # port 9633 + prometheus = { + enable = true; + port = 9090; + listenAddress = "100.87.209.97"; + scrapeConfigs = [ + { + job_name = "node"; + static_configs = [{ + targets = [ + "localhost:${toString config.services.prometheus.exporters.node.port}" + ]; + }]; + } + { + job_name = "systemd"; + static_configs = [{ + targets = [ + "localhost:${toString config.services.prometheus.exporters.systemd.port}" + ]; + }]; + } + { + job_name = "smartctl"; + static_configs = [{ + targets = [ + "localhost:${toString config.services.prometheus.exporters.smartctl.port}" + ]; + }]; + } + ]; + exporters = { + node.enable = true; # port 9100 + systemd.enable = true; # port 9558 + smartctl.enable = true; # port 9633 + }; }; # shares @@ -177,7 +230,6 @@ in openFirewall = true; settings = { global = { - ## Browsing/Identification ### "workgroup" = "Pacific"; "server string" = "lampadas"; @@ -269,18 +321,6 @@ in "force user" = "emile"; "guest ok" = "no"; "read only" = "no"; - - # "fruit:aapl" = "yes"; - # "fruit:copyfile" = "yes"; - # "fruit:delete_empty_adfiles" = "yes"; - # "fruit:metadata" = "stream"; - # "fruit:posix_rename" = "yes"; - # "fruit:time machine" = "yes"; - # "fruit:veto_appledouble" = "no"; - # "fruit:wipe_intentionally_left_blank_rfork" = "yes"; - # "fruit:nfs_aces" = "no"; - # "fruit:zero_file_id" = "yes"; - # "fruit:encoding" = "native"; }; public = { diff --git a/nix/lib/flake-helper.nix b/nix/lib/flake-helper.nix index f841fa5..e58e8b1 100644 --- a/nix/lib/flake-helper.nix +++ b/nix/lib/flake-helper.nix @@ -6,6 +6,8 @@ deploy-rs, home-manager, darwin, + flake-utils, + pwndbg, ... }@inputs: @@ -65,7 +67,7 @@ rec { if system == "x86_64-linux" then self.nixosModules.x86_64-linux else if system == "aarch64-darwin" then - ({ }) + { } else null ) @@ -88,6 +90,8 @@ rec { self.overlays.x86_64-linux else if system == "aarch64-darwin" then self.overlays.aarch64-darwin + # // self.overlays.unstable-darwin + # {} else null ) @@ -95,7 +99,9 @@ rec { # no clue why, but when rebuilding corrino and this not being commented, # something in the hardware.bluetooth module breaks # - # (if system == "aarch64-darwin" then self.overlays.unstable-darwin else null) + # (if system == "aarch64-darwin" + # then self.overlays.unstable-darwin + # else null) (_: _: { inherit (agenix.packages."x86_64-linux") agenix; }) @@ -240,4 +246,35 @@ rec { # don't build hosts that start with an underscore (nixpkgs.lib.filterAttrs (name: host: (builtins.substring 0 1 name) != "_") hosts); + + # A function taking an attribute set of flake templates, importing their + # flake.nix/output/packages (if there are any) and returning an attribute set + # of their packages (if the template has one or more) + template-packages = + builtins.mapAttrs (name: value: + (((import ../../nix/templates/${name}/flake.nix).outputs) + { inherit nixpkgs flake-utils pwndbg; }) + .packages or { } + ); + + # TODO(emile): templates + # apply the above function to the templates + # templates = template-packages self.templates; + + # TODO(emile): templates + # Merge template packages into root packages with template prefix + # merged-template-packages = + # system: + # let + # lib = nixpkgs.lib; + # in + # lib.foldl ( + # acc: tplName: + # let + # tplPkgs = templates.${tplName}.${system} or { }; + # prefixed = lib.mapAttrs' (pkgName: pkg: lib.nameValuePair "${tplName}-${pkgName}" pkg) tplPkgs; + # in + # acc // prefixed + # ) { } (builtins.attrNames templates); + } diff --git a/nix/modules/libvirtnix/a.xml b/nix/modules/libvirtnix/a.xml new file mode 100644 index 0000000..1255ad4 --- /dev/null +++ b/nix/modules/libvirtnix/a.xml @@ -0,0 +1,259 @@ +<domain type='kvm' id='5'> + <name>fileserver2</name> + <uuid>d62e0276-d474-452b-80f4-c951c39bcf74</uuid> + <metadata> + <libosinfo:libosinfo xmlns:libosinfo='http://libosinfo.org/xmlns/libvirt/domain/1.0'> + <libosinfo:os id='http://nixos.org/nixos/unknown'/> + </libosinfo:libosinfo> + </metadata> + <memory unit='KiB'>2097152</memory> + <currentMemory unit='KiB'>2097152</currentMemory> + <vcpu placement='static'>3</vcpu> + <resource> + <partition>/machine</partition> + </resource> + <os> + <type arch='x86_64' machine='pc-q35-3.1'>hvm</type> + <loader readonly='yes' type='pflash'>/usr/share/OVMF/OVMF_CODE.fd</loader> + <nvram>/var/lib/libvirt/qemu/nvram/fileserver2_VARS.fd</nvram> + <boot dev='hd'/> + </os> + <features> + <acpi/> + <apic/> + <vmport state='off'/> + </features> + <cpu mode='host-passthrough' check='none' migratable='on'/> + <clock offset='utc'> + <timer name='rtc' tickpolicy='catchup'/> + <timer name='pit' tickpolicy='delay'/> + <timer name='hpet' present='no'/> + </clock> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <pm> + <suspend-to-mem enabled='no'/> + <suspend-to-disk enabled='no'/> + </pm> + <devices> + <emulator>/usr/bin/qemu-system-x86_64</emulator> + <disk type='block' device='disk'> + <driver name='qemu' type='raw' cache='none' io='native' discard='unmap'/> + <source dev='/dev/vmstorage/fileserver2' index='3'/> + <backingStore/> + <target dev='vda' bus='virtio'/> + <alias name='virtio-disk0'/> + <address type='pci' domain='0x0000' bus='0x04' slot='0x00' function='0x0'/> + </disk> + <disk type='block' device='disk'> + <driver name='qemu' type='raw'/> + <source dev='/dev/mapper/storage1' index='2'/> + <backingStore/> + <target dev='vdb' bus='virtio'/> + <alias name='virtio-disk1'/> + <address type='pci' domain='0x0000' bus='0x08' slot='0x00' function='0x0'/> + </disk> + <disk type='block' device='disk'> + <driver name='qemu' type='raw'/> + <source dev='/dev/mapper/storage2' index='1'/> + <backingStore/> + <target dev='vdc' bus='virtio'/> + <alias name='virtio-disk2'/> + <address type='pci' domain='0x0000' bus='0x09' slot='0x00' function='0x0'/> + </disk> + <controller type='usb' index='0' model='qemu-xhci' ports='15'> + <alias name='usb'/> + <address type='pci' domain='0x0000' bus='0x02' slot='0x00' function='0x0'/> + </controller> + <controller type='pci' index='0' model='pcie-root'> + <alias name='pcie.0'/> + </controller> + <controller type='pci' index='1' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='1' port='0x10'/> + <alias name='pci.1'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0' multifunction='on'/> + </controller> + <controller type='pci' index='2' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='2' port='0x11'/> + <alias name='pci.2'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x1'/> + </controller> + <controller type='pci' index='3' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='3' port='0x12'/> + <alias name='pci.3'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x2'/> + </controller> + <controller type='pci' index='4' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='4' port='0x13'/> + <alias name='pci.4'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x3'/> + </controller> + <controller type='pci' index='5' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='5' port='0x14'/> + <alias name='pci.5'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x4'/> + </controller> + <controller type='pci' index='6' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='6' port='0x15'/> + <alias name='pci.6'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x5'/> + </controller> + <controller type='pci' index='7' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='7' port='0x16'/> + <alias name='pci.7'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x6'/> + </controller> + <controller type='pci' index='8' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='8' port='0x17'/> + <alias name='pci.8'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x7'/> + </controller> + <controller type='pci' index='9' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='9' port='0x18'/> + <alias name='pci.9'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0' multifunction='on'/> + </controller> + <controller type='pci' index='10' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='10' port='0x19'/> + <alias name='pci.10'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x1'/> + </controller> + <controller type='pci' index='11' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='11' port='0x1a'/> + <alias name='pci.11'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x2'/> + </controller> + <controller type='pci' index='12' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='12' port='0x1b'/> + <alias name='pci.12'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x3'/> + </controller> + <controller type='pci' index='13' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='13' port='0x1c'/> + <alias name='pci.13'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x4'/> + </controller> + <controller type='pci' index='14' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='14' port='0x1d'/> + <alias name='pci.14'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x5'/> + </controller> + <controller type='pci' index='15' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='15' port='0x1e'/> + <alias name='pci.15'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x6'/> + </controller> + <controller type='pci' index='16' model='pcie-to-pci-bridge'> + <model name='pcie-pci-bridge'/> + <alias name='pci.16'/> + <address type='pci' domain='0x0000' bus='0x07' slot='0x00' function='0x0'/> + </controller> + <controller type='sata' index='0'> + <alias name='ide'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/> + </controller> + <controller type='virtio-serial' index='0'> + <alias name='virtio-serial0'/> + <address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x0'/> + </controller> + <controller type='scsi' index='0' model='lsilogic'> + <alias name='scsi0'/> + <address type='pci' domain='0x0000' bus='0x10' slot='0x01' function='0x0'/> + </controller> + <interface type='bridge'> + <mac address='52:54:00:bf:ba:88'/> + <source network='services' portid='6c3a3512-d823-4521-9043-3a91a65682f5' bridge='br7'/> + <target dev='vnet2'/> + <model type='virtio'/> + <alias name='net0'/> + <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/> + </interface> + <serial type='pty'> + <source path='/dev/pts/3'/> + <target type='isa-serial' port='0'> + <model name='isa-serial'/> + </target> + <alias name='serial0'/> + </serial> + <console type='pty' tty='/dev/pts/3'> + <source path='/dev/pts/3'/> + <target type='serial' port='0'/> + <alias name='serial0'/> + </console> + <channel type='unix'> + <source mode='bind' path='/var/lib/libvirt/qemu/channel/target/domain-5-fileserver2/org.qemu.guest_agent.0'/> + <target type='virtio' name='org.qemu.guest_agent.0' state='disconnected'/> + <alias name='channel0'/> + <address type='virtio-serial' controller='0' bus='0' port='1'/> + </channel> + <channel type='spicevmc'> + <target type='virtio' name='com.redhat.spice.0' state='disconnected'/> + <alias name='channel1'/> + <address type='virtio-serial' controller='0' bus='0' port='2'/> + </channel> + <input type='tablet' bus='usb'> + <alias name='input0'/> + <address type='usb' bus='0' port='1'/> + </input> + <input type='mouse' bus='ps2'> + <alias name='input1'/> + </input> + <input type='keyboard' bus='ps2'> + <alias name='input2'/> + </input> + <graphics type='spice' port='5901' autoport='yes' listen='127.0.0.1'> + <listen type='address' address='127.0.0.1'/> + </graphics> + <sound model='ich9'> + <alias name='sound0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1b' function='0x0'/> + </sound> + <audio id='1' type='spice'/> + <video> + <model type='qxl' ram='65536' vram='65536' vgamem='16384' heads='1' primary='yes'/> + <alias name='video0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> + </video> + <redirdev bus='usb' type='spicevmc'> + <alias name='redir0'/> + <address type='usb' bus='0' port='2'/> + </redirdev> + <redirdev bus='usb' type='spicevmc'> + <alias name='redir1'/> + <address type='usb' bus='0' port='3'/> + </redirdev> + <memballoon model='virtio'> + <alias name='balloon0'/> + <address type='pci' domain='0x0000' bus='0x05' slot='0x00' function='0x0'/> + </memballoon> + <rng model='virtio'> + <backend model='random'>/dev/urandom</backend> + <alias name='rng0'/> + <address type='pci' domain='0x0000' bus='0x06' slot='0x00' function='0x0'/> + </rng> + </devices> + <seclabel type='dynamic' model='apparmor' relabel='yes'> + <label>libvirt-d62e0276-d474-452b-80f4-c951c39bcf74</label> + <imagelabel>libvirt-d62e0276-d474-452b-80f4-c951c39bcf74</imagelabel> + </seclabel> + <seclabel type='dynamic' model='dac' relabel='yes'> + <label>+109:+115</label> + <imagelabel>+109:+115</imagelabel> + </seclabel> +</domain> diff --git a/nix/modules/libvirtnix/b.xml b/nix/modules/libvirtnix/b.xml new file mode 100644 index 0000000..311e7d5 --- /dev/null +++ b/nix/modules/libvirtnix/b.xml @@ -0,0 +1,183 @@ +<domain type="kvm" id="1337"> + <name>blub</name> + <uuid>cafebabe-d474-452b-80f4-c951c39bcf74</uuid> + <metadata> + <libosinfo:libosinfo xmlns:libosinfo="https://libosinfo.org/xmlns/libvirt/domain/1.0"> + <libosinfo:os id="https://nixos.org/nixos/unknown"/> + </libosinfo:libosinfo> + </metadata> + <memory unit="KiB">2097152</memory> + <currentMemory unit="KiB">2097152</currentMemory> + <vcpu placement="static">3</vcpu> + <resource> + <partition>/machine</partition> + </resource> + <os> + <type arch="x86_64" machine="pc-q35-3.1">hvm</type> + <loader readonly="yes" pflash="pflash">/usr/share/OVMF/OVMF_CODE.fd</loader> + <nvram>/var/lib/libvirt/qemu/nvram/fileserver2_VARS.fd</nvram> + <type dev="hd"/> + </os> + <features> + <acpi/> + <apic/> + <vmport state="off"/> + </features> + <cpu mode="host-passthrough" check="none" migratable="on"/> + <clock offset="utc"> + <timer name="rtc" tickpolicy="catchup"/> + <timer name="pit" tickpolicy="delay"/> + <timer name="hpet" present="no"/> + </clock> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <pm> + <suspend-to-mem enabled="no"/> + <suspend-to-disk enabled="no"/> + </pm> + <devices> + <emulator>/usr/bin/qemu-system-x86_64</emulator> + <disk type="block" device="disk">block + <driver name="qemu" type="raw" cache="none" io="native" discard="unmap"/> + <source dev="/dev/vmstorage/fileserver2" index="3"/> + <backingStore/> + <target dev="vda" bus="virtio"/> + <alias name="virtio-disk0"/> + <address type="pci" domain="0x0000" bus="0x04" slot="0x00" function="0x0"/> + </disk> + <disk type="block" device="disk">block + <driver name="qemu" type="raw"/> + <source dev="/dev/mapper/storage1" index="2"/> + <backingStore/> + <target dev="vdb" bus="virtio"/> + <alias name="virtio-disk1"/> + <address type="pci" domain="0x0000" bus="0x08" slot="0x00" function="0x0"/> + </disk> + <disk type="block" device="disk">block + <driver name="qemu" type="raw"/> + <source dev="/dev/maper/storage2" index="1"/> + <backingStore/> + <target dev="vdc" bus="virtio"/> + <alias name="virtio-disk2"/> + <address type="pci" domain="0x0000" bus="0x09" slot="0x00" function="0x0"/> + </disk> + <controller type="usb" index="0" model="qemu-xhci" ports="15"> + <model name="qemu-xhci"/> + <alias name="usb"/> + <address type="pci" domain="0x0000" bus="0x02" slot="0x00" function="0x0"/> + </controller> + <controller type="pci" index="0" model="pci-root"> + <model name="pci-root"/> + <alias name="pcie.0"/> + </controller> + <controller type="pci" index="1" model="pcie-root-port"> + <model name="pcie-root-port"/> + <target chassis="1" port="0x10"/> + <alias name="pci.1"/> + <address type="pci" domain="0x0000" bus="0x00" slot="0x02" function="0x0"/> + </controller> + <controller type="pci" index="2" model="pcie-root-port"> + <model name="pcie-root-port"/> + <target chassis="2" port="0x11"/> + <alias name="pci.2"/> + <address type="pci" domain="0x0000" bus="0x00" slot="0x02" function="0x0"/> + </controller> + <controller type="pci" index="3" model="pcie-root-port"> + <model name="pcie-root-port"/> + <target chassis="3" port="0x12"/> + <alias name="pci.3"/> + <address type="pci" domain="0x0000" bus="0x00" slot="0x02" function="0x2"/> + </controller> + <controller type="pci" index="4" model="pcie-root-port"> + <model name="pcie-root-port"/> + <target chassis="4" port="0x13"/> + <alias name="pci.4"/> + <address type="pci" domain="0x0000" bus="0x00" slot="0x02" function="0x3"/> + </controller> + <controller type="pci" index="5" model="pcie-root-port"> + <model name="pcie-root-port"/> + <target chassis="5" port="0x14"/> + <alias name="pci.5"/> + <address type="pci" domain="0x0000" bus="0x00" slot="0x02" function="0x4"/> + </controller> + <controller type="pci" index="6" model="pcie-root-port"> + <model name="pcie-root-port"/> + <target chassis="6" port="0x15"/> + <alias name="pci.6"/> + <address type="pci" domain="0x0000" bus="0x00" slot="0x02" function="0x5"/> + </controller> + <controller type="pci" index="7" model="pcie-root-port"> + <model name="pcie-root-port"/> + <target chassis="7" port="0x16"/> + <alias name="pci.7"/> + <address type="pci" domain="0x0000" bus="0x00" slot="0x02" function="0x6"/> + </controller> + <controller type="pci" index="8" model="pcie-root-port"> + <model name="pcie-root-port"/> + <target chassis="8" port="0x17"/> + <alias name="pci.8"/> + <address type="pci" domain="0x0000" bus="0x00" slot="0x02" function="0x7"/> + </controller> + <controller type="pci" index="9" model="pcie-root-port"> + <model name="pcie-root-port"/> + <target chassis="9" port="0x18"/> + <alias name="pci.9"/> + <address type="pci" domain="0x0000" bus="0x00" slot="0x03" function="0x0"/> + </controller> + <controller type="pci" index="10" model="pcie-root-port"> + <model name="pcie-root-port"/> + <target chassis="10" port="0x19"/> + <alias name="pci.10"/> + <address type="pci" domain="0x0000" bus="0x00" slot="0x03" function="0x1"/> + </controller> + <controller type="pci" index="11" model="pcie-root-port"> + <model name="pcie-root-port"/> + <target chassis="11" port="0x1a"/> + <alias name="pci.11"/> + <address type="pci" domain="0x0000" bus="0x00" slot="0x03" function="0x2"/> + </controller> + <controller type="pci" index="12" model="pcie-root-port"> + <model name="pcie-root-port"/> + <target chassis="12" port="0x1b"/> + <alias name="pci.12"/> + <address type="pci" domain="0x0000" bus="0x00" slot="0x03" function="0x3"/> + </controller> + <controller type="pci" index="13" model="pcie-root-port"> + <model name="pcie-root-port"/> + <target chassis="13" port="0x1c"/> + <alias name="pci.13"/> + <address type="pci" domain="0x0000" bus="0x00" slot="0x03" function="0x4"/> + </controller> + <controller type="pci" index="14" model="pcie-root-port"> + <model name="pcie-root-port"/> + <target chassis="14" port="0x1d"/> + <alias name="pci.14"/> + <address type="pci" domain="0x0000" bus="0x00" slot="0x03" function="0x5"/> + </controller> + <controller type="pci" index="15" model="pcie-root-port"> + <model name="pcie-root-port"/> + <target chassis="15" port="0x1e"/> + <alias name="pci.15"/> + <address type="pci" domain="0x0000" bus="0x00" slot="0x03" function="0x6"/> + </controller> + <controller type="pci" index="16" model="pcie-root-port"> + <model name="pcie-root-port"/> + <alias name="pci.16"/> + <address type="pci" domain="0x0000" bus="0x07" slot="0x00" function="0x0"/> + </controller> + <controller type="sata" index="0"> + <alias name="ide"/> + <address type="pci" domain="0x0000" bus="0x00" slot="0x1f" function="0x02"/> + </controller> + <controller type="virtio-serial" index="0"> + <alias name="virtio-serial0"/> + <address type="pci" domain="0x0000" bus="0x03" slot="0x00" function="0x0"/> + </controller> + <controller type="scsi" index="0" model="lsilogic"> + <model name="lsilogic"/> + <alias name="scsi0"/> + <address type="pci" domain="0x0000" bus="0x10" slot="0x01" function="0x0"/> + </controller> + </devices> +</domain> diff --git a/nix/modules/libvirtnix/config.nix b/nix/modules/libvirtnix/config.nix new file mode 100644 index 0000000..5272ce2 --- /dev/null +++ b/nix/modules/libvirtnix/config.nix @@ -0,0 +1,583 @@ +{ + services.emile.libvirtnix = { + enable = true; + vm = { + "alan" = { + vm_type = "kvm"; + id = "1337"; + name = "blub"; + uuid = "cafebabe-d474-452b-80f4-c951c39bcf74"; + + metadata.libosinfo = "https://libosinfo.org/xmlns/libvirt/domain/1.0"; + metadata.libosinfo_os = "https://nixos.org/nixos/unknown"; + + memory.unit = "KiB"; + memory.value = 2097152; + + currentMemory.unit = "KiB"; + currentMemory.value = 2097152; + + vcpu.placement = "static"; + vcpu.count = 3; + + resource.partition = "/machine"; + + os = { + type = { + arch = "x86_64"; + machine = "pc-q35-3.1"; + value = "hvm"; + }; + + loader = { + readonly = "yes"; + type = "pflash"; + value = "/usr/share/OVMF/OVMF_CODE.fd"; + }; + + nvram.value = "/var/lib/libvirt/qemu/nvram/fileserver2_VARS.fd"; + + boot.dev = "hd"; + }; + + features = { + acpi = true; + apic = true; + vmport = { + state = "off"; + }; + }; + + cpu = { + mode = "host-passthrough"; + check = "none"; + migratable = "on"; + }; + + clock = { + offset = "utc"; + timer = [ + { + name = "rtc"; + tickpolicy = "catchup"; + } + { + name = "pit"; + tickpolicy = "delay"; + } + { + name = "hpet"; + present = "no"; + } + ]; + }; + + on_poweroff = "destroy"; + on_reboot = "restart"; + on_crash = "destroy"; + + pm = { + suspend-to-mem = "no"; + suspend-to-disk = "no"; + }; + + devices = { + emulators = [ + { + value = "/usr/bin/qemu-system-x86_64"; + } + ]; + + disks = [ + { + type = "block"; + device = "disk"; + driver = { + name = "qemu"; + type = "raw"; + cache = "none"; + io = "native"; + discard = "unmap"; + }; + source = { + dev = "/dev/vmstorage/fileserver2"; + index = 3; + }; + backingStore = true; + target = { + dev = "vda"; + bus = "virtio"; + }; + alias = { + name = "virtio-disk0"; + }; + address = { + type = "pci"; + domain = "0x0000"; + bus = "0x04"; + slot = "0x00"; + function = "0x0"; + }; + } + { + type = "block"; + device = "disk"; + driver = { + name = "qemu"; + type = "raw"; + }; + source = { + dev = "/dev/mapper/storage1"; + index = 2; + }; + backingStore = true; + target = { + dev = "vdb"; + bus = "virtio"; + }; + alias = { + name = "virtio-disk1"; + }; + address = { + type = "pci"; + domain = "0x0000"; + bus = "0x08"; + slot = "0x00"; + function = "0x0"; + }; + } + { + type = "block"; + device = "disk"; + driver = { + name = "qemu"; + type = "raw"; + }; + source = { + dev = "/dev/maper/storage2"; + index = 1; + }; + backingStore = true; + target = { + dev = "vdc"; + bus = "virtio"; + }; + alias = { + name = "virtio-disk2"; + }; + address = { + type = "pci"; + domain = "0x0000"; + bus = "0x09"; + slot = "0x00"; + function = "0x0"; + }; + } + ]; + + controllers = [ + { + type = "usb"; + index = 0; + model = "qemu-xhci"; + ports = 15; + alias = { + name = "usb"; + }; + address = { + type = "pci"; + domain = "0x0000"; + bus = "0x02"; + slot = "0x00"; + function = "0x0"; + }; + } + { + type = "pci"; + index = 0; + model = "pci-root"; + alias = { + name = "pcie.0"; + }; + } + { + type = "pci"; + index = 1; + model = "pcie-root-port"; + target = { + chassis = 1; + port = "0x10"; + }; + alias = { + name = "pci.1"; + }; + address = { + type = "pci"; + domain = "0x0000"; + bus = "0x00"; + slot = "0x02"; + function = "0x0"; + multifunction = "on"; + }; + } + { + type = "pci"; + index = 2; + model = "pcie-root-port"; + target = { + chassis = 2; + port = "0x11"; + }; + alias = { + name = "pci.2"; + }; + address = { + type = "pci"; + domain = "0x0000"; + bus = "0x00"; + slot = "0x02"; + function = "0x0"; + multifunction = "on"; + }; + } + { + type = "pci"; + index = 3; + model = "pcie-root-port"; + target = { + chassis = 3; + port = "0x12"; + }; + alias = { + name = "pci.3"; + }; + address = { + type = "pci"; + domain = "0x0000"; + bus = "0x00"; + slot = "0x02"; + function = "0x2"; + }; + } + { + type = "pci"; + index = 4; + model = "pcie-root-port"; + target = { + chassis = 4; + port = "0x13"; + }; + alias = { + name = "pci.4"; + }; + address = { + type = "pci"; + domain = "0x0000"; + bus = "0x00"; + slot = "0x02"; + function = "0x3"; + }; + } + { + type = "pci"; + index = 5; + model = "pcie-root-port"; + target = { + chassis = 5; + port = "0x14"; + }; + alias = { + name = "pci.5"; + }; + address = { + type = "pci"; + domain = "0x0000"; + bus = "0x00"; + slot = "0x02"; + function = "0x4"; + }; + } + { + type = "pci"; + index = 6; + model = "pcie-root-port"; + target = { + chassis = 6; + port = "0x15"; + }; + alias = { + name = "pci.6"; + }; + address = { + type = "pci"; + domain = "0x0000"; + bus = "0x00"; + slot = "0x02"; + function = "0x5"; + }; + } + { + type = "pci"; + index = 7; + model = "pcie-root-port"; + target = { + chassis = 7; + port = "0x16"; + }; + alias = { + name = "pci.7"; + }; + address = { + type = "pci"; + domain = "0x0000"; + bus = "0x00"; + slot = "0x02"; + function = "0x6"; + }; + } + { + type = "pci"; + index = 8; + model = "pcie-root-port"; + target = { + chassis = 8; + port = "0x17"; + }; + alias = { + name = "pci.8"; + }; + address = { + type = "pci"; + domain = "0x0000"; + bus = "0x00"; + slot = "0x02"; + function = "0x7"; + }; + } + { + type = "pci"; + index = 9; + model = "pcie-root-port"; + target = { + chassis = 9; + port = "0x18"; + }; + alias = { + name = "pci.9"; + }; + address = { + type = "pci"; + domain = "0x0000"; + bus = "0x00"; + slot = "0x03"; + function = "0x0"; + multifunction = "on"; + }; + } + { + type = "pci"; + index = 10; + model = "pcie-root-port"; + target = { + chassis = 10; + port = "0x19"; + }; + alias = { + name = "pci.10"; + }; + address = { + type = "pci"; + domain = "0x0000"; + bus = "0x00"; + slot = "0x03"; + function = "0x1"; + }; + } + { + type = "pci"; + index = 11; + model = "pcie-root-port"; + target = { + chassis = 11; + port = "0x1a"; + }; + alias = { + name = "pci.11"; + }; + address = { + type = "pci"; + domain = "0x0000"; + bus = "0x00"; + slot = "0x03"; + function = "0x2"; + }; + } + { + type = "pci"; + index = 12; + model = "pcie-root-port"; + target = { + chassis = 12; + port = "0x1b"; + }; + alias = { + name = "pci.12"; + }; + address = { + type = "pci"; + domain = "0x0000"; + bus = "0x00"; + slot = "0x03"; + function = "0x3"; + }; + } + { + type = "pci"; + index = 13; + model = "pcie-root-port"; + target = { + chassis = 13; + port = "0x1c"; + }; + alias = { + name = "pci.13"; + }; + address = { + type = "pci"; + domain = "0x0000"; + bus = "0x00"; + slot = "0x03"; + function = "0x4"; + }; + } + { + type = "pci"; + index = 14; + model = "pcie-root-port"; + target = { + chassis = 14; + port = "0x1d"; + }; + alias = { + name = "pci.14"; + }; + address = { + type = "pci"; + domain = "0x0000"; + bus = "0x00"; + slot = "0x03"; + function = "0x5"; + }; + } + { + type = "pci"; + index = 15; + model = "pcie-root-port"; + target = { + chassis = 15; + port = "0x1e"; + }; + alias = { + name = "pci.15"; + }; + address = { + type = "pci"; + domain = "0x0000"; + bus = "0x00"; + slot = "0x03"; + function = "0x6"; + }; + } + { + type = "pci"; + index = 16; + model = "pcie-root-port"; + alias = { + name = "pci.16"; + }; + address = { + type = "pci"; + domain = "0x0000"; + bus = "0x07"; + slot = "0x00"; + function = "0x0"; + }; + } + { + type = "sata"; + index = 0; + alias = { + name = "ide"; + }; + address = { + type = "pci"; + domain = "0x0000"; + bus = "0x00"; + slot = "0x1f"; + function = "0x02"; + }; + } + { + type = "virtio-serial"; + index = 0; + alias = { + name = "virtio-serial0"; + }; + address = { + type = "pci"; + domain = "0x0000"; + bus = "0x03"; + slot = "0x00"; + function = "0x0"; + }; + } + { + type = "scsi"; + index = 0; + model = "lsilogic"; + alias = { + name = "scsi0"; + }; + address = { + type = "pci"; + domain = "0x0000"; + bus = "0x10"; + slot = "0x01"; + function = "0x0"; + }; + } + ]; + interfaces = [ + { + type = "bridge"; + mac = { + address = "52:54:00:bf:ba:88"; + }; + source = { + network = "services"; + portid = "6c3a3512-d823-4521-9043-3a91a65682f5"; + bridge = "br7"; + }; + target = { + dev = "vnet2"; + }; + model = { + type = "virtio"; + }; + alias = { + name = "net0"; + }; + address = { + type = "pci"; + domain = "0x0000"; + bus = "0x01"; + slot = "0x00"; + function = "0x0"; + }; + } + ]; + }; + }; + }; + }; +} diff --git a/nix/modules/libvirtnix/domain.nix b/nix/modules/libvirtnix/domain.nix index a028c7d..d1a5b9c 100644 --- a/nix/modules/libvirtnix/domain.nix +++ b/nix/modules/libvirtnix/domain.nix @@ -1,701 +1,1443 @@ -{ pkgs, lib, ... }: - -{ - options = with lib; { - - # meta, this allows defining the package used for each vm individually, defaults should be sane - packages = mkOption { - type = types.submodule { - options = { - libvirt = mkPackageOption pkgs "libvirt" { }; - qemu = mkPackageOption pkgs "qemu" { }; - }; - }; +{ config, lib, ... }: + +let + mkTag = import ./xml.nix { inherit lib; }; + pkgs = import <nixpkgs> { }; + + stringOption = + { + default ? "", + }: + lib.mkOption { + type = lib.types.str; + default = "${default}"; }; - # attributs for the root `<domain ...>` node - type = mkOption { - type = types.enum [ - "xen" - "hvm" - "kvm" - "qemu" - "lxc" - ]; - default = "kvm"; - example = "qemu"; - description = '' - hypervisor used for running the domain - - allowed values are driver specific, if missing, plz send PR - - hvm since since 8.1.0 and QEMU 2.12 - ''; - }; - - id = mkOption { - type = types.int; - default = 0; - example = 42; - }; - - # General metadata - name = mkOption { - type = types.str; - example = "MyGuest"; - }; - - uuid = mkOption { - type = types.str; - example = "3e3fce45-4f53-4fa7-bb32-11f34168b82b"; - }; - - genid = mkOption { - type = types.str; - example = "43dc0cf8-809b-4adb-9bea-a9abb5f3d90e"; - }; - - title = mkOption { - type = types.str; - example = "A short description - title - of the domain"; + # shorthand for an option with an enum, no default value + enumOpt = + options: + lib.mkOption { + type = lib.types.nullOr (lib.types.enum options); + default = null; }; +in +{ + options = { + services.emile.libvirtnix = + let + + address = lib.mkOption { + default = null; + type = lib.types.nullOr ( + lib.types.submodule { + options = { + type = enumOpt [ "pci" ]; + domain = lib.mkOption { + type = lib.types.str; + example = "0x0000"; + }; + bus = lib.mkOption { + type = lib.types.str; + example = "0x4"; + }; + slot = lib.mkOption { + type = lib.types.str; + example = "0x00"; + }; + function = lib.mkOption { + type = lib.types.str; + example = "0x00"; + }; + multifunction = lib.mkOption { + type = lib.types.enum [ + "on" + "off" + ]; + example = "on"; + default = "off"; + }; + }; + } + ); + }; - description = mkOption { - type = types.str; - example = "Some human readable description"; - }; + interface = lib.mkOption { + type = lib.types.submodule { + options = { + type = enumOpt [ "bridge" ]; + mac = lib.mkOption { + type = lib.types.submodule { + options = { + address = lib.types.mkOption { + type = lib.types.str; + }; + }; + }; + }; + source = lib.mkOption { + type = lib.types.submodule { + options = { + network = lib.types.mkOption { + type = lib.types.str; + }; + portid = lib.types.mkOption { + type = lib.types.str; + }; + bridge = lib.types.mkOption { + type = lib.types.str; + }; + }; + }; + }; + target = lib.mkOption { + type = lib.types.submodule { + options = { + dev = lib.types.mkOption { + type = lib.types.str; + }; + }; + }; + }; + model = lib.mkOption { + type = lib.types.submodule { + options = { + type = lib.types.mkOption { + type = enumOpt [ "virtio" ]; + }; + }; + }; + }; + alias = lib.mkOption { + type = lib.types.submodule { + options = { + dev = lib.types.mkOption { + name = lib.types.str; + }; + }; + }; + }; + inherit address; + }; + }; + }; - metadata = mkOption { - type = types.str; - default = ""; - example = '' - <metadata> - <app1:foo xmlns:app1="http://app1.org/app1/">..</app1:foo> - <app2:bar xmlns:app2="http://app1.org/app2/">..</app2:bar> - </metadata> - ''; - }; - os = mkOption { - type = types.submodule { - options = { - firmware = mkOption { - type = types.enum [ - "bios" - "efi" + controller = lib.types.submodule { + options = { + type = enumOpt [ + "usb" + "pci" + "sata" + "virtio-serial" + "scsi" ]; - default = "efi"; - example = "bios"; + index = lib.mkOption { type = lib.types.int; }; + model = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + }; + ports = lib.mkOption { + type = lib.types.nullOr lib.types.int; + default = null; + }; + alias = lib.mkOption { + type = lib.types.submodule { + options = { + name = lib.mkOption { type = lib.types.str; }; + }; + }; + }; + target = lib.mkOption { + type = lib.types.nullOr ( + lib.types.submodule { + options = { + chassis = lib.mkOption { type = lib.types.int; }; + port = lib.mkOption { type = lib.types.str; }; + }; + } + ); + default = null; + }; + inherit address; }; - type = mkOption { - type = types.enum [ - "hvm" - "linux" - ]; - default = "hvm"; - example = "linux"; - }; - arch = mkOption { type = types.str; }; - machine = mkOption { type = types.str; }; - - # TODO(emile): features - # Search for the following... - # > When using firmware auto-selection there are different features enabled in the firmwares - # ... here: https://libvirt.org/formatdomain.html - # can't bother to implement this now - - # features = mkOption { - # type = types.submodule { - # options = { - # enabled = { - # type = types.enum [ "yes" "no" ]; - # }; - # name = {}; - # }; - # }; - # }; - - # such as: - # <loader readonly='yes' secure='yes' type='pflash'>/usr/share/OVMF/OVMF_CODE.fd</loader> - loader = mkOption { - type = types.submodule { - options = { - readonly = mkOption { - type = types.enum [ - "yes" - "no" - ]; + }; + + emulator = lib.types.submodule { + options = { + value = lib.mkOption { type = lib.types.str; }; + }; + }; + + disk = lib.types.submodule { + options = { + type = enumOpt [ "block" ]; + device = enumOpt [ "disk" ]; + driver = lib.mkOption { + type = lib.types.submodule { + options = { + name = lib.mkOption { type = lib.types.str; }; + type = enumOpt [ "raw" ]; + cache = enumOpt [ "none" ]; + io = enumOpt [ "native" ]; + discard = enumOpt [ "unmap" ]; }; - type = mkOption { - type = types.enum [ - "rom" - "pflash" - ]; + }; + }; + source = lib.mkOption { + type = lib.types.submodule { + options = { + dev = lib.mkOption { type = lib.types.str; }; + index = lib.mkOption { type = lib.types.int; }; + }; + }; + }; + backingStore = lib.mkOption { type = lib.types.bool; }; + target = lib.mkOption { + type = lib.types.submodule { + options = { + dev = lib.mkOption { type = lib.types.str; }; + bus = enumOpt [ "virtio" ]; + }; + }; + }; + alias = lib.mkOption { + type = lib.types.submodule { + options = { + name = lib.mkOption { type = lib.types.str; }; }; - secure = mkOption { - type = types.enum [ + }; + }; + inherit address; + }; + }; + + devices = lib.mkOption { + type = lib.types.submodule { + options = { + emulators = lib.mkOption { + type = lib.types.listOf emulator; + }; + disks = lib.mkOption { + type = lib.types.listOf disk; + }; + controllers = lib.mkOption { + type = lib.types.listOf controller; + }; + interfaces = lib.mkOption { + type = lib.types.listOf interface; + }; + }; + }; + }; + + pm = lib.mkOption { + type = lib.types.submodule { + options = { + suspend-to-mem = lib.mkOption { + type = lib.types.nullOr ( + lib.types.enum [ "yes" "no" - ]; - }; - stateless = mkOption { - type = types.enum [ + ] + ); + default = null; + example = "yes"; + }; + suspend-to-disk = lib.mkOption { + type = lib.types.nullOr ( + lib.types.enum [ "yes" "no" - ]; - }; - format = mkOption { - type = types.enum [ - "raw" - "qcow2" - ]; - }; - value = mkOption { - type = types.str; - example = "/usr/share/OVMF/OVMF_CODE.fd"; - }; + ] + ); + default = null; + example = "yes"; }; }; }; + }; - # <nvram type='network'> - # <source protocol='iscsi' name='iqn.2013-07.com.example:iscsi-nopool/0'> - # <host name='example.com' port='6000'/> - # <auth username='myname'> - # <secret type='iscsi' usage='mycluster_myname'/> - # </auth> - # </source> - # </nvram> - - # nvram = { - # type = "network"; - # source = { - # protocol = "iscsi"; - # name = "iqn.2013-07.com.example:iscsi-nopool/0"; - # }; - # }; - - nvram = mkOption { - type = types.submodule { - options = { - type = mkOption { - type = types.enum [ - "file" - "block" - "dir" - "network" - "volume" - "nvme" - "vhostuser" - "vhostvdpa" - ]; - default = ""; - }; + on_handle = lib.mkOption { + type = lib.types.enum [ + "destroy" + "restart" + "preserve" + "rename-restart" + ]; + }; - source = mkOption { - type = types.submodule { + on_poweroff = on_handle; + on_reboot = on_handle; + on_crash = on_handle; + + clock = lib.mkOption { + type = lib.types.submodule { + options = { + offset = lib.mkOption { + type = lib.types.str; + example = "utc"; + default = "utc"; + }; + timer = lib.mkOption { + type = lib.types.listOf ( + lib.types.submodule { options = { - # TODO(emile): figure out how to conditionally allow setting the options below - # if the type defined above has been set - - # if type == file - file = mkOption { type = types.str; }; - fdgroup = mkOption { type = types.str; }; - - # if type == block - dev = mkOption { type = types.str; }; - - # if type == dir - dir = mkOption { type = types.str; }; - - # if type == network - protocol = mkOption { - type = types.enum [ - "nbd" - "iscsi" - "rbd" - "sheepdog" - "gluster" - "vxhs" - "nfs" - "http" - "https" - "ftp" - "ftps" - "tftp" - "ssh" - ]; - }; - name = mkOption { type = types.str; }; - tls = mkOption { - type = types.enum [ - "yes" - "no" + name = lib.mkOption { + type = lib.types.enum [ + # "platform" (currently unsupported) + "hpet" # xen, qemu, lxc + "kvmclock" # qemu + "pit" # qemu + "rtc" # qemu, lxc + "tsc" # xen, qemu - since 3.2.0 + + # The hypervclock timer adds support for the reference time counter and the reference page for iTSC feature for guests running the Microsoft Windows operating system. + "hypervclock" # qemu - since 1.2.2 + + "armvtimer" # qemu - since 6.1.0 ]; + default = ""; + example = ""; }; - tlsHostname = mkOption { type = types.str; }; - query = mkOption { type = types.str; }; - - # if type == volume - pool = mkOption { type = types.str; }; - volume = mkOption { type = types.str; }; - mode = mkOption { - type = types.enum [ - "direct" - "host" + track = lib.mkOption { + # TODO(emile): Only valid for name="rtc" or name="platform". + type = lib.types.enum [ + "boot" + "guest" + "wall" + "realtime" ]; - default = "host"; - }; - - # if type == nvme - type = mkOption { - type = types.enum [ "pci" ]; - default = "pci"; - description = '' - When the type is `nvme`, only `pci` is supported - When the type is `vhostuser`, only `unix` is supported - - (I've got not clue how to model this is nix, it's essentially an attribute that is overloaded based on another value) - ''; + default = ""; + example = ""; }; - managed = mkOption { - type = types.enum [ - "yes" - "no" - ]; + tickpolicy = lib.mkOption { + type = lib.types.nullOr ( + lib.types.enum [ + "catchup" + "delay" + "merge" + "discard" + "catchup" + ] + ); + default = null; + example = ""; }; - namespace = mkOption { - type = types.int; - default = 0; + present = lib.mkOption { + type = lib.types.nullOr ( + lib.types.enum [ + "yes" + "no" + ] + ); + default = null; + example = ""; }; + }; + } + ); + example = [ + { + name = "rtc"; + tickpolicy = "catchup"; + } + { + name = "pit"; + tickpolicy = "delay"; + } + { + name = "hpet"; + present = "no"; + } + ]; + default = [ + { + name = "rtc"; + tickpolicy = "catchup"; + } + { + name = "pit"; + tickpolicy = "delay"; + } + { + name = "hpet"; + present = "no"; + } + ]; + }; + }; + }; + }; - # if type == vhostuser - # type = see the type in the nvme section above - path = mkOption { type = types.str; }; + cpu = lib.mkOption { + type = lib.types.submodule { + options = { + mode = lib.mkOption { + type = lib.types.str; + example = "host-passthrough"; + default = ""; + }; + check = lib.mkOption { + type = lib.types.str; + example = "none"; + default = ""; + }; + migratable = lib.mkOption { + type = lib.types.str; + example = "on"; + default = ""; + }; + }; + }; + }; - # if type == vhostvdpa - # dev = (defined above in the "type == block" section) + features = lib.mkOption { + type = lib.types.submodule { + options = { + acpi = lib.mkEnableOption "enable acpi"; + apic = lib.mkEnableOption "enable apic"; + + vmport = lib.mkOption { + type = lib.types.submodule { + options = { + state = lib.mkOption { + type = lib.types.str; + example = "off"; + default = ""; + }; + }; + }; + }; + }; + }; + }; - # if type == file - # if type == block - # if type == volume - seclabel = mkOption { type = types.str; }; + os_boot = lib.mkOption { + type = lib.types.submodule { + options = { + dev = lib.mkOption { + type = lib.types.str; + example = "hd"; + default = ""; + }; + }; + }; + }; - index = mkOption { - type = types.int; - default = 0; - }; + os_nvram = lib.mkOption { + type = lib.types.submodule { + options = { + value = lib.mkOption { + type = lib.types.str; + example = "/var/lib/libvirt/qemu/nvram/fileserver2_VARS.fd"; + default = ""; + }; + }; + }; + }; - # TODO(emile): implement checks here - # start here and scroll down a bit to the table - # https://libvirt.org/formatdomain.html#hard-drives-floppy-disks-cdroms - # if type == network - host = mkOption { - type = types.submodule { - options = { - name = mkOption { type = types.str; }; - port = mkOption { - type = types.int; - default = 0; - }; - transport = mkOption { type = types.str; }; - socket = mkOption { type = types.str; }; - - }; - }; - }; + os_loader = lib.mkOption { + type = lib.types.submodule { + options = { + readonly = lib.mkOption { + type = lib.types.str; + example = "yes"; + default = ""; + }; + type = lib.mkOption { + type = lib.types.str; + example = "pflash"; + default = ""; + }; + value = lib.mkOption { + type = lib.types.str; + example = "/usr/share/OVMF/OVMF_CODE.fd"; + default = ""; + }; + }; + }; + }; - snapshot = mkOption { - type = types.submodule { - options = { - name = mkOption { type = types.str; }; - }; - }; - }; + os_type = lib.mkOption { + type = lib.types.submodule { + options = { + arch = lib.mkOption { + type = lib.types.str; + example = "x86_64"; + default = ""; + }; + machine = lib.mkOption { + type = lib.types.str; + example = "pc-q35-3.1"; + default = ""; + }; + value = lib.mkOption { + type = lib.types.str; + example = "hvm"; + default = ""; + }; + }; + }; + }; - config = mkOption { - type = types.submodule { - options = { - file = mkOption { type = types.str; }; - }; - }; - }; + os = lib.mkOption { + description = "os"; + type = lib.types.submodule { + options = { + type = os_type; + loader = os_loader; + nvram = os_nvram; + boot = os_boot; + }; + }; + }; - # Since 3.9.0, the auth element is supported for a disk type "network" that is using a source element with the protocol attributes "rbd", "iscsi", or "ssh". - auth = mkOption { - type = types.submodule { - options = { - type = mkOption { - # type = types.enum [ "chap" ]; - # freeform, yet "chap" is one of the allowed options, I don't know others (yet) - type = types.str; - }; - username = mkOption { type = types.str; }; - - # https://libvirt.org/formatsecret.html - secret = mkOption { - type = types.submodule { - options = { - ephemeral = mkOption { - type = types.enum [ - "yes" - "no" - ]; - default = "no"; - }; - private = mkOption { - type = types.enum [ - "yes" - "no" - ]; - default = "no"; - }; - - uuid = types.submodule { - options = { - value = mkOption { - type = types.str; - default = ""; - }; - }; - }; - description = types.submodule { - options = { - value = mkOption { - type = types.str; - default = ""; - }; - }; - }; - - usage = types.submodule { - options = { - type = mkOption { - type = types.enum [ - "volume" - "ceph" - "iscsi" - "tls" - "vtpm" - ]; - default = ""; - }; - value = mkOption { - type = types.str; - default = ""; - }; - - name = mkOption { - type = types.submodule { - options = { - value = mkOption { type = types.str; }; - }; - }; - }; - - volume = mkOption { - type = types.submodule { - options = { - value = mkOption { type = types.str; }; - }; - }; - }; - - # when using the "iscsi" type - target = mkOption { - type = types.submodule { - options = { - value = mkOption { type = types.str; }; - }; - }; - }; - - }; - }; - - }; - }; - }; # end of secret - - }; - }; - }; # end of auth - - # https://libvirt.org/formatstorageencryption.html - encryption = mkOption { - type = types.submodule { - options = { - type = mkOption { type = types.str; }; - - # mandatory - format = mkOption { - type = types.enum [ - "default" - "qcow" - "luks" - "luks2" - "luks-any" - ]; - }; - - engine = mkOption { - type = types.enum [ - "qemu" - "librbd" - ]; - }; - - secrets = mkOption { - type = types.listOf (mkOption { - type = types.submodule { - options = { - - # mandatory - type = mkOption { type = types.enum [ "volume" ]; }; - - # uuid or usage - uuid = mkOption { type = types.str; }; - usage = mkOption { type = types.str; }; - - }; - }; - }); - }; # end of secrets - - cipher = mkOption { - type = types.submodule { - options = { - name = mkOption { - type = types.str; - example = "'aes', 'des', 'cast5', 'serpent', 'twofish', etc."; - }; - size = mkOption { - type = types.str; - example = "'256', '192', '128', etc."; - }; - mode = mkOption { - type = types.str; - example = "'cbc', 'xts', 'ecb', etc."; - }; - hash = mkOption { - type = types.str; - example = "'md5', 'sha1', 'sha256', etc."; - }; - }; - }; - }; # end of cipher - - ivgen = mkOption { - type = types.submodule { - options = { - name = mkOption { - type = types.str; - example = "'plain', 'plain64', 'essiv', etc."; - }; - hash = mkOption { - type = types.str; - example = "'md5', 'sha1', 'sha256'"; - }; - }; - }; - }; # end of ivygen - }; - }; - }; # end of encryption - - # TODO(emile): reservations - # Looking at the following, it seems like this can use the source element recursively - # Haven't looked into how to define recursive nix options yet... - # https://github.com/virt-manager/virt-manager/blob/5ddd3456a0ca9836a98fc6ca4f0b2eaab268bf47/tests/data/cli/compare/virt-install-many-devices.xml#L398-L400 - - # TODO(emile): initiator - - # Based on this here: - # https://github.com/virt-manager/virt-manager/blob/5ddd3456a0ca9836a98fc6ca4f0b2eaab268bf47/tests/data/cli/compare/virt-install-many-devices.xml#L440 - address = mkOption { - type = types.submodule { - options = { - domain = mkOption { type = types.int; }; - bus = mkOption { type = types.int; }; - slot = mkOption { type = types.int; }; - function = mkOption { type = types.int; }; - }; - }; - }; # end of address - - # TODO(emile): slices - # Didn't find any usage of it, why is there documentation for it then? - - ssl = mkOption { - type = types.submodule { - options = { - verify = mkOption { - type = types.enum [ - "yes" - "no" - ]; - }; - }; - }; - }; # end of ssl - - # TODO(emile): cookies for http and https - - readahead = mkOption { - type = types.submodule { - options = { - size = mkOption { type = types.int; }; - }; - }; - }; # end of readahead - - timeout = mkOption { - type = types.submodule { - options = { - seconds = mkOption { type = types.int; }; - }; - }; - }; # end of timeout - - identity = mkOption { - type = types.submodule { - options = { - user = mkOption { type = types.str; }; - group = mkOption { type = types.str; }; - - # if ssh - # required - username = mkOption { type = types.str; }; - - # one of these: - agentsock = mkOption { type = types.str; }; - keyfile = mkOption { type = types.str; }; - }; - }; - }; # end of identity - - # disk type "vhostuser" - reconnect = mkOption { - type = types.submodule { - options = { - # mandatory - enabled = mkOption { - type = types.enum [ - "yes" - "no" - ]; - }; - timeout = mkOption { - type = types.int; - description = "seconds"; - }; - - # optional for disk type network and protocol nbd - delay = mkOption { - type = types.int; - default = 0; - description = "seconds"; - }; - }; - }; - }; # end of reconnect - - # disk type "ssh" - knownHosts = mkOption { - type = types.submodule { - options = { - path = mkOption { type = types.str; }; - }; - }; - }; # end of knownHosts - - dataStore = mkOption { - type = types.submodule { - options = { - # TODO(emile): can accept the same types as a `source` element - type = mkOption { type = types.str; }; - - # TODO(emile): can accept format and source subelements - # this is (once again) recursive for the source, stil need to figure - # out how to handle this, just not now - }; - }; - }; # end of dataStore - - startupPolicy = mkOption { - type = types.enum [ - "mandatory" - "requisite" - "optional" - ]; - default = "mandatory"; - }; # end of startupPolicy - - backingStore = mkOption { - type = types.submodule { - options = { - type = mkOption { - # TODO(emile): can accept the same types as a `source` element - type = types.str; - }; - - index = mkOption { - # TODO(emile): figure out if this can just be an int - type = types.str; - }; - - # TODO(emile): can use the following sub elements: - # - format - # - source - # - backingStore - }; - }; - }; # end of backingStore - - mirror = mkOption { - type = types.submodule { - options = { - api = mkOption { - type = types.enum [ - "copy" - "active-commit" - ]; - }; - ready = mkOption { - type = types.enum [ - "yes" - "abort" - "pivot" - ]; - }; - # TODO(emile): can use the following sub elements: - # - type (disk types) - # - format - # - source - # - file - }; - }; - }; # end of mirror + resource = lib.mkOption { + description = "resource"; + type = lib.types.submodule { + options = { + partition = lib.mkOption { + type = lib.types.str; + example = "/machine"; + default = ""; + }; + }; + }; + }; - }; - }; - }; # end of source + vcpu = lib.mkOption { + description = "vcpu"; + type = lib.types.submodule { + options = { + placement = lib.mkOption { + # TODO(emile): fill up + type = lib.types.enum [ "static" ]; + example = "static"; + default = "static"; + }; + count = lib.mkOption { + type = lib.types.int; + example = 4; + default = 1; + }; + }; + }; + }; + + mem = lib.mkOption { + description = "memory"; + type = lib.types.submodule { + options = { + unit = lib.mkOption { + # TODO(emile): fill up + type = lib.types.enum [ + "KiB" + "MiB" + "GiB" + "TiB" + ]; + example = "KiB"; + default = "KiB"; + }; + value = lib.mkOption { + type = lib.types.int; + example = 2097152; + default = 1000; + }; + }; + }; + }; + memory = mem; + currentMemory = mem; + + metadata = lib.mkOption { + description = "metadata submodule"; + type = lib.types.submodule { + options = { + libosinfo = lib.mkOption { + type = lib.types.str; + example = "https://libosinfo.org/xmlns/libvirt/domain/1.0"; + default = ""; + }; + libosinfo_os = lib.mkOption { + type = lib.types.str; + example = "https://nixos.org/nixos/unknown"; + default = ""; }; }; - }; # end of nvram + }; + }; + vm = lib.types.submodule { + options = { + vm_type = stringOption { default = "kvm"; }; + id = stringOption { }; + name = stringOption { }; + uuid = stringOption { }; + + inherit + metadata + memory + currentMemory + vcpu + resource + os + features + cpu + clock + on_poweroff + on_reboot + on_crash + pm + devices + ; + }; + }; + in + { + enable = lib.mkEnableOption "Enable r2wars-web"; + + # Temporary output we write the domain to, in order to inspect the correctness of + # the generated xml + output.domain = lib.mkOption { type = lib.types.path; }; + + # An attrset of VMs + vm = lib.mkOption { + description = "VMs to define"; + type = lib.types.attrsOf vm; }; }; - }; + }; - memory = lib.mkOption { - type = lib.types.int; - default = 1024; - example = 2048; - description = '' - The amount of memory to provide to the VM - ''; - }; + config = lib.mkIf config.services.emile.libvirtnix.enable { + services.emile.libvirtnix = + let + vm = config.services.emile.libvirtnix.vm; + + # try this in a nix repl + # nix-repl> mkTag = import ./xml.nix { lib = (import <nixpkgs> {}).lib; } + # nix-repl> :p let func = (x: mkTag {name=x.variant;}); case = {"emulator" = func; "disk" = func;}; in map (x: case."${x.variant}" x) [ {variant = "emulator"; value = "asd";} {variant = "disk"; type = "block"; } ] + + emulator = + x: + mkTag { + name = "emulator"; + value = x.value; + }; + + interface = + x: + mkTag { + name = "interface"; + args = [ + ( + if x.type != null then + { + key = "type"; + val = x.type; + } + else + "" + ) + ]; + children = [ + # ( + # if x.mac != null then + # (mkTag { + # name = "mac"; + # args = [ + # { + # key = "address"; + # val = x.mac.address; + # } + # ]; + # closing = false; + # }) + # else + # "" + # ) + #( + # if x.source != null then + # (mkTag { + # name = "source"; + # args = [ + # { + # key = "network"; + # val = x.source.network; + # } + # { + # key = "portid"; + # val = x.source.portid; + # } + # { + # key = "bridge"; + # val = x.source.bridge; + # } + # ]; + # closing = false; + # }) + # else + # "" + #) + #( + # if x.target != null then + # (mkTag { + # name = "target"; + # args = [ + # { + # key = "dev"; + # val = x.target.dev; + # } + # ]; + # }) + # else + # "" + #) + #( + # if x.model != null then + # (mkTag { + # name = "model"; + # args = [ + # { + # key = "type"; + # val = x.model.type; + # } + # ]; + # }) + # else + # "" + #) + #( + # if x.alias!= null then + # (mkTag { + # name = "alias"; + # args = [ + # { + # key = "name"; + # val = x.alias.name; + # } + # ]; + # }) + # else + # "" + #) + #( + # if x.address != null then + # mkTag { + # name = "address"; + # args = [ + # ( + # if x.address.type != null then + # { + # key = "type"; + # val = x.address.type; + # } + # else + # "" + # ) + # { + # key = "domain"; + # val = x.address.domain; + # } + # { + # key = "bus"; + # val = x.address.bus; + # } + # { + # key = "slot"; + # val = x.address.slot; + # } + # { + # key = "function"; + # val = x.address.function; + # } + # ]; + # closing = false; + # } + # else + # "" + #) + ]; + }; + + controller = + x: + mkTag { + name = "controller"; + args = [ + ( + if x.type != null then + { + key = "type"; + val = x.type; + } + else + "" + ) + ( + if x.index != null then + { + key = "index"; + val = "${toString x.index}"; + } + else + "" + ) + ( + if x.model != null then + { + key = "model"; + val = x.model; + } + else + "" + ) + ( + if x.ports != null then + { + key = "ports"; + val = "${toString x.ports}"; + } + else + "" + ) + ]; + children = [ + # TODO(emile): figure out if the arg in controller is really the same as the + # one given in model. The configs I've got let it seem so + # <controller type="pci" index="1" model="pcie-root-port"> + # <model name="pcie-root-port"/> + ( + if x.model != null then + (mkTag { + name = "model"; + args = [ + { + key = "name"; + val = x.model; + } + ]; + closing = false; + }) + else + "" + ) + ( + if x.target != null then + (mkTag { + name = "target"; + args = [ + { + key = "chassis"; + val = "${toString x.target.chassis}"; + } + { + key = "port"; + val = x.target.port; + } + ]; + }) + else + "" + ) + (mkTag { + name = "alias"; + args = [ + ( + if x.alias.name != null then + { + key = "name"; + val = x.alias.name; + } + else + "" + ) + ]; + closing = false; + }) + + ( + if x.address != null then + mkTag { + name = "address"; + args = [ + ( + if x.address.type != null then + { + key = "type"; + val = x.address.type; + } + else + "" + ) + { + key = "domain"; + val = x.address.domain; + } + { + key = "bus"; + val = x.address.bus; + } + { + key = "slot"; + val = x.address.slot; + } + { + key = "function"; + val = x.address.function; + } + ]; + closing = false; + } + else + "" + ) + ]; + }; + + disk = + x: + mkTag { + name = "disk"; + args = [ + { + key = "type"; + val = x.type; + } + { + key = "device"; + val = x.device; + } + ]; + children = [ + (mkTag { + name = "driver"; + args = [ + ( + if x.driver.name != null then + { + key = "name"; + val = x.driver.name; + } + else + "" + ) + ( + if x.driver.type != null then + { + key = "type"; + val = x.driver.type; + } + else + "" + ) + ( + if x.driver.cache != null then + { + key = "cache"; + val = x.driver.cache; + } + else + "" + ) + ( + if x.driver.io != null then + { + key = "io"; + val = x.driver.io; + } + else + "" + ) + ( + if x.driver.discard != null then + { + key = "discard"; + val = x.driver.discard; + } + else + "" + ) + ]; + closing = false; + }) + (mkTag { + name = "source"; + args = [ + { + key = "dev"; + val = x.source.dev; + } + { + key = "index"; + val = "${toString x.source.index}"; + } + ]; + closing = false; + }) + ( + if x.backingStore == true then + mkTag { + name = "backingStore"; + closing = false; + } + else + "" + ) + (mkTag { + name = "target"; + args = [ + { + key = "dev"; + val = x.target.dev; + } + { + key = "bus"; + val = x.target.bus; + } + ]; + closing = false; + }) + (mkTag { + name = "alias"; + args = [ + { + key = "name"; + val = x.alias.name; + } + ]; + closing = false; + }) + (mkTag { + name = "address"; + args = [ + { + key = "type"; + val = x.address.type; + } + { + key = "domain"; + val = x.address.domain; + } + { + key = "bus"; + val = x.address.bus; + } + { + key = "slot"; + val = x.address.slot; + } + { + key = "function"; + val = x.address.function; + } + ]; + closing = false; + }) + ]; + value = x.type; + }; + + devices = + vm_name: + mkTag { + name = "devices"; + children = + map (x: emulator x) vm.${vm_name}.devices.emulators + ++ map (x: disk x) vm.${vm_name}.devices.disks + ++ map (x: controller x) vm.${vm_name}.devices.controllers + ++ map (x: interface x) vm.${vm_name}.devices.interfaces; + }; + + pm = + vm_name: + mkTag { + name = "pm"; + children = + let + suspend-to-mem = mkTag { + name = "suspend-to-mem"; + args = [ + { + key = "enabled"; + val = vm.${vm_name}.pm.suspend-to-mem; + } + ]; + closing = false; + }; + + suspend-to-disk = mkTag { + name = "suspend-to-disk"; + args = [ + { + key = "enabled"; + val = vm.${vm_name}.pm.suspend-to-disk; + } + ]; + closing = false; + }; + in + [ + suspend-to-mem + suspend-to-disk + ]; + }; + + on_handler = + { vm_name, tag }: + mkTag { + name = "${tag}"; + value = vm.${vm_name}.${tag}; + }; + + on_poweroff = + vm_name: + on_handler { + inherit vm_name; + tag = "on_poweroff"; + }; + on_reboot = + vm_name: + on_handler { + inherit vm_name; + tag = "on_reboot"; + }; + on_crash = + vm_name: + on_handler { + inherit vm_name; + tag = "on_crash"; + }; + + clock = + vm_name: + mkTag { + name = "clock"; + args = [ + { + key = "offset"; + val = vm.${vm_name}.clock.offset; + } + ]; + children = map ( + x: + mkTag { + name = "timer"; + args = + let + tickpolicy = + if x.tickpolicy != null then + { + key = "tickpolicy"; + val = x.tickpolicy; + } + else + { }; + + present = + if x.present != null then + { + key = "present"; + val = x.present; + } + else + { }; + in + [ + { + key = "name"; + val = x.name; + } + tickpolicy + present + ]; + } + ) vm.${vm_name}.clock.timer; + }; + + cpu = + vm_name: + mkTag { + name = "cpu"; + args = + let + mode = vm.${vm_name}.cpu.mode; + check = vm.${vm_name}.cpu.check; + migratable = vm.${vm_name}.cpu.migratable; + in + [ + ( + if (mode != null) then + { + key = "mode"; + val = mode; + } + else + "" + ) + ( + if (check != null) then + { + key = "check"; + val = check; + } + else + "" + ) + ( + if (migratable != null) then + { + key = "migratable"; + val = migratable; + } + else + "" + ) + ]; + closing = false; + }; + + features = + vm_name: + mkTag { + name = "features"; + children = + let + acpi = + vm_name: + mkTag { + name = "acpi"; + closing = false; + }; + apic = + vm_name: + mkTag { + name = "apic"; + closing = false; + }; + vmport = + vm_name: + mkTag { + name = "vmport"; + args = [ + { + key = "state"; + val = vm.${vm_name}.features.vmport.state; + } + ]; + closing = false; + }; + in + [ + (if (vm.${vm_name}.features.acpi != false) then (acpi vm_name) else "") + (if (vm.${vm_name}.features.apic != false) then (apic vm_name) else "") + (if (vm.${vm_name}.features.vmport != null) then (vmport vm_name) else "") + ]; + }; + + os = + vm_name: + mkTag { + name = "os"; + children = + let + os_type = + vm_name: + mkTag { + name = "type"; + args = [ + { + key = "arch"; + val = vm.${vm_name}.os.type.arch; + } + { + key = "machine"; + val = vm.${vm_name}.os.type.machine; + } + ]; + value = vm.${vm_name}.os.type.value; + }; + os_loader = + vm_name: + mkTag { + name = "loader"; + args = [ + { + key = "readonly"; + val = vm.${vm_name}.os.loader.readonly; + } + { + key = "pflash"; + val = vm.${vm_name}.os.loader.type; + } + ]; + value = vm.${vm_name}.os.loader.value; + }; + os_nvram = + vm_name: + mkTag { + name = "nvram"; + value = vm.${vm_name}.os.nvram.value; + }; + os_boot = + vm_name: + mkTag { + name = "type"; + args = [ + { + key = "dev"; + val = vm.${vm_name}.os.boot.dev; + } + ]; + closing = false; + }; + in + [ + (os_type vm_name) + (os_loader vm_name) + (os_nvram vm_name) + (os_boot vm_name) + ]; + }; + + resource = + vm_name: + mkTag { + name = "resource"; + children = [ + (mkTag { + name = "partition"; + value = "${toString vm.${vm_name}.resource.partition}"; + }) + ]; + }; + + vcpu = + vm_name: + mkTag { + name = "vcpu"; + args = [ + { + key = "placement"; + val = vm.${vm_name}.vcpu.placement; + } + ]; + value = "${toString vm.${vm_name}.vcpu.count}"; + }; + + currentMemory = + vm_name: + mkTag { + name = "currentMemory"; + args = [ + { + key = "unit"; + val = vm.${vm_name}.currentMemory.unit; + } + ]; + value = "${toString vm.${vm_name}.currentMemory.value}"; + }; + memory = + vm_name: + mkTag { + name = "memory"; + args = [ + { + key = "unit"; + val = vm.${vm_name}.memory.unit; + } + ]; + value = "${toString vm.${vm_name}.memory.value}"; + }; + + libosinfo_os = + vm_name: + mkTag { + name = "libosinfo:os"; + args = [ + { + key = "id"; + val = vm.${vm_name}.metadata.libosinfo_os; + } + ]; + closing = false; + }; + + libosinfo_libosinfo = + vm_name: + mkTag { + name = "libosinfo:libosinfo"; + args = [ + { + key = "xmlns:libosinfo"; + val = vm.${vm_name}.metadata.libosinfo; + } + ]; + children = [ + (libosinfo_os vm_name) + ]; + }; + + metadata = + vm_name: + mkTag { + name = "metadata"; + children = [ (libosinfo_libosinfo vm_name) ]; + }; + + uuid = + vm_name: + mkTag { + name = "uuid"; + value = vm.${vm_name}.uuid; + }; + + name = + vm_name: + mkTag { + name = "name"; + value = vm.${vm_name}.name; + }; + + # the vm_name has to be passed in, as we want to accesses the value for the given vm when + # generating the config + domain = + vm_name: + mkTag { + name = "domain"; + args = [ + { + key = "type"; + val = vm.${vm_name}.vm_type; + } + { + key = "id"; + val = vm.${vm_name}.id; + } + ]; + children = [ + (name vm_name) + (uuid vm_name) + (metadata vm_name) + (memory vm_name) + (currentMemory vm_name) + (vcpu vm_name) + (resource vm_name) + (os vm_name) + (features vm_name) + (cpu vm_name) + (clock vm_name) + (on_poweroff vm_name) + (on_reboot vm_name) + (on_crash vm_name) + (pm vm_name) + (devices vm_name) + ]; + }; + in + { + output.domain = pkgs.writeText "libvirt-domain-config.xml" (domain "alan"); + }; }; } diff --git a/nix/modules/libvirtnix/os.nix b/nix/modules/libvirtnix/os.nix new file mode 100644 index 0000000..41f36f3 --- /dev/null +++ b/nix/modules/libvirtnix/os.nix @@ -0,0 +1,119 @@ +{ lib, ... }: + +let + mkOption = lib.mkOption; + submodule = lib.types.submodule; + types = lib.types; + + os = { + firmware = mkOption { + type = types.enum [ + "bios" + "efi" + ]; + default = "efi"; + example = "bios"; + }; + + type = mkOption { + type = types.enum [ + "hvm" + "linux" + ]; + default = "hvm"; + example = "linux"; + }; + + arch = mkOption { type = types.str; }; + machine = mkOption { type = types.str; }; + + # TODO(emile): features + # Search for the following... + # > When using firmware auto-selection there are different features enabled in the firmwares + # ... here: https://libvirt.org/formatdomain.html + # can't bother to implement this now + + # features = mkOption { + # type = types.submodule { + # options = { + # enabled = { + # type = types.enum [ "yes" "no" ]; + # }; + # name = {}; + # }; + # }; + # }; + + # such as: + # <loader readonly='yes' secure='yes' type='pflash'>/usr/share/OVMF/OVMF_CODE.fd</loader> + loader = mkOption { + type = types.submodule { + options = { + readonly = mkOption { + type = types.enum [ + "yes" + "no" + ]; + }; + type = mkOption { + type = types.enum [ + "rom" + "pflash" + ]; + }; + secure = mkOption { + type = types.enum [ + "yes" + "no" + ]; + }; + stateless = mkOption { + type = types.enum [ + "yes" + "no" + ]; + }; + format = mkOption { + type = types.enum [ + "raw" + "qcow2" + ]; + }; + value = mkOption { + type = types.str; + example = "/usr/share/OVMF/OVMF_CODE.fd"; + }; + }; + }; + }; + + # <nvram type='network'> + # <source protocol='iscsi' name='iqn.2013-07.com.example:iscsi-nopool/0'> + # <host name='example.com' port='6000'/> + # <auth username='myname'> + # <secret type='iscsi' usage='mycluster_myname'/> + # </auth> + # </source> + # </nvram> + + # nvram = { + # type = "network"; + # source = { + # protocol = "iscsi"; + # name = "iqn.2013-07.com.example:iscsi-nopool/0"; + # }; + # }; + + }; +in +{ + options = { + os = mkOption { + type = submodule { + options = { + inherit (os) firmware type arch machine loader; + }; + }; + }; + }; +} diff --git a/nix/modules/libvirtnix/secret.nix b/nix/modules/libvirtnix/secret.nix new file mode 100644 index 0000000..b597174 --- /dev/null +++ b/nix/modules/libvirtnix/secret.nix @@ -0,0 +1,174 @@ +{ config, lib, ... }: + +# https://libvirt.org/formatsecret.html + +let + pkgs = import <nixpkgs> { }; + + mkOption = lib.mkOption; + submodule = lib.types.submodule; + types = lib.types; + enum = types.enum; + str = types.str; + + yesNoOption = mkOption { + type = enum [ + "yes" + "no" + ]; + default = "no"; + }; + # YesnoOption = mkOption { type = enum [ "yes" "no" ]; default = "yes"; }; + + # takes a few args and creats a valid xml tag pair out of it + # + # testTag = mkTag { + # name = "name"; + # args = [ + # { + # key = "arg1"; + # val = "arg1val"; + # } + # { + # key = "arg2"; + # val = "arg2val"; + # } + # ]; + # value = "qwe"; + # children = [ + # (mkTag { name = "nested"; args = []; value = "qwe"; children = [];}) + # ]; + # }; + # + # <name arg1=arg1val arg2=arg2val> + # value + # {children} + # </name> + mkTag = + { + name, # name of the tag to be used, such as `secret`, `description`, ... + args ? [ ], # args, [ { key="a"; val="b"; } { key="c"; val="d"; } ] + value ? "", # the value to place in the middle + children ? [ ], # the child elements + }: + let + args_str = + " " + lib.strings.concatStrings (lib.strings.intersperse " " (map (x: "${x.key}='${x.val}'") args)); + child_evaled = lib.strings.concatStrings children; + in + "<${name}${lib.optionalString (args != [ ]) args_str}>${value}${child_evaled}</${name}>"; + + strOption = + { + default ? "", + }: + mkOption { + type = str; + default = "${default}"; + }; + + usage = mkOption { + type = submodule { + options = { + type = mkOption { + type = enum [ + "volume" + "ceph" + "iscsi" + "tls" + "vtpm" + ]; + default = ""; + }; + + value = strOption { }; + + name = strOption { }; + volume = strOption { }; + target = strOption { }; + }; + }; + }; + + secret = { + inherit usage; + + ephemeral = yesNoOption; + private = yesNoOption; + + uuid = strOption { }; + description = strOption { }; + }; + +in +{ + options = { + services.emile.libvirtnix = { + enable = lib.mkEnableOption "Enable r2wars-web"; + + secret = mkOption { + type = submodule { + options = { + inherit (secret) + ephemeral + private + uuid + description + usage + ; + }; + }; + }; + + # output = mkOption { type = types.path; }; + }; + }; + + config = lib.mkIf config.services.emile.libvirtnix.enable { + services.emile.libvirtnix = + let + secret = mkTag { + name = "secret"; + args = [ + { + key = "ephemeral"; + val = config.services.emile.libvirtnix.secret.ephemeral; + } + { + key = "private"; + val = config.services.emile.libvirtnix.secret.private; + } + ]; + children = [ + (mkTag { + name = "description"; + value = "Super secret description"; + }) + (mkTag { + name = "uuid"; + value = "0a81f5b2-8403-7b23-c8d6-21ccc2f80d6f"; + }) + (mkTag { + name = "usage"; + args = [ + { + key = "type"; + val = "volume"; + } + ]; + children = [ + (mkTag { + name = "volume"; + value = "/var/lib/libvirt/images/kernel.img"; + }) + ]; + }) + ]; + }; + + in + { + # output = pkgs.writeText "libvirt-secret-config.xml" secret; + }; + }; +} diff --git a/nix/modules/libvirtnix/test.nix b/nix/modules/libvirtnix/test.nix new file mode 100644 index 0000000..8542b7e --- /dev/null +++ b/nix/modules/libvirtnix/test.nix @@ -0,0 +1,10 @@ +let + pkgs = import <nixpkgs> {}; +in + pkgs.lib.evalModules { + modules = [ + # ./secret.nix + ./domain.nix + ./config.nix + ]; + } diff --git a/nix/modules/libvirtnix/xml.nix b/nix/modules/libvirtnix/xml.nix new file mode 100644 index 0000000..10eefa3 --- /dev/null +++ b/nix/modules/libvirtnix/xml.nix @@ -0,0 +1,58 @@ +{ lib, ... }: + +# takes a few args and creats a valid xml tag pair out of it +# +# testTag = mkTag { +# name = "name"; +# args = [ +# { +# key = "arg1"; +# val = "arg1val"; +# } +# { +# key = "arg2"; +# val = "arg2val"; +# } +# ]; +# value = "qwe"; +# children = [ +# (mkTag { name = "nested"; args = []; value = "qwe"; children = [];}) +# ]; +# }; +# +# <name arg1=arg1val arg2=arg2val> +# value +# {children} +# </name> +{ + name, # name of the tag to be used, such as `secret`, `description`, ... + args ? [ ], # args, [ { key="a"; val="b"; } { key="c"; val="d"; } ] + value ? "", # the value to place in the middle + children ? [ ], # the child elements + closing ? true, # add a closing tag +}: +let + + # filter out all values missing a key + # this allows passing empty args such as `{}` which then get discarded + filteredArgs = (builtins.filter (x: x ? key) args); + + # convert the list of attr sets into a list of strings + mappedArgs = (map (x: "${x.key}='${x.val}'") filteredArgs); + + # [ "A" "B" "C" ] => [ "A" " " "B" " " "C" ] + spacedArgs = lib.strings.intersperse "" mappedArgs; + + # [ "A" " " "B" " " "C" ] => "A B C" + joinedArgs = lib.strings.concatStrings spacedArgs; + + # prefix the args with a space when inserting + args_str = lib.optionalString (filteredArgs != [ ]) (" " + joinedArgs); + + child_evaled = lib.strings.concatStrings children; + + cond = condition: value: if condition then value else ""; + + closingTag = if closing == true then "</${name}>" else ""; +in +"<${name}${args_str}${cond (closing == false) "/"}>${value}${child_evaled}${lib.optionalString (closing) closingTag}" diff --git a/nix/pkgs/aarch64-darwin.nix b/nix/pkgs/aarch64-darwin.nix index f5e8b60..78d5374 100644 --- a/nix/pkgs/aarch64-darwin.nix +++ b/nix/pkgs/aarch64-darwin.nix @@ -1,6 +1,7 @@ final: prev: { vokobe = final.callPackage ./vokobe { inherit (final) naersk; }; r2wars-web = final.callPackage ./r2wars-web { }; - remarvin = final.callPackage ./remarvin { }; - libc-database = final.callPackage ./libc-database {}; + # remarvin = final.callPackage ./remarvin { }; + # libc-database = final.callPackage ./libc-database {}; + # glibc-all-in-one = final.callPackage ./glibc-all-in-one { }; } diff --git a/nix/pkgs/glibc-all-in-one/default.nix b/nix/pkgs/glibc-all-in-one/default.nix new file mode 100644 index 0000000..896f91e --- /dev/null +++ b/nix/pkgs/glibc-all-in-one/default.nix @@ -0,0 +1,36 @@ +{ pkgs ? import <nixpkgs> {}, lib, fetchFromGitHub }: + +let + python = pkgs.python311.withPackages ( ps: with ps; [ requests ] ); +in pkgs.stdenv.mkDerivation rec { + name = "glibc-all-in-one"; + version = "master"; + + src = fetchFromGitHub { + owner = "fr0ster"; + repo = "glibc-all-in-one"; + rev = version; + sha256 = "sha256-vrh/ol56sNWTjGbwZ1Jrh+Lxz7aROvI6IbkJf/WliNE="; + }; + + buildPhase = ''''; + + installPhase = '' + mkdir -p $out/bin + cp build download extract $out/bin + cp update_list $out/bin/update_list_raw + + echo "${python}/bin/python3 $out/bin/update_list_raw" > $out/bin/update_list + chmod +x $out/bin/update_list + + mkdir -p $out/debs + mkdir -p $out/libs + ''; + + meta = { + description = ""; + homepage = "https://github.com/fr0ster/glibc-all-in-one"; + license = lib.licenses.mit; + maintainers = with lib.maintainers; [ hanemile ]; + }; + } diff --git a/nix/pkgs/libc-database/default.nix b/nix/pkgs/libc-database/default.nix index b13a167..0bc91b4 100644 --- a/nix/pkgs/libc-database/default.nix +++ b/nix/pkgs/libc-database/default.nix @@ -13,7 +13,7 @@ pkgs.stdenv.mkDerivation rec { owner = "niklasb"; repo = "libc-database"; rev = version; - sha256 = "Zysjhr76TenMarnoKo+M8DrTNbsnaXSoFZO1puPVoxU="; + sha256 = "sha256-Zysjhr76TenMarnoKo+M8DrTNbsnaXSoFZO1puPVoxU="; }; # not building, we just want to download the repo diff --git a/nix/pkgs/r2wars-web/default.nix b/nix/pkgs/r2wars-web/default.nix index 1d55de3..01b4a2d 100644 --- a/nix/pkgs/r2wars-web/default.nix +++ b/nix/pkgs/r2wars-web/default.nix @@ -18,7 +18,7 @@ pkgs.buildGoModule rec { vendorHash = null; - CGO_ENABLED = 0; + env.CGO_ENABLED = 0; subPackages = [ "src" ]; postInstall = '' diff --git a/nix/pkgs/x86_64-linux.nix b/nix/pkgs/x86_64-linux.nix index c186cc4..33f314b 100644 --- a/nix/pkgs/x86_64-linux.nix +++ b/nix/pkgs/x86_64-linux.nix @@ -2,5 +2,6 @@ final: prev: { vokobe = final.callPackage ./vokobe { inherit (final) naersk; }; r2wars-web = final.callPackage ./r2wars-web { }; remarvin = final.callPackage ./remarvin { }; + # glibc-all-in-one = final.callPackage ./glibc-all-in-one { }; # libc-database = final.callPackage ./libc-database {}; } diff --git a/nix/templates/ctf/flake.lock b/nix/templates/ctf/flake.lock new file mode 100644 index 0000000..b756d8d --- /dev/null +++ b/nix/templates/ctf/flake.lock @@ -0,0 +1,141 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1740603184, + "narHash": "sha256-t+VaahjQAWyA+Ctn2idyo1yxRIYpaDxMgHkgCNiMJa4=", + "ref": "nixos-24.11", + "rev": "f44bd8ca21e026135061a0a57dcf3d0775b67a49", + "shallow": true, + "type": "git", + "url": "ssh://git@github.com/nixos/nixpkgs.git" + }, + "original": { + "ref": "nixos-24.11", + "shallow": true, + "type": "git", + "url": "ssh://git@github.com/nixos/nixpkgs.git" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1736241350, + "narHash": "sha256-CHd7yhaDigUuJyDeX0SADbTM9FXfiWaeNyY34FL1wQU=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "8c9fd3e564728e90829ee7dbac6edc972971cd0f", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "pwndbg": { + "inputs": { + "nixpkgs": "nixpkgs_2", + "pyproject-build-systems": "pyproject-build-systems", + "pyproject-nix": "pyproject-nix", + "uv2nix": "uv2nix" + }, + "locked": { + "lastModified": 1740333626, + "narHash": "sha256-OcwULIZcWOC1FNGa0SNGtyMyfbwTsBj17LBPpGOZL78=", + "ref": "refs/heads/dev", + "rev": "ef090ebf5eb75713b1f97c3d9aa3d7be636b0c3a", + "revCount": 2284, + "type": "git", + "url": "ssh://git@github.com/pwndbg/pwndbg" + }, + "original": { + "type": "git", + "url": "ssh://git@github.com/pwndbg/pwndbg" + } + }, + "pyproject-build-systems": { + "inputs": { + "nixpkgs": [ + "pwndbg", + "nixpkgs" + ], + "pyproject-nix": [ + "pwndbg", + "pyproject-nix" + ], + "uv2nix": [ + "pwndbg", + "uv2nix" + ] + }, + "locked": { + "lastModified": 1737338290, + "narHash": "sha256-gnXlfFEHA+/jMH7R+7y3JxrI3WfOjgBhzzJNuFW70UU=", + "owner": "pyproject-nix", + "repo": "build-system-pkgs", + "rev": "e1487e5cefda0c7990bdd2e660bee20971680e45", + "type": "github" + }, + "original": { + "owner": "pyproject-nix", + "repo": "build-system-pkgs", + "type": "github" + } + }, + "pyproject-nix": { + "inputs": { + "nixpkgs": [ + "pwndbg", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1738204167, + "narHash": "sha256-J5M2sj3x4ocM93shScT/3Z4XWHZhwwW1NyQK+C+8Mys=", + "owner": "pyproject-nix", + "repo": "pyproject.nix", + "rev": "0d9f4b90cee1b5c5d6c142ef22de1e246e003ccc", + "type": "github" + }, + "original": { + "owner": "pyproject-nix", + "repo": "pyproject.nix", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs", + "pwndbg": "pwndbg" + } + }, + "uv2nix": { + "inputs": { + "nixpkgs": [ + "pwndbg", + "nixpkgs" + ], + "pyproject-nix": [ + "pwndbg", + "pyproject-nix" + ] + }, + "locked": { + "lastModified": 1738653454, + "narHash": "sha256-tAFX8mPZtZ+zVE/+bwPC3U+u5MxjpNP0gG24DG26jVs=", + "owner": "pyproject-nix", + "repo": "uv2nix", + "rev": "05b0c148bc53aebc6a906b6d0ac41dde5954cd47", + "type": "github" + }, + "original": { + "owner": "pyproject-nix", + "repo": "uv2nix", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/nix/templates/ctf/flake.nix b/nix/templates/ctf/flake.nix index da21034..f185bb7 100644 --- a/nix/templates/ctf/flake.nix +++ b/nix/templates/ctf/flake.nix @@ -1,14 +1,20 @@ { - description = "ctf"; + description = '' + One Flake to rule them all^W^Wcommon CTF problems, namely broken infa. + + Usage: + ; nix flake init -t git+https://github.com/hanemile/hefe\#ctf + ''; nixConfig.bash-prompt = "\[ctf\]; "; inputs = { - nixpkgs.url = "git+https://github.com/NixOS/nixpkgs"; + nixpkgs.url = "git+ssh://git@github.com/nixos/nixpkgs.git?shallow=1&ref=nixos-24.11"; + pwndbg.url = "git+ssh://git@github.com/pwndbg/pwndbg"; }; # Flake outputs outputs = - { nixpkgs, ... }: + { nixpkgs, pwndbg, ... }@inputs: let # Systems supported allSystems = [ @@ -21,30 +27,46 @@ # Helper to provide system-specific attributes nameValuePair = name: value: { inherit name value; }; genAttrs = names: f: builtins.listToAttrs (map (n: nameValuePair n (f n)) names); - forAllSystems = f: genAttrs allSystems (system: f { pkgs = import nixpkgs { inherit system; }; }); + forAllSystems = f: genAttrs allSystems (system: f { + pkgs = import nixpkgs { inherit system; }; + pwndbg = inputs.pwndbg.packages.${system}.default; + }); in { # Development environment output devShells = forAllSystems ( - { pkgs }: + { pkgs, pwndbg }: { default = - let - python = pkgs.python311; # Use Python 3.11 - in pkgs.mkShell { - packages = - with pkgs; - [ qemu ] - ++ [ - # Python plus helper tools - (python.withPackages ( - ps: with ps; [ - pwntools - pycryptodome - ] - )) - ]; + shellHook = '' + cat << EOF > solve.py + from pwn import * + + context.gdbinit="${pwndbg}/share/pwndbg/gdbinit.py" + + # exe = ELF("./a.out") + + p = remote("138.199.213.51", 31335) + #p = gdb.debug(exe.path, gdbscript='''' + # break main + # c + # '''') + + p.sendlineafter(b"> ", b"asd") + + p.interactive() + EOF + ''; + packages = [ + pkgs.gcc + pwndbg + (pkgs.python311.withPackages ( ps: with ps; [ + pwntools + pwndbg + pycryptodome + ])) + ]; }; } ); diff --git a/nix/templates/ctf/solve.py b/nix/templates/ctf/solve.py new file mode 100644 index 0000000..acc4a75 --- /dev/null +++ b/nix/templates/ctf/solve.py @@ -0,0 +1,15 @@ +from pwn import * + +context.gdbinit="/nix/store/jhvjf5drzzqq54xghzz94h0a6wsn1fs1-pwndbg/share/pwndbg/gdbinit.py" + +# exe = ELF("./a.out") + +p = remote("138.199.213.51", 31335) +#p = gdb.debug(exe.path, gdbscript=''' +# break main +# c +# ''') + +p.sendlineafter(b"> ", b"asd") + +p.interactive() |