SSD Nodes Learn 🎉 VPS $5.50/ماہ سے
تعلیمی Matt Connorتحریر: Matt Connor

Ansible میں unreachable hosts کو ignore کریں

Ansible میں unreachable host، failed task سے مختلف ہوتا ہے۔ ignore_unreachable، serial اور max_fail_percentage سے کارروائی جاری رکھیں اور معلوم کریں کہ کیا رہ گیا۔

غیر قابل رسائی host ناکام task نہیں ہے

Ansible میں غیر قابل رسائی hosts کو نظر انداز کرنے کے لیے ignore_unreachable: true set کریں۔ یہ switch کام کرتا ہے۔ اہم بات یہ سمجھنا ہے کہ اسے کب استعمال کرنا ہے، کیونکہ Ansible دو مختلف مسائل کو دو مختلف طریقوں سے handle کرتا ہے۔ جو task host پر چلا اور error کے ساتھ واپس آیا، وہ failure ہے۔ جس host سے Ansible بالکل connect نہ ہو سکا، وہ unreachable ہے۔ ignore_errors صرف پہلے معاملے کو handle کرتا ہے۔ ignore_unreachable صرف دوسرے معاملے کو handle کرتا ہے۔

Play recap میں فرق یہ ہے۔

PLAY RECAP *********************************************************************
web1  : ok=7  changed=2  unreachable=0  failed=0  skipped=0  rescued=0  ignored=0
web2  : ok=0  changed=0  unreachable=1  failed=0  skipped=0  rescued=0  ignored=0

Ansible نے web1 سے connect ہو کر سات tasks چلائے۔ web2 میں unreachable=1 اور failed=0 دکھائی دیتے ہیں، جس کا مطلب ہے کہ اس host پر کچھ بھی نہیں چلا۔ Ansible کو connection ہی نہیں ملا، اس لیے اس نے host کو play سے خارج کیا اور باقی hosts کے ساتھ کام جاری رکھا۔ اگر وہ play security update install کر رہی تھی تو آپ کے ایک server پر وہ update موجود نہیں ہے۔

میزبان ناقابل رسائی کیوں ہوتا ہے

ناقابل رسائی کا مطلب ہے کہ کسی بھی module کے میزبان تک پہنچنے سے پہلے connection ناکام ہو گیا۔ پڑھنے کے لیے کوئی module output موجود نہیں ہوتا، صرف connection error ظاہر ہوتی ہے، اور یہ مشین سے متعلق پہلے task پر دکھائی دیتی ہے۔

fatal: [web2]: UNREACHABLE! => {"changed": false, "msg": "Failed to connect to the host via ssh: ssh: connect to host 203.0.113.20 port 22: Connection refused", "unreachable": true}

msg فیلڈ اصل وجہ بتاتا ہے۔ آپ کو عموماً یہ وجوہات نظر آئیں گی:

  • Connection refused: TCP connection مسترد کر دیا گیا، اس لیے اس port پر کچھ بھی listening نہیں کر رہا۔ sshd بند ہے، یا SSH کسی دوسرے port پر منتقل کر دیا گیا ہے جبکہ inventory میں اب بھی 22 درج ہے۔
  • Connection timed out: کسی نے بھی جواب نہیں دیا۔ Firewall packets کو drop کر رہا ہے، یا server بند ہے۔ ہر کوشش میں مکمل connection timeout صرف ہوتا ہے، جو by default 10 seconds ہے۔
  • Host key verification failed.: ~/.ssh/known_hosts میں موجود key، server کی پیش کردہ key سے مطابقت نہیں رکھتی۔ دوبارہ بنائے گئے VPS کا IP address وہی رہتا ہے لیکن اسے نئی host key ملتی ہے، اس لیے reinstall کے بعد یہ متوقع ہے؛ دوسرے کسی وقت یہ ایک سنگین مسئلہ ہے۔
  • Permission denied (publickey): SSH نے جواب دیا اور آپ کی key مسترد کر دی۔ Port درست ہے، اس لیے مسئلہ authentication کا ہے۔ عموماً ansible_user غلط ہوتا ہے یا key load نہیں کی گئی ہوتی۔
  • Timeout (12s) waiting for privilege escalation prompt: connection کامیاب ہو گیا، لیکن become کامیاب نہیں ہوا۔ sudo ایسے password کا انتظار کر رہا ہے جو کبھی موصول نہیں ہوتا۔

لوگ عموماً missing Python interpreter کو بھی اس فہرست میں شامل سمجھتے ہیں، لیکن وہ اس فہرست کا حصہ نہیں ہے۔ SSH connect ہو جاتا ہے، اس لیے host reachable ہے۔ اس کے بعد module کے پاس چلانے کے لیے کچھ موجود نہیں ہوتا:

fatal: [db1]: FAILED! => {"changed": false, "module_stdout": "/bin/sh: 1: /usr/bin/python3: not found\r\n", "msg": "The module failed to execute correctly, you probably need to set the interpreter", "rc": 127}

اس سطر سے معلوم ہوتا ہے کہ FAILED! ہے، اور recap اسے failed کے تحت شمار کرتا ہے، اس لیے ignore_unreachable اسے کبھی touch نہیں کرے گا۔ اس host کے لیے ansible_python_interpreter مقرر کریں، یا اس پر python3 install کریں۔

کسی play میں ناقابلِ رسائی hosts کو نظر انداز کرنے کا طریقہ

task level پر keyword، module کے ساتھ لکھی جاتی ہے:

- name: Read the package list, and do not stop if the host is down
  ansible.builtin.command: dpkg -l
  register: packages
  changed_when: false
  ignore_unreachable: true

play level پر یہ play کے ہر task کے لیے default مقرر کرتی ہے، اور کوئی ایک task اسے دوبارہ فعال کر سکتا ہے:

- name: Opportunistic fleet maintenance
  hosts: all
  ignore_unreachable: true
  tasks:
    - name: This runs, cannot connect, and the play carries on
      ansible.builtin.ping:

    - name: This one still ends the play for a host that is down
      ansible.builtin.ping:
      ignore_unreachable: false

اندرونی طور پر کیا تبدیل ہوتا ہے، یہ جاننا مفید ہے۔ ignore_unreachable مقرر ہونے پر host کو play سے خارج نہیں کیا جاتا، اس لیے بعد کے ہر task میں دوبارہ connection کی کوشش ہوتی ہے اور ہر بار اسی طرح failure ہوتی ہے۔ ہر کوشش connection timeout تک انتظار کرتی ہے، جو ansible.cfg میں timeout تبدیل نہ کرنے تک 10 seconds ہوتا ہے۔ ایک dead server کے خلاف 20 tasks والے play سے run میں تقریباً 200 seconds کا اضافہ اور log میں 20 سرخ lines شامل ہو جاتی ہیں۔

اس لیے ایک بار check کریں، پھر اس host کو صاف طریقے سے روک دیں:

- name: Opportunistic fleet maintenance
  hosts: all
  gather_facts: false
  tasks:
    - name: Check that the host answers before doing any work
      ansible.builtin.ping:
      register: reachable
      ignore_unreachable: true

    - name: End the play for this host if it never answered
      ansible.builtin.meta: end_host
      when: reachable.unreachable | default(false)

    - name: Gather facts now that the connection is known good
      ansible.builtin.setup:

    - name: Refresh the package index
      ansible.builtin.apt:
        update_cache: true
      become: true

اس طرح ہر dead host کے لیے ہر task کے بجائے صرف ایک connection attempt ہوتی ہے۔ end_host، جو Ansible 2.8 میں شامل ہوا، موجودہ host کے لیے play ختم کر دیتا ہے، مگر اسے failed نشان زد نہیں کرتا۔ unreachable key صرف اس وقت registered result میں موجود ہوتی ہے جب connection failed ہو، اس لیے default(false) ہر جواب دینے والے host پر condition کو valid رکھتا ہے۔ play level پر fact gathering بند ہے، کیونکہ بصورتِ دیگر implicit Gathering Facts task ہی broken connection سے ٹکراتا۔ یہاں مقصد یہ ہے کہ یہ کام آپ کا اپنا ping کرے۔

ignore_unreachable play keyword اور task keyword دونوں ہے۔ اسے playbook میں ایسی جگہ رکھیں جہاں قاری اسے دیکھ سکے، نہ کہ role کے اندر، کیونکہ یہ طے کرتا ہے کہ run کن hosts کو نظر انداز کر سکتا ہے۔ playbooks اور roles کے درمیان تقسیم میں بتایا گیا ہے کہ اس طرح کی setting کی ذمہ داری کس layer کو دینی چاہیے۔

یہاں ignore_errors غلط آلہ کیوں ہے

Ansible کی دستاویزات اس کی حد واضح طور پر بیان کرتی ہیں۔ ignore_errors "یہ صرف اس وقت کام کرتا ہے جب task چل سکے اور 'failed' کی value واپس کرے۔ یہ Ansible کو undefined variable errors، connection failures، execution issues، مثلاً missing packages، یا syntax errors کو نظرانداز کرنے پر مجبور نہیں کرتا۔"

Connection failure کبھی بھی failed: true کے ساتھ task result نہیں بنتی۔ یہ ایک الگ flag کے طور پر آتی ہے، اور Ansible پہلے اسی flag پر کارروائی کرتا ہے: host unreachable list میں شامل ہو جاتا ہے اور play سے خارج ہو جاتا ہے۔ کسی play کے تمام بارہ tasks پر ignore_errors: true لگانے کے باوجود، closed SSH port والا host پہلے task پر ہی رک جاتا ہے۔ یہ اس معاملے میں سب سے عام غلط فہمی ہے۔ اس لیے اپنی پرانی playbooks میں اسے تلاش کرنا مفید ہے، خاص طور پر ان playbooks میں جو VPS کے خلاف پہلی playbook لکھنا سیکھتے وقت تیار کی گئی تھیں۔

ترتیباً تشخیص کریں، پھر نظرانداز کریں

مسئلہ چھپانے کا مستقل طریقہ fleet میں بتدریج انحراف پیدا کرتا ہے، کیونکہ جس host تک کوئی رسائی نہیں کر سکتا اسے کوئی patch بھی نہیں کر رہا ہوتا۔ پہلے اس ترتیب سے کام کریں۔ یہاں ہر command صرف معلومات پڑھتی ہے۔

  1. ansible web2 -i inventory.ini -m ansible.builtin.ping -o ایک host کے خلاف ایک module چلاتا ہے اور ایک سطر دکھاتا ہے۔
  2. اسی command میں -vvvv شامل کریں۔ Ansible وہ مکمل ssh command دکھاتا ہے جو یہ خود بناتا ہے، جس میں target user، port، private key اور منتقل کیے جانے والے options شامل ہوتے ہیں۔
  3. اس ssh command کو -v کے ساتھ خود چلائیں۔ اگر عام ssh کے ذریعے بھی رسائی حاصل نہ ہو تو مسئلہ Ansible کی سطح سے نیچے ہے، اور playbook کا کوئی keyword اسے درست نہیں کر سکتا۔
  4. msg string پڑھیں اور اسے اوپر دی گئی فہرست سے ملائیں۔ Connection refused اور Connection timed out دو مختلف مقامات کی طرف اشارہ کرتے ہیں؛ ایک SSH service اور دوسرا network path ہے۔
  5. Host key verification failed. کے لیے دیکھیں کہ آپ نے ssh-keygen -F web2.example.com کے ساتھ کیا محفوظ کر رکھا ہے۔ اگر server دوبارہ بنایا گیا تھا تو ssh-keygen -R web2.example.com کے ساتھ پرانی entry حذف کریں، پھر provider console سے تصدیق کرنے کے بعد نئی key قبول کریں۔ host_key_checking = False کو ansible.cfg میں مقرر کرنے سے error ختم ہو جاتا ہے، لیکن وہ check بھی ختم ہو جاتا ہے جو یہ بتا سکتا تھا کہ اس address پر اب کوئی مختلف machine جواب دے رہی ہے۔
  6. Permission denied (publickey) کے لیے تصدیق کریں کہ Ansible کے مطابق کون سی چیز استعمال ہونی چاہیے۔ ansible-inventory -i inventory.ini --host web2 مؤثر variables دکھاتا ہے، جن میں ansible_user اور ansible_port شامل ہیں۔
  7. اگر SSH کام کرتا ہو لیکن modules کام نہ کریں تو ansible web2 -m ansible.builtin.raw -a 'command -v python3 || echo none' کے ساتھ interpreter چیک کریں۔ raw module shell کے ذریعے command چلاتا ہے اور target پر python کی ضرورت نہیں ہوتی۔

اس کے بعد ہی host کو نظرانداز کرنا عادت کے بجائے ایک سوچا سمجھا فیصلہ بنتا ہے۔

Recap میں unreachable کو الگ شمار کیا جاتا ہے، اور CI عموماً اسے نظر انداز کر دیتا ہے

ansible-playbook کامیابی پر 0، کم از کم ایک host کے fail ہونے پر 2، اور کم از کم ایک host کے unreachable ہونے پر 4 کے ساتھ ختم ہوتا ہے۔ یہ دونوں values source میں bit flags ہیں، اس لیے failed host اور unreachable host والی run کا exit code 6 ہوتا ہے۔ ansible command بھی یہی codes واپس کرتا ہے۔ ان کی تصدیق August 2026 میں ansible-core source کے ذریعے کی گئی تھی۔

اب ignore_unreachable: true set کریں اور اسی dead host کے خلاف وہی سات task والا play چلائیں:

PLAY RECAP *********************************************************************
web1  : ok=7  changed=2  unreachable=0  failed=0  skipped=0  rescued=0  ignored=0
web2  : ok=7  changed=0  unreachable=0  failed=0  skipped=0  rescued=0  ignored=7

web2، unreachable=0 اور سات tasks کے لیے ok report کرتا ہے، اور run کا exit code 0 ہوتا ہے۔ keyword set ہونے پر Ansible اس host کے لیے ok اور ignored counters میں اضافہ کرتا ہے، اس counter کے بجائے جسے وہ dark کہتا ہے اور جو unreachable column کو پُر کرتا ہے۔ سرخ UNREACHABLE! lines پھر بھی print ہوتی ہیں، اس لیے log درست صورتِ حال دکھاتا ہے، لیکن recap اور exit code نہیں۔

جو CI job playbook چلا کر صرف $? check کرتی ہے، وہ اس run کو کامیاب سمجھتی ہے۔ اس کے summary میں یہ ظاہر نہیں ہوتا کہ کسی machine سے کبھی رابطہ نہیں کیا گیا۔ reachability check کو play سے پہلے ایک الگ step بنائیں:

ansible all -i inventory.ini -m ansible.builtin.ping -o

یہ ہر host کے لیے ایک line print کرتا ہے اور اگر کوئی host unreachable ہو تو 4 کے ساتھ exit ہوتا ہے۔ اس سے pipeline کے پاس fail ہونے کی بنیاد اور log میں host names دونوں آ جاتے ہیں۔ ping کو target پر working Python interpreter درکار ہوتا ہے، اس لیے یہ صرف connection کے مقابلے میں کچھ زیادہ چیز verify کرتا ہے، جو عموماً مطلوب ہوتا ہے۔ اس کے بعد playbook کو ignore_unreachable کے ساتھ چلائیں تاکہ جو hosts دستیاب ہیں، ان پر تبدیلی پھر بھی لاگو ہو جائے۔

any_errors_fatal اور max_fail_percentage کا batch پر اطلاق

یہ دونوں play keywords اس بات کا تعین کرتے ہیں کہ fleet کے کسی حصے میں خرابی کے بعد کیا ہوگا۔ یہ unreachable hosts کو ایک دوسرے سے مختلف طریقے سے handle کرتے ہیں۔

any_errors_fatal: true unreachable host پر بھی ردعمل دیتا ہے۔ Ansible batch کے باقی hosts پر موجودہ task مکمل کرتا ہے، پھر اس batch کے ہر host کے لیے play روک دیتا ہے۔ اسے اس وقت استعمال کریں جب run کا کامیاب ہونا مکمل طور پر یکساں نتیجے پر منحصر ہو، جیسے coordinated schema change۔

max_fail_percentage: 30 unreachable host پر ردعمل نہیں دیتا۔ یہ check failed hosts کی تعداد کو batch کے سائز سے تقسیم کرتا ہے۔ unreachable hosts الگ فہرست میں رکھے جاتے ہیں، اس لیے وہ اس تعداد میں شامل نہیں ہوتے۔ max_fail_percentage: 10 کے تحت دس hosts میں سے چار unreachable ہوں تو run جاری رہتا ہے، جبکہ دو hosts کے task میں fail ہونے پر play رک جاتا ہے۔ Documentation ایک اور اہم نکتہ بیان کرتی ہے: "The percentage set must be exceeded, not equaled." serial: 4 کے ساتھ چار میں سے دو failures کے بعد رکنے کے لیے 50 نہیں بلکہ 49 لکھنا ہوگا۔

ایک صورت میں unreachable hosts خود run روک دیتے ہیں۔ اگر batch کا ہر host failed یا unreachable ہو، تو Ansible کے پاس کام جاری رکھنے کے لیے کچھ نہیں رہتا اور وہ NO MORE HOSTS LEFT کے ساتھ play ختم کر دیتا ہے۔

فلیٹ میں تبدیلی مرحلہ وار نافذ کرنا

- name: Rolling nginx config update
  hosts: webservers
  serial: 2
  max_fail_percentage: 25
  tasks:
    - name: Deploy the site config
      ansible.builtin.template:
        src: site.conf.j2
        dest: /etc/nginx/conf.d/site.conf
        owner: root
        mode: "0644"
      become: true
      notify: Reload nginx
  handlers:
    - name: Reload nginx
      ansible.builtin.service:
        name: nginx
        state: reloaded
      become: true

serial: 2 پورا play دو hosts پر چلاتا ہے، اسے مکمل کرتا ہے، پھر اگلے دو hosts شروع کرتا ہے۔ serial: "25%" گروپ کے حجم کے مطابق بڑھتا ہے۔ ایک فہرست، serial: [1, 5, 10]، canary طریقہ ہے: پہلے ایک host، پھر پانچ، پھر دس؛ اس کے بعد باقی hosts آخری حجم کے batches میں چلتے ہیں۔ max_fail_percentage کی پیمائش ہر batch کے لحاظ سے ہوتی ہے، اس لیے دونوں مل کر کام کرتے ہیں۔ پہلے machine کو خراب کریں تو run چالیس machines کو متاثر کرنے سے پہلے رک جاتا ہے۔ اسی وجہ سے ایک control machine سے Linux servers کے فلیٹ کا انتظام ایک ہی command سے محفوظ طریقے سے کیا جا سکتا ہے۔

ناقابل رسائی hosts کو کب نظرانداز کریں، اور کب نہیں

موقع پر مبنی کاموں کے لیے انہیں نظرانداز کریں۔ Fact collection run یا فی گھنٹہ drift check میں اس host کو چھوڑ دینے سے کوئی نقصان نہیں ہوتا جو down ہو، کیونکہ اگلا pass اسے دوبارہ شامل کر لیتا ہے۔ یہاں play level ignore_unreachable: true درست طریقہ ہے۔ اسے ping step کے ساتھ استعمال کریں تاکہ چھوڑے گئے names ایسی جگہ درج ہوں جہاں کوئی شخص انہیں پڑھ سکے۔

Security patch run میں انہیں کبھی نظرانداز نہ کریں۔ اس run کی اہمیت اس ضمانت میں ہے کہ ہر host پر fix موجود ہے۔ Unreachable state کو suppress کرنے سے "ایک server اب بھی vulnerable ہے" ایک صاف green recap میں تبدیل ہو جاتا ہے۔ جو host دو ہفتوں سے unreachable ہے، اس کے بہت پیچھے رہ جانے کا امکان سب سے زیادہ ہے۔ اس run کو exit 4 کرنے دیں اور کسی شخص کو اس کا جائزہ لینے دیں۔

دونوں صورتوں میں ایک اصول لاگو ہوتا ہے: stop کو suppress کریں، record کو نہیں۔ اگر کسی host کو چھوڑا گیا ہے تو recap، CI log یا monitoring alert میں اس کا ذکر ہونا چاہیے۔ Ansible کو host کے موجود ہونے کا صرف اسی وقت علم ہوتا ہے جب play اس کے خلاف چل رہا ہو۔ اس لیے یہ جاننے کے لیے Ansible ناقص جگہ ہے کہ کوئی server منگل سے down ہے۔ یہ کام monitoring کا ہے، اور Zabbix انسٹال کرنے والا Ansible playbook ایک دوپہر میں پورے fleet کا view فراہم کر دیتا ہے۔

FAQ

ignore_errors اور ignore_unreachable میں Ansible کے اندر کیا فرق ہے؟

ignore_errors: true اس task پر لاگو ہوتا ہے جو host پر چلا اور failure واپس کیا، مثلاً command نے non-zero exit code کے ساتھ ختم کیا۔ ignore_unreachable: true اس host پر لاگو ہوتا ہے جس سے Ansible connect نہیں کر سکا، جہاں کوئی module چلا ہی نہیں۔ یہ دونوں task result کے مختلف fields پڑھتے ہیں، اور ان میں سے کوئی بھی دوسرے case کا احاطہ نہیں کرتا۔ Ansible documentation کے مطابق ignore_errors "Ansible کو undefined variable errors، connection failures، execution issues (مثلاً missing packages)، یا syntax errors کو نظرانداز کرنے پر مجبور نہیں کرتا"، اور بند SSH port ایک connection failure ہے۔

کیا ignore_unreachable host کو play recap سے چھپا دیتا ہے؟

عملاً ہاں۔ یہ keyword set ہونے پر Ansible اس host کو unreachable کے تحت شمار کرنا بند کر دیتا ہے اور ہر task کے لیے اسے ok اور ignored کے طور پر شمار کرتا ہے، پھر run 0 کے ساتھ ختم ہوتا ہے۔ fatal: [host]: UNREACHABLE! lines پھر بھی print ہوتی ہیں، اس لیے log درست رہتا ہے، اگرچہ recap اور exit code درست صورت حال نہیں دکھاتے۔ ignored column دیکھیں، یا ansible all -m ansible.builtin.ping -o کو الگ step کے طور پر چلائیں تاکہ unreachable host کہیں نہ کہیں non-zero exit code ضرور پیدا کرے۔

جب host unreachable ہو تو ansible-playbook کون سا exit code واپس کرتا ہے؟

یہ 4 واپس کرتا ہے۔ کم از کم ایک failed host والے run کا exit code 2 ہوتا ہے، اور یہ دونوں values bit flags ہیں، اس لیے failure اور unreachable host دونوں والے run کا exit code 6 ہوتا ہے۔ کامیاب run 0 واپس کرتا ہے۔ ان codes کی تصدیق August 2026 میں ansible-core source کے خلاف کی گئی تھی۔ ignore_unreachable: true set کرنے سے 4 ختم ہو جاتا ہے، اسی لیے جو pipeline صرف exit code test کرتی ہے وہ skipped machine کا پتا نہیں چلا سکتی۔

میں ایسے host کے لیے play کا باقی حصہ کیسے skip کروں جس نے کبھی جواب نہیں دیا؟

پہلا task ansible.builtin.ping بنائیں، جس میں ignore_unreachable: true اور register: reachable ہوں، پھر اس کے بعد ansible.builtin.meta: end_host کو when: reachable.unreachable | default(false) condition کے تحت رکھیں۔ end_host اس host کے لیے play ختم کر دیتا ہے، مگر اسے failed mark نہیں کرتا۔ play پر gather_facts: false set کریں تاکہ broken connection کا سامنا کرنے والا task آپ کا ping ہو۔ اس pattern کے بغیر dead host play میں موجود رہتا ہے، اور ہر بعد والا task دوبارہ connection timeout تک انتظار کرتا ہے۔

کیا security patch run کے دوران unreachable hosts کو ignore کرنا چاہیے؟

نہیں۔ Patch run کا مقصد یہ یقین حاصل کرنا ہے کہ ہر host پر update موجود ہے، جبکہ unreachable hosts کو ignore کرنے سے یہ یقین ایک green recap سے بدل جاتا ہے۔ Run کو 4 کے ساتھ ختم ہونے دیں، ان hosts کے نام پڑھیں جنہوں نے جواب نہیں دیا، اور مسئلہ حل کریں۔ Suppression ان بار بار چلنے والے opportunistic runs کے لیے مناسب ہے جہاں اگلا pass پچھلی بار رہ جانے والے hosts کو شامل کر لے گا۔

#ansible#playbooks#error-handling#inventory#automation