I’m old enough to remember the days before .d directories. My favorite would be the heyday of desktop UNIX workstations with software packages that would install themselves using creative applications of sed and awk on important system configuration files and break everything. I don’t miss it.
.d directories are great when one manages files with a configuration manager.
You just have to ensure that a file is present or absent to change the configuration. No need to “check if line is in file” and fight with regexes.
Also, you won’t stomp on the maintainer’s default configuration on the next apt/dnf upgrade. I wish more app supported.
The only drawback is complexity. For example, did you know that systemd supports foobar.service.d/... for “drop-in units”? This is great when you have a generic foobar@.service and you want to override some parts with email@example.com/. But when trying to understand what’s happening that can be tricky if you don’t use systemctl cat firstname.lastname@example.org.
systemctl cat email@example.com
IMO, the best alternative is to make your stuff do the right thing without user-specific configuration. You don’t need a program-managed ‘.d’ directory if the only changes from defaults are user-defined.
Well I did know about foo.service.d, but didn’t know about systemctl cat :)
Just noting that this is annoying to use with templating tools such as ansible, since removing the generated files does not remove the settings, contrary to whole-file templating.
I still greatly prefer this variant though, since I can characterize my configs as “what I changed from the defaults” rather than “the defaults as of version x.y.z when I first used this software”.
As I was saying, usually people use lineinfile in Ansible to achieve the same as .d directories for programs that don’t support them. However, you end up very quickly fighting with regexes, messing it up.
I greatly prefer the pattern you see in e.g. OpenBSD’s resolv.conf and resolv.conf.tail, or the more generic BSD rc.conf and rc.local. Of course, maybe I’m just a curmudgeon whining about configuration complexity in an operating system that is more complex just as it is more extensive in capability. But maybe both?
I also like the .local convention, but find it works well with local.d directories full of fragments too, and can make CM a little saner that way.
Both approaches beat the snot out of the old
####START MANAGED CONFIG FILE SECTION: Leave this line intact and don't modify anything between here and END
####END MANAGED CONFIG FILE SECTION
that you used to see all over the place, IMO.
I should clarify that I brought up OpenBSD because of their approach to cascading rules, then offered an irrelevant example. I probably should have used pf as my example instead of something specific to writing over the values a dhcp server might set for a client (though the pf example instead requires warning that you can create exceptions to how rules cascade).
In any case, the idea being that conflicting snippets are perfectly acceptable to scatter all over configuration files managed by applications so long as the only snippet that matters is the last rule that applies, and the file containing those can’t be touched by any of those aforementioned hooligans.
I greatly prefer this pattern, and in fact I’ve started using systemd mount units instead of lines directly in fstab on our machines out in the cluster. It’s much easier to let systemd generate a mount unit from the fstab and then use that unit as the source of truth so you can just replace entire files instead of messing around with sed and awk.
Any new program should use libUCL for its configuration. libUCL lets you merge structured configuration and define individual files that contain removal of keys from the defaults or add objects that override some but remove the others. You can also define priorities for the merging and many other useful things.
while it is a boon, I wouldn’t universally call it a success. In cases like udev, you have to know all the .rules files and their lexicographic order before writing your own custom rules. I found it confusing when I tried to automate running a backup when I inserted my USB attached harddrive and later learned some of the variables I expected to be set came from a rule at something like 55-*.rules. once I reordered my custom rule it magically started working.
This pattern would probably be better extended if more software gave you an ability to define a dependence on other configuration files or specific configuration key/value being defined.