Ansible之templates模板

  一、jinja2简介解

  Jinja2是Python下一个被广泛应用的模版引擎,他的设计思想来源于Djanjo的模板引擎,并扩展了其语法和一系列强大的功能。ansible的模板配置文件就是用jinja2这种模板编程语言写的,其中jinja2使用字面量有如下形式

  1)字符串:使用单引号或双引号引起来的部分

  2)数字:支持整数,浮点数(小数)

  3)列表:和python里的列表一样,用中括号括起来,每个元素之间用逗号隔开,如[item1,item2,....]

  4)元组:和python里的元组一样,小括号括起来,每个元素之间用逗号隔开,如(item1,item2,....)

  5)字典:同python里的字典一样,大括号括起来,每个k/v(键值对)用逗号隔开,键和值用":"冒号隔开,如{key1:value1,key2:value2,....}

  6)布尔型:同其他语言布尔型一样,ture/false

  7)支持算数运算:+,-,*,/,//(整除,地板除),%(取模,取余数),**(幂运算)

  8)支持比较操作:==(比较两个值是否相等),!=(不等),>,>=(大于等于),<,<=(小于等于)

  9)支持逻辑运算:and(与),or(或),not(非)

  10)支持for(循环) ,if(判断),when(当某一条件满足才开始执行when所在的代码块,作用类似if)

  除此以外,jinja2还支持“test”测试语句,比如我们要判断某个变量是否定义,可以使用defined来判断,如 vars is defined ,如果vars定义则表达式返回true,相反返回false。类似的还有undefined(与defined相反),equalto(与“==”作用等效),even(判断对象是否是偶数),iterable(判断对象是否可迭代)

  二、jinja2语法

jinja2有如下语法:

  1)控制结构,它和我们写别的语言的控制结构类似,唯一不同的是它的for循环要用”{%%}“给括起来,且必须写在两个百分号之间,后面结束有一个{%endfor$}来表示for循环的结束,同样if语句也是,必须写在"{%%}" 两个百分号之间,后面结束也有个{%endif%}来表示if语句的结束,当然if语句支持elif ,else  这个同python里的if用法一样。

  2)变量引用,jinja2的变量引用同ansible的变量应用类似,都是用"{{}}" 双大括号来表示中间括起来的内容表示变量

  3)注释用"{#"开始,中间部分表示注释,以"#}"结束表示注释结束,支持多行注释和当行注释

示例:

  1)for循环使用

{% for vhost in nginx_vhosts %}
server {
listen {{ vhost.listen }}
}
{% endfor %}

  说明:以上模板表示,从nginx_vhosts列表里去循环,nginx_vhosts里有几个元素,它将循环几次,每次循环取的值用vhost变量代替,它的用法类型shell里的for循环和python里的for循环

  2)if单分支选择使用

{% if vhost.server_name is defined %}
    server_name {{ vhost.server_name }}
{% endif %}

  3)if多分支选择使用

{%if vhost.port is undefined %}
    http_port=80
{%elif vhost.port == 81%}
    http_port=81
{%else%}
    http_port = 83
{%endif%}

  4)单行注释

{#% for i in list %#}

  5)多行注释

{#
    {% for i in list %}
         i+=i
      {% endfor %}
#}

  三、playbook中使用模板

templates是ansible的一个模块,其功能是根据模板文件动态生成配置文件,templates文件必须存放于templates目录下,且命名为".j2"结尾,yaml/yml文件需要和templates目录平级,这样我们在yml文件中调用模板的时候,就不需要写模板文件的路径,否则需要描述模板文件的路径,因为template模块会自动去找templates目录下的模板文件。目录结构如下

.
├── temnginx.yml
└── templates
   └── nginx.conf.j2

示例:playbook中template变量替换

  利用tamplates同步nginx配置文件,其中修改nginx.conf.j2(worker_processes {{ ansible_processor_vcpus }};)指定其worker进程的个数由远程主机的cpu个数决定

[root@test ~]#ll
总用量 4
-rw-r--r-- 1 root root 212 11月 18 14:08 temnginx.yml
drwxr-xr-x 2 root root  27 11月 18 14:05 templates
[root@test ~]#tree
.
├── temnginx.yml
└── templates
    └── nginx.conf.j2

1 directory, 2 files
[root@test ~]#head templates/nginx.conf.j2 
# For more information on configuration, see:
#   * Official English Documentation: http://nginx.org/en/docs/
#   * Official Russian Documentation: http://nginx.org/ru/docs/

user nginx;
worker_processes {{ ansible_processor_vcpus }};
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

# Load dynamic modules. See /usr/share/nginx/README.dynamic.
[root@test ~]#cat temnginx.yml 
---
- hosts: websers
  remote_user: root

  tasks:
    - name: install nginx
      yum: name=nginx 
    - name: template config to remote hosts
      template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
 
[root@test ~]#

  说明:以上playbook里是使用template模板去动态生成的配置文件,不是拷贝,拷贝是将文件原封不动的拷贝过去,还需要注意的是template模块不能在ad-hoc命令行里使用,只能在playbook里使用,且模板文件必须是".j2"结尾的

示例:playbook中template算数运算

还是以上的示例,我们可以这样写

vim nginx.conf.j2
worker_processes {{ ansible_processor_vcpus**2 }};

  说明:我们可以用ansible内置变量做算术运算后的值作为模板文件的值,在playbook中还是用template模块去调用就好了

示例:模板文件中 for循环的用法

[root@test ~]#tree
.
├── temnginx.yml
└── templates
    └── nginx.conf.j2

1 directory, 2 files
[root@test ~]#cat templates/nginx.conf.j2 
{% for vhost in nginx_vhosts %}
server {
listen {{ vhost.listen }}
}
{% endfor %}
[root@test ~]#cat temnginx.yml 
---
- hosts: websers
  remote_user: root
  vars:
    nginx_vhosts:
      - listen: 8080
  tasks:
    - name: install nginx
      yum: name=nginx 
    - name: template config to remote hosts
      template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
 
[root@test ~]#  

生成结果:

[root@test ~]#ansible-playbook  temnginx.yml   

PLAY [websers] ******************************************************************************************************

TASK [Gathering Facts] **********************************************************************************************
ok: [192.168.0.128]
ok: [192.168.0.218]

TASK [install nginx] ************************************************************************************************
changed: [192.168.0.128]
changed: [192.168.0.218]

TASK [template config to remote hosts] ******************************************************************************
changed: [192.168.0.128]
changed: [192.168.0.218]

PLAY RECAP **********************************************************************************************************
192.168.0.128              : ok=3    changed=2    unreachable=0    failed=0   
192.168.0.218              : ok=3    changed=2    unreachable=0    failed=0   

[root@test ~]#ansible websers -m shell -a 'cat /etc/nginx/nginx.conf'
192.168.0.128 | SUCCESS | rc=0 >>
server {
listen 8080
}

192.168.0.218 | SUCCESS | rc=0 >>
server {
listen 8080
}

[root@test ~]#

  示例:模板文件中if的用法

[root@test ~]#tree
.
├── temnginx.yml
└── templates
    └── nginx.conf.j2

1 directory, 2 files
[root@test ~]#cat temnginx.yml 
---
- hosts: websers
  remote_user: root
  vars:
    nginx_vhosts:
      - web1:
        listen: 8080
        server_name: "web1.test.com"
        root: "/var/www/nginx/web1/"
      - web2:
        listen: 8080
        root: "/var/www/nginx/web2/"
      - web3:
        listen: 8080
        server_name: "web2.test.com"
        root: "var/www/nginx/web3/" 
  tasks:
    - name: template config to remote hosts
      template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
 
[root@test ~]#cat templates/nginx.conf.j2 
{% for vhost in nginx_vhosts %}
        server {
                listen {{ vhost.listen }}
                {% if vhost.server_name is defined %}
                server_name {{ vhost.server_name }}
                {% endif %}
                root {{ vhost.root }}
        }
{% endfor %}
[root@test ~]#

生成结果:

[root@test ~]#ansible-playbook temnginx.yml 

PLAY [websers] ******************************************************************************************************

TASK [Gathering Facts] **********************************************************************************************
ok: [192.168.0.128]
ok: [192.168.0.218]

TASK [template config to remote hosts] ******************************************************************************
changed: [192.168.0.128]
changed: [192.168.0.218]

PLAY RECAP **********************************************************************************************************
192.168.0.128              : ok=2    changed=1    unreachable=0    failed=0   
192.168.0.218              : ok=2    changed=1    unreachable=0    failed=0   

[root@test ~]#ansible websers -m shell -a 'cat /etc/nginx/nginx.conf'
192.168.0.128 | SUCCESS | rc=0 >>
server {
        listen 8080
                server_name web1.test.com
                root /var/www/nginx/web1/
}
server {
        listen 8080
                root /var/www/nginx/web2/
}
server {
        listen 8080
                server_name web2.test.com
                root var/www/nginx/web3/
}

192.168.0.218 | SUCCESS | rc=0 >>
server {
        listen 8080
                server_name web1.test.com
                root /var/www/nginx/web1/
}
server {
        listen 8080
                root /var/www/nginx/web2/
}
server {
        listen 8080
                server_name web2.test.com
                root var/www/nginx/web3/
}

[root@test ~]#

  说明:可以看到第二个server里是没有server_name,因为定义的变量列表里web2没有定义server_name

  四、playbook中使用when条件测试

  条件测试:如果需要根据变量、facts或此前任务的执行结果来作为某task执行与否的前提时需要用到条件测试,通过when语句实现,在task中使用jinja2的语法格式,when语句支持jinja2表达式语法;

示例:

[root@test ~]#cat test.yml 
---
- hosts: all 
  remote_user: root

  tasks:
    - name: set hostname centos6
      hostname: name=ansible_centos6
      when: ansible_distribution_major_version == "6"
    - name: set hostname centos7
      hostname: name=ansible_centos7
      when: ansible_distribution_major_version == "7" 
[root@test ~]#ansible all -m shell -a 'hostname'
192.168.0.128 | SUCCESS | rc=0 >>
localhost

192.168.0.218 | SUCCESS | rc=0 >>
localhost.localdomain

192.168.0.217 | SUCCESS | rc=0 >>
centos7

[root@test ~]#ansible-playbook test.yml 

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

TASK [Gathering Facts] **********************************************************************************************
ok: [192.168.0.128]
ok: [192.168.0.218]
ok: [192.168.0.217]

TASK [set hostname centos6] *****************************************************************************************
skipping: [192.168.0.217]
changed: [192.168.0.218]
changed: [192.168.0.128]

TASK [set hostname centos7] *****************************************************************************************
skipping: [192.168.0.128]
skipping: [192.168.0.218]
changed: [192.168.0.217]

PLAY RECAP **********************************************************************************************************
192.168.0.128              : ok=2    changed=1    unreachable=0    failed=0   
192.168.0.217              : ok=2    changed=1    unreachable=0    failed=0   
192.168.0.218              : ok=2    changed=1    unreachable=0    failed=0   

[root@test ~]#ansible all -m shell -a 'hostname'
192.168.0.128 | SUCCESS | rc=0 >>
ansible_centos6

192.168.0.218 | SUCCESS | rc=0 >>
ansible_centos6

192.168.0.217 | SUCCESS | rc=0 >>
ansible_centos7

[root@test ~]#

  说明:以上playbook利用when语句判断系统版本号,实现了通过不同的系统版本号,设置不同的主机名。

  五、playbook迭代with_items

  迭代:当有需要重复性执行的任务时,可使用迭代机制;对迭代项的引用,ansible有固定不变的变量,名为“item”;要在task中使用with_items给定要迭代的元素列表,列表格式可以为字符串、字典。

示例:批量创建用户

[root@test ~]#cat adduser.yml 
---
- hosts: websers
  remote_user: root
  
  tasks:
    - name: add users
      user: name={{ item }} state=present home=/home/{{ item }} groups=root,bin,wheel
      with_items:
        - user1
        - user2
        - user3
[root@test ~]#ansible-playbook adduser.yml

PLAY [websers] ******************************************************************************************************

TASK [Gathering Facts] **********************************************************************************************
ok: [192.168.0.128]
ok: [192.168.0.218]

TASK [add users] ****************************************************************************************************
changed: [192.168.0.128] => (item=user1)
changed: [192.168.0.218] => (item=user1)
changed: [192.168.0.128] => (item=user2)
changed: [192.168.0.218] => (item=user2)
changed: [192.168.0.128] => (item=user3)
changed: [192.168.0.218] => (item=user3)

PLAY RECAP **********************************************************************************************************
192.168.0.128              : ok=2    changed=1    unreachable=0    failed=0   
192.168.0.218              : ok=2    changed=1    unreachable=0    failed=0   

[root@test ~]#ansible websers -m shell -a 'tail -3 /etc/passwd'
192.168.0.128 | SUCCESS | rc=0 >>
user1:x:503:503::/home/user1:/bin/bash
user2:x:504:504::/home/user2:/bin/bash
user3:x:505:505::/home/user3:/bin/bash

192.168.0.218 | SUCCESS | rc=0 >>
user1:x:1213:1213::/home/user1:/bin/bash
user2:x:1214:1214::/home/user2:/bin/bash
user3:x:1215:1215::/home/user3:/bin/bash

[root@test ~]#ansible websers -m shell -a 'id user1'           
192.168.0.218 | SUCCESS | rc=0 >>
uid=1213(user1) gid=1213(user1) 组=1213(user1),0(root),1(bin),10(wheel)

192.168.0.128 | SUCCESS | rc=0 >>
uid=503(user1) gid=503(user1) 组=503(user1),0(root),1(bin),10(wheel)

[root@test ~]# 

示例:迭代嵌套子变量

[root@test ~]#cat adduser2.yml 
---
- hosts: websers
  remote_user: root
  
  tasks:
    - name: create groups
      group: name={{ item }}
      with_items:
        - group1
        - group2
        - group3
    - name: create users
      user: name={{ item.name }} group={{ item.group }} state=present
      with_items:
        - {name: 'test1',group: 'group1'}
        - {name: 'test2',group: 'group2'}
        - {name: 'test3',group: 'group3'}
[root@test ~]#ansible-playbook adduser2.yml

PLAY [websers] ******************************************************************************************************

TASK [Gathering Facts] **********************************************************************************************
ok: [192.168.0.128]
ok: [192.168.0.218]

TASK [create groups] ************************************************************************************************
changed: [192.168.0.128] => (item=group1)
changed: [192.168.0.218] => (item=group1)
changed: [192.168.0.128] => (item=group2)
changed: [192.168.0.218] => (item=group2)
changed: [192.168.0.128] => (item=group3)
changed: [192.168.0.218] => (item=group3)

TASK [create users] *************************************************************************************************
changed: [192.168.0.128] => (item={u'group': u'group1', u'name': u'test1'})
changed: [192.168.0.218] => (item={u'group': u'group1', u'name': u'test1'})
changed: [192.168.0.128] => (item={u'group': u'group2', u'name': u'test2'})
changed: [192.168.0.218] => (item={u'group': u'group2', u'name': u'test2'})
changed: [192.168.0.128] => (item={u'group': u'group3', u'name': u'test3'})
changed: [192.168.0.218] => (item={u'group': u'group3', u'name': u'test3'})

PLAY RECAP **********************************************************************************************************
192.168.0.128              : ok=3    changed=2    unreachable=0    failed=0   
192.168.0.218              : ok=3    changed=2    unreachable=0    failed=0   

[root@test ~]#ansible websers -m shell -a 'tail -3 /etc/passwd'
192.168.0.128 | SUCCESS | rc=0 >>
test1:x:506:506::/home/test1:/bin/bash
test2:x:507:507::/home/test2:/bin/bash
test3:x:508:508::/home/test3:/bin/bash

192.168.0.218 | SUCCESS | rc=0 >>
test1:x:1216:1216::/home/test1:/bin/bash
test2:x:1217:1217::/home/test2:/bin/bash
test3:x:1218:1218::/home/test3:/bin/bash

[root@test ~]#ansible websers -m shell -a 'id test1'           
192.168.0.218 | SUCCESS | rc=0 >>
uid=1216(test1) gid=1216(group1) 组=1216(group1)

192.168.0.128 | SUCCESS | rc=0 >>
uid=506(test1) gid=506(group1) 组=506(group1)

[root@test ~]#ansible websers -m shell -a 'id test2'
192.168.0.128 | SUCCESS | rc=0 >>
uid=507(test2) gid=507(group2) 组=507(group2)

192.168.0.218 | SUCCESS | rc=0 >>
uid=1217(test2) gid=1217(group2) 组=1217(group2)

[root@test ~]#ansible websers -m shell -a 'id test3'
192.168.0.128 | SUCCESS | rc=0 >>
uid=508(test3) gid=508(group3) 组=508(group3)

192.168.0.218 | SUCCESS | rc=0 >>
uid=1218(test3) gid=1218(group3) 组=1218(group3)

[root@test ~]#

  说明:以上playbook实现了对应用户创建时加入对应的组里

posted @ 2019-11-18 19:30  Linux-1874  阅读(8092)  评论(0编辑  收藏  举报