-
-
Notifications
You must be signed in to change notification settings - Fork 162
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,167 @@ | ||||||||
--- | ||||||||
feature: configuration_file_generators | ||||||||
start-date: 2020-10-18 | ||||||||
author: Michael Raskin @7c6f434c | ||||||||
co-authors: (in-progress) | ||||||||
shepherd-team: @ehmry, @edolstra, @roberth | ||||||||
shepherd-leader: @edolstra | ||||||||
related-issues: (will contain links to implementation PRs) | ||||||||
--- | ||||||||
|
||||||||
# Summary | ||||||||
[summary]: #summary | ||||||||
|
||||||||
Provide the configuration file generation functionality separately from NixOS | ||||||||
as a whole, and using the module system without the global namespace. | ||||||||
|
||||||||
# Motivation | ||||||||
[motivation]: #motivation | ||||||||
|
||||||||
There is currently a lot of code duplication between | ||||||||
* NixOS | ||||||||
* home-manager | ||||||||
* nix-darwin | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Another target that would benefit from this are containers that need configuration independent from NixOS modules since they don't support systemd etc. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Option generation is also useful for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 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. |
||||||||
|
||||||||
and obviously growing code duplication with any effort running on below-Tier-2 | ||||||||
platforms. That leads both to effort duplication, and to confusion among users | ||||||||
using multiple Nix ecosystem tools for service generation, | ||||||||
|
||||||||
While fully resolving the problem is likely not fully compatible with the core | ||||||||
preferences of maintainers on each specific platform, we believe that config | ||||||||
file generation could be a shared resource just like Nixpkgs based on the | ||||||||
following properties: | ||||||||
* unlike, say, upstream `systemd` unit files we typically do not | ||||||||
reuse-and-override upstream configs, but generate our own (both in NixOS and | ||||||||
other service collections) | ||||||||
* the configs for a piece of software often have few dependencies on the | ||||||||
general environment | ||||||||
* it can be defined as a purely functional library, simplifying integration | ||||||||
|
||||||||
We aim to reduce duplication of effort and code while also having a high level | ||||||||
of inspection and tweaking possibilities without needing to patch module | ||||||||
source. An additional goal is to move the more package-like configuration file | ||||||||
generation code closer to the Nixpkgs model with scope/visibility rules. At | ||||||||
the same time we aim to avoid or minimise code in the NixOS subtree that | ||||||||
cannot be tested on NixOS. | ||||||||
Comment on lines
+42
to
+45
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not a goal but an implementation choice. |
||||||||
|
||||||||
# Detailed design | ||||||||
[design]: #detailed-design | ||||||||
|
||||||||
This RFC proposal builds upon RFCs#42 defining a configuration file abstraction | ||||||||
approach. | ||||||||
|
||||||||
A top-level directory is added to the Nixpkgs repository, and a library of | ||||||||
functions implementing program configuration file generation is created within | ||||||||
this directory. Each such generator takes as an input a NixOS module system | ||||||||
based attribute set «subtree», e.g. the attribute set typically bound to `cfg` | ||||||||
variable in the current NixOS service modules. | ||||||||
|
||||||||
The output of each such function is an attribute set. The keys are relative | ||||||||
file names of configuration files, and the values are attribute sets of RFCs#42 | ||||||||
settings abstraction and serialiser. | ||||||||
Comment on lines
+60
to
+61
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. «well-known» is factually wrong here for some of the more interesting configuration file formats. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, that was my interpretation of I changed the suggestion and eliminated well-known. It should be still a little clearer that way. |
||||||||
|
||||||||
The function is provided as a member of an attribute set, which also contains | ||||||||
the corresponding type specifications for input and output modules are defined. | ||||||||
The specifications for the input should be suitable for importing as a part of | ||||||||
the NixOS service module options. | ||||||||
|
||||||||
In some cases we only provide low-level overridable default configuration. In | ||||||||
this case the input may have the type that is always an empty attribute set, | ||||||||
`{}`. | ||||||||
|
||||||||
# Examples and Interactions | ||||||||
[examples-and-interactions]: #examples-and-interactions | ||||||||
|
||||||||
A minimalistic silly example is: | ||||||||
|
||||||||
Input: | ||||||||
``` | ||||||||
{ | ||||||||
port = 1234; | ||||||||
nodeName = "localhost"; | ||||||||
content = "Hello"; | ||||||||
Comment on lines
+80
to
+82
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this typed? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, the type is provided next to the generator function. |
||||||||
} | ||||||||
``` | ||||||||
|
||||||||
Output: | ||||||||
``` | ||||||||
{ | ||||||||
"subdir/listen.conf" = { | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. An example how this would be integrated into NixOS modules might be helpful. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, I am not sure it can be done easily without integrating an entire example from #42 and then extending it… |
||||||||
serialiser = toJSON; | ||||||||
settings = { | ||||||||
listenPort = "1234"; | ||||||||
serverGreet = "I am localhost"; | ||||||||
}; | ||||||||
type = …; | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is this type for? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, the output is intended for use with an RFCs#42 implementing NixOS module, to put into (in the simplest case) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That deserves introduction and propper reasoning in the detailed section, then? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, we promise to provide type specification and serialiser. |
||||||||
}; | ||||||||
"subdir/content.conf" = { | ||||||||
serialiser = toINI; | ||||||||
settings = { | ||||||||
greeting = { | ||||||||
greeter = "localhost"; | ||||||||
}; | ||||||||
payload = { | ||||||||
value = "I say to you: ‘Hello’"; | ||||||||
}; | ||||||||
}; | ||||||||
type = …; | ||||||||
}; | ||||||||
} | ||||||||
``` | ||||||||
|
||||||||
# Drawbacks | ||||||||
[drawbacks]: #drawbacks | ||||||||
|
||||||||
The proposed approach increases the spreading of the related code, from package | ||||||||
and service module to package and configuration generator and module. | ||||||||
|
||||||||
The proposed refactoring incurs a cost in terms of implementation effort across | ||||||||
NixOS, and likely to create a medium-term situation of partial migration. | ||||||||
|
||||||||
# Alternatives | ||||||||
[alternatives]: #alternatives | ||||||||
|
||||||||
Do nothing, continuing with the current code duplication. | ||||||||
|
||||||||
Same, but put configuration generators closer to packages. This would mean | ||||||||
widespread use of the module system inside `pkgs/`. There is also no guarantee | ||||||||
that all the configuration files describing interaction of multiple software | ||||||||
packages will have a clear choice of reference package. | ||||||||
|
||||||||
Introduce a guideline on making configuration files available to the module | ||||||||
system after generation (i.e. avoidance of only putting them in a `let` to add | ||||||||
a path reference inside some string; maybe with best practices on naming the | ||||||||
corresponding options). Does not help with scoping, still needs a non-trivial | ||||||||
amount of refactoring. Might make other desirable refactorings such as | ||||||||
multiple instances of a module marginally harder. | ||||||||
|
||||||||
A complete or partial merge of the module collections of the major currently | ||||||||
existing module system based code bases, with internal options for platform | ||||||||
specific implementation details. Unfortunately, this would force more coupling | ||||||||
Comment on lines
+139
to
+140
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This misses the point entirely. The dependencies are inverted, with the internal options serving the role of the function output, so the internal options are platform agnostic. |
||||||||
of the development cycle for the platform-specific parts. It also does not | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So does the function approach. |
||||||||
create a clean inspection/override point, and mixes the code with different | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just a matter of calling |
||||||||
platform requirements for testing. | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again, the common module isn't platform specific and can stand alone. The two approaches are isomorphic if it wasn't for the fact that going back to a simple function loses the option metadata and checking. inputs <-> normal options |
||||||||
|
||||||||
There also have been many solutions proposed based on a significant rework of | ||||||||
the module system. | ||||||||
|
||||||||
Abstract generation of configuration files with package-like flat arguments and | ||||||||
plain text file outputs. This approach will need less code as long as it we do | ||||||||
not want type checks, or ease of overriding values. | ||||||||
|
||||||||
Implement a complete service abstraction not tied to global system-wide | ||||||||
assumptions. | ||||||||
Comment on lines
+152
to
+153
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can understand the abstract motion, but am not capable of visualizing this alternative before my inner eye. Maybe a complementary statement can make it easier to reconstruct the argument behind it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A single statement would not be enough to do much good. A good description will overtake the rest of the RFC. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, maybe you want to define at least the system boundaries so it becomes clear what "system-wide" refers to? If you can rephrase I can re-try if it's — while applying utmost care while reading — intelligible (to me). |
||||||||
|
||||||||
# Unresolved questions | ||||||||
[unresolved]: #unresolved-questions | ||||||||
|
||||||||
Full proof-of-concept implementation for some module. | ||||||||
|
||||||||
# Future work | ||||||||
[future]: #future-work | ||||||||
|
||||||||
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 | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why? (what for) → you might want to clarify to improve intelligibility here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Anyone interested in this future work item now is likely to be aware of the context like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 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. |
||||||||
generators via `meta` or `passthru`, in a way similar to `passthru.tests`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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:
→ It might still be useful to apply fully dynamic service configuration declaratively through nix.
Examples of such configuration APIs are:
yang
ornetconf
It might be out of scope for this particular RFC, though it might be worth including in future work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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)?