diff --git a/.gitignore b/.gitignore index 92e2d4b56..e1da1cb95 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ revision *.html ci/cache ci/packages +contrib/nix/flake.lock diff --git a/contrib/nix/README.md b/contrib/nix/README.md new file mode 100644 index 000000000..146545ca5 --- /dev/null +++ b/contrib/nix/README.md @@ -0,0 +1,78 @@ + +# Building CFEngine with nix + +## Common workflow + +You add a change in one of your repo. This workflow assumes you commit your changes first — `nix flake update` needs a stable commit to pin to (an uncommitted/dirty tree is handled differently; see the note at the end). + + +``` +victor-moene@victomoe:~/northern.tech/cfengine/core (cfengine-flake)$ touch a +victor-moene@victomoe:~/northern.tech/cfengine/core (cfengine-flake)$ git add a +victor-moene@victomoe:~/northern.tech/cfengine/core (cfengine-flake)$ git commit -m "a" +[cfengine-flake 150282eb4] a + 1 file changed, 0 insertions(+), 0 deletions(-) + create mode 100644 a +victor-moene@victomoe:~/northern.tech/cfengine/core (cfengine-flake)$ git status +On branch cfengine-flake +Your branch is ahead of 'origin/cfengine-flake' by 1 commit. + (use "git push" to publish your local commits) + +nothing to commit, working tree clean +``` + +Then you update buildscripts' flake.lock + +``` +victor-moene@victomoe:~/northern.tech/cfengine/buildscripts/contrib/nix (cfengine-buildscripts-flake)$ nix flake update +warning: Git tree '/home/victor-moene/northern.tech/cfengine/buildscripts' is dirty +warning: updating lock file "/home/victor-moene/northern.tech/cfengine/buildscripts/contrib/nix/flake.lock": +• Updated input 'core': + 'git+file:///home/victor-moene/northern.tech/cfengine/core?dir=contrib/nix&ref=refs/heads/cfengine-flake&rev=87d67cce8b4367d21139282256d23f7f407aca49&submodules=1' (2026-09-07) + → 'git+file:///home/victor-moene/northern.tech/cfengine/core?dir=contrib/nix&ref=refs/heads/cfengine-flake&rev=150282eb48c808a745abcdfee69cc0d409313a14&submodules=1' (2026-09-07) +• Updated input 'enterprise/core': + 'git+file:///home/victor-moene/northern.tech/cfengine/core?dir=contrib/nix&ref=refs/heads/cfengine-flake&rev=87d67cce8b4367d21139282256d23f7f407aca49&submodules=1' (2026-09-07) + → 'git+file:///home/victor-moene/northern.tech/cfengine/core?dir=contrib/nix&ref=refs/heads/cfengine-flake&rev=150282eb48c808a745abcdfee69cc0d409313a14&submodules=1' (2026-09-07) +• Updated input 'mission-portal/nova/core': + 'git+file:///home/victor-moene/northern.tech/cfengine/core?dir=contrib/nix&ref=refs/heads/cfengine-flake&rev=87d67cce8b4367d21139282256d23f7f407aca49&submodules=1' (2026-09-07) + → 'git+file:///home/victor-moene/northern.tech/cfengine/core?dir=contrib/nix&ref=refs/heads/cfengine-flake&rev=150282eb48c808a745abcdfee69cc0d409313a14&submodules=1' (2026-09-07) +• Updated input 'mission-portal/nova/enterprise/core': + 'git+file:///home/victor-moene/northern.tech/cfengine/core?dir=contrib/nix&ref=refs/heads/cfengine-flake&rev=87d67cce8b4367d21139282256d23f7f407aca49&submodules=1' (2026-09-07) + → 'git+file:///home/victor-moene/northern.tech/cfengine/core?dir=contrib/nix&ref=refs/heads/cfengine-flake&rev=150282eb48c808a745abcdfee69cc0d409313a14&submodules=1' (2026-09-07) +• Updated input 'nova/core': + 'git+file:///home/victor-moene/northern.tech/cfengine/core?dir=contrib/nix&ref=refs/heads/cfengine-flake&rev=87d67cce8b4367d21139282256d23f7f407aca49&submodules=1' (2026-09-07) + → 'git+file:///home/victor-moene/northern.tech/cfengine/core?dir=contrib/nix&ref=refs/heads/cfengine-flake&rev=150282eb48c808a745abcdfee69cc0d409313a14&submodules=1' (2026-09-07) +• Updated input 'nova/enterprise/core': + 'git+file:///home/victor-moene/northern.tech/cfengine/core?dir=contrib/nix&ref=refs/heads/cfengine-flake&rev=87d67cce8b4367d21139282256d23f7f407aca49&submodules=1' (2026-09-07) + → 'git+file:///home/victor-moene/northern.tech/cfengine/core?dir=contrib/nix&ref=refs/heads/cfengine-flake&rev=150282eb48c808a745abcdfee69cc0d409313a14&submodules=1' (2026-09-07) +``` + +In short, the flake.lock is a file pinning all the inputs of the final derivation. + +Now you can build with the newest commit: + +``` +victor-moene@victomoe:~/northern.tech/cfengine/buildscripts/contrib/nix (cfengine-buildscripts-flake)$ nix build .#community-client -o myoutput +``` + +You can choose to build `community-client`, `enterprise-client` or `enterprise-hub`. These are listed in `buildscripts/contrib/nix/flake.nix` + +Where myoutput is a symlink with the compiled binaries. For exemple, from a previous build, I got: + +``` +victor-moene@victomoe:~/northern.tech/cfengine/buildscripts/contrib/nix (cfengine-buildscripts-flake)$ ls myoutput +bin cgi-bin conf error etc htdocs icons lib logs masterfiles master_software_updates modules php sbin share var +``` + +CFEngine expects some level of permissions on its source files, so you might have to copy the output somewhere else. + +## Sharing builds + +To share fully reproducible builds, simply share the `flake.lock` file, and run nix build. This assumes you have the same commits in the repos. + +## Garbage collection + +Nix stores every derivation as a unique package in the Nix store, so disk usage can grow quickly. Run `nix-collect-garbage` (or `nix-collect-garbage -d` to also remove old generations) from time to time to reclaim space. + +Note: any `-o` result symlink (e.g. `myoutput`) acts as a garbage-collection root — as long as it exists, Nix won't clean up the store paths it points to. Remove old output symlinks you no longer need before running garbage collection, or point `-o` at `/tmp` so they get cleaned up automatically. + diff --git a/contrib/nix/community-client.nix b/contrib/nix/community-client.nix new file mode 100644 index 000000000..27b4c6436 --- /dev/null +++ b/contrib/nix/community-client.nix @@ -0,0 +1,6 @@ +{ symlinkJoin, core, masterfiles }: + +symlinkJoin { + name = "cfengine-community-client"; + paths = [ core masterfiles ]; +} diff --git a/contrib/nix/enterprise-client.nix b/contrib/nix/enterprise-client.nix new file mode 100644 index 000000000..56af4dbbf --- /dev/null +++ b/contrib/nix/enterprise-client.nix @@ -0,0 +1,9 @@ +{ symlinkJoin, core, enterprise }: + +# Deliberately no masterfiles here: an enterprise agent gets its policy +# from the hub it's bootstrapped to, unlike the standalone community +# agent, which ships default policy to bootstrap itself. +symlinkJoin { + name = "cfengine-enterprise-client"; + paths = [ core enterprise ]; +} diff --git a/contrib/nix/enterprise-hub.nix b/contrib/nix/enterprise-hub.nix new file mode 100644 index 000000000..b07767895 --- /dev/null +++ b/contrib/nix/enterprise-hub.nix @@ -0,0 +1,10 @@ +{ symlinkJoin, core, enterprise, nova, masterfiles, missionPortal, apacheHttpd, php }: + +# apacheHttpd/php are included so they're on PATH/in the closure for +# whoever deploys this (a NixOS module, a container, ...) to actually run +# the hub's web UI against -- this derivation doesn't configure or start +# Apache itself, same as it doesn't start cf-serverd/cf-hub. +symlinkJoin { + name = "cfengine-enterprise-hub"; + paths = [ core enterprise nova masterfiles missionPortal apacheHttpd php ]; +} diff --git a/contrib/nix/flake.nix b/contrib/nix/flake.nix new file mode 100644 index 000000000..508bbf941 --- /dev/null +++ b/contrib/nix/flake.nix @@ -0,0 +1,48 @@ +{ + description = "CFEngine meta-flake: community-client, enterprise-client, enterprise-hub"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + # Absolute paths required -- see the comment in + # enterprise/contrib/nix/flake.nix for why relative "../.." doesn't + # work here. + core.url = "git+file:///home/victor-moene/northern.tech/cfengine/core?dir=contrib/nix"; + enterprise.url = "git+file:///home/victor-moene/northern.tech/cfengine/enterprise?dir=contrib/nix"; + nova.url = "git+file:///home/victor-moene/northern.tech/cfengine/nova?dir=contrib/nix"; + masterfiles.url = "git+file:///home/victor-moene/northern.tech/cfengine/masterfiles?dir=contrib/nix"; + mission-portal.url = "git+file:///home/victor-moene/northern.tech/cfengine/mission-portal?dir=contrib/nix"; + }; + + outputs = { self, nixpkgs, flake-utils, core, enterprise, nova, masterfiles, mission-portal }: + flake-utils.lib.eachDefaultSystem (system: + let + pkgs = nixpkgs.legacyPackages.${system}; + + coreOut = core.packages.${system}.default; + enterpriseOut = enterprise.packages.${system}.default; + novaOut = nova.packages.${system}.default; + masterfilesOut = masterfiles.packages.${system}.default; + missionPortalOut = mission-portal.packages.${system}.default; + in + { + packages = { + community-client = pkgs.callPackage ./community-client.nix { + core = coreOut; + masterfiles = masterfilesOut; + }; + enterprise-client = pkgs.callPackage ./enterprise-client.nix { + core = coreOut; + enterprise = enterpriseOut; + }; + enterprise-hub = pkgs.callPackage ./enterprise-hub.nix { + core = coreOut; + enterprise = enterpriseOut; + nova = novaOut; + masterfiles = masterfilesOut; + missionPortal = missionPortalOut; + }; + }; + } + ); +}