Task Ansible yang gagal karena direktori conf.d tidak ada
Playbook mitigation berhenti di server kesembilan: journald.conf.d ternyata tidak pernah ada. Satu task file state=directory menutup asumsi itu.
Ringkasan
Playbook gagal di server kesembilan karena folder /etc/systemd/journald.conf.d nggak ada; delapan server lain kebetulan punya, jadi lolos terus. Fix-nya simpel banget: tambah satu task file state=directory sebelum task salin, beres. Hasilnya journal turun dari 720M ke 288M, aman di bawah cap 300M.
Gagal di server kesembilan
Playbook mitigate-disk.yml saya sudah lewat delapan server tanpa drama. Di server kesembilan, BSA-WEB, dia berhenti di tengah jalan: task yang menyalin cap SystemMaxUse=300M ke /etc/systemd/journald.conf.d/ gagal. Tebakan pertama saya salah ketik di task, atau path-nya beda di host itu. Setelah dibedah, penyebabnya lebih konyol: direktori /etc/systemd/journald.conf.d memang tidak pernah ada di BSA-WEB. Task saya menyalin file ke folder yang tidak ada.
Di sinilah saya menyadari asumsi tersembunyi di playbook sendiri. Delapan server lain kebetulan punya direktori itu, jadi task-nya lolos terus dan tidak pernah ditantang. "Jalan di delapan server" ternyata bukan bukti playbook-nya benar; itu bukti delapan server kebetulan senada.
Drop-in journald itu konvensi resmi
Cap yang saya pasang bukan coba-coba. Man page journald mencatat SystemMaxUse= sebagai penegak batas ukuran file journal [1], dan drop-in dari /etc/systemd/*.conf.d/ punya prioritas lebih tinggi daripada file utama [1]. Dokumentasi systemd bahkan merekomendasikan drop-in daripada mengedit file utama [1]. Jadi arahnya sudah benar; yang kurang cuma satu: konvensi drop-in tidak menjamin foldernya ada.
Instalasi stock tidak selalu menyediakan journald.conf.d, dan itu sah menurut systemd, karena konfigurasi default ditentukan saat kompilasi [1]. Folder itu hanya muncul kalau ada yang membuatnya. Playbook yang menulis ke dalamnya berarti playbook yang wajib membuatnya dulu.
Perbaikan satu task yang membosankan
Fix-nya semembosankan mungkin: satu task sebelum task salin.
- name: Ensure journald.conf.d exists
when: ansible_service_mgr == 'systemd'
ansible.builtin.file:
path: /etc/systemd/journald.conf.d
state: directory
mode: "0755"
Modul ansible.builtin.file mengatur atribut file, direktori, atau symlink [2], dan dengan state=directory semua subdirektori perantara ikut dibuat kalau belum ada [2]. Di delapan server lain task ini jadi no-op, karena foldernya memang sudah ada; playbook tetap idempoten. Di BSA-WEB task ini menjalankan satu pekerjaan, lalu task salin di belakangnya akhirnya punya tempat untuk mendarat.
Satu detail kecil yang gampang kelewat: task ini diberi kondisi when: ansible_service_mgr == 'systemd'. Host non-systemd tidak punya journald sama sekali, dan memaksa direktori journald di host seperti itu cuma bikin sampah config. Fakta bahwa kondisi ini mungkin terlihat sepele justru intinya: semua asumsi playbook layak ditulis eksplisit, bukan disimpan di kepala penulisnya.
Urutannya nggak bisa dibalik. Copy dulu baru mkdir sama saja dengan meminta kegagalan sekali lagi. Kalau boleh keras: file config yang Anda salin bukan deliverable; jalur lengkap sampai file itu yang deliverable. Task yang menulis config tanpa menjamin induknya ada itu menyimpan bom yang meledaknya tergantung nasib host.
Ada pertanyaan yang wajar muncul: kenapa delapan server lain punya folder itu sementara BSA-WEB tidak? Jawaban jujurnya: saya tidak tahu dan itu nggak penting untuk fix-nya. Yang penting polanya. Image bawaan beda-beda, dan konvensi drop-in justru dirancang buat situasi ini: file di /etc/ milik admin lokal, sementara paket vendor meletakkan miliknya di /usr/ [1]. Automation yang menulis ke area admin lokal harus siap menghadapi host yang masih polos.
Pola ini juga gampang dibawa ke config lain. Setiap kali ada task salin menuju semacam conf.d, apa pun aplikasinya, task direktori di depannya adalah partner wajibnya. Biayanya satu task no-op di host yang sudah rapi, dan satu penyelamat di host yang belum. Bandingkan dengan biaya sebaliknya: playbook yang gagal di tengah jalan di satu server, jam insiden yang hilang, dan cap disk yang nggak jadi terpasang.
Angka penutupnya
Setelah direktori dijamin ada dan cap terpasang, BSA-WEB turun dari /var/log 992M ke 458M, dan journal dari 720M ke 288M — aman di bawah cap 300M. Rule logrotate untuk btmp juga terpasang di host yang sama; cerita pagarnya sudah saya tulis terpisah di artikel logrotate guard.
Total perubahan kode untuk seluruh hasil ini: tujuh baris task file. Itu bagian yang saya suka dari pola begini. Masalahnya muncul dari asumsi yang nggak pernah ditulis, dan solusinya cuma menulis asumsi itu jadi task yang bisa diverifikasi. Playbook nggak jadi lebih pintar; dia cuma berhenti menganggap.