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

[RFC 0078] System-agnostic configuration file generators #78

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

@7c6f434c
Copy link
Member

@7c6f434c 7c6f434c commented Oct 18, 2020

Extracting configuration file generation out of NixOS service modules in a more reusable way. Based on a discussion during NxCon 2020 Hackday.

@7c6f434c 7c6f434c changed the title Initial version of RFC proposal System-agnostic configuration file generators Oct 19, 2020
@7c6f434c
Copy link
Member Author

@7c6f434c 7c6f434c commented Oct 19, 2020

This is based on brainstorming during NixCon mainly with @svanderburg . Sander, do you accept to co-sign this as a co-author?

(Also thanks to aanderse jtojnar edolstra 0x4A6F LnL7 for discussion)

@edolstra edolstra changed the title System-agnostic configuration file generators [RFC 0078] System-agnostic configuration file generators Oct 19, 2020
@Mic92 Mic92 removed the status: new label Oct 22, 2020
@Mic92
Copy link
Member

@Mic92 Mic92 commented Oct 22, 2020

Anyone who wants to shepherd this RFC?

@nixos-discourse
Copy link

@nixos-discourse nixos-discourse commented Oct 23, 2020

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/why-isnt-more-of-home-manager-merged-into-nixpkgs/6096/29

@DamienCassou
Copy link

@DamienCassou DamienCassou commented Oct 23, 2020

I like this RFC, thank you!

@svanderburg
Copy link
Member

@svanderburg svanderburg commented Oct 23, 2020

@7c6f434c sure! RFC looks great so far. I'm going to read it in detail.

There is currently a lot of code duplication between
* NixOS
* home-manager
* nix-darwin
Copy link
Member

@Mic92 Mic92 Oct 23, 2020

Another target that would benefit from this are containers that need configuration independent from NixOS modules since they don't support systemd etc.

Copy link
Member Author

@7c6f434c 7c6f434c Oct 23, 2020

True; I am not sure what publically available codebase should be referenced as an example. My real use case is not even in the list and it is closer to what you say about containers; on the other hand, highly-visible existing parallel efforts are more convenient to discuss.

Copy link
Member

@aaronjanse aaronjanse Oct 25, 2020

Option generation is also useful for override, such as pkgs.rofi.override = { theme = <file>; }

Copy link
Member Author

@7c6f434c 7c6f434c Oct 25, 2020

True. But the packages are shared just fine already anyway, so not a strong motivation. Wrapper packages can already be done easily enough. If implementation turns out to be a huge success we might discuss this on a case by case basis whether to move stuff to the configuration file generator library, but let's get there first.

port = 1234;
nodeName = "localhost";
content = "Hello";
Copy link
Member

@Mic92 Mic92 Oct 23, 2020

Is this typed?

Copy link
Member Author

@7c6f434c 7c6f434c Oct 23, 2020

Yes, the type is provided next to the generator function.

Output:
```
{
"subdir/listen.conf" = {
Copy link
Member

@Mic92 Mic92 Oct 23, 2020

An example how this would be integrated into NixOS modules might be helpful.

Copy link
Member Author

@7c6f434c 7c6f434c Oct 23, 2020

Hmm, I am not sure it can be done easily without integrating an entire example from #42 and then extending it…

listenPort = "1234";
serverGreet = "I am localhost";
};
type = …;
Copy link
Member

@Mic92 Mic92 Oct 23, 2020

What is this type for?

Copy link
Member Author

@7c6f434c 7c6f434c Oct 23, 2020

Well, the output is intended for use with an RFCs#42 implementing NixOS module, to put into (in the simplest case) services.<service>.settings. In the simplest cases one can just have a static type for the settings entry, but I guess it doesn't hurt to repeat it here and to allow, when necessary, some variation (depending on configuration format input option, I guess)

That deserves introduction and propper reasoning in the detailed section, then?

Copy link
Member Author

@7c6f434c 7c6f434c Oct 24, 2020

Well, we promise to provide type specification and serialiser.

Copy link

@blaggacao blaggacao left a comment

A great motion to factor config management, define abstract interfaces and reduce the current bundling! ❤️ I hope some of my comments prompt you to do a clarifying fixup commit.

I'd also like to see a broader perspective on config management incorporated (my stated use case is just a top-of-my-head thought, nothing duly researched)

[summary]: #summary

Provide the configuration file generation functionality separately from NixOS
as a whole, and with scoped use of the module system.
Copy link

@blaggacao blaggacao Oct 23, 2020

What is a "scoped use of the module system"? Maybe affording another sentence for the message would do.

Copy link
Member Author

@7c6f434c 7c6f434c Oct 23, 2020

Scope in the sense of visibility… reworded

# Summary
[summary]: #summary

Provide the configuration file generation functionality separately from NixOS
Copy link

@blaggacao blaggacao Oct 23, 2020

I want to add, that in my use case, I would have an interest in that configuration management (as a shared resource) in nix would compound different APIs, like:

  • filesystem API (configuration files)
  • socket based APIs (fully dynamic service configuration)

→ It might still be useful to apply fully dynamic service configuration declaratively through nix.

Examples of such configuration APIs are:

  • network gear TCP endpoints that respond to yang or netconf
  • k8s APIs
  • ldap configuration (set of boostrapping data after handing off data management to the ldap specific UIs)

It might be out of scope for this particular RFC, though it might be worth including in future work.

Copy link
Member Author

@7c6f434c 7c6f434c Oct 23, 2020

I am not even sure it is in scope for future work!

Sure, that's a good idea in general, but this RFC is about sharing something that is already written now, and in a format that has seen some use by now. Inventing on-start configuration for things without persistent configuration is a good direction of work, but it is somewhat different type of work than described here.

You are right maybe "future work" is too normative. Would you like to add a "broader context" (or a better naming!) section at the end (as an after thought)?

functions implementing program configuration file generation. .As the design
uses a module system, putting configuration generators next to packages is also
not a perfect solution; also a configuration generator might end up generating
a set of config for a combination of packages.

As the design uses a module system, putting configuration generators next to packages is also
not a perfect solution; also a configuration generator might end up generating
a set of config for a combination of packages.

→ for terseness sake, that might entirely go into the alternative section?

Copy link
Member Author

@7c6f434c 7c6f434c Oct 23, 2020

Good point.

rfcs/0078-configuration-file-generators.md Outdated Show resolved Hide resolved
Abstract generation of configuration files with package-like flat arguments and
plain text file outputs.

This is not clear to me. Would that be something comparable to a templating approach with variable substitution?

Copy link
Member Author

@7c6f434c 7c6f434c Oct 23, 2020

What you say is a reasonable implementation of this abstract interface.

This RFC proposal builds upon RFCs#42 defining a configuration file abstraction
approach.

A subtree is established in the Nixpkgs repository serving as a library of
Suggested change
A subtree is established in the Nixpkgs repository serving as a library of
`NixOs/nixpkgs:./configs` is established serving as a library of

(or some ore appropriate folder name)

Copy link
Member Author

@7c6f434c 7c6f434c Oct 23, 2020

I do not think configs is a perfect name, but maybe it is good enough, so let's see if there are other opinions. In principle, that could be left to implementation step, should only lead to a little bit of bikeshedding

Agree, maybe you can change it to "folder subtree" to differenciate the token from "attribute subtree" below.

Copy link
Member Author

@7c6f434c 7c6f434c Oct 24, 2020

Hmmm. Indeed an identifier conflict, thanks. Reworded a bit.

Each such generator takes as an input a NixOS module system based «subtree»,
e.g. the values typically bound to `cfg` variable in typical modules.

NixOS module system based «subtree»

Does it take the subtree as input (as I understand it: it's path — since above sibtree referred to a path) or rather does it take the (lazily) evaluated attribute set corresponding to current config? (I'd induce the latter is what's intended here).

Copy link
Member Author

@7c6f434c 7c6f434c Oct 23, 2020

Well, the value of the subtree? A possibly nested attribute set, yes. But not to entire config, just to the service.

So here you could use "attribute subtree" to differenciate from "folder subtree" above. That would help to not get confused.

Copy link
Member Author

@7c6f434c 7c6f434c Oct 24, 2020

Hm, maybe indeed worth expanding.

file names of configuration files, and the values are attribute sets of RFCs#42
settings abstraction and serialiser.
Copy link

@blaggacao blaggacao Oct 23, 2020

Suggested change
file names of configuration files, and the values are attribute sets of RFCs#42
settings abstraction and serialiser.
file names of configuration files, and the values are attribute sets with one or several attributes conforming to RFCs#42 settings notation and other required metadata.

Copy link
Member Author

@7c6f434c 7c6f434c Oct 23, 2020

«well-known» is factually wrong here for some of the more interesting configuration file formats.

Oh, that was my interpretation of logSettings question on RFC42.

I changed the suggestion and eliminated well-known. It should be still a little clearer that way.

Along with the function the corresponding type specifications for input and
output modules are provided.
Copy link

@blaggacao blaggacao Oct 23, 2020

Suggested change
Along with the function the corresponding type specifications for input and
output modules are provided.
Along with the function definition, its corresponding input and output types are specified.

Move this up to where the detailed idea is presented. At this position, I got almost confused as if it was an afterthought.

Copy link
Member Author

@7c6f434c 7c6f434c Oct 23, 2020

It is still detailed-design section. We define the function, and what else is provided. In a sense, it is an afterthought, or supporting scaffolding.

Copy link

@blaggacao blaggacao Oct 24, 2020

With the removed non-terse interlude this notion is now close enough to it's object (the functions). I reformulated for conciseness sake.

"Provided along with the function." can mean many things (including providing when calling).

"specified along with the function definition" is much less open, though still not perfect.

Copy link
Member Author

@7c6f434c 7c6f434c Oct 24, 2020

Somewhat reshuffled everything in the paragraph.

approach.

A subtree is established in the Nixpkgs repository serving as a library of
functions implementing program configuration file generation. .As the design
Suggested change
functions implementing program configuration file generation. .As the design
functions implementing program configuration file generation. Alongside these functions their respective input and output types are specified. As the design

@ehmry
Copy link
Member

@ehmry ehmry commented Oct 24, 2020

I nominate myself as a shepherd. I don't have practical experience using Nix with other inits, but I am currently working on this.

@Profpatsch
Copy link
Member

@Profpatsch Profpatsch commented Oct 24, 2020

I’d be interested maybe helping out when it’s in progress. Maybe a flakes-based setup will help realizing this.

Define generic service abstraction for non-`systemd` systems, possibly with a
convertor from `systemd` units.

Consider some way of referring from package to related configuration file

Why? (what for) → you might want to clarify to improve intelligibility here.

Copy link
Member Author

@7c6f434c 7c6f434c Oct 24, 2020

Anyone interested in this future work item now is likely to be aware of the context like passthru.tests; those who are not familiar with that will wait anyway until some detailed work is started

Your response is a little bit enigmatic with regard to rhe matter of the question, but let's make some assumptions at the risk of requiring further clarification:

Do you consider here the possibility of moving service configuration still closer to the packaging itself?

If that is the case, the (new) proposed module system for packaging might come into play. And (very) early coordination with this RFC might benefit future development.

Copy link
Member Author

@7c6f434c 7c6f434c Oct 25, 2020

We'll see from feedback, but currently the RFC argues against moving configuration generators close to packages. However, we might consider developing a way of having some kind of cross-references available at evaluation time.

@06kellyjac
Copy link

@06kellyjac 06kellyjac commented Oct 26, 2020

https://github.com/svanderburg/nix-processmgmt/ is my favourite prototype so far for abstracting services

I know the example is listed as "a minimalistic silly example" but looking at it I have no idea how the input results in the output

@7c6f434c
Copy link
Member Author

@7c6f434c 7c6f434c commented Oct 26, 2020

@06kellyjac

agree on nix-processmgmt, but it looks like NixOS is headed towards more reuse of upstream units, and in an RFC aiming to factor something out of NixOS-only I did not want to go too far into things inapplicable to current direction of NixOS.

I think how the input gets converted into the output is an implementation detail? I expect whatever is described before implementation will get even the interface slightly changed once implemented; I do not think specifying internals of the function implementation is a good idea. I guess at first it should be similar to how #42 is prototyped now.

@06kellyjac
Copy link

@06kellyjac 06kellyjac commented Oct 26, 2020

@7c6f434c
I wouldn't really want to switch to a new way of defining services, only to then adopt a nix-processmgmt approach and need to do it all over again.

I'm unclear as to whether this RFC is focusing on just configuration files or also the definiton of services, both of which having different implementations across nixos, home-manager, nix-darwin as you've listed.
There are a lot of mentions of systemd in the RFC but I think the problem of configuration files and services having different implementations in different projects are two separate but related issues.
If the RFC's goal is "Extracting configuration file generation out of NixOS service modules in a more reusable way." then I think the RFC should avoid changing the actual systemd service much/at all and leave that to another RFC.


I get not wanting to define implementation details but in the output there are file names like listen.conf and content.conf. where are they defined? what determines that listen.conf is JSON and content.conf is INI? where is it defined that the input port then becomes listenPort for listen.conf?

With #42 I can see how things were before, a proposed structure, and a full example module.

@7c6f434c
Copy link
Member Author

@7c6f434c 7c6f434c commented Oct 26, 2020

@deliciouslytyped
Copy link

@deliciouslytyped deliciouslytyped commented Oct 31, 2020

As one data point for usecases; I recently started wanting to be able - in nix-on-droid - to start web servers for apps from f-droid that are just frontend clients. My understanding is Termux doesn't support systemd, or something,
I imagine standard sysv init scripts will work fine since they are just shell scripts.

...and then I ended up going doing a slight bit more research:
There are differences to linux: https://wiki.termux.com/wiki/Differences_from_Linux , probably most importantly no user separation, I'm not sure if you can get fake differring UIDs. Nix-on-droid also uses the proot functionality, which maybe does fake uid0: https://wiki.termux.com/wiki/PRoot

There appears to be a bit of infra for launching service scripts:
https://old.reddit.com/r/termux/comments/cs014w/termuxservices_new_package_to_control_daemons/
https://wiki.termux.com/wiki/Termux-services
https://wiki.termux.com/wiki/Termux:Boot

A bit of a todo/note to self:

  • if we ever get sufficient functionality to generate services, it would probably be nice to tell termux upstream about it / add it to their wiki

You can observe me naively running into idiosyncrasies of the proot environment in t184256/nix-on-droid#75 (comment) . IIRC the main issues were debugging difficulties and x11 needing patches from termux to handle setuid/setgid exiting with failure because proot refuses to emulate them - so nothing immediately relevant to service generation I think.

@blaggacao
Copy link

@blaggacao blaggacao commented Nov 18, 2020

Potential use case: ttacon/glorious#49 / numtide/devshell#47

@@ -0,0 +1,334 @@
---
Copy link
Member

@edolstra edolstra Nov 19, 2020

For some reason 0072-commonmark-docs.md is part of this RFC, could you remove it?

Copy link
Member Author

@7c6f434c 7c6f434c Nov 19, 2020

Squashed the edits until now. Seems to have helped.

@7c6f434c
Copy link
Member Author

@7c6f434c 7c6f434c commented Mar 26, 2021

Maybe it is indeed a good idea to review what we know now

https://www.when2meet.com/?11458739-kF6rB

@ehmry @edolstra @roberth @svanderburg and anyone who wants to bring some module system expertise to make the integration as smooth as possible

@Mic92
Copy link
Member

@Mic92 Mic92 commented Apr 6, 2021

@7c6f434c mhm. Looks like the shepherds are not following this issue close enough. Would it be maybe more efficient to contact them via email or IRC?

@7c6f434c
Copy link
Member Author

@7c6f434c 7c6f434c commented Apr 6, 2021

@ehmry
Copy link
Member

@ehmry ehmry commented Apr 6, 2021

Is this strictly about the RFC as it is written, or is this now also about generalizing the NixOS modules system? (I would advocate refactoring the module system to be adaptable to more than Linux+systemd)

@7c6f434c
Copy link
Member Author

@7c6f434c 7c6f434c commented Apr 6, 2021

@nbp
Copy link
Member

@nbp nbp commented Apr 6, 2021

What could be added at the module system level is a nicer way of importing a module as a submodule at as specified deep position. So NixOS/rfcs#42 like configuration file generator could be internally defined as a top-level thing, but imported into services.serviceName subtree. Than this RFC would encourage converting configuration file handling into this approach.

I tried this approach in the past for implementing web applications (php, wikimedia, …).

Converting namespace to submodules adds extra complexity, as submodules do not have the ability to reference the parent modules, and parent modules has to deal with merging the content provided by the submodules, which adds a lot of complexity.

One way to deal with this issue would be to add a new concept of aliases which are working across module boundaries. However this is not always desirable as this breaks the laziness at the submodule boundary. This can be a problem, as if any submodule is expected to set a parent option, then all submodule have to be evaluated to check if they do or do not set the parent module option. Aliases across module would have to be crafted carefully to avoid this issue.

@7c6f434c
Copy link
Member Author

@7c6f434c 7c6f434c commented Apr 6, 2021

@roberth
Copy link
Member

@roberth roberth commented Apr 6, 2021

Converting namespace to submodules adds extra complexity, as submodules do not have the ability to reference the parent modules

By default they don't, but the parent module can merge its own definitions into the submodule.

and parent modules has to deal with merging the content provided by the submodules, which adds a lot of complexity.

This complexity seems to be the complexity that is inherent to premise of the RFC; splitting config file generation from platform specifics.

One way to deal with this issue would be to add a new concept of aliases which are working across module boundaries. However this is not always desirable as this breaks the laziness at the submodule boundary. This can be a problem, as if any submodule is expected to set a parent option, then all submodule have to be evaluated to check if they do or do not set the parent module option. Aliases across module would have to be crafted carefully to avoid this issue.

This alias feature seems unnecessary and it would make modules harder to understand. It's probably a good thing for modules to state explicitly what they are setting. I that light, I also doubt whether adding syntax sugar for importing in a submodule is a good thing or not.

I think I've overcomplicated my earlier example a bit. The "import at namespace" feature was intended to replace liftedModule, but the imports line below should already do the trick, if I'm not mistaken.

  nixosSshModule = { config, ... }: {
    options.services.ssh = mkOption {
      type = types.submodule {
        imports = [ pureModule ];  # I guess we don't need liftedModule if we have this line?
        options.socketActivated = mkOption { default = true; /* etcetera */ };
      };
    };

@7c6f434c
Copy link
Member Author

@7c6f434c 7c6f434c commented Apr 6, 2021

@roberth
Copy link
Member

@roberth roberth commented Apr 6, 2021

Does that mean that the option set needs to be defined twice, once in the submodule and once in the parent module?

Most options are declared in the pure module. Definitions can come from either the user configuration, platform module or pure module.
When the platform module imports the pure module in its submodule, it reuses those options.

@7c6f434c
Copy link
Member Author

@7c6f434c 7c6f434c commented Apr 6, 2021

@roberth
Copy link
Member

@roberth roberth commented Apr 6, 2021

Most options are declared in the pure module.
What still needs to be declared in the platform module then?

Anything that isn't in scope for the pure module, like platform-specific options or perhaps some cross-service integration options. We'll know after a couple of refactored modules.

@7c6f434c
Copy link
Member Author

@7c6f434c 7c6f434c commented Apr 6, 2021

@nbp
Copy link
Member

@nbp nbp commented Apr 7, 2021

and parent modules has to deal with merging the content provided by the submodules, which adds a lot of complexity.

This complexity seems to be the complexity that is inherent to premise of the RFC; splitting config file generation from platform specifics.

You are right, I guess the complexity came from the fact that I was always attempting that on collections of submodules.

@edolstra
Copy link
Member

@edolstra edolstra commented Jun 24, 2021

Sorry @7c6f434c, I must have missed your attempt to set up a shepherd meeting. Should we try again? (CC @ehmry @edolstra @roberth @svanderburg)

@7c6f434c
Copy link
Member Author

@7c6f434c 7c6f434c commented Jun 24, 2021

Not only you, to be fair… (I am also still in doubt whether there is something to discuss that benefits from synchronicity)

@edolstra
Copy link
Member

@edolstra edolstra commented Jul 8, 2021

@7c6f434c Well, a meeting can be a good way to get the discussion unstuck and decide on steps forward. So I think it would be a good idea.

@7c6f434c
Copy link
Member Author

@7c6f434c 7c6f434c commented Jul 8, 2021

@edolstra
Copy link
Member

@edolstra edolstra commented Jul 22, 2021

@7c6f434c Okay, thanks. I've marked the RFC as "on hold". It can be moved back to under discussion at any time, of course, when you're ready.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment