Instances and refs
A kind is also a type. A field of type yen.kinds.environment holds a ref to an environment instance:
yen.environment.prod, never the string "prod".
# A kind is a type too: a field of kind `environment` holds a ref to an environment instance.# Nothing spawns `environment`, so it is a data kind: its instances have no scope.{ yen, lib, ... }:{ yen.kinds.environment.fields.domain = lib.types.str; yen.kinds.host.fields = { environment = yen.kinds.environment; backup = yen.lib.maybe yen.kinds.host; # a ref to another host, or null };}{ yen, ... }:{ yen.environment.prod.domain = "example.com"; yen.environment.lab.domain = "lab.example.com";
yen.host.web = { environment = yen.environment.prod; backup = yen.host.db; }; yen.host.db = { environment = yen.environment.prod; backup = yen.host.web; }; # refs can point both ways yen.host.test.environment = yen.environment.lab;}Refs are lazy, so two hosts can point at each other. There is no cycle error.
Follow a ref like an attrset, and compare two instances with yen.lib.same:
{ yen, lib, ... }:{ yen.aspects.report = { at = yen.kinds.host; report = { host, ... }: { ${host.name} = { fqdn = "${host.name}.${host.environment.domain}"; # follow a ref, read its fields backup = if host.backup == null then null else host.backup.name; # `same` compares two instances by kind and name peers = lib.attrNames ( lib.filterAttrs (n: h: n != host.name && yen.lib.same h.environment host.environment) yen.host ); }; }; };}{ db = { backup = "web"; fqdn = "db.example.com"; peers = [ "web" ]; }; test = { backup = null; fqdn = "test.lab.example.com"; peers = [ ]; }; web = { backup = "db"; fqdn = "web.example.com"; peers = [ "db" ]; };}Data kinds
Section titled “Data kinds”environment is a data kind: no kind spawns it. Its instances have no place in the scope tree,
and refs to them still work. The tree has the fleet and the hosts only:
flowchart TD n6c4c773b6d["fleet main"] nbe39bbfa9b["host db"] n493d96ad82["host test"] n0f3c4939ab["host web"] n6c4c773b6d --> nbe39bbfa9b n6c4c773b6d --> n493d96ad82 n6c4c773b6d --> n0f3c4939ab
Groups, channels and secrets are good data kinds. Scopes shows how a kind gets a place in the tree.
A string is not a ref
Section titled “A string is not a ref”A name where a ref goes is an error record, with the fix:
# A name where a ref goes.{ yen, ... }:{ yen.host.cache.environment = "prod";}[ { class = "fixable"; code = "ref"; error = "environment wants a environment ref"; fix = "use yen.environment.<name>, not a string"; from = "host:cache"; got = "prod"; path = [ "environment" ]; want = "a environment ref"; }]