Playbook进阶
变量
– 解决密码明文问题
– user 模块的 password 为什么不能设置密码呢?
– 经过测试发现,password 是把字符串直接写入
shadow,并没有改变,而 Linux 的 shadow 密码是
经过加密的,所以不能使用
– 解决方案:
– 变量过滤器 password_hash
– {{ 'urpassword' | password_hash('sha512')}}
添加用户
给所有主机添加用户plj,设置
[root@ansible ~]# cat  user01.yml 
---
-  hosts: web
   remote_user: root
   vars:
     nu: jj
   tasks:
     - user:
         name: "{{nu}}" 
         group: users
     - shell: echo 123456 | passwd --stdin "{{nu}}"
     - name: ooxx
       shell: chage -d 0 "{{nu}}"
 
[root@ansible ~]# ssh web1
 
cat /etc/shadow
 
lj:$6$dm7UACxP$nutBdDj3QiyUixvnz4bddYRKM2TUlfblN/7sQszPTuKaucxSeRJaza2Y8Ta9rNEERyTt8..p6RELPysqheFIB1:0:0:99999:7:::
jj:$6$aa9sEngo$5VcqZ5/9N/amdkuFIjSaJkDekgU5nbBV6ejrLcWbFIn6lvCzuXgucXGJIGRVejgKHWiL1l1kBOUiJGNzgBWyG0:0:0:99999:7:::
 
 
[root@ansible ~]# cat /etc/login.defs 
UID_MIN                  1000
UID_MAX                 60000
 
SYS_UID_MIN               201
SYS_UID_MAX               999
 
#
# Min/max values for automatic gid selection in groupadd
#
GID_MIN                  1000
GID_MAX                 60000
# Use SHA512 to encrypt password.
ENCRYPT_METHOD SHA512
 
[root@ansible ~]# vim aa
[root@ansible ~]# md5sum aa
d41d8cd98f00b204e9800998ecf8427e  aa
 
使用变量和过滤器添加用户
[root@ansible ~]# cat user01.yml 
---
-  hosts: web
   remote_user: root
   vars:
     nu: nb
   tasks:
     - user:
         name: "{{nu}}" 
         group: users
         password: "{{'123456'|password_hash('sha512')}}"
     - name: ooxx
       shell: chage -d 0 "{{nu}}"
 
nb:$6$8QROWytJ$16TtvA9236Dxs50bSPnEuJ8.b7pJ5kU.JHsSiImUGj7PAtSC7MkfWP6vPJCn6/QBFG8IWkCA2vYYg1c4pMElX1:0:0:99999:7:::
 
[root@ansible ~]# cat /etc/ansible/hosts 
 
[other]
192.168.6.33  ansible_ssh_user="root"  ansible_ssh_pass="123456"
[root@ansible ~]# cat  user01.yml 
---
-  hosts: other
   remote_user: root
   vars:
     nu: nb
   tasks:
     - user:
         name: "{{nu}}" 
         group: users
         password: "{{'123456'|password_hash('sha512')}}"
     
     - name: ooxx
       shell: chage -d 0 "{{nu}}"
 
[root@ansible ~]# ansible-playbook user01.yml 
[root@ansible ~]# ansible-playbook user01.yml 
 
PLAY [other] *************************************************************************************************************************************************
 
TASK [Gathering Facts] ***************************************************************************************************************************************
ok: [192.168.6.33]
 
TASK [user] **************************************************************************************************************************************************
changed: [192.168.6.33]
 
TASK [command] ***********************************************************************************************************************************************
changed: [192.168.6.33]
 
TASK [ooxx] **************************************************************************************************************************************************
changed: [192.168.6.33]
 
PLAY RECAP ***************************************************************************************************************************************************
192.168.6.33               : ok=4    changed=3    unreachable=0    failed=0  
 
[root@ansible ~]# cat user01.yml 
---
-  hosts: db
   remote_user: root
   vars:
     un: zhang3
   tasks:
     - shell: adduser "{{un}}"
     - shell: echo 123456|passwd --stdin "{{un}}"
     - name: ooxx
       shell: chage -d 0 "{{un}}"
 
[root@ansible ~]# ssh db1
Last login: Fri Jul 27 22:40:45 2018 from 192.168.6.10
[root@db1 ~]# adduser zhang3
adduser:用户“zhang3”已存在
[root@db1 ~]# echo $?
9
[root@db1 ~]# exit
登出
Connection to db1 closed.
[root@db1 ~]# adduser zhang3 || echo
adduser:用户“zhang3”已存在
 
[root@db1 ~]# echo $?
0
[root@db1 ~]# adduser zhang3 || true
adduser:用户“zhang3”已存在
[root@db1 ~]# echo $?
0
 
[root@db1 ~]# true
[root@db1 ~]# echo $?
0
[root@db1 ~]# false
[root@db1 ~]# echo $?
1
[root@ansible ~]# vim  user01.yml 
---
-  hosts: db
   remote_user: root
   vars:
     un: zhang3
   tasks:
     - shell: adduser "{{un}}" || true
     - shell: echo 123456|passwd --stdin "{{un}}"
     - name: ooxx
       shell: chage -d 0 "{{un}}"
 
[root@ansible ~]# ansible-playbook user01.yml 
 
PLAY [db] ****************************************************************************************************************************************************
 
TASK [Gathering Facts] ***************************************************************************************************************************************
ok: [db1]
ok: [db2]
 
//ansible执行时要求上一条命令正确的时候$?=0才执行,这时可以忽略错误执行
[root@ansible ~]# cp user01.yml user02.yml
[root@ansible ~]# vim user02.yml 
[root@ansible ~]# cat  user02.yml 
---
-  hosts: db
   remote_user: root
   vars:
     un: zhang3
   tasks:
     - shell: adduser "{{un}}"
      ignore_errors: True
     - shell: echo 123456|passwd --stdin "{{un}}"
     - name: ooxx
       shell: chage -d 0 "{{un}}"
 
[root@ansible ~]# ansible-playbook user02.yml 
fatal: [db1]: FAILED! => {"changed": true, "cmd": "adduser \"zhang3\"", "delta": "0:00:00.005628", "end": "2018-07-27 22:47:31.506750", "msg": "non-zero return code", "rc": 9, "start": "2018-07-27 22:47:31.501122", "stderr": "adduser:用户“zhang3”已存在", "stderr_lines": ["adduser:用户“zhang3”已存在"], "stdout": "", "stdout_lines": []}
 
Handlers
用于当关注的资源发生变化时采取一定的操作
"notify" 这个action可用于在每个play的最后被触发
这样可以避免多次有改变发生时每次都执行指定的操
作取而代之仅在所有的变化发生完成后一次性地执行
指定操作。
• 在 notify 中列出的操作称为 handler 也即 notify 中
调用 handler 中定义的操作
 
[root@ansible ~]# cat  http.yml
---
- hosts: web
  remote_user: root
  tasks:
    - name: install the latest version of Apache
      yum:
        name: httpd
        state: installed
    - lineinfile:
        path: /etc/httpd/conf/httpd.conf
        regexp: '^Listen '
        insertafter: '^#Listen '
        line: 'Listen 8080'
      notify:
        - restart_httpd
    - lineinfile:
        path: /etc/httpd/conf/httpd.conf
        regexp: '^#ServerName'
        line: 'ServerName localhost'
      notify:
        - restart_httpd
    - copy:
        src: /root/index.html
        dest: /var/www/html/index.html
        owner: apache
        group: apache
        mode: 0644
      notify:
        - restart_httpd
  handlers:
    - name: restart_httpd
      service:
        name: httpd
        state: restarted
        enabled: yes
 
 
[root@ansible ~]# ssh web1
Last login: Sat Jul 28 00:05:45 2018 from 192.168.6.10
[root@web1 ~]# ss -ltun
Netid  State      Recv-Q Send-Q                               Local Address:Port                                              Peer Address:Port              
tcp    LISTEN     0      128                                              *:22                                                           *:*                  
tcp    LISTEN     0      100                                      127.0.0.1:25                                                           *:*                  
tcp    LISTEN     0      128                                             :::8080                                                        :::*                  
tcp    LISTEN     0      128                                             :::22                                                          :::*                  
tcp    LISTEN     0      100                                            ::1:25                                                          :::*                  
[root@web1 ~]# uptime
 00:06:42 up  7:02,  3 users,  load average: 0.01, 0.02, 0.02
[root@web1 ~]# ss -ltnu
Netid  State      Recv-Q Send-Q                               Local Address:Port                                              Peer Address:Port              
tcp    LISTEN     0      128                                              *:22                                                           *:*                  
tcp    LISTEN     0      100                                      127.0.0.1:25                                                           *:*                  
tcp    LISTEN     0      128                                             :::8080                                                        :::*                  
tcp    LISTEN     0      128                                             :::22                                                          :::*                  
tcp    LISTEN     0      100                                            ::1:25                               
                           :::* 
 
register
• 变量注册进阶
– 我们还可以针对运行命令结果的返回值做判定
– 当系统负载超过一定值的时候做特殊处理
 
[root@web1 ~]# uptime | awk '{printf("%.2f",$(NF-2))}'
0.00[root@web1 ~]# 
[root@ansible ~]# cat load.yml 
---
- hosts: web
  remote_user: root
  tasks:
    - shell: uptime | awk '{printf("%.2f",$(NF-2))}'
      register: result
    - service: name=httpd state=stopped
      when: result.stdout|float > 0.7
[root@ansible ~]# 
 
[root@ansible ~]# for i in web1 web2;do curl http://${i}:8080; done
curl: (7) Failed connect to web1:8080; 拒绝连接
hello 
[root@ansible ~]# for i in web1 web2;do curl http://${i}:8080; done
hello 
hello 
[root@web1 ~]#  awk 'BEGIN{while(1){}}'
^C
[root@web1 ~]# systemctl restart httpd
 
//区别
password 是把字符串直接写入shadow
- shell: echo 123456 | passwd --stdin "{{nu}}"
password: "{{'123456'|password_hash('sha512')}}"
zhang30:$6$7LlagyCY$s1qsyrGnApzqDY3/EXUMGqidhOv2H46f7qt3lH35Zj.RDpDauvksHp5xDp3igV8uQG5velzbqpYziGk3mmSOG0:0:0:99999:7:::
zhang31:!!:0:0:99999:7:::
 
 
[root@ansible ~]# cat  user01.yml 
---
-  hosts: web1
   remote_user: root
   vars:
     un: zhang30
   tasks:
     - shell: adduser "{{un}}" || true
     - shell: echo 123456|passwd --stdin "{{un}}"
     - name: ooxx
       shell: chage -d 0 "{{un}}"
[root@web1 ~]# tailf -2 /etc/shadow
nb:$6$8QROWytJ$16TtvA9236Dxs50bSPnEuJ8.b7pJ5kU.JHsSiImUGj7PAtSC7MkfWP6vPJCn6/QBFG8IWkCA2vYYg1c4pMElX1:0:0:99999:7:::
zhang30:$6$7LlagyCY$s1qsyrGnApzqDY3/EXUMGqidhOv2H46f7qt3lH35Zj.RDpDauvksHp5xDp3igV8uQG5velzbqpYziGk3mmSOG0:0:0:99999:7:::
 
 
[root@ansible ~]# cat user02.yml
---
-  hosts: web1
   remote_user: root
   vars:
     un: zhang31
   tasks:
     - shell: adduser "{{un}}" || true
       password: "{{'123456'|password_hash('sha512')}}"
     - name: ooxx
       shell: chage -d 0 "{{un}}"
 
[root@web1 ~]# tailf -2 /etc/shadow
zhang30:$6$7LlagyCY$s1qsyrGnApzqDY3/EXUMGqidhOv2H46f7qt3lH35Zj.RDpDauvksHp5xDp3igV8uQG5velzbqpYziGk3mmSOG0:0:0:99999:7:::
zhang31:!!:0:0:99999:7:::
 
 
[root@ansible ~]# cat  user04.yml
---
 - hosts: web2
  remote_user: root
  tasks:
     - user:
         name: "{{item.name}}"
         group: "{{item.group}}"
         password: "{{'123456'|password_hash('sha512')}}"
       with_items:
           - {name: "nb",group: "users"}
           - {name: "dd",group: "mail" }
           - {name: "jj",group: "wheel"}
           - {name: "lx",group: "root" } 
[root@ansible ~]# ansible-playbook user04.yml
[root@web2 ~]# tailf -4
tailf: no input file specified
[root@web2 ~]# tailf -4 /etc/shadow
jj:$6$rounds=656000$E.QZRKDpiapi2.47$uj/Fg8i4EOCaq0bOo0PBLSI2xQXxIT1i6TaHt6zbePSWd7YqDNc8uSk3vdEEqIuo9v0xStDPYYdTkAMZDx6Kg0:17739:0:99999:7:::
nb:$6$rounds=656000$P8Uei7Jtw8Ozdlbt$PBBxoOs35/rNUzZInIBAkikK7iLnpMrTR6iVjcK9dAPmt5YBb5mj5XLk7OfqF8.wqJf5LCmUXaM5OAPRx9yHf1:17739:0:99999:7:::
dd:$6$rounds=656000$oCRChU5/pxIQA02.$0SC8YXyZYcRiWM5VY.X8dhrBCLCG8pg07HGz0I9QZGRWPrnMA1/fegjapfNtjdXeAngpygCkEAyvp3issEccf/:17739:0:99999:7:::
lx:$6$rounds=656000$m7F8xs5CFlS7ecCu$dXkqbrIqrWgqZQEEY8rA6Xltuc02pHGo.82lqou.jRVysDu.d1jDu/X8C35I.p.iEUgyzn1ANhkdT2ouF5BWv0:17739:0:99999:7:::
with_nested
• 嵌套循环:
[root@ansible ~]# cat  test.yml
---
- hosts: web
  remote_user: root
  vars:
    un: [a, b, c]   //3*3
    id: [1, 2, 3]
  tasks:
    - name: add users
      shell: echo {{item}}
      with_nested:
        - "{{un}}"
        - "{{id}}"
 
[root@ansible ~]# ansible-playbook test.yml
 
PLAY [web] ***************************************************************************************************************************************************
 
TASK [Gathering Facts] ***************************************************************************************************************************************
ok: [web1]
ok: [web2]
 
TASK [add users] *********************************************************************************************************************************************
changed: [web1] => (item=[u'a', 1])
changed: [web2] => (item=[u'a', 1])
changed: [web2] => (item=[u'a', 2])
changed: [web1] => (item=[u'a', 2])
changed: [web2] => (item=[u'a', 3])
changed: [web1] => (item=[u'a', 3])
changed: [web2] => (item=[u'b', 1])
changed: [web1] => (item=[u'b', 1])
changed: [web1] => (item=[u'b', 2])
changed: [web2] => (item=[u'b', 2])
changed: [web2] => (item=[u'b', 3])
changed: [web1] => (item=[u'b', 3])
changed: [web2] => (item=[u'c', 1])
changed: [web1] => (item=[u'c', 1])
changed: [web1] => (item=[u'c', 2])
changed: [web2] => (item=[u'c', 2])
changed: [web2] => (item=[u'c', 3])
changed: [web1] => (item=[u'c', 3])
 
tags:给指定的任务定义一个调用标识;
 
[root@ansible ~]# vim http.yml 
[root@ansible ~]# cat http.yml 
---
- hosts: web
  remote_user: root
  tasks:
    - name: install the latest version of Apache
      yum:
        name: httpd
        state: installed
    - lineinfile:
        path: /etc/httpd/conf/httpd.conf
        regexp: '^Listen '
        insertafter: '^#Listen '
        line: 'Listen 8080'
      notify:
        - restart_httpd
    - lineinfile:
        path: /etc/httpd/conf/httpd.conf
        regexp: '^#ServerName'
        line: 'ServerName localhost'
      notify:
        - restart_httpd
    - copy:
        src: /root/index.html
        dest: /var/www/html/index.html
        owner: apache
        group: apache
        mode: 0644
    - copy:
        src: /root/httpd.conf
        dest: /etc/httpd/conf/httpd.conf
        owner: root
        group: root
        mode: 0644
        tags: restartweb
      notify:
        - restart_httpd
  handlers:
    - name: restart_httpd
      service:
        name: httpd
        state: restarted
        enabled: yes
 
[root@ansible ~]# ansible-playbook http.yml --tags=restartweb
 
 
include and roles
• 我们在编写 playbook 的时候随着项目越来越大,
playbook 也越来越复杂,修改起来也越来越麻烦。
这时候可以把一些 play、task 或 handler 放到其他
文件中,然后通过include指令包含进来是一个不错
的选择
tasks:
- include: tasks/setup.yml
- include: tasks/users.yml user=plj #users.yml 中可以通过
{{ user }}来使用这些变量
handlers:
- include: handlers/handlers.yml
include and roles
• roles 像是加强版的 include,他可以引入一个项目
的文件和目录
• 一般所需的目录层级有
– vars 变量层
– tasks 任务层
– handlers 触发条件
– files
文件
– template 模板
– default
默认,优先级最低include and roles
• 假如有一个play包含了一个叫 "x" 的role,则
---
- hosts: host_group
roles:
- x
– x/tasks/main.yml
– x/vars/main.yml
– x/handler/main.yml
– x/... .../main.yml
– 都会自动添加进这个 play
调试debug
• 对于 python 语法不熟悉的同学,playbook 书写起
来容易出错,且排错困难,这里介绍几种简单的排错
调试方法
– 检测语法
ansible-playbook --syntax-check playbook.yaml
– 测试运行
ansible-playbook -C playbook.yaml
– 显示收到影响到主机 --list-hosts
– 显示工作的 task --list-tasks
– 显示将要运行的 tag --list-tagsdebug
• debug 模块可以在运行时输出更为详细的信息,来
帮助我们排错,debug 使用样例:
[root@ansible ~]# vim load1.yml 
---
- hosts: web
  remote_user: root
  tasks:
    - shell: uptime |awk '{printf("%f\n",$(NF-2))}'
      register: result
    - shell: touch /tmp/isreboot
      when: result.stdout|float > 0.5
    - name: Show debug info
      debug: var=result
[root@web1 ~]# awk 'BEGIN{while(1){}}'
[root@ansible ~]# ansible-playbook load1.yml
 
PLAY [web] ***************************************************************************************************************************************************
 
TASK [Gathering Facts] ***************************************************************************************************************************************
ok: [web2]
ok: [web1]
 
TASK [command] ***********************************************************************************************************************************************
changed: [web1]
changed: [web2]
 
TASK [command] ***********************************************************************************************************************************************
skipping: [web2]
 [WARNING]: Consider using file module with state=touch rather than running touch
 
changed: [web1]
 
TASK [Show debug info] ***************************************************************************************************************************************
ok: [web1] => {
    "result": {
        "changed": true, 
        "cmd": "uptime |awk '{printf(\"%f\\n\",$(NF-2))}'", 
        "delta": "0:00:00.003584", 
        "end": "2018-07-28 01:50:23.064444", 
        "failed": false, 
        "rc": 0, 
        "start": "2018-07-28 01:50:23.060860", 
        "stderr": "", 
        "stderr_lines": [], 
        "stdout": "0.900000", 
        "stdout_lines": [
            "0.900000"
        ]
    }
}
ok: [web2] => {
    "result": {
        "changed": true, 
        "cmd": "uptime |awk '{printf(\"%f\\n\",$(NF-2))}'", 
        "delta": "0:00:00.003379", //时间
        "end": "2018-07-28 01:50:23.071763", 
        "failed": false, 
        "rc": 0, //$?,默认作为判断  when result.rc
        "start": "2018-07-28 01:50:23.068384", 
        "stderr": "",    //标准错误
        "stderr_lines": [], 
        "stdout": "0.150000", //标准输出
        "stdout_lines": [
            "0.150000"
        ]
    }
}
[root@ansible ~]# vim http.yml 
[root@ansible ~]# ansible-playbook --syntax-check http.yml
ERROR! Syntax Error while loading YAML.
 
 
The error appears to have been in '/root/http.yml': line 30, column 9, but may
be elsewhere in the file depending on the exact syntax problem.
 
The offending line appears to be:
 
         src: /root/httpd.conf
        dest: /etc/httpd/conf/httpd.conf
        ^ here
 
exception type: <class 'yaml.parser.ParserError'>
exception: while parsing a block mapping
  in "<unicode string>", line 28, column 7
did not find expected key
  in "<unicode string>", line 30, column 9
[root@ansible ~]# vim http.yml 
 
//测试运行
[root@ansible ~]# ansible-playbook --syntax-check -C http.yml
//查看
[root@ansible ~]# ansible-playbook --list-hosts http.yml
 
playbook: http.yml
 
  play #1 (db): db TAGS: []
    pattern: [u'db']
    hosts (2):
      db1
      db2
[root@ansible ~]# ansible-playbook --list-tasks http.yml
 
playbook: http.yml
 
  play #1 (db): db TAGS: []
    tasks:
      install the latest version of Apache TAGS: []
      lineinfile TAGS: []
      lineinfile TAGS: []
      copy TAGS: []
      copy TAGS: []
[root@ansible ~]# ansible-playbook --list-tags http.yml
 
playbook: http.yml
 
  play #1 (db): db TAGS: []
      TASK TAGS: []