# ntpd-rs 1.9.0 — el reloj, en Rust. Reemplaza a `chrony` como raíz del perfil `servidor`. # # ── POR QUÉ SE CAMBIA, Y LO QUE NO SE GANA ────────────────────────────────────────────────────── # `chrony` es una hoja: 0 consumidores, declarada sólo en `servidor`. Eso la hace la pieza C vital # más baratа de cambiar del corpus — tocarla no invalida a nadie. Lo que se gana es que el demonio # que **ajusta el reloj del sistema como root** deje de ser C: ntpd-rs es de Trifecta Tech / # Tweede Golf, está en Debian y Fedora, y se escribió para este nicho exacto. # # ⚠ **Lo que NO se gana hoy, dicho antes de que alguien lo lea al revés: NTS sigue apagado.** # `recipes/chrony.toml` lo apaga porque NTS necesita nettle o gnutls y ninguna está en el corpus. Acá # el muro es el mismo un piso más arriba: el TLS de NTS lo hace `rustls`, y rustls necesita un # *proveedor* de criptografía compilado —`aws-lc-rs` o `ring`—, **y los dos son C** (`aws-lc-sys` # arrastra cmake + asm; medido en el `Cargo.lock` del tag: `aws-lc-sys` ← `aws-lc-rs` ← `rustls`). # Por eso este build va con `--no-default-features --features rustcrypto`: la criptografía del # protocolo NTP (AES-SIV, MD5) sí queda pura-Rust —`ntp-proto` la declara como proveedor de primera # clase y aborta con `compile_error!` si no hay ninguno— pero el NTS-KE queda sin proveedor de TLS. # ⇒ **NTP clásico, igual que chrony hoy.** Subir NTS es su propia unidad de trabajo y lo que pide es # un proveedor de rustls, no esta receta. # # ── EL BUILD: DOS BINARIOS, Y POR ESO LA FASE `compile` ES PROPIA ─────────────────────────────── # El camino por defecto del lab es `cargo rustc -- `, que exige UN solo target; `ntpd` produce # tres (`ntp-daemon`, `ntp-ctl`, `ntp-metrics-exporter`). Se itera, igual que `recipes/cargo-edit.toml` # —de donde sale este bloque verbatim— y por la misma razón: `+crt-static` NO puede ir en RUSTFLAGS # porque alcanza a los proc-macros (`serde_derive`, `tokio-macros`, `tracing-attributes`) y rustc # aborta con «cannot produce proc-macro». Tras `cargo rustc --` sólo toca el binario final. # # Se construyen DOS de los tres: el demonio y `ntp-ctl`, que es el equivalente de `chronyc` —sin él la # caja no se puede inspeccionar y eso sería una regresión frente a chrony—. El exportador de # Prometheus queda fuera: nadie lo pide y es un binario más. # # `NTPD_RS_GIT_REV` se fija al commit PINEADO a propósito: el `build.rs` de ntpd pregunta a `git` por # la revisión y, si el árbol de fuentes trae `.git`, el string de versión del binario cambiaría con # él. Fijarlo lo vuelve función de la receta —que sí entra en `hash_inputs`— y no del árbol. # # MSRV 1.88; el lab trae rust 1.97.0 (`docs/state/lab-toolchain.lock`). Cargo.lock commiteado # upstream ⇒ `--locked` + vendoreo dan un build reproducible (ADR 0006). name = "ntpd-rs" version = "1.9.0" license = "Apache-2.0 OR MIT" [source] repo = "https://github.com/pendulum-project/ntpd-rs" # tag v1.9.0. El commit es el identificador inmutable (ADR 0006), no el tag. commit = "46ec9bb4d5b6cb24f814f5543d85b9138afb4cba" [build] compiler = "zig-cc" target = "x86_64-linux-musl" link = "static" strip_debug = true flags = [] [build.phases] compile = ''' printf '%s\n' '#!/bin/sh' 'for a do' 'case "$a" in --target=*) a=--target=x86_64-linux-musl ;; esac' 'set -- "$@" "$a"' 'shift' 'done' 'exec zig cc -mcpu=baseline "$@"' > "$PWD/.hammer-zig-cc" chmod +x "$PWD/.hammer-zig-cc" RF="-C linker=$PWD/.hammer-zig-cc" rustc -vV | grep -q 'host: .*-alpine-' || RF="$RF -C link-self-contained=no" for b in ntp-daemon ntp-ctl; do NTPD_RS_GIT_REV=46ec9bb4d5b6cb24f814f5543d85b9138afb4cba \ CC="$PWD/.hammer-zig-cc" RUSTFLAGS="$RF" \ cargo rustc --release --locked -p ntpd --bin "$b" --no-default-features --features rustcrypto \ -- -C target-feature=+crt-static -C relocation-model=static done ''' # El install es propio porque además de los binarios viaja el EJEMPLO de config. No se instala como # `/etc/ntpd-rs/ntp.toml` —eso lo hace el .deb de upstream— porque a qué servidores NTP se pregunta # es decisión del SITIO: ver el `[[service]]` de abajo, que sale 78 nombrando el fichero. install = ''' mkdir -p /out/usr/bin /out/usr/share/doc/ntpd-rs cp target/release/ntp-daemon /out/usr/bin/ntp-daemon cp target/release/ntp-ctl /out/usr/bin/ntp-ctl cp docs/examples/conf/ntp.toml.default /out/usr/share/doc/ntpd-rs/ntp.toml.default ''' [deps] build = ["binutils"] # ── EL SERVICIO QUE ESTE PAQUETE TRAE (SDD 30) ────────────────────────────────────────────────── # Fuera de `hash_inputs`: declararlo NO re-hashea nada. # # El porqué es el de `recipes/chrony.toml` y no cambia: **sin hora no hay TLS ni firmas**, y el # síntoma no se parece a la causa — los certificados salen «not yet valid» o «expired», el ACME falla, # y todo apunta al servidor web. Una caja de Hetzner arranca con la hora del reloj virtual y sin nadie # que la corrija: `netup` pone la red y ahí termina su trabajo. # # Corre como root porque ajusta el reloj del sistema (`clock_settime`/`adjtimex`), que es capability # de root. Bajar de privilegio necesita una cuenta de servicio, y esa decisión va con la del setuid # (ver `crates/takana-core/src/setuid.rs`), no antes. # # ⚠ La CONFIG es del sitio y el servicio sale **78** nombrando el fichero en vez de inventarse un # pool: una caja que se sincroniza contra un servidor que nadie eligió es peor que una sin hora, # porque nadie lo mira. El ejemplo viaja en `/usr/share/doc/ntpd-rs/ntp.toml.default`. # # ⚠ `exec = "/bin/busybox"` es el patrón de TODAS las cards de hoy (chrony, gitea, pacha…): el `sh` # sale del `product-rootfs`, que lo trae por `STAGE1_COMPONENTS`. Cuando el frente C de busybox se # cierre, las cards se mueven juntas — no es deuda de esta receta. [[service]] label = "ntpd-rs" id = "01M2EKDA00NTPDRS7K2X4M9V40" exec = "/bin/busybox" argv = ["sh", "-c", "test -f /etc/ntpd-rs/ntp.toml || { echo 'ntpd-rs: falta /etc/ntpd-rs/ntp.toml — a qué servidores NTP se pregunta es decisión del sitio, no del paquete (ejemplo en /usr/share/doc/ntpd-rs/ntp.toml.default)' >&2; exit 78; }; mkdir -p /var/run/ntpd-rs; exec /usr/bin/ntp-daemon -c /etc/ntpd-rs/ntp.toml"] envp = [["PATH", "/usr/sbin:/usr/bin:/sbin:/bin"], ["HOME", "/root"], ["USER", "root"]] networking = "full" cgroup = "arje.slice/ntpd-rs" restart = { initial_ms = 1000, max_ms = 30000 }