Ansible 回滚:运行 即使其中一个主机发生故障,主机列表上的一组任务
Ansible rollback: run a group of tasks over list of hosts even when one of hosts failed
我有一个包含多个角色、主机和组的剧本。我正在尝试开发一个回滚功能,它将 运行 覆盖所有主机。我目前的障碍是我看不到将角色、块或任务集委托给主机组的方法
- 我尝试查找没有循环的分组委托,所以它可以在一个块上工作。
- import_role 不接受循环
- include_role 不接受 delegate_to
- 同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."
如您所见,现在我通过引入
来使用蹩脚的解决方法
delegate_to: "{{ item }}"
with_items:
- "{{ ansible_play_hosts }}"
在每个任务之后。
这里有两个问题:
1. 我不能在任务 return config files
之后使用相同的方法,因为它已经使用了一个循环
2. 这通常是蹩脚的重复代码,我讨厌它
为什么我需要它:如果 playbook 在 mysql
角色的某处执行失败,例如,rescue
块将仅在该 mysql
角色的主机上执行(顺便说一句,下一个角色的任务将继续执行,而 运行ning 救援块 - 相同数量的任务,尽管付出了所有努力),而我希望它 运行 在所有主机上。
我终于能够通过 ugly-ugly hack 解决这个问题。使用过的剧本而不仅仅是角色——现在有超过 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)
include_role
doesn't accept 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" from George Shuklin, mentioned in 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 角色及其任务 运行。
我有一个包含多个角色、主机和组的剧本。我正在尝试开发一个回滚功能,它将 运行 覆盖所有主机。我目前的障碍是我看不到将角色、块或任务集委托给主机组的方法
- 我尝试查找没有循环的分组委托,所以它可以在一个块上工作。
- import_role 不接受循环
- include_role 不接受 delegate_to
- 同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."
如您所见,现在我通过引入
来使用蹩脚的解决方法 delegate_to: "{{ item }}"
with_items:
- "{{ ansible_play_hosts }}"
在每个任务之后。
这里有两个问题:
1. 我不能在任务 return config files
之后使用相同的方法,因为它已经使用了一个循环
2. 这通常是蹩脚的重复代码,我讨厌它
为什么我需要它:如果 playbook 在 mysql
角色的某处执行失败,例如,rescue
块将仅在该 mysql
角色的主机上执行(顺便说一句,下一个角色的任务将继续执行,而 运行ning 救援块 - 相同数量的任务,尽管付出了所有努力),而我希望它 运行 在所有主机上。
我终于能够通过 ugly-ugly hack 解决这个问题。使用过的剧本而不仅仅是角色——现在有超过 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)
include_role
doesn't acceptdelegate_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" from George Shuklin, mentioned in 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 角色及其任务 运行。