Ansible playbook’larınızı çalıştırıyorsunuz, her şey yeşil gösteriyor, “ok” yazıyor, ama gerçekten beklediğiniz değişiklikler oldu mu? Servis ayakta mı? Konfigürasyon dosyası doğru içeriğe sahip mi? İşte bu soruların cevabını almak için Ansible’ın assert modülü tam da ihtiyacınız olan araç.
assert modülü, Ansible playbook’larınıza test ve doğrulama mantığı eklemenizi sağlar. Bir nevi playbook içindeki “sanity check” mekanizmasıdır. Koşullar sağlandığında sessizce geçer, sağlanmadığında anlamlı hata mesajlarıyla durur ve size tam olarak neyin yanlış gittiğini söyler. Özellikle büyük altyapılarda, üretim ortamlarına deployment yapmadan önce veya karmaşık konfigürasyon değişiklikleri sonrasında bu modül hayat kurtarır.
assert Modülü Nedir ve Neden Kullanmalıyız
Klasik sysadmin yaklaşımıyla düşünelim: Bir shell scripti yazıyorsunuz ve bir servisi başlattıktan sonra systemctl status nginx çıktısını kontrol ediyorsunuz. Bu kontrol başarısız olursa script’i durduruyorsunuz. assert modülü de tam olarak bunu yapıyor, ama Ansible’ın deklaratif yapısı içinde, çok daha okunabilir ve yönetilebilir bir şekilde.
Bu modülü kullanmanın birkaç temel sebebi var:
- Erken hata yakalama: Sorun küçükken, yanlış bir konfigürasyonun tüm sisteme yayılmadan fark edilmesi
- Belgelenmiş beklentiler: Kodunuz aynı zamanda beklentilerinizi de belgeler hale gelir
- Güvenli deployment: Kritik adımlar arasında doğrulama noktaları koyabilirsiniz
- Debugging kolaylığı: Anlamlı hata mesajları sayesinde neyin nerede bozulduğu hemen anlaşılır
- Regression testing: Altyapınıza yönelik testler yazabilirsiniz
Temel Kullanım
assert modülünün en basit hali şu şekilde görünür:
---
- name: Temel assert kullanimi
hosts: webservers
tasks:
- name: Nginx'in kurulu olup olmadigini dogrula
ansible.builtin.assert:
that:
- ansible_facts['os_family'] == "Debian"
fail_msg: "Bu playbook sadece Debian tabanli sistemlerde calisir!"
success_msg: "Sistem Debian tabanli, devam ediyoruz."
Buradaki parametreleri açıklayalım:
- that: Kontrol edilecek koşulları listeler. Jinja2 ifadeleri kullanabilirsiniz, birden fazla koşul AND mantığıyla değerlendirilir
- fail_msg: Koşul sağlanmadığında gösterilecek hata mesajı (eski versiyonlarda
msgolarak geçerdi) - success_msg: Koşul sağlandığında gösterilecek başarı mesajı (opsiyonel)
- quiet: True yapıldığında başarılı assert’lerde çıktı üretmez, daha temiz log için kullanışlı
Gerçek Dünya Senaryosu 1: Deployment Öncesi Sistem Kontrolleri
Bir web uygulaması deployment’ı yapmadan önce sistemin hazır olup olmadığını kontrol eden bir playbook yazalım:
---
- name: Pre-deployment sistem dogrulamalari
hosts: appservers
gather_facts: yes
vars:
minimum_ram_mb: 2048
minimum_disk_gb: 20
required_ports:
- 80
- 443
- 8080
tasks:
- name: RAM miktarini kontrol et
ansible.builtin.assert:
that:
- ansible_memtotal_mb >= minimum_ram_mb
fail_msg: >
Yetersiz RAM! Mevcut: {{ ansible_memtotal_mb }}MB,
Gerekli: {{ minimum_ram_mb }}MB
success_msg: "RAM kontrolu gecti: {{ ansible_memtotal_mb }}MB mevcut"
- name: Disk alani kontrol et
ansible.builtin.assert:
that:
- (ansible_mounts | selectattr('mount', 'equalto', '/') |
list | first).size_available > (minimum_disk_gb * 1024 * 1024 * 1024)
fail_msg: "/ bolumunde yeterli disk alani yok!"
success_msg: "Disk alani yeterli"
- name: Isletim sistemi versiyonunu dogrula
ansible.builtin.assert:
that:
- ansible_distribution == "Ubuntu"
- ansible_distribution_major_version | int >= 20
fail_msg: >
Desteklenmeyen OS: {{ ansible_distribution }}
{{ ansible_distribution_version }}. Ubuntu 20.04+ gerekli.
Bu örnekte birden fazla koşulu aynı that listesinde verdiğimizde hepsi AND mantığıyla çalışır. Ubuntu olması VE versiyon 20’den büyük olması gerekiyor.
Gerçek Dünya Senaryosu 2: Servis Konfigürasyon Doğrulaması
Nginx konfigürasyonu değiştirdikten sonra servisi doğrulayan bir örnek:
---
- name: Nginx konfigurasyonu dogrula
hosts: webservers
tasks:
- name: Nginx'i kur ve yapilandir
ansible.builtin.package:
name: nginx
state: present
- name: Nginx konfigürasyon dosyasini kopyala
ansible.builtin.template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
owner: root
group: root
mode: '0644'
notify: reload nginx
- name: Nginx konfigurasyonunu test et
ansible.builtin.command: nginx -t
register: nginx_config_test
changed_when: false
- name: Nginx konfig test sonucunu dogrula
ansible.builtin.assert:
that:
- nginx_config_test.rc == 0
fail_msg: >
Nginx konfigurasyon testi basarisiz!
Hata: {{ nginx_config_test.stderr }}
success_msg: "Nginx konfigurasyonu gecerli"
- name: Nginx servisinin calistigini dogrula
ansible.builtin.service_facts:
- name: Nginx servis durumunu kontrol et
ansible.builtin.assert:
that:
- "'nginx' in services"
- "services['nginx'].state == 'running'"
- "services['nginx'].status == 'enabled'"
fail_msg: "Nginx servisi beklenen durumda degil!"
success_msg: "Nginx calisiyor ve aktif"
handlers:
- name: reload nginx
ansible.builtin.service:
name: nginx
state: reloaded
Burada dikkat çekici bir nokta var: register ile komut çıktısını kaydediyoruz ve ardından assert ile bu çıktıyı analiz ediyoruz. Bu pattern çok güçlü bir kombinasyon.
Gerçek Dünya Senaryosu 3: Güvenlik Kontrolleri
Güvenlik odaklı kontroller yazmak, compliance gereksinimleri için çok önemli:
---
- name: Guvenlik dogrulamalari
hosts: all
become: yes
tasks:
- name: SSH konfigurasyonunu oku
ansible.builtin.slurp:
src: /etc/ssh/sshd_config
register: sshd_config_raw
- name: SSH konfig icerigini decode et
ansible.builtin.set_fact:
sshd_config: "{{ sshd_config_raw.content | b64decode }}"
- name: Root SSH girisinin kapali oldugunu dogrula
ansible.builtin.assert:
that:
- "'PermitRootLogin no' in sshd_config or
'PermitRootLogin prohibit-password' in sshd_config"
fail_msg: >
GUVENLIK UYARISI: Root SSH girisi aktif!
/etc/ssh/sshd_config dosyasinda PermitRootLogin ayarini kontrol edin.
success_msg: "Root SSH girisi devre disi"
- name: Sifre ile SSH girisinin kapali oldugunu dogrula
ansible.builtin.assert:
that:
- "'PasswordAuthentication no' in sshd_config"
fail_msg: "GUVENLIK UYARISI: SSH sifre ile girise izin veriyor!"
success_msg: "SSH sifre girisi devre disi"
- name: UFW durumunu kontrol et
ansible.builtin.command: ufw status
register: ufw_status
changed_when: false
when: ansible_distribution == "Ubuntu"
- name: Guvenliq duvari aktif mi dogrula
ansible.builtin.assert:
that:
- "'Status: active' in ufw_status.stdout"
fail_msg: "Guvenlik duvari (UFW) aktif degil!"
success_msg: "Guvenlik duvari aktif"
when: ansible_distribution == "Ubuntu"
assert ile fail_when Farkı
Burada sık karşılaşılan bir kavram karmaşasını açıklığa kavuşturalım. fail_when ve assert benzer işler yapsa da farklı kullanım senaryoları var:
fail_when daha çok bir task’ın başarısız sayılması gereken durumu belirtirken, assert bağımsız bir doğrulama noktası olarak kullanılır. assert her zaman önce koşulu değerlendirir ve sonucu bildirir. Anlamlı mesajlar ekleyebilme kapasitesi açısından assert çok daha esnek.
---
- name: fail_when vs assert karsilastirma
hosts: localhost
tasks:
# fail_when yaklasimi
- name: Dosya varligini kontrol et (fail_when ile)
ansible.builtin.stat:
path: /etc/myapp/config.yml
register: config_file
failed_when: not config_file.stat.exists
# assert yaklasimi - daha aciklayici
- name: Dosya varligini dogrula (assert ile)
ansible.builtin.assert:
that:
- config_file.stat.exists
- config_file.stat.size > 0
fail_msg: >
Konfigürasyon dosyasi /etc/myapp/config.yml bulunamadi
veya bos! Lutfen uygulama kurulumunu kontrol edin.
success_msg: "Konfigürasyon dosyasi mevcut ve bos degil"
Değişken Doğrulama: assert ile Input Validation
Playbook değişkenlerini doğrulamak, özellikle role yazarken çok kritik:
---
# roles/webapp/tasks/validate.yml
- name: Gerekli degiskenleri dogrula
ansible.builtin.assert:
that:
- webapp_name is defined
- webapp_name | length > 0
- webapp_port is defined
- webapp_port | int > 1024
- webapp_port | int < 65535
- webapp_environment in ['development', 'staging', 'production']
- webapp_db_host is defined
- webapp_db_name is defined
fail_msg: >
Gerekli degiskenler eksik veya gecersiz!
Kontrol edilmesi gerekenler:
- webapp_name: {{ webapp_name | default('TANIMLANMAMIS') }}
- webapp_port: {{ webapp_port | default('TANIMLANMAMIS') }}
- webapp_environment: {{ webapp_environment | default('TANIMLANMAMIS') }}
- name: Production ortaminda ekstra kontroller
ansible.builtin.assert:
that:
- webapp_ssl_cert is defined
- webapp_ssl_key is defined
- webapp_backup_enabled | bool == true
fail_msg: >
Production ortaminda SSL sertifikasi ve yedekleme zorunlu!
when: webapp_environment == 'production'
Bu pattern özellikle başkalarının kullanacağı role’ler yazarken çok değerli. Role’ü kullanan kişi yanlış değer girdiğinde, anlamlı bir hata mesajı görür.
Kompleks Koşullar ve Jinja2 Filtreleri
assert modülünün gerçek gücü, Jinja2’nin tüm filtre ve test kapasitesini kullanabilmesinden geliyor:
---
- name: Kompleks assert ornekleri
hosts: dbservers
vars:
allowed_mysql_versions:
- "8.0"
- "8.1"
- "8.2"
tasks:
- name: MySQL versiyon bilgisini al
ansible.builtin.command: mysql --version
register: mysql_version_output
changed_when: false
- name: MySQL versiyon formatini isle
ansible.builtin.set_fact:
mysql_major_minor: >-
{{ mysql_version_output.stdout |
regex_search('(d+.d+)', '1') | first }}
- name: MySQL versiyonunu dogrula
ansible.builtin.assert:
that:
- mysql_major_minor in allowed_mysql_versions
fail_msg: >
Desteklenmeyen MySQL versiyonu: {{ mysql_major_minor }}
Desteklenen versiyonlar: {{ allowed_mysql_versions | join(', ') }}
- name: Veritabani baglantisini test et
ansible.builtin.command: >
mysql -u {{ db_user }} -p{{ db_password }}
-h {{ db_host }} -e "SELECT 1"
register: db_connection_test
changed_when: false
no_log: true
- name: Veritabani baglantisini dogrula
ansible.builtin.assert:
that:
- db_connection_test.rc == 0
fail_msg: >
Veritabanina baglanamiyorum!
Host: {{ db_host }}, User: {{ db_user }}
Lutfen baglanti bilgilerini ve ag ayarlarini kontrol edin.
success_msg: "Veritabani baglantisi basarili"
quiet Parametresi ile Temiz Çıktı
Çok fazla assert kullandığınızda terminal çıktısı gürültülü olabilir. quiet: true parametresi başarılı assert’lerin çıktısını bastırır:
---
- name: Sessiz dogrulama ornegi
hosts: all
tasks:
- name: Temel sistem kontrolleri (sessiz)
ansible.builtin.assert:
that:
- ansible_python_version is version('3.6', '>=')
fail_msg: "Python 3.6+ gerekli, mevcut: {{ ansible_python_version }}"
quiet: true
- name: Kritik guvenlik kontrolu (sesli - gormek istiyoruz)
ansible.builtin.assert:
that:
- ansible_selinux.status == 'enabled' or
ansible_distribution == 'Ubuntu'
fail_msg: "SELinux aktif degil!"
success_msg: "Guvenlik kontrolu gecti"
quiet: false
Genel tavsiye: rutin kontroller için quiet: true, güvenlik ve kritik kontroller için quiet: false kullanın.
assert ile Test Driven Infrastructure
assert modülünü kullanarak gerçek anlamda altyapı testi yapabilirsiniz. Bu yaklaşım, “Testinfra” veya “ServerSpec” gibi araçların yaptığı şeyi Ansible içinde native olarak yapmanızı sağlar:
---
# tests/webserver_tests.yml
- name: Web sunucu kabul testleri
hosts: webservers
gather_facts: yes
tasks:
- name: HTTP portunu kontrol et
ansible.builtin.wait_for:
port: 80
timeout: 5
register: http_port_check
ignore_errors: yes
- name: HTTP portu acik mi
ansible.builtin.assert:
that:
- http_port_check.failed == false
fail_msg: "HTTP portu (80) kapali veya servis cevap vermiyor!"
- name: HTTPS portunu kontrol et
ansible.builtin.wait_for:
port: 443
timeout: 5
register: https_port_check
ignore_errors: yes
- name: HTTPS portu acik mi
ansible.builtin.assert:
that:
- https_port_check.failed == false
fail_msg: "HTTPS portu (443) kapali!"
- name: Web uygulamasina HTTP istegi gonder
ansible.builtin.uri:
url: "http://{{ ansible_default_ipv4.address }}/health"
method: GET
status_code: 200
timeout: 10
register: health_check
delegate_to: localhost
- name: Health check endpoint dogrula
ansible.builtin.assert:
that:
- health_check.status == 200
- health_check.json.status == 'healthy'
fail_msg: >
Uygulama health check basarisiz!
HTTP Status: {{ health_check.status }}
Response: {{ health_check.json | default('Yanit alinamadi') }}
success_msg: "Uygulama saglikli calisiyor"
Hata Ayıklama İpuçları
assert ile çalışırken bazı pratik ipuçları:
verbose modda çalıştırın: ansible-playbook -v ile çalıştırdığınızda başarılı assert’lerin detaylarını da görürsünüz.
Koşulları adlandırın: Uzun that listeleri yerine, koşulları önce set_fact ile anlamlı isimler altında saklayın:
---
- name: Koşulları adlandirarak assert kullanimi
hosts: all
tasks:
- name: Sistem metriklerini topla
ansible.builtin.set_fact:
ram_yeterli: "{{ ansible_memtotal_mb >= 2048 }}"
swap_aktif: "{{ ansible_swaptotal_mb > 0 }}"
x86_64: "{{ ansible_architecture == 'x86_64' }}"
- name: Donanım gereksinimlerini kontrol et
ansible.builtin.assert:
that:
- ram_yeterli
- swap_aktif
- x86_64
fail_msg: >
Donanim gereksinimleri karsilanmiyor!
RAM yeterli: {{ ram_yeterli }}
Swap aktif: {{ swap_aktif }}
x86_64 mimari: {{ x86_64 }}
Bu yaklaşım hem daha okunabilir hem de hata mesajında hangi koşulun neden başarısız olduğunu açıkça gösteriyor.
ignore_errors ile kombinasyon: Bazen bir assert başarısız olsa bile devam etmek istersiniz, özellikle raporlama amaçlı:
- name: Opsiyonel ozellik kontrolu
ansible.builtin.assert:
that:
- "'avx2' in ansible_processor_flags"
fail_msg: "AVX2 destegi yok, bazi ozellikler devre disi olacak"
success_msg: "AVX2 destegi mevcut"
ignore_errors: yes
register: avx2_check
- name: AVX2 sonucunu kaydet
ansible.builtin.set_fact:
avx2_available: "{{ avx2_check.failed == false }}"
Sonuç
assert modülü, Ansible playbook’larınızı sadece konfigürasyon uygulayan araçlardan, kendi kendini doğrulayan akıllı otomasyon sistemlerine dönüştürür. Küçük projelerde bile kullanmaya başlamanızı tavsiye ederim çünkü alışkanlık kazanmak önemli.
Pratikte şunu görüyorum: assert kullanan playbook’lar başlangıçta biraz daha uzun oluyor, ama üretim ortamında bir şeyler ters gittiğinde saatlerce debug yapmak yerine dakikalar içinde sorunu bulabiliyorsunuz. Özellikle ekip olarak çalıştığınızda, başka birinin yazdığı playbook’u çalıştırırken neyin beklendiğini anlamak çok daha kolay oluyor.
Ansible’da infrastructure as code yaklaşımının tam anlamıyla olgunlaşması için testlerin de kod gibi ele alınması gerekiyor. assert modülü bu olgunluğun en pratik ve erişilebilir yolu. Bir sonraki playbook’unuzu yazarken, her kritik adımın ardından bir assert bloğu eklemeyi alışkanlık haline getirin. Birkaç ay sonra geriye baktığınızda, bu alışkanlığın size ne kadar zaman ve stres kurtardığını göreceksiniz.