侧边栏壁纸
博主头像
张种恩的技术小栈博主等级

行动起来,活在当下

  • 累计撰写 747 篇文章
  • 累计创建 65 个标签
  • 累计收到 39 条评论

目 录CONTENT

文章目录

ansible笔记(11)之内置变量

zze
zze
2020-03-29 / 0 评论 / 0 点赞 / 667 阅读 / 9494 字

不定期更新相关视频,抖音点击左上角加号后扫一扫右方侧边栏二维码关注我~正在更新《Shell其实很简单》系列

本来打算自己写一波 ansible 系列的,后来发现一老哥写的太好了,「点击此处直达」,我这里也就边看边对该系列文章做下笔记,方便以后查阅,ansible 入门的话墙裂建议阅读前方链接博文~~~

ansible_version

我们可以通过内置变量 ansible_version 获取到 ansible 的版本号,示例命令如下:

$ ansible B -m debug -a "msg={{ansible_version}}"

hostvars

hostvars 可以帮助我们在操作当前主机时获取到其他主机中的信息。

假设,我想要在操作 C 主机时获取到 B 主机中的 facts 信息,我该怎么办呢?示例如下:

---
- name: "play 1: Gather facts of B"
  hosts: B
 
- name: "play 2: Get facts of B when operating on C"
  hosts: C
  tasks:
  - debug:
      msg: "{{hostvars['B'].ansible_eth0.ipv4}}"

上例中有两个 play,第一个 play 针对 B 主机执行,但是第一个 play 中没有显式指定任何 task,第二个 play 针对 C 主机执行,在第二个 play 中只有一个 task,即使用 debug 模块,输出了 B 主机中的 eth0 网卡的 IP 信息。

如你所见,我们可以借助 hostvars 在操作当前主机时输出其他主机中的 facts 信息,上例中使用 hostvars 加上清单中的主机名称再加上 facts 的 key,即可获取到对应的 facts 信息。
上例中的msg的值改为如下写法也是可以的:

"{{hostvars.B.ansible_eth0.ipv4}}"

上例中的第一个 play 中并没有任何的 task,为什么还需要第一个 play 呢?如果你将上例的第一个 play 删除,只保留第二个 play,运行时则会报错,这是因为,虽然第一个 play 中没有任何 task,但是当第一个 play 执行时,默认会调用 [Gathering Facts] 任务,也就是说,默认会收集 B 主机的 facts 信息,只有被收集过的 facts 信息才能被后面的 play 引用到,如果压根没有收集对应主机的 facts 信息,即使使用 hostvars 内置变量,也无法获取到对应主机的 facts 信息。

我们来做个试验,我们可以直接把上例的第一个 play 从 playbook 中删除,也可以指明让第一个 play 不收集对应的 facts 信息,使用 gather_facts 关键字可以控制当前 play 是否收集对应主机的 facts 信息,示例如下:

---
- name: "play 1: Gather facts of B"
  hosts: B
  gather_facts: no
 
- name: "play 2: Get facts of B when operating on C"
  hosts: C
  tasks:
  - debug:
      msg: "{{hostvars['B'].ansible_eth0.ipv4}}"

如上例所示,第一个 play 中的 gather_facts: no 表示设置当前 play 不收集对应主机的信息,运行上例 playbook 会报错,因为第二个 play 在操作 B 时,无法获取到 B 主机中的 facts 信息,原因是 B 的 facts 信息并未被收集过,所以,调用其他主机的 facts 信息的前提是对应主机的 facts 信息已经被收集过。

其实,除了 facts 信息,我们还能够利用 hostvars 内置变量从别的主机中获取到其他类型的一些变量信息,比如,其他主机的注册变量、主机变量、组变量等信息,我们先来看一个获取其他主机的注册变量的小示例,如下:

---
- hosts: B
  gather_facts: no
  tasks:
  - shell: "echo register_var_in_play1"
    register: shellreturn
 
- hosts: C
  gather_facts: no
  tasks:
  - debug:
      msg: "{{hostvars.B.shellreturn.stdout}}"

如上例所示,通过 hostvars 内置变量可以直接获取到其他主机中的注册变量,你一定发现了,注册变量并不用像 facts 信息那样需要事先收集,即可直接通过 hostvars 跨主机被引用到,同理,如果你在清单中为 B 主机配置了主机变量,或者为 B 主机所在的组配置了组变量,也是可以通过 hostvars 直接跨主机引用的。

你可能会问,如果我直接在 play 中为当前主机定义一个变量,可以在之后的 play 中操作其他主机时被引用到吗?那么我们来做个实验,示例如下:

---
- hosts: B
  gather_facts: no
  vars:
    testvar: testvar_in_B
  tasks:
  - debug:
      msg: "{{testvar}}"
 
- hosts: C
  gather_facts: no
  tasks:
  - debug:
      msg: "{{hostvars.B.testvar}}"

在上例的第一个 play 中我们为 B 主机定义了一个变量,变量名称为 testvar,在第二个 play 中操作 B 主机时,使用 hostvars 尝试引用 B 主机中的变量。如果执行上述 playbook 则会报错,看来通过 vars 关键字定义的变量使用上例中的方法是无法被跨主机引用的。

聪明如你,一定想到了解决方案,前面我们总结了怎样使用 set_fact 模块定义变量,通过 set_fact 模块定义的变量拥有类似 facts 信息的特性,所以,我们可以把 vars 关键字中定义的变量通过 set_fact 模块去定义,这样这些变量就好像 facts 信息被收集过一样,能被之后的 play 引用到了,示例如下:

---
- hosts: B
  gather_facts: no
  tasks:
  - set_fact:
      testvar: "testvar_in_B"
  - debug:
      msg: "{{testvar}}"
 
- hosts: C
  gather_facts: no
  tasks:
  - debug:
      msg: "{{hostvars.B.testvar}}"

通过 set_fact 模块结合 hostvars 的方式,实现了跨 play 获取其他主机中的变量信息的功能,还是很方便的。

inventory_hostname

通过 inventory_hostname 变量可以获取到被操作的当前主机的主机名称,这里所说的主机名称并不是 linux 系统的主机名,而是对应主机在清单中配置的名称,假设我的清单配置如下:

B ansible_host=10.0.1.201
C ansible_host=10.0.1.202

那么我们使用内置变量 inventory_hostname 获取一下各个主机的对应的主机名,看看会返回什么,示例如下:

$ ansible all -m debug -a "msg={{inventory_hostname}}"          
B | SUCCESS => {
    "msg": "B"
}
C | SUCCESS => {
    "msg": "C"
}

从返回信息可以看出,如果使用 IP 配置主机,inventory_hostname 的值就是 IP,如果使用别名,inventory_hostname 的值就是别名。

inventory_hostname_short

与内置变量 inventory_hostname 类似,通过 inventory_hostname_short 也可以获取当前play操作的主机在清单中对应的名称,但是这个名称更加简短,假设我的清单配置如下:

B.host ansible_host=10.0.1.201
C.host ansible_host=10.0.1.202

那么通过内置变量 inventory_hostname_short 获取到的主机的简短名称如下:

$ ansible all -m debug -a "msg={{inventory_hostname_short}}"
B.host | SUCCESS => {
    "msg": "B"
}
C.host | SUCCESS => {
    "msg": "C"
}

可以看到,无论是 IP 还是别名,如果清单的主机名称中包含 .inventory_hostname_short 都会取得主机名中第一个 . 之前的字符作为主机的简短名称。

play_hosts

通过内置变量 play_hosts 可以获取到当前 play 所操作的所有主机的主机名列表,示例 playbook 如下:

---
- hosts: all
  gather_facts: no
  tasks:
  - debug:
      msg: "{{play_hosts}}"

执行上例的playbook,返回信息如下:

$ ansible-playbook test.yml 

PLAY [all] ****************************************************************************************************************************

TASK [debug] **************************************************************************************************************************
ok: [B.host] => {
    "msg": [
        "B.host", 
        "C.host"
    ]
}
ok: [C.host] => {
    "msg": [
        "B.host", 
        "C.host"
    ]
}

PLAY RECAP ****************************************************************************************************************************
B.host                     : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
C.host                     : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 

可以看到,此 play 每操作一个主机,都会将当前 play 操作的所有主机的主机名列表返回。

没错,inventory_hostnameplay_hosts 都是返回主机名,只不过,inventory_hostname 只返回当前被操作的主机的主机名,而 play_hosts 则返回当前 play 中所有被操作主机的主机名列表。

groups

通过 groups 内置变量可以获取到清单中所有分组的分组信息,什么意思呢?我们先来看一个清单配置,假设我的清单配置如下:

A ansible_host=10.0.1.200
[group1]
B ansible_host=10.0.1.201

[group2]
C ansible_host=10.0.1.202

[groupall:children]
group1
group2

现在,我们获取一下 groups 变量的值,看看会返回哪些信息,随便操作清单中的任意一台主机即可,示例如下:

$ ansible B -m debug -a "msg={{groups}}"
B | SUCCESS => {
    "msg": {
        "all": [
            "A", 
            "B", 
            "C"
        ], 
        "group1": [
            "B"
        ], 
        "group2": [
            "C"
        ], 
        "groupall": [
            "B", 
            "C"
        ], 
        "ungrouped": [
            "A"
        ]
    }
}

从上述返回信息可以看出,所有主机默认被分成了组名为 all 的组,group1group2 组中各有一台主机,由于它们都属于 groupall 组的子组,所以 group1 组与 group2 组中的主机都属于 groupall 组,由于 A 主机在清单中并未分组,所以,ansible 自动将没有分组的主机分到了名为 ungrouped 的组中。

我们还能够通过组名,获取到指定组的分组信息,假设,我想要获取到上例中未分组的主机名称,则可以使用如下方法。

$ ansible B -m debug -a "msg={{groups.ungrouped}}"
B | SUCCESS => {
    "msg": [
        "A"
    ]
}

group_names

见名知义,我们可以通过内置变量 group_names 获取到当前主机所在分组的组名,比如,我的清单配置如下:

A ansible_host=10.0.1.200
[group1]
B ansible_host=10.0.1.201

[group2]
C ansible_host=10.0.1.202

[groupall:children]
group1
group2

那么,当我操作 B 主机时,group_names 变量值如下:

$ ansible B -m debug -a "msg={{group_names}}"       
B | SUCCESS => {
    "msg": [
        "group1", 
        "groupall"
    ]
}

如上例返回值所示,B 主机属于 group1 组,而 group1 组又是 groupall 组的子组,所以 B 主机同时属于 group1 组和 groupall 组,所以,最终返回的信息中包括 group1groupall

inventory_dir

我们可以通过 inventory_dir 变量获取到 ansible 主机中清单文件的存放路径,我使用的是默认的清单文件/etc/ansible/hosts,所以,inventory_dir变量对应的值为/etc/ansible`,如下例所示:

$ ansible B -m debug -a "msg={{inventory_dir}}"      
B | SUCCESS => {
    "msg": "/etc/ansible"
}
0

评论区