ansible之实施任务控制

一、编写循环和条件任务

1.1 简单循环

1.不用循环

---
- name: test
  hosts: webservers
  tasks:
    - name: apache is running
      service:
        name: httpd
        state: started
    - name: vsftpd is running
      service:
        name: vsftpd
        state: started

2.使用循环

- name: test
  hosts: webservers
  tasks:
    - name: apache and vsftpd are running
      service:
        name: "{{ item }}" #循环变量item
        state: started
      loop:
        - httpd
        - vsftpd

3.将变量放入列表

- name: test
  hosts: webservers
  vars:
    web_service:
      - httpd
      - vsftpd
  tasks:
    - name: apache and vsftpd are running
      service:
        name: "{{ item }}"
        state: started
      loop: "{{ web_service }}"

循环散列或字典列表

- name: User Test
  user:
    name: "{{ item.name }}"
    state: present
    groups: "{{ item.groups }}"
  loop:
    - name: westos
      groups: westos
    - name: redhat
      groups: root

register 和loop 一起使用

---
- name: loop register test
  gather_facts: no
  hosts: localhost
  tasks:
    - name: loop echo task
      shell: "echo This is my item: {{ item }}"
      loop:
        - one
        - two
      register: echo_results #注册变量
    - name: Show echo results variable
      debug:
        var: echo_results#显示变量结果

迭代上面playbook 的结果(即使用上面item 的结果)

---
- name: loop register test
  gather_facts: no
  hosts: localhost
  tasks:
    - name: loop echo task
      shell: "echo This is my item: {{ item }}"
      loop:
        - one
        - two
      register: echo_results
    - name: Show echo results variable
      debug:
        msg: "STDOUT from previous task: {{ item.stdout }}"
      loop: "{{ echo_results['results'] }}"
1.2 条件任务语法

使用布尔值测试

---
- name: Boolean test
  hosts: all
  vars:
    run_my_task: true #只有当变量为true 时,才会执行
  tasks:
    - name: httpd is installed
      yum:
        name: httpd
      when: run_my_task

测试my_service 变量是否有值,有值则安装

---
- name: Boolean test
  hosts: all
  vars:
    my_service: httpd
  tasks:
    - name: "{{ my_service }} is installed"
      yum:
        name: "{{ my_service }}"
      when: my_service is defined

条件:
等于(字符串) A == “B”
等于(数字) A == 100
小于<
大于>
小于等于<=
大于等于>=
不等于!=
变量存在xxx is defined
变量不存在xxx is not defined
布尔值true 1、true、yes
布尔值false 0、false、no
第一个变量的值存在,且在第二个变量的列表中A in B
测试多个条件:
or 两个条件一个为真即可
and 两个条件必须都为真

1.3 组合循环和有条件任务
- name: Restart httpd if vsftpd is running
  hosts: all
  tasks:
    - name: Get vsftpd status
      command: /usr/bin/systemctl is-active vsftpd #判断状态
      ignore_errors: yes #如果vsftpd 没运行或失败,则忽略
      register: result #定义变量保存结果
    - name: Restart httpd
      service:
        name: httpd
        state: restarted
      when: result.rc == 0 #退出码为0,则重启httpd

实施处理程序:
处理程序是响应由其他任务触发的通知的任务,只有在template 任务通知已发生更改时才会触发

---
- name: Test
  hosts: webservers
  tasks:
    - name: Copyt File
      template:
        src: files/example.conf
        dest: /etc/httpd/conf.d/example.conf
      notify: #notify 语句指出该任务需要触发一个处理程序
        - restart apache #程序名
  handlers: #表示处理程序任务列表的开头
    - name: restart apache #被任务调用的处理程序名称
      service: #处理该程序的模块
        name: httpd
        state: restarted

ansible 把notify 语句当作数组

vim files/example.conf
<VirtualHost *:80>
    DocumentRoot /www
    ServerName www.westos.org
</VirtualHost>
<VirtualHost *:80>
    DocumentRoot /bbs
    ServerName bbs.westos.org
</VirtualHost>
vim notify.yml
---
- name: Test
  hosts: webservers
  tasks:
    - name: Copyt File
      template:
        src: files/example.conf
        dest: /etc/httpd/conf.d/example.conf
      notify:
        - restart apache
        - restart mysql
  handlers:
    - name: restart apache
      service:
        name: httpd
        state: restarted
    - name: restart mysql
      service:
        name: mariadb
        state: restarted

使用处理程序注意:
1.处理程序始终按照play 的handlers 部分指定的顺序运行,不按notify 里的
2.处理程序通常在相关play 中所有其他任务运行完后运行
3.处理程序名称存在于个play 命名空间中(若两个处理程序同名,只会运行一个)
4.如果多个任务通知处理程序,处理程序也只会运行一次
5.如果包含notify 的语句任务没有报告changed 结果,则处理程序不会获得通知

二、处理任务失败

通常playbook 遇到错误会中止执行,但是有时我们想要失败时也继续执行

2.1 忽略任务失败

关键字:ignore_errors

vim ignore.yml
---
- name: Test
  hosts: webservers
  tasks:
    - name: Install package
      yum:
        name: k8s
        state: latest
      ignore_errors: yes
2.2 任务失败后强制执行处理程序

通常任务失败,play 会中止,那么收到play 中之前任务通知的处理程序将不会运行,如果要运行,需要使用关键字:force_handlers:yes

cat force.yml
---
- hosts: webservers
  force_handlers: yes
  tasks:
    - name: always notify
      command: /bin/true
      notify: restart apache
    - name: Fail task
      yum:
        name: k8s
        state: latest
  handlers:
    - name: restart apache
      service:
        name: httpd
        state: restarted

处理程序会在任务报告changed 结果时获得通知,ok 或者failed 都不会

2.3 指定任务失败条件

关键字:failed_when

tasks:
  - name: Run Script
    shell: /usr/local/bin/user.sh
    register: command_result
    failed_when: "'failure' in command_result.stdout"

fail 模块可以实现此效果

tasks:
  - name: Run Script
    shell: /usr/local/bin/user.sh
    register: command_result
    ignore_error: yes
  - name: Report failure
    fail:
      msg: "Authentication failure" #fail 模块可以提供明确消息
    when: "'failure' in command_result.stdout"
2.4 指定任务何时报告"Changed"结果

关键字:changed_when

-name: get time
 shell: date
 changed_when: false
2.5 ansible 块和错误处理

三种关键字:
block:定义要运行的主要任务
rescue:定义要在block 子句中定义的任务失败时运行的任务
always:定义时中独立运行的任务
示例:故意制造错误

cat error.yml
---
- name: Task Failure
  hosts: webservers
  vars:
    web_pkg: http
    db_pkg: mariadb-server
    db_service: mariadb
  tasks:
    - name: Install {{ web_pkg }} packages
      yum:
        name: "{{ web_pkg }}"
        state: present
    - name: Install {{ db_pkg }} packages
      yum:
        name: "{{ db_pkg }}"
        state: present

运行报错

ansible-playbook error.yml
TASK [Install http packages] ***************************************************
fatal: [servera.lab.example.com]: FAILED! => {"changed": false, "failures": ["No
package http available."], "msg": "Failed to install some of the specified packages",
"rc": 1, "results": []}

第一个任务失败,第二个任务不运行
1.添加忽略关键字

vim error.yml
......
ignore_errors: yes

2.使用block、rescue、always 将任务分开

cat error.yml
---
- name: Task Failure
  hosts: webservers
  vars:
    web_pkg: http
    db_pkg: mariadb-server
    db_service: mariadb
  tasks:
    - name: Set up Web
      block:
        - name: Install {{ web_pkg }} packages
           yum:
              name: "{{ web_pkg }}"
              state: present
      rescue:
        - name: Install {{ db_pkg }} packages
           yum:
              name: "{{ db_pkg }}"
              state: present
      always:
        - name: Start {{ db_service }} service
          service:
             name: "{{ db_service }}"
             state: started

执行结果有报错,但是mariadb 正常启动
再修改,将http 的包改为正确

vim error.yml
 .........
 web_pkg: httpd

发现rescue 部分被忽略,但是always 总会执行
控制’changed’条件:

cat error.yml
---
- name: Task Failure
  hosts: webservers
  vars:
    web_pkg: httpd
    db_pkg: mariadb-server
    db_service: mariadb
  tasks:
    - name: Check Time #添加查看时间任务
      command: date
      register: command_result
    - name: Print Time
       debug:
         var: command_result.stdout
    - name: Set up Web
       block:
    - name: Install {{ web_pkg }} packages
      yum:
        name: "{{ web_pkg }}"
        state: present
      rescue:
        - name: Install {{ db_pkg }} packages
          yum:
            name: "{{ db_pkg }}"
            state: present
      always:
        - name: Start {{ db_service }} service
          service:
             name: "{{ db_service }}"
             state: started

运行发现check time 任务始终是changed
因为任务没有更改受管主机,所以不应该每次都是changed
修改文件

vim error.yml
changed_when: false

再次运行,变为ok
使用failed_when 关键字

vim error.yml
failed_when: web_pkg == "httpd"

运行

ansible-playbook error.yml
TASK [Install httpd packages] **************************************************
fatal: [servera.lab.example.com]: FAILED! => {"changed": false,
"failed_when_result": true, "msg": "Nothing to do", "rc": 0, "results": ["Installed:
httpd"]}

有报错,但是其实已经安装了httpd 包,failed_when 关键字只是改变了任务的执行状态,没有改变任务本身,但是失败的状态可以让rescue 语句块执行

你可能感兴趣的:(ansible之实施任务控制)