ansible变量的使用

本章主要介绍playbook中的变量

  • 自定义变量
  • 使用变量文件
  • 字典变量
  • 列表变量
  • facts变量
  • 内置变量
  • 变量的过滤器

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

复制代码
[blab@node01 ~]$ mkdir demo2
[blab@node01 ~]$ cp ansible.cfg hosts demo2/
[blab@node01 ~]$ cd demo2/
[blab@node01 demo2]$ ls
ansible.cfg  hosts
[blab@node01 demo2]$ 

1.自定义变量

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

1 vars :
2 变量 1 : 值 1
3 变量 2 : 值 2
4 ...
定义变量时,不可有重复的变量,否则后面定义的变量的值会覆盖前面定义的变量的值, 如下所示。
1 vars :
2 aa : value1
3 bb : value2
4 aa : value3
5 ...
这里aa重复定义了,所以aa的值最终是value3。
引用变量时用 {{变量名}} ,大括号内侧两边是否有空格是无所谓的,如下所示。
1 {{ 变量名 }}
2 {{ 变量名 }}
3 {{ 变量名 }}
4 {{ 变量名 }}

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

myname1=tom
myname2=tom2
myname3=tom3
然后打印mynamel的值,命令如下。

复制代码
[blab@node01 demo2]$ cat a.yml 
---
- hosts: node02
  vars:
   myname1: tom1
   myname2: tom2
   myname3: tom3
  tasks:
  - name: 打印某个变量
    debug: msg="变量myname1的值是{{myname1}}"
[blab@node01 demo2]$ 

运行此playbook,命令如下。

复制代码
[blab@node01 demo2]$ ansible-playbook a.yml 

PLAY [node02] ******************************************************************

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

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

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

[blab@node01 demo2]$

可以看到,打印了myname1的值为 tom1。
定义变量时,同一个变量定义多次,后面定义的生效,修改a.yml的内容如下。

复制代码
[blab@node01 demo2]$ cat a.yml 
---
- hosts: node02
  vars:
   myname1: tom1
   myname2: tom2
   myname3: tom3
   myname1: tom3        //增加内容
  tasks:
  - name: 打印某个变量
    debug: msg="变量myname1的值是{{myname1}}"
[blab@node01 demo2]

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

复制代码
[blab@node01 demo2]$ ansible-playbook a.yml 
[WARNING]: While constructing a mapping from /home/blab/demo2/a.yml, line 4,
column 4, found a duplicate dict key (myname1). Using last defined value only.

PLAY [node02] ******************************************************************

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

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

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

[blab@node01 demo2]$ 

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

2.变量文件

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

例如,创建文件vars.yml,内容如下。
复制代码
[blab@node01 demo2]$ cat vars.yml 
myv1: aaa
myv2: bbb
myv3: ccc
[blab@node01 demo2]$ 
修改1.yaml 的内容如下。
复制代码
[blab@node01 demo2]$ cat a.yml 
---
- hosts: node02
  vars_files:        //增加变量
  - vars.yml        //变量嵌套文件
  vars:
   myname1: tom1
   myname2: tom2
   myname3: tom3
   myname1: tom3
  tasks:
  - name: 打印某个变量
    debug: msg="变量myname1的值是{{myname1}}"
  - name: 打印变量myv1的值
    debug: msg="变量myv1的值是{{myv1}}"        //增加嵌套文件的值
[blab@node01 demo2]$

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

复制代码
[blab@node01 demo2]$ ansible-playbook a.yml 
[WARNING]: While constructing a mapping from /home/blab/demo2/a.yml, line 6,
column 4, found a duplicate dict key (myname1). Using last defined value only.

PLAY [node02] ******************************************************************

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

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

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

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

[blab@node01 demo2]$ 

3.字典变量

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

同一个字典中定义的多个变量不可有重复值,否则后面定义的变量会覆盖前面定义的变量。
要是引用木桶中的变量,必须指定是哪个木桶中的变量。例如,要引用木桶xx中的变量 aa,则使用xx.aa。
字典是在vars下定义的,语法如下。

1 字典名 :
2 var1 : value2
3 var2 : value2
4 ...
注意 : 在字典中定义这一个个变量时,变量前面是不加"-"的,且定义变量没有先后顺序。

通过"字典名.变量名"这种格式来引用变量,看下面的例子。
复制代码
[blab@node01 demo2]$ cat bb.yml 
---
- hosts: node02
  vars:
   dict1:
    myv1: aaa
    myv2: bbb
    myv3: ccc
   dict2:
    myv1: 111
    myv2: 222
    myv3: 333
  tasks:
  - name: 打印第一个变量
    debug: msg="{{dict1.myv1}}"
[blab@node01 demo2]$ 

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

复制代码
[blab@node01 demo2]$ ansible-playbook bb.yml 

PLAY [node02] ******************************************************************

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

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

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

[blab@node01 demo2]$ 

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

4.列表变量

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

  1. uname:记录用户名
  2. age:记录年龄
  3. sex:记录性别
这个员工表的内容如下:
复制代码
employee:
 uname: lisi
 age: 22
 sex: man
 
 uname: wangwu
 age: 19
 sex: man
 
 uname: xiaohua
 age: 20
 sex: wuman

为了看得清楚,这里把每个用户用空白行隔开了。每个用户都是由3个变量组成的一个整体,这个整体是员工表employee的一个元素。所以,这个员工表有3个元素,即3个人。
每个元素都有uname,所以列表employee共有3个uname,但是这3个uname不应该是冲突的,因为它们分别属于不同的人。
但是为了防止误会,每个元素的第一个变量前都加上一个"-",表示它是这个元素的第一个变量。所以,员工表改成如下内容。

复制代码
employee:
 - uname: lisi
   age: 22
   sex: man
 
 - uname: wangwu
   age: 19
   sex: man
 
 - uname: xiaohua
   age: 20
   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]。
列表和字典的不同如下:
(1)列表的每个元素的第一个变量都是以"-"开头。
(2)字典的每个变量前面都不带"-"。

练习1:写一个名称为3-list.yaml 的playbook,定义一个用户列表,里面包含3个用户,每个用户由uname、sex、age组成,命令如下
复制代码
[blab@node01 demo2]$ cat cc.yml 
---
- hosts: node02
  vars:
   users:
   - uname: tom
     sex: man
     age: 19
   - uname: bob
     sex: man
     agx: 20
   - uname: mary
     sex: women
     age: 18
  tasks:
  - name: 打印一个变量
    debug: msg={{users.2}}
[blab@node01 demo2]$

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

复制代码
[blab@node01 demo2]$ ansible-playbook cc.yml 

PLAY [node02] ******************************************************************

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

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

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

[blab@node01 demo2]$

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

复制代码
[blab@node01 demo2]$ cat cc.yml 
---
- hosts: node02
  vars:
   users:
   - uname: tom
     sex: man
     age: 19
   - uname: bob
     sex: man
     agx: 20
   - uname: mary
     sex: women
     age: 18
  tasks:
  - name: 打印一个变量
    debug: msg={{users.2.uname}}    //增加uname
[blab@node01 demo2]$

运行此playbook,命令如下

复制代码
[blab@node01 demo2]$ ansible-playbook cc.yml 

PLAY [node02] ******************************************************************

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

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

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

[blab@node01 demo2]$ 

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

1 listname :
2 ‐ var1
3 ‐ var2
4 ‐ var3
5 ...
这种定义变量的方式可以换成如下内容。

复制代码
 listname: [var1,var2,var3,...]

5.数字变量的运算

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

练习:写一个名称为4-vars,yaml 的 playbook,定义了变量aa,值为3,然后求aa*2和 aa的3次方
复制代码
[blab@node01 demo2]$ cat dd.yml 
---
- hosts: node02
  vars:
   aa: 3
  tasks:
  - name: 3*2的值
    debug: msg={{aa*2}}
  - name: 3的3次方
    debug: msg={{3**3}}
[blab@node01 demo2]$ 

运行此playbook

复制代码
[blab@node01 demo2]$ ansible-playbook dd.yml 

PLAY [node02] ******************************************************************

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

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

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

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

[blab@node01 demo2]$

6.注册变量

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

练习:写一个 playbook,在里面执行系统命令hostname
复制代码
[blab@node01 demo2]$ cat ee.yml 
---
- hosts: node02
  tasks:
  - name: 执行一个操作系统命令
    shell: 'hostname'
[blab@node01 demo2]$ 

运行此playbook,命令如下。

复制代码
[blab@node01 demo2]$ ansible-playbook ee.yml 

PLAY [node02] ******************************************************************

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

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

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

[blab@node01 demo2]$

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

复制代码
[blab@node01 demo2]$ cat ee.yml 
---
- hosts: node02
  tasks:
  - name: 执行一个操作系统命令
    shell: 'hostname'
    register: aa
  - name: 打印注册变量aa的值
    debug: msg={{aa}}
[blab@node01 demo2]$ 

运行此playbook

复制代码
[blab@node01 demo2]$ ansible-playbook ee.yml 

PLAY [node02] ******************************************************************

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

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

TASK [打印注册变量aa的值] **************************************************************
ok: [node02] => {
    "msg": {
        "changed": true,
        "cmd": "hostname",
        "delta": "0:00:00.002749",
        "end": "2023-12-21 12:02:47.875633",
        "failed": false,
        "rc": 0,
        "start": "2023-12-21 12:02:47.872884",
        "stderr": "",
        "stderr_lines": [],
        "stdout": "node02",
        "stdout_lines": [
            "node02"
        ]
    }
}

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

[blab@node01 demo2]$ 

结果中msg后面的内容就是aa的值,可以看到aa就是一个字典。其中cmd是执行的系统命令,rc是此命令的返回值,stdout表示此命令的结果。
所以,如果只获取这个命令的结果,只要打印字典aa中的 stdout 变量即可。修改ee.yml的内容如下。

复制代码
[blab@node01 demo2]$ cat ee.yml 
---
- hosts: node02
  tasks:
  - name: 执行一个操作系统命令
    shell: 'hostname'
    register: aa
  - name: 打印注册变量aa的值
    debug: msg={{aa.stdout}}    //增加stdout
[blab@node01 demo2]$ 

运行此playbook

复制代码
[blab@node01 demo2]$ ansible-playbook ee.yml 

PLAY [node02] ******************************************************************

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

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

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

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

[blab@node01 demo2]$

7.facts变量

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

复制代码
[blab@node01 demo2]$ cat ff.yml 
---
- hosts: node02
  vars:
   list1: ['aaa: ']
  tasks:
  - name: 打印IP
    debug: msg={{ansible_default_ipv4.address}}
  - name: 打印主机名
    debug: msg={{ansible_fqdn}}
[blab@node01 demo2]$

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

复制代码
[blab@node01 demo2]$ ansible-playbook ff.yml 

PLAY [node02] ******************************************************************

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

TASK [打印IP] ********************************************************************
ok: [node02] => {
    "msg": "192.168.182.193"
}

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

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

[blab@node01 demo2]$ 

这里显示 node02的 IP 是192.168.182.193,主机名是node02。

8.内置变量 groups

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

groups用于列出清单文件中所有定义的主机组及里面的主机,看下面的例子。
复制代码
[blab@node01 demo2]$ cat gg.yml 
---
- hosts: node02
  tasks:
  - name: xxx
    debug: msg={{groups}}
[blab@node01 demo2]$ 

运行此playbook,命令如下。

复制代码
[blab@node01 demo2]$ ansible-playbook gg.yml 

PLAY [node02] ******************************************************************

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

TASK [xxx] *********************************************************************
ok: [node02] => {
    "msg": {
        "all": [
            "node02",
            "node04",
            "node03"
        ],
        "db": [
            "node02",
            "node03"
        ],
        "db1": [
            "node02",
            "node04"
        ],
        "ungrouped": []
    }
}

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

[blab@node01 demo2]$

这里显示了清单文件中所有的主机组及里面的主机信息
如果只想列出某个主机组,可以通过"groups['主机组名]"或"groups.主机组名"来表示。修改gg.yml的内容如下。

复制代码
[blab@node01 demo2]$ cat gg.yml 
---
- hosts: node02
  tasks:
  - name: xxx
    debug: msg={{groups.db}}    //增加内容.db
[blab@node01 demo2]$ 

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

复制代码
[blab@node01 demo2]$ ansible-playbook gg.yml 

PLAY [node02] ******************************************************************

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

TASK [xxx] *********************************************************************
ok: [node02] => {
    "msg": [
        "node02",
        "node03"
    ]
}

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

[blab@node01 demo2]$

可以看到,这里只显示了db 主机组中的主机。
groups.db可以改写成 groups['db'],如下所示。

复制代码
[blab@node01 demo2]$ cat gg.yml 
---
- hosts: node02
  tasks:
  - name: xxx
    debug: msg={{groups['db']}}
[blab@node01 demo2]$

9.内置变量hostvars

hostvars用来显示指定主机的 fact变量,用法如下
hostvars [ ' 主机名 ' ]. 键值
此变量一般用于,当某个play的 hosts 中只写了A主机组,但是同时想在此play中显示B主机组中的信息,这时可以选择此变量。

练习:写一个playbook,里面包含一个play,里面的hosts指定为node02,但是要显示node03的IP地址,命令如下。
复制代码
[blab@node01 demo2]$ cat hh-hostvars.yml 
---
- hosts: node02
  tasks:
  - name: 打印node03的ip
    debug: msg={{hostvars.node03.ansible_default_ipv4.address}}
[blab@node01 demo2]$

运行此playbook

复制代码
[blab@node01 demo2]$ ansible-playbook hh-hostvars.yml 

PLAY [node02] ******************************************************************

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

TASK [打印node03的ip] *************************************************************
fatal: [node02]: 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/blab/demo2/hh-hostvars.yml': 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: 打印node03的ip\n    ^ here\n"}

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

[blab@node01 demo2]$ 

这里却出现了报错,这是因为play 的hosts中只写了node02,所以只会获取node02的 fact 变量,并不会获取node03的fact变量,也就不会识别node03上的ansible_default_ipv4.address。
修改hh-hostvars.yml的内容如下

复制代码
[blab@node01 demo2]$ cat hh-hostvars.yml 
---
- hosts: node03

- hosts: node02
  tasks:
  - name: 打印node03的ip
    debug: msg={{hostvars.node03.ansible_default_ipv4.address}}
[blab@node01 demo2]$

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

复制代码
[blab@node01 demo2]$ ansible-playbook hh-hostvars.yml 

PLAY [node03] ******************************************************************

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

PLAY [node02] ******************************************************************

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

TASK [打印node03的ip] *************************************************************
ok: [node02] => {
    "msg": "192.168.182.210"
}

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

[blab@node01 demo2]$ 

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

10.内置变量inventory hostname

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

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

练习:写一个playbook,在主机组db上执行,命令如下。
复制代码
[blab@node01 demo2]$ cat 9-inventory.yml 
---
- hosts: db
  tasks:
  - name: 打印我在清单文件中的名称
    debug: msg={{inventory_hostname}}
[blab@node01 demo2]$

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

复制代码
[blab@node01 demo2]$ ansible-playbook 9-inventory.yml 

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

TASK [Gathering Facts] *********************************************************
ok: [node03]
ok: [node02]

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

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

[blab@node01 demo2]$

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

复制代码
[blab@node01 demo2]$ cat hosts 
node02
node03

[db]
node02
node03

[xx]        //增加的主机组
node02
[blab@node01 demo2]$

修改9-inventory1.yml的内容如下。

复制代码
[blab@node01 demo2]$ cat 9-inventory.yml 
---
- hosts: db
  tasks:
  - name: 打印我在清单文件中的名称
    debug: msg={{inventory_hostname}}
    when: inventory_hostname in groups ['xx']    //增加内容
[blab@node01 demo2]$

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

复制代码
[blab@node01 demo2]$ ansible-playbook 9-inventory.yml 

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

TASK [Gathering Facts] *********************************************************
ok: [node03]
ok: [node02]

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

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

[blab@node01 demo2]$

这里跳过了node03,只有ndoe02执行了debug模块。

11.变量的过滤器

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

练习:把大写字符转换成小写字符,命令如下。
复制代码
[blab@node01 demo2]$ cat 10-vars1.yml 
---
- hosts: node02
  vars:
   aa: tom
   bb: BOB
  tasks:
  - name: xxx
    debug: msg={{bb | lower}}
[blab@node01 demo2]$

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

复制代码
[blab@node01 demo2]$ ansible-playbook 10-vars1.yml 

PLAY [node02] ******************************************************************

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

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

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

[blab@node01 demo2]$

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

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

11.1.数字类型

整型int,可以把字符串转换成整型,看下面的例子。
复制代码
[blab@node01 demo2]$ cat 10-vars2.yml 
---
- hosts: node02
  tasks:
  - name: 数学运算
    debug: msg:{{3+'3'}}
[blab@node01 demo2]$
这里对3+'3'进行数学运算,但是第二个3用单引号引起来了,说明是一个字符串,用数字3和字符串3相加是要报错的,运行结果如下。
复制代码
[blab@node01 demo2]$ ansible-playbook 10-vars2.yml 

PLAY [node02] ******************************************************************

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

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

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

[blab@node01 demo2]$ 
这里报错的提示信息的意思是,数字不能和字符串进行数学运算。我们可以把字符串'3'通过int转换成数字,修改10-vars2.yml的内容如下。
复制代码
[blab@node01 demo2]$ cat 10-vars2.yml 
---
- hosts: node02
  tasks:
  - name: 数学运算
    debug: msg={{3+('3'|int)}}
[blab@node01 demo2]$ 
其中'3'通过管道传递给int,转换成整型类型的,这样就可以相加了,运行结果如下。
复制代码
[blab@node01 demo2]$ ansible-playbook 10-vars2.yml 

PLAY [node02] ******************************************************************

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

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

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

[blab@node01 demo2]$
2.浮点型float,可以把字符串转换成小数类型的数字,修改10-vars2.yaml的内容如下。
复制代码
[blab@node01 demo2]$ cat 10-vars2.yml 
---
- hosts: node02
  tasks:
  - name: 数学运算
    debug: msg={{3+('3'|float)}}
[blab@node01 demo2]$ 
这里用float把'3'转换成浮点型,即 3.0,运行结果如下。
复制代码
[blab@node01 demo2]$ ansible-playbook 10-vars2.yml 

PLAY [node02] ******************************************************************

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

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

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

[blab@node01 demo2]$ 
3.绝对值abs,可以把负数转换成正数,如-3变成3,修改10-vars2.yaml的内容如下。
复制代码
[blab@node01 demo2]$ cat 10-vars2.yml 
---
- hosts: node02
  tasks:
  - name: 数学运算
    debug: msg={{-3 | abs}}
[blab@node01 demo2]$
这里用abs求-3的绝对值,得到的值应该是3,运行结果如下。
复制代码
[blab@node01 demo2]$ ansible-playbook 10-vars2.yml 

PLAY [node02] ******************************************************************

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

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

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

[blab@node01 demo2]$

11.2列表

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

  1. length:用于求列表的长度
  2. max:用于求列表中的最大值
  3. min:用于求列表中的最小值
练习:写一个 playbook,内容如下。
复制代码
[blab@node01 demo2]$ cat 10-vars3.yml 
---
- hosts: node02
  vars:
   list1: [1,2,8,3,2]
  tasks:
  - name: 求列表长度
    debug: msg="{{list1 | length}}"
  - name: 求列表中的最大值
    debug: msg="{{list1 | max}}"
  - name: 求列表中的最小值
    debug: msg="{{list1 | min}}"
[blab@node01 demo2]$ 
这里定义了一个列表list1,然后分别求列表的长度、最大值、最小值,运行结果如下。
复制代码
[blab@node01 demo2]$ ansible-playbook 10-vars3.yml 

PLAY [node02] ******************************************************************

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

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

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

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

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

[blab@node01 demo2]$

可以看到,列表的长度为5,说明列表中有5个元素,最大值为8,最小值为1。用于列表的过滤器还包括sort(排序)、sum(求和)、shuffle(打乱顺序显示)等。

11.3设置默认值default

如果某个变量没有被定义,那么可以通过default给它设置一个默认值,用法如下。
{{ var1 | default(value1) }}
如果某个变量var1已经定义了,则显示它自己的值;如果没有被定义,则被赋值为value1.

练习:写一个playbook,内容如下。
复制代码
[blab@node01 demo2]$ cat 10-vars4.yml 
---
- hosts: node02
  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')}}"
[blab@node01 demo2]$

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

复制代码
[blab@node01 demo2]$ ansible-playbook 10-vars4.yml 

PLAY [node02] ******************************************************************

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

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

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

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

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

[blab@node01 demo2]$

11.4字符串相关

string能把其他数据类型转换成字符串,看下面的例子。
复制代码
[blab@node01 demo2]$ cat 10-vars5.yml 
---
- hosts: node02
  tasks:
  - name: 求和
    debug: msg="{{3+3|string}}"
[blab@node01 demo2]$
3+3本身是可以正常运行的,但这里通过3string把第二个3转换成了字符串,因为数字只能和数字相加,所以上述执行数字3和字符串3相加会报错,运行结果如下。
复制代码
[blab@node01 demo2]$ ansible-playbook 10-vars5.yml 

PLAY [node02] ******************************************************************

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

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

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

[blab@node01 demo2]$ 

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

capitalize过滤器用于把字符串的首字符转换成大写,看下面的例子。
复制代码
[blab@node01 demo2]$ cat 10-vars6.yml 
---
- hosts: node02
  tasks:
  - name: 字符串集
    debug: msg="{{'aa' | capitalize}}"
[blab@node01 demo2]$
运行此playbook,命令如下。
复制代码
[blab@node01 demo2]$ ansible-playbook 10-vars6.yml 

PLAY [node02] ******************************************************************

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

TASK [字符串集] ********************************************************************
ok: [node02] => {
    "msg": "Aa"
}

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

[blab@node01 demo2]$ 

可以看到,aa通过capitalize过滤器转换之后,首字符变成了大写。
关于字符的过滤器还有upper(把小写字符转换成大写)、lower(把大写字符转换成小写),这些请大家自行练习。

11.5加密相关

有时需要对字符串进行加密操作,例如,在创建用户时给用户设置密码,就要用密文的形式而不能用明文。
求哈希值hash,算法可以是md5 或sha等,用法如下。
hash ( ' 算法名 ' )

练习1:写一个 playbook,对字符串 haha001实现不同的加密,命令如下。
复制代码
[blab@node01 demo2]$ cat 10-vars7.yml 
---
- hosts: node02
  vars:
   password: aaa001
  tasks:
  - name: 用md5加密
    debug: msg={{password | hash('md5')}}
  - name: 用sha1加密
    debug: msg={{password | hash('sha1')}}
  - name: 用sha512加密
    debug: msg={{password | hash('sha512')}}
[blab@node01 demo2]$ 
这里定义了一个变量 passa=haha001,然后分别使用md5、sha1、sha512对它进行加密,运行结果如下
复制代码
[blab@node01 demo2]$ ansible-playbook 10-vars7.yml 

PLAY [node02] ******************************************************************

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

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

TASK [用sha1加密] *****************************************************************
ok: [node02] => {
    "msg": "189d05ec2089c54128700410b76168bb0bea9be8"
}

TASK [用sha512加密] ***************************************************************
ok: [node02] => {
    "msg": "47bb39c0066fad64c31187030979d822b984c6f5fd6acf5db401b914fe69d279c7229f33c7485cfa1c00de6fa0fea36ee87e6c39aa3ba0a29edadb070be71d72"
}

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

[blab@node01 demo2]$ 

注意: hash过滤器中的md5或sha要用单引号引起来
password_hash ( ' 算法名 ' )
在 Linux系统中,用户密码一般使用的是sha512加密算法,所以一般用 password_hash('sha512')给用户的密码加密。

修改10-vars7.yaml的内容如下。
复制代码
[blab@node01 demo2]$ cat 10-vars7.yml 
---
- hosts: node02
  vars:
   password: aaa001
  tasks:
  - name: 用md5加密
    debug: msg={{password | password_hash('md5')}}    //修改内容
[blab@node01 demo2]$ 
这里调用sha512对变量 password 的值(就是 aaa001)进行加密,运行结果如下。
复制代码
[blab@node01 demo2]$ ansible-playbook 10-vars7.yml 

PLAY [node02] ******************************************************************

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

TASK [用md5加密] ******************************************************************
ok: [node02] => {
    "msg": "$1$.JFajmN6$pg5Bkp9E.jqvN1abNghW1/"
}

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

[blab@node01 demo2]$

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

练习2:在server2上创建用户bob,并设置密码为haha001。
先确定node02上不存在bob用户,命令如下。
复制代码
[blab@node01 demo2]$ ansible node02 -m shell -a "id bob"
node02 | FAILED | rc=1 >>
id: "bob":无此用户non-zero return code
[blab@node01 demo2]$
然后开始写playbook,内容如下。
复制代码
[blab@node01 demo2]$ cat 10-vars8.yml 
---
- hosts: node02
  vars:
   password: aaa001
  tasks:
  - name: 创建一个bob用户
    user: user=bob comment="Im bob" groups=root password={{password | password_hash('sha512')}}
[blab@node01 demo2]$ 

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

运行此 playbook
复制代码
[blab@node01 demo2]$ ansible-playbook 10-vars8.yml 

PLAY [node02] ******************************************************************

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

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

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

[blab@node01 demo2]$
验证,切换到node02上
复制代码
[blab@node01 demo2]$ ansible node02 -m shell -a "id bob"
node02 | CHANGED | rc=0 >>
uid=1003(bob) gid=1003(bob) 组=1003(bob),0(root)
[blab@node01 demo2]$

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

相关推荐
在野靡生.19 小时前
Ansible(4)—— Playbook
linux·运维·ansible
rocksun1 天前
如何使用Semaphore在Ansible上添加GUI
ansible
千航@abc4 天前
深度剖析 ansible:从部署基础到模块运用及剧本编写
运维·centos·ansible
一只栖枝4 天前
RHCA核心课程技术解析3:Ansible 自动化平台深度实践指南
linux·服务器·自动化·ansible·运维工程师·红帽认证·rhce认证
chairon5 天前
Ansible:playbook实战案例
运维·服务器·网络·ansible
leo·Thomas8 天前
什么是 Ansible Playbook?
ansible·playbook
luojiaao9 天前
【CICD】Ansible知识库
ansible
hhzz10 天前
从零开始使用 Ansible 自动化部署 SpringBoot Web 应用(含 MySQL、Redis、Vue、Nginx)
前端·自动化·ansible
zxnbmk15 天前
ansible速查手册
linux·服务器·ansible
book012115 天前
Ansible 自动化运维
运维·自动化·ansible