ansible使用
一、ansible基本概念
- ansible的配置清单位于/etc/ansible/hosts,ansible配置位于/etc/ansible/ansible.cfg
- ansible依赖与sshpass,配置文件ansible.cfg中需要把host_key_checking=False注释删除
- 配置清单中,ansible_port为ssh服务端口号,ansible_user为连接到主机使用的用户名,ansible_ssh_pass为用户名对应的密码
- 配置清单中支持使用主机别名,使用别名后主机IP地址必须使用ansible_host指明
- ansible也可以基于密钥进行ssh认证
- ansible保证重复执行的幂等性
二、ansible清单配置详解
- 清单支持分组功能,可以将某些主机分为一组,然后通过组明去管理组内的所有主机。ansible [组名] -m ping
- 清单支持子分组
- 清单支持INI和YAML两种配置格式
- 清单中可以定义变量,后续playbook中可以使用
三、ansible模块的基本使用
- 使用ansible-doc -l可以查看ansible所有模块的名称和功能呢大概
- 如需了解具体模块的使用可以使用命令ansible-doc -s [模块名]
- ansible命令给模块传递参数使用 -a [参数串]
- ansible命令中的changed说明ansible有没有执行具体操作
- ansible中的fetch模块是将受管主机中的文件拉渠道ansible主机
- 对于fetch模块,如果文件的hash值修改了,ansible依旧会执行命令下载新文件,因为ansible会比较文件的hash进行结果判断
四、常用模块之文件操作
- copy模块是将ansible主机的文件拷贝到远程主机
- copy模块常见参数:
- src 需要copy的文件或目录
- dest 指定文件被拷贝的远程主机的哪个目录
- content 文件内容与src二选一
- force 是否强制覆盖
- backup 如远程主机目标路径下已存在同名文件,并且与ansible主机文件内容不同时,是否备份
- owner 指定文件拷贝到远程主机后的属主
- group 同owner
- mode 指定文件拷贝到远程主机后的权限
- file模块可以帮助我们完成一些对文件的基本操作,比如创建文件或目录、删除文件或目录、修改文件权限等
- file模块常见参数:
- path 用户指定要操作的文件或目录
- state 创建文件时用户指定文件类型(directory、touch、link等),删除文件时为absent
- src state为link或者hard时,表示想要创建一个软链或硬链连接的文件
- force state为link使用,yes表示强制创建链接
- owner 指定被操作文件的属主
- group 指定被操作文件的属组
- mode 指定被操作文件的权限
- recurse 操作文件为目录时,recurse=yes可以递归操作目录中的文件
- blockinfile模块可以帮助我们在指定的文件中插入"一段文本",该文本是被标记过的
- blockinfile模块常见参数:
- path 指定要操作的文件
- block(content) 文本
- marker 指定标记
- state present表示插入或更新,absent表示删除标记文本
- insertafter 使用此参数指定对应的行后面插入,也可以使用正则表达式指定插入位置
- insertbefore 同上
- backup 修改文件之前对文件进行备份
- create 当要操作的文件不存在,是否创建文件
- lineinfile模块可以确保某一行文本存在与指定文件中,或者确保删除指定文本,还可以根据正则替换某一行文本
- lineinfile模块常见参数:
- path 表示要操作的文件
- line 文本内容
- regexp 使用正则表达式匹配对应的行,多行匹配时只有最后面那行会被替换,如果是删除则全部匹配都会删除
- state absent和present
- backrefs 表示开启正则表达式后向引用
- insertafter 使用此参数指定对应的行后面插入,也可以使用正则表达式指定插入位置
- insertbefore 同上
- backup 修改文件之前对文件进行备份
- create 当要操作的文件不存在,是否创建文件
五、常用模块之文件操作(二)
- find模块可以帮助我们在远程主机中查找符合条件的文件
- find模块常见参数:
- paths 搜索路径,可以使用name或path替代
- rescurse recurse=yes可以递归查找文件
- hidden 默认情况下,隐藏文件会被忽略,hidden=yes则会查找隐藏文件
- file_type 默认情况下指挥查找"文件",file_type可以指定文件类型,all、directory、file、link
- patterns 文件名,支持shell或正则表达式去匹配文件名称
- user_regex yes表示支持patterns使用正则
- contains 匹配文件内容,使用正则
- age 默认以文件mtime为准与指定时间进行对比
- age_stamp age的时间属性atime、ctime、mtime
- size 根据文件大小查找文件
- get_checksum 返回对应文件的sha1校验码
- replace模块可以根据我们指定的正则表达式替换文件中的字符串
- replace模块常见参数:
- path 要操作的文件
- regexp 正则表达式
- replace 最终要替换成的字符串
- backup 是否在修改前备份文件
六、常用模块之命令类模块
- command模块可以帮助我们在远程主机上执行命令
- command模块常见参数:
- free_form 需要执行的命令
- chdir 执行命令前会先进入到chdir参数指定的目录中
- creates 当指定文件存在就不执行对应命令
- removes 当指定文件不存在就不指定对应命令
- shell模块与command模块不同的是,shell模块执行命令时,会经过远程主机上的/bin/sh程序处理
- shell模块常见参数包含command模块四个参数:
- executable 指定其他类型的shell执行命令,默认shell都是bash
- script模块可以帮助我们在远程主机上执行ansible主机上的脚本,脚本存在与ansible主机不需要拷贝到远程主机再执行
- script常见参数与command模块相同,free_form表示要执行的脚本
七、 常用模块之系统类模块
- cron模块可以帮助我们管理远程主机上的计划任务,相当于crontab
- cron模块常见参数:
- minute 设置计划任务中分钟设定为的值
- hour 设置计划任务中小时设定为的值
- day 设置计划任务中日设定为的值
- month 设置计划任务中月设定为的值
- weekday 设置计划任务中周几设定为的值
- special_time 比如@reboot表示重启时@hourly表示每小时执行一次
- user 计划任务属于哪个用户
- job 任务实际执行的命令或脚本
- name 计划任务名称
- state 删除任务为absent
- disabled 根据名称使对应任务失效
- backup yes会对计划任务进行备份
- service模块可以帮助我们管理远程主机上的服务
- service模块常见参数:
- name 服务名称
- state 此参数值有started、stopped、restarted、reloaded
- enabled 将服务设置为开机启动项
八、 常用模块之系统类模块(二)
- user模块可以帮助我们管理远程主机上的用户
- user模块常见参数:
- name 用户名称,别名user
- group 指定用户所在的基本组
- groups 指定用户所在的夫家族
- append yes表示追加附加组
- shell 指定用户的默认shell
- uid 指定用户的uid
- expires 指定用户的过期时间
- comment 指定用户的注释信息
- state present和absent
- remove yes表示删除用户时会删除用户的home目录
- password 指定用户的密码
- generate_ssh_key yes表示为对应的用户生成ssh密钥对
- ssh_key_file yes表示自定义生成ssh私钥的路径和名称
- group模块可以帮助我们管理远程主机上的组
- group模块常见参数:
- name 组名称
- state present和absent
- gid 组的gid
九、常用模块值包管理模块
- yum_repository模块可以帮助我们管理远程主机上的yum仓库
- yum模块可以帮助我们在远程主机上通过yum源管理软件包
十、初识ansible playbook
- 多条ansible命令可以用ansible playbook完成
- ansible playbook配置文件是YAML格式的
- ansible-playbook用于运行playbook文件
- 一个playbook文件中可以编写多个play
- ansible-playbook --syntax-check [yaml文件]可以检查playbook文件是否存在语法错误
- ansible-playbook --check [yaml文件]可以模拟执行playbook
十一、初识ansible playbook(二)
- ansible playbook的不同写法
- 推荐下面的写法
---
- hosts: test70
remote_user: root
tasks:
- name: make testfile
file:
path: /testdir/testfile
state: touch
mode: 0700
tasks中也可以这么写
tasks:
- name: make testfile
file: path=/testdir/testfile state=touch mode=0700
file后面的参数可以换行,但是要注意缩进
tasks:
- name: make testfile
file: path=/testdir/testfile
state=touch mode=0700
比较老的版本会使用action关键字调用模块
tasks:
- name: make testfile
action: file path=/testdir/testfile state=touch mode=0700
十二、handlers的用法
- handlers可以解决当tasks任务真正执行以后,handlers中被调用的任务才会执行
example,当配置文件真正被修改后才重启nginx服务,否则不重启:
---
- hosts: test70
remote_user: root
tasks:
- name: Modify the configuration
lineinfile:
path=/etc/nginx/conf.d/test.zsythink.net.conf
regexp="listen(.*) 8080(.*)"
line="listen\1 8088\2"
backrefs=yes
backup=yes
notify:
restart nginx
handlers:
- name: restart nginx
service:
name=nginx
state=restarted
- 默认情况下,只有全部tasks都执行完毕才会执行handler。handlers的执行顺序和在playbook中定义的顺序是相同的,与被notify的顺序无关
- meta模块是一种特殊任务,可以影响aansible的内部运行方式,参数值为flush_handlers表示立即执行之前的task所对应的handlers
- 一次性notify多个handler可以使用listen关键字
---
- hosts: test70
remote_user: root
tasks:
- name: task1
file: path=/testdir/testfile
state=touch
notify: handler group1
handlers:
- name: handler1
listen: handler group1
file: path=/testdir/ht1
state=touch
- name: handler2
listen: handler group1
file: path=/testdir/ht2
state=touch
十三、tags的用法
- tags可以帮助我们对任务进行打标签,当任务存在标签后,我们就可以在执行playbook的时候传入标签指定执行哪些任务
---
- hosts: test70
remote_user: root
tags: file
tasks:
- name: task1
file:
path: /testdir/t1
state: touch
tags: t1
- name: task2
file: path=/testdir/t2
state=touch
tags:
- t2
- name: task3
file: path=/testdir/t3
state=touch
tags: ['t3']
ansible-playbook --tags=t2 testtag.yml
ansible-playbook --skip-tags=t2 testtag.yml
- tags还可以写在play上,play下的所有tasks继承play的tags
- ansible预置了5个特殊tag,分别是always、never、tagged、untagged、all
- always、never用于yaml配置文件中,tagged、untagged、all用于执行ansible-playbook命令
十四、变量(一)
- 在play文件中定义变量,可以借助vars关键字,使用变量可以用{{变量名}}
---
- hosts: test70
vars:
testvar1: testfile
testvar2: testfile2
remote_user: root
tasks:
- name: task1
file:
path: /testdir/{{ testvar1 }}
state: touch
- 变量可以多层级定义
---
- hosts: test70
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
- 引用变量时,如果处在开头未知,需要用双引号引起变量
- playbook中的变量可以与配置文件分离,在配置文件中使用vars_files关键字进行引入
---
- hosts: test70
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
十五、变量(二)
- 当我们运行一个playbook时,默认都会运行一个名为Gathering Facts的任务,这个默认任务收集远程主机的相关信息并保存到对应的变量中,我们可以通过ansible [hosts] -m setup查看这些变量,也可以在playbook配置文件中使用这些变量
- ansible_all_ipv4_addresses 表示主机上的所有ipv4的地址
- ansible_distribution 表示主机的系统发行版本
- ansible_distribution_version 表示主机的系统版本号
- ansible_memory_mb 表示内存配置信息
- 我们还可以在受管主机中写入一些自定义的信息,这些自定义信息可以写在/etc/ansible/facts.d目录下,自定义信息文件必须以.fact结尾,文件内容时INI格式或者json格式
- 自定义信息的目录可以通过setup模块的fact_path参数进行定义
- debug模块是用来帮助我们调试的,可以将信息输出到ansible控制台
十六、变量(三)
- 使用register可以将模块的返回值写入到变量中,称作注册变量
- 模块的返回值为json格式,可以使用.或者[]获取json中特定项的值
- 使用vars_prompt关键字提示用户输入信息并写入变量
---
- hosts: test70
remote_user: root
vars_prompt:
- name: "your_name"
prompt: "What is your name"
- name: "your_age"
prompt: "How old are you"
tasks:
- name: output vars
debug:
msg: Your name is {{your_name}},You are {{your_age}} years old.
- 通过命令行也可以传入变量,命令行变量的优先级要高于playbook中的变量
ansible-playbook cmdvar.yml -e 'pass_var="test" pass_var1="test1"'
十七、变量(四)
- 在清单中配置主机信息时,可以同时为主机配置对应的变量
- 为主机组配置变量可以这样做
[testB]
test70 ansible_host=10.1.1.70
test71 anisble_host=10.1.1.71
[testB:vars]
test_group_var1='group var test'
test_group_var2='group var test2'
- set_fact模块可以让我们在tasks中定义变量
- 通过set_fact创建的变量就像主机上的额facts信息,可以在之后的play中被引用(注册变量也可以在之后的play中引用)
以下示例中,testvar1不能被正常输出,testvar2却可以
---
- hosts: test70
remote_user: root
vars:
testvar1: tv1
tasks:
- set_fact:
testvar2: tv2
- debug:
msg: "{{testvar1}} ----- {{testvar2}}"
- hosts: test70
remote_user: root
tasks:
- name: other play get testvar2
debug:
msg: "{{testvar2}}"
- name: other play get testvar1
debug:
msg: "{{testvar1}}"
十八、变量(五)
- 内置变量ansible_version可以获取到ansible版本号
ansible test70 -m debug -a "msg={{ansible_version}}"
- 内置变量hostvars可以帮助我们在操作当前主机的时候获取其他主机中的信息,包括注册变量、主机变量、组变量等信息
- 内置变量inventory_hostname可以获取当前主机的主机名,对应主机在清单中配置的名称
- 内置变量inventory_hostname_short可以获取当前主机的主机名第一个"."之前的字符作为主机的简称
- 内置变量play_hosts可以获取到当前play所操作的所有主机的主机名列表
- 内置变量groups可以获取到清单中所有分则的分则信息
- 内置变量group_names可以获取当前主机所在分组的组名
- 内置变量inventory_dir可以获取ansible主机中清单文件的存放路径
十九、循环(一)
- 关键字with_items可以接收列表信息并使用{{item}}迭代列表的每一项
---
- hosts: test70
remote_user: root
gather_facts: no
tasks:
- debug:
msg: "{{item}}"
with_items: "{{groups.ungrouped}}"
使用循环可以简化playbook文件配置,比如在主机上创建四个文件
---
- hosts: test70
remote_user: root
gather_facts: no
tasks:
- file:
path: "/opt/a"
state: touch
- file:
path: "/opt/b"
state: touch
- file:
path: "/opt/c"
state: touch
- file:
path: "/opt/d"
state: touch
可以使用循环简化为
---
- hosts: test70
remote_user: root
gather_facts: no
vars:
dirs:
- "/opt/a"
- "/opt/b"
- "/opt/c"
- "/opt/d"
tasks:
- file:
path: "{{item}}"
state: touch
with_items: "{{dirs}}"
- 使用循环后注入变量,会让变量列表放在results属性中
---
- hosts: test70
gather_facts: no
tasks:
- shell: "{{item}}"
with_items:
- "ls /opt"
- "ls /home"
register: returnvalue
- debug:
msg:
"{% for i in returnvalue.results %}
{{ i.stdout }}
{% endfor %}"
二十、循环(二)
- with_item如果是嵌套列表,循环会处理每个小列表中的值
- with_list处理嵌套列表,只会处理到第一层列表的元素
- 处理单层列表时,with_items和with_list有一样的效果
- with_flattened与with_items效果一样
- with_together可以将两个列表中的元素对其合并
---
- hosts: test70
remote_user: root
gather_facts: no
tasks:
- debug:
msg: "{{ item }}"
with_together:
- [ 1, 2, 3 ]
- [ a, b, c ]
输出结果:
TASK [debug] ******************************
ok: [test70] => (item=[1, u'a']) => {
"changed": false,
"item": [
1,
"a"
],
"msg": [
1,
"a"
]
}
ok: [test70] => (item=[2, u'b']) => {
"changed": false,
"item": [
2,
"b"
],
"msg": [
2,
"b"
]
}
ok: [test70] => (item=[3, u'c']) => {
"changed": false,
"item": [
3,
"c"
],
"msg": [
3,
"c"
]
}
- 如果with_together中两个列表长度不一致,缺失的部分会用null替代
二十一、循环(三)
- with_cartesian可以进行嵌套循环,可以用with_nested,效果一致
创建三个文件夹,并且都包含test1和test2两个文件
---
- hosts: test70
remote_user: root
gather_facts: no
tasks:
- debug:
msg: "{{ item }}"
with_cartesian:
- [ a, b, c ]
- [ test1, test2 ]
二十二、循环(四)
- with_indexed_items可以给循环列表加上数字索引,获取数字索引{{item.0}}
- with_indexed_items可以将"两层"嵌套列表"拉平",然后按照顺序为每一项编号。不支持多层嵌套
二十三、循环(五)
- with_sequence可以执行循环开始和结束,以及步长
比如要创建test2、test4、test6、test8、test10五个文件,示例如下:
---
- hosts: test70
remote_user: root
gather_facts: no
tasks:
- debug:
msg: "{{ item }}"
with_sequence: start=2 end=10 stride=2
- with_sequence还可以格式化输出数据
---
- hosts: test70
remote_user: root
gather_facts: no
tasks:
- debug:
msg: "{{item}}"
with_sequence: start=2 end=6 stride=2 format="number is %0.2f"
- with_random_choice可以从列表中多个值随机返回一个值
二十四、循环(六)
- with_dict可以循环"字典",将键值对中的键放入key关键字,值放入value关键字中
---
- hosts: test70
remote_user: root
gather_facts: no
vars:
users:
alice: female
bob: male
tasks:
- debug:
msg: "{{item}}"
with_dict: "{{users}}"
- with_subelements可以在处理列表时,指定一个属性
---
- hosts: test70
remote_user: root
gather_facts: no
vars:
users:
- name: bob
gender: male
hobby:
- Skateboard
- VideoGame
- name: alice
gender: female
hobby:
- Music
tasks:
- debug:
msg: "{{ item.0.name }} 's hobby is {{ item.1 }}"
with_subelements:
- "{{users}}"
- hobby
循环过程中的item为
(item=({u'gender': u'male', u'name': u'bob'}, u'Skateboard')) => {
"changed": false,
"item": [
{
"gender": "male",
"name": "bob"
},
"Skateboard"
]
}
结果为
"msg": "bob 's hobby is Skateboard"
"msg": "bob 's hobby is VideoGame"
"msg": "alice 's hobby is Music"
二十五、循环(七)
- with_file可以获取ansible主机的文件
- with_fileglob用来匹配文件名称,在指定目录中匹配符合模式的文件名,也是针对ansible主机文件,不是远程主机
- with_fileglob只能匹配文件,不包含目录
二十六、条件判断
- when作为条件判断的关键字
比如判断条件是Centos系统才执行task
---
- hosts: test70
remote_user: root
tasks:
- debug:
msg: "System release is centos"
when: ansible_distribution == "CentOS"
- 在循环中使用条件判断
---
- hosts: test70
remote_user: root
gather_facts: no
tasks:
- debug:
msg: "{{ item }}"
with_items:
- 1
- 2
- 3
when: item > 1
- 条件判断中的逻辑操作符为and和or,取非为not [condition]
二十七、条件判断与tests
- tests可以进行一些判断操作
---
- hosts: test70
remote_user: root
gather_facts: no
vars:
testpath: /testdir
tasks:
- debug:
msg: "file exist"
when: testpath is exists
is exists中exists是tests的一种,与test -e命令作用相同
- 判断变量的一些tests
- defined :判断变量是否已经定义,已经定义则返回真
- undefind :判断变量是否已经定义,未定义则返回真
- none :判断变量值是否为空,如果变量已经定义,但是变量值为空,则返回真
- 判断执行结果的一些tests
- success 或 succeeded:通过任务的返回信息判断任务的执行状态,任务执行成功则返回真
- failure 或 failed:通过任务的返回信息判断任务的执行状态,任务执行失败则返回真
- change 或 changed:通过任务的返回信息判断任务的执行状态,任务执行状态为changed则返回真
- skip 或 skipped:通过任务的返回信息判断任务的执行状态,当任务没有满足条件,而被跳过执行时,则返回真
- 判断路径的一些tests
- file : 判断路径是否是一个文件,如果路径是一个文件则返回真
- directory :判断路径是否是一个目录,如果路径是一个目录则返回真
- link :判断路径是否是一个软链接,如果路径是一个软链接则返回真
- mount:判断路径是否是一个挂载点,如果路径是一个挂载点则返回真
- exists:判断路径是否存在,如果路径存在则返回真
- 判断字符串的一些tests
- lower:判断包含字母的字符串中的字母是否是纯小写,字符串中的字母全部为小写则返回真
- upper:判断包含字母的字符串中的字母是否是纯大写,字符串中的字母全部为大写则返回真
- 判断整除的一些tests
- even :判断数值是否是偶数,是偶数则返回真
- odd :判断数值是否是奇数,是奇数则返回真
- divisibleby(num) :判断是否可以整除指定的数值,如果除以指定的值以后余数为0,则返回真
- 其他常用的tests判断
- subset:判断一个list是不是另一个list的子集,是另一个list的子集时返回真
- superset : 判断一个list是不是另一个list的父集,是另一个list的父集时返回真
- string:判断对象是否是一个字符串,是字符串则返回真
- number:判断对象是否是一个数字,是数字则返回真
二十八、条件判断与block
- 使用when可以对条件进行判断,当条件成立执行对应的任务。如果需要条件成立执行多个任务,需要使用block关键字
- block可以将多个任务整合成一个块,并把这个块当作一个整体
- 关键字rescue可以在block任务执行失败时执行进行不久,如果block中的任务顺利执行就不会执行rescue中的任务
- 关键字always无论block执行成功还是失败,always中的任务都会被执行
二十九、条件判断与错误处理
- 在执行playbook时,如果任何一个任务执行失败,playbook都会停止运行,除非这个任务设置了ignore_errors: true
- fail模块就是一个用来"执行失败"的模块,当fail模块执行后,playbook就会认为有任务失败而终止运行
- fail模块加上条件判断when可以达到根据执行过程中一些结果输出而终止运行
- 关键字failed_when也可以达到此效果,条件成立将对应任务的执行状态设置为失败
- 关键字changed_when的作用时条件成立,将对应任务的执行状态设置为changed
三十、过滤器(一)
- 过滤器可以帮助我们对数据进行处理
- ansible的过滤器功能来自于jinja2模板引擎
字符串相关的过滤器
---
- hosts: test70
remote_user: root
vars:
testvar: "abc123ABC 666"
testvar1: " abc "
testvar2: '123456789'
testvar3: "1a2b,@#$%^&"
tasks:
- debug:
#将字符串转换成纯大写
msg: "{{ testvar | upper }}"
- debug:
#将字符串转换成纯小写
msg: "{{ testvar | lower }}"
- debug:
#将字符串变成首字母大写,之后所有字母纯小写
msg: "{{ testvar | capitalize }}"
- debug:
#将字符串反转
msg: "{{ testvar | reverse }}"
- debug:
#返回字符串的第一个字符
msg: "{{ testvar | first }}"
- debug:
#返回字符串的最后一个字符
msg: "{{ testvar | last }}"
- debug:
#将字符串开头和结尾的空格去除
msg: "{{ testvar1 | trim }}"
- debug:
#将字符串放在中间,并且设置字符串的长度为30,字符串两边用空格补齐30位长
msg: "{{ testvar1 | center(width=30) }}"
- debug:
#返回字符串长度,length与count等效,可以写为count
msg: "{{ testvar2 | length }}"
- debug:
#将字符串转换成列表,每个字符作为一个元素
msg: "{{ testvar3 | list }}"
- debug:
#将字符串转换成列表,每个字符作为一个元素,并且随机打乱顺序
#shuffle的字面意思为洗牌
msg: "{{ testvar3 | shuffle }}"
- debug:
#将字符串转换成列表,每个字符作为一个元素,并且随机打乱顺序
#在随机打乱顺序时,将ansible_date_time.epoch的值设置为随机种子
#也可以使用其他值作为随机种子,ansible_date_time.epoch是facts信息
msg: "{{ testvar3 | shuffle(seed=(ansible_date_time.epoch)) }}"
与数字相关的过滤器
---
- hosts: test70
remote_user: root
vars:
testvar4: -1
tasks:
- debug:
#将对应的值转换成int类型
#ansible中,字符串和整形不能直接计算,比如{{ 8+'8' }}会报错
#所以,我们可以把一个值为数字的字符串转换成整形后再做计算
msg: "{{ 8+('8' | int) }}"
- debug:
#将对应的值转换成int类型,如果无法转换,默认返回0
#使用int(default=6)或者int(6)时,如果无法转换则返回指定值6
msg: "{{ 'a' | int(default=6) }}"
- debug:
#将对应的值转换成浮点型,如果无法转换,默认返回'0.0'
msg: "{{ '8' | float }}"
- debug:
#当对应的值无法被转换成浮点型时,则返回指定值’8.8‘
msg: "{{ 'a' | float(8.88) }}"
- debug:
#获取对应数值的绝对值
msg: "{{ testvar4 | abs }}"
- debug:
#四舍五入
msg: "{{ 12.5 | round }}"
- debug:
#取小数点后五位
msg: "{{ 3.1415926 | round(5) }}"
- debug:
#从0到100中随机返回一个随机数
msg: "{{ 100 | random }}"
- debug:
#从5到10中随机返回一个随机数
msg: "{{ 10 | random(start=5) }}"
- debug:
#从5到15中随机返回一个随机数,步长为3
#步长为3的意思是返回的随机数只有可能是5、8、11、14中的一个
msg: "{{ 15 | random(start=5,step=3) }}"
- debug:
#从0到15中随机返回一个随机数,这个随机数是5的倍数
msg: "{{ 15 | random(step=5) }}"
- debug:
#从0到15中随机返回一个随机数,并将ansible_date_time.epoch的值设置为随机种子
#也可以使用其他值作为随机种子,ansible_date_time.epoch是facts信息
#seed参数从ansible2.3版本开始可用
msg: "{{ 15 | random(seed=(ansible_date_time.epoch)) }}"
与列表相关的过滤器
---
- hosts: test70
remote_user: root
vars:
testvar7: [22,18,5,33,27,30]
testvar8: [1,[7,2,[15,9]],3,5]
testvar9: [1,'b',5]
testvar10: [1,'A','b',['QQ','wechat'],'CdEf']
testvar11: ['abc',1,3,'a',3,'1','abc']
testvar12: ['abc',2,'a','b','a']
tasks:
- debug:
#返回列表长度,length与count等效,可以写为count
msg: "{{ testvar7 | length }}"
- debug:
#返回列表中的第一个值
msg: "{{ testvar7 | first }}"
- debug:
#返回列表中的最后一个值
msg: "{{ testvar7 | last }}"
- debug:
#返回列表中最小的值
msg: "{{ testvar7 | min }}"
- debug:
#返回列表中最大的值
msg: "{{ testvar7 | max }}"
- debug:
#将列表升序排序输出
msg: "{{ testvar7 | sort }}"
- debug:
#将列表降序排序输出
msg: "{{ testvar7 | sort(reverse=true) }}"
- debug:
#返回纯数字非嵌套列表中所有数字的和
msg: "{{ testvar7 | sum }}"
- debug:
#如果列表中包含列表,那么使用flatten可以'拉平'嵌套的列表
#2.5版本中可用,执行如下示例后查看效果
msg: "{{ testvar8 | flatten }}"
- debug:
#如果列表中嵌套了列表,那么将第1层的嵌套列表‘拉平’
#2.5版本中可用,执行如下示例后查看效果
msg: "{{ testvar8 | flatten(levels=1) }}"
- debug:
#过滤器都是可以自由结合使用的,就好像linux命令中的管道符一样
#如下,取出嵌套列表中的最大值
msg: "{{ testvar8 | flatten | max }}"
- debug:
#将列表中的元素合并成一个字符串
msg: "{{ testvar9 | join }}"
- debug:
#将列表中的元素合并成一个字符串,每个元素之间用指定的字符隔开
msg: "{{ testvar9 | join(' , ') }}"
- debug:
#从列表中随机返回一个元素
#对列表使用random过滤器时,不能使用start和step参数
msg: "{{ testvar9 | random }}"
- debug:
#从列表中随机返回一个元素,并将ansible_date_time.epoch的值设置为随机种子
#seed参数从ansible2.3版本开始可用
msg: "{{ testvar9 | random(seed=(ansible_date_time.epoch)) }}"
- debug:
#随机打乱顺序列表中元素的顺序
#shuffle的字面意思为洗牌
msg: "{{ testvar9 | shuffle }}"
- debug:
#随机打乱顺序列表中元素的顺序
#在随机打乱顺序时,将ansible_date_time.epoch的值设置为随机种子
#seed参数从ansible2.3版本开始可用
msg: "{{ testvar9 | shuffle(seed=(ansible_date_time.epoch)) }}"
- debug:
#将列表中的每个元素变成纯大写
msg: "{{ testvar10 | upper }}"
- debug:
#将列表中的每个元素变成纯小写
msg: "{{ testvar10 | lower }}"
- debug:
#去掉列表中重复的元素,重复的元素只留下一个
msg: "{{ testvar11 | unique }}"
- debug:
#将两个列表合并,重复的元素只留下一个
#也就是求两个列表的并集
msg: "{{ testvar11 | union(testvar12) }}"
- debug:
#取出两个列表的交集,重复的元素只留下一个
msg: "{{ testvar11 | intersect(testvar12) }}"
- debug:
#取出存在于testvar11列表中,但是不存在于testvar12列表中的元素
#去重后重复的元素只留下一个
#换句话说就是:两个列表的交集在列表1中的补集
msg: "{{ testvar11 | difference(testvar12) }}"
- debug:
#取出两个列表中各自独有的元素,重复的元素只留下一个
#即去除两个列表的交集,剩余的元素
msg: "{{ testvar11 | symmetric_difference(testvar12) }}"
与变量未定义相关的过滤器
---
- hosts: test70
remote_user: root
gather_facts: no
vars:
testvar6: ''
tasks:
- debug:
#如果变量没有定义,则临时返回一个指定的默认值
#注:如果定义了变量,变量值为空字符串,则会输出空字符
#default过滤器的别名是d
msg: "{{ testvar5 | default('zsythink') }}"
- debug:
#如果变量的值是一个空字符串或者变量没有定义,则临时返回一个指定的默认值
msg: "{{ testvar6 | default('zsythink',boolean=true) }}"
- debug:
#如果对应的变量未定义,则报出“Mandatory variable not defined.”错误,而不是报出默认错误
msg: "{{ testvar5 | mandatory }}"
三十一、变量(六)
- vars_files只能在一开始就引入文件中的所有变量,如果需要动态获取到最新的变量文件内容需要使用include_vars
---
- 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}}"
- include_vars可以将文件中的全部变量赋值给另一个变量
- include_vars可以将指定目录的所有变量文件加载进来
- include_vars还有其他属性,extensions、depth、files_matching、ignore_files
三十二、过滤器(二)
- json_query过滤器可以获取json中指定属性的值
三十三、过滤器(三)
- 常用的过滤器
---
- hosts: test70
remote_user: root
gather_facts: no
tasks:
######################################################################
#在调用shell模块时,如果引用某些变量时需要添加引号,则可以使用quote过滤器代替引号
#示例如下,先看示例,后面会有注解
- shell: "echo {{teststr | quote}} > /testdir/testfile"
vars:
teststr: "a\nb\nc"
#上例中shell模块的写法与如下写法完全等效
#shell: "echo '{{teststr}}' > /testdir/testfile"
#没错,如你所见,quote过滤器能够代替引号
#上例中,如果不对{{teststr}}添加引号,则会报错,因为teststr变量中包含"\n"转义符
######################################################################
#ternary过滤器可以实现三元运算的效果 示例如下
#如下示例表示如果name变量的值是John,那么对应的值则为Mr,否则则为Ms
#简便的实现类似if else对变量赋值的效果
- debug:
msg: "{{ (name == 'John') | ternary('Mr','Ms') }}"
vars:
name: "John"
######################################################################
#basename过滤器可以获取到一个路径字符串中的文件名
- debug:
msg: "{{teststr | basename}}"
vars:
teststr: "/testdir/ansible/testfile"
######################################################################
#获取到一个windows路径字符串中的文件名,2.0版本以后的ansible可用
- debug:
msg: "{{teststr | win_basename}}"
vars:
teststr: 'D:\study\zsythink'
######################################################################
#dirname过滤器可以获取到一个路径字符串中的路径名
- debug:
msg: "{{teststr | dirname}}"
vars:
teststr: "/testdir/ansible/testfile"
######################################################################
#获取到一个windows路径字符串中的文件名,2.0版本以后的ansible可用
- debug:
msg: "{{teststr | win_dirname}}"
vars:
teststr: 'D:\study\zsythink'
######################################################################
#将一个windows路径字符串中的盘符和路径分开,2.0版本以后的ansible可用
- debug:
msg: "{{teststr | win_splitdrive}}"
vars:
teststr: 'D:\study\zsythink'
#可以配合之前总结的过滤器一起使用,比如只获取到盘符,示例如下
#msg: "{{teststr | win_splitdrive | first}}"
#可以配合之前总结的过滤器一起使用,比如只获取到路径,示例如下
#msg: "{{teststr | win_splitdrive | last}}"
######################################################################
#realpath过滤器可以获取软链接文件所指向的真正文件
- debug:
msg: "{{ path | realpath }}"
vars:
path: "/testdir/ansible/testsoft"
######################################################################
#relpath过滤器可以获取到path对于“指定路径”来说的“相对路径”
- debug:
msg: "{{ path | relpath('/testdir/testdir') }}"
vars:
path: "/testdir/ansible"
######################################################################
#splitext过滤器可以将带有文件名后缀的路径从“.后缀”部分分开
- debug:
msg: "{{ path | splitext }}"
vars:
path: "/etc/nginx/conf.d/test.conf"
#可以配置之前总结的过滤器,获取到文件后缀
#msg: "{{ path | splitext | last}}"
#可以配置之前总结的过滤器,获取到文件前缀名
#msg: "{{ path | splitext | first | basename}}"
######################################################################
#to_uuid过滤器能够为对应的字符串生成uuid
- debug:
msg: "{{ teststr | to_uuid }}"
vars:
teststr: "This is a test statement"
######################################################################
#bool过滤器可以根据字符串的内容返回bool值true或者false
#字符串的内容为yes、1、True、true则返回布尔值true,字符串内容为其他内容则返回false
- debug:
msg: "{{ teststr | bool }}"
vars:
teststr: "1"
#当和用户交互时,有可能需要用户从两个选项中选择一个,比如是否继续,
#这时,将用户输入的字符串通过bool过滤器处理后得出布尔值,从而进行判断,比如如下用法
#- debug:
# msg: "output when bool is true"
# when: some_string_user_input | bool
######################################################################
#map过滤器可以从列表中获取到每个元素所共有的某个属性的值,并将这些值组成一个列表
#当列表中嵌套了列表,不能越级获取属性的值,也就是说只能获取直接子元素的共有属性值。
- vars:
users:
- name: tom
age: 18
hobby:
- Skateboard
- VideoGame
- name: jerry
age: 20
hobby:
- Music
debug:
msg: "{{ users | map(attribute='name') | list }}"
#也可以组成一个字符串,用指定的字符隔开,比如分号
#msg: "{{ users | map(attribute='name') | join(';') }}"
######################################################################
#与python中的用法相同,两个日期类型相减能够算出两个日期间的时间差
#下例中,我们使用to_datatime过滤器将字符串类型转换成了日期了类型,并且算出了时间差
- debug:
msg: '{{ ("2016-08-14 20:00:12"| to_datetime) - ("2012-12-25 19:00:00" | to_datetime) }}'
#默认情况下,to_datatime转换的字符串的格式必须是“%Y-%m-%d %H:%M:%S”
#如果对应的字符串不是这种格式,则需要在to_datetime中指定与字符串相同的时间格式,才能正确的转换为时间类型
- debug:
msg: '{{ ("20160814"| to_datetime("%Y%m%d")) - ("2012-12-25 19:00:00" | to_datetime) }}'
#如下方法可以获取到两个日期之间一共相差多少秒
- debug:
msg: '{{ ( ("20160814"| to_datetime("%Y%m%d")) - ("20121225" | to_datetime("%Y%m%d")) ).total_seconds() }}'
#如下方法可以获取到两个日期“时间位”相差多少秒,注意:日期位不会纳入对比计算范围
#也就是说,下例中的2016-08-14和2012-12-25不会纳入计算范围
#只是计算20:00:12与08:30:00相差多少秒
#如果想要算出连带日期的秒数差则使用total_seconds()
- debug:
msg: '{{ ( ("2016-08-14 20:00:12"| to_datetime) - ("2012-12-25 08:30:00" | to_datetime) ).seconds }}'
#如下方法可以获取到两个日期“日期位”相差多少天,注意:时间位不会纳入对比计算范围
- debug:
msg: '{{ ( ("2016-08-14 20:00:12"| to_datetime) - ("2012-12-25 08:30:00" | to_datetime) ).days }}'
######################################################################
#使用base64编码方式对字符串进行编码
- debug:
msg: "{{ 'hello' | b64encode }}"
#使用base64编码方式对字符串进行解码
- debug:
msg: "{{ 'aGVsbG8=' | b64decode }}"
#######################################################################
#使用sha1算法对字符串进行哈希
- debug:
msg: "{{ '123456' | hash('sha1') }}"
#使用md5算法对字符串进行哈希
- debug:
msg: "{{ '123456' | hash('md5') }}"
#获取到字符串的校验和,与md5哈希值一致
- debug:
msg: "{{ '123456' | checksum }}"
#使用blowfish算法对字符串进行哈希,注:部分系统支持
- debug:
msg: "{{ '123456' | hash('blowfish') }}"
#使用sha256算法对字符串进行哈希,哈希过程中会生成随机"盐",以便无法直接对比出原值
- debug:
msg: "{{ '123456' | password_hash('sha256') }}"
#使用sha256算法对字符串进行哈希,并使用指定的字符串作为"盐"
- debug:
msg: "{{ '123456' | password_hash('sha256','mysalt') }}"
#使用sha512算法对字符串进行哈希,哈希过程中会生成随机"盐",以便无法直接对比出原值
- debug:
msg: "{{ '123123' | password_hash('sha512') }}"
#使用sha512算法对字符串进行哈希,并使用指定的字符串作为"盐"
- debug:
msg: "{{ '123123' | password_hash('sha512','ebzL.U5cjaHe55KK') }}"
#如下方法可以幂等的为每个主机的密码生成对应哈希串
#有了之前总结的过滤器用法作为基础,你一定已经看懂了
- debug:
msg: "{{ '123123' | password_hash('sha512', 65534|random(seed=inventory_hostname)|string) }}"
三十四、lookup插件
- 前文中的循环在本质上就是lookup插件
---
- hosts: test70
remote_user: root
gather_facts: no
tasks:
- debug:
msg: "index is {{item.0}} , value is {{item.1}}"
with_indexed_items: ['a','b','c']
也可以写成
---
- hosts: test70
remote_user: root
gather_facts: no
tasks:
- debug:
msg: "index is {{item.0}} , value is {{item.1}}"
loop: "{{ lookup('indexed_items',['a','b','c']) }}"
---
- hosts: test70
remote_user: root
gather_facts: no
vars:
users:
alice: female
bob: male
tasks:
- debug:
msg: "{{item.key}} is {{item.value}}"
with_dict: "{{ users }}"
也可以用lookup写成
---
- hosts: test70
remote_user: root
gather_facts: no
vars:
users:
alice: female
bob: male
tasks:
- debug:
msg: "{{item.key}} is {{item.value}}"
loop: "{{ lookup('dict',users) }}"
- 可以使用命令行查看lookup插件是否可用,以及具体插件的用法
ansible-doc -t lookup -l
ansible-doc -t lookup dict
三十五、循环(八)
- 2.5版本之前的ansible习惯使用"with_X"风格的关键字操作循环,2.6版本之后推荐使用loop关键字代替with_X风格的关键字
三十六、include
- 将重复性的任务提取到文件中并使用include进行引入,与代码中的函数类似
三十七、include(二)
- include_tasks可以代替include关键字
- import_tasks也可以引入任务,不过是静态的(playbook被加载时就预处理了),include_tasks是动态的(playbook运行时实时处理)
- import_playbook可以引入整个playbook
三十八、jinja2模板(一)
- 模板可以用来修改配置文件,通过template模块进行引用,模板中可以使用变量进行渲染
# cat temptest.yml
---
- hosts: test70
remote_user: root
gather_facts: no
tasks:
- yum:
name: redis
state: present
- template:
src: /testdir/ansible/redis.conf
dest: /etc/redis.conf
- jinja2模板中常用的基本语法:
- {{ }} :用来装载表达式,比如变量、运算表达式、比较表达式等。
- {% %} :用来装载控制语句,比如 if 控制结构,for循环控制结构。
- {# #} :用来装载注释,模板文件被渲染后,注释不会包含在最终生成的文件中。
三十九、jinja2模板(二)
- 模板中的语法
if控制语句
{% if 条件 %}
...
{% endif %}
{% if 条件 %}
...
{% else %}
...
{% endif %}
{% if 条件一 %}
...
{% elif 条件二 %}
...
{% elif 条件N %}
...
{% endif %}
类似三元表达式
{{ 'a' if 2>1 else 'b' }}
定义变量
{% set teststr='abc' %}
{{ teststr }}
for循环
{% for 迭代变量 in 可迭代对象 %}
{{ 迭代变量 }}
{% endfor %}
四十、jinja2模板(三)
- 模板中的转义字符可以使用引号直接引起或者使用{{raw}}和{{endraw}}组合来括起来
- 模板中可以定义类似函数的东西,叫做宏
{% macro testfunc() %}
test string
{% endmacro %}
{{ testfunc() }}
四十一、jinja2模板(四)
- 模板中可以包含其他模板,使用标签
- import可以引入其他文件中的宏
- 集成模板使用
四十二、角色
- 使用ansible-galaxy命令快速创建角色、下载角色、管理角色
四十三、使用ansible-vault加密数据
- 使用命令对playbook文件进行加密
# 使用此命令加密
ansible-vault encrypt test.yml
# 使用此命令解密执行
ansible-playbook --ask-vault-pass test.yml
- ansible-vault其他命令,create、view、edit,rekey、encrypt_string
四十四、变量(七)
- group_vars和host_vars
四十五、常用技巧(一)
- 在ansible中使用python字符串的一些特性
- 使用[]截取字符串
- 使用+连接字符串
- 使用*连续重复输出字符串
- 使用任务委托delegate_to可以让某个任务指定在主机上执行
- 让某个任务在ansible主机上执行,而不是受管主机上执行,connection: local
- 让某个任务只执行一次(在ansible主机上的任务只执行一次),run_once: true