Ansible: Функция: Разрешить циклы «до» на блоках или включениях.

Созданный на 27 сент. 2018  ·  29Комментарии  ·  Источник: ansible/ansible

РЕЗЮМЕ

Было бы очень полезно, если бы вы могли перебирать более одной задачи.

Например, если вам нужно опросить удаленную систему на наличие какого-либо прогресса, и в то же время вы хотите передать этот прогресс на другой сервер, вы можете сделать:

- hosts: localhost
  tasks:
  - name: Start a long-running task
    uri:
      url: https://some-service/v1/put/new_job
      body: { foo: bar }
    register: new_job

  - until: job_status.json.message in ['Finished', 'Failed']
    block:
    - name: Get job status
      uri:
        url: https://some-service/v1/get/new_job
      register: job_status

    - name: Report job status to web service
      uri:
        url: https://backend-system/v1/post/job_status
        body: '{{ job_status.json }}'

Этому есть много применений.

ТИП ПРОБЛЕМЫ
  • Идея функции
НАЗВАНИЕ КОМПОНЕНТА

Основной

affects_2.8 feature has_pr core

Самый полезный комментарий

Естественно, блок должен быть повторяемым. В противном случае это очень контринтуитивно. Это сбивает с толку.

И, похоже, нет никакого способа написать сценарий цикла с более чем одним оператором. Ни один язык программирования не имеет таких ограничений.

Все 29 Комментарий

@mkrizek Хм, я искал разные комбинации ключевых слов, и это не выделялось :-(

Тем не менее, я пытался использовать until: с block: , include: и include_tasks , но первый не работает, а два других запускают включенный файл только один раз. .

- hosts: localhost
  tasks:
  - include: taskboot.yml
    until: 5|random == 5

Но, по-видимому, зацикливание работает только при использовании loop: ?

- hosts: localhost
  tasks:
  - include: taskboot.yml
    loop: [ 1, 2, 3, 4, 5 ]

Что бы я ни пытался, использование until: не работает с include: и include_tasks: .

- hosts: localhost
  tasks:
  - include: taskbook.yml
    until: false
    retries: 5
    delay: 1

Да, until не является допустимым аргументом для включения, см . https://github.com/ansible/ansible/pull/46177.

@mkrizek Другими словами, то, что нам нужно, невозможно ни на блоках, ни на включениях.

Так что я оставлю это открытым, но изменю название.

У нас есть открытое предложение по включению «taskify», что позволит работать над ними таким вещам, как «пока».

https://github.com/ansible/proposals/issues/136

Я, однако, не считаю, что блоки должны быть расширены для поддержки этой функции.

@sivel А по какой причине функциональность не будет расширена на блоки? Поскольку это было бы естественно, если бы это сработало. (т.е. возможность зацикливать каждую конструкцию в пьесе)

блоки в настоящее время являются «статическими» группами, включение циклов на них (а не только наследование их задачами) потребует сделать их динамическими ... как мы видели с include: , это имеет много последствий, которые не очевидны сразу.

Чтобы расширить то, что упоминает @bcoca , это потребует от нас отказаться от block и заменить что-то вроде block_dynamic и block_static .

Кроме того, _каждый_ пользователь ansible использует блоки, как явные, так и наше внутреннее неявное их использование. Они являются фундаментальным строительным блоком представления и выполнения задач. Изменение такой неотъемлемой функции обязательно приведет к непредвиденным проблемам.

В любом случае документация не дает никаких подробностей и даже не обсуждает, что должно работать, а что нет. Нет реального различия между «циклами» и циклами «до тех пор», не знаю, как мы можем сделать это более понятным в целом. Ожидается, что то, что работает для «циклов», также работает и для циклов «до».

я бы сделал и то, и другое, разрешил циклам until/retry работать с включениями, а затем четко документировал, как они работают... чтобы нам было на что указать, когда это не соответствует ожиданиям некоторых людей

Просто чтобы предоставить небольшое количество деталей о том, как работает включение, скажем, что динамическое включение является скорее внутренним триггером, а не чем-то, что оборачивает выполнение.

Таким образом, task_executor рано замыкается на включении, указывая стратегии, что он должен прочитать файл и вставить блоки задач в TQM, которые позже будут обработаны task_executor.

В связи с этим отсутствует отслеживание состояния при свертывании родительского включения. Таким образом, цикл «до тех пор», который будет полагаться на какую-то версию неудачного сценария «когда/успех», будет относиться только к тому, было ли сказано стратегии действовать, как описано выше. В этом случае он всегда должен быть успешным.

В любом случае, режим работы заключается в том, что мы замыкаем цепь задолго до того, как будут проверены условия. Если бы мы просто «заставили это работать» прямо сейчас, это определенно не соответствовало бы ожиданиям человека. Чтобы сделать то, что ожидают люди, потребуется реализовать ansible/proposals#136.

В этом случае до тех пор, пока придется полагаться на vars, установленные или зарегистрированные из включенных задач, поскольку регистрация самого включения будет бесполезной ... она все равно будет «работать», но не так, как в большинстве других случаев.

@dagwieers Другая ветка сейчас заблокирована. Но это недавнее предложение (комментарий @sivel выше) совершенно новое:

https://github.com/ansible/ansible/issues/46203#issuecomment -425111123

И вы говорите, что мы, возможно, захотим оставить открытой возможность того, что кто-то еще придет позже, чтобы сделать PR для того, чтобы зацикливаться на блоках со своей спины. Тогда, по крайней мере, мы могли бы дать им кристально ясное представление о том, как сделать его отдельным и новым block_dynamic: , не касаясь традиционных статических block: нетронутыми? Не будет ли это иметь больше смысла для всех? Можем ли мы все договориться об этом заранее? Потому что я согласен с этой идеей. По тем же причинам — это поможет предотвратить поломку других существующих вещей, на которые мы полагаемся. По-прежнему допуская возможность того, что кто-то придет, попробуйте сделать PR для фактической реализации этого. Должны ли мы действительно хотеть, чтобы они выполняли свою работу как можно лучше и тому подобное. Тогда мы должны, по крайней мере, четко указать это. Если мы уже знаем это заранее. Что, кажется, имеет место сейчас?

Ссылка на это здесь https://github.com/ansible/ansible/issues/16621

+1 За реализацию этой функции

Естественно, блок должен быть повторяемым. В противном случае это очень контринтуитивно. Это сбивает с толку.

И, похоже, нет никакого способа написать сценарий цикла с более чем одним оператором. Ни один язык программирования не имеет таких ограничений.

Похоже, в Ansible, если нужно сделать что-то сложное, нужно написать плагин действия. Это то, что мы собираемся сделать.

Здесь есть много примеров:
https://github.com/ansible/ansible/tree/devel/lib/ansible/plugins/action

С наилучшими пожеланиями

Это абсолютно недостаток. До сих пор Ansible идеально подходил для большинства моих нужд, но кажется, что расширение возможностей блоков сделало бы Ansible намного лучшим решением.

Я пытался использовать until в include_tasks , и это не сработало.

Что я сделал в качестве обходного пути, так это создал файл yml, который включает задачу ( loop.yml ) и рекурсивно вызывает себя ( recursive.yml ), пока условие все еще не выполняется.

_recursive.yml:_

---

- name: 'checking {{ watch_job }} status (recursive)'
  include_tasks: 'loop.yml'

- name: 'count ({{ watch_count | int + 1 }})'
  set_fact:
    watch_count: '{{ watch_count | int + 1 }}'

- name: 'retries ({{ (watch_timeout | int / watch_poll | int) | int }})'
  set_fact:
    watch_retries: '{{ (watch_timeout | int / watch_poll | int) | int }}'

- name: 'timeout ({{ watch_timeout }} seconds)'
  fail: 
    msg: "Timeout of {{ watch_timeout }} seconds exceeded ({{ watch_retries }} retries)"
  when: (not watch_status.finished) and (watch_count | int > watch_retries | int)

- name: 'wait for {{ watch_poll }} seconds'
  wait_for:
    timeout: '{{ watch_poll | int }}'
  when: not watch_status.finished

- name: 'call itself recursively'
  include_tasks: 'recursive.yml'
  when: not watch_status.finished

В приведенном выше файле я включил тайм-аут на случай слишком долгого выполнения (это в роли, которая показывает вывод того, что работает в хостах ).

Не идеальное решение, но сработало для меня и было относительно легко изменить, используя until , чтобы сделать вышеперечисленное.

+1 за эту функцию!

+1

+1 за до циклов на блоках

Я искал способ сделать until (бесконечно) для успеха на всех модулях в блоке, и мне удалось сделать это с include_tasks с rescue

Я не мог использовать обычные until , потому что IP со временем меняется, и мне приходилось изменять его на ходу.

wait_until_success.yml

- name: 'Wait until success'
  block:
    - name: Get server updated ip
      uri:
        url: https://localhost/ip
        return_content: yes
        status_code: 200
      register: ip

    - name: ssh to the server
      wait_for:
        host: "{{ ip }}"
        port: 22
        timeout: 30
        state: started
  rescue:
    - debug:
        msg: "Failed to connect - Retrying..."
    - include_tasks: wait_until_success.yml

То же, что и @matanbaru , но с ошибкой после нескольких попыток.

- name: 'Wait until success'
  block:
    - name: Set the retry count
      set_fact:
        retry_count: "{{ 0 if retry_count is undefined else retry_count|int + 1 }}"

    - name: Get server updated ip
      uri:
        url: https://localhost/ip
        return_content: yes
        status_code: 200
      register: ip

    - name: ssh to the server
      wait_for:
        host: "{{ ip }}"
        port: 22
        timeout: 30
        state: started
  rescue:
    - fail:
        msg: Ended after 5 retries
      when: retry_count|int == 5

    - debug:
        msg: "Failed to connect - Retrying..."

    - include_tasks: wait_until_success.yml

+1 не могли бы вы добавить повторение в циклах!
Абсолютно обязательная функция!

+1

+1

Я заблокировал это для участников на данный момент. Добавление комментариев +1 слишком шумно. Для дальнейшего использования добавьте реакцию в тело проблемы и не комментируйте.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги