From 207bff9cb9773e3e0ef7fe7114e4b1aa70ffd4b6 Mon Sep 17 00:00:00 2001 From: Luke Hoersten Date: Tue, 28 Jul 2026 21:11:08 -0500 Subject: Rename mattertimesync role to mattertimectl (build + controller) - Rename role dir and all vars from mattertimesync to mattertimectl - Rename the server subrole to controller - Build via cargo instead of npm; run the binary directly (no node) - Default fabricLabel to "Matter Time Controller" --- mattertimectl/build/defaults/main.yaml | 16 +++++ mattertimectl/build/meta/main.yaml | 5 ++ mattertimectl/build/tasks/main.yaml | 71 +++++++++++++++++++ mattertimectl/controller/defaults/main.yaml | 25 +++++++ mattertimectl/controller/handlers/main.yaml | 6 ++ mattertimectl/controller/meta/main.yaml | 5 ++ mattertimectl/controller/tasks/main.yaml | 80 ++++++++++++++++++++++ mattertimectl/controller/templates/config.json.j2 | 6 ++ .../controller/templates/mattertimectl.service.j2 | 15 ++++ .../controller/templates/mattertimectl.timer.j2 | 10 +++ 10 files changed, 239 insertions(+) create mode 100644 mattertimectl/build/defaults/main.yaml create mode 100644 mattertimectl/build/meta/main.yaml create mode 100644 mattertimectl/build/tasks/main.yaml create mode 100644 mattertimectl/controller/defaults/main.yaml create mode 100644 mattertimectl/controller/handlers/main.yaml create mode 100644 mattertimectl/controller/meta/main.yaml create mode 100644 mattertimectl/controller/tasks/main.yaml create mode 100644 mattertimectl/controller/templates/config.json.j2 create mode 100644 mattertimectl/controller/templates/mattertimectl.service.j2 create mode 100644 mattertimectl/controller/templates/mattertimectl.timer.j2 (limited to 'mattertimectl') diff --git a/mattertimectl/build/defaults/main.yaml b/mattertimectl/build/defaults/main.yaml new file mode 100644 index 0000000..56cabdc --- /dev/null +++ b/mattertimectl/build/defaults/main.yaml @@ -0,0 +1,16 @@ +--- + +mattertimectl_version: "0.1.0" +# https://github.com/lukehoersten/mattertimectl/tags +# Rust project: cargo build --release produces one self-contained binary +# (all runtime deps are pure Rust), so the target only needs the binary to +# run it. The source tarball must point at the Rust implementation. +mattertimectl_tar: "https://github.com/{{github_user}}/mattertimectl/archive/refs/tags/v{{mattertimectl_version}}.tar.gz" +mattertimectl_build_dir: "{{build_work_dir}}/mattertimectl-{{mattertimectl_version}}" +mattertimectl_srv_dir: "{{build_srv_dir}}" + +# Keep cargo's registry cache, the rustup toolchains, and the build output +# on build_work_dir (the SSD), not the SD card. +mattertimectl_cargo_home: "{{build_work_dir}}/.cargo" +mattertimectl_rustup_home: "{{build_work_dir}}/.rustup" +mattertimectl_cargo_target_dir: "{{build_work_dir}}/.cargo-target" diff --git a/mattertimectl/build/meta/main.yaml b/mattertimectl/build/meta/main.yaml new file mode 100644 index 0000000..dae4be5 --- /dev/null +++ b/mattertimectl/build/meta/main.yaml @@ -0,0 +1,5 @@ +--- + +# No role dependency: the Rust toolchain is installed inline via rustup +# (the distro rustc is too old for this crate's Rust edition). +dependencies: [] diff --git a/mattertimectl/build/tasks/main.yaml b/mattertimectl/build/tasks/main.yaml new file mode 100644 index 0000000..d5721d7 --- /dev/null +++ b/mattertimectl/build/tasks/main.yaml @@ -0,0 +1,71 @@ +--- + +- name: ensure build work dir exists + become: yes + file: + path: "{{build_work_dir}}" + state: "directory" + owner: "{{ansible_user}}" + group: "{{ansible_user}}" + mode: "0755" + +- name: check if mattertimectl build exists + stat: + path: "{{mattertimectl_srv_dir}}/mattertimectl-{{mattertimectl_version}}.tar.gz" + register: build_file + +# NOTE: rustup is used only because rs-matter requires a newer rustc than +# Ubuntu 24.04's apt ships (apt rustc is 1.75; rs-matter needs >= 1.87). Once +# the build host runs an Ubuntu whose apt rustc/cargo are new enough, drop +# rustup and the toolchain tasks below and just `apt install rustc cargo`. +- name: install rustup + become: yes + apt: + name: "rustup" + state: "present" + +- name: install a current stable rust toolchain + command: "rustup toolchain install stable" + environment: + CARGO_HOME: "{{mattertimectl_cargo_home}}" + RUSTUP_HOME: "{{mattertimectl_rustup_home}}" + when: not build_file.stat.exists + +- name: unarchive mattertimectl source + unarchive: + remote_src: yes + src: "{{mattertimectl_tar}}" + dest: "{{build_work_dir}}/" + creates: "{{mattertimectl_build_dir}}" + +- name: build mattertimectl release binary + # rustup run stable dispatches cargo through the toolchain regardless of + # the apt rustup package's proxy layout or the configured default. + command: "rustup run stable cargo build --release" + args: + chdir: "{{mattertimectl_build_dir}}" + creates: "{{mattertimectl_cargo_target_dir}}/release/mattertimectl" + environment: + CARGO_HOME: "{{mattertimectl_cargo_home}}" + RUSTUP_HOME: "{{mattertimectl_rustup_home}}" + CARGO_TARGET_DIR: "{{mattertimectl_cargo_target_dir}}" + when: not build_file.stat.exists + +- name: create build server dir + become: yes + file: + path: "{{mattertimectl_srv_dir}}" + mode: "0755" + state: "directory" + +- name: create gz archive of mattertimectl binary + become: yes + archive: + path: "{{mattertimectl_cargo_target_dir}}/release/mattertimectl" + dest: "{{mattertimectl_srv_dir}}/mattertimectl-{{mattertimectl_version}}.tar.gz" + format: "gz" + # force a real tar for the single-file binary; the module otherwise gzips + # a lone file into a bare .gz that the server's unarchive can't extract. + # The tar preserves the executable bit the target relies on. + force_archive: true + when: not build_file.stat.exists diff --git a/mattertimectl/controller/defaults/main.yaml b/mattertimectl/controller/defaults/main.yaml new file mode 100644 index 0000000..933a4bb --- /dev/null +++ b/mattertimectl/controller/defaults/main.yaml @@ -0,0 +1,25 @@ +--- + +# https://github.com/lukehoersten/mattertimectl/tags +mattertimectl_version: "0.1.0" + +mattertimectl_user: "mattertimectl" +mattertimectl_install_dir: "/opt/mattertimectl" +mattertimectl_config_dir: "/etc/mattertimectl" +# Persistent Matter fabric state: holds the controller's private keys and +# operational certs, so it stays mode 0700 and owned by the service user. +mattertimectl_storage_path: "/var/lib/mattertimectl" + +# --- config.json --- +# IANA time-zone name (never a fixed UTC offset; DST is derived from it). +mattertimectl_timezone: "America/Chicago" +mattertimectl_log_level: "info" # debug, info, warn, error +mattertimectl_fabric_label: "Matter Time Controller" + +# --- systemd timer schedule --- +mattertimectl_on_boot_sec: "2min" +mattertimectl_on_active_sec: "1h" +mattertimectl_randomized_delay_sec: "5min" + +# mattertimectl_bin_url: required, set in host_vars, e.g. +# http://{{build_server_host}}:{{build_server_port}}/mattertimectl-{{mattertimectl_version}}.tar.gz diff --git a/mattertimectl/controller/handlers/main.yaml b/mattertimectl/controller/handlers/main.yaml new file mode 100644 index 0000000..9b124e3 --- /dev/null +++ b/mattertimectl/controller/handlers/main.yaml @@ -0,0 +1,6 @@ +--- + +- name: reload systemd + become: yes + systemd: + daemon_reload: "yes" diff --git a/mattertimectl/controller/meta/main.yaml b/mattertimectl/controller/meta/main.yaml new file mode 100644 index 0000000..0fa3794 --- /dev/null +++ b/mattertimectl/controller/meta/main.yaml @@ -0,0 +1,5 @@ +--- + +# No runtime dependency: the Rust build is a single self-contained binary, +# so the target needs no node or other runtime. +dependencies: [] diff --git a/mattertimectl/controller/tasks/main.yaml b/mattertimectl/controller/tasks/main.yaml new file mode 100644 index 0000000..a77145c --- /dev/null +++ b/mattertimectl/controller/tasks/main.yaml @@ -0,0 +1,80 @@ +--- + +- name: add mattertimectl user + become: yes + user: + name: "{{mattertimectl_user}}" + system: "yes" + shell: "/usr/sbin/nologin" + home: "{{mattertimectl_storage_path}}" + create_home: "no" + +- name: create mattertimectl directories + become: yes + file: + path: "{{item.path}}" + state: "directory" + owner: "{{item.owner}}" + group: "{{item.owner}}" + mode: "{{item.mode}}" + loop: + - { path: "{{mattertimectl_install_dir}}", owner: "root", mode: "0755" } + - { path: "{{mattertimectl_config_dir}}", owner: "root", mode: "0755" } + - { path: "{{mattertimectl_storage_path}}", owner: "{{mattertimectl_user}}", mode: "0700" } + +- name: check installed mattertimectl version + become: yes + stat: + path: "{{mattertimectl_install_dir}}/.installed-{{mattertimectl_version}}" + register: mattertimectl_installed + +- name: install mattertimectl bundle + become: yes + unarchive: + remote_src: yes + src: "{{mattertimectl_bin_url}}" + dest: "{{mattertimectl_install_dir}}/" + owner: "root" + group: "root" + when: not mattertimectl_installed.stat.exists + +- name: stamp installed mattertimectl version + become: yes + copy: + dest: "{{mattertimectl_install_dir}}/.installed-{{mattertimectl_version}}" + content: "{{mattertimectl_version}}\n" + mode: "0644" + when: not mattertimectl_installed.stat.exists + +- name: configure mattertimectl + become: yes + template: + src: "config.json.j2" + dest: "{{mattertimectl_config_dir}}/config.json" + owner: "root" + group: "{{mattertimectl_user}}" + mode: "0640" + +- name: install mattertimectl systemd service + become: yes + template: + src: "mattertimectl.service.j2" + dest: "/etc/systemd/system/mattertimectl.service" + mode: "0644" + notify: reload systemd + +- name: install mattertimectl systemd timer + become: yes + template: + src: "mattertimectl.timer.j2" + dest: "/etc/systemd/system/mattertimectl.timer" + mode: "0644" + notify: reload systemd + +- name: enable mattertimectl timer + become: yes + systemd: + name: "mattertimectl.timer" + enabled: "yes" + state: "started" + daemon_reload: "yes" diff --git a/mattertimectl/controller/templates/config.json.j2 b/mattertimectl/controller/templates/config.json.j2 new file mode 100644 index 0000000..34f319c --- /dev/null +++ b/mattertimectl/controller/templates/config.json.j2 @@ -0,0 +1,6 @@ +{ + "storagePath": "{{mattertimectl_storage_path}}", + "timezone": "{{mattertimectl_timezone}}", + "logLevel": "{{mattertimectl_log_level}}", + "fabricLabel": "{{mattertimectl_fabric_label}}" +} diff --git a/mattertimectl/controller/templates/mattertimectl.service.j2 b/mattertimectl/controller/templates/mattertimectl.service.j2 new file mode 100644 index 0000000..96cbeee --- /dev/null +++ b/mattertimectl/controller/templates/mattertimectl.service.j2 @@ -0,0 +1,15 @@ +[Unit] +Description=Matter device clock synchronization +Wants=network-online.target +After=network-online.target time-sync.target + +[Service] +Type=oneshot +User={{mattertimectl_user}} +Group={{mattertimectl_user}} +ExecStart={{mattertimectl_install_dir}}/mattertimectl --config {{mattertimectl_config_dir}}/config.json sync +NoNewPrivileges=true +PrivateTmp=true +ProtectSystem=strict +ProtectHome=true +ReadWritePaths={{mattertimectl_storage_path}} diff --git a/mattertimectl/controller/templates/mattertimectl.timer.j2 b/mattertimectl/controller/templates/mattertimectl.timer.j2 new file mode 100644 index 0000000..a4242de --- /dev/null +++ b/mattertimectl/controller/templates/mattertimectl.timer.j2 @@ -0,0 +1,10 @@ +[Unit] +Description=Periodic Matter device clock synchronization + +[Timer] +OnBootSec={{mattertimectl_on_boot_sec}} +OnUnitActiveSec={{mattertimectl_on_active_sec}} +RandomizedDelaySec={{mattertimectl_randomized_delay_sec}} + +[Install] +WantedBy=timers.target -- cgit v1.2.3