Страницы

Поиск по вопросам

четверг, 2 мая 2019 г.

Параллельная и последовательная обработка в ansible

Вопрос вообще возник из того, что при клонировании крупных репозиториев вижу, что порядок вывода на экран меняется.
Ну, чтобы не быть голословным, - конкретный пример для ansible 2.1
Набор данных:
repositories: mediawiki_core1: repo: https://gerrit.wikimedia.org/r/p/mediawiki/core.git path: w1 mediawiki_core2: repo: https://gerrit.wikimedia.org/r/p/mediawiki/core.git path: w2 version: REL1_25 mediawiki_core3: repo: https://gerrit.wikimedia.org/r/p/mediawiki/core.git path: w3
Обработчик:
- name: clone repositories git: repo: "{{ item.value.repo }}" dest: "/root/tests/{{ item.value.path }}/" version: "{{ item.value.version | default('HEAD') }}" become: true become_user: apache with_dict: "{{ repositories }}"
Вывод окажется таким:
TASK [abcdef : clone repositories] changed: [server.domain.ru] => (item={'value': {u'repo': u'https://gerrit.wikimedia.org/r/p/mediawiki/core.git', u'path': u'w1'}, 'key': u'mediawiki_core1'}) changed: [server.domain.ru] => (item={'value': {u'repo': u'https://gerrit.wikimedia.org/r/p/mediawiki/core.git', u'path': u'w3'}, 'key': u'mediawiki_core3'}) changed: [server.domain.ru] => (item={'value': {u'repo': u'https://gerrit.wikimedia.org/r/p/mediawiki/core.git', u'path': u'w2', u'version': u'REL1_25'}, 'key': u'mediawiki_core2'})
Нужно сделать так, чтобы гарантированно выполнить последовательно задачи одну за другой -- вне зависимости от того, сколько длится её выполнение.
Типичный пример: после того, как клонируется движок вики (очень длительная задача), можно приступать к клонированию множества мелких репозиториев со скринами и экстеншнами.
Дополнительно, хочется навести порядок в голове и разобраться, как управлять порядком выполнения, чтобы уметь распараллеливать задачи, если нужно, но и если нужно гарантировать, что задачи выполнятся одна за другой в указанном порядке, то уметь выполнять их последовательно.
P.S. Что самое странное: именно в приведённом примере проблема с порядком возникает, а вот когда запускаешь разные репозитории (первым -- тяжёлый медиавики, вторым -- небольшой собственный репозиторий), проблема перестаёт воспроизводиться: сначала долго отрабатывает первый таск, потом быстро пролетает второй. В мистику не верю: это просто говорит о непонимании, как оно всё работает под капотом.


Ответ

Насколько я понял гоняя допонительные тесты, дело вообще не в том, сколько по времени выполняется задача внутри dict -- а в том, что сортировка для dict не гарантирована. Об этом было в этом вопросе на большом СО.
Точнее, обход with_dict проходит по dict не в том порядке, в котором я указываю элементы: идёт внутренняя сортировка по значению хеша.
Для того, чтобы обходить элементы в том порядке, в котором я записал их - нужно заменять dict на items и обход делать не with_dict, а with_items
vars: with_dict_test: - { key: 'one', value: 1 } - { key: 'two', value: 2 } - { key: 'three', value: 3 } - { key: 'four', value: 4 } - { key: 'five', value: 5 } tasks: - name: with_dict test debug: msg="{{item.key}} --> {{item.value}}" with_items: "{{ with_dict_test }}"
Или, точный пример, как у меня в вопросе:
vars: with_dict_test: - { repo: 'url1', path: 'A', version: 'REL1_25' } - { repo: 'url2', path: 'B' } tasks: - name: with_dict test debug: msg="{{item.repo}} --> {{item.path}} -- {{ item.version | default ('HEAD') }}" with_items: "{{ with_dict_test }}"
И что-то мне такая форма сильно напоминает ;) Открываем документацию, раздел Standard Loops и видим:
Note that the types of items you iterate over with ‘with_items’ do not have to be simple lists of strings. If you have a list of hashes, you can reference subkeys using things like:
- name: add several users user: name={{ item.name }} state=present groups={{ item.groups }} with_items: - { name: 'testuser1', groups: 'wheel' } - { name: 'testuser2', groups: 'root' }
Вот так совсем хорошо:
with_dict_test: - { repo: 'url1' , version: 'REL1_25' , path: 'A' } - { repo: 'url2' , path: 'B' }

Комментариев нет:

Отправить комментарий