التعليمات: كيفية اختبار الأدوار غير المرغوبة ومعرفة المشاكل قبل الإنتاج

مرحبا بالجميع!

أعمل كمهندس DevOps في خدمة حجز الفنادق. Ostrovok.ru. في هذا المقال ، أريد أن أتحدث عن تجربتنا في اختبار الأدوار غير الصالحة.

في Ostrovok.ru ، نستخدم ansible كمدير تكوين. في الآونة الأخيرة ، توصلنا إلى الحاجة إلى اختبار الأدوار ، ولكن كما اتضح ، لا يوجد الكثير من الأدوات لهذا - ربما يكون أكثرها شيوعًا هو إطار عمل الجزيء ، لذلك قررنا استخدامه. لكن اتضح أن وثائقه صامتة بشأن العديد من المزالق. لم نتمكن من العثور على دليل مفصل بما فيه الكفاية باللغة الروسية ، لذلك قررنا كتابة هذه المقالة.

التعليمات: كيفية اختبار الأدوار غير المرغوبة ومعرفة المشاكل قبل الإنتاج

مركب

مركب - إطار عمل للمساعدة في اختبار الأدوار الثابتة.

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

الآن التفاصيل.

بعض نظرية

ضع في اعتبارك كيانين رئيسيين للجزيء: السيناريو والمحرك.

سيناريو

يحتوي النص على وصف لما سيتم تنفيذه وأين وكيف وبأي تسلسل. يمكن أن يكون لدور واحد عدة نصوص ، وكل منها عبارة عن دليل على طول المسار <role>/molecule/<scenario>، الذي يحتوي على أوصاف للإجراءات المطلوبة للاختبار. يجب تضمين البرنامج النصي default، والذي سيتم إنشاؤه تلقائيًا إذا قمت بتهيئة الدور باستخدام جزيء. أسماء النصوص التالية متروكة لك.

تسلسل إجراءات الاختبار في البرنامج النصي يسمى البخور، وهي بشكل افتراضي:

(الخطوات المسمى ?، يتم تخطيه افتراضيًا إذا لم يحدده المستخدم)

  • lint - تشغيل الوبر. يتم استخدامها بشكل افتراضي yamllint и flake8,
  • destroy - حذف مثيلات من الإطلاق الأخير للجزيء (إن وجد) ،
  • dependency؟ - تثبيت التبعية الثابتة للدور الذي تم اختباره ،
  • syntax - التحقق من صياغة الدور باستخدام ansible-playbook --syntax-check,
  • create - إنشاء مثيل ،
  • prepare؟ - إعداد المثيل ؛ على سبيل المثال تحقق / ثبت python2
  • converge - إطلاق كتاب قواعد اللعبة قيد الاختبار ،
  • idempotence - إعادة تشغيل كتاب قواعد اللعبة لاختبار العاطفة ،
  • side_effect؟ - الإجراءات التي لا تتعلق مباشرة بالدور ، ولكنها ضرورية للاختبارات ،
  • verify - تشغيل اختبارات التكوين الناتج باستخدام testinfra(تقصير) /goss/inspec,
  • cleanup؟ - (في الإصدارات الجديدة) - بشكل تقريبي ، "تنظيف" البنية التحتية الخارجية المتأثرة بالجزيء ،
  • destroy - حذف مثيل.

يغطي هذا التسلسل معظم الحالات ، ولكن يمكن تغييره إذا لزم الأمر.

يمكن تشغيل كل خطوة من الخطوات المذكورة أعلاه بشكل منفصل باستخدام molecule <command>. ولكن يجب أن يكون مفهوماً أنه لكل أمر cli قد يكون هناك تسلسل خاص به من الإجراءات ، والذي يمكنك اكتشافه من خلال تنفيذ molecule matrix <command>. على سبيل المثال ، عند تشغيل الأمر converge (تشغيل الكتيب قيد الاختبار) ، سيتم تنفيذ الإجراءات التالية:

$ molecule matrix converge
...
└── default         # название сценария
    ├── dependency  # установка зависимостей
    ├── create      # создание инстанса
    ├── prepare     # преднастройка инстанса
    └── converge    # прогон плейбука

يمكن تحرير تسلسل هذه الإجراءات. إذا تم تنفيذ شيء ما من القائمة بالفعل ، فسيتم تخطيه. الحالة الحالية ، بالإضافة إلى تكوين المثيلات ، يخزن الجزيء في الدليل $TMPDIR/molecule/<role>/<scenario>.

أضف الخطوات مع ? يمكنك وصف الإجراءات المرغوبة بتنسيق دليل التشغيل غير القابل للكسر ، وإنشاء اسم الملف وفقًا للخطوة: prepare.yml/side_effect.yml. توقع هذه الملفات سيكون الجزيء في مجلد البرنامج النصي.

سائق

السائق هو كيان يتم فيه إنشاء مثيلات الاختبار.
قائمة برامج التشغيل القياسية التي يحتوي Molecule على قوالب جاهزة لها هي كما يلي: Azure و Docker و EC2 و GCE و LXC و LXD و OpenStack و Vagrant و Delegated.

في معظم الحالات ، تكون القوالب عبارة عن ملفات create.yml и destroy.yml في مجلد البرنامج النصي الذي يصف إنشاء وحذف مثيل ، على التوالي.
الاستثناءات هي Docker و Vagrant ، حيث يمكن أن تحدث تفاعلات مع الوحدات النمطية الخاصة بهم بدون الملفات المذكورة أعلاه.

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

المشغل الافتراضي هو Docker.

الآن دعنا ننتقل إلى التدريب والنظر في المزيد من الميزات هناك.

الشروع في العمل

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

دعونا نستعد virtualenv وتثبيته فيه molecule:

> pip install virtualenv
> virtualenv -p `which python2` venv
> source venv/bin/activate
> pip install molecule docker  # molecule установит ansible как зависимость; docker для драйвера

الخطوة التالية هي تهيئة الدور الجديد.
يتم إجراء تهيئة دور جديد ، بالإضافة إلى نص جديد ، باستخدام الأمر molecule init <params>:

> molecule init role -r nginx
--> Initializing new role nginx...
Initialized role in <path>/nginx successfully.
> cd nginx
> tree -L 1
.
├── README.md
├── defaults
├── handlers
├── meta
├── molecule
├── tasks
└── vars

6 directories, 1 file

اتضح دور نموذجي غير مرغوب فيه. علاوة على ذلك ، يتم إجراء جميع التفاعلات مع جزيئات CLI من جذر الدور.

دعونا نرى ما هو موجود في دليل الدور:

> tree molecule/default/
molecule/default/
├── Dockerfile.j2  # Jinja-шаблон для Dockerfile
├── INSTALL.rst.   # Немного информации об установке зависимостей сценария
├── molecule.yml   # Файл конфигурации
├── playbook.yml   # Плейбук запуска роли
└── tests          # Директория с тестами стадии verify
    └── test_default.py

1 directory, 6 files

دعنا نحلل ملف config molecule/default/molecule.yml (استبدل صورة عامل الإرساء فقط):

---
dependency:
  name: galaxy
driver:
  name: docker
lint:
  name: yamllint
platforms:
  - name: instance
    image: centos:7
provisioner:
  name: ansible
  lint:
    name: ansible-lint
scenario:
  name: default
verifier:
  name: testinfra
  lint:
    name: flake8

التبعية

يصف هذا القسم مصدر التبعيات.

الخيارات الممكنة: Galaxy, مذهب، صدَفَة.

شل هو مجرد قذيفة أوامر يتم استخدامها في حالة عدم تغطية galaxy و gilt لاحتياجاتك.

لن أسكن هنا لفترة طويلة ، يكفي وصفها في توثيق.

سائق

اسم السائق. بلدنا عامل ميناء.

الوبر

اللنتر هو yamllint.

الخيارات المفيدة في هذا الجزء من التكوين هي القدرة على تحديد ملف تكوين لـ yamllint أو متغيرات البيئة إلى الأمام أو تعطيل linter:

lint:
  name: yamllint
  options:
    config-file: foo/bar
  env:
    FOO: bar
  enabled: False

منصات

يصف تكوين الحالات.
في حالة عامل الإرساء كسائق ، يتم تكرار الجزيء فوق هذا القسم ، ويتوفر كل عنصر من عناصر القائمة في Dockerfile.j2 كمتغير item.

في حالة وجود سائق يتطلب create.yml и destroy.yml، القسم متوفر فيها كـ molecule_yml.platforms، والتكرارات عليها موصوفة بالفعل في هذه الملفات.

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

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

استبدل هنا سنتوس: 7 في أوبونتو.

الموفر

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

  • كتب اللعب: يمكنك تحديد كتيبات التشغيل التي يجب استخدامها في مراحل معينة.

provisioner:
  name: ansible
  playbooks:
    create: create.yml
    destroy: ../default/destroy.yml
    converge: playbook.yml
    side_effect: side_effect.yml
    cleanup: cleanup.yml

provisioner:
  name: ansible
  config_options:
    defaults:
      fact_caching: jsonfile
    ssh_connection:
      scp_if_ssh: True

  • خيارات_الاتصال: خيارات صلة

provisioner:
  name: ansible  
  connection_options:
    ansible_ssh_common_args: "-o 'UserKnownHostsFile=/dev/null' -o 'ForwardAgent=yes'"

  • الخيارات: خيارات أنسبل ومتغيرات البيئة

provisioner:
  name: ansible  
  options:
    vvv: true
    diff: true
  env:
    FOO: BAR

سيناريو

اسم ووصف تسلسل البرنامج النصي.
يمكنك تغيير مصفوفة الإجراءات الافتراضية لأي أمر عن طريق إضافة المفتاح <command>_sequence وكقيمة لها من خلال تحديد قائمة الخطوات التي نحتاجها.
لنفترض أننا نريد تغيير تسلسل الإجراءات عند تشغيل أمر playbook run: molecule converge

# изначально:
# - dependency
# - create
# - prepare
# - converge
scenario:
  name: default
  converge_sequence:
    - create
    - converge

المدقق

وضع إطار عمل للاختبارات وتوضيحها. الوبر الافتراضي هو testinfra и flake8. الخيارات الممكنة هي نفسها المذكورة أعلاه:

verifier:
  name: testinfra
  additional_files_or_dirs:
    - ../path/to/test_1.py
    - ../path/to/test_2.py
    - ../path/to/directory/*
  options:
    n: 1
  enabled: False
  env:
    FOO: bar
  lint:
    name: flake8
    options:
      benchmark: True
    enabled: False
    env:
      FOO: bar

لنعد إلى دورنا. دعنا نعدل الملف tasks/main.yml لهذا النوع:

---
- name: Install nginx
  apt:
    name: nginx
    state: present

- name: Start nginx
  service:
    name: nginx
    state: started

وإضافة الاختبارات إلى molecule/default/tests/test_default.py

def test_nginx_is_installed(host):
    nginx = host.package("nginx")
    assert nginx.is_installed

def test_nginx_running_and_enabled(host):
    nginx = host.service("nginx")
    assert nginx.is_running
    assert nginx.is_enabled

def test_nginx_config(host):
    host.run("nginx -t")

تم ، يبقى فقط للتشغيل (من جذر الدور ، دعني أذكرك):

> molecule test

عادم طويل تحت الجناح:

--> Validating schema <path>/nginx/molecule/default/molecule.yml.
Validation completed successfully.
--> Test matrix

└── default
    ├── lint
    ├── destroy
    ├── dependency
    ├── syntax
    ├── create
    ├── prepare
    ├── converge
    ├── idempotence
    ├── side_effect
    ├── verify
    └── destroy

--> Scenario: 'default'
--> Action: 'lint'
--> Executing Yamllint on files found in <path>/nginx/...
Lint completed successfully.
--> Executing Flake8 on files found in <path>/nginx/molecule/default/tests/...
Lint completed successfully.
--> Executing Ansible Lint on <path>/nginx/molecule/default/playbook.yml...
Lint completed successfully.
--> Scenario: 'default'
--> Action: 'destroy'

    PLAY [Destroy] *****************************************************************

    TASK [Destroy molecule instance(s)] ********************************************
    changed: [localhost] => (item=None)
    changed: [localhost]

    TASK [Wait for instance(s) deletion to complete] *******************************
    ok: [localhost] => (item=None)
    ok: [localhost]

    TASK [Delete docker network(s)] ************************************************

    PLAY RECAP *********************************************************************
    localhost                  : ok=2    changed=1    unreachable=0    failed=0

--> Scenario: 'default'
--> Action: 'dependency'
Skipping, missing the requirements file.
--> Scenario: 'default'
--> Action: 'syntax'

    playbook: <path>/nginx/molecule/default/playbook.yml

--> Scenario: 'default'
--> Action: 'create'

    PLAY [Create] ******************************************************************

    TASK [Log into a Docker registry] **********************************************
    skipping: [localhost] => (item=None)

    TASK [Create Dockerfiles from image names] *************************************
    changed: [localhost] => (item=None)
    changed: [localhost]

    TASK [Discover local Docker images] ********************************************
    ok: [localhost] => (item=None)
    ok: [localhost]

    TASK [Build an Ansible compatible image] ***************************************
    changed: [localhost] => (item=None)
    changed: [localhost]

    TASK [Create docker network(s)] ************************************************

    TASK [Create molecule instance(s)] *********************************************
    changed: [localhost] => (item=None)
    changed: [localhost]

    TASK [Wait for instance(s) creation to complete] *******************************
    changed: [localhost] => (item=None)
    changed: [localhost]

    PLAY RECAP *********************************************************************
    localhost                  : ok=5    changed=4    unreachable=0    failed=0

--> Scenario: 'default'
--> Action: 'prepare'
Skipping, prepare playbook not configured.
--> Scenario: 'default'
--> Action: 'converge'

    PLAY [Converge] ****************************************************************

    TASK [Gathering Facts] *********************************************************
    ok: [instance]

    TASK [nginx : Install nginx] ***************************************************
    changed: [instance]

    TASK [nginx : Start nginx] *****************************************************
    changed: [instance]

    PLAY RECAP *********************************************************************
    instance                   : ok=3    changed=2    unreachable=0    failed=0

--> Scenario: 'default'
--> Action: 'idempotence'
Idempotence completed successfully.
--> Scenario: 'default'
--> Action: 'side_effect'
Skipping, side effect playbook not configured.
--> Scenario: 'default'
--> Action: 'verify'
--> Executing Testinfra tests found in <path>/nginx/molecule/default/tests/...
    ============================= test session starts ==============================
    platform darwin -- Python 2.7.15, pytest-4.3.0, py-1.8.0, pluggy-0.9.0
    rootdir: <path>/nginx/molecule/default, inifile:
    plugins: testinfra-1.16.0
collected 4 items

    tests/test_default.py ....                                               [100%]

    ========================== 4 passed in 27.23 seconds ===========================
Verifier completed successfully.
--> Scenario: 'default'
--> Action: 'destroy'

    PLAY [Destroy] *****************************************************************

    TASK [Destroy molecule instance(s)] ********************************************
    changed: [localhost] => (item=None)
    changed: [localhost]

    TASK [Wait for instance(s) deletion to complete] *******************************
    changed: [localhost] => (item=None)
    changed: [localhost]

    TASK [Delete docker network(s)] ************************************************

    PLAY RECAP *********************************************************************
    localhost                  : ok=2    changed=2    unreachable=0    failed=0

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

الأوامر التالية مفيدة لتصحيح الأخطاء:

> molecule --debug <command> # debug info. При обычном запуске Молекула скрывает логи.
> molecule converge          # Оставляет инстанс после прогона тестируемой роли.
> molecule login             # Зайти в созданный инстанс.
> molecule --help            # Полный список команд.

الدور الحالي

إضافة نص جديد إلى دور موجود هو من دليل الدور بالأوامر التالية:

# полный список доступных параметров
> molecule init scenarion --help
# создание нового сценария
> molecule init scenario -r <role_name> -s <scenario_name>

في حال كان هذا هو السيناريو الأول في الدور ، ثم المعلمة -s يمكن حذفها لأنها ستنشئ نصًا default.

اختتام

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

شكرًا لكم على اهتمامكم. إذا كانت لديك خبرة في اختبار الأدوار غير المرغوبة ، ولم تكن مرتبطة بالجزيء ، فأخبرنا عنها في التعليقات!

المصدر: www.habr.com

إضافة تعليق