Ansible—— 28. 变量

Ansible变量名不能与Python属性和方法名冲突

1. 命令行变量 (command vars)
1.1 必须传入变量

否则报错

---
- hosts: test70
  remote_user: root
  tasks:
  - name: "Passing Variables On The Command Line"
    debug:
      msg: "{{pass_var}}"
ansible-playbook cmdvar.yml --extra-vars "pass_var=cmdline pass var"
ansible-playbook cmdvar.yml -e 'pass_var="test" pass_var1="test1"' 
1.2 命令行的变量优先级高于yaml文件中的同名变量
---
- hosts: test70
  remote_user: root
  vars:
    pass_var: test_default
  tasks:
  - name: "Passing Variables On The Command Line"
    debug:
      msg: "{{pass_var}}"
ansible-playbook cmdvar.yml -e 'pass_var="test"'

输出test,也就是说,命令行的变量优先级高于yaml文件中的同名变量。

1.3 不使用yaml也可以传入变量
ansible test70 -e "testvar=test" -m shell -a "echo {{testvar}}"
1.4 传入json格式的变量
ansible-playbook cmdvar.yml -e '{"testvar":"test","testvar1":"test1"}'
1.5 引用变量数组
ansible-playbook cmdvar.yml -e '{"countlist":["one","two","three","four"]}'

{{countlist.n}}或{{countlist[n]}}

1.6 传入变量文件
# cat /testdir/ansible/testvar
testvar: testvarinfile
countlist:
- one
- two
- three
- four
---
- hosts: test70
  remote_user: root
  tasks:
  - name: "Passing Variables On The Command Line"
    debug:
      msg: "{{testvar}} {{countlist[0]}}"
ansible-playbook cmdvar.yml -e "@/testdir/ansible/testvar"
2. 清单变量 (inventory vars)
2.1 主机名清单变量
[root@test2 playbook]# cat /etc/ansible/hosts 
[all]
10.0.102.212 test_var=212
10.0.102.200 test_var=200
10.0.102.162 test_var=162
[root@test2 playbook]# cat test.yml 
---
 - hosts: all
   remote_user: root
   gather_facts: no
   tasks:
     - name: test playbook variables
       command: echo {{ test_var }}
[root@test2 playbook]# ansible-playbook test.yml -v
2.2 主机组清单变量

作用范围为整个主机组。

[root@test2 playbook]# cat /etc/ansible/hosts 
[all]
10.0.102.212 
10.0.102.200 
10.0.102.162

[all:vars]                            #给主机组定义变量
test_var=Hello World
3. 主机变量和组变量

在执行ansbile命令时,ansible默认会从/etc/ansible/host_vars/和/etc/amsible/group_vars/两个目录下读取变量定义,如果/etc/ansible下面没有这两个目录,可以直接手动创建,并且可以在这两个目录中创建与hosts(这里是指inventory文件)文件中主机名或组名同名的文件来定义变量。

3.1 主机变量
[root@test2 playbook]# cd /etc/ansible/
[root@test2 ansible]# tree
.
├── group_vars
├── hosts
└── host_vars                 #定义与主机名同名的文件
    ├── 10.0.102.162
    ├── 10.0.102.200
    └── 10.0.102.212

2 directories, 4 files

文件中的内容

[root@test2 ansible]# cat host_vars/10.0.102.162
---
test_var: 162
[root@test2 ansible]# cat host_vars/10.0.102.200
---
  test_var: 200
[root@test2 ansible]# cat host_vars/10.0.102.212
---
  test_var: 212
[root@test2 playbook]# cat test.yml 
---
 - hosts: all
   remote_user: root
   gather_facts: no
   tasks:
     - name: test playbook variables
       command: echo {{ test_var }}
[root@test2 playbook]# ansible-playbook test.yml -v
3.2 主机组变量

创建与组名同名的文件

[root@test2 ansible]# tree
.
├── group_vars
│   └── all               #创建与组名同名的文件
├── hosts
└── host_vars
    ├── 10.0.102.162
    ├── 10.0.102.200
    └── 10.0.102.212

2 directories, 5 files
[root@test2 ansible]# cat group_vars/all 
---
  test_group_var: from group
[root@test2 playbook]# cat test.yml 
---
 - hosts: all
   remote_user: root
   gather_facts: no
   tasks:
     - name: test the host variables
       command: echo {{ test_var }}

     - name: test host group variables           #写入测试组变量的task
       command: echo {{ test_group_var }}
[root@test2 playbook]# ansible-playbook test.yml -v
4. playbook变量(playbook vars)
4.1 vars
vars:
  testvar1: testfile
  testvar2: testfile2 
vars:
  - testvar1: testfile
  - testvar2: testfile2
---
- hosts: master
  remote_user: root
  vars:
    nginx:
      conf80: /etc/nginx/conf.d/80.conf
      conf8080: /etc/nginx/conf.d/8080.conf
  tasks:
  - name: task1
    file:
      path: "{{nginx.conf80}}"
      state: touch
  - name: task2
    file:
      path: "{{nginx.conf8080}}"
      state: touch

引用这两个变量时,有两种语法
语法一


"{{nginx.conf80}}"

语法二

"{{nginx['conf8080']}}"
4.2 引用变量使用双引号

引用变量时使用双引号,变量在被引用时,并没有处于"开头的位置"

path: /testdir/{{ testvar1 }}

当file模块的path参数引用对应的变量时,先写入了’/testdir/’,然后才引用了"testvar1"变量,{{ testvar1 }}并没有处于"开头的位置",换句话说就是,{{ testvar1 }}前面还有字符串’/testdir/’
变量被引用时如下,处于"开头的位置"

path: "{{nginx.conf80}}"

这种情况下,引用变量时必须使用双引号引起被引用的变量,否则会报语法错误。

---
- hosts: master
  vars:
    testvar1: testfile
  remote_user: root
  tasks:
  - name: task1
    file:
      path: /testdir/{{ testvar1 }}
      state: touch

当在playbook中为模块的参数赋值时,可以使用"冒号",也可以使用"等号",当使用"等号"为模块的参数赋值时,则不用考虑引用变量时是否使用"引号"的问题。

---
- hosts: master
  remote_user: root
  vars:
    nginx:
      conf80: /etc/nginx/conf.d/80.conf
      conf8080: /etc/nginx/conf.d/8080.conf
  tasks:
  - name: task1
    file:
      path={{nginx.conf80}}
      state=touch
  - name: task2
    file:
      path={{nginx['conf8080']}}
      state=touch
4.3 vars_files

变量文件语法
语法一:

  testvar1: testfile
  testvar2: testfile2

语法二:

  - testvar1: testfile
  - testvar2: testfile2

语法三:

nginx:
  conf80: /etc/nginx/conf.d/80.conf
  conf8080: /etc/nginx/conf.d/8080.conf
---
- hosts: master
  remote_user: root
  vars_files:
  - /testdir/ansible/nginx_vars.yml
  tasks:
  - name: task1
    file:
      path={{nginx.conf80}}
      state=touch
  - name: task2
    file:
      path={{nginx['conf8080']}}
      state=touch

引入多个变量文件

  vars_files:
  - /testdir/ansible/nginx_vars.yml
  - /testdir/ansible/other_vars.yml

vars和vars_files混用

  vars:
  - conf90: /etc/nginx/conf.d/90.conf
  vars_files:
  - /testdir/ansible/nginx_vars.yml
4.4 include_vars
vim /testdir/ansible/testfile
testvar1: aaa
testvar2: bbb

定义了三个任务,第二个任务中,使用lineinfile模块在变量文件中增加了testvar3变量,然后在第三个任务 中调用了testvar3变量,执行上例playbook,你会发现,执行出错了,因为在playbook载入vars_files对应的变量文件时,文 件中只有两个变量,在执行第三个任务执行,并没有重新载入对应的变量文件,所以执行报错了。

---
- hosts: test71
  remote_user: root
  gather_facts: no
  vars_files:
  - /testdir/ansible/testfile
  tasks:
  - debug:
      msg: "{{testvar1}},{{testvar2}}"
  - lineinfile:
      path: "/testdir/ansible/testfile"
      line: "testvar3: ccc"
  - debug:
      msg: "{{testvar1}},{{testvar2}},{{testvar3}}"

由于testvar3已经加入到了变量文件中,第一个任务中就能调用到testvar3,第二个任务中, 我们在变量文件中新增了一个变量testvar4,第三个任务调用了’include_vars’模块,'include_vars’模块重新加载了变量 文件,第四个任务中,调用了testvar4变量。

---
- hosts: test71
  remote_user: root
  gather_facts: no
  vars_files:
  - /testdir/ansible/testfile
  tasks:
  - debug:
      msg: "{{testvar3}}"
  - lineinfile:
      path: "/testdir/ansible/testfile"
      line: "testvar4: ddd"
  - include_vars: "/testdir/ansible/testfile"
  - debug:
      msg: "{{testvar4}}"

有些时候,变量文件可能并没有位于ansible主机中,而是位于远程主机中,所以,需要先把变量文件从远程主机中拉取到ansible主机 中,当通过前面的task拉取到变量文件以后,也可以使用’include_vars’模块加载刚才拉取到的变量文件,以便后面的task可以使用变量文 件中的变量。

---
- hosts: test70
  remote_user: root
  gather_facts: no
  tasks:
  - include_vars:
      file: /testdir/ansible/testfile
  - debug:
      msg: "{{testvar4}}"

file参数可以指定要包含的变量文件,其实与如下写法效果相同

- include_vars: "/testdir/ansible/testfile"

include_vars可以把变量文件中的变量全部赋值给另外一个变量

---
- hosts: test70
  remote_user: root
  gather_facts: no
  tasks:
  - include_vars:
      file: /testdir/ansible/testfile
      name: trans_var
  - debug:
      msg: "{{trans_var}}"

如果想要获取到文件中的某一个变量的值,则可以使用如下方法

  tasks:
  - include_vars:
      file: /testdir/ansible/testfile
      name: trans_var
  - debug:
      msg: "{{trans_var.testvar4}}"

include_vars不仅能够加载指定的变量文件,还能够一次性将指定目录下的所有变量文件中的变量加载,使用dir参数即可指定对应的目录。

  - include_vars:
      dir: /testdir/ansible/test/
      name: trans_var
  - debug:
      msg: "{{trans_var}}"

使用dir参数指定了"/testdir/ansible/test/"目录,此目录中的所有变量文件都会被加载,但是在使用dir参数时,需要注意如下三点
第一:指定目录中的所有文件的文件后缀必须是 ‘.yaml’ 、’.yml’ 、’.json’中的一种,默认只有这三种后缀是合法后缀,如果目录中存在非合法后缀的文件,执行playbook时则会报错。
第二:如果此目录中的子目录中包含变量文件,子目录中的变量文件也会被递归的加载,而且子目录中的文件也必须遵守上述第一条规则。
第三:dir参数与file参数不能同时使用。

第一点与第二点都是默认设置,可以通过其他选项修改, 当使用dir参数时,指定目录中的所有文件必须以 ‘.yaml’ 、’.yml’ 、’.json’ 作为文件的后缀,如果想要手动指定合法的文件后缀名,则可以使用extensions参数指定哪些后缀是合法的文件后缀,extensions参数的值需 要是一个列表。

  tasks:
  - include_vars:
      dir: /testdir/ansible/test/
      extensions: [yaml,yml,json,varfile]
      name: trans_var
  - debug:
      msg: "{{trans_var}}"

当使用dir参数时,默认情况下会递归的加载指定目录及其子目录中的所有变量文件,如果想要控制递归的深度,则可以借助depth参数。

  tasks:
  - include_vars:
      dir: /testdir/ansible/test/
      depth: 1
      name: trans_var
  - debug:
      msg: "{{trans_var}}"

在使用dir参数时,还可以借助正则表达式,匹配那些我们想要加载的变量文件,比如,我们只想加载指定目录中以"var_"开头的变量文件,使用’files_matching’参数可以指定正则表达式,当指定目录中的文件名称符合正则时,则可以被加载。

  tasks:
  - include_vars:
      dir: /testdir/ansible/test/
      files_matching: "^var_.*"
      name: trans_var
  - debug:
      msg: "{{trans_var}}"

其实,不仅能够使用正则去匹配需要加载的变量文件名,还可以明确指定,哪些变量文件不能被加载,使用’ignore_files’参数可以明确指定需要忽略的变量文件名称,'ignore_files’参数的值是需要是一个列表,加载 /testdir/ansible/test/目录中的变量文件,但是所有以"var_"开头的变量文件和varintest.yaml变量文件将不会被加载, 'files_matching’参数和’ignore_files’参数能够同时使用,当它们同时出现时,会先找出正则匹配到的文件,然后从中排除那些 需要忽略的文件。

  tasks:
  - include_vars:
      dir: /testdir/ansible/test/
      ignore_files: ["^var_.*",varintest.yaml]
      name: trans_var
  - debug:
      msg: "{{trans_var}}" 

在2.4版本以后的ansible中,当执行了include_vars模块以后,include_vars模块会将载入的变量文件列表写入到自己 的返回值中,这个返回值的关键字为ansible_included_var_files。

  tasks:
  - include_vars:
      dir: /testdir/ansible/test/
    register: return_val
  - debug:
      msg: "{{return_val.ansible_included_var_files}}"
5. 角色变量 (role vars)
roles:
    { role: app_user, name: alex }
6. 内置变量
6.1 内置变量精确过滤
ansible localhost -m setup -a 'filter=ansible_memory_mb'
"ansible_all_ipv4_addresses"表示远程主机中的所有ipv4地址,从其对应的值可以看出,master主机上一共有4个ipv4地址。
 "ansible_distribution"表示远程主机的系统发行版,从其对应的值可以看出master主机的系统发行版为centos
 "ansible_distribution_version"表示远程主机的系统版本号,从其对应的值与  "ansible_distribution" 的值可以看出master主机的系统版本为centos7.4
 "ansible_ens35"表示远程主机ens35网卡的相关信息,细心如你一定也发现了,我还有两个名为"ens33""ens34"的网卡,只不过为了方便示例,这两个网卡的信息被我省略了。
 "ansible_memory_mb"表示远程主机的内存配置信息。
6.2 内置变量模糊过滤

使用通配符,进行相对模糊的过滤

ansible master -m setup -a "filter=*mb*"
6.3 注入变量

文件位置/etc/ansible/facts.d/下:

[root@master facts.d]# cat testinfo.fact
[testmsg]
msg1=This is the first custom test message
msg2=This is the second custom test message
[root@master facts.d]# cat testinfo.fact
   "testmsg":{
       "msg1":"This is the first custom test message",
       "msg2":"This is the second custom test message"
   }
}
ansible master -m setup -a "filter=ansible_local filter=ansible_local "
6.4 debug模块msg、var 输出变量
---
- hosts: test70
  remote_user: root
  vars:
    testvar: value of test variable
  tasks:
  - name: debug demo
    debug:
      var: testvar
---
- hosts: test70
  remote_user: root
  vars:
    testvar: testv
  tasks:
  - name: debug demo
    debug:
      msg: "value of testvar is : {{testvar}}"
---
- hosts: test70
  remote_user: root
  tasks:
  - name: debug demo
    debug:
      msg: "Remote host memory information: {{ansible_memory_mb}}"
6.5 自动引入fact变量
vim  /etc/ansible/facts.d/custom.fact
[general]
package = httpd
service = httpd
state = started
vim setup_facts.yml
---
- name: Install remote facts
  hosts: test
  vars: 
    remote_dir: /etc/ansible/facts.d
    facts_file: custom.fact
  tasks:
    - name: Create the remote directory
      file:
        state: directory
        recurse: yes
        path: "{{ remote_dir }}"
    - name: Install the new facts
      copy:
        src: "{{ facts_file }}"
        dest: "{{ remote_dir }}"

执行该playbook,完成facts的推送:

[root@master ~]#ansible-playbook setup_facts.yml

验证新的facts已经生成:

[root@master ~]# ansible test -m setup        
10.1.61.187 | SUCCESS => {
    "ansible_facts": {
    
        ...output omitted...
        
        "ansible_local": {
            "custom": {
                "general": {
                    "package": "httpd",
                    "service": "httpd",
                    "state": "started"
                }
            }
        },

        ...output omitted...
  
}

在playbook中使用自定义的fact变量:

- name: Install Apache and starts the service
  hosts: test
  tasks:
    - name: Install the required package
      yum: 
        name: "{{ ansible_facts.ansible_local.custom.general.package }}"
        state: latest
    - name: Start the service
      service: 
        name: "{{ ansible_facts.ansible_local.custom.general.service }}"
        state: "{{ ansible_facts.ansible_local.custom.general.state }}"

在playbook中使用set_fact模块定义新的变量:

- name: set_fact example
  hosts: test
  tasks:
    - name: Calculate InnoDB buffer pool size
      set_fact: innodb_buffer_pool_size_mb="{{ ansible_memtotal_mb / 2 |int }}"
      
    - debug: var=innodb_buffer_pool_size_mb
[root@master ~]#ansible-playbook set_fact_ex.yaml 

这种设置方式只在当前playbook当中有效

6.6 手动采集fact变量
- name: Deploy apps
  hosts: webservers
  gather_facts: False
  tasks:
    - name: wait for ssh to be running
      local_action: wait_for port=22 host="{{ inventory_hostname }}" search_regex=OpenSSH
    - name: gather facts
      setup:
    ......
6.7 启用fact缓存

在playbook中需要引入fact,可以开启fact缓存。fact缓存支持三种存储方式:JSON、memcached、redis。

6.7.1 Json文件fact缓存后端

使用JSON文件作为fact缓存后端的时候,ansible将会把采集的fact写入到控制主机的文件中。
/etc/ansible/ansible.cfg配置如下:
[defaults]
gathering = smart
#缓存时间,单位为秒
fact_caching_timeout = 86400
fact_caching = jsonfile
#指定ansible包含fact的json文件位置,如果目录不存在,会自动创建
fact_caching_connection = /tmp/ansible_fact_cache

6.7.2 Redis fact缓存后端

使用redis作为fact缓存后端,需要控制主机安装redis服务并保持运行。需要安装python操作redis的软件包。
/etc/ansible/ansible.cfg配置如下:
[defaults]
gathering = smart
fact_caching_timeout = 86400
fact_caching = redis

6.7.3 Memcached fact缓存后端

使用memcached作为fact缓存后端,需要控制主机安装Memcached服务并保持运行,需要安装python操作memcached的软件包。
/etc/ansible/ansible.cfg配置如下:
[defaults]
gathering = smart
fact_caching_timeout = 86400
fact_caching = memcached

6.7.4 关闭fact

关闭fact以提升执行效率

- hosts: test
  gather_facts: no

也可以在/etc/ansible/ansible.cfg中关闭。

[defaults]
gathering = explicit
7. 注册变量

ansible的模块在运行之后,其实都会返回一些返回值,默认情况下,返回值并不会显示而已,我们可以把这些返回值写入到某个变 量中,通过引用对应的变量从而获取到这些返回值了,这种将模块的返回值写入到变量中的方法被称为注册变量。

---
- hosts: test70
  remote_user: root
  tasks:
  - name: test shell
    shell: "echo test > /var/testshellfile"
    register: testvar
  - name: shell module return values
    debug:
      var: testvar

返回的部分信息

...........
"testvar": {
        "changed": true, 
        "cmd": "echo test > /var/testshellfile", 
        "delta": "0:00:00.003808", 
        "end": "2018-06-17 20:42:37.675382", 
        "failed": false, 
        "rc": 0, 
        "start": "2018-06-17 20:42:37.671574", 
        "stderr": "", 
        "stderr_lines": [], 
        "stdout": "", 
        "stdout_lines": []
    }
...........

取得具体属性值
语法一

  - name: shell module return values
    debug:
      msg: "{{testvar.cmd}}"

语法二

  - name: shell module return values
    debug:
      msg: "{{testvar['cmd']}}"

注册变量,其实就是将操作结果,包括标准输出和标准错误输出,保存到变量中,然后再根据这个变量的内容来决定下一步的操作,在这个过程中用来保存操作结果的变量就叫注册变量。

[root@test2 playbook]# cat test.yml 
---
 - hosts: all
   remote_user: root
   gather_facts: no
   tasks:
     - name: test the register variables
       shell: uptime
       register: results                              #使用关键字register声明注册变量,上面uptime命令产生的结果,存入到results中。结果是字典形式。

     - name: print the register result
       debug: msg="{{ results.stdout }}"              #使用debug模块,打印出上面命令的输出结果。

一个注册变量通常会有以下4个属性:
changed:任务是否对远程主机造成的变更。
delta:任务运行所用的时间。
stdout:正常的输出信息。
stderr:错误信息。

8. 高阶变量

对于普通变量,在ansible命令行设定的,在hosts文件中定义的,或者在playbook中定义的等,这些都是普通变量,在引用时,可以使用使用{{ variable }}的形式。ansible是用python语言写的,因此也支持一种叫做列表的变量,形式如下:

[root@test2 playbook]# cat test.yml 
---
 - hosts: all
   remote_user: root
   gather_facts: no
   vars:
      var_list:  #注意形式,定义了var_list列表,取值方法和列表取值一样,不推荐使用jinja2的方法取值。
          - one
          - two
          - three
   tasks:
     - name: test the list variables
       shell: echo {{ var_list[0] }}            #取列表中的第一个字,也就是one
       register: results

     - name: print the register result
       debug: msg="{{ results.stdout }}"

收集的主机信息可以使用setup模块查看

[root@test2 playbook]# ansible 10.0.102.162 -m setup 

在实际应用中,运用的比较多的facts变量有ansible_os_family,ansible_hostname等,这些变量通常会被拿来作为when条件语句的判断条件,来决定下一步的操作。

[root@test2 playbook]# cat test.yml 
---
 - hosts: all
   remote_user: root
   tasks:
     - name: test the list variables
       shell: echo {{ ansible_os_family }}
       register: results

     - name: print the register result
       debug: msg="{{ results.stdout }}" 

————Blueicex 2020/2/2 10:20 blueice1980@126.com

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值