Generic way to modify package's config files

Hello list,
new user here, with some documentations read and some partially
successful web searches looking for a theoretically simple thing: a,
possibly universal/generic, way to modify configs files.

The trigger of this question is that I discover in my new SSDs
based NixOS desktop setup “issue_discards = 0” in default lvm.conf
config without find a way to change it to 1. I easily found how
to support TRIM in LUKS (allowDiscards = true) but not in lvm…

I found a way to completely re-write lvm.conf via environment.etc
but I’d like something more simple like substituteInPlace, like
Ansible’s “lineinfile”, a simple “scripted” sed -i, etc.

My knowledge of Nix is limited to a quick read of the excellent
James Fisher’s “Nix by example” medium post [1] and my general
knowledge of NixOS is limited to a skim read of the manual and
few blog posts. Looking around I unsuccessfully tried to write
a simple derivation

packageOverrides = super: let self = super.pkgs; in {
        devicemapper = super.devicemapper.override {
            ...
        };
};

and to “create a nix-ified lvm2 config” grabbing code from sshd
and other derivation, again without success, my nix language
knowledge is still too limited…

This “trigger” is “specific” however I’m pretty sure sooner or
later I’ll find other config files to change without specific
pre-made nix support so the question of a “generic” solution.

Thanks and sorry for my poor English!

– Ingmar

[1]
Nix by example | by James Fisher | Medium

Hello!

a, possibly universal/generic, way to modify configs files.

Yeah, a habit to modify files (and config files too!) results into pain in NixOS, because there doesn’t exist

a general way to modify arbitrary files.

I discover in my new SSDs based NixOS desktop setup “issue_discards = 0” in default lvm.conf

config without find a way to change it to 1.

I don’t think NixOS sets this. I can’t find any explicit references to lvm.conf or issue_discards in NixOS source

Your /etc/lvm/lvm.conf may be created ad-hoc by some service.

I found a way to completely re-write lvm.conf via environment.etc
but I’d like something more simple like substituteInPlace, like

Ansible’s “lineinfile”, a simple “scripted” sed -i, etc.

Complete rewrite isn’t as bad as you think. Usually NixOS provides ways to override configs,

but sometimes fails (in this example lvm.conf is a nested structured thing, so usual merge semantics

don’t work here). You also can’t do the sed-like substitution in configuration.nix, because, due to nature

of module system, this will lead to infinite recursion error…

So here we have situation “all-or-nothing” (until somebody tries to codify lvm.conf using NixOS options).

Hi!
thanks for the super quick replay!

a, possibly universal/generic, way to modify configs files.
Yeah, a habit to modify files (and config files too!) results
into pain in NixOS, because there doesn’t exist a general
way to modify arbitrary files.
That’s bad for me… Being an admin I see NixOS like an OS with
IaC and Immutable Server and DevOps concepts builtin, it’s clear
that nix-ify anything is a (good) target but IMO it’s practically
utopic…

I don’t think NixOS sets this. I can’t find any explicit
references to lvm.conf or issue_discards in NixOS source
I think it’s created by LVM itself after the build phase, it’s
substantially fill of defaults…

Complete rewrite isn’t as bad as you think.
Well… I do not think it’s bad per se, only write around 115
lines in nixos config just to change a 0 to 1… Also I do not
expect changes in LVM ‘issue_discards = 1’ but some other part of
lvm conf may change and if I re-write the entire config I have
slightly more work to do keeping up with a thing that may even
change unnoticed and without any effect on my system.

So here we have situation “all-or-nothing” (until somebody
tries to codify lvm.conf using NixOS options).
Did you think It’s doable to codify it myself at this point?
Can you link some docs? For know I skim-read other derivation
that codify configs but found no docs on that topic.

Thanks again,
– Ingmar

Hi. Sorry, looks like Discourse truncated my previous email. I’ll repost it again:

But there is an escape hatch called “activationScripts”

https://nixos.org/nixos/options.html#activationscripts

Those scripts run during nixos-rebuild switch/test. For example, the whole /etc stuff is statically

generated on every nixos rebuild using such an activationScript:

https://github.com/NixOS/nixpkgs/blob/faac018630b8d3f89c633c1235ae649498c938e8/nixos/modules/system/etc/etc.nix#L153-L158

So you can setup your own activation script that will do all the necessary modifications:

system.activationScripts.my-lvm-fix = stringAfter [ "etc" ]
  ''
    echo "Fixing lvm.conf..."
    ${pkgs.sed}/bin/sed -i 's/issue_discards = 0/issue_discards = 1/' /etc/lvm/lvm.conf
  '';

Note that I haven’t tested this, and it can fail on readonly filesystems or when requested file doesn’t exist.

PPS: Also you may like my LVM trimmer service. Once a week it discards unused LVM space, which fstrim doesn’t touch.

systemd.services.periodic_fstrim = {

  startAt = "Sun 00:00:00";

  path = with pkgs; [ utillinux lvm2 ];

  script = ''

    echo TRIMming mounted filesystems...

    time fstrim -v --all

    echo TRIMming unused LVM space...

    lvm vgs -o vg_name,vg_free_count --noheadings | while read vgname free ; do

          vgdev="/dev/$vgname/discard"

          if [ -e "$vgdev" ]; then

               echo "Logical volume $vgdev does already exist." >&2

               echo "If it is just a leftover from a previous run then remove it with:" >&2

               echo "lvm lvremove -f \"$vgdev\"" >&2

          elif [ "$free" -gt 0 ]; then

               lvm lvcreate -l100%FREE -n discard "$vgname"

               cnt=5

               while [ $cnt -gt 0 ] && ! time lvm lvremove -f "$vgdev" ; do

                   sleep 1

                   cnt=$(($cnt-1))

               done

               if [ "$cnt" -eq 0 ]; then

                   echo "Could not remove logical volume $vgdev" >&2

               fi

          fi

    done

    echo TRIMming finished

  '';

};
1 Like

Hi!

looks like Discourse truncated my previous email. I’ll repost it again:
But there is an escape hatch called “activationScripts”
NixOS Search - Loading...
[…] it can fail on readonly filesystems […]
Thanks! This is a good step forward. I tried and it does not work
only exactly because lvm.conf is on a readonly fs (it physically
reside in /nix/store/lvm/etc/lvm.conf). Now I can copy it in /etc
and than modify in place, the sole remaining problem is how to
change LVM_SYSTEM_DIR in initrd so lvm pick the new one, trying to
figure out :slight_smile:

PPS: Also you may like my LVM trimmer service. Once a week it
discards unused LVM space, which fstrim doesn’t touch.
Thanks again! Already adopted it straight :slight_smile:

– Ingmar

Once you know where the file comes from, you can edit it with sed or other generic tools.

The following snippet works for me:

  environment.etc."lvm/lvm.conf".source = pkgs.runCommandNoCC "lvm.conf" {} ''
    sed ${pkgs.lvm2}/etc/lvm.conf -e "s/issue_discards = 0/issue_discards = 1/" > $out
  '';
$ nixos-rebuild build
$ grep "issue_discards =" ./result/etc/lvm/lvm.conf 
	issue_discards = 1
2 Likes