domain/architecture/system/deployment/nix_darwin/ops.bend source
domain/architecture/system/deployment/nix_darwin/ops.bend on the hub · documented module
import Baseimport ./type.bend as NDimport ./service/type.bend as Svimport ./service/ops.bend as SvOimport ../../container/type.bend as Ctdef user(nd: ND.NixDarwin) -> String: match nd: case ND.NixDarwin{_, _, u, _, _, _, _, _, _, _, _, _, _, _}: udef tailscale(nd: ND.NixDarwin) -> Bool: match nd: case ND.NixDarwin{_, _, _, _, t, _, _, _, _, _, _, _, _, _}: tdef services(nd: ND.NixDarwin) -> List<&2, Sv.Service>: match nd: case ND.NixDarwin{_, _, _, _, _, _, _, _, ss, _, _, _, _, _}: ssdef serves(nd: ND.NixDarwin) -> List<&2, ND.Serve>: match nd: case ND.NixDarwin{_, _, _, _, _, _, _, _, _, ss, _, _, _, _}: ssdef listeners(nd: ND.NixDarwin) -> List<&2, ND.Listening>: match nd: case ND.NixDarwin{_, _, _, _, _, _, _, _, _, _, ls, _, _, _}: lsdef kept(nd: ND.NixDarwin) -> List<&2, String>: match nd: case ND.NixDarwin{_, _, _, _, _, _, _, _, _, _, _, k, _, _}: kdef serve_container(s: ND.Serve) -> String: match s: case ND.Serve{c, _, _, _}: cdef serve_https(s: ND.Serve) -> U32: match s: case ND.Serve{_, h, _, _}: hdef serve_port(s: ND.Serve) -> U32: match s: case ND.Serve{_, _, p, _}: p# What Tailscale proxies a serve to.def serve_target(s: ND.Serve) -> String: match s: case ND.Serve{_, _, p, path}: "http://127.0.0.1:" ++ U32.show(p) ++ pathdef listening_process(l: ND.Listening) -> String: match l: case ND.Listening{p, _}: pdef listening_processes(xs: List<&2, ND.Listening>) -> List<&2, String>: match xs: case []: [] case l <> rest: listening_process(l) <> listening_processes(rest)# ---- the nix-darwin flake: pinned inputs, the Mac's module, and one launchd job per service ----def tailscale_line(on: Bool) -> String: match on: case True{}: " services.tailscale.enable = true;\n" case False{}: ""# `lets` are Nix bindings the jobs may use (e.g. a derivation); `config` is extra nix-darwin config lines.def flake(nd: ND.NixDarwin) -> String: match nd: case ND.NixDarwin{host, platform, +u, +logs, t, _, _, _, ss, _, _, _, lets, config}: "# Generated by V from the architecture. Do not edit.\n" ++ "{\n" ++ " inputs.nixpkgs.url = \"github:NixOS/nixpkgs/nixpkgs-unstable\";\n" ++ " inputs.nix-darwin.url = \"github:nix-darwin/nix-darwin/master\";\n" ++ " inputs.nix-darwin.inputs.nixpkgs.follows = \"nixpkgs\";\n" ++ " outputs = { nixpkgs, nix-darwin, ... }: {\n" ++ " darwinConfigurations." ++ host ++ " = nix-darwin.lib.darwinSystem {\n" ++ " system = \"" ++ platform ++ "\";\n" ++ " modules = [ ./mac.nix ({ pkgs, ... }: let\n" ++ lets ++ " in {\n" ++ config ++ tailscale_line(t) ++ SvO.jobs(ss, u, logs) ++ " }) ];\n };\n };\n}"# The Tailscale CLI: Nix's when Nix runs Tailscale, else the app's.def tailscale_command(nd: ND.NixDarwin) -> String: Bool.pick(String, tailscale(nd), "/run/current-system/sw/bin/tailscale", "/Applications/Tailscale.app/Contents/MacOS/Tailscale")# ---- laws of a system with this node ----# 0 is not a port.def fresh(+p: U32, ps: List<&2, U32>) -> Bool: U32.is_eq(p, 0) || Bool.not(List.contains(~U32, ~U32.is_eq, ps, p))def distinct(ps: List<&2, U32>) -> Bool: match ps: case []: True{} case +p <> +rest: fresh(p, rest) && distinct(rest)def https_ports(xs: List<&2, ND.Serve>) -> List<&2, U32>: match xs: case []: [] case s <> rest: serve_https(s) <> https_ports(rest)# No two serves share a tailnet HTTPS port.def serve_ports_distinct(nd: ND.NixDarwin) -> Bool: distinct(https_ports(serves(nd)))def belongs(l: ND.Listening, +keys: List<&2, String>) -> Bool: match l: case ND.Listening{_, +o}: String.eq(o, "macos") || List.contains(~String, ~String.eq, keys, o)def all_belong(xs: List<&2, ND.Listening>, +keys: List<&2, String>) -> Bool: match xs: case []: True{} case l <> rest: belongs(l, keys) && all_belong(rest, keys)# Every allowed listener belongs to macOS or to one of `keys` (the system's containers and nodes).def listeners_belong(nd: ND.NixDarwin, +keys: List<&2, String>) -> Bool: all_belong(listeners(nd), keys)def services_among(xs: List<&2, Sv.Service>, +instances: List<&2, String>) -> Bool: match xs: case []: True{} case s <> rest: List.contains(~String, ~String.eq, instances, SvO.container(s)) && services_among(rest, instances)def serves_among(xs: List<&2, ND.Serve>, +instances: List<&2, String>) -> Bool: match xs: case []: True{} case s <> rest: List.contains(~String, ~String.eq, instances, serve_container(s)) && serves_among(rest, instances)# Services and serves run only containers this node runs.def services_on(+nd: ND.NixDarwin, +instances: List<&2, String>) -> Bool: services_among(services(nd), instances) && serves_among(serves(nd), instances)def served(+k: String, xs: List<&2, ND.Serve>) -> Bool: match xs: case []: False{} case s <> rest: String.eq(k, serve_container(s)) || served(k, rest)def is_tailnet(e: Ct.Exposure) -> Bool: match e: case Ct.Tailnet{}: True{} case _: False{}def honest(c: Ct.Container, +ss: List<&2, ND.Serve>, +instances: List<&2, String>) -> Bool: match c: case Ct.Container{+k, _, _, _, _, e, _, _, _, _, _, _, _, _, _}: Bool.not(List.contains(~String, ~String.eq, instances, k)) || Bool.not(Bool.xor(is_tailnet(e), served(k, ss)))def all_honest(cs: List<&2, Ct.Container>, +ss: List<&2, ND.Serve>, +instances: List<&2, String>) -> Bool: match cs: case []: True{} case c <> rest: honest(c, ss, instances) && all_honest(rest, ss, instances)# A container on this node is on the tailnet exactly when a serve names it.def exposure_honest(nd: ND.NixDarwin, +cs: List<&2, Ct.Container>, +instances: List<&2, String>) -> Bool: all_honest(cs, serves(nd), instances)# Services that start at login need the Mac to log its user in by itself.def survives_reboot(+nd: ND.NixDarwin, auto_login_user: String) -> Bool: Bool.not(SvO.needs_login(services(nd))) || String.eq(auto_login_user, user(nd))