11 Oct 2024 |
emily | but there are a variety of ways to phrase that right now & most of them aren't nice | 18:34:12 |
Arian | Feels like we want something like Context in React/SwiftUI | 18:34:18 |
emily | like I'd prefer services to expose the interface and the policy modules to consume that interface | 18:34:32 |
emily | rather than the interface being implicit as a result of asking modules to interfere with policy | 18:34:41 |
emily | which is bad layering in my view | 18:34:46 |
emily | (modules are global so this is purely theoretically-justified, but: it's also bad for encapsulation/security; in an ideal object-capability world a module setting up an OpenSSH daemon would have no ability to change your firewall settings) | 18:35:22 |
emily | (but the firewall settings would always be able to consume information from the OpenSSH service that it freely offers) | 18:35:34 |
emily | (this doesn't matter in NixOS as we have it, but drives my intuition for why I don't love the way we currently do it) | 18:35:53 |
raitobezarius | Liminix offers that separation and it doesn't spark joy neither | 20:00:32 |
raitobezarius | I feel like it boils down again to NixOS module being a first class citizen in the language level and introducing ocap in there | 20:01:07 |
emily | do you have an example of how Liminix does it? | 20:05:08 |
emily | (and agreed that we can't solve it without starting over but we can at least use the design principles to drive how we make new APIs) | 20:05:28 |
raitobezarius | In reply to @emilazy:matrix.org do you have an example of how Liminix does it? https://www.liminix.org/doc/configuration.html#writing-services | 20:55:07 |
emily | thanks. too global still :( | 21:07:07 |
Arian | At work we use functions that produce NixOS configs when we don't want global Behaviour. You use the nice type checking from the module system though... | 21:15:25 |
Arian | * At work we use functions that produce NixOS configs when we don't want globaly overridaeable Behaviour. You use the nice type checking from the module system though... | 21:15:38 |
Arian | Those modules can still set read only options for consumption by other modules | 21:15:53 |
Arian | But they can't be modified by other modules | 21:16:02 |
emily | services not being functions is the original sin of NixOS | 21:16:03 |
emily | if NixOS configurations were assembled more like Nix packages, everything would be better | 21:16:26 |
emily | instead everything is a global singleton that has access to everything else | 21:16:37 |
emily | it's absurd how many of the good properties we throw away for OS config | 21:16:48 |
Arian | So we just do `import ./myservice { foo = bar;} ` | 21:17:24 |
Arian | And then the service will expose foo as options.foo with readOnly true | 21:17:43 |
Arian | * And then the service will expose foo as options.myservice.foo with readOnly true | 21:17:58 |
Arian | basically this:
{ config, ... }: {
imports = [
(import ./hostname { name = "google.com"; })
(import ./service-a.nix { port = 8080; })
(import ./service-.bnix {
port = 9090;
logLevel = "debug";
})
(import ./firewall.nix {
allowedPorts = [ config.service-a.port config.service-b.port ];
})
(import ./nginx.nix {
virtualHosts = {
"service-a.${config.hostname.name}" = {
location = "/";
proxyPass = "http://localhost:${config.service-a.port}";
};
};
})
];
}
| 21:23:24 |
Arian | and we still use module options in some rare cases where there are cross-cutting concerns | 21:23:57 |
Arian | now service-b can not change settings of service-a for example | 21:27:29 |
emily | right | 21:29:12 |
emily | cool | 21:29:13 |