Playbook reboot yang berani menolak reboot
Reboot satu server produksi itu mudah; yang sulit adalah pagarnya. Pre-flight lock, modul reboot, dan post-check uptime yang berani gagal.
Ringkasan
Reboot satu server ternyata bukan cuma manggil modul reboot Ansible; playbook-nya dikasih pagar biar nggak nyasar. Dia nolak jalan kalau unattended-upgrades atau lock apt masih aktif, plus wajib konfirmasi dan --limit satu host biar nggak sembilan server ke-reboot sekaligus. Setelah reboot, uptime dibandingkan sebelum-sesudah buat membuktikan reboot-nya beneran kejadian.
Teka-teki yang menipu
Kolektor saya memantau sembilan server, dan minggu itu satu di antaranya butuh patch kernel yang cuma selesai setelah reboot. Niat saya sederhana: bikin satu playbook Ansible buat me-reboot satu server dengan aman. Ternyata bagian yang susah bukan perintah reboot-nya, tapi pagar-pagar di sekelilingnya. Playbook reboot.yml itu justru lebih banyak isinya penolakan daripada aksi: dia bisa menolak jalan, dan bisa gagal setelah jalan.
Percaya pertama saya: apa susahnya, modul ansible.builtin.reboot toh sudah mengurus semuanya. Dokumentasinya jelas, dia me-reboot mesin, menunggu mesin turun, kembali hidup, dan merespons perintah lagi [1]. Dengan reboot_timeout 600 detik buat menunggu siklus turun dan naik [1], saya tinggal memanggil dan pulang.
Tapi coba perhatikan urutan kejadiannya. Sembilan server itu di-patch otomatis oleh unattended-upgrades, yang memang dirancang jalan berkala lewat service apt-daily-upgrade [3]. Kalau playbook saya nyambar di saat patch sedang berjalan, saya memotong dpkg di tengah konfigurasi. Risiko bukan mesinnya mati, tapi dia hidup dengan setengah paket yang belum selesai. Dan setelah reboot selesai, modul cuma menjawab "selesai" — bukti bahwa uptime benar-benar reset itu urusan saya sendiri.
Pagar sebelum dan sesudah
Solusinya satu playbook dengan tiga lapis. Lapis pertama, gerbang panggilan: playbook ini butuh konfirmasi eksplisit dan --limit ke satu host. Tanpa itu, satu salah ketik di inventori bisa me-reboot sembilan server sekaligus.
Lapis kedua, pre-flight. Playbook menolak jalan kalau ada penanda progress unattended-upgrades, atau kalau lock apt dan dpkg masih dipegang proses lain. Detektor lock-nya fuser: dia menampilkan PID proses yang memakai file atau file system tertentu [2], dan return code-nya non-zero kalau nggak ada proses yang memakai file itu [2]. Pasangan return code itu bikin fuser enak dipakai sebagai probe otomatis: nggak perlu parsing output, cukup percaya exit code.
Lapis ketiga, eksekusi dan pembuktian. Task reboot memakai ansible.builtin.reboot dengan timeout 600 detik [1]. Setelah mesin responsif lagi, playbook melakukan post-check yang kadang bikin saya senyum: dia membandingkan uptime sebelum dan sesudah, dan menggagalkan host kalau uptime-nya nggak reset. Recap akhirnya menampilkan uptime, kernel, dan memori bebas sebelum-sesudah, jadi buktinya tercetak rapi di output.
Kenapa post-check yang menggagalkan itu penting
Ekoran seketika itu memang canggung. Tapi pemisahnya jelas: task yang balik "ok" cuma bilang perintahnya lari, sedangkan uptime yang reset membuktikan kejadian yang saya inginkan benar-benar terjadi. Saya pernah paham bedanya waktu membaca opsi test_command di modul reboot, yang jadi patokan "mesin siap untuk task lanjutan" [1]. Patokan siap itu belum bilang apa-apa soal reboot-nya sendiri. Verifikasi pasca-reboot harus mengukur efek reboot, bukan responsivitas mesin.
Lapis kedua-nya juga penting: kalau unattended-upgrades sedang jalan, yang saya butuhkan bukan reboot yang dipaksa, tapi playbook yang mundur dengan rapi. Server itu akan di-patch sampai selesai, dan reboot-nya bisa dicoba lagi nanti.
Sebelum semua lapis itu pernah disentuh ke server sungguhan, playbook-nya melewati syntax-check dan 111 unit test dulu. Angka 111 itu bukan gaya-gayaan; reboot termasuk operasi yang salah satunya langsung terasa, dan test inilah tempat murah buat menemukan variabel yang typo atau kondisi yang kebalik. Setelah hijau semua, barulah playbook ini layak disebut siap dipanggil.
Lapis paling luar malah nggak ada di kode: playbook ini hanya dipanggil manual, nggak pernah tersambung ke kolektor. Ada tools yang sengaja dibiarkan jauh dari automation. Kolektor jalan sendiri tiap beberapa jam; satu playbook reboot yang dipicu otomatis berarti satu bug jadi sembilan server mati serentak. Jarak antara "tool yang dipanggil manusia" dan "tool yang dipanggil jadwal" itu memang merepotkan, tapi merepotkan itu murah. Data recovery yang mahal.
Sources
[1] ansible.builtin.reboot module, Ansible docs