diff --git a/README.md b/README.md new file mode 100644 index 0000000..c58f57e --- /dev/null +++ b/README.md @@ -0,0 +1,119 @@ +# Dynix — WIP modular dynamicism for NixOS systems + +Dynix is a prototype for modifying an append-only NixOS configuration, and dynamically + +## Running the tests + +There are currently 3 implemented dynamicism modules: `gotosocial`, `harmonia`, and `distccd`. +Each test uses the [NixOS test infrastructure](https://nixos.org/manual/nixos/unstable/#sec-nixos-tests) to: + +1. Setup a virtual machine running NixOS +2. Configure the VM's NixOS to run a given service, with certain settings +3. Verify that the running service is using those settings +4. Use Dynix to change a setting for that service +5. Verify that the running service is now using the new setting + +The tests themselves can be run with Nix. +To run the test for, e.g., Gotosocial, you can run: + +```bash +$ nix --experimental-features "nix-command flakes pipe-operator pipe-operators" build .#default.tests.gotosocial +``` + +The experimental [piping operator](https://github.com/NixOS/rfcs/pull/148) is currently used in Dynix, so you must enable the experimental feature `pipe-operator` for Lix or `pipe-operators` for CppNix (you can add both to cover both Nix implementations); flakes are used for locked inputs. + + +To run a test with fewer experimental features, and without locked inputs, you can use the old CLI: + +```bash +$ nix-build --experimental-features "pipe-operator pipe-operators" -A tests.gotosocial +``` + +All the tests at once can be run with: + +```bash +$ nix build --experimental-features "nix-command flakes pipe-operator pipe-operators" .#default.allTests +``` + +## Gotosocial + +This example, implemented in [./modules/dynamicism/gotosocial.nix](./modules/dynamicism/gotosocial.nix), is tested in [./tests/gotosocial](./tests/gotosocial). +The test sets up a VM using NixOS's `services.gotosocial` module with the following *static* [configuration](./tests/gotosocial/configuration.nix): + +```nix +{ + services.gotosocial = { + enable = true; + setupPostgresqlDB = true; + settings = { + application-name = "gotosocial-for-machine"; + host = "gotosocial-machine.local"; + }; + }; +} +``` + +The automated [test script](./tests/gotosocial/test-script.py): + +1. Asserts that that the above *static* configuration is in effect (by extracting the configuration from the running Gotosocial process) +2. Runs `dynix append "services.gotosocial.settings.application-name" "yay!"`, which modifies the append-only configuration file `/etc/nixos/dynamic.nix` in the VM filesystem +3. Runs the dynamic activation script built by `(import ).config.dynamicism.applyDynamicConfiguration { }`, which *applies* the dynamic configuration +4. Asserts that the dynamically configured `application-name` is in effect +5. Runs `nixos-rebuild switch` to re-apply the *static* configuration +6. Asserts that the dynamic configuration is *no longer* in effect, and we are back to the static configuration + +## Harmonia + +This example, implemented in [./modules/dynamicism/harmonia.nix](./modules/dynamicism/harmonia.nix), is tested in [./tests/harmonia](./tests/harmonia). +The test sets up a VM using NixOS's `services.harmonia` module with the following *static* [configuration](./tests/harmonia/configuration.nix) + +```nix +{ + services.harmonia = { + enable = true; + settings = { + workers = 4; + max_connection_rate = 256; + }; + }; +} +``` + +The VM [test script](./tests/harmonia/test-script.py): + +1. Asserts that the above *static* configuration is in effect (by extracting the configuration from the running Harmonia process) +2. Runs `dynix append "services.harmonia.settings.workers" 20`, to modify the append-only configuration file `/etc/nixos/dynamic.nix` in the VM filesystem +3. Runs the dynamic activation script built by `(import ).config.dynamicism.applyDynamicConfiguration { }`, to *apply* the dynamic configuration +4. Asserts that the dynamically configured `workers` is in effect +5. Runs `dynix append "services.harmonia.settings.max_connection_rate" 100` +6. Runs the dynamic activation script +7. Asserts that *both* `max_connection_rate` and `workers` dynamic values are in effect +8. Runs `nixos-rebuild switch` to re-apply the *static* configuration +9. Asserts that the dynamic configuration is *no longer* in effect, and we are back to the static configuration + +## Distccd + +This example, implemented in [./modules/dynamicism/distccd.nix](./modules/dynamicism/distccd.nix), is tested in [./tests/distccd](./tests/distccd). +The test sets up a VM using NixOS's `services.distccd` module with the following *static* [configuration](./tests/distccd/configuration.nix): + +```nix +{ + services.distccd = { + jobTimeout = 900; + maxJobs = 12; + logLevel = "warning"; + }; +} +``` + +The VM [test script](./tests/distccd/test-script.py): + +1. Asserts that the above *static* configuration is in effect (by extracting the configuration from the running Distccd process) +2. Runs `dynix append "services.distccd.maxJobs" 4`, to modify the append-only configuration file `/etc/nixos/dynamic.nix` in the VM filesystem +3. Runs the dynamic activation script built by `(import ).config.dynamicism.applyDynamicConfiguration { }`, to *apply* the dynamic configuration +4. Asserts that the dynamically configured `maxJobs` is in effect +5. Runs `dynix append "services.distccd.logLevel" "error"` +6. Runs the dynamic activation script +7. Asserts that *both* `maxJobs` and `logLevel` dynamic values are in effect +8. Runs `nixos-rebuild switch` to re-apply the *static* configuration +9. Asserts that the dynamic configuration is *no longer* in effect, and we are back to the static configuration.