Forwards
The keys of a sink, other than reduce, of, at and out, give elements to other sinks.
They run at the receiver, with the receiver’s args. You already know one: out gives to the flake.
# A sink's other keys give elements to other sinks. They run at the receiver, with its args.{ yen, ... }:let inherit (yen.lib.reduce) merge;in{ yen.kinds.host.sinks = { ports.config = { ports, ... }: { firewall.allowedTCPPorts = ports; }; # ports feed config config = { reduce = merge; out = { host, config, ... }: { config.${host.name} = config; }; }; }; yen.kinds.guest.sinks = { ports.config = { ports, ... }: { firewall.allowedTCPPorts = ports; }; config = { reduce = merge; config = { guest, config, ... }: { vms.${guest.name} = config; }; # its own name: a forward up, to the host }; };}- At a host,
portsfeedsconfig: aspects give port numbers, and the host turns them into firewall config. - At a guest,
confighas a key with its own name. A sink cannot feed itself, so this forward goes strictly up: to the nearestconfigsink above the guest, the host’s.
{ yen, lib, ... }:{ yen.kinds.fleet = { spawns.host = _: yen.host; sinks.out.reduce = yen.lib.reduce.merge; }; yen.kinds.host.spawns.guest = s: lib.filterAttrs (_: g: yen.lib.same g.on s) yen.guest; yen.kinds.guest.fields.on = yen.kinds.host;
yen.fleet.main = { }; yen.host.server = { }; yen.guest.ci.on = yen.host.server; yen.flake = { out, ... }: out;}{ yen, ... }:{ yen.aspects.ssh = { at = yen.kinds.host; ports = 22; }; yen.aspects.runner = { at = yen.guest.ci; ports = 8080; config.runner.enable = true; };}The guest’s config arrives inside the host’s config, under vms.ci:
{ server = { firewall = { allowedTCPPorts = [ 22 ]; }; vms = { ci = { firewall = { allowedTCPPorts = [ 8080 ]; }; runner = { enable = true; }; }; }; };}flowchart BT n6c4c773b6d["fleet main"] n04467a35ae["host server"] n99b25160dc["guest ci"] n99b25160dc -->|config| n04467a35ae n04467a35ae -->|out| n6c4c773b6d