Ansible回滚:即使其中一个主机发生故障,也要在主机列表上运行一组任务

时间:2019-06-06 08:47:01

标签: ansible ansible-2.x

我有一本有多个角色,主持人和小组的剧本。我正在尝试开发回滚功能,该功能可以在所有主机上运行。我目前的障碍是我看不到将角色,阻止或任务集委派给主机组的方法

  • 我尝试查找没有循环的组,因此可以在一个块上工作。
  • import_role不接受循环
  • include_role不接受委托给
  • 与import_tasks / include_tasks相同

这是我现在所拥有的剧本文件(简化版)

- hosts: all
  any_errors_fatal: true
  vars_prompt:

  - name: "remote_user_p"
    prompt: "Remote user running the playbook"
    default: "root"
    private: no

  - name: "service_user_p"
    prompt: "Specify user to run non-root tasks"
    default: "user"
    private: no

  tasks:
    - set_fact:
        playbook_type: "upgrade"

    - import_role:
        name: 0_pre_check
      run_once: true
      remote_user: "{{ remote_user_p }}"
      become_user: "{{ service_user_p }}"
      become_method: su
      become: yes

    - block:      
      - import_role:
          name: 1_os

      - import_role:
          name: 2_mysql
        when: inventory_hostname in groups['mysql'] | default("")

      - import_role:
          name: 3_web
        when: inventory_hostname in groups['web'] | default("") 
...

      rescue:
        - block:
          - name: run rollback
            import_tasks: ../common/roles/5_rollback/tasks/rollback.yml

      remote_user: "{{ remote_user }}"
      become_user: "{{ service_user }}"
      become_method: su
      become: yes

这是rollback.yml中的一些示例代码:

- block:
  - name: rollback symlinks to config dir
    file:
      src: "{{ current_config_path }}"
      dest: "{{ install_dir }}/static/cfg"
      owner: "{{ service_user }}"
      group: "{{ service_user_primary_group }}"
      state: link
    when: current_new_configs | default("N") == "Y"
    delegate_to: "{{ item }}"
    with_items:
      - "{{ ansible_play_hosts }}"

  - block:           
    - name: return config files
      shell: test -f '{{ item.1.current_ver_file_path }}' && cp -p {{ item.1.current_ver_file_path }} {{ item.1.old_config_location }}
      args:
        warn: false
      register: return_config_files
      failed_when: return_config_files.rc >= 2
      when:
        - roolback_moved_cfg | default('N') == "Y"
        - inventory_hostname in groups[item.0.group]
        - item.1.old_config_location != ""
        - item.1.current_ver_file_path != ""
      with_subelements:
        - "{{ config_files }}"
        - files
      become_user: root
      become_method: sudo
      become: yes

    - name: systemctl daemon-reload  
      shell: systemctl daemon-reload
      failed_when: false
      when: root_rights == "Y"
      args:
        warn: false
      delegate_to: "{{ item }}"
      with_items:
        - "{{ ansible_play_hosts }}"
    when: root_rights == "Y"
    become_user: root
    become_method: sudo
    become: yes

  - fail:
      msg: "Upgrade failed. Symbolic links were set to the previous version. Fix the issues and try again. If you wish to cancel the upgrade, restore the database backup manually."

如您所见,现在我通过引入

使用la脚的解决方法
      delegate_to: "{{ item }}"
      with_items:
        - "{{ ansible_play_hosts }}"

在每个任务之后。

这里有两个问题: 1.在任务return config files之后,我不能使用相同的方法,因为它已经使用了一个循环 2.这通常是la脚的代码重复,我讨厌它

为什么我完全需要它:例如,如果剧本执行在mysql角色的某个地方失败,则rescue块将仅在该mysql角色的主机上执行(并且顺便说一句,在运行救援块时,将继续执行下一个角色的任务-尽管执行了所有工作,但任务量相同),而我希望它运行在所有主机上。

2 个答案:

答案 0 :(得分:0)

我终于可以用一个丑陋的骇客解决这个问题。用过的戏剧不只是角色-现在有10多种戏剧。不要判断我,我花了很多心思来使它变得不错):

示例游戏,然后进行检查-彼此相同。

- hosts: mysql
  any_errors_fatal: true
  tasks:
    - block:              
      - import_role:
          name: 2_mysql
        when: not rollback | default(false)
      rescue:
        - block:
          - name: set fact for rollback
            set_fact: 
              rollback: "yes"
            delegate_to: "{{ item }}"
            delegate_facts: true
            with_items: "{{ groups['all'] }}"

- hosts: all
  any_errors_fatal: true
  tasks:
    - name: run rollback
      import_tasks: ../common/roles/5_rollback/tasks/rollback.yml
      when: rollback | default(false)

答案 1 :(得分:0)

  

include_role不接受delegate_to

实际上是。

使用ansible-core 2.8:

- name: "call my/role with host '{{ansible_hostname}}' for hosts in '{{ansible_play_hosts}}'"
  include_role:
    name: my/role
  apply:
    delegate_to: "{{current_host}}"
  with_items: "{{ansible_play_hosts}}"
    loop_control:
      loop_var: current_host

对于ansible-core 2.5到2.7,请参见2.5: delegate_to, include_role with loops中提到的George Shuklin中的“ ansible/ansible issue 35398

- name: "call my/role with host '{{ansible_hostname}}' for items in '{{ansible_play_hosts}}'"
    include_tasks: loop.yml
    with_items: "{{ansible_play_hosts}}"
    loop_control:
      loop_var: current_host

通过loop.yml在其自己的文件中执行其他任务:

- name: "Import my/role for '{{current_host}}'"
  import_role: name=my/role
  delegate_to: "{{current_host}}"

因此,在两个文件(具有ansible-core 2.7)或一个文件(2.8)中,您可以担任all角色,并且其任务在委托的服务器上运行。