Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

systemd service doesn't start if home-manager is not used as a nixosModule #52

Closed
maydayv7 opened this issue Oct 26, 2021 · 2 comments
Closed

Comments

@maydayv7
Copy link
Contributor

maydayv7 commented Oct 26, 2021

Hi, I'm pretty new to Nix, and am trying to use the impermanence home-manager module in my configuration (using Flakes), and I have some difficulties understanding how it all works. You can find my dotfiles here

Problem

Every single time the system boots, the home directory is regenerated (because of tmpfs), so all files in ~ are deleted (including the user systemd units to bind-mount the directories), and I need to re-apply the user configuration every time after login to get back all the files, which I hope isn't the desired method of operation. Also, I must run rm -rf ~ before re-applying, else it errors out with this message:

fuse: mountpoint is not empty
fuse: if you are sure this is safe, use the 'nonempty' mount option

and the home-manager configuration is not applied. It is also not possible for me to define a user systemd service to re-apply the configuration on login, so every boot requires a manual rebuild, which is not ideal.

Expected Behaviour

The directories (both the persisted ones and the ones linked using the home-manager option home.file are present on login, w/o any interference from the user.

Important Configuration Files

shortened, for decreasing complexity
flake.nix

{
  description = "My Reproducible, Hermetic, Derivational, Portable, Atomic, Multi-PC NixOS Dotfiles";
  
  ## Package Repositories ##
  inputs =
  {
    ## Main Repositories ##
    # NixOS Stable Release
    nixpkgs.url = "github:NixOS/nixpkgs?ref=nixos-21.05";
    
    # Home Manager
    home-manager =
    {
      url = "github:nix-community/home-manager?ref=release-21.05";
      inputs.nixpkgs.follows = "nixpkgs";
    };
    
    # Persistent State Handler
    impermanence.url = "github:nix-community/impermanence";
  };
  
  ## Output Configuration ##
  outputs = { self, ... } @ inputs:
  let
    ## Variable Declaration ##
    # Architecture
    system = "x86_64-linux";
    
    # NixOS Version
    version = "21.05";
    
    # Package Configuration
    pkgs = import inputs.nixpkgs
    {
      inherit system overlays;
      config =
      {
        allowUnfree = true;
        allowBroken = true;
      };
    };
    
    # System Libraries
    inherit (inputs.nixpkgs) lib;
    inherit (lib) attrValues;
    
    # Custom Functions
    util = import ./lib { inherit system lib inputs pkgs; };
    inherit (util) user;
    inherit (util) host;
  in
  {
    ## User Specific Configuration ##
    homeManagerConfigurations =
    {
      # User V7
      v7 = user.mkHome
      {
        username = "v7";
        roles = [ "dconf" "discord" "firefox" "git" "zsh" ];
        inherit version;
        persist = true;
      };
    };
    
    ## Device Specific Configuration ##
    nixosConfigurations =
    {
      # PC - Dell Inspiron 15 5000
      Vortex = host.mkHost
      {
        inherit version;
        name = "Vortex";
        kernelPackage = pkgs.linuxPackages_lqx;
        initrdMods = [ "xhci_pci" "thunderbolt" "nvme" "usb_storage" "sd_mod" ];
        kernelMods = [ "kvm-intel" ];
        kernelParams = [ "quiet" "splash" "rd.systemd.show_status=false" "rd.udev.log_level=3" "udev.log_priority=3" ];
        modprobe = "options kvm_intel nested=1";
        cpuCores = 8;
        filesystem = "btrfs";
        ssd = true;
        roles = [ "android" "fonts" "git" "gnome" "libvirt" "office" "security" "xorg" ];
        users =
        [
          {
            name = "v7";
            description = "V 7";
            groups = [ "wheel" "networkmanager" "audio" "video" "cdrom" "disk" "kvm" "libvirtd" "adbusers" ];
            uid = 1000;
            shell = pkgs.zsh;
          }
        ];
      };
    };
  };
}

filesystem module

{ config, lib, pkgs, ... }:
with lib;
with builtins;
let
  cfg = config.hardware.filesystem;
in rec
{
  options.hardware.filesystem = mkOption
  {
    type = types.enum [ "btrfs" "ext4" ];
    description = "This is the File System to be used by the disk";
    default = "ext4";
  };
  
  config =
  {
    # Partitions
    fileSystems = (if (cfg == "ext4")
    then
    ## EXT4 File System Configuration ##
    {
      "/" =
      {
        device = "/dev/disk/by-label/System";
        fsType = "ext4";
      };
    }
    else
    ## BTRFS Opt-in State File System Configuration ##
    {
      # ROOT Partition
      # Opt-in State with TMPFS
      "/" =
      {
        device = "tmpfs";
        fsType = "tmpfs";
        options = [ "defaults" "size=3G" "mode=755" ];
      };
      # BTRFS Partition
      "/mnt/btrfs" =
      {
        device = "/dev/disk/by-label/System";
        fsType = "btrfs";
        options = [ "subvolid=5" "compress=zstd" "autodefrag" "noatime" ];
      };
      # NIX Subvolume
      "/nix" =
      {
        device = "/dev/disk/by-label/System";
        fsType = "btrfs";
        options = [ "subvol=nix" ];
      };
      # PERSISTENT Subvolume
      "/persist" =
      {
        device = "/dev/disk/by-label/System";
        fsType = "btrfs";
        options = [ "subvol=persist" ];
        neededForBoot = true;
      };
    });
    
    # Persisted Files
    environment.persistence."/persist" = (mkIf (cfg == "btrfs")
    {
      directories =
      [
        "/etc/nixos"
        "/etc/NetworkManager/system-connections"
        "/var/log"
        "/var/lib/AccountsService"
        "/var/lib/bluetooth"
        "/var/lib/libvirt"
      ];
      
      files =
      [
        "/etc/machine-id"
      ];
    });
    
    # Snapshots
    services.btrbk = (mkIf (cfg == "btrfs")
    {
      instances =
      {
        persist =
        {
          onCalendar = "daily";
          settings =
          {
            timestamp_format = "long";
            snapshot_preserve = "31d";
            snapshot_preserve_min = "7d";
            volume."/mnt/btrfs".subvolume =
            {
              persist.snapshot_create = "always";
            };
          };
        };
      };
    });
  };
}

lib/user.nix

{ system, lib, inputs, pkgs, ... }:
with builtins;
{
  ## User Home Configuration ##
  mkHome = { username, roles, version, persist ? false, ... }:
  inputs.home-manager.lib.homeManagerConfiguration
  {
    inherit system username pkgs;
    stateVersion = version;
    homeDirectory = "/home/${username}";
    configuration =
    let
      # Module Import Function
      mkRole = name: import (../roles/user + "/${name}");
      user_roles = map (r: mkRole r) roles;
      
      # Extra Configuration Modules
      extra_modules =
      [
        ../modules/user
        "${inputs.impermanence}/home-manager.nix"
      ];
    in
    {
      _module.args =
      {
        inherit inputs pkgs username;
      };
            
      # Modulated Configuration Imports
      imports = shared_roles ++ user_roles ++ extra_modules;
            
      # Home Manager Configuration
      home.username = username;
      programs.home-manager.enable = true;
      systemd.user.startServices = true;
      home.persist = persist;
    };
  };
}

persist module

{ config, lib, pkgs, username, ... }:
with lib;
with builtins;
let
  cfg = config.home.persist;
in rec
{
  options.home.persist = mkOption
  {
    description = "Persist User Folders";
    type = types.bool;
    default = false;
  };
  
  config = mkIf (cfg == true)
  {
    # Persist files in Home Directory
    home.persistence."/persist/home/${username}" =
    {
      directories =
      [
        "Desktop"
        "Documents"
        "Downloads"
        "Music"
        "Pictures"
        "Templates"
        "Videos"
        ".config/dconf"
        ".config/discord"
        ".config/evolution"
        ".config/geary"
        ".config/gnome-boxes"
        ".config/goa-1.0"
        ".config/google-chrome"
        ".config/libvirt"
        ".config/Microsoft"
        ".local/share/evolution"
        ".local/share/gnome-boxes"
        ".local/share/keyrings"
        ".mozilla"
      ];
      
      files =
      [
        ".git-credentials"
        ".zsh_history"
      ];
      
      allowOther = false;
    };
  };
}

Command for applying user configuration (since, I'm using home-manager as a separate function instead of conventionally importing the module)

nix build /etc/nixos#homeManagerConfigurations.$USER.activationPackage
./result/activate
rm -rf ./result

Also, if this behaviour is irregular, please point out what is being done wrong in my configuration

@maydayv7 maydayv7 changed the title Understanding workflow for the home-managermodule Understanding workflow for the home-manager module Oct 26, 2021
@talyz
Copy link
Collaborator

talyz commented Oct 28, 2021

Hi! To automatically set up home-manager when using impermanence, it's easiest to use home-manager's NixOS module (it's in the nixos directory of the home-manager repo). It will activate the configuration in a systemd service on boot before you log in and therefore also solve the conflict problem you're seeing. I guess this info really should be in the readme.. Sorry about that!

@maydayv7
Copy link
Contributor Author

Okay, thanks a lot!

@maydayv7 maydayv7 changed the title Understanding workflow for the home-manager module Systemd service not starting use home-manager as a separate function Oct 29, 2021
@maydayv7 maydayv7 changed the title Systemd service not starting use home-manager as a separate function systemd service doesn't start if home-manager is not used as a nixosModule Jan 8, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants