aboutsummaryrefslogtreecommitdiffstats
path: root/modules/by-name/ni/nixos-shell/shell_setup.nix
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--modules/by-name/ni/nixos-shell/shell_setup.nix191
1 files changed, 191 insertions, 0 deletions
diff --git a/modules/by-name/ni/nixos-shell/shell_setup.nix b/modules/by-name/ni/nixos-shell/shell_setup.nix
new file mode 100644
index 00000000..75af0678
--- /dev/null
+++ b/modules/by-name/ni/nixos-shell/shell_setup.nix
@@ -0,0 +1,191 @@
+# nixos-config - My current NixOS configuration
+#
+# Copyright (C) 2025 Jörg Thalheim and contributors
+# SPDX-License-Identifier: MIT
+#
+# This file is part of my nixos-config.
+#
+# You should have received a copy of the License along with this program.
+# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
+# This file contains the code that is used to setup the VM shell.
+{cfg}: {
+ lib,
+ config,
+ pkgs,
+ modulesPath,
+ ...
+}: let
+ mkVMDefault = lib.mkOverride 970;
+
+ env_file = "/tmp/shared/.env_variables";
+in {
+ imports = [
+ (modulesPath + "/profiles/qemu-guest.nix")
+ (modulesPath + "/virtualisation/qemu-vm.nix")
+ ];
+
+ config = {
+ assertions = [
+ {
+ assertion = builtins.elem cfg.user_name (lib.mapAttrsToList (name: value: name) config.users.users);
+ message = ''
+ Your user ${cfg.user_name} is not a recorded user in `config.users.users`.
+ Auto-login will not work.
+ '';
+ }
+ ];
+
+ # Lock root login.
+ users.users.root.hashedPassword = "";
+
+ # Remove unneeded clutter.
+ system.switch.enable = false;
+
+ virtualisation = {
+ # See https://wiki.qemu.org/Documentation/9psetup#Performance_Considerations.
+ # It is effectively a balance between ram and IO speed.
+ msize = let
+ kib = x: x * 1024;
+ in
+ mkVMDefault (kib 512);
+
+ graphics = mkVMDefault false;
+ memorySize = mkVMDefault 1700; # in MB
+ cores = mkVMDefault 16;
+
+ # Do not persist this VM.
+ diskImage = mkVMDefault null;
+
+ fileSystems =
+ lib.mapAttrs'
+ (_: mount: {
+ name = mount.target;
+
+ value = {
+ device = mount.tag;
+ fsType = "9p";
+ options =
+ [
+ "trans=virtio"
+ "version=9p2000.L"
+ "cache=${mount.cache_mode}"
+ "msize=${toString config.virtualisation.msize}"
+ ]
+ ++ lib.optionals mount.readOnly ["ro"];
+ };
+ })
+ cfg.mounts;
+
+ qemu = {
+ consoles = lib.mkIf (!config.virtualisation.graphics) ["tty0" "hvc0"];
+
+ options = let
+ mkMount = options: "-virtfs " + (builtins.concatStringsSep "," options);
+ in
+ lib.optionals (!config.virtualisation.graphics) [
+ "-serial null"
+ "-device virtio-serial"
+ "-chardev stdio,mux=on,id=char0,signal=off"
+ "-mon chardev=char0,mode=readline"
+ "-device virtconsole,chardev=char0,nr=0"
+ ]
+ ++ (lib.mapAttrsToList
+ (hostPath: mount:
+ mkMount [
+ "local"
+ "path=${builtins.toString hostPath}"
+ "security_model=none"
+ "readonly=on"
+ "mount_tag=${mount.tag}"
+ ])
+ cfg.mounts);
+ };
+ };
+
+ services = {
+ getty.helpLine = ''
+ If you are connect via serial console:
+ Type Ctrl-a c to switch to the qemu console
+ and `quit` to stop the VM.
+ '';
+
+ getty.autologinUser = cfg.user_name;
+ };
+
+ system.activationScripts = {
+ mountAdditionalPaths =
+ # bash
+ ''
+ PATH="${pkgs.jq}/bin:${pkgs.util-linux}/bin:$PATH"
+ export PATH
+
+ max_index="$(jq '.mount | keys | length' --raw-output ${env_file})"
+ index=0
+
+ mount --mkdir --type=tmpfs none "/.rw" --options=rw,relatime,mode=0755
+ while [ "$index" -lt "$max_index" ]; do
+ what="$(jq --argjson index "$index" '.mount | keys | map(.)[$index]' --raw-output ${env_file})"
+ where="$(jq --argjson index "$index" '.mount | map(.)[$index]' --raw-output ${env_file})"
+
+ mkdir "/.rw/$what"
+ mount --mkdir "$what" "/.ro/$what" \
+ --type=9p \
+ --options=ro,trans=virtio,version=9p2000.L,msize=${toString config.virtualisation.msize},x-systemd.requires=modprobe@9pnet_virtio.service
+
+ mkdir "/.rw/work-$what"
+ mount --mkdir --type=overlay overlay \
+ --options=rw,relatime,lowerdir="/.ro/$what",upperdir="/.rw/$what",workdir="/.rw/work-$what",uuid=on \
+ "/.ov/$what"
+
+ index="$((index + 1))"
+ done
+ '';
+ };
+
+ systemd.services.mountAdditionalPaths = {
+ after = ["local-fs.target"];
+ wantedBy = ["multi-user.target"];
+ path = [pkgs.jq];
+ script =
+ # bash
+ ''
+ max_index="$(jq '.mount | keys | length' --raw-output ${env_file})"
+ index=0
+
+ while [ "$index" -lt "$max_index" ]; do
+ what="$(jq --argjson index "$index" '.mount | keys | map(.)[$index]' --raw-output ${env_file})"
+ where="$(jq --argjson index "$index" '.mount | map(.)[$index]' --raw-output ${env_file})"
+
+ systemd-mount --type none "/.ov/$what" "$where" --options=bind
+
+ # HACK(@bpeetz): Nearly all of the paths are in $HOME anyways. So simply avoid
+ # the permission issue.
+ # Ideally, we would pass the original owners along with the mount. <2025-05-17>
+ chown --recursive soispha:users "/home/soispha"
+
+ index="$((index + 1))"
+ done
+ '';
+ };
+
+ environment = {
+ systemPackages = [
+ pkgs.jq
+ ];
+
+ sessionVariables = {
+ IN_NIXOS_SHELL = "true";
+ };
+
+ loginShellInit =
+ # bash
+ ''
+ cd "$(jq '.pwd' --raw-output ${env_file})"
+ export TERM="$(jq '.term' --raw-output ${env_file})"
+ export PATH="$(jq '.path' --raw-output ${env_file}):$PATH"
+ '';
+ };
+
+ networking.firewall.enable = mkVMDefault true;
+ };
+}