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
posted @ 2022-03-25 16:35  無花無酒鋤作田  阅读(87)  评论(0编辑  收藏  举报