playbook变量的使用

本章主要介绍playbook中的变量。

目录

 手动定义变量 

变量文件 

字典变量 

列表变量 

数字变量的运算 

注册变量 

facts变量 

内置变量 groups 

 内置变量hostvars 

内置变量inventory hostname 

变量的过滤器 

(1)数字类型 

(2)列表 

(3)设置变量默认值default 

字符串相关 

加密相关 


为了能够写出更实用的playbook,需要在playbook中使用变量。下面来讲解playbook中常见的变量。本章实验都在/home/lduan/demo2下操作,先把 demo2目录创建出来并 把ansible.cfg和 hosts拷贝进去,命令如下。 

[bdqn@rhel01 ~]$ mkdir demo2
[bdqn@rhel01 ~]$ cp ansible.cfg hosts demo2/
[bdqn@rhel01 ~]$ cd demo2
[bdqn@rhel01 demo2]$ ls
ansible.cfg  hosts
[bdqn@rhel01 demo2]$

 手动定义变量 

通过vars来定义变量,vars和 tasks对齐。定义变量的格式如下。 

vars:

  变量1: 值1 

  变量2: 值2

  ...

定义变量时,不可有重复的变量,否则后面定义的变量的值会覆盖前面定义的变量的值, 如下所示。 

vars:

  aa: value1

  bb: value2

  aa: value3

  ... 

这里aa重复定义了,所以aa的值最终是value3。

引用变量时用 {{变量名}} ,大括号内侧两边是否有空格是无所谓的,如下所示。 

{{变量名}}

{{ 变量名 }}

{{ 变量名 }}

{{ 变量名 }} 

练习:写一个名称为1.yaml的playbook,里面定义以下3个变量。

myname1=tom1

myname2=tom2

myname3=tom3

然后打印mynamel的值,命令如下。 

[bdqn@rhel01 demo2]$ cat 1.yaml 
---
- hosts: server2
  vars:
    myname1: tom1
    myname2: tom2
    myname3: tom3
  tasks:
  - name: 打印某个变量
    debug: msg="变量myname1的值是{{myname1}}"
[bdqn@rhel01 demo2]$ 

运行此playbook,命令如下。 

[bdqn@rhel01 demo2]$ ansible-playbook 1.yaml 

PLAY [server2] ********************************************************************************************************************************************

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

TASK [打印某个变量] *********************************************************************************************************************************************
ok: [server2] => {
    "msg": "变量myname1的值是tom1"
}

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

[bdqn@rhel01 demo2]$ 

可以看到,打印了myname1的值为 tom1。

定义变量时,同一个变量定义多次,后面定义的生效,修改1.yaml的内容如下。 

[bdqn@rhel01 demo2]$ cat 1.yaml 
---
- hosts: server2
  vars:
    myname1: tom1
    myname2: tom2
    myname3: tom3
    myname1: tom3
  tasks:
  - name: 打印某个变量
    debug: msg="变量myname1的值是{{myname1}}"
[bdqn@rhel01 demo2]$ 

这里定义了两次 mynamel 这个变量,第一次定义的值为tom1,第二次定义的值为 tom3。下面运行此playbook查看结果,如下所示。 

[bdqn@rhel01 demo2]$ ansible-playbook 1.yaml 
[WARNING]: While constructing a mapping from /home/bdqn/demo2/1.yaml, line 4, column 5, found a duplicate dict key (myname1). Using last defined value
only.

PLAY [server2] ********************************************************************************************************************************************

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

TASK [打印某个变量] *********************************************************************************************************************************************
ok: [server2] => {
    "msg": "变量myname1的值是tom3"
}

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

[bdqn@rhel01 demo2]$

因为mynamel重复定义了两次,所以运行此playbook时会有提示,意思是变量重复定义 了,且后面定义的myname1生效,打印的结果为 tom3。 


变量文件 

如果定义的变量太多,可以把变量拿出来单独放在一个文件中,然后在playbook中通过 vars_files引用此变量文件,那么就可以直接使用此变量文件中的变量了,就像变量文件中的变量直接在YAML文件中定义似的,这样更方便管理。 

例如,创建文件vars.yaml,内容如下。

[bdqn@rhel01 demo2]$ cat vars.yaml 
myv1: aaa
myv2: bbb
myv3: ccc
[bdqn@rhel01 demo2]$

修改1.yaml 的内容如下。 

[bdqn@rhel01 demo2]$ cat 1.yaml 
---
- hosts: server2
  vars_files:
  - vars.yaml
  vars:
    myname1: tom1
    myname2: tom2
    myname3: tom3
    myname1: tom3
  tasks:
  - name: 打印某个变量
    debug: msg="变量myname1的值是{{myname1}}"
  - name: 打印变量myv1的值
    debug: msg='变量myv1的值是{{myv1}}'
[bdqn@rhel01 demo2]$ 

这里通过vars_files来引用变量文件 vars.yaml,然后打印变量myvl的值,运行结果如下。 

[bdqn@rhel01 demo2]$ 
[bdqn@rhel01 demo2]$ ansible-playbook 1.yaml 
[WARNING]: While constructing a mapping from /home/bdqn/demo2/1.yaml, line 6, column 5, found a duplicate dict key (myname1). Using last defined value only.

PLAY [server2] **********************************************************************************************************************************************

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

TASK [打印某个变量] ***********************************************************************************************************************************************
ok: [server2] => {
    "msg": "变量myname1的值是tom3"
}

TASK [打印变量myv1的值] *******************************************************************************************************************************************
ok: [server2] => {
    "msg": "变量myv1的值是aaa"
}

PLAY RECAP **************************************************************************************************************************************************
server2                    : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

[bdqn@rhel01 demo2]$ 

字典变量 

所谓字典(dictionaries简写为dict),就是存储多个变量的容器, 可以把字典理解为一个木桶,里面存放了很多个变量。如下图所 示,两个木桶xx和yy,里面分别存储了3个变量: aa=1,bb=2, cc=3。 

playbook变量的使用_第1张图片 

存储多个变量的容器

同一个字典中定义的多个变量不可有重复值,否则后面定义的变量会覆盖前面定义的变量。 

要是引用木桶中的变量,必须指定是哪个木桶中的变量。例如,要引用木桶xx中的变量 aa,则使用xx.aa。 

字典是在vars下定义的,语法如下。 

字典名:

  var1: value2 

  var2: value2

  ...

注意:在字典中定义这一个变量时,变量前面是不加“-”的,且定义变量没有先后顺序。 

通过“字典名.变量名”这种格式来引用变量,看下面的例子。 

[bdqn@rhel01 demo2]$ cat 2.yaml 
---
- hosts: server2
  vars:
    dict1:
      myv1: aaa
      myv2: bbb
      myv3: ccc
    dict2:
      myv1: 111
      myv2: 222
      myv3: 333
  tasks:
  - name: 打印第一个变量
    debug: msg="{{dict1.myv1}}"
[bdqn@rhel01 demo2]$ 

这里定义了两个字典dict1和 dict2,里面分别有3个变量,最后通过dict1.myvl引用了字典dick1中的变量myvl。通过ansible-playbook 2.yaml运行的结果应该为aaa,如下所示。 

[bdqn@rhel01 demo2]$ ansible-playbook 2.yaml 

PLAY [server2] **********************************************************************************************************************************************

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

TASK [打印第一个变量] **********************************************************************************************************************************************
ok: [server2] => {
    "msg": "aaa"
}

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

[bdqn@rhel01 demo2]$

如果在同一个字典中出现了相同的变量名,则后面定义的变量的值会覆盖前面定义的变量的值。


列表变量 

列表变量和字典变量比较容易弄混。下面来看一个例子,定义一个员工表,里面有3个员工,每个员工通过以下3个属性记录。 

  1. uname:记录用户名。
  2. age:记录年龄。
  3. sex:记录性别。这个员工表的内容如下。  

employee:

  uname: lisi

  age: 22

  sex: man

  uname: wangwu

  age: 24

  sex: man

  uname: xiaohua

  age: 21

  sex: wuman

为了看得清楚,这里把每个用户用空白行隔开了。每个用户都是由3个变量组成的一个整体,这个整体是员工表employee的一个元素。所以,这个员工表有3个元素,即3个人。 

每个元素都有uname,所以列表employee共有3个uname,但是这3个uname不应该是冲突的,因为它们分别属于不同的人。 

但是为了防止误会,每个元素的第一个变量前都加上一个“-”,表示它是这个元素的第 一个变量。所以,员工表改成如下内容。 

employee:

  - uname: lisi

  age: 22

  sex: man

  - uname: wangwu

  age: 24

  sex: man

  - uname: xiaohua

  age: 21

  sex: wuman

这样看起来就清晰了很多,这里employee就是一个列表。 

那如果想获取某个元素(某个员工)的信息该怎么办呢?可以通过employee[n]来获取, 这里的n叫作下标,下标从0开始。 

例如,要获取第一个用户的信息,则使用employee[0]即可,employee[0]得到的值如下。

uname: lisi

age: 22

sex: man 

可以看到,这是由3个变量组成的,这3个变量组成了一个字典,即employee[0]就是一个字典。如果想获取第一个用户的用户名,则可以通过employee[0].uname来获取。 

所以,员工表employee是由3个字典组成的;employee[0]、employee[1]、 employee[2]。

写一个名称为3.yaml 的playbook,定义一个用户列表,里面包含3个用户,每 个用户由uname、sex、age组成,命令如下。 

[bdqn@rhel01 demo2]$ cat 3.yaml 
---
- hosts: server2
  vars:
    users:
    - uname: tom
      sex: men
      age: 19
    - uname: bob
      sex: men
      age: 20
    - uname: mary
      sex: women
      age: 22
  tasks:
  - name: 打印一个变量
    debug: msg={{users[2]}}
[bdqn@rhel01 demo2]$

这里列表users定义了3个元素,现在要获取第3个元素用users[2]来表示,运行结果如下。 

[bdqn@rhel01 demo2]$ ansible-playbook 3.yaml 

PLAY [server2] **********************************************************************************************************************************************

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

TASK [打印一个变量] ***********************************************************************************************************************************************
ok: [server2] => {
    "msg": {
        "age": 22,
        "sex": "women",
        "uname": "mary"
    }
}

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

[bdqn@rhel01 demo2]$ 

如果要获取第3个用户的用户名,修改3.yaml的内容如下。 

[bdqn@rhel01 demo2]$ cat 3.yaml 
---
- hosts: server2
  vars:
    users:
    - uname: tom
      sex: men
      age: 19
    - uname: bob
      sex: men
      age: 20
    - uname: mary
      sex: women
      age: 22
  tasks:
  - name: 打印一个变量
    debug: msg={{users[2].uname}}
[bdqn@rhel01 demo2]$

运行此playbook,命令如下 

[bdqn@rhel01 demo2]$ ansible-playbook 3.yaml 

PLAY [server2] **********************************************************************************************************************************************

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

TASK [打印一个变量] ***********************************************************************************************************************************************
ok: [server2] => {
    "msg": "mary"
}

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

[bdqn@rhel01 demo2]$

定义列表时,也可以直接写值不写变量,通过如下方式来定义。 

listname:

‐ var1

‐ var2

‐ var3

...

这种定义变量的方式可以换成如下内容。

listname: [var1,var2,var3,...] 


数字变量的运算 

在YAML 文件中定义的变量,其值如果是数字,则可以进行数学运算。常见的数学运算符包括+(加)、-(减)、*(乘)、/(除)、**(次方)。 

写一个名称为4.yaml 的 playbook,定义了变量aa,值为3,然后求aa*2和 aa的3次方,命令如下。 

[bdqn@rhel01 demo2]$ cat 4.yaml 
---
- hosts: server2
  vars:
    aa: 3
  tasks: 
  - name: 3乘2的值
    debug: msg={{aa*2}}
  - name: 3的3次方
    debug: msg="{{3**3}}"
[bdqn@rhel01 demo2]$

运行此playbook,命令如下。 

[bdqn@rhel01 demo2]$ ansible-playbook 4.yaml 

PLAY [server2] **********************************************************************************************************************************************

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

TASK [3乘2的值] ************************************************************************************************************************************************
ok: [server2] => {
    "msg": "6"
}

TASK [3的3次方] ************************************************************************************************************************************************
ok: [server2] => {
    "msg": "27"
}

PLAY RECAP **************************************************************************************************************************************************
server2                    : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

[bdqn@rhel01 demo2]$

注册变量 

在playbook中用shell模块执行某个系统命令后,在结果中是不会显示这个命令结果的,这个和在命令行中用ansible命令调用shell模块不一样。 

写一个 playbook,在里面执行系统命令hostname,命令如下。 

[bdqn@rhel01 demo2]$ cat 5.yaml 
---
- hosts: server2
  tasks:
  - name: 执行一个操作系统命令
    shell: 'hostname'
[bdqn@rhel01 demo2]$

运行此playbook,命令如下。

[bdqn@rhel01 demo2]$ ansible-playbook 5.yaml 

PLAY [server2] **********************************************************************************************************************************************

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

TASK [执行一个操作系统命令] *******************************************************************************************************************************************
changed: [server2]

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

[bdqn@rhel01 demo2]$ 

可以看到,没有任何输出。如果想查看这个shell命令的结果,可以把shell 命令的结果保存在一个变量中,这个变量就是注册变量,然后打印这个变量的值即可。修改5.yaml 的内容如下。 

[bdqn@rhel01 demo2]$ cat 5.yaml 
---
- hosts: server2
  tasks:
  - name: 执行一个操作系统命令
    shell: 'hostname'
    register: aa
  - name: 打印注册变量aa的值
    debug: msg={{aa}}
[bdqn@rhel01 demo2]$ 

运行此playbook,命令如下 

[bdqn@rhel01 demo2]$ ansible-playbook 5.yaml 

PLAY [server2] **********************************************************************************************************************************************

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

TASK [执行一个操作系统命令] *******************************************************************************************************************************************
changed: [server2]

TASK [打印注册变量aa的值] *******************************************************************************************************************************************
ok: [server2] => {
    "msg": {
        "changed": true,
        "cmd": "hostname",
        "delta": "0:00:00.006506",
        "end": "2023-12-21 12:08:56.019337",
        "failed": false,
        "rc": 0,
        "start": "2023-12-21 12:08:56.012831",
        "stderr": "",
        "stderr_lines": [],
        "stdout": "rhel02",
        "stdout_lines": [
            "rhel02"
        ]
    }
}

PLAY RECAP **************************************************************************************************************************************************
server2                    : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

[bdqn@rhel01 demo2]$ 

结果中msg后面的内容就是aa的值,可以看到aa就是一个字典。其中cmd是执行的系统命令,rc是此命令的返回值,stdout表示此命令的结果。 

所以,如果只获取这个命令的结果,只要打印字典aa中的 stdout 变量即可。修改5.yaml的内容如下。 

[bdqn@rhel01 demo2]$ cat 5.yaml 
---
- hosts: server2
  tasks:
  - name: 执行一个操作系统命令
    shell: 'hostname'
    register: aa
  - name: 打印注册变量aa的值
    debug: msg={{aa.stdout}}
[bdqn@rhel01 demo2]$

运行此playbook,命令如下 

[bdqn@rhel01 demo2]$ ansible-playbook 5.yaml 

PLAY [server2] ********************************************************************************************************************************************

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

TASK [执行一个操作系统命令] *****************************************************************************************************************************************
changed: [server2]

TASK [打印注册变量aa的值] *****************************************************************************************************************************************
ok: [server2] => {
    "msg": "rhel02"
}

PLAY RECAP ************************************************************************************************************************************************
server2                    : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

[bdqn@rhel01 demo2]$

这里正确的显示了hostname的值为rhel02


facts变量 

ansible通过setup模块是可以获取到被管理主机的所有信息的,这些信息都是以变量的方式存在,这些变量称为facts,前面在setup模块中已经介绍过了。现在写一个名称为6.yaml的playbook,用于打印server2的IP和主机名,命令如下。 

[bdqn@rhel01 demo2]$ cat 6.yaml 
---
- hosts: server2
  vars:
    list1: ['aaa: ']
  tasks:
  - name: 打印IP
    debug: msg={{ansible_default_ipv4.address}}
  - name: 打印主机名
    debug: msg={{ansible_fqdn}}
[bdqn@rhel01 demo2]$ 

这里打印 IP 用到的fact变量是 ansible default ipv4.address,打印主机名用到的fact变量是 ansible_fqdn,运行结果如下。 

[bdqn@rhel01 demo2]$ ansible-playbook 6.yaml 

PLAY [server2] ********************************************************************************************************************************************

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

TASK [打印IP] ***********************************************************************************************************************************************
ok: [server2] => {
    "msg": "192.168.23.32"
}

TASK [打印主机名] **********************************************************************************************************************************************
ok: [server2] => {
    "msg": "rhel02"
}

PLAY RECAP ************************************************************************************************************************************************
server2                    : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

[bdqn@rhel01 demo2]$ 

这里显示 server2的 IP 是192.168.23.32,主机名是rhel02。 


内置变量 groups 

在 ansible 中,除用户手动去定义一些变量外,还有一些内置的变量,这些变量不需要用户定义就可以直接使用。 

groups用于列出清单文件中所有定义的主机组及里面的主机,看下面的例子。 

[bdqn@rhel01 demo2]$ cat 7.yaml 
---
- hosts: server2
  tasks:
  - name: xxx
    debug: msg={{groups}}
 
[bdqn@rhel01 demo2]$

运行此playbook,命令如下。 

[bdqn@rhel01 demo2]$ ansible-playbook 7.yaml 

PLAY [server2] ********************************************************************************************************************************************

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

TASK [xxx] ************************************************************************************************************************************************
ok: [server2] => {
    "msg": {
        "all": [
            "server2",
            "server3"
        ],
        "db": [
            "server2",
            "server3"
        ],
        "ungrouped": []
    }
}

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

[bdqn@rhel01 demo2]$

这里显示了清单文件中所有的主机组及里面的主机信息。 

如果只想列出某个主机组,可以通过“groups['主机组名]”或“groups.主机组名”来表 示。修改7.yaml的内容如下。 

[bdqn@rhel01 demo2]$ cat 7.yaml 
---
- hosts: server2
  tasks:
  - name: xxx
    debug: msg={{groups['db']}} 
[bdqn@rhel01 demo2]$ 

这里只显示主机组db中的主机,运行结果如下。 

[bdqn@rhel01 demo2]$ ansible-playbook 7.yaml 

PLAY [server2] ********************************************************************************************************************************************

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

TASK [xxx] ************************************************************************************************************************************************
ok: [server2] => {
    "msg": [
        "server2",
        "server3"
    ]
}

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

[bdqn@rhel01 demo2]$ 

可以看到,这里只显示了db 主机组中的主机。 

groups['db]可以改写成 groups.db,如下所示。 

[bdqn@rhel01 demo2]$ cat 7.yaml 
---
- hosts: server2
  tasks:
  - name: xxx
    debug: msg={{groups.db}} 
[bdqn@rhel01 demo2]$

 内置变量hostvars 

hostvars用来显示指定主机的 fact变量,用法如下。 

hostvars[' 主机名 '].键值 

此变量一般用于,当某个play的 hosts 中只写了A主机组,但是同时想在此play中显示B主机组中的信息,这时可以选择此变量。 

写一个playbook,里面包含一个play,里面的hosts指定为server2,但是要显示 server3的IP地址,命令如下。 

[bdqn@rhel01 demo2]$ cat 8.yaml 
---
- hosts: server2
  tasks:
  - name: 打印server3的IP
    debug: msg={{hostvars['server3'].ansible_default_ipv4.address}}
[bdqn@rhel01 demo2]$ 

运行此playbook,命令如下 

[bdqn@rhel01 demo2]$ ansible-playbook 8.yaml 

PLAY [server2] ********************************************************************************************************************************************

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

TASK [打印server3的IP] ***************************************************************************************************************************************
fatal: [server2]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'ansible.vars.hostvars.HostVarsVars object' has no attribute 'ansible_default_ipv4'\n\nThe error appears to be in '/home/bdqn/demo2/8.yaml': line 4, column 5, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n  tasks:\n  - name: 打印server3的IP\n    ^ here\n"}

PLAY RECAP ************************************************************************************************************************************************
server2                    : ok=1    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   

[bdqn@rhel01 demo2]$

这里却出现了报错,这是因为play 的hosts中只写了server2,所以只会获取server2的 fact 变量,并不会获取server3的fact变量,也就不会识别server3上的 ansible_default_ipv4.address 

修改8.yaml的内容如下。 

[bdqn@rhel01 demo2]$ cat 8.yaml 
---
- hosts: server3

- hosts: server2
  tasks:
  - name: 打印server3的IP
    debug: msg={{hostvars['server3'].ansible_default_ipv4.address}}
[bdqn@rhel01 demo2]$ 

这里只比前面多了一个play,且这个play中只写了一个 hosts: server3。但是这一句就可以获取到server3的 fact变量,这样在第二个play中再次获取server3的fact变量时就不会报错了。 

运行结果如下。

[bdqn@rhel01 demo2]$ ansible-playbook 8.yaml 

PLAY [server3] ********************************************************************************************************************************************

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

PLAY [server2] ********************************************************************************************************************************************

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

TASK [打印server3的IP] ***************************************************************************************************************************************
ok: [server2] => {
    "msg": "192.168.23.33"
}

PLAY RECAP ************************************************************************************************************************************************
server2                    : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
server3                    : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

[bdqn@rhel01 demo2]$

可以看到,此处已经正确地获取到 server3的IP了。


内置变量inventory hostname 

当ansible主机同时在多台被管理主机上执行任务时,每台被管理主机都会有一个变量记录它在清单文件中的名称是什么,如下图所示。 

playbook变量的使用_第2张图片 

主机记录清单名称 

这个变量就是inventory _hostname,记录了每个主机在清单文件中的名称。 

写一个playbook,在主机组db上执行,命令如下。 

[bdqn@rhel01 ~]$ cat 9.yaml 
---
- hosts: db
  tasks:
  - name: 打印我在清单文件中的名称
    debug: msg={{inventory_hostname}}
[bdqn@rhel01 ~]$

这里playbook 会在db主机组上执行,即在server2和 server3上执行。在server2上执行时inventory_hostname的值为server2,在server3上执行时 inventory_hostname的值为 server3,运行结果如下。 

[bdqn@rhel01 ~]$ ansible-playbook 9.yaml 

PLAY [db] *************************************************************************************************************************************************

TASK [Gathering Facts] ************************************************************************************************************************************
ok: [server3]
ok: [server2]

TASK [打印我在清单文件中的名称] ***************************************************************************************************************************************
ok: [server2] => {
    "msg": "server2"
}
ok: [server3] => {
    "msg": "server3"
}

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

[bdqn@rhel01 ~]$ 

上面的例子中,hosts 的值写的是 db,所以后续的task是要在server2和 server3上同时执行的。修改清单文件 hosts,添加一个主机组xx,里面的主机包括server2这一台主机。 

[bdqn@rhel01 demo2]$ cat hosts 
server2
server3

[db]
server2
server3

[xx]
server2
[bdqn@rhel01 demo2]$ 

修改9.yaml的内容如下。 

[bdqn@rhel01 demo2]$ cat 9.yaml 
---
- hosts: db
  tasks:
  - name: 打印我在清单文件中的名称
    debug: msg={{inventory_hostname}}
    when: inventory_hostname in groups ['xx']
[bdqn@rhel01 demo2]$ 

这里增加了一条判断语句when(后面会专门讲解),执行debug模块的条件是被管理主机要属于xx主机组。虽然 hosts后面跟的是db,server3在db主机组但没有在xx主机组中,条件不满足,所以在 server3上并不执行debug模块。运行结果如下。 

[bdqn@rhel01 demo2]$ ansible-playbook 9.yaml 

PLAY [db] *************************************************************************************************************************************************

TASK [Gathering Facts] ************************************************************************************************************************************
ok: [server2]
ok: [server3]

TASK [打印我在清单文件中的名称] ***************************************************************************************************************************************
ok: [server2] => {
    "msg": "server2"
}
skipping: [server3]

PLAY RECAP ************************************************************************************************************************************************
server2                    : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
server3                    : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   

[bdqn@rhel01 demo2]$

这里跳过了server3,只有server2执行了debug模块。


变量的过滤器 

所谓变量的过滤器,实际上就是对变量的值进行一些操作,例如,进行类型转化、截取、 加密等操作,使用格式如下。 

{{ 变量名 | 函数 }} 

把大写字符转换成小写字符,命令如下。 

[bdqn@rhel01 demo2]$ cat 10.yaml 
---
- hosts: server2
  vars:
    aa: tom
    bb: BOB
  tasks: 
  - name: xxx
    debug: msg={{bb | lower}}
[bdqn@rhel01 demo2]$ 

这里定义了一个变量bb值为大写的 BOB,通过 lower这个过滤器会把大写字符转换成小写字符。运行此playbook,命令如下。 

[bdqn@rhel01 demo2]$ vim 10.yaml
[bdqn@rhel01 demo2]$ ansible-playbook 10.yaml 

PLAY [server2] ********************************************************************************************************************************************

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

TASK [xxx] ************************************************************************************************************************************************
ok: [server2] => {
    "msg": "bob"
}

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

[bdqn@rhel01 demo2]$

可以看到,这里显示的是小写的bob。

下面列出几个常见的过滤器。


(1)数字类型 

整型int,可以把字符串转换成整型,看下面的例子。 

[bdqn@rhel01 demo2]$ cat 10.yaml 
---
- hosts: server2
  tasks: 
  - name: 数学运算
    debug: msg={{3+'3'}}
[bdqn@rhel01 demo2]$

这里对3+'3'进行数学运算,但是第二个3用单引号引起来了,说明是一个字符串,用数字 3和字符串3相加是要报错的,运行结果如下。 

[bdqn@rhel01 demo2]$ ansible-playbook 10.yaml 

PLAY [server2] ********************************************************************************************************************************************

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

TASK [数学运算] ***********************************************************************************************************************************************
fatal: [server2]: FAILED! => {"msg": "Unexpected templating type error occurred on ({{3+'3'}}): unsupported operand type(s) for +: 'int' and 'str'"}

PLAY RECAP ************************************************************************************************************************************************
server2                    : ok=1    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   

[bdqn@rhel01 demo2]$ 

这里报错的提示信息的意思是,数字不能和字符串进行数学运算。我们可以把字符串'3'通 过int转换成数字,修改10.yaml的内容如下。 

[bdqn@rhel01 demo2]$ cat 10.yaml 
---
- hosts: server2
  tasks: 
  - name: 数学运算
    debug: msg={{3+'3'|int}}
[bdqn@rhel01 demo2]$ 

其中'3'通过管道传递给int,转换成整型类型的,这样就可以相加了,运行结果如下。 

[bdqn@rhel01 demo2]$ ansible-playbook 10.yaml 

PLAY [server2] ********************************************************************************************************************************************

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

TASK [数学运算] ***********************************************************************************************************************************************
ok: [server2] => {
    "msg": "6"
}

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

[bdqn@rhel01 demo2]$ 

浮点型float,可以把字符串转换成小数类型的数字,修改10.yaml的内容如下。 

[bdqn@rhel01 demo2]$ cat 10.yaml 
---
- hosts: server2
  tasks: 
  - name: 数学运算
    debug: msg={{3+'3'|float}}
[bdqn@rhel01 demo2]$ 

这里用float把'3'转换成浮点型,即 3.0,运行结果如下。 

[bdqn@rhel01 demo2]$ ansible-playbook 10.yaml 

PLAY [server2] ********************************************************************************************************************************************

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

TASK [数学运算] ***********************************************************************************************************************************************
ok: [server2] => {
    "msg": "6.0"
}

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

[bdqn@rhel01 demo2]$ 

绝对值abs,可以把负数转换成正数,如-3变成3,修改10.yaml的内容如下。 

[bdqn@rhel01 demo2]$ cat 10.yaml 
---
- hosts: server2
  tasks: 
  - name: 数学运算
    debug: msg={{-3| abs }}
[bdqn@rhel01 demo2]$ 

这里用abs求-3的绝对值,得到的值应该是3,运行结果如下。 

[bdqn@rhel01 demo2]$ ansible-playbook 10.yaml 

PLAY [server2] ********************************************************************************************************************************************

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

TASK [数学运算] ***********************************************************************************************************************************************
ok: [server2] => {
    "msg": "3"
}

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

[bdqn@rhel01 demo2]$ 

(2)列表 

前面讲过一个列表中可以包括多个值,列表的过滤器可以求出列表的长度、最大值、最小 值等。 

length:用于求列表的长度。

max:用于求列表中的最大值。

min:用于求列表中的最小值。 

写一个 playbook,内容如下。 

[bdqn@rhel01 demo2]$ cat 11.yaml 
---
- hosts: server2
  vars:
    list1: [1,2,8,3,2]
  tasks:
  - name: 求列表长度
    debug: msg="{{list1 | length}}"
  - name: 求列表中的最大值
    debug: msg="{{list1 | max}}"
  - name: 求列表中的最小值
    debug: msg="{{list1 | min}}"
[bdqn@rhel01 demo2]$ 

这里定义了一个列表list1,然后分别求列表的长度、最大值、最小值,运行结果如下。 

[bdqn@rhel01 demo2]$ ansible-playbook 11.yaml 

PLAY [server2] ********************************************************************************************************************************************

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

TASK [求列表长度] **********************************************************************************************************************************************
ok: [server2] => {
    "msg": "5"
}

TASK [求列表中的最大值] *******************************************************************************************************************************************
ok: [server2] => {
    "msg": "8"
}

TASK [求列表中的最小值] *******************************************************************************************************************************************
ok: [server2] => {
    "msg": "1"
}

PLAY RECAP ************************************************************************************************************************************************
server2                    : ok=4    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

[bdqn@rhel01 demo2]$ 

可以看到,列表的长度为5,说明列表中有5个元素,最大值为8,最小值为1。 

用于列表的过滤器还包括sort(排序)、sum(求和)、shuffle(打乱顺序显示)等。 


(3)设置变量默认值default 

如果某个变量没有被定义,那么可以通过default给它设置一个默认值,用法如下。 

{{ var1 | default(value1) }} 

如果某个变量var1已经定义了,则显示它自己的值;如果没有被定义,则被赋值为value1. 

写一个playbook,内容如下。 

[bdqn@rhel01 demo2]$ cat 12.yaml 
---
- hosts: server2
  vars:
    aa: 11
    bb:
  tasks:
  - name: aa的值
    debug: msg="{{ aa | default('xxx')}}"
  - name: bb的值
    debug: msg="{{ bb | default('xxx')}}"
  - name: cc的值
    debug: msg="{{ cc | default('xxx')}}"
[bdqn@rhel01 demo2]$ 

这里定义了aa的值为11,定义了bb但是没有赋值,并没有定义cc。所以,打印aa时,会显示自己的值即11;打印bb时,会显示自己的值即空值;打印 cc时,显示的是default中的值即 xxx。运行结果下。 

[bdqn@rhel01 demo2]$ ansible-playbook 12.yaml 

PLAY [server2] ********************************************************************************************************************************************

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

TASK [aa的值] ***********************************************************************************************************************************************
ok: [server2] => {
    "msg": "11"
}

TASK [bb的值] ***********************************************************************************************************************************************
ok: [server2] => {
    "msg": ""
}

TASK [cc的值] ***********************************************************************************************************************************************
ok: [server2] => {
    "msg": "xxx"
}

PLAY RECAP ************************************************************************************************************************************************
server2                    : ok=4    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

[bdqn@rhel01 demo2]$ 

字符串相关 

string能把其他数据类型转换成字符串,看下面的例子。 

[bdqn@rhel01 demo2]$ cat 10.yaml 
---
- hosts: server2
  tasks: 
  - name: 求和
    debug: msg={{3+(3|string)}}
[bdqn@rhel01 demo2]$

3+3本身是可以正常运行的,但这里通过3string把第二个3转换成了字符串,因为数字只 能和数字相加,所以上述执行数字3和字符串3相加会报错,运行结果如下。 

[bdqn@rhel01 demo2]$ ansible-playbook 10.yaml 

PLAY [server2] ********************************************************************************************************************************************

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

TASK [求和] *************************************************************************************************************************************************
fatal: [server2]: FAILED! => {"msg": "Unexpected templating type error occurred on ({{3+(3|string)}}): unsupported operand type(s) for +: 'int' and 'str'"}

PLAY RECAP ************************************************************************************************************************************************
server2                    : ok=1    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   

[bdqn@rhel01 demo2]$ 

这个用法其实和前面的3+3'是类似的,单引号也可以转换成字符串。 

capitalize过滤器用于把字符串的首字符转换成大写,看下面的例子。 

[bdqn@rhel01 demo2]$ cat 10.yaml 
---
- hosts: server2
  tasks: 
  - name: 字符串转换
    debug: msg={{'aa' | capitalize}}
[bdqn@rhel01 demo2]$ 

运行此playbook,命令如下。 

[bdqn@rhel01 demo2]$ ansible-playbook 10.yaml 

PLAY [server2] ********************************************************************************************************************************************

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

TASK [字符串转换] **********************************************************************************************************************************************
ok: [server2] => {
    "msg": "Aa"
}

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

[bdqn@rhel01 demo2]$ 

可以看到,aa通过capitalize过滤器转换之后,首字符变成了大写。

关于字符的过滤器还有upper(把小写字符转换成大写)、lower(把大写字符转换成小写),这些请大家自行练习。 


加密相关 

有时需要对字符串进行加密操作,例如,在创建用户时给用户设置密码,就要用密文的形式而不能用明文。 

求哈希值hash,算法可以是md5 或sha等,用法如下。 

hash('算法名') 

写一个 playbook,对字符串 haha001实现不同的加密,命令如下。 

[bdqn@rhel01 demo2]$ cat 13.yaml 
---
- hosts: server2
  vars:
    passa: haha001
  tasks:
  - name: 用md5加密
    debug: msg={{passa | hash('md5')}}
  - name: 用sha1加密
    debug: msg={{passa | hash('sha1')}}
  - name: 用sha512加密
    debug: msg={{passa | hash('sha512')}}
[bdqn@rhel01 demo2]$ 

这里定义了一个变量 passa=haha001,然后分别使用md5、sha1、sha512对它进行加密,运行结果如下。 

[bdqn@rhel01 demo2]$ ansible-playbook 13.yaml 

PLAY [server2] ********************************************************************************************************************************************

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

TASK [用md5加密] *********************************************************************************************************************************************
ok: [server2] => {
    "msg": "da48dd48779209245c671bf9fddfde23"
}

TASK [用sha1加密] ********************************************************************************************************************************************
ok: [server2] => {
    "msg": "0d7c6d97655f38d7773c9a78a0861d533b1b32f1"
}

TASK [用sha512加密] ******************************************************************************************************************************************
ok: [server2] => {
    "msg": "b37c491d6a36ef90c6c718855c06cc53053fe646fcae8889fafbad198c07a91fc283dd266af5dceb5378ff0a04cc1f9062fd4ea203c81dd2c9fbc58efa72a68b"
}

PLAY RECAP ************************************************************************************************************************************************
server2                    : ok=4    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

[bdqn@rhel01 demo2]$ 

注意:hash过滤器中的md5或sha要用单引号引起来。 

password_hash('算法名') 

在 Linux系统中,用户密码一般使用的是sha512加密算法,所以一般用 password_hash('sha512')给用户的密码加密。 

修改13.yaml的内容如下。 

[bdqn@rhel01 demo2]$ cat 13.yaml 
---
- hosts: server2
  vars:
    passa: haha001
  tasks:
  - name: password_hash过滤器 sha512
    debug: msg={{passa | password_hash('md5')}}
[bdqn@rhel01 demo2]$ 

这里调用sha512对变量 passa 的值(就是 haha001)进行加密,运行结果如下。 

[bdqn@rhel01 demo2]$ ansible-playbook 13.yaml 

PLAY [server2] ********************************************************************************************************************************************

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

TASK [password_hash过滤器 sha512] ****************************************************************************************************************************
ok: [server2] => {
    "msg": "$1$7tR30EK2$2nFKNypc/hpgPmQMczNwl0"
}

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

[bdqn@rhel01 demo2]$

注意:password_hash过滤器中的sha512要用单引号引起来。 

在server2上创建用户bob,并设置密码为haha001。

先确定server2上不存在bob用户,命令如下。

[bdqn@rhel01 demo2]$ ansible server2 -m shell -a "id bob"
server2 | FAILED | rc=1 >>
id: “bob”:无此用户non-zero return code
[bdqn@rhel01 demo2]$ 

然后开始写playbook,内容如下。 

[bdqn@rhel01 demo2]$ cat 14.yaml 
---
- hosts: server2
  vars:
    passa: haha001
  tasks:
  - name: 创建一个bob用户
    user: user=bob comment="Im bob" groups=root password={{passa | password_hash('sha512')}}
[bdqn@rhel01 demo2]$ 

这里调用user模块,name指定用户名为bob,comment用于指定用户的描述信息, password用于指定密码。 

运行此 playbook,命令如下。 

[bdqn@rhel01 demo2]$ ansible-playbook 14.yaml 

PLAY [server2] ********************************************************************************************************************************************

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

TASK [创建一个bob用户] ******************************************************************************************************************************************
changed: [server2]

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

[bdqn@rhel01 demo2]$ 

验证,切换到server2 上,命令如下。 

[root@rhel02 ~]# su - tom
[tom@rhel02 ~]$ su - bob
密码:
[bob@rhel02 ~]$ 

这里先从 root切换到tom用户,因为root切换到其他任何用户都不需要密码。从tom用 户用su命令切换到bob用户时需要输入密码 haha001,证明bob用户已经创建成功且密码也是正确的。 

你可能感兴趣的:(Red,Hat,linux,运维,服务器,ansible)