playbook进阶
语法进阶
变量
- 添加用户
给所有主机添加用户srv ,设置默认密码123456
要求第次登录修改密码 ( 使用变量 )
[root@web1 ~]# vim user.yml
---
- hosts: xl
remote_user: root
vars:
username: bb # 变量 username = bb
tasks:
- name: 创建用户名 "{{username}}"
user:
name: "{{username}}"
- name: 设置密码
shell: echo 123 | passwd --stdin "{{username}}"
- shell: chage -d 0 "{{username}}"
[root@web1 ~]# ansible-playbook user.yml
[root@web1 ~]# vim user.yml
---
- hosts: xl
remote_user: root
vars:
tasks:
- name: 创建用户名 "{{username}}"
user:
name: "{{username}}"
- name: 设置密码
shell: echo 123 | passwd --stdin "{{username}}"
- shell: chage -d 0 "{{username}}"
[root@web1 ~]# ansible-playbook user.yml -e '{"username": "cc"}'
- 设密码
解决密码明文问题
user模块的password为什么不能设置密码呢
经过测试发现, password是把字符串直接写入shadow,并没有改变,而Linux的shadow密码是经过加密的,所以不能使用
- 解决方案
变量过滤器password_hash
[root@web1 ~]# ansible-doc user
[root@web1 ~]#
---
- hosts: xl
remote_user: root
vars:
username: dd
tasks:
- name: 创建用户名 "{{username}}"
user:
name: "{{username}}"
password: "123"
- shell: chage -d 0 "{{username}}"
[root@web1 ~]# ansible-playbook user.yml
[root@web1 ~]# ssh -l dd xl
让我们来看看id和密码文件
[root@web1 ~]# ssh xl
[root@xl ~]# id dd
[root@xl ~]# vim /etc/shadow
- 变量过滤器
那我们来帮dd用户加密
[root@web1 ~]# vim user.yml
---
- hosts: xl
remote_user: root
vars:
username: dd
tasks:
- name: 创建用户名 "{{username}}"
user:
name: "{{username}}"
password: "{{'123' | password_hash('sha512')}}"
- shell: chage -d 0 "{{username}}"
[root@web1 ~]# ansible-playbook user.yml
测试
[root@web1 ~]# ssh xl
[root@xl ~]# cat /etc/shadow
error
- ansible-playbook对错误的处理
默认情况判断$? ,如果值不为0就停止执行
但某些情况我们需要忽略错误继续执行
[root@web1 ~]# vim user.yml
---
- hosts: xl
remote_user: root
vars:
username: aa
tasks:
- shell:
ignore_errors: True
- shell: echo 123 | passwd --stdin aa
[root@web1 ~]# ansible-playbook user.yml
- 错误处理方法
关闭selinux ,如果selinux已经关闭, 返回1,若之前已经关闭则不算错误,可以忽略错误继续运行,忽略错误有两种方法
第一种方式:
shell: /usr/bin/somecommand || /bin/true
第二种方式:
- name: run some command
shell: /usr/bin/somecommand
ignore_errors: True
- 完整的playbook
[root@web1 ~]# vim user.yml
---
- hosts: xl
remote_user: root
tasks:
- user:
name: aa
password: "{{'123'|password_hash('sha512')}}"
[root@web1 ~]# ansible-playbook user.yml
handlers
- 当关注的资源发生变化时采取的操作
- notify这个action可用于在每个play的最后被触发,这样可以避免有多次改变发生时每次都执行指定的操作,取而代之仅在所有的变化发生完成后一次性地执行指定操作
- 在notify中列出的操作称为handler,即notify调用handler中定义的操作
- 前面安装了Apache ,修改httpd的配置文件,重新载入配置文件让服务生效
- 使用handers来实现
[root@web1 ~]# lftp sftp://web2
lftp web2:~> cd /etc/httpd/conf
lftp web2:/etc/httpd/conf> get httpd.conf
lftp web2:/etc/httpd/conf> bye
[root@web1 ~]# vim httpd.conf
Listen 88 # 42行
[root@web1 ~]# vim httpconf.yml
---
- hosts: mysql
remote_user: root
tasks:
- copy:
src: /root/httpd.conf
dest: /etc/httpd/conf/httpd.conf
owner: root
group: root
mode: 0644
- service:
name: httpd
state: restarted
[root@web1 ~]# ansible-playbook httpconf.yml
[root@web1 ~]# curl mysql1:88
- 结合之前实验,完整的playbook
[root@web1 ~]# vim httpd.conf
Listen 80 # 42行
[root@web1 ~]# vim httpconf.yml
---
- hosts: mysql
remote_user: root
tasks:
- copy:
src: /root/httpd.conf
dest: /etc/httpd/conf/httpd.conf
owner: root
group: root
mode: 0644
tags: aabb
notify: reloadhttp
handlers:
- name: reloadhttp
service:
name: httpd
state: restarted
[root@web1 ~]# ansible-playbook httpconf.yml -t aabb
[root@web1 ~]# curl mysql1:80
hello ansible
- 注意事项:
notify调用的是handler段的name定义的串,必须一致,否则达不到触发的效果
多个task触发同一个notify的时候,同一个服务只会触发一次
notify可以触发多个条件,在生产环境中往往涉及到某一个配置文件的改变要重启若干服务的场景, handler用到这里非常适合
结合vars可以写出非常普适的服务管理脚本
when
- 有些时候需要在满足特定的条件后再触发某一项操作,或在特定的条件下终止某个行为,这个时候需要进行条件判断,when正是解决这个问题的最佳选择,远程中的系统变量facts作为when的条件,可以通过setup模块查看
when的样例
[root@web1 ~]# ansible xl -m setup -a 'filter=ansible_os_family'
- 一个使用when的例子
[root@web1 ~]# vim user.yml
---
- hosts: xl
remote_user: root
tasks:
- shell: id aa
register: result
- user:
name: aa
password: "{{'123'|password_hash('sha512')}}"
when: result
[root@web1 ~]# uptime | awk '{print $(NF-2)}'
0.00,
[root@web1 ~]# printf "aaaaa"
aaaaa[root@web1 ~]#
[root@web1 ~]# uptime | awk '{printf("%f",$(NF-2))}'
0.020000[root@web1 ~]#
[root@web1 ~]# uptime | awk '{printf("%.2f",$(NF-2))}'
0.01[root@web1 ~]#
[root@web1 ~]# vim load.yml
---
- hosts: mysql
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@web1 ~]# ansible-playbook load.yml
register
- register
有时候我们还需要更复杂的例子,如判断前一个命令的执行结果去处理后面的操作,这时候就需要register模块来保存前一个命令的返回状态,在后面进行调用
针对运行命令结果的返回值做判定
当系统负载超过一定值的时候做特殊处理
[root@mysql2 ~]# awk 'BEGIN{while(1){}}' &
[root@mysql2 ~]# watch -n 1 'uptime'
[root@web1 ~]# vim load.yml
---
- hosts: mysql
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@web1 ~]# ansible-playbook load.yml
- with_items进阶
为不同用户定义不同组
[root@web1 ~]# vim user.yml
---
- hosts: mysql
remote_user: root
tasks:
- user:
name: "{{item}}"
group: root
password: "{{'123'|password_hash('sha512')}}"
with_items:
- aa
- bb
- cc
- dd
- ee
[root@web1 ~]# ansible-playbook user.yml
[root@web1 ~]# vim user.yml
---
- hosts: mysql
remote_user: root
tasks:
- user:
name: "{{item.username}}"
group: "{{item.group}}"
password: "{{item.password|password_hash('sha512')}}"
with_items:
-
username: nb
password: bn
group: users
-
username: wk
password: kw
group: man
-
username: dd
password: dd
group: daemon
-
username: ww
password: 123qqq...A
group: mysql
-
username: xx
password: oo
group: root
[root@web1 ~]# ansible-playbook user.yml
with_nested
- 嵌套循环:
[root@web1 ~]# vim test.yml
---
- hosts: mysql
remote_user: root
vars:
id: [1, 2, 3]
un: ['a', 'b', 'c']
tasks:
- shell: echo {{item}}
with_nested:
- "{{id}}"
- "{{un}}"
[root@web1 ~]# ansible-playbook test.yml
tags
- tags: 给指定的任务定义一个调用标识
- 使用格式:
name: NAME
module: arguments
tags: TAG_ID
- playbook调用方式
-t TAGS, --tags=TAGS
–skip-tags=SKIP_TAGS
–start-at-task=START_AT
include and roles
- 在编写playbook的时候随着项目越来越大, playbook越来越复杂,修改也很麻烦。这时可以把一些play、task 或 handler放到其他文件中,通过include指令包含进来是一个不错的选择
????
- roles像是加强版的include ,它可以引入一个项目的文件和目录
- 一般所需的目录层级有
vars : 变量层
tasks : 任务层
handlers : 触发条件
files : 文件
template : 模板
default : 默认,优先级最低
- 假如有一个play包含了一个叫"x"的role ,则
????
x/tasks/main.yml
x/vars/main.yml
x/handler/main.yml
x/… …main.yml
都会自动添加进这个play
测试
debug
- 对于Python语法不熟悉的同学, playbook书写起来容易出错,且排错困难,这里介绍几种简单的排错调试方法
检测语法
[root@web1 ~]# vim dubug.yml
---
- hosts: mysql
remote_user: root
tasks:
- shell: uptime | awk '{printf("%.2f",$(NF-2))}'
register: result
- service:
name: httpd
state: stopped
when: result.stdout|float > 0.7
- name: debug info
debug: var=result
[root@web1 ~]# ansible-playbook dubug.yml
测试运行
显示受到影响的主机–list-hosts
显示I作的task --list-tasks
显示将要运行的tag --list tags
- debug模块可以在运行时输出更为详细的信息,帮助我们排错
- debug使用样例