条件判断、任务失败、文件管理

334 阅读6分钟

条件判断、任务失败、文件管理

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

条件判断

在Ansible中,条件判断的关键字是"when"

---
#~/test.yml
- hosts: node2
  tasks:
    - debug:
        msg: "system release is CentOS"
      when:
        ansible_distribution == "CentOS"
[root@node1 ~]# ansible-playbook playbook/test1.yml 

PLAY [node2] ************************************************************************************************************************

TASK [Gathering Facts] **************************************************************************************************************
ok: [node2]

TASK [debug] ************************************************************************************************************************
ok: [node2] => {
    "msg": "system release is CentOS"
}

PLAY RECAP **************************************************************************************************************************
node2                      : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

如上所示,使用when关键字指明条件,条件是ansible_distribution的值为CentOS,我们可以发现,ansible_distribution就是facts信息中的一个key,通过ansible_distribution可以获取到目标主机系统的发行版。在使用when关键字时,我们并没有为ansible_distribution添加"{{ }}",在when关键字中引用变量时,变量名不需要加"{{ }}",上例playbook表示如果ansible_distribution的值是CentOS,则调用debug模块输出"system release is CentOS"这句话,如果值不是CentOS,则不满足条件,不会调用debug模块,使用when关键字为任务指定条件,条件成立则执行任务,条件不成立则不执行任务

在ansible也可以使用比较运算符

比较运算符含义
==比较两个对象是否相等,相等为真
!=比较两个对象是否不等,不等为真
比较两个值的大小,如果左边的值大于右边的值,则为真
<比较两个值的大小,如果左边的值小于右边的值,则为真
>=比较两个值的大小,如果左边的值大于右边的值或左右相等,则为真
<=比较两个值的大小,如果左边的值小于右边的值或左右相等,则为真

处理程序

处理程序:程序响应由其他任务触发通知的任务

handllers可以理解成另一种tasks,handlers是另一种人物列表,由通知者进行notify,如果没有被notify,handlers就不会被调用。但是,被调用不意味着一定会执行,只有当tasks中的任务真正执行以后,handlers中被调用的任务才会执行,如果tasks中的任务并没有做出任何实际的操作,那么handlers中的任务即使被调用也不会执行

如:复制文件给受管主机

---
#~/test.yml
- hosts: node2
  gather_facts: no
  tasks:
    - name: copy files
      copy:
        src: ~/1.txt
        dest: ~/
      notify:
        - restart httpd

  handlers:
    - name: restart httpd
      service:
        name: httpd
        state: restarted
[root@node1 ~]# ansible-playbook playbook/test1.yml 

PLAY [node2] ************************************************************************************************************************

TASK [copy files] *******************************************************************************************************************
changed: [node2]

RUNNING HANDLER [restart httpd] *****************************************************************************************************
changed: [node2]

PLAY RECAP **************************************************************************************************************************
node2                      : ok=2    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

在上例中,restarted httpd处理程序只有在copy任务通知changer时才会触发。一个任务可以在其notify部分中调用多个处理程序。ansible将notify语句视为数组,并且迭代处理程序名称

tasks:
  - name: copy file
     copy:
      src: ~/1.txt
      dest: ~/
    notify:
      - restart mysql
      - restart httpd

handlers:
  - name: restart mysql
    service:
      name: mariadb
      state: restarted
      
  - name: restart httpd
    service:
      name: httpd
      state: restarted

使用处理程序应注意

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

处理任务失败

忽略任务失败

Ansible默认会检查命令和模块的返回状态,并进行相应的错误处理,默认是遇到错误就中断playbook的执行,这些默认行为都是可以改变的,可以通过ignore_errors忽略返回状态码

下例演示了如何在任务中使用ignore_errors,以便在任务失败时也继续在主机上执行playbook。例如,如果httpdabc软件包不存在,则yum模块将失败,但若将ignore_errors设置为yes,则执行将继续

- name: install httpdabc
  yum:
    name: httpdabc
    state: present
  ignore_errors: yes

强制执行任务

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

---
#~/test.yml
- hosts: node2
  gather_facts: no
  force_handlers: yes
  tasks:
    - name: copy files
      copy:
        src: ~/1.txt
        dest: ~/abc			
      notify:
        - restart httpd

  handlers:
    - name: restart httpd
      service:
        name: httpd
        state: restarted

指定任务失败条件

方法一:使用failed_when关键字

---
#~/test.yml
- hosts: node2
  tasks:
    - name: test
      script: files/test.sh
      register: result
      failed_when: "'No such file or directory' in result.stdout"
TASK [test] ********************************************************************************************  
fatal: [node2]: FAILED! => {"changed": true, "failed_when_result": true, "rc": 0, "stderr": "Shared connection to node2 closed.\r\n", "stderr_lines": ["Shared connection to 192.168.190.134 closed."], "stdout": "ls: cannot access 'sdsdsdsdsdsds': No such file or directory\r\nanaconda-ks.cfg\r\n", "stdout_lines": ["ls: cannot access 'sdsdsdsdsdsds': No such file or directory", "anaconda-ks.cfg"]}

方法二:使用fail模块进行报错条件

---
#~/test.yml
- hosts: node2
  tasks:
    - name: test
      script: ~/abc.sh
      register: result

    - name: fail control
      fail:
        msg: "you are a fool"
      when:
        "'No such file or directory' in result.stdout"
TASK [fail control] ************************************************************************************
fatal: [node2]: FAILED! => {"changed": false, "msg": "you are a fool"}

指定何时报告“changed”结果

利用changed_when关键字来确定是否报告changed结果

---
#~/test.yml
- hosts: node2
  gather_facts: no
  tasks: 
    - name: useradd
      user:
        name: tom
        state: present
      changed_when: True

ansible块和错误处理

三种关键字:

  • block:定义要运行的任务
  • rescue:定义要在block子句中定义的任务失败时运行的任务
  • always:定义始终独立运行的任务
---
#~/test.yml
- hosts: node2
  vars:
    file_name: test1
  tasks:
    - name: test block
      block:
        - name: block1
          command: ls /tmp
        - name: block2
          command: ls /tmp/ {{ file_name }}
      rescue:
        - name: touch the {{ file_name}}
          file:
            name: "{{ file_name}}"
            state: touch
      always:
        - name: print
          command: echo "123456"
          register: rrresult
        - debug:
            msg: " {{ result.stdout }} "

文件管理

ansible中常用的文件管理模块:

  • blockinfile:将文本块添加到现有文件
  • copy:将文件复制到受管主机
  • fetch:从受管主机拷贝文件到控制节点
  • file:设置文件属性
  • lineinfile:确保特定行位于某个文件
  • stat:检索文件状态信息
  • synchronize:rsync命令的打包程序

确保受管主机上存在文件

使用file模块处理受管主机上的文件。其工作方式与touch命令类似,如果不存在则创建一个空文件,如果存在,则更新其修改时间。

- name: Touch a file and set permissions
  file:
    path: ~/file/test
    owner: tom
    group: tom
    mode: 0777
    state: touch

修改文件属性

使用file模块还可以确保新的或现有的文件具有正确的权限和SELinux类型

例如,以下文件保留了相对于用户主目录的默认SELinux上下文,这不是所需的上下文

[root@localhost ~]# ls -Z samba_file
- rw-r--r-- owner group unconfined_u:object_r:user_home_t:s0 samba_file

使SELinux文件上下文更改具有持久性

设置文件上下文时,file模块的行为与chcon类似。通过运行restorecon,可能会意外的撤销使用该模块所做的更改。使用file设置上下文后,用户可以使用system模块集合中的sefcontext来更新SELinux策略,如semanage fcontext。

- name: SELinux
  sefcontext:
    target: ~/file/samba_file
    setype: samba_share_t
    state: present

在受管主机上复制和编辑文件

在此示例中,copy模块用于将位于控制节点上的Ansible工作目录中的文件复制到选定的受管主机。

默认情况下,此模块假定设置了force: yes。这会强制该模块覆盖远程文件(如果存在但包含与正在复制的文件不同的内容)。如果设置force: no,则它仅会将该文件复制到受管主机(如果该文件尚不存在)。

 name: Copy a file to managed hosts
  copy:
    src: file
    dest: ~/file

要确保现有文件中存在特定的单行文本,请使用lineinfile模块:

- name: Add a line of text to a file
  lineinfile:
    path: ~/file
    line: 'Add this line to the file'
    state: present

要将文本块添加到现有文件,请使用blockinfile模块:

- name: Add additional lines to a file
  blockinfile:
    path: ~/file
    block: |
      First line in the additional block of text
      Second line in the additional block of text
    state: present

使用blockinfile模块时,注释块标记插入到块的开头和结尾,以确保幂等性。

# BEGIN ANSIBLE MANAGED BLOCK
First line in the additional block of text
Second line in the additional block of text
# END ANSIBLE MANAGED BLOCK

从受管主机中删除文件

从受管主机中删除文件的基本示例是使用file模块和state:absent参数。state参数对于许多模块是可选的

- name: shan chu wenjian
  file: 
    dest: ~/test
    state: absent

检索受管主机上的文件状态

stat模块检索文件的事实,类似于linux中的stat命令。参数提供检索文件属性、确定文件检验和等功能

stat模块返回一个包含文件状态数据的值的散列字典,允许用户使用单独的变量引用各条信息

以下示例注册stat模块的结果,然后显示它检查的文件的MD5检验和。

- name: Verify the checksum of a file
  stat:
    path: ~/file/123
    checksum_algorithm: md5
  register: result
  
- debug
  msg: "The checksum of the file is {{ result.stat.checksum }}"

有关stat模块返回的值的信息由ansible-doc记录,或者可以注册一个变量并显示其内容以查看可用内容:

- hosts: node2
  tasks:
    - name: stat /etc/passwd
      stat:
        path: /etc/passwd
      register: results
      
    - name: Display stat results
      debug:
        var: results

同步控制节点和受管主机之间的文件

synchronize模块是一个围绕rsync工具的打包程序,它简化了playbook中的常见文件管理任务。rsync工具必须同时安装在本机和远程主机上。默认情况下,在使用synchronize模块时,“本地主机”是同步任务所源自的主机(通常是控制节点),而“目标主机”是synchronize连接到的主机。

以下示例将位于Ansible工作目录中的文件同步到受管主机:

- name: tong bu
  synchronize:
    src: file
    dest: ~/file/abc

有很多种方法可以使用synchronize模块及其许多参数,包括同步目录。运行ansible-doc synchronize命令查看其他参数和playbook示例。