أتمتة الشبكة مع Ansible: وحدة القيادة

عند الحديث عن السيناريوهات النموذجية لأتمتة الشبكة ، لا يمكن للمرء الاستغناء عن مجموعة من وحدات الأوامر. بفضل هذه الوحدات ، يتيح لك Ansible تشغيل الأوامر على أجهزة الشبكة كما لو كنت تدخلها مباشرة من وحدة التحكم. في الوقت نفسه ، لا ينزلق إخراج الأوامر في نافذة المحطة الطرفية لتغرق في غياهب النسيان ، ولكن يمكن حفظها واستخدامها في المستقبل. يمكن كتابتها في متغيرات أو تحليلها للاستخدام في المهام اللاحقة أو حفظها في المستقبل في متغيرات المضيف.



الهدف من هذا المنشور هو إظهار أنه يمكن أتمتة أي مهمة متكررة لإدارة الشبكة ، وأن Ansible لا يسمح لك فقط بإدارة التكوينات ، ولكن يساعد أيضًا في التخلص من الروتين وتوفير الوقت.

دعنا نحلل الطرق الأساسية لاستخدام وحدات أمر الشبكة ، بما في ذلك حفظ مخرجات الأوامر باستخدام معلمة التسجيل. نضع في الاعتبار أيضًا كيفية القياس على أجهزة شبكة متعددة باستخدام hostvars وكيفية تنظيم التنفيذ الشرطي باستخدام المعلمة wait_for وثلاثة معلمات أخرى ذات صلة: الفاصل الزمني وإعادة المحاولة والمطابقة.

تحتوي منصات الشبكات المختلفة على وحدات قيادة خاصة بها ، وكلها مدعومة بمستوى ملحق الوظيفة الإضافية Red Hat Ansible Engine Networking:

منصات الشبكةوحدات * os_command
أريستا eoseos_command
Cisco IOS / IOS-XEios_command
Cisco IOS-XRiosxr_command
Cisco NX-OSnxos_command
جونيبر جونوسjunos_command
فيوسvyos_command

أساسيات وحدة القيادة


ضع في اعتبارك كتاب قواعد تشغيل يقوم بتشغيل أمر show version باستخدام الوحدة النمطية eos_command:

--- - name: COMMAND MODULE PLAYBOOK hosts: eos connection: network_cli tasks: - name: EXECUTE ARISTA EOS COMMAND eos_command: commands: show version register: output - name: PRINT OUT THE OUTPUT VARIABLE debug: var: output 

هنا لدينا مهمتان ، الأول يستخدم وحدة eos_command مع معلمة أوامر واحدة. نظرًا لأننا نقوم بتشغيل إصدار واحد فقط لإظهار الأوامر - يمكن تحديده في نفس السطر كمعلمة الأوامر نفسها. إذا كان هناك فريقان أو أكثر ، فيجب وضع كل فريق على سطر منفصل بعد الأوامر:. في هذا المثال ، نستخدم كلمة أساسية للتسجيل لحفظ مخرجات الأمر show version. تقوم معلمة التسجيل (يمكن استخدامها في أي مهمة Ansible) بتعيين المتغير حيث سيتم حفظ مخرجات مهمتنا بحيث يمكن استخدامها لاحقًا. في مثالنا ، هذا المتغير يسمى الإخراج.

المهمة الثانية في مثالنا تستخدم وحدة تصحيح الأخطاء لعرض محتويات متغير الإخراج المنشأ حديثًا. بمعنى ، هذه هي نفس البيانات التي ستراها على واجهة سطر الأوامر على جهاز EOS إذا أدخلت "show version" هناك. الفرق هو أن قواعد اللعبة التي نوفرها ستعرضها في نافذة المحطة التي تقوم بتشغيلها عليها. كما ترى ، فإن وحدة تصحيح الأخطاء تجعل من السهل التحقق من متغيرات Ansible.

هنا هو إخراج playbook لدينا:

 PLAY [eos] ************************************************************************* TASK [execute Arista eos command] ************************************************** ok: [eos] TASK [print out the output variable] *********************************************** ok: [eos] => { "output": { "changed": false, "failed": false, "stdout": [ "Arista vEOS\nHardware version: \nSerial number: \nSystem MAC address: 0800.27ec.005e\n\nSoftware image version: 4.20.1F\nArchitecture: i386\nInternal build version: 4.20.1F-6820520.4201F\nInternal build ID: 790a11e8-5aaf-4be7-a11a-e61795d05b91\n\nUptime: 1 day, 3 hours and 23 minutes\nTotal memory: 2017324 kB\nFree memory: 1111848 kB" ], "stdout_lines": [ [ "Arista vEOS", "Hardware version: ", "Serial number: ", "System MAC address: 0800.27ec.005e", "", "Software image version: 4.20.1F", "Architecture: i386", "Internal build version: 4.20.1F-6820520.4201F", "Internal build ID: 790a11e8-5aaf-4be7-a11a-e61795d05b91", "", "Uptime: 1 day, 3 hours and 23 minutes", "Total memory: 2017324 kB", "Free memory: 1111848 kB" ] ] } } PLAY RECAP ************************************************************************* eos : ok=2 changed=0 unreachable=0 failed=0 

كما يتضح من لقطة الشاشة ، تم تنفيذ كل من مهامنا بنجاح. نظرًا لأن المهمة الأولى تستخدم المستوى الافتراضي من التفاصيل للرسائل ، فإنها تشير ببساطة إلى أن مضيف eos أكمل المهمة وكانت النتيجة جيدة ، مع التركيز على نجاح التنفيذ باللون الأخضر. المهمة الثانية ، مع وحدة تصحيح الأخطاء ، تقوم بإرجاع إخراج الأمر الذي يتم تنفيذه ، مع عرض نفس المعلومات بتنسيقين:

  • stdout
  • stdout_lines

يُظهر قسم stdout نفس الشيء الذي ستراه في واجهة سطر الأوامر على الجهاز ، ولكن في شكل سطر طويل واحد. وقسم stdout_lines يقسم هذا الإخراج إلى خطوط بحيث تكون مريحة للقراءة. كل عنصر في هذه القائمة هو سطر منفصل في إخراج الأمر.

قارن إخراج الأمر على الجهاز وفي Ansible:

خرج الفريق في Arista EOSstdout_lines في Ansible
eos> عرض مقابل
أريستا فيوس
نسخة الأجهزة:
الرقم التسلسلي:
عنوان MAC للنظام: 0800.27ec.005e

إصدار صورة البرنامج: 4.20.1F
العمارة: i386
إصدار البنية الداخلية: 4.20.1F-6820520.4201F
معرف البنية الداخلية: 790a11e8-5aaf-4be7-a11a-e61795d05b91

مدة التشغيل: يوم واحد و 3 ساعات و 56 دقيقة
إجمالي الذاكرة: 2017324 كيلو بايت
ذاكرة حرة: 1116624 كيلو بايت
"Stdout_lines": [
[
"Arista vEOS" ،
"إصدار الأجهزة:" ،
"الرقم التسلسلي:" ،
"عنوان MAC للنظام: 0800.27ec.005e" ،
"" ،
"إصدار صورة البرنامج: 4.20.1F" ،
"العمارة: i386" ،
"إصدار البنية الداخلية:
4.20.1F-6820520.4201F "،
"معرف البنية الداخلية:
790a11e8-5aaf-4be7-a11a-e61795d05b91 "،
"" ،
"مدة التشغيل: يوم واحد و 3 ساعات و 23 دقيقة" ،
"إجمالي الذاكرة: 2017324 كيلو بايت" ،
"ذاكرة مجانية: 1111848 كيلو بايت"
]

إذا كنت معتادًا على JSON و YAML ، فمن المحتمل أنك قد لاحظت بالفعل غرابة واحدة: يبدأ stdout_lines بين قوسين مفتوحين:

 "stdout_lines": [ [ 

تشير أقواس فتح اثنين إلى أن stdout_lines تُرجع فعليًا قائمة قوائم الخطوط. إذا قمت بتعديل مهمة التصحيح بشكل بسيط ، فيمكن استخدام هذه الشريحة لعرض نتائج الأمر بشكل انتقائي. نظرًا لوجود قائمة واحدة فقط من الأسطر في قائمتنا ، تسمى هذه القائمة "صفر" (في الواقع ، إنها الأولى ، لكن العدد يبدأ من الصفر). لنرى الآن كيفية استخراج سطر منفصل منه ، على سبيل المثال ، عنوان MAC System. في إخراج الأمر ، هذا السطر هو الرابع على التوالي ، ولكن بما أننا نعول من نقطة الصفر ، فنحن نحتاج في النهاية إلى السطر 3 من القائمة 0 ، وبمعنى آخر: output.stdout_lines [0] [3].

  - name: print out a single line of the output variable debug: var: output.stdout_lines[0][3]   debug-   : TASK [print out a single line of the output variable] ****************************** ok: [eos] => { "output.stdout_lines[0][3]": "System MAC address: 0800.27ec.005e" } 

ما هي نقطة ترقيم القائمة ولماذا هي ضرورية؟ الحقيقة هي أنه في نفس المهمة ، يمكنك إدارة عدة فرق ، على سبيل المثال ، مثل هذا (هنا لدينا ثلاثة فرق):

 --- - hosts: eos connection: network_cli tasks: - name: execute Arista eos command eos_command: commands: - show version - show ip int br - show int status register: output - name: print out command debug: var: output.stdout_lines 

إليك ما يبدو عليه الإخراج:

  "output.stdout_lines": [ [ "Arista vEOS", "Hardware version: ", "Serial number: ", "System MAC address: 0800.27ec.005e", "", "Software image version: 4.20.1F", "Architecture: i386", "Internal build version: 4.20.1F-6820520.4201F", "Internal build ID: 790a11e8-5aaf-4be7-a11a-e61795d05b91", "", "Uptime: 1 day, 4 hours and 20 minutes", "Total memory: 2017324 kB", "Free memory: 1111104 kB" ], [ "Interface IP Address Status Protocol MTU", "Ethernet1 172.16.1.1/24 up up 1500", "Management1 192.168.2.10/24 up up 1500" ], [ "Port Name Status Vlan Duplex Speed Type Flags", "Et1 connected routed full unconf EbraTestPhyPort ", "Et2 connected 1 full unconf EbraTestPhyPort ", "Et3 connected 1 full unconf EbraTestPhyPort ", "Ma1 connected routed a-full a-1G 10/100/1000" ] ] 

هنا ، رقم القائمة صفر هو إخراج الأمر show version ، والقائمة رقم واحد هي show show int الإخراج ، والقائمة رقم 2 هي إخراج show int status. أي ، يتم تحديد رقم القائمة حسب الترتيب الذي يتم به تنفيذ الأوامر.

فرق أريستا EOSمطابقة قوائم الإخراج
عرض الإصدارoutput.stdout_lines [0]
إظهار الملكية الفكرية رoutput.stdout_lines [1]
تظهر حالة كثافة العملياتoutput.stdout_lines [2]

تحجيم وحدة الأوامر: متغيرات المضيف


وماذا يحدث إذا قمت بتشغيل playbook على العديد من الأجهزة في نفس الوقت؟



لتكون فريدة من نوعها ، يتم تخزين متغير الإخراج كمتغير مضيف لكل مضيف في المخزون. إذا كان لدينا ثلاثة مفاتيح ، وقمنا بتشغيل قواعد اللعب لدينا عليها ، فسنحصل على متغير الإخراج لكل مضيف فريد. لنفترض أننا بحاجة إلى عنوان IP من أمر show ip int br لمنفذ Ethernet1 على switch03. نظرًا لأن show ip int br هو الأمر الثاني الذي يتم تشغيله كجزء من المهمة ، والبيانات الموجودة على Ethernet1 مضمنة في السطر الثاني من ناتجها ، سنحتاج إلى كتابة stdout_lines [1] [1]. للوصول إلى متغيرات مضيف معين ، نستخدم الكلمة الأساسية hostvars والبحث عن المضيف الذي نحتاجه بالاسم.

إليك كيفية القيام بذلك:

  - name: debug hostvar debug: var: hostvars["switch03"].output.stdout_lines[1][1] 

نتيجة لذلك ، يحتوي الإخراج على ما نحتاج إليه بالضبط:

 TASK [debug hostvar] *************************************************************** ok: [switch03] => { "hostvars[\"switch03\"].output.stdout_lines[1][1]": "Ethernet1 172.16.1.3/24 up up 1500" } 

بشكل افتراضي ، تستخدم المهمة متغيرات المضيف الحالي ، ولكن تتيح لك hostvars الوصول مباشرة إلى متغيرات مضيف آخر.

الشروط في المهام مع وحدات القيادة: wait_for المعلمة


تسمح لك المعلمة wait_for بتنفيذ فحص شرط فور تنفيذ الأمر. على سبيل المثال ، لجعل المهمة تعتبر مكتملة بنجاح فقط إذا كان ناتج أمر check status يحتوي على نص معين. بشكل افتراضي ، لا يتم استخدام المعلمة wait_for ، لذلك يتم تشغيل المهمة مرة واحدة فقط ، كما في الأمثلة أعلاه. ولكن إذا قمت بتعيينها بشكل صريح ، فسيتم إعادة تشغيل المهمة حتى يتم استيفاء الشرط أو يتم تجاوز حد المحاولات (هناك 10 بشكل افتراضي). إذا قمت بتمكين تسجيل الأوامر ، يمكنك أن ترى أنه في كتاب اللعب أدناه (والذي تم كتابته خصيصًا بحيث لا يتم الاحتفاظ بالشرط) ، يحدث كل شيء على هذا النحو.

 --- - hosts: eos connection: network_cli tasks: - name: execute Arista eos command eos_command: commands: - show int status wait_for: - result[0] contains DURHAM 

سيتم تشغيل playbook هذا الأمر show int status 10 مرات ، لأن ناتجه لن يحتوي أبدًا على خط DURHAM.

يمكنك التحقق من ذلك باستخدام أمر show logging:

 Mar 24 20:33:52 eos Aaa: %ACCOUNTING-6-CMD: admin vty6 192.168.2.1 stop task_id=17 start_time=1521923632.5 timezone=UTC service=shell priv-lvl=15 cmd=show interfaces status Mar 24 20:33:53 eos Aaa: %ACCOUNTING-6-CMD: admin vty6 192.168.2.1 stop task_id=18 start_time=1521923633.71 timezone=UTC service=shell priv-lvl=15 cmd=show interfaces status Mar 24 20:33:54 eos Aaa: %ACCOUNTING-6-CMD: admin vty6 192.168.2.1 stop task_id=19 start_time=1521923634.81 timezone=UTC service=shell priv-lvl=15 cmd=show interfaces status Mar 24 20:33:55 eos Aaa: %ACCOUNTING-6-CMD: admin vty6 192.168.2.1 stop task_id=20 start_time=1521923635.92 timezone=UTC service=shell priv-lvl=15 cmd=show interfaces status Mar 24 20:33:56 eos Aaa: %ACCOUNTING-6-CMD: admin vty6 192.168.2.1 stop task_id=21 start_time=1521923636.99 timezone=UTC service=shell priv-lvl=15 cmd=show interfaces status Mar 24 20:33:58 eos Aaa: %ACCOUNTING-6-CMD: admin vty6 192.168.2.1 stop task_id=22 start_time=1521923638.07 timezone=UTC service=shell priv-lvl=15 cmd=show interfaces status Mar 24 20:33:59 eos Aaa: %ACCOUNTING-6-CMD: admin vty6 192.168.2.1 stop task_id=23 start_time=1521923639.22 timezone=UTC service=shell priv-lvl=15 cmd=show interfaces status Mar 24 20:34:00 eos Aaa: %ACCOUNTING-6-CMD: admin vty6 192.168.2.1 stop task_id=24 start_time=1521923640.32 timezone=UTC service=shell priv-lvl=15 cmd=show interfaces status Mar 24 20:34:01 eos Aaa: %ACCOUNTING-6-CMD: admin vty6 192.168.2.1 stop task_id=25 start_time=1521923641.4 timezone=UTC service=shell priv-lvl=15 cmd=show interfaces status Mar 24 20:34:02 eos Aaa: %ACCOUNTING-6-CMD: admin vty6 192.168.2.1 stop task_id=26 start_time=1521923642.47 timezone=UTC service=shell priv-lvl=15 cmd=show interfaces status 

الآن دعونا نلقي نظرة على مثال للكتاب التشغيل الحقيقي الذي تم تكوين كل شيء فيه لإنشاء حي OSPF (المجاور) مع جهاز آخر غير أمر ip ospf area. سنستخدم هذا الأمر ثم نستخدم المعلمة wait_for للتحقق من وجود الكلمة FULL في الإخراج: إذا كان هناك ، فقد تم إنشاء الحي بنجاح. إذا لم يظهر FULL في 10 محاولات ، فستفشل المهمة.

 --- - hosts: eos connection: network_cli tasks: - name: turn on OSPF for interface Ethernet1 eos_config: lines: - ip ospf area 0.0.0.0 parents: interface Ethernet1 - name: execute Arista eos command eos_command: commands: - show ip ospf neigh wait_for: - result[0] contains FULL 

قم بتشغيل playbook هذا باستخدام الأمر ansible-playbook:

 ➜ ansible-playbook ospf.yml PLAY [eos] ********************************************************************************************* TASK [turn on OSPF for interface Ethernet1] ******************************************************* changed: [eos] TASK [execute Arista eos command] **************************************************************** ok: [eos] PLAY RECAP ****************************************************************************************** eos : ok=2 changed=1 unreachable=0 failed=0 

ننظر إلى سطر الأوامر ونرى أن كتاب اللعب كان ناجحًا:

 eos#show ip ospf neigh Neighbor ID VRF Pri State Dead Time Address Interface 2.2.2.2 default 1 FULL/DR 00:00:33 172.16.1.2 Ethernet1 

بالإضافة إلى يحتوي على ، يمكنك استخدام عوامل المقارنة التالية:

  • مكافئ: - يساوي
  • neq: - ليست متساوية
  • GT: - أكثر من ذلك
  • ge: - أكبر من أو يساوي
  • لتر: - أقل
  • le: - أقل من أو يساوي

بالإضافة إلى ذلك ، مع wait_for ، يمكنك استخدام ثلاث معلمات إضافية (موصوفة بالتفصيل في وثائق الوحدات):

المعلمةالوصف
الفاصل الزمنيالوقت بين التكرار للفريق.
إعادة المحاولةماكس عدد مرات التكرار قبل اكتمال المهمة مع وجود خطأ ، أو استيفاء الشرط.
المباراةصدفة جميع الظروف أو واحدة على الأقل.

دعنا نتناول بمزيد من التفصيل معلمة المطابقة:

  - name: execute Arista eos command eos_command: commands: - show ip ospf neigh match: any wait_for: - result[0] contains FULL - result[0] contains 172.16.1.2 

عند التطابق: تم تحديد أي ، تعتبر المهمة ناجحة إذا كانت النتيجة تحتوي على FULL أو 172.16.1.2. إذا كانت المطابقة: تم تحديد الكل ، فيجب أن تحتوي النتيجة على FULL و 172.16.1.2. بشكل افتراضي ، يتم استخدام المطابقة: الكل ، لأنه إذا وصفت عدة شروط ، فمن المرجح أنك تريد أن تتحقق جميعها ، ولكن ليس شرط واحد على الأقل.

متى يمكن أن تطابق: أي تأتي في متناول اليدين؟ افترض أنك بحاجة إلى التحقق من أن مركز البيانات لديه اتصال ثنائي الاتجاه بالإنترنت. ويتصل مركز البيانات بخمسة مزودي إنترنت مختلفين ، ولكل منهم اتصال BGP خاص به. يمكن لقواعد اللعبة أن تتحقق من كل هذه الاتصالات الخمسة ، وإذا كان هناك واحد على الأقل يعمل ، وليس كل خمسة ، فأبلغ أن كل شيء في وضع جيد. فقط تذكر أن أيًا هو منطقي OR ، وكل ما هو منطقي AND.

المعلمةالوصف
المباراة: أيمنطقي "OR"
شرط واحد على الأقل مطلوب
المباراة: الكلمنطقية "و"
جميع الشروط المطلوبة

الظروف السلبية: بناء المنطق العكسي


من المهم في بعض الأحيان ليس ما هو في الخلاصة ، ولكن ما هو غير موجود. هنا ، بالطبع ، من المغري دائمًا استخدام عامل المقارنة neq ، ولكن بالنسبة لبعض السيناريوهات ذات الظروف السلبية ، هناك خيارات أفضل. على سبيل المثال ، إذا كنت بحاجة إلى عكس العبارة التي تحتوي على (من النوع ، "يجب ألا يحتوي مخرجات الأمر على هذا القبيل") ، يمكنك استخدام الكلمة الأساسية للتسجيل لحفظ المخرجات ، ثم معالجتها في المهمة التالية باستخدام التعبير عند . أو ، على سبيل المثال ، عندما تحتاج إلى إيقاف playbook إذا لم يتم استيفاء الشروط ، استخدم ببساطة الوحدات النمطية للفشل أو التأكيد للخروج بشكل خاص من الخطأ. بالنسبة إلى عامل المقارنة neq ، يكون مفيدًا فقط عندما يمكنك استخراج القيمة الدقيقة من الإخراج (على سبيل المثال ، من زوج قيمة المفتاح أو من JSON) ، وليس فقط سلسلة أو قائمة سلاسل. خلاف ذلك ، سيتم تنفيذ مقارنة سلاسل الأحرف.

ما التالي


اقرأ الوثائق المتعلقة بالعمل مع إخراج الأوامر في وحدات الشبكة. يوفر أمثلة مفيدة لاستخدام ge و le وشروط أخرى عند العمل مع إخراج تنسيق JSON على منصات شبكة محددة.

Source: https://habr.com/ru/post/ar438312/


All Articles