2.5 Ansible 变量和循环

变量

通过 Inventory 文件定义主机以及主机组变量

Ansible 默认的 Inventory 文件是 ini 格式,分别对每台主机设置一个变量名称叫做key,接着使用 debug 模块来查看变量的值,最后通过 nginx 组定义一个变量同样使用 debug 模块查看。如下所示

172.18.12.51 key=51
172.18.12.52 key=52
172.18.12.53 key=53
[nginx]
172.18.12.5[1:3]

编写一个 Playbook 文件来验证变量的引用是否正确

---
- hosts: all
  tasks:
    - name: display Host variale from hostfile
      debug: msg="the {{ inventory_hostname }} value is {{ key }}"

运行这个 Playbook 发现每天主机都引用了自己定义的变量,接下来我们注释每台主机的变量定义,直接给 nginx 组定义一个变量,变量名称还是 key ,值为 nginx,如下所示,

#172.18.12.51 key=51
#172.18.12.52 key=52
#172.18.12.53 key=53
[nginx]
172.18.12.5[1:3]
[nginx:vars]
key=nginx

执行 验证的 Playbook 可以看到,改组定义的变量针对组内所有主机都生效。如果 nginx 组定义了变量,然后每台主机也定义了变量,只要定义的变量 key 名称不同,我们都可以直接引用这些变量。

通过命令行传参传入

上边介绍了日常过程中常用的一种变量定义方式,接下来介绍一个通过 ansible-playbook 命令行传参的方式定义变量,但是默认传进去的变量都是全局变量。如下:

$ ansible-playbook variable.yml -e "key=value"

当然也支持同时传递多个变量,

$ ansible-playbook variable.yml -e 'pass_var="test" pass_var1="test1"'

而且命令行传入的变量的优先级要高于 Playbook 中设置的变量,这样可以更灵活的指定变量的值。

通过文件传入变量

ansible-playbook 支持指定文件的方式传入变量,变量文件支持 YAML 和 JSON 两种格式,如下所示

$ cat var.yml
---
key: value
$ cat var.json
{"key": "value"}

指定 var.json文件传入变量

$ ansible-playbook variable.yml -e "@var.json"

指定 var.yml文件传入变量

$ ansible-playbook variable.yml -e "@var.yml"

在 Playbook 文件中使用 vars

我们还可以在 Playbook 文件内通过 vars 字段定义变量,比如上边的 variable.yml 文件内容如下:

---
- hosts: all
  vars:
    key: ansible
  tasks:
    - name: display Host variale from hostfile
      debug: msg="the {{ inventory_hostname }} value is {{ key }}"

在 Playbook 文件内使用 vars_files

我们还可以在 Playbook 文件内通过 vars_files 字段引用变量,首先吧所有变量定义到某个文件内,然后在 Playbook 文件内使用 vars_files 参数引用这个变量文件,

---
- hosts: all
  vars_files:
    - var.yml
  tasks:
    - name: display Host variale from hostfile
      debug: msg="the {{ inventory_hostname }} value is {{ key }}"

var.yml 文件就是变量定义存放的文件,这个时候我们就可以直接运行 variable.yml 。

使用 register 内的变量

Ansible Playbook 内 task 之间还可以互相传递数据,比如我们有两个以上的 tasks ,其中第 2 个 task 是否执行是需要判断第一个 task 运行后的结果,这个时候我们就的在 task 之间传递数据,需要把第 1 个 task 执行的结果传递给第 2 个 task。 Ansible task 之间传递数据使用 register 方式,看一个简单的例子。

---
- hosts: all
  tasks:
    - name: register variable
      shell: hostname
      register: info
    - name: display Host variale from hostfile
      debug: msg="the variable is {{ info['stdout'] }}"

这里把第 1 个 task 执行的 hostname 的结果 register 给 info 这个变量,然后在第 2 个 task 把这个结果使用 debug 模块打印出来。

stdout 是一个标准的 Python 语言在字典中取值的用法。

使用 var_prompt 传入

Ansible 还支持在运行 Playbook 的时候通过交互式的方式给定义好的参数传入变量值,只需要在 Playbook 中定义 var_prompt 的变量名和交互式提交内容即可。

而且 Ansible 还支持对输入的变量值进行加密处理,比如采用 SHA512 和 MD5 算法加密,但是需要安装 passlib python 库。 下面来看一个例子。

---
- hosts: all
  vars_prompt:
    - name: "one"
      prompt: "please input one value"
      private: no
    - name: "two"
      prompt: "please input two value"
      default: 'good'
      private: yes

  tasks:
    - name: display one value
      debug: msg="one value is {{ one }}"
    - name: display two value
      debug: msg="one value is {{ two }}"

在例子中通过 vars_prompt 参数进行交互输入两个变量的值,变量名分别为 one 和 two ,one 定义为非私有变量,two 变量定义为私有变量且还提供一个默认值。如果不给变量 two 输入值的话,two 的变量的值会变成默认值。

循环

有时候写 Playbook 的时候发现写了很多的 task 都在重复引用某个模块,比如一次传输10个文件,就要写 10个 task。接下来介绍使用 loops 的方式去编写 Playbook 以减少重复使用某个模块。

标准 loops

标准 loops 是我们在编写 Playbook 过程中使用最多的一种 loops ,他能直接减少编写 task 的次数,示例如下:

---
- hosts: all
  tasks:
    - name: display loops
      debug: msg="name is {{ item }}"
      with_items:
        - one
        - two
        - aaa

with_items 的值是 python list 数据结果,可以理解为每个 task 会循环读取 list 李明的值,然后 key 的名称是 item,当然 list 里面也支持 python 字典。

---
- hosts: all
  tasks:
    - name: display loops
      debug: msg="name is {{ item.key }} ,vaule is {{  item.value }}"
      with_items:
        - {key: "one", vaule: "1"}
        - {key: "two", vaule: "2"}
        - {key: "AAA", vaule: "a"}

loops 除了标准的支持以外,还支持嵌套和散列

文件匹配 loops

文件匹配 loops 是我们编写 Playbook 的时候需要针对文件进行操作中最常用的一些循环,比如我们需要针对一个目录下指定哪个个事的文件进行处理,这个时候直接在引用的时候 用 with_fileglob 循环去匹配我们需要处理的 文件即可。 看一个例子。

---
- hosts: all
  tasks:
    - name: display loops
      debug: msg="file is {{ item }}"
      with_fileglob:
        - /root/*.yml

with_fileglob 会匹配 root 目录下所有以 yml 结尾的文件,当中 变量 item

随机 loops

随机选择一个作为变量。

---
- hosts: all
  tasks:
    - name: display loops
      debug: msg="file is {{ item }}"
      with_random_choice:
        - "A1"
        - "A2"
        - "A3"

with_random_choice 会在传入的 list 中随机选择一个,与 python random 实现原理一样。

条件判断 loops

有时候执行一个 task 以后,我们需要检查这个 task 的结果是否达到了预想状态,如果没有达到我们需要的状态是,就需要退出整个 Playbook 执行过程。这个时候我们就需要对某个task 结果一直循环检测了,示例如下

---
- hosts: all
  tasks:
    - name: display loops
      shell: cat /root/ansible
      register: host
      until: host.stdout.startswith("Master")
      retries: 5
      delay: 5

5 秒执行一次 cat /root/ansible 将结果 register 给 host 然后判断 host.stdout.startswith 的内容是否是 Master 字符串开头,如果条件成立,此 task 完成,如果条件不成立,5 秒后重试,5次后不成立,此 task 运行失败。

results matching ""

    No results matching ""