diff --git a/ansible/molecule/default/converge.yml b/ansible/molecule/default/converge.yml index f14b9c8..b0e18b5 100644 --- a/ansible/molecule/default/converge.yml +++ b/ansible/molecule/default/converge.yml @@ -22,8 +22,11 @@ decdn_payment_channel_address: "0x1111111111111111111111111111111111111111" decdn_capacity_bond_address: "0x2222222222222222222222222222222222222222" decdn_slash_judge_address: "0x3333333333333333333333333333333333333333" - decdn_cache_origin_kind: "http" - decdn_cache_origin_url: "https://origin.example.invalid/" + # fs origin: exercises the role's "create the fs cache-origin base dir" task + # (#28) — /var/lib/decdn/origin does not pre-exist, so the run genuinely creates + # it (verify.yml asserts owner/group/mode). Keep in sync with verify.yml. + decdn_cache_origin_kind: "fs" + decdn_cache_origin_path: "/var/lib/decdn/origin" # Exercise baseline's named-sudo-users feature (see pre_tasks below). Throwaway # keys, generated for this test only — public keys, not credentials. Two users # on purpose: `alice.smith` has a '.' (so the sudoers.d filename-sanitize maps it diff --git a/ansible/molecule/default/verify.yml b/ansible/molecule/default/verify.yml index 34737ad..9a84d34 100644 --- a/ansible/molecule/default/verify.yml +++ b/ansible/molecule/default/verify.yml @@ -90,12 +90,39 @@ if bad: print("node.toml content mismatch (got, want):", bad, file=sys.stderr) sys.exit(1) + # [cache.origin] is a nested table (3 levels), so check it separately from + # the flat two-level `want` lookups above. Mirrors converge.yml's fs origin. + origin = d.get("cache", {}).get("origin", {}) + if origin.get("kind") != "fs" or origin.get("path") != "/var/lib/decdn/origin": + print("node.toml [cache.origin] mismatch (got):", origin, file=sys.stderr) + sys.exit(1) - name: Assert node.toml is valid TOML and renders the expected content ansible.builtin.command: cmd: python3 /root/molecule-assert-node-toml.py changed_when: false + # The role must CREATE the fs origin base dir (converge sets kind: fs) — the + # daemon's FilesystemOrigin::new crash-loops if it is missing (#28). This dir + # does not pre-exist, so its presence + ownership proves the role's task ran. + - name: Stat the fs cache-origin base directory + ansible.builtin.stat: + path: /var/lib/decdn/origin + register: decdn_origin_dir + + - name: Assert the fs cache-origin dir exists (decdn:decdn, 0755, directory) + ansible.builtin.assert: + that: + # Single short-circuiting expression (file convention — cf. lines 39-40, + # 59-61): a missing dir stops at `stat.exists` and routes to fail_msg + # instead of raising AnsibleUndefinedVariable on the absent pw_name/mode. + - >- + decdn_origin_dir.stat.exists and decdn_origin_dir.stat.isdir + and decdn_origin_dir.stat.pw_name == 'decdn' + and decdn_origin_dir.stat.gr_name == 'decdn' + and decdn_origin_dir.stat.mode == '0755' + fail_msg: "fs cache-origin dir missing / not a dir / wrong owner / wrong mode" + - name: Validate the systemd unit ansible.builtin.command: cmd: systemd-analyze verify /etc/systemd/system/decdn-node.service diff --git a/ansible/roles/decdn_node/tasks/main.yml b/ansible/roles/decdn_node/tasks/main.yml index d937783..69f7f9e 100644 --- a/ansible/roles/decdn_node/tasks/main.yml +++ b/ansible/roles/decdn_node/tasks/main.yml @@ -205,6 +205,27 @@ loop_control: label: "{{ item.path }}" +# For a filesystem pull-through origin (kind: fs), the daemon's FilesystemOrigin::new +# fails fast if the base path is missing or is not a directory — a crash-loop on every +# (re)start. Create it here so a kind: fs deploy is self-contained. The sharded blob +# files under it ({path}/{hex[0..2]}/{hex}) are content, not config, and stay an +# operator concern — only the base dir is role-managed. mode 0755 (looser than the +# 0700 data dirs above) per issue #28: the pull-through origin blobs are public CDN +# content, not secrets, so world-readable is harmless. It grants no write — the +# daemon reads as decdn (owner) and out-of-band population runs as decdn or root +# regardless — and in the default layout the 0700 parent (/var/lib/decdn) still +# blocks traversal; 0755 only widens read access if an operator relocates the path. +- name: Ensure the fs cache-origin base directory exists (kind == fs) + ansible.builtin.file: + path: "{{ decdn_cache_origin_path }}" + state: directory + owner: "{{ decdn_user }}" + group: "{{ decdn_group }}" + mode: "0755" + when: + - decdn_cache_origin_kind == "fs" + - decdn_cache_origin_path | length > 0 + # --- Install the binaries ----------------------------------------------------- - name: Install decdn-node + decdn CLI ansible.builtin.import_tasks: install.yml