ansible
ansible

ansible

ansible简介

1. 概述

官方简介

http://www.ansible.com.cn/docs/

Ansible命令选项

参数 英文释义 中文释义
-i inventory list 指定主机清单
-m module 指定模块
-a action 指定动作(一般是模块中的参数)

环境初始化

#windows不能作为主控设备
#(不建议)安装centos7 默认ansible-2.9.27版本(可能会造成下面部分命令参数不可用)
yum install epel-release -y
yum install ansible -y

#(建议)安装最新ansible-4.10  python3.x
pip3 install ansible

#创建默认配置文件
mkdir -p /etc/ansible
ansible-config init --disabled > /etc/ansible/ansible.cfg

#验证
python3 -m pip show ansible
which ansible

PS:

ERROR! Unexpected Exception, this is probably a bug: (cryptography 0.8.2 (/usr/lib64/python2.7/site-packages), Requirement.parse(‘cryptography>=1.1’))

#cryptography包冲突
rpm -qa |grep python-crypto
yum -y remove python-cryptography

pip3 install ansible

ERROR! Unexpected Exception, this is probably a bug: module ‘ansible.constants’ has no attribute ‘CONTROLLER_PYTHON_WARNING’

#检查环境变量里的ansible是否齐全
whereis ansible
ll /usr/local/bin/ansible*
ll /usr/bin/ansible*
#一般在    $PYTHON_HOME/bin/ansible

#旧ansible删干净
rm -rf /usr/local/bin/ansible*
#重建ansible软链接
ln /opt/env/python38/bin/ansible /usr/local/bin/ansible

#或清空所有ansible重新安装

文档

https://blog.csdn.net/sj349781478/article/details/105755615/

https://docs.ansible.com/

https://docs.ansible.com/ansible/latest/collections/index.html

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/index.html#modules

ansible-doc -s 模块名

Bili教程

使用前的准备工作

0. 新建初始化目录

mkdir -p /opt/ansible

1. 修改全局配置

#查看ansible.cfg路径
#ansible --version | grep "config file" | awk -F " = " '{print $2}'
#为None说明文件不存在

mkdir -p /etc/ansible
vi /etc/ansible/ansible.cfg


[defaults]
#设置是否检查SSH主机的密钥,关闭后第一次连接不会提示配置实例
host_key_checking = False
#主机列表配置文件
inventory      = /opt/ansible/hosts
# 指定ansible命令执行的用户,默认使用当前用户
remote_user = root
#库文件存放目录     
#library        = /usr/share/my_modules/
#临时py文件存放在远程主机目录
#remote_tmp     = ~/.ansible/tmp
#本机的临时执行目录
#local_tmp      = ~/.ansible/tmp
#默认并发数
#forks          = 5
#默认sudo用户
#sudo_user      = root
#每次执行是否询问sudo的ssh密码
#ask_sudo_pass = True
#每次执行是否询问ssh密码
#ask_pass      = True
#远程主机端口
#remote_port    = 22
#ansible日志目录
#log_path = /var/log/ansible.log
#指定通信机制
#transport = smart
# 角色配置路径
#roles_path = /etc/ansible/roles
# ssh连接超时
#timeout = 10
# ansible命令默认执行模块
#module_name = command

#普通用户提权操作
#[privilege_escalation]
#become=True
#become_method=sudo
#become_user=root
#become_ask_pass=False

简洁配置

echo -e "[defaults]
inventory      = /opt/ansible/hosts
host_key_checking = False
remote_user = root">/etc/ansible/ansible.cfg

2. 修改主机清单

vi /opt/ansible/hosts

[gp-master]
192.168.1.183

#设置所有主机的配置
[all:vars]
ansible_ssh_port=22
ansible_ssh_user=root
ansible_ssh_pass=6

2. 主机清单

2.1 使用前的优化

#优化ssh速度
vi /etc/ssh/sshd_config
UseDNS no
GSSAPIAuthentication no
GSSAPICleanupcredentials no

2.1 配置主机清单

vi /opt/ansible/hosts

#组
[gp]
192.168.1.170
192.168.1.171
192.168.1.172
192.168.1.173
#上面4台设备等同于=>
[gp]
192.168.1.17[0:3]
#子组
[gp-master]
192.168.1.170
[gp-datenode01]
192.168.1.171
[gp-datenode02]
192.168.1.172
[gp-datenode03]
192.168.1.173

#建立gp子组
[gp:children]
gp-master
gp-datenode01
gp-datenode02
gp-datenode03
#带配置项
[master]
192.168.1.170 ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass=6 hostname=gp_master

#对组批量配置
#设置gp-master组的所有配置
[gp-master:vars]
ansible_ssh_port=22
ansible_ssh_user=root
ansible_ssh_pass=6
hostname=gp_master

#all 表示所有
[all:vars]

3. 模块

ansible -m 模块名 -a '参数'

不带参数默认使用command

https://docs.ansible.com/ansible/latest/collections/index_module.html

https://docs.ansible.com/ansible/latest/collections/index_module.html#ansible-builtin

https://docs.ansible.com/ansible/latest/collections/index_module.html#ansible-posix

1. 执行脚本

script 脚本执行器

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/script_module.html#ansible-collections-ansible-builtin-script-module

命令 参数 说明
cmd string 要运行的本地脚本的路径,后跟可选参数
chdir path 执行命令前请进入该目录(cd path)
executable string 用于调用脚本的可执行文件的名称或路径(默认为bash),可自行定义为python等
creates path 如果匹配的文件已经存在,则不会运行此步骤
removes path 如果存在匹配的文件,则运行此步骤
ansible test -m script -a "xxx.sh"
- name: Run a script with arguments (free form)
  ansible.builtin.script: /some/local/script.sh --some-argument 1234

- name: Run a script with arguments (using 'cmd' parameter)
  ansible.builtin.script:
    cmd: /some/local/script.sh --some-argument 1234

- name: Run a script only if file.txt does not exist on the remote node
  ansible.builtin.script: /some/local/create_file.sh --some-argument 1234
  args:
    creates: /the/created/file.txt

command 命令执行器

不支持通配符,管道符,变量(等很多都不能用)!

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/command_module.html#ansible-builtin-command-module-execute-commands-on-targets

命令 参数 说明
cmd string 要运行的命令后面跟着可选参数
chdir path 执行命令前请进入该目录(cd path)
executable string 修改执行命令的shell,需要一个可执行文件的绝对路径
argv list 以列表而不是字符串的形式传递命令
creates path 如果匹配的文件已经存在,则不会运行此步骤
removes path 如果存在匹配的文件,则运行此步骤
stdin string 将命令的 stdin 直接设置为指定的值
stdin_add_newline boolean 是否向标准输入数据追加换行符
strip_empty_ends boolean 从result中stdout/stderr的末尾删除空行
ansible test -m command -a "ls /tmp/"

ansible test -m command -a "cat /tmp/hello.txt"
- name: Return motd to registered var
  ansible.builtin.command: cat /etc/motd
  register: mymotd

# free-form (string) arguments, all arguments on one line
- name: Run command if /path/to/database does not exist (without 'args')
  ansible.builtin.command: /usr/bin/make_database.sh db_user db_name creates=/path/to/database

#'args'是一个任务关键字,与模块在同一级别传递
- name: Change the working directory to somedir/ and run the command as db_owner if /path/to/database does not exist
  ansible.builtin.command: /usr/bin/make_database.sh db_user db_name
  become: yes
  become_user: db_owner
  args:
    chdir: somedir/
    creates: /path/to/database

- name: Safely use templated variable to run command. Always use the quote filter to avoid injection issues
  ansible.builtin.command: cat {{ myfile|quote }}
  register: myoutput

- name: Run command if /path/to/database does not exist (with 'cmd' parameter)
  ansible.builtin.command:
    cmd: /usr/bin/make_database.sh db_user db_name
    creates: /path/to/database

修改默认模块为shell

vi /etc/ansible/ansible.cfg

module_name = shell

shell 命令执行器

(使用”)通配符,管道符,变量 基本上都支持

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/shell_module.html#ansible-builtin-shell-module-execute-shell-commands-on-targets

命令 参数 说明
cmd string 要运行的命令后面跟着可选参数
chdir path 执行命令前请进入该目录(cd path)
executable string 修改执行命令的shell,需要一个可执行文件的绝对路径
creates path 如果匹配的文件已经存在,则不会运行此步骤
removes path 如果存在匹配的文件,则运行此步骤
stdin string 将命令的 stdin 直接设置为指定的值
stdin_add_newline boolean 是否向标准输入数据追加换行符
ansible test -m shell -a 'ls /tmp/'

#查看端口监听
ansible test -m shell -a "ss -ntl | grep '\*:\*' | awk  '{print \$4}'"
#查看端口监听程序
ansible test -m shell -a "ss -ntlp | grep ':6379' | awk  '{print \$6}'"

#杀进程
ansible test -m shell -a "killall nginx"

ansible test -m shell -a 'cat /tmp/hello.txt'
- name: Execute the command in remote shell; stdout goes to the specified file on the remote
  ansible.builtin.shell: somescript.sh >> somelog.txt

- name: This command will change the working directory to somedir/
  ansible.builtin.shell:
    cmd: ls -l | grep log
    chdir: somedir/

- name: '查看进程状态'  # 对每个管道错误都对外抛出
  shell:
    cmd: 'set -o pipefail && ps aux | grep fdfs_ | grep -v grep'

expect 带交互的命令执行器

执行命令并响应设定交互

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/expect_module.html#ansible-builtin-expect-module-executes-a-command-and-responds-to-prompts

命令 参数 说明
command string 要运行的命令
responses dictionary 期望的字符串/正则表达式和响应的字符串的映射. 如果响应是一个列表,连续的匹配将返回连续的响应
echo boolean 是否回显你的响应字符串 false-(默认)
timeout integer 等待预期字符串的时间(以秒为单位) 使用 null 禁用超时 30-(默认)
chdir path 执行命令前请进入该目录(cd path)
creates path 如果文件已经存在,则不会运行此步骤
removes path 如果文件不存在,则不会运行此步骤
ansible test -m expect -a 'command="passwd gpadmin" responses={".*密码":"123456"} echo=true'
- name: Case insensitive password string match
  ansible.builtin.expect:
    command: passwd username
    responses:
      (?i)password: "MySekretPassword"
  # you don't want to show passwords in your logs
  no_log: true

- name: Generic question with multiple different responses
  ansible.builtin.expect:
    command: /path/to/custom/command
    responses:
      Question:
        - response1
        - response2
        - response3

PS

  • FAILED! => {
    "changed": false,
    "msg": "Failed to import the required Python library (pexpect) on gp-datanode01's Python /usr/bin/python3. Please read the module documentation and install it in the appropriate location. If the required library is installed, but Ansible is using the wrong Python interpreter, please consult the documentation on ansible_python_interpreter"
    }

    #Python library (pexpect)  =>  pexpect库不存在
    pip install pexpect
    
    #指定py版本
    ansible_python_interpreter=/usr/bin/python3
    #或直接替换原始(系统会崩)
    ln -sf /usr/bin/python3.6 /usr/bin/python3
    ln -sf /usr/bin/pip-3.6 /usr/bin/pip3
    ln -sf /usr/bin/python3 /usr/bin/python
    ln -sf /usr/bin/pip3 /usr/bin/pip
    ln -sf /usr/bin/python3 /usr/local/bin/python
    ln -sf /usr/bin/pip3 /usr/local/bin/pip
    

template Jinja2模板填充分发

参数同copy

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/template_module.html#ansible-builtin-template-module-template-a-file-out-to-a-target-host

命令 参数 说明
src path Jinja2格式模板的路径(文件必须使用utf-8编码)
dest path 在远程计算机上呈现模板的位置
force boolean true-文件不一致时替换远程文件(默认) false-仅当目标不存在时才传输文件
mode 0777 or u+rwx or u=rw,g=r,o=r 目标文件或目录的权限
newline_sequence string \n(默认)
output_encoding string 重写用于写入dest定义的模板文件的编码,默认为utf-8,可以使用python支持的任何编码
owner string 应该拥有文件系统对象的用户名(chown)
group string 应该拥有文件系统对象的组的名称(chown)
backup boolean 备份
ansible test -m template -a 'src=/etc/hostname dest=/tmp/hostname'

ansible test -m template -a 'src=/opt/ansible/hello.j2 dest=/opt/ansible/hello.txt' -e "helloworld=QL"
- name: Template a file to /etc/file.conf
  ansible.builtin.template:
    src: /mytemplates/foo.j2
    dest: /etc/file.conf
    owner: bin
    group: wheel
    mode: '0644'

- name: Template a file, using symbolic modes (equivalent to 0644)
  ansible.builtin.template:
    src: /mytemplates/foo.j2
    dest: /etc/file.conf
    owner: bin
    group: wheel
    mode: u=rw,g=r,o=r

模板文件

https://jinja.palletsprojects.com/en/latest/

HelloWorld : {{helloworld}}

2. 文件/文本操作

replace 文本替换

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/replace_module.html#ansible-builtin-replace-module-replace-all-instances-of-a-particular-string-in-a-file-using-a-back-referenced-regular-expression

正则反向引用

命令 参数 说明
path path 要修改的文件
replace string 替换regexp的字符串匹配. 可以包含反向引用,如果regexp匹配,将使用regexp捕获组展开. 如果未设置,则完全删除匹配项. 反向引用可以模糊地像\1那样使用,也可以明确地像\g<1>那样使用
regexp string 要在文件内容中查找的(Python)正则表达式
after string 如果指定了,只有匹配之后的内容才会被替换/删除. 可与before结合使用
before string 如果指定,则只替换/删除匹配之前的内容. 可与after配合使用
encoding string 编码 utf-8-(默认)
mode 0777 or u+rwx or u=rw,g=r,o=r 目标文件或目录的权限
create boolean 与 state = current 一起使用 true-创建尚不存在的文件 false-(默认)
owner string 应该拥有文件系统对象的用户名(chown)
group string 应该拥有文件系统对象的组的名称(chown)
backup boolean 备份
#模糊匹配替换(最后一个匹配位置),找不到默认插入末尾
ansible test -m replace -a 'path=/etc/hosts replace="192.168.1.181    gp-datanode03" regexp="192\.168\.1\.183.*" search_string="192.168.1.181"'

- name: 替换183为QL
  replace:
    path: /opt/ansible/hostsssss
    regexp: "192\\.168\\.1\\.183.*"
    replace: QL

- name: 替换
  replace:
    path: /opt/ansible/hostsssss
    regexp: "QL"
    replace: "192.168.1.183    gp-master"

lineinfile 文本操作

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/lineinfile_module.html#ansible-builtin-lineinfile-module-manage-lines-in-text-files

命令 参数 说明
path path 要修改的文件
line boolean 要插入/替换到文件中的行
state absent present absent-删除(所有匹配) present-添加/替换(默认)
search_string string 要在文件的每一行中查找的字符串. 对于state=present,找到则替换该行(只替换找到的最后一行) 对于state=absent,如果找到则删除该行. 如果文本表达式不匹配,那么这一行将被添加到文件中(根据insertafterinsertbefore的设置). 不能与regexp一起使用
regexp string 要在文件的每一行中查找的(Python)正则表达式. 对于state=present,找到则替换(只替换找到的最后一行) 对于state=absent,如果找到则删除该行. 如果正则表达式不匹配,则该行将被添加到文件中(根据insertbeforeinsertafter的设置) https://docs.python.org/zh-cn/3/library/re.html
insertbefore string 如果正则表达式同时传递给regexp和insertbefore,则只有在没有找到与regexp匹配的情况下才使用insertbefore. 不能与insertafter一起使用
insertafter string 如果正则表达式同时传递给regexp和insertafter,则只有在没有找到与regexp匹配的情况下才使用insertafter. 不能与insertbefore一起使用
firstmatch boolean insertafterinsertbefore一起使用 true-第一个匹配 false-最后一个匹配
mode 0777 or u+rwx or u=rw,g=r,o=r 目标文件或目录的权限
create boolean 与 state = current 一起使用 true-创建尚不存在的文件 false-(默认)
owner string 应该拥有文件系统对象的用户名(chown)
group string 应该拥有文件系统对象的组的名称(chown)
backup boolean 备份
#模糊匹配替换(最后一个匹配位置),找不到默认插入末尾
ansible test -m lineinfile -a 'path=/etc/hosts line="192.168.1.181    gp-datanode03" state=present search_string="192.168.1.181"'

#正则匹配替换(最后一个匹配位置),找不到默认插入末尾
ansible test -m lineinfile -a 'path=/etc/hosts line="192.168.1.181    gp-datanode03" state=present regexp="192\.168\.1\.181.*"'

#模糊匹配删除(删除所有),找不到不操作
ansible test -m lineinfile -a 'path=/etc/hosts search_string="192.168.1.181" state=absent'

#模糊匹配(最后一个匹配位置),后置插入
ansible test -m lineinfile -a 'path=/etc/hosts line="192.168.1.184 QL" state=present insertafter="192.168.1.183"'

#模糊匹配(最后一个匹配位置),前置插入
ansible test -m lineinfile -a 'path=/etc/hosts line="192.168.1.184 QL" state=present insertbefore="192.168.1.183"'
- name: Ensure SELinux is set to enforcing mode
  ansible.builtin.lineinfile:
    path: /etc/selinux/config
    regexp: '^SELINUX='
    line: SELINUX=enforcing

- name: Make sure group wheel is not in the sudoers configuration
  ansible.builtin.lineinfile:
    path: /etc/sudoers
    state: absent
    regexp: '^%wheel'

- name: Replace a localhost entry with our own
  ansible.builtin.lineinfile:
    path: /etc/hosts
    regexp: '^127\.0\.0\.1'
    line: 127.0.0.1 localhost
    owner: root
    group: root
    mode: '0644'

- name: Replace a localhost entry searching for a literal string to avoid escaping
  ansible.builtin.lineinfile:
    path: /etc/hosts
    search_string: '127.0.0.1'
    line: 127.0.0.1 localhost
    owner: root
    group: root
    mode: '0644'

- name: Ensure the default Apache port is 8080
  ansible.builtin.lineinfile:
    path: /etc/httpd/conf/httpd.conf
    regexp: '^Listen '
    insertafter: '^#Listen '
    line: Listen 8080

- name: Ensure php extension matches new pattern
  ansible.builtin.lineinfile:
    path: /etc/httpd/conf/httpd.conf
    search_string: '<FilesMatch ".php[45]?$">'
    insertafter: '^\t<Location \/>\n'
    line: '        <FilesMatch ".php[34]?$">'

- name: Ensure we have our own comment added to /etc/services
  ansible.builtin.lineinfile:
    path: /etc/services
    regexp: '^# port for http'
    insertbefore: '^www.*80/tcp'
    line: '# port for http by default'

- name: Add a line to a file if the file does not exist, without passing regexp
  ansible.builtin.lineinfile:
    path: /tmp/testfile
    line: 192.168.1.99 foo.lab.net foo
    create: yes

# NOTE: Yaml requires escaping backslashes in double quotes but not in single quotes
- name: Ensure the JBoss memory settings are exactly as needed
  ansible.builtin.lineinfile:
    path: /opt/jboss-as/bin/standalone.conf
    regexp: '^(.*)Xms(\d+)m(.*)$'
    line: '\1Xms${xms}m\3'
    backrefs: yes

# NOTE: Fully quoted because of the ': ' on the line. See the Gotchas in the YAML docs.
- name: Validate the sudoers file before saving
  ansible.builtin.lineinfile:
    path: /etc/sudoers
    state: present
    regexp: '^%ADMIN ALL='
    line: '%ADMIN ALL=(ALL) NOPASSWD: ALL'
    validate: /usr/sbin/visudo -cf %s

# See https://docs.python.org/3/library/re.html for further details on syntax
- name: Use backrefs with alternative group syntax to avoid conflicts with variable values
  ansible.builtin.lineinfile:
    path: /tmp/config
    regexp: ^(host=).*
    line: \g<1>{{ hostname }}
    backrefs: yes

- name: sudoers添加gpadmin权限
  lineinfile:
    path: /etc/sudoers
    line: 'gpadmin  ALL=(ALL) ALL'
    insertafter: "^root.*?ALL="
    owner: root
    group: root
    mode: '0644'

PS

插入命令仅当文本内没有和line变量一样的行数据时执行

#ansible test -m lineinfile -a 'path=/etc/hosts line="192.168.1.184 QL" state=present insertafter="192.168.1.183"'

192.168.1.183    gp-master
192.168.1.184 QL
192.168.1.180    gp-datanode01
192.168.1.182    gp-datanode02
192.168.1.181    gp-datanode03

#执行  ansible test -m lineinfile -a 'path=/etc/hosts line="192.168.1.184 QL" state=present insertbefore="192.168.1.183"'  不发生更改,因为行数据  "192.168.1.184 QL"  已存在相同的

blockinfile 文本块操作

插入/更新/删除由标记行包围的文本块

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/blockinfile_module.html#ansible-builtin-blockinfile-module-insert-update-remove-a-text-block-surrounded-by-marker-lines

命令 参数 说明
path path 要修改的文件
block string 要插入标记行内的文本. 如果它是空字符串或缺失,块将被删除
state absent present absent-删除(所有匹配) present-添加/替换(默认)
marker string 标记块模板,{mark}将被替换为marker_beginmarker_end中的值 # {mark} ANSIBLE MANAGED BLOCK-(默认)
marker_begin string 这将被插入到{mark}块的开始标记处 BEGIN-(默认)
marker_end string 这将被插入到{mark}块的结束标记处 END-(默认)
insertbefore string 如果正则表达式同时传递给regexp和insertbefore,则只有在没有找到与regexp匹配的情况下才使用insertbefore. 不能与insertafter一起使用
insertafter string 如果正则表达式同时传递给regexp和insertafter,则只有在没有找到与regexp匹配的情况下才使用insertafter. 不能与insertbefore一起使用
mode 0777 or u+rwx or u=rw,g=r,o=r 目标文件或目录的权限
create boolean 与 state = current 一起使用 true-创建尚不存在的文件 false-(默认)
owner string 应该拥有文件系统对象的用户名(chown)
group string 应该拥有文件系统对象的组的名称(chown)
backup boolean 备份
- name: Insert/Update HTML surrounded by custom markers after <body> line
  ansible.builtin.blockinfile:
    path: /var/www/html/index.html
    marker: "<!-- {mark} ANSIBLE MANAGED BLOCK -->"
    insertafter: "<body>"
    block: |
      <h1>Welcome to {{ ansible_hostname }}</h1>
      <p>Last updated on {{ ansible_date_time.iso8601 }}</p>

- name: Insert/Update "Match User" configuration block in /etc/ssh/sshd_config
  ansible.builtin.blockinfile:
    path: /etc/ssh/sshd_config
    block: |
      Match User ansible-agent
      PasswordAuthentication no

- name: Search with a multiline search flags regex and if found insert after   (?m)=>多行匹配
  blockinfile:
    path: listener.ora
    block: "{{ listener_line | indent(width=8, first=True) }}"
    insertafter: '(?m)SID_LIST_LISTENER_DG =\n.*\(SID_LIST ='
    marker: "    <!-- {mark} ANSIBLE MANAGED BLOCK -->"

find 查找文件

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/find_module.html#ansible-builtin-find-module-return-a-list-of-files-based-on-specific-criteria

命令 参数 说明
paths list[path] 要搜索的目录的路径列表,所有路径必须是完全限定的
contains string 应该与文件内容匹配的正则表达式或模式( file_type=file 时生效)
file_type string any-任意 directory-目录 file-文件(默认) link-链接
patterns list[globs] 一个或多个(shell 或 regex)模式,其类型由use_regex选项控制 匹配过滤器
excludes list[globs] 同patterns 排除过滤器
use_regex boolean true-regexes(python) false-globs(shell)(默认)
size string 搜索 >=size 的文件 为负时查找<= 单位: 字节B(b) 千字节KB(k) 兆字节MB(m) 千兆字节GB(g) 太字节T(t)
age string 搜索 >=age 的文件 为负时查找<= 单位: 秒(s) 分(m) 小时(h) 日(d) 周(w)
age_stamp string 比较文件的时间属性 atime-访问时间 mtime-修改时间 ctime-状态改变时间
recurse boolean true-递归子目录 false-不递归(默认)
depth integer 递归深度(默认无限深度)
hidden boolean true-包括隐藏文件 false-忽略(默认)
#找出/opt/download/下 大于20mb的文件(递归子目录)
ansible test -m find -a "paths=/opt/download/ size=20m recurse=true"

#找出/opt/download/下 30天前创建的文件(递归子目录)
ansible test -m find -a "paths=/opt/download/ age=-30d recurse=true age_stamp=ctime"
- name: Recursively find /tmp files older than 2 days
  ansible.builtin.find:
    paths: /tmp
    age: 2d
    recurse: yes

- name: Recursively find /tmp files older than 4 weeks and equal or greater than 1 megabyte
  ansible.builtin.find:
    paths: /tmp
    age: 4w
    size: 1m
    recurse: yes

- name: Recursively find /var/tmp files with last access time greater than 3600 seconds
  ansible.builtin.find:
    paths: /var/tmp
    age: 3600
    age_stamp: atime
    recurse: yes

- name: Find /var/log files equal or greater than 10 megabytes ending with .old or .log.gz
  ansible.builtin.find:
    paths: /var/log
    patterns: '*.old,*.log.gz'
    size: 10m

# Note that YAML double quotes require escaping backslashes but yaml single quotes do not.
- name: Find /var/log files equal or greater than 10 megabytes ending with .old or .log.gz via regex
  ansible.builtin.find:
    paths: /var/log
    patterns: "^.*?\\.(?:old|log\\.gz)$"
    size: 10m
    use_regex: yes

- name: Find /var/log all directories, exclude nginx and mysql
  ansible.builtin.find:
    paths: /var/log
    recurse: no
    file_type: directory
    excludes: 'nginx,mysql'

# When using patterns that contain a comma, make sure they are formatted as lists to avoid splitting the pattern
- name: Use a single pattern that contains a comma formatted as a list
  ansible.builtin.find:
    paths: /var/log
    file_type: file
    use_regex: yes
    patterns: ['^_[0-9]{2,4}_.*.log$']

- name: Use multiple patterns that contain a comma formatted as a YAML list
  ansible.builtin.find:
    paths: /var/log
    file_type: file
    use_regex: yes
    patterns:
      - '^_[0-9]{2,4}_.*.log$'
      - '^[a-z]{1,5}_.*log$'

file 文件操作

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/file_module.html#ansible-builtin-file-module-manage-files-and-file-properties

命令 参数 说明
path path 文件路径
state "absent" "directory" "file" "hard" "link" "touch" file-更新文件权限/状态(需文件存在) hard-硬链接 link-软链接 absent-递归删除目录 directory-创建目录 touch-创建文件
mode 0777 / u+rwx or u=rw,g=r,o=r 生成的文件系统对象应该具有的权限
src path 要链接到的文件的路径
owner string 应该拥有文件系统对象的用户名(chown)
group string 应该拥有文件系统对象的组的名称(chown)
force boolean 强制在两种情况下创建符号链接(文件不存在|目标存在并且是一个文件(删除替换)) false-(默认)
#创建目录
ansible test -m file -a "path=/opt/download state=directory"

#创建文件
ansible test -m file -a "path=/opt/download/install.sh state=touch"

#更改权限
ansible test -m file -a "path=/opt/download/install.sh state=file mode=0777"

#创建链接(/结尾的会被认为是目录)
ansible test -m file -a "src=/opt/download path=/etc/download state=link"
- name: Change file ownership, group and permissions
  ansible.builtin.file:
    path: /etc/foo.conf
    owner: foo
    group: foo
    mode: '0644'

- name: Give insecure permissions to an existing file
  ansible.builtin.file:
    path: /work
    owner: root
    group: root
    mode: '1777'

copy 分发文件

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/copy_module.html#ansible-builtin-copy-module-copy-files-to-remote-locations

命令 参数 说明
src path 要复制到远程服务器的文件的本地路径
dest path 文件应复制到的远程绝对路径.如果dest是一个不存在的路径,并且dest以”/”结尾,或者src是一个目录,则创建dest
content string 当用于代替src时,直接将文件的内容设置为指定的值. 只有dest为文件时才有效
mode 0777 or u+rwx or u=rw,g=r,o=r 目标文件或目录的权限
backup yes or no 备份
owner string 应该拥有文件系统对象的用户名(chown)
group string 应该拥有文件系统对象的组的名称(chown)
#分发文件
ansible test -m copy -a 'src=/etc/hostname dest=/tmp/'

#分发目录(/opt/download -> /opt/download)
ansible test -m copy -a 'src=/opt/download dest=/opt/'
ansible test -m copy -a 'src=/opt/download/ dest=/opt/download/'

#分发并修改权限
ansible test -m copy -a 'src=/etc/hostname dest=/tmp/ mode=644 owner=root group=root'

#将文本写到远程文件
ansible test -m copy -a 'content="QL" dest=/tmp/ql.txt'

/opt/download  目录+目录内容
/opt/download/ 目录的内容
- name: Copy file with owner and permissions
  ansible.builtin.copy:
    src: /srv/myfiles/foo.conf
    dest: /etc/foo.conf
    owner: foo
    group: foo
    mode: '0644'

- name: Copy file with owner and permission, using symbolic representation
  ansible.builtin.copy:
    src: /srv/myfiles/foo.conf
    dest: /etc/foo.conf
    owner: foo
    group: foo
    mode: u=rw,g=r,o=r

fetch 从远程节点获取文件

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/fetch_module.html#ansible-builtin-fetch-module-fetch-files-from-remote-nodes

命令 参数 说明
src path 要获取的远程系统上的文件(不能为目录)
dest path 保存文件的目录(保存在 dest/ip/src )
flat boolean true-不保留原始目录结构复制 false-(默认)
fail_on_missing boolean true-远程文件由于任何原因无法读取,任务将失败(默认)
validate_checksum boolean true-在获取文件后,验证源和目标校验和是否匹配(默认)
ansible all -m fetch -a 'src=/etc/hostname dest=/tmp/ansible'
- name: Store file into /tmp/fetched/host.example.com/tmp/somefile
  ansible.builtin.fetch:
    src: /tmp/somefile
    dest: /tmp/fetched

- name: Specifying a path directly
  ansible.builtin.fetch:
    src: /tmp/somefile
    dest: /tmp/prefix-{{ inventory_hostname }}
    flat: yes

- name: Specifying a destination path
  ansible.builtin.fetch:
    src: /tmp/uniquefile
    dest: /tmp/special/
    flat: yes

- name: Storing in a path relative to the playbook
  ansible.builtin.fetch:
    src: /tmp/uniquefile
    dest: special/prefix-{{ inventory_hostname }}
    flat: yes

slurp 从远程节点获取文件的base64编码值

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/slurp_module.html#ansible-builtin-slurp-module-slurps-a-file-from-remote-nodes

命令 参数 说明
src path 要获取的远程系统上的文件(不能为目录)
ansible test -m slurp -a 'src=/etc/hostname'
#192.168.1.180 | SUCCESS => {
#    "changed": false,
#    "content": "Z3AtZGF0YW5vZGUwMQo=",
#    "encoding": "base64",
#    "source": "/etc/hostname"
#}
- name: Find out what the remote machine's hostname are
  ansible.builtin.slurp:
    src: /etc/hostname
  register: hostname

- name: Print returned information
  ansible.builtin.debug:
    msg: "{{ hostname['content'] | b64decode }}"

get_url 文件下载

类似wget

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/get_url_module.html#ansible-builtin-get-url-module-downloads-files-from-http-https-or-ftp-to-node

命令 参数 说明
url string 下载网址
dest path 下载文件保存的绝对路径
force boolean true-忽略并覆盖文件 false-不存在时下载(默认)
mode 0777 or u+rwx or u=rw,g=r,o=r 目标文件或目录的权限
owner string 应该拥有文件系统对象的用户名(chown)
group string 应该拥有文件系统对象的组的名称(chown)
timeout integer URL请求的超时时间(秒)
validate_certs boolean 验证SSL证书(默认)
#下载  切记路径要以/结尾,或使用文件路径
ansible test -m get_url -a 'url=https://download.jetbrains.com/idea/ideaIU-2021.2.2.tar.gz dest=/opt/download/ force=true'
ansible test -m get_url -a 'url=https://download.jetbrains.com/idea/ideaIU-2021.2.2.tar.gz dest=/opt/download/ideaIU-2021.2.2.tar.gz  force=true'
- name: Download file from a file path
  ansible.builtin.get_url:
    url: file:///tmp/afile.txt
    dest: /tmp/afilecopy.txt

- name: Download foo.conf
  ansible.builtin.get_url:
    url: http://example.com/path/file.conf
    dest: /etc/foo.conf
    mode: '0440'

stat 检索文件或文件系统状态

文件信息收集

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/stat_module.html#ansible-builtin-stat-module-retrieve-file-or-file-system-status

命令 参数 说明
path path 文件/对象的完整路径
follow boolean 是否遵循符号链接 false-不遵循(默认)
ansible test -m stat -a 'path=/usr/lib64/libc.so.6'
#"stat": {
#   "atime": 1678795947.01495,
#   "ctime": 1678363941.14613,
#   "exists": true,
#   "gr_name": "root",#Group name of owner
#   "pw_name": "root",#User name of owner
#   "lnk_source": "/usr/lib64/libc-2.17.so",
#   "lnk_target": "libc-2.17.so",
#   "mode": "0777",
#   "mtime": 1678363941.14613,
#   "nlink": 1,
#   "path": "/usr/lib64/libc.so.6",
#   "pw_name": "root",
#   "size": 12,
#   "version": null,
#   "isdir": false,
#   "islnk": true
#}
- name: Get stats of a file
  ansible.builtin.stat:
    path: /etc/foo.conf
  register: st

- name: Get stats of the FS object
  ansible.builtin.stat:
    path: /path/to/something
  register: p
- name: Print a debug message
  ansible.builtin.debug:
    msg: "Path exists and is a directory"
  when: p.stat.isdir is defined and p.stat.isdir

返回值

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/stat_module.html#return-values

tempfile 创建临时文件和目录

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/tempfile_module.html#ansible-builtin-tempfile-module-creates-temporary-files-and-directories

命令 参数 说明
path path 应该创建临时文件或目录的位置 如果未指定 path,则将使用默认的系统临时目录
prefix string 模块创建的文件/目录名后缀 "ansible."-(默认)
suffix string 模块创建的文件/目录名后缀 ""-(默认)
state directory file 是否创建文件或目录 "file"-(默认)
- name: Create temporary build directory
  ansible.builtin.tempfile:
    state: directory
    suffix: build

- name: Create temporary file
  ansible.builtin.tempfile:
    state: file
    suffix: temp
  register: tempfile_1

#"tempfile_1": {
#     "changed": true,
#     "failed": false,
#     "gid": 0,
#     "group": "root",
#     "mode": "0600",
#     "owner": "root",
#     "path": "/tmp/ansible.2OHSfAtemp",
#     "size": 0,
#     "state": "file",
#     "uid": 0
#}

- name: Use the registered var and the file module to remove the temporary file
  ansible.builtin.file:
    path: "{{ tempfile_1.path }}"
    state: absent
  when: tempfile_1.path is defined

(posix) patch 使用 GNU 补丁工具应用补丁文件

https://docs.ansible.com/ansible/latest/collections/ansible/posix/patch_module.html#ansible-posix-patch-module-apply-patch-files-using-the-gnu-patch-tool

命令 参数 说明
src path 补丁文件路径
dest path 要修补的远程计算机上文件的路径
basedir path 将在其中应用补丁程序文件的基目录的路径(批量补丁目录下的文件). 如果指定了dest选项,则可以省略
state absent present 应用/还原补丁 present-(默认)
remote_src boolean true-使用远程机器上的src文件 false-使用主控机src文件(默认)
ignore_whitespace boolean true-忽略补丁和输入之间的空白更改 false-(默认)
binary boolean true-禁用转换CRLF行结束到LF(src和dest的行尾必须匹配) false-替换POSIX上src文件中的CRLF(默认)
strip integer 包含前导斜杠的最小前缀的数字 0-(默认)
backup boolean 传递--backup --version-control=numbered到patch命令
- name: Apply patch to one file
  ansible.posix.patch:
    src: /tmp/index.html.patch
    dest: /var/www/index.html

- name: Apply patch to multiple files under basedir
  ansible.posix.patch:
    src: /tmp/customize.patch
    basedir: /var/www
    strip: 1

- name: Revert patch to one file
  ansible.posix.patch:
    src: /tmp/index.html.patch
    dest: /var/www/index.html
    state: absent

3. 服务管理

systemd 系统服务管理

类似于systemctl,一般应用于Centos 7/8

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/systemd_service_module.html#ansible-builtin-systemd-service-module-manage-systemd-units

命令 参数 说明
name string 服务名
enabled true or false yes or no 是否开机自启动
state "reloaded" "restarted" "started" "stopped" restarted-关闭再开启 reloaded-重载配置
daemon_reload true or false yes or no 重启加载systemctl配置 systemctl daemon-reload
#开机自启定时任务(crond)
ansible test -m systemd -a 'name=crond enabled=yes'

#重启服务
ansible test -m systemd -a 'name=crond state=restarted'
- name: Make sure a service unit is running
  ansible.builtin.systemd:
    state: started
    name: httpd

- name: Stop service cron on debian, if running
  ansible.builtin.systemd:
    name: cron
    state: stopped

service 系统服务管理

比systemd更细致,一般应用于Centos 5/6, 7/8也可以用

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/service_module.html#ansible-builtin-service-module-manage-services

命令 参数 说明
name string 服务名
enabled false or true yes or no 是否开机自启动
state "reloaded" "restarted" "started" "stopped" restarted-关闭再开启 reloaded-重载配置
sleep 重启操作间的延时
pattern string 如果服务不响应status命令,则将查找的子字符串命名为ps命令的输出中可以找到的子字符串,作为状态结果的替身. 如果找到该字符串,则假定服务已启动
arguments/args string 命令行上提供的其他参数
#重启服务
ansible test -m systemd -a 'name=network state=restarted args=eth0'
- name: Start service httpd, if not started
  ansible.builtin.service:
    name: httpd
    state: started

- name: Stop service httpd, if started
  ansible.builtin.service:
    name: httpd
    state: stopped

4. 软件包管理

package 自动识别操作系统的通用包管理器

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/package_module.html#ansible-builtin-package-module-generic-os-package-manager

命令 参数 说明
name string 软件包名
state string present-安装 absent-卸载 latest-最新
use string 手动指定包管理器模块(yum、apt等)
ansible test -m package -a 'name=python3 state=present'

ansible test -m package -a 'name=python3 state=absent'
- name: Install ntpdate
  ansible.builtin.package:
    name: ntpdate
    state: present

# This uses a variable as this changes per distribution.
- name: Remove the apache package
  ansible.builtin.package:
    name: "{{ apache }}"
    state: absent

- name: Install the latest version of Apache and MariaDB
  ansible.builtin.package:
    name:
      - httpd
      - mariadb-server
    state: latest

yum_repository 配置yum源

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/yum_repository_module.html#ansible-builtin-yum-repository-module-add-or-remove-yum-repositories

命令 参数 说明
name string 源名
baseurl string 源baseurl地址 可以是多个url的列表
description string 源注释说明
enabled boolean 是否启用
file string repo的文件名 不带.repo扩展名.默认为name的值
sslverify boolean SSL证书验证 默认true
gpgcheck boolean 对包执行GPG签名检查
#阿里 epel 镜像
ansible test -m yum_repository -a 'name="aliyun_epel" description="Extra Packages for Enterprise Linux 7 - $basearch" baseurl="http://mirrors.aliyun.com/epel/7/$basearch" enabled=true gpgcheck=false'
- name: Add repository
  ansible.builtin.yum_repository:
    name: epel
    description: EPEL YUM repo
    baseurl: https://download.fedoraproject.org/pub/epel/$releasever/$basearch/

- name: Add multiple repositories into the same file (1/2)
  ansible.builtin.yum_repository:
    name: epel
    description: EPEL YUM repo
    file: external_repos
    baseurl: https://download.fedoraproject.org/pub/epel/$releasever/$basearch/
    gpgcheck: no

- name: Add multiple repositories into the same file (2/2)
  ansible.builtin.yum_repository:
    name: rpmforge
    description: RPMforge YUM repo
    file: external_repos
    baseurl: http://apt.sw.be/redhat/el7/en/$basearch/rpmforge
    mirrorlist: http://mirrorlist.repoforge.org/el7/mirrors-rpmforge
    enabled: no

yum yum包管理器

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/yum_module.html#ansible-builtin-yum-module-manages-packages-with-the-yum-package-manager

命令 参数 说明
name list name>=1.0 软件包名(逗号分割) *-运行yum -y update
state "absent" "installed" "latest" "present" "removed" present/installed 只会确 保安装所需的包. latest 将更新该包. removed/absent 将删除指定的包.
description string 源注释说明
enabled boolean 是否启用
file string repo的文件名 不带.repo扩展名.默认为name的值
sslverify boolean SSL证书验证 默认true
gpgcheck boolean 对包执行GPG签名检查
#安装最新
ansible test -m yum_repository -a 'name=ansible state=latest'

#安装
ansible test -m yum_repository -a 'name=ansible state=latest'
- name: Install one specific version of Apache
  ansible.builtin.yum:
    name: httpd-2.2.29-1.4.amzn1
    state: present

- name: Upgrade all packages
  ansible.builtin.yum:
    name: '*'
    state: latest

dnf dnf包管理器

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/dnf_module.html#ansible-builtin-dnf-module-manages-packages-with-the-dnf-package-manager

命令 参数 说明
name list 软件包名(逗号分割)
state "absent" "installed" "latest" "present" "removed" present/installed 只会确 保安装所需的包. latest 将更新该包. removed/absent 将删除指定的包.
autoremove boolean true-从系统中删除所有(不被需要的)“叶子”依赖包
allowerasing boolean true-允许删除已安装的包以解决依赖关系 false-默认
file string repo的文件名 不带.repo扩展名.默认为name的值
sslverify boolean SSL证书验证 默认true
#安装最新
ansible test -m yum_repository -a 'name=ansible state=latest'

#安装
ansible test -m yum_repository -a 'name=ansible state=latest'
- name: Install Apache >= 2.4
  ansible.builtin.dnf:
    name: httpd >= 2.4
    state: present

- name: Upgrade all packages
  ansible.builtin.dnf:
    name: "*"
    state: latest

pip python包管理器

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/pip_module.html#ansible-builtin-pip-module-manages-python-library-dependencies

命令 参数 说明
name list[string] 要安装的Python库名称或远程包的url
state present absent forcereinstall latest present-安装 absent-卸载 forcereinstall-强制重新安装 latest-最新版
version string name 参数中指定的 Python 库的安装版本号
chdir path 执行命令前请进入该目录(cd path)
extra_args string 额外的参数传递给pip
requirements string pip需求文件的路径,它应该是远程系统的本地路径
executable path pip可执行文件的显式可执行文件或路径名
- name: Install bottle python package with version specifiers
  ansible.builtin.pip:
    name: bottle>0.10,<0.20,!=0.11

- name: Install specified python requirements and custom Index URL
  ansible.builtin.pip:
    requirements: /my_app/requirements.txt
    extra_args: -i https://example.com/pypi/simple

- name: Install specified python requirements offline from a local directory with downloaded packages
  ansible.builtin.pip:
    requirements: /my_app/requirements.txt
    extra_args: "--no-index --find-links=file:///my_downloaded_packages_dir"

- name: Install bottle for Python 3.3 specifically, using the 'pip3.3' executable
  ansible.builtin.pip:
    name: bottle
    executable: pip3.3

- name: Install bottle, forcing reinstallation if it's already installed
  ansible.builtin.pip:
    name: bottle
    state: forcereinstall

5. 系统管理

(posix) mount 挂载远程文件系统

https://docs.ansible.com/ansible/latest/collections/ansible/posix/mount_module.html?q=mount&check_keywords=yes&area=default#ansible-posix-mount-module-control-active-and-configured-mount-points

命令 参数 说明
src path 要挂载的设备链接
path path 挂载点的路径
fstype string 文件系统类型(nfs)
state mounted unmounted remounted present absent absent_from_fstab ephemeral mounted-挂载 unmounted-卸载,不修改fstab remounted-重新挂载 present-仅配置fstab,不触发或需要挂载 absent-从fstab中删除,卸载设备并删除挂载点 absent_from_fstab-从fstab中删除,不卸载或删除挂载点 ephemeral-仅挂载的设备,不更改fstab.如果已经挂载,将触发重新挂载
backup boolean 创建一个包含时间戳信息的备份文件
#显示目标设备可挂载区
ansible test -a 'showmount -e 192.168.1.183'

#查看fstab
ansible test -a 'grep wwwroot /etc/fstab'

#挂载  183的/www/wwwroot  ->  /opt/smb
ansible test -m mount -a 'src=192.168.1.183:/www/wwwroot  path=/opt/smb/ fstype=nfs state=mounted'

#卸载
ansible test -m mount -a 'src=192.168.1.183:/www/wwwroot  path=/opt/smb/ fstype=nfs state=unmounted'
# Before 2.3, option 'name' was used instead of 'path'
- name: Mount DVD read-only
  ansible.posix.mount:
    path: /mnt/dvd
    src: /dev/sr0
    fstype: iso9660
    opts: ro,noauto
    state: present

- name: Mount up device by label
  ansible.posix.mount:
    path: /srv/disk
    src: LABEL=SOME_LABEL
    fstype: ext4
    state: present

- name: Mount up device by UUID
  ansible.posix.mount:
    path: /home
    src: UUID=b3e48f45-f933-4c8e-a700-22a159ec9077
    fstype: xfs
    opts: noatime
    state: present

- name: Unmount a mounted volume
  ansible.posix.mount:
    path: /tmp/mnt-pnt
    state: unmounted

- name: Remount a mounted volume
  ansible.posix.mount:
    path: /tmp/mnt-pnt
    state: remounted

# The following will not save changes to fstab, and only be temporary until
# a reboot, or until calling "state: unmounted" followed by "state: mounted"
# on the same "path"
- name: Remount a mounted volume and append exec to the existing options
  ansible.posix.mount:
    path: /tmp
    state: remounted
    opts: exec

- name: Mount and bind a volume
  ansible.posix.mount:
    path: /system/new_volume/boot
    src: /boot
    opts: bind
    state: mounted
    fstype: none

- name: Mount an NFS volume
  ansible.posix.mount:
    src: 192.168.1.100:/nfs/ssd/shared_data
    path: /mnt/shared_data
    opts: rw,sync,hard
    state: mounted
    fstype: nfs

- name: Mount NFS volumes with noauto according to boot option
  ansible.posix.mount:
    src: 192.168.1.100:/nfs/ssd/shared_data
    path: /mnt/shared_data
    opts: rw,sync,hard
    boot: false
    state: mounted
    fstype: nfs

- name: Mount ephemeral SMB volume
  ansible.posix.mount:
    src: //192.168.1.200/share
    path: /mnt/smb_share
    opts: "rw,vers=3,file_mode=0600,dir_mode=0700,dom={{ ad_domain }},username={{ ad_username }},password={{ ad_password }}"
    fstype: cifs
    state: ephemeral

cron 定时任务模块

可指定

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/cron_module.html#ansible-builtin-cron-module-manage-cron-d-and-crontab-entries

命令 参数 说明
name string 定时任务名
minute string * */2
hour string
day string
month string
weekday string
job string 要执行的命令
state absent present absent-删除 present-添加(默认)
disabled boolean 该作业是否应该在crontab中禁用(注释). 仅当state=present时有效
env boolean true-则设置环境变量(Name和Job分别为环境变量的名称和值)
#查看设备的cron执行列表
ansible test -a 'crontab -l'
#手动配置列表
crontab -e

#每2分钟更新一次ntp时间
ansible test -m cron -a 'name="sync time"  minute="*/2" job="/sbin/ntpdate ntp1.aliyun.com &>/dev/null" state=present'

#删除指定cron
ansible test -m cron -a 'name="sync time" state=absent'

#注释指定cron
ansible test -m cron -a 'name="sync time" state=absent disabled=true'
- name: Creates an entry like "@reboot /some/job.sh"
  ansible.builtin.cron:
    name: "a job for reboot"
    special_time: reboot
    job: "/some/job.sh"

- name: Creates an entry like "PATH=/opt/bin" on top of crontab
  ansible.builtin.cron:
    name: PATH
    env: yes
    job: /opt/bin

hostname hostname管理

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/hostname_module.html#ansible-builtin-hostname-module-manage-hostname

命令 参数 说明
name string 定时任务名
use alpine debian freebsd generic macos macosx darwin openbsd openrc redhat sles solaris systemd 使用哪种策略来更新主机名. 为空-自动检测 systemd-Centos7
ansible test -m hostname -a 'name="QL" use=systemd'
- name: Set a hostname
  ansible.builtin.hostname:
    name: web01

- name: Set a hostname specifying strategy
  ansible.builtin.hostname:
    name: web01
    use: systemd

known_hosts 添加或移除known_hosts

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/known_hosts_module.html#ansible-builtin-known-hosts-module-add-or-remove-a-host-from-the-known-hosts-file

命令 参数 说明
name string 要添加或删除的主机(必须与key中指定的主机匹配). 它将被转换为小写,以便ssh-keygen可以找到它
key <hostname[,IP]> ssh-rsa <pubkey> 组的可选GID
state absent present absent-删除 present-添加(默认)
path path 要编辑的known_hosts文件
- name: Tell the host about our servers it might want to ssh to
  ansible.builtin.known_hosts:
    path: /etc/ssh/ssh_known_hosts
    name: foo.com.invalid
    key: "{{ lookup('ansible.builtin.file', 'pubkeys/foo.com.invalid') }}"

- name: Another way to call known_hosts
  ansible.builtin.known_hosts:
    name: host1.example.com   # or 10.9.8.77
    key: host1.example.com,10.9.8.77 ssh-rsa ASDeararAIUHI324324  # some key gibberish
    path: /etc/ssh/ssh_known_hosts
    state: present

- name: Add host with custom SSH port
  ansible.builtin.known_hosts:
    name: '[host1.example.com]:2222'
    key: '[host1.example.com]:2222 ssh-rsa ASDeararAIUHI324324' # some key gibberish
    path: /etc/ssh/ssh_known_hosts
    state: present

- name: Ensure server is present in known_hosts file
  ansible.builtin.known_hosts:
    name:"QL"
    state: present
    key:"{{ lookup('pipe', 'ssh-keyscan QL') }}"
    hash_host: true

reboot 重启并等待

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/debug_module.html#ansible-builtin-debug-module-print-statements-during-execution

命令 参数 说明
msg string 在重新启动之前显示给用户的消息
test_command string 命令在重新启动的主机上运行,并期望从中获得成功,以确定计算机已准备好执行进一步的任务
post_reboot_delay integer 重新启动命令成功后,在尝试验证系统成功重新启动之前需要等待几秒钟 0-(默认)
pre_reboot_delay integer 重启前需要等待几秒. 在Linux、macOS和OpenBSD上,这个时间转换为分钟并四舍五入. 如果小于60,它将被设置为0. 在Solaris和FreeBSD上,这将是几秒钟 0-(默认)
reboot_timeout integer 等待机器重新启动并响应测试命令的最大秒数 600-(默认)
connect_timeout integer 在再次尝试之前等待成功连接到托管主机的最大秒数
ansible test -m reboot

ansible test -m reboot -a 'reboot_timeout=3600 test_command=whoami'
- name: Unconditionally reboot the machine with all defaults
  ansible.builtin.reboot:

- name: Reboot a slow machine that might have lots of updates to apply
  ansible.builtin.reboot:
    reboot_timeout: 3600

- name: Reboot a machine with shutdown command in unusual place
  ansible.builtin.reboot:
    search_paths:
     - '/lib/molly-guard'

- name: Reboot machine using a custom reboot command
  ansible.builtin.reboot:
    reboot_command: launchctl reboot userspace
    boot_time_command: uptime | cut -d ' ' -f 5

(posix) authorized_key 添加或删除 SSH 授权密钥

https://docs.ansible.com/ansible/latest/collections/ansible/posix/authorized_key_module.html#ansible-posix-authorized-key-module-adds-or-removes-an-ssh-authorized-key

命令 参数 说明
key string SSH 公钥(字符串或URL)
user string 远程主机上的用户名
path ~/.ssh/authorized_keys-(默认) authorized_keys文件的替代路径
state absent present-(默认) 给定的键(带有给定的key_options)是否应该在文件中
key_options string authorized_keys文件中密钥前的ssh密钥选项字符串
follow boolean true-遵循路径符号链接 false-(默认)
exclusive boolean true-从authorized_keys文件中删除所有其他非指定的密钥 false-(默认)
manage_dir boolean 是否应该管理授权密钥文件的目录,使用自定义目录时请设置此项为false
validate_certs boolean true-不验证SSL证书(默认)
- name: Set authorized key taken from file
  ansible.posix.authorized_key:
    user: charlie
    state: present
    key: "{{ lookup('file', '/home/charlie/.ssh/id_rsa.pub') }}"

- name: Set authorized keys taken from url
  ansible.posix.authorized_key:
    user: charlie
    state: present
    key: https://github.com/charlie.keys

- name: Set authorized keys taken from url using lookup
  ansible.posix.authorized_key:
    user: charlie
    state: present
    key: "{{ lookup('url', 'https://github.com/charlie.keys', split_lines=False) }}"

- name: Set authorized key in alternate location
  ansible.posix.authorized_key:
    user: charlie
    state: present
    key: "{{ lookup('file', '/home/charlie/.ssh/id_rsa.pub') }}"
    path: /etc/ssh/authorized_keys/charlie
    manage_dir: false

- name: Set up multiple authorized keys
  ansible.posix.authorized_key:
    user: deploy
    state: present
    key: '{{ item }}'
  with_file:
    - public_keys/doe-jane
    - public_keys/doe-john

- name: Set authorized key defining key options
  ansible.posix.authorized_key:
    user: charlie
    state: present
    key: "{{ lookup('file', '/home/charlie/.ssh/id_rsa.pub') }}"
    key_options: 'no-port-forwarding,from="10.0.1.1"'

- name: Set authorized key without validating the TLS/SSL certificates
  ansible.posix.authorized_key:
    user: charlie
    state: present
    key: https://github.com/user.keys
    validate_certs: false

- name: Set authorized key, removing all the authorized keys already set
  ansible.posix.authorized_key:
    user: root
    key: "{{ lookup('file', 'public_keys/doe-jane') }}"
    state: present
    exclusive: true

- name: Set authorized key for user ubuntu copying it from current user
  ansible.posix.authorized_key:
    user: ubuntu
    state: present
    key: "{{ lookup('file', lookup('env','HOME') + '/.ssh/id_rsa.pub') }}"

(posix) firewalld 使用防火墙管理任意端口/服务

https://docs.ansible.com/ansible/latest/collections/ansible/posix/firewalld_module.html#ansible-posix-firewalld-module-manage-arbitrary-ports-services-with-firewalld

命令 参数 说明
port string 要在防火墙中添加/删除的端口或端口范围的名称
service string 要在防火墙中添加/删除的服务的名称
source string 192.0.2.0/24 要从防火墙中添加/删除的源/网络
masquerade string 要在防火墙内启用/禁用到/来自区域的伪装设置
interface string eth2 要在防火墙中的区域中添加/删除的接口
icmp_block string echo-request 要在防火墙中的区域中添加/删除的 ICMP 块
icmp_block_inversion boolean 启用/禁用防火墙中某个区域的 ICMP 块的反转功能
zone block dmz drop external home internal public trusted work 防火墙区域
target default ACCEPT DROP %%REJECT%% 防火墙区域目标. 如果state被设置为absent,值将变为default
state absent present disabled enabled 启用或禁用设置
permanent boolean 这个配置是在正在运行的防火墙配置中还是在重新启动时保持
immediate boolean 如果将此配置设置为永久配置,则应立即应用该配置
offline boolean 防火墙离线时是否运行此模块
rich_rule string 在防火墙中添加/删除的富规则 rules
- name: permit traffic in default zone for https service
  ansible.posix.firewalld:
    service: https
    permanent: true
    state: enabled

- name: do not permit traffic in default zone on port 8081/tcp
  ansible.posix.firewalld:
    port: 8081/tcp
    permanent: true
    state: disabled

- ansible.posix.firewalld:
    port: 161-162/udp
    permanent: true
    state: enabled

- ansible.posix.firewalld:
    zone: dmz
    service: http
    permanent: true
    state: enabled

- ansible.posix.firewalld:
    rich_rule: rule service name="ftp" audit limit value="1/m" accept
    permanent: true
    state: enabled

- ansible.posix.firewalld:
    source: 192.0.2.0/24
    zone: internal
    state: enabled

- ansible.posix.firewalld:
    zone: trusted
    interface: eth2
    permanent: true
    state: enabled

- ansible.posix.firewalld:
    masquerade: true
    state: enabled
    permanent: true
    zone: dmz

- ansible.posix.firewalld:
    zone: custom
    state: present
    permanent: true

- ansible.posix.firewalld:
    zone: drop
    state: enabled
    permanent: true
    icmp_block_inversion: true

- ansible.posix.firewalld:
    zone: drop
    state: enabled
    permanent: true
    icmp_block: echo-request

- ansible.posix.firewalld:
    zone: internal
    state: present
    permanent: true
    target: ACCEPT

- name: Redirect port 443 to 8443 with Rich Rule
  ansible.posix.firewalld:
    rich_rule: rule family=ipv4 forward-port port=443 protocol=tcp to-port=8443
    zone: public
    permanent: true
    immediate: true
    state: enabled

(posix) seboolean 切换SELinux布尔值

https://docs.ansible.com/ansible/latest/collections/ansible/posix/seboolean_module.html#ansible-posix-seboolean-module-toggles-selinux-booleans

命令 参数 说明
name string 要配置的布尔值的名
state boolean 期望的布尔值
persistent boolean true-设置在重新启动后仍然存在 false-(默认)
ignore_selinux_state boolean 对于无法获得真正 SELinux 状态的场景(chroted 环境)非常有用
- name: Set httpd_can_network_connect flag on and keep it persistent across reboots
  ansible.posix.seboolean:
    name: httpd_can_network_connect
    state: true
    persistent: true

(posix) selinux 更改 SELinux 的策略和状态

https://docs.ansible.com/ansible/latest/collections/ansible/posix/selinux_module.html#ansible-posix-selinux-module-change-policy-and-state-of-selinux

命令 参数 说明
state disabled enforcing permissive SELinux模式 Permissve Mode(宽容模式) Enfocing mode(强制模式) disabled(禁用)
configfile string /etc/selinux/config SELinux 配置文件的路径
policy string SELinux 策略的名称
update_kernel_param boolean true-在禁用/启用 SELinux 时会更新内核引导参数 false-(默认)
- name: Enable SELinux
  ansible.posix.selinux:
    policy: targeted
    state: enforcing

- name: Put SELinux in permissive mode, logging actions that would be blocked.
  ansible.posix.selinux:
    policy: targeted
    state: permissive

- name: Disable SELinux
  ansible.posix.selinux:
    state: disabled

(posix) sysctl 管理 sysctl.conf 中的条目

https://docs.ansible.com/ansible/latest/collections/ansible/posix/sysctl_module.html#ansible-posix-sysctl-module-manage-entries-in-sysctl-conf

命令 参数 说明
name string 指定 sysctl 变量的点分隔路径,变量的Key
value string sysctl键的期望值
state present absent 该条目在sysctl文件中是否存在 present-(默认)
reload boolean true-如果sysctl_file被更新,则执行/sbin/sysctl -p(默认)
sysctl_set boolean true-使用sysctl命令验证值,并在必要时使用-w false-(默认)
ignoreerrors boolean true-忽略关于未知键的错误 false-(默认)
sysctl_file string /etc/sysctl.conf 自定义sysctl.conf的绝对路径
# Set vm.swappiness to 5 in /etc/sysctl.conf
- ansible.posix.sysctl:
    name: vm.swappiness
    value: '5'
    state: present

# Remove kernel.panic entry from /etc/sysctl.conf
- ansible.posix.sysctl:
    name: kernel.panic
    state: absent
    sysctl_file: /etc/sysctl.conf

# Set kernel.panic to 3 in /tmp/test_sysctl.conf
- ansible.posix.sysctl:
    name: kernel.panic
    value: '3'
    sysctl_file: /tmp/test_sysctl.conf
    reload: false

# Set ip forwarding on in /proc and verify token value with the sysctl command
- ansible.posix.sysctl:
    name: net.ipv4.ip_forward
    value: '1'
    sysctl_set: true

# Set ip forwarding on in /proc and in the sysctl file and reload if necessary
- ansible.posix.sysctl:
    name: net.ipv4.ip_forward
    value: '1'
    sysctl_set: true
    state: present
    reload: true

6. 用户管理

group 用户组管理

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/group_module.html#ansible-builtin-group-module-add-or-remove-groups

命令 参数 说明
name string 组的名称
gid integer 组的可选GID
state absent present absent-删除 present-添加(默认)
system boolean true-创建的组为系统组 false-默认
#添加gpadmin组
ansible test -m group -a 'name=gpadmin state=present gid=520'
- name: Ensure group "somegroup" exists
  ansible.builtin.group:
    name: somegroup
    state: present

- name: Ensure group "docker" exists with correct gid
  ansible.builtin.group:
    name: docker
    state: present
    gid: 1750

user 用户管理

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/user_module.html#ansible-builtin-user-module-manage-user-accounts

命令 参数 说明
uid integer 用户的UID
name string 要 创建/删除/修改 的用户名
group string 用户的主组
groups list 用户将被添加到的组列表(逗号分隔). 当设置为”时,用户将从除主组外的所有组中删除
home path 设置用户的主目录
password string 加密哈希(Linux)或明文密码(macOS)
state absent present absent-删除 present-添加(默认)
force boolean true-强制删除受支持平台上的用户和相关目录(userdel –force),仅在state=absent时删除生效 false-默认
generate_ssh_key boolean 是否为用户生成SSH密钥, force=true时会覆盖现有的SSH密钥
append boolean 追加模式 true-添加到groups中指定的组中 false-(默认)只添加到groups中指定的组,并从所有其他组中删除
shell /bin/bash 指定sh运行程序
role string 设置用户的角色(逗号分隔). 删除所有角色 role=”
system boolean true-使用户成为系统帐户,仅在state=present时生效 false-默认
create_home boolean 在帐户创建时或在主目录不存在时,将为用户创建一个主目录 true-默认
remove boolean true-删除与用户关联的目录(userdel),仅在state=absent时生效 false-默认
#添加gpadmin用户
ansible test -m user -a 'name=gpadmin uid=520 state=present home=/home/gpadmin group=gpadmin'

#查询用户
ansible test -a 'id gpadmin'

ansible test -m user -a 'password_hash("123456")'
- name: Add the user 'johnd' with a specific uid and a primary group of 'admin'
  ansible.builtin.user:
    name: johnd
    comment: John Doe
    uid: 1040
    group: admin

- name: Add the user 'james' with a bash shell, appending the group 'admins' and 'developers' to the user's groups
  ansible.builtin.user:
    name: james
    shell: /bin/bash
    groups: admins,developers
    append: yes

7. 加/解压

unarchive 解压

可处理 .gz .bz2 .xz .zst .tar .zip

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/unarchive_module.html#ansible-builtin-unarchive-module-unpacks-an-archive-after-optionally-copying-it-from-the-local-machine

命令 参数 说明
src list[path] 要解压缩的现有存档文件的路径,可以为网址
dest path 解压缩到的远程绝对路径,指定的路径必须存在
exclude list[path] 解压排除的目录和文件条目, 与include互斥 (逗号分割)
include list[path] 待解压的目录和文件条目的列表. 如果include不为空,则只提取列出的文件. 与exclude互斥 (逗号分割)
remote_src boolean true-使用目标服务器的存档文件 false-将本地存档文件复制到目标服务器的本地路径(默认)
keep_newer boolean 不要替换比存档中的文件更新的现有文件 false-默认
list_files boolean 如果设置为True,则返回tarball中包含的文件列表
mode 0777 or u+rwx or u=rw,g=r,o=r 目标归档文件的权限
owner string 应该拥有文件系统对象的用户名(chown)
group string 应该拥有文件系统对象的组的名称(chown)
validate_certs boolean 证书验证
#项目文件压缩,排除 /target 和 /src/test
ansible test -m unarchive -a 'src=/opt/pt.zip dest=/opt/download/pt2'
- name: Extract foo.tgz into /var/lib/foo
  ansible.builtin.unarchive:
    src: foo.tgz
    dest: /var/lib/foo

- name: Unarchive a file that is already on the remote machine
  ansible.builtin.unarchive:
    src: /tmp/foo.zip
    dest: /usr/local/bin
    remote_src: yes

archive 压缩

支持格式 bz2 gz tar xz zip

https://docs.ansible.com/ansible/latest/collections/community/general/archive_module.html#community-general-archive-module-creates-a-compressed-archive-of-one-or-more-files-or-trees

命令 参数 说明
path list[path] 要压缩或存档的文件的远程绝对路径,通配符或路径或通配符列表 (/opt/*)(逗号分割)
dest path 目标归档文件的文件名(父目录必须在远端主机上存在). 如果目标存档已经存在,它将被截断和覆盖
format "bz2" "gz" "tar" "xz" "zip" 要使用的压缩类型 gz-默认
remove boolean 添加到归档后删除所有添加的源文件和树
exclude_path list[path] 要排除的文件的远程绝对路径,通配符或路径或通配符列表 (/opt/soft/*)(逗号分割)
exclusion_patterns list[path] 使用通配符模式将文件或目录从结果存档中排除(逗号分割)
force_archive boolean 允许您强制模块将其视为存档,即使只指定了一个文件
mode 0777 or u+rwx or u=rw,g=r,o=r 目标归档文件的权限
owner string 应该拥有文件系统对象的用户名(chown)
group string 应该拥有文件系统对象的组的名称(chown)
#压缩/data/greenplum/
ansible gp-master -m archive -a 'path=/data/greenplum/ dest=/data/greenplum/gpdb6.10.1.tar group=gpadmin owner=gpadmin'

#单文件压缩
ansible test -m archive -a 'path=/tmp/ql.txt dest=/tmp/ql.zip format=zip'

#项目文件压缩,排除 /target 和 /src/test   (path=/opt/pt 会包含 /pt 文件夹   path=/opt/pt/ 只会压缩里面的文件)
ansible test -m archive -a 'path=/opt/pt dest=/opt/pt.zip format=zip exclusion_patterns="/opt/pt/target/*,/opt/pt/src/test/*,/opt/pt/.git/*,/opt/pt/.idea/*"'
- name: 创建bz2压缩包,并屏蔽指定文件
  community.general.archive:
    path:
    - /path/to/foo/*
    dest: /path/file.tar.bz2
    exclude_path:
    - /path/to/foo/ba*
    exclusion_patterns:
    - /path/to/foo/ball/*
    format: bz2

8. 数据库

https://docs.ansible.com/ansible/latest/collections/index_module.html#community-mysql

名称 说明
mysql_db 从远程主机添加或删除MySQL数据库
mysql_info 收集有关MySQL服务器的信息
mysql_query 运行MySQL查询
mysql_replication 管理MySQL复制
mysql_role 添加、删除或更新MySQL角色
mysql_user 从MySQL数据库中添加或删除一个用户
mysql_variables 管理MySQL全局变量

9. 版本管理

subversion svn项目管理

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/subversion_module.html#ansible-builtin-subversion-module-deploys-a-subversion-repository

命令 参数 说明
repo string 存储库URL
dest path 保存目录
username string 用户名
password string 密码
force boolean true-修改后的文件将被丢弃 false-如果遇到修改过的文件,模块将失败(默认)
checkout boolean true-签出存储库(默认)
export boolean true-导出
#签出ptWeb
ansible test -m subversion -a 'repo=https://192.168.1.11/svn/ptWeb dest=/opt/download/ptWeb username=QL password=xxxxxx'
- name: Checkout subversion repository to specified folder
  ansible.builtin.subversion:
    repo: svn+ssh://an.example.org/path/to/repo
    dest: /src/checkout

- name: Export subversion directory to folder
  ansible.builtin.subversion:
    repo: svn+ssh://an.example.org/path/to/repo
    dest: /src/export
    export: yes

- name: Get information about the repository whether or not it has already been cloned locally
  ansible.builtin.subversion:
    repo: svn+ssh://an.example.org/path/to/repo
    dest: /src/checkout
    checkout: no
    update: no

git git项目管理

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/git_module.html#ansible-builtin-git-module-deploy-software-or-files-from-git-checkouts

命令 参数 说明
repo string git,SSH或HTTP(S)协议地址
dest path 签出存储库的路径(目标目录必须为空)
clone boolean false-不克隆 true-(默认)
force boolean true-工作存储库中的任何修改文件都将被丢弃 false-(默认)
update boolean false-不从原始存储库检索新的修订 true-(默认)
version string 签出存储库的哪个版本(HEAD,SHA-1 hash,name)
depth integer 创建一个浅克隆,其历史记录被截断为指定的数字或版本. 最小值为1
remote string 远端的名称 origin-(默认)
recursive integer false-克隆存储库时不带-recursive选项 true-(默认)
refspec string git fetch命令相同的语法
track_submodules boolean 相当于为git子模块update指定-remote标志 false-(默认)
single_branch boolean true-只克隆指向指定修订的尖端的历史记录 false-(默认)
reference string 参考存储库(参见git clone -reference…)
#签出ptWeb
ansible test -m git -a 'repo=https://192.168.1.11/svn/ptWeb dest=/opt/download/ptWeb'
- name: Git checkout
  ansible.builtin.git:
    repo: 'https://foosball.example.org/path/to/repo.git'
    dest: /srv/checkout
    version: release-0.22

- name: Read-write git checkout from github
  ansible.builtin.git:
    repo: git@github.com:mylogin/hello.git
    dest: /home/mylogin/hello

- name: Just ensuring the repo checkout exists
  ansible.builtin.git:
    repo: 'https://foosball.example.org/path/to/repo.git'
    dest: /srv/checkout
    update: no

- name: Just get information about the repository whether or not it has already been cloned locally
  ansible.builtin.git:
    repo: 'https://foosball.example.org/path/to/repo.git'
    dest: /srv/checkout
    clone: no
    update: no

- name: Checkout a github repo and use refspec to fetch all pull requests
  ansible.builtin.git:
    repo: https://github.com/ansible/ansible-examples.git
    dest: /src/ansible-examples
    refspec: '+refs/pull/*:refs/heads/*'

- name: Create git archive from repo
  ansible.builtin.git:
    repo: https://github.com/ansible/ansible-examples.git
    dest: /src/ansible-examples
    archive: /tmp/ansible-examples.zip

- name: Clone a repo with separate git directory
  ansible.builtin.git:
    repo: https://github.com/ansible/ansible-examples.git
    dest: /src/ansible-examples
    separate_git_dir: /src/ansible-examples.git

- name: Example clone of a single branch
  ansible.builtin.git:
    repo: https://github.com/ansible/ansible-examples.git
    dest: /src/ansible-examples
    single_branch: yes
    version: master

- name: Avoid hanging when http(s) password is missing
  ansible.builtin.git:
    repo: https://github.com/ansible/could-be-a-private-repo
    dest: /src/from-private-repo
  environment:
    GIT_TERMINAL_PROMPT: 0 # reports "terminal prompts disabled" on missing password
    # or GIT_ASKPASS: /bin/true # for git before version 2.3.0, reports "Authentication failed" on missing password

10. 其他

pause 暂停

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/pause_module.html#ansible-builtin-pause-module-pause-playbook-execution

命令 参数 说明
echo boolean 控制在输入时是否显示键盘输入. 如果设置了’ seconds ‘或’ minutes ‘则无效 true-显示(默认) false-不显示
prompt string 用于提示消息的可选文本
minutes string 需要暂停的正数分钟
seconds string 需要暂停的正数秒数
#暂停5s,显示提示
ansible test -m pause -a 'seconds=5 prompt=等我5s归来'

#暂停,等待输入,不回显
ansible test -m pause -a 'echo=false prompt=输点啥'
- name: Pause for 5 minutes to build app cache
  ansible.builtin.pause:
    minutes: 5

- name: Pause until you can verify updates to an application were successful
  ansible.builtin.pause:

- name: A helpful reminder of what to look out for post-update
  ansible.builtin.pause:
    prompt: "Make sure org.foo.FooOverload exception is not present"

- name: 不回显等待输入
  pause:
    prompt: "Enter a secret"
    echo: no
  register: res
- name: 输出输入值
  debug:
    msg: "{{ res.user_input }}"

ping 尝试连接到主机

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/ping_module.html#ansible-builtin-ping-module-try-to-connect-to-host-verify-a-usable-python-and-return-pong-on-success

命令 参数 说明
data string 返回ping返回值的数据 "crash"-模块将抛出异常
ansible all -m ping

#抛出异常
ansible all -m ping -a "data=crash"

#返回pong
ansible all -m ping -a "data=pong"
- name: Example from an Ansible Playbook
  ansible.builtin.ping:

- name: Induce an exception to see what happens
  ansible.builtin.ping:
    data: crash

debug 调试输出

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/debug_module.html#ansible-builtin-debug-module-print-statements-during-execution

命令 参数 说明
msg string 输出信息 可以包含 {{变量}}
var string 要调试的变量名, 与msg选项互斥. 这个选项已经在Jinja2上下文中运行,并且有一个隐式的{{}}包装
verbosity integer 0-默认 3-(-vvv)
ansible test -m debug -a 'var=ansible_default_ipv4.address'

ansible test -m debug -a 'var=hostvars[inventory_hostname]'
- name: Print the gateway for each host when defined
  ansible.builtin.debug:
    msg: System {{ inventory_hostname }} has gateway {{ ansible_default_ipv4.gateway }}
  when: ansible_default_ipv4.gateway is defined

- name: Print return information from the previous task
  ansible.builtin.debug:
    var: result
    verbosity: 2

fail 自定义消息失败抛出

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/fail_module.html#ansible-builtin-fail-module-fail-with-custom-message

命令 参数 说明
msg string 用于执行失败的自定义消息
- name: Fail if the file does not belong to 'root'
  ansible.builtin.fail:
    msg: "Whoops! file ownership has changed"
  when: st.stat.pw_name != 'root'

setup 收集指定的facts

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/setup_module.html#ansible-builtin-setup-module-gathers-facts-about-remote-hosts

命令 参数 说明
fact_path path 本地*.fact文件路径
filter list[string] 返回与 shell 样式(fnmatch)模式之一匹配的数据
gather_subset 将收集到的信息附加在给定子集. all, all_ipv4_addresses, all_ipv6_addresses, apparmor, architecture, caps, chroot,cmdline, date_time, default_ipv4, default_ipv6, devices, distribution, distribution_major_version, distribution_release, distribution_version, dns, effective_group_ids, effective_user_id, env, facter, fips, hardware, interfaces, is_chroot, iscsi, kernel, local, lsb, machine, machine_id, mounts, network, ohai, os_family, pkg_mgr, platform, processor, processor_cores, processor_count, python, python_version, real_user_id, selinux, service_mgr, ssh_host_key_dsa_public, ssh_host_key_ecdsa_public, ssh_host_key_ed25519_public, ssh_host_key_rsa_public, ssh_host_pub_keys, ssh_pub_keys, system, system_capabilities, system_capabilities_enforced, user, user_dir, user_gecos, user_gid, user_id, user_shell, user_uid, virtual, virtualization_role, virtualization_type
gather_timeout integer 为单独的事实收集设置默认超时(以秒为单位)
ansible test -m setup -a 'gather_subset=network,virtual'

ansible test -m setup -a 'filter=ansible_default_ipv4'

- name: Collect only facts returned by facter
  ansible.builtin.setup:
    gather_subset:
      - 'network'
      - 'virtual'

- name: Filter and return only selected facts
  ansible.builtin.setup:
    filter:
      - 'ansible_distribution'
      - 'ansible_machine_id'
      - 'ansible_*_mb'

uri 网络访问

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/uri_module.html#ansible-builtin-uri-module-interacts-with-webservices

命令 参数 说明
url string HTTP或HTTPS
method string 请求或响应的HTTP方法 GET-(默认)
body_format json form-multipart form-urlencoded raw 主体的序列化格式 raw-(默认)
body path 文件/对象的完整路径
src path 要提交到远程服务器的文件的路径. 不能与body连用. 应该与force_basic_auth一起使用,以确保远程端发送401时成功
remote_src boolean false-在控制节点上搜索src true-在远程节点上搜索src
headers dictionary 以YAML散列的格式向请求添加自定义HTTP标头. 在这里提供Content-Type将覆盖通过为body_format提供json或form-urlencoded生成的头文件
dest path 下载文件的路径
http_agent string 标识头,通常出现在 Web 服务器日志中 ansible-httpget-(默认)
timeout integer 超时时间 30-(默认)
status_code list 表示请求成功的有效的数字 HTTP 状态代码列表 [200]-(默认)
decompress boolean 是否尝试解压缩 gzip 内容编码的响应 true-(默认)
follow_redirects safe(false) all(true) none urllib2 URI模块是否应该遵循重定向 safe-(默认)
force boolean true-不获取缓存副本 false-(默认)
creates path 如果文件名已经存在,则不会运行此步骤
removes path 如果文件名不存在,则不会运行此步骤
return_content boolean 不管成功还是失败,是否将响应体作为content键返回到字典结果中. 独立于这个选项,如果报告的Content-type是application/json,那么json总是被加载到字典结果中名为json的键中 false-(默认)
mode 0777 or u+rwx or u=rw,g=r,o=r 目标归档文件的权限
owner string 应该拥有文件系统对象的用户名(chown)
group string 应该拥有文件系统对象的组的名称(chown)
force_basic_auth boolean 在初始请求时强制发送基本身份验证标头 false-(默认)
url_password string Digest, Basic or WSSE 身份验证用户密码
url_username string Digest, Basic or WSSE 身份验证用户名
use_proxy boolean 开启代理 true-(默认)
validate_certs boolean 验证证书 true-(默认)
ansible test -m uri -a 'url=https://www.baidu.com return_content=true'
- name: Check that you can connect (GET) to a page and it returns a status 200
  ansible.builtin.uri:
    url: http://www.example.com

- name: Check that a page returns a status 200 and fail if the word AWESOME is not in the page contents
  ansible.builtin.uri:
    url: http://www.example.com
    return_content: true
  register: this
  failed_when: "'AWESOME' not in this.content"

- name: Create a JIRA issue
  ansible.builtin.uri:
    url: https://your.jira.example.com/rest/api/2/issue/
    user: your_username
    password: your_pass
    method: POST
    body: "{{ lookup('ansible.builtin.file','issue.json') }}"
    force_basic_auth: true
    status_code: 201
    body_format: json

- name: Login to a form based webpage, then use the returned cookie to access the app in later tasks
  ansible.builtin.uri:
    url: https://your.form.based.auth.example.com/index.php
    method: POST
    body_format: form-urlencoded
    body:
      name: your_username
      password: your_password
      enter: Sign in
    status_code: 302
  register: login

- name: Login to a form based webpage using a list of tuples
  ansible.builtin.uri:
    url: https://your.form.based.auth.example.com/index.php
    method: POST
    body_format: form-urlencoded
    body:
    - [ name, your_username ]
    - [ password, your_password ]
    - [ enter, Sign in ]
    status_code: 302
  register: login

- name: Upload a file via multipart/form-multipart
  ansible.builtin.uri:
    url: https://httpbin.org/post
    method: POST
    body_format: form-multipart
    body:
      file1:
        filename: /bin/true
        mime_type: application/octet-stream
      file2:
        content: text based file content
        filename: fake.txt
        mime_type: text/plain
      text_form_field: value

- name: Connect to website using a previously stored cookie
  ansible.builtin.uri:
    url: https://your.form.based.auth.example.com/dashboard.php
    method: GET
    return_content: true
    headers:
      Cookie: "{{ login.cookies_string }}"

- name: Queue build of a project in Jenkins
  ansible.builtin.uri:
    url: http://{{ jenkins.host }}/job/{{ jenkins.job }}/build?token={{ jenkins.token }}
    user: "{{ jenkins.user }}"
    password: "{{ jenkins.password }}"
    method: GET
    force_basic_auth: true
    status_code: 201

- name: POST from contents of local file
  ansible.builtin.uri:
    url: https://httpbin.org/post
    method: POST
    src: file.json

- name: POST from contents of remote file
  ansible.builtin.uri:
    url: https://httpbin.org/post
    method: POST
    src: /path/to/my/file.json
    remote_src: true

- name: Create workspaces in Log analytics Azure
  ansible.builtin.uri:
    url: https://www.mms.microsoft.com/Embedded/Api/ConfigDataSources/LogManagementData/Save
    method: POST
    body_format: json
    status_code: [200, 202]
    return_content: true
    headers:
      Content-Type: application/json
      x-ms-client-workspace-path: /subscriptions/{{ sub_id }}/resourcegroups/{{ res_group }}/providers/microsoft.operationalinsights/workspaces/{{ w_spaces }}
      x-ms-client-platform: ibiza
      x-ms-client-auth-token: "{{ token_az }}"
    body:

- name: Pause play until a URL is reachable from this host
  ansible.builtin.uri:
    url: "http://192.0.2.1/some/test"
    follow_redirects: none
    method: GET
  register: _result
  until: _result.status == 200
  retries: 720 # 720 * 5 seconds = 1hour (60*60/5)
  delay: 5 # Every 5 seconds

- name: Provide SSL/TLS ciphers as a list
  uri:
    url: https://example.org
    ciphers:
      - '@SECLEVEL=2'
      - ECDH+AESGCM
      - ECDH+CHACHA20
      - ECDH+AES
      - DHE+AES
      - '!aNULL'
      - '!eNULL'
      - '!aDSS'
      - '!SHA1'
      - '!AESCCM'

- name: Provide SSL/TLS ciphers as an OpenSSL formatted cipher list
  uri:
    url: https://example.org
    ciphers: '@SECLEVEL=2:ECDH+AESGCM:ECDH+CHACHA20:ECDH+AES:DHE+AES:!aNULL:!eNULL:!aDSS:!SHA1:!AESCCM'

wait_for 等待条件成立后继续运行

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/wait_for_module.html#ansible-builtin-wait-for-module-waits-for-a-condition-before-continuing

命令 参数 说明
connect_timeout list[string] 活动连接计数的TCP连接状态列表 ["ESTABLISHED", "FIN_WAIT1", "FIN_WAIT2", "SYN_RECV", "SYN_SENT", "TIME_WAIT"]-(默认)
delay integer 开始轮询前等待的秒数
host string 等待的可解析主机名或IP地址 127.0.0.1-(默认)
port integer 轮询的端口号
path path 文件系统中继续之前必须存在的文件的路径。 “path”和”port”为互斥参数。
msg string 这将覆盖由于未能满足所需条件而产生的正常错误消息
search_regex string 可用于匹配文件或套接字连接中的字符串. 默认为多行正则表达式
sleep integer 检查之间的睡眠秒数 1-(默认)
state string started-检查端口开放(默认) stopped-检查端口关闭 drained-检查活动连接 absent-检查文件是否存在或已删除 present-检查文件或搜索字符串
timeout integer 等待的最大秒数 300-(默认)
ansible test -m wait_for -a 'host=127.0.0.1 port=6379 msg="redis未启动" state=started timeout=3'
- name: Sleep for 300 seconds and continue with play
  ansible.builtin.wait_for:
    timeout: 300
  delegate_to: localhost

- name: Wait for port 8000 to become open on the host, don't start checking for 10 seconds
  ansible.builtin.wait_for:
    port: 8000
    delay: 10

- name: Waits for port 8000 of any IP to close active connections, don't start checking for 10 seconds
  ansible.builtin.wait_for:
    host: 0.0.0.0
    port: 8000
    delay: 10
    state: drained

meta 执行Ansible的”actions”

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/meta_module.html#ansible-builtin-meta-module-execute-ansible-actions

命令 参数 说明
free_form string clear_facts-清除剧中主机列表中指定的主机所收集的事实 clear_host_errors-剧本主机列表中指定的主机中清除失败状态 end_host-是 end _ play 的每个主机变体,使当前主机的剧本结束而不会失败 end_play-使剧本在没有失败的情况下结束(影响所有主机) flush_handlers-使Ansible运行已notified的handler noop-什么都不做 refresh_inventory-重新加载inventory reset_connection-中断一个持久连接 end_batch-导致当前批处理结束,而不导致主机故障
# Example showing flushing handlers on demand, not at end of play
- ansible.builtin.template:
    src: new.j2
    dest: /etc/config.txt
  notify: myhandler

- name: Force all notified handlers to run at this point, not waiting for normal sync points
  ansible.builtin.meta: flush_handlers

# Example showing how to end the play for specific targets
- name: End the play for hosts that run CentOS 6
  ansible.builtin.meta: end_host
  when:
  - ansible_distribution == 'CentOS'
  - ansible_distribution_major_version == '6'

assert 断言表达式

当表达式为false时,task会抛出异常结束

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/assert_module.html#ansible-builtin-assert-module-asserts-given-expressions-are-true

命令 参数 说明
that list[string] 可以传递给when语句的相同形式的字符串表达式列表
fail_msg string 用于失败断言的自定义消息
success_msg string 用于成功断言的自定义消息
quiet boolean 将此设置为true以避免冗长的输出 false-(默认)
- name: assert test
  assert: 
    fail_msg: "RedHat设备"
    success_msg: "非RedHat设备"
    that: "ansible_os_family != 'RedHat'" 
    quiet: true

- ansible.builtin.assert:
    that:
      - "'foo' in some_command_result.stdout"
      - number_of_the_counting == 3

- name: After version 2.7 both 'msg' and 'fail_msg' can customize failing assertion message
  ansible.builtin.assert:
    that:
      - my_param <= 100
      - my_param >= 0
    fail_msg: "'my_param' must be between 0 and 100"
    success_msg: "'my_param' is between 0 and 100"

- name: Please use 'msg' when ansible version is smaller than 2.7
  ansible.builtin.assert:
    that:
      - my_param <= 100
      - my_param >= 0
    msg: "'my_param' must be between 0 and 100"

- name: Use quiet to avoid verbose output
  ansible.builtin.assert:
    that:
      - my_param <= 100
      - my_param >= 0
    quiet: true

4. 内置插件

Filter 过滤器

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/index.html#filter-plugins

加解密

名称 说明 示例
b64decode b64encode Base64加解密 {{ mypath | basename }} => ‘foo.txt’ out of ‘/etc/asdf/foo.txt’
checksum SHA-1 {{ ‘123’ | checksum }} => ’40bd001563085fc35165329ea1ff5c5ecbdbbeef’
sha1 SHA-1 {{ ‘123’ | sha1 }} => ’40bd001563085fc35165329ea1ff5c5ecbdbbeef’
hash hash加密 sha1 sha256 sha3_512 shake_256 md5 blake2b sha512 sha3_224 sha3_256 shake_128 sha384 blake2s sha224 sha3_384 {{ ‘123’ | hash(‘md5’) }} => ‘202cb962ac59075b964b07152d234b70’
md5 MD5 {{ ‘123’ | md5 }} => ‘202cb962ac59075b964b07152d234b70’
password_hash 转换输入密码为password_hash {{ ‘123456’ | password_hash }}
vault vault加密 salt-加密盐(默认随机) {{ ‘明文’ | vault(‘密钥’) }}
unvault vault解密 {{ ‘密文’ | unvault(‘密钥’) }}

文件路径

链接 说明 示例
basename 获取路径的文件名(带后缀) {{ ‘/etc/asdf/foo.txt’ | basename }} => ‘foo.txt’
dirname 获取路径的目录名 {{ ‘/etc/asdf/foo.txt’ | dirname }} => ‘/etc/asdf’
fileglob 将路径glob分解为匹配文件 {{ ‘/etc/h?sts’ | fileglob }} => [‘/etc/hosts’, ‘/etc/hasts’]
path_join 连接一个或多个路径 {{ [‘/etc’, ‘apt’, ‘trusted.d’, ‘mykey.gpg’] | path_join }} => ‘/etc/apt/trusted.d/mykey.gpgp’
realpath 将路径转换为实际路径(如软链接的真实路径) {{ ‘/usr/bin/vimdiff’ | realpath }} => ‘/usr/bin/vim’
relpath 获得相对路径 {{ ‘/tmp/test/me.txt’ | relpath(‘/tmp/other/’) }} => ‘../test/me.txt’
splitext 将路径拆分为根目录和文件扩展名 {{ ‘/etc/make.conf’ | splitext }} => [ ‘/etc/make’, ‘conf’ ]
win_basename 获取Windows路径的基名称 {{ ‘C:\Users\asdf\foo.txt’ | win_basename }} => ‘foo.txt’
win_dirname 获取Windows路径的目录 {{ ‘C:\Users\asdf\foo.txt’ | win_dirname }} => ‘C:\\Users\\asdf’
win_splitdrive 按驱动器号拆分 Windows 路径 {{ ‘C:\Users\asdf\foo.txt’ | win_splitdrive }} => “(‘C:’, ‘\\\\Users\\\\asdf\\\\foo.txt’)”

数学运算

链接 说明 示例
log 输入数字以N为底的对数的数学运算(默认为自然对数e) {{ 8 | log(5) }} => 1.2920296742201791
pow {{ 2 | pow(3) }} => 8
product 笛卡儿积列表 {{ [1,2] | product(repeat=2) }} => [[1,1],[1,2],[2,1],[2,2]]
root 开根号 {{ 4 | root }} => 2

正则

链接 说明 示例
regex_escape 转义正则表达式字符 posix_basic python-(默认) {{ ‘^f.o(.)$’ | regex_escape(‘python’) }} => ‘\^f.*o(.*)\$’
regex_findall 从字符串中提取所有匹配的正则表达式 ignorecase-忽略大小写 multiline-多行匹配 {{ ‘CAR\ntar\nfoo\nbar\n’ | regex_findall(‘^.ar$’, multiline=True, ignorecase=True) }}
regex_replace 通过正则表达式替换字符串 ignorecase-忽略大小写 multiline-多行匹配 {{ ‘ansible’ | regex_replace(‘^a.i(.)$’, ‘a\\1’) }}
regex_search 从字符串中提取正则表达式匹配 ignorecase-忽略大小写 multiline-多行匹配 {{ ‘server1/database42’ | regex_search(‘database[0-9]+’) }}

变量处理

链接 说明 示例
bool 转换为布尔值 {{ “0” | bool }} => false {{ 1 | bool }} => true
split 把一个字符串拆分成一个列表 " "-(默认) {{ ‘jojo is, a’ | split(‘,’ }} => [ “jojo is”, “a” ]
extract 根据索引或键提取值 {{ 1 | extract([‘a’, ‘b’, ‘c’]) }} => [‘a’, ‘b’, ‘c’][1] => ‘b’ {{ 0 | extract([{‘a’: 1, ‘b’: 2, ‘c’: 3}, {‘x’: 9, ‘y’: 10}], morekeys=’b’) }} => ‘2’
comment 注释掉字符串 {{ ‘Plain style (default)’ | comment }} => # Plain style (default)
human_readable 字节大小转可读文本串 Y Z E P T G M K B {{ 1232345345 | human_readable }} => ‘1.15 GB’ {{ 1232345345 | human_readable(unit=’M’) }} => ‘1175.26 MB’
human_to_bytes 字符串中获取字节大小 Y Z E P T G M K B {{ “1.15 GB” | human_to_bytes }} => 1234803098 {{ “1.15” | human_to_bytes(deafult_unit=”G”) }} => 1234803098
strftime 日期格式化(10位时间戳) {{ ‘%Y-%m-%d %H:%M:%S’ | strftime(1680278400) }}
quote 适当转义,防止命令语句错误 - shell: echo {{ “hello’world” | quote }} => “echo ‘hello’\”‘\”‘world'”
random 随机数或列表项目(py range [a,b) ) {{ [‘a’,’b’,’c’] | random }} {{10 | random(start=1,step=1) }} => [1,10)随机
mandatory 确保变量存在或已定义 {{ notdefined | mandatory }} => 不存在会抛”Mandatory variable ‘notdefined’ not defined.”
ternary 三元运算过滤器 {{ (name ‘group1’) | ternary(‘service’, ‘systemd’) }}
to_datetime 从字符串获取datetime {{ ((‘2023-04-01 00:00:00’ |to_datetime) – (‘2023-04-02’ |to_datetime(‘%Y-%m-%d’))).total_seconds() }} => “-86400.0”
type_debug 显示输入数据类型 {{ 123 | type_debug }} => ‘int’

文本转换

链接 说明 示例
to_json 将变量转换为 JSON 字符串 ensure_ascii-转义非ASCII字符(默认true) indent-缩进空格数(默认0) sort_keys-排序键名(默认false) {{ temp | to_json(ensure_ascii=false,sort_keys=true) }}
to_nice_json 将变量转换为“精心格式化的”JSON 字符串 参数同上 {{ temp | to_nice_json }}
to_nice_yaml sort_keys-排序键名(默认false) {{ temp | to_nice_yaml }}
to_uuid 对指定数据转化为uuid(非随机,同数据的结果每次都一致) {{ 123 | to_uuid }} => ‘f9a0d8fa-35e1-516f-b1bf-bb8f6c322ec4’
to_yaml 将变量转换为YAML字符串 sort_keys-排序键名(默认false) {{ github_workflow | to_yaml }}
from_json 将JSON字符串转换为变量结构 {{ ‘{“a”: true, “b”: 54, “c”: [1,2,3]}’ | from_json }}
from_yaml 将YAML字符串转换为变量结构
from_yaml_all 将一些YAML文档转换为可变结构
urlsplit 获取网址里的信息 fragment hostname path port query scheme netloc password username <scheme>://<netloc>/<path>;<params>?<query>#<fragment> netloc => <username>:<password>@<hostname>:<port> {{ “http://user:password@www.acme.com:9000/dir/index.html?query=term#fragment” | urlsplit(“hostname”) }} => ‘www.acme.com’

数组/字典操作

链接 说明 示例
intersect 列表的交集 {{ [1, 2, 3, 6] | intersect([1, 2, 3, 4, 5]) }} => [1, 2, 3]
subelements 返回列表及其元素的乘积
union 列表的并集 {{ [1, 2, 5, 1, 3, 4, 10] | union([3, 4, 5, 11, 99]) }} => [1, 2, 5, 1, 3, 4, 10, 11, 99]
unique 列表中的一组唯一项 {{ [1, 2, 5, 1, 3, 4, 10] | unique }} => [1, 2, 5, 3, 4, 10]
symmetric_difference 两个列表的不同项目 {{ [1, 2, 5, 1, 3, 4, 10] | symmetric_difference([1, 2, 3, 4, 5, 11, 99]) }} => [10, 11, 99]
shuffle 随机打乱列表 {{ [‘a’,’b’,’c’] | shuffle}}
rekey_on_member 使用成员将字词列表重新键入到字词列表中 {{ [{“ip”: “127.0.0.1”, “name”: “G1”}, {“ip”: “127.0.0.2”, “name”: “G2”}] | rekey_on_member(“ip”) }} => {“127.0.0.1”:{“ip”:”127.0.0.1″,”name”:”G1″},”127.0.0.2″:{“ip”:”127.0.0.2″,”name”:”G2″}}
permutations 列表元素的排列A {{ [1,2,3] | permutations(2) }} => [[1,2],[1,3],[2,1],[2,3],[3,1],[3,2]]
difference 比较A,B数组差异 {{ [1, 2, 5, 1, 3, 4, 10] | difference([1, 2, 3, 4, 5, 11, 99]) }} => [10]
flatten 扁平化列表 {{ [1, 2, [3, [4, 5]], 6] | flatten(1) }} => [1,2,3,[4,5],6] {{ [1 , 2, [3, [4, 5]], 6] | flatten }} => [1,2,3,4,5,6]
items2dict 字典KV提取合并为新字典 {{ [{‘key’: ‘hi’, ‘value’: ‘bye’}, {‘key’: ‘ciao’, ‘value’: ‘ciao’} ]| items2dict(‘key’,’value’)}} => { “hi”: “bye”, “ciao”: “ciao” }
combinations 穷举列表的所有元素的组合C {{ [1,2,3,4] | combinations(3) }} => [[1,2,3],[1,2,4],[1,3,4],[2,3,4]]
dict2items 字典展开为对象列表 {{ {‘a’: 1, ‘b’: 2} => [{ “key”: “a”, “value”: 1 }, { “key”: “b”, “value”: 2 }]
zip 组合列表元素(对多个列表并行递归,取遍历的对象生成元组) {{ [1,2,3,4,5,6] | zip([‘a’,’b’,’c’,’d’,’e’,’f’]) }} => [[1,”a”],[2,”b”],[3,”c”],[4,”d”],[5,”e”],[6,”f”]] {{ [1,2,3] | zip([‘a’,’b’,’c’], [‘d’,’e’,’f’]) }} => [[1,”a”,”d”],[2,”b”,”e”],[3,”c”,”f”]] {{ [1,2,3] | zip([‘a’,’b’,’c’,’d’,’e’,’f’]) }} => [[1,”a”],[2,”b”],[3,”c”]]
zip_longest 将列表元素与填充符合并(同上,对取不到的值使用fillvalue填充) {{ [1,2,3] | zip_longest([‘a’,’b’,’c’,’d’,’e’,’f’], [21, 22, 23], fillvalue=’X’) }} => [[1, “a”, 21], [2, “b”, 22], [3, “c”, 23], [“X”, “d”, “X”], [“X”, “e”, “X”], [“X”, “f”, “X”]]

环境变量

链接 说明 示例
expandvars 返回补全环境变量的路径 {{ ‘$HOME/stuff.txt’ | expandvars }} => ‘/home/myuser/stuff.txt’
expanduser 返回一个带有~转换的路径 {{ ‘~/stuff.txt’ | expanduser }} => ‘/home/myuser/stuff.txt’

Lookup 插件

用于主控机本地数据处理

query函数(简写q)也可以调用lookup插件,但query函数的默认返回一个列表

errors可以处理报错机制 ignore,warn,strict(默认)

链接 说明 示例
ini 从ini文件中读取数据 section-节中查找键的位置 re-正则 false(默认) file-导入文件 {{ lookup(‘ini’, ‘键名’, section=’节点名’, file=’users.ini’) }}
dict 返回字典中的键/值对项 {{ lookup(‘dict’, users) }} with_dict
env 读取环境变量的值 {{ lookup(‘env’, ‘HOME’) }} {{ lookup(‘env’, ‘PATH’) }}
file 读取文件内容 {{ lookup(‘file’, ‘/etc/hostname’) }} with_file
fileglob 列出符合模式的文件 {{ lookup(‘fileglob’, ‘/etc/host*’) }} with_fileglob
first_found 返回files列表中找到的第一个本地存在的文件 skip false(默认)抛出异常 true-当没有文件匹配时返回一个空列表 path-要在其中查找文件的路径列表(优先遍历) files-待查找的文件名列表 {{ lookup(‘first_found’, params) }} 建议使用模块内vars传参
indexed_items 重写列表以返回“索引项” with_indexed_items
items 转为对象列表 with_items
list 简单地返回给定的内容 with_list
lines 从命令中读取行 with_lines: cat /etc/hostname
nested 使用其他列表的嵌套元素组成列表 with_nested
password 检索或生成存储在文件中的随机密码 encryptmd5_crypt bcrypt sha256_crypt sha512_crypt length-20(默认) {{ lookup(‘password’, ‘123’,length=30) }} => ‘IaaKoWqqTeEK5Of0SQ:sKqCzIsjdZL’
pipe 从命令中读取输出 {{ lookup(‘pipe’, ‘date’) }} => ‘2023年 04月 07日 星期五 15:51:37 CST’
random_choice 从列表返回随机元素 with_random_choice
sequence 根据数字序列生成一个列表 start-0(默认) count-0(默认) end-0(默认) format-格式化 stride-序号之间递增 1(默认) with_sequence: start=0 end=10 format=%02d with_sequence: start=10 end=0 stride=-1
subelements 遍历字典列表中的嵌套键 {{ q(‘subelements’, users, ‘groups’, {‘skip_missing’: True}) }}
template 使用Jinja2模板后检索文件内容 详细配置 {{ lookup(‘template’, ‘./some_template.j2′, variable_start_string='[%’, variable_end_string=’%]’) }}
together 将列表合并为同步列表 with_together
url 从 URL 返回内容 detail

5. 剧本

#检查脚本
ansible-playbook -C test.yml

#运行脚本
ansible-playbook test.yml

YAML格式

https://www.runoob.com/w3cnote/yaml-intro.html

需要固定格式对齐(不会报错,但会执行失败)(请不要手动tab,对齐为2个空格)

https://www.bejson.com/validators/yaml_editor/

建议使用编辑器 Sublime Text 或 VSCode,并安装ansible插件

YAML块运算符

> 折叠块运算符

key: >
  This text
  has multiple
  lines

| 文本块运算符

key: |
  This text
  has multiple
  lines

可用于多行shell脚本

- name: iterate user groups
  shell: |
    groupmod -o -g {{ item['guid'] }} {{ item['username'] }} 
    do_some_stuff_here
    and_some_other_stuff
  with_items: "{{ users }}"

Playbook 基本结构

- name: 剧本1
  hosts: 主机清单中定义的组名
  vars:
    参数名: 参数值
  vars_files: 外置参数文件路径
  # gather_facts: false  #关闭facts收集
  tasks:
    - name: 任务1
      ignore_errors: true # 忽略错误并继续
      任务模块:
        模块参数名: 参数值
      tags: 标签名
    - name: 任务2
  handles:
    - name: 触发器1
      任务模块:
        模块参数名: 参数值
    - name: 触发器2
      任务模块:
        模块参数名: 参数值

- name: 剧本2
  hosts: 主机清单中定义的组名

基础字段详解

1. vars_* 变量定义及使用

vars 参数
- vars:
    download_path: /opt/download/


#使用
- hosts: test
  vars:
    download_path: /opt/download/
  tasks:
    - name: 输出变量
      debug:
        msg: "{{download_path}}"
#变量在开头时需要加"",中间可忽略
vars_files 变量文件

将所有变量写入yml文件,顶格书写

vim vars1.yml

download_path: /opt/download/
env_path: /opt/env/
soft_path: /opt/soft/
- hosts: test
  vars_files: ./vars1.yml
  tasks:
    - name: 输出变量
      debug:
        msg: |
          下载路径->{{download_path}}
          环境路径->{{env_path}}
          软件路径->{{soft_path}}
group_vars 根据主机清单分组自动识别变量

./group_vars/主机名/vars.yml 优先

./group_vars/all/vars.yml 所有主机共用

- hosts: gp-master
  #gather_facts: false #关闭收集
  tasks:
    - name: 输出变量
      debug:
        msg: "{{port}}"
- hosts: gp-datenode01
  tasks:
    - name: 输出变量
      debug:
        msg: "{{port}}"
- hosts: gp-datenode02
  tasks:
    - name: 输出变量
      debug:
        msg: "{{port}}"
- hosts: all
  tasks:
    - name: 输出变量
      debug:
        msg: "{{port}}"

#group_vars 结构树
group_vars
├── gp-datenode01
│   └── vars.yml
├── gp-datenode02
│   └── vars.yml
├── gp-datenode03
│   └── vars.yml
├── gp-master
│   └── vars.yml
└── vars.yml

#输出
PLAY [gp-datenode02] ***********************************************************
TASK [输出变量] ****************************************************************
ok: [192.168.1.182] => {
    "msg": 7001
}
#all
PLAY [all] *********************************************************************
TASK [输出变量] ****************************************************************
ok: [192.168.1.183] => {
    "msg": 8000
}
ok: [192.168.1.180] => {
    "msg": 7000
}
ok: [192.168.1.182] => {
    "msg": 7001
}

facts 主机内置变量
变量名 说明
ansible_hostname 主机名
ansible_memfree_mb 内存剩余大小(MB)
ansible_memtotal_mb 内存总大小(MB)
ansible_selinux.status selinux开启状态 “disabled”
ansible_swaptotal_mb swap大小
ansible_architecture 系统位数 “x86_64”
ansible_distribution 系统名
ansible_distribution_version 系统版本
ansible_processor_cores cpu核心数
ansible_processor_vcpus cpu数量
ansible_processor_threads_per_core cpu每核线程数
ansible_env 环境变量
//输出  ansible test -m setup
{
    "ansible_facts": {
        "ansible_all_ipv4_addresses": [ "192.168.1.180", "172.17.0.1", "192.168.122.1" ],
        "ansible_all_ipv6_addresses": [ "240e:37b:1bf3:3300:2ef0:5dff:fe43:376e", "fe80::2ef0:5dff:fe43:376e" ],
        "ansible_apparmor": {
            "status": "disabled"
        },
        "ansible_architecture": "x86_64",
        "ansible_bios_date": "01/07/2020",
        "ansible_bios_vendor": "American Megatrends Inc.",
        "ansible_bios_version": "1.40",
        "ansible_board_asset_tag": "Default string",
        "ansible_board_name": "B365M PRO-VH (MS-7C31)",
        "ansible_board_serial": "K4F0045483",
        "ansible_board_vendor": "Micro-Star International Co., Ltd.",
        "ansible_board_version": "1.0",
        "ansible_chassis_asset_tag": "Default string",
        "ansible_chassis_serial": "Default string",
        "ansible_chassis_vendor": "Micro-Star International Co., Ltd.",
        "ansible_chassis_version": "1.0",
        "ansible_cmdline": {
            "BOOT_IMAGE": "/vmlinuz-3.10.0-1160.83.1.el7.x86_64",
            "LANG": "zh_CN.UTF-8",
            "crashkernel": "auto",
            "nouveau.modeset": "0",
            "quiet": true,
            "rd.driver.blacklist": "nouveau",
            "rd.lvm.lv": "centos/swap",
            "rhgb": true,
            "ro": true,
            "root": "/dev/mapper/centos-root",
            "spectre_v2": "retpoline"
        },
        "ansible_date_time": {
            "date": "2023-03-01",
            "day": "01",
            "epoch": "1677633367",
            "epoch_int": "1677633367",
            "hour": "09",
            "iso8601": "2023-03-01T01:16:07Z",
            "iso8601_basic": "20230301T091607666726",
            "iso8601_basic_short": "20230301T091607",
            "iso8601_micro": "2023-03-01T01:16:07.666726Z",
            "minute": "16",
            "month": "03",
            "second": "07",
            "time": "09:16:07",
            "tz": "CST",
            "tz_dst": "CST",
            "tz_offset": "+0800",
            "weekday": "星期三",
            "weekday_number": "3",
            "weeknumber": "09",
            "year": "2023"
        },
        "ansible_default_ipv4": {
            "address": "192.168.1.180",
            "alias": "enp2s0",
            "broadcast": "192.168.1.255",
            "gateway": "192.168.1.1",
            "interface": "enp2s0",
            "macaddress": "2c:f0:5d:43:37:6e",
            "mtu": 1500,
            "netmask": "255.255.255.0",
            "network": "192.168.1.0",
            "prefix": "24",
            "type": "ether"
        },
        "ansible_default_ipv6": {
            "address": "240e:37b:1bf3:3300:2ef0:5dff:fe43:376e",
            "gateway": "fe80::1",
            "interface": "enp2s0",
            "macaddress": "2c:f0:5d:43:37:6e",
            "mtu": 1500,
            "prefix": "64",
            "scope": "global",
            "type": "ether"
        },
        "ansible_device_links": {},
        "ansible_devices": {},
        "ansible_distribution": "CentOS",
        "ansible_distribution_file_parsed": true,
        "ansible_distribution_file_path": "/etc/redhat-release",
        "ansible_distribution_file_variety": "RedHat",
        "ansible_distribution_major_version": "7",
        "ansible_distribution_release": "Core",
        "ansible_distribution_version": "7.9",
        "ansible_dns": {
            "nameservers": [ "8.8.8.8" ]
        },
        "ansible_domain": "",
        "ansible_effective_group_id": 0,
        "ansible_effective_user_id": 0,
        "ansible_enp2s0": {},
        "ansible_env": {
            "CLION_VM_OPTIONS": "/opt/soft/idea-IU-212.5284.40/ja-netfilter-all/vmoptions/clion.vmoptions",
            "DATAGRIP_VM_OPTIONS": "/opt/soft/idea-IU-212.5284.40/ja-netfilter-all/vmoptions/datagrip.vmoptions",
            "GOLAND_VM_OPTIONS": "/opt/soft/idea-IU-212.5284.40/ja-netfilter-all/vmoptions/goland.vmoptions",
            "HARDWARE_PLATFORM": "x86_64",
            "HOME": "/root",
            "IDEA_VM_OPTIONS": "/opt/soft/idea-IU-212.5284.40/ja-netfilter-all/vmoptions/idea.vmoptions",
            "LANG": "zh_CN.UTF-8",
            "LESSOPEN": "||/usr/bin/lesspipe.sh %s",
            "LOGNAME": "root",
            "LS_COLORS": "rs=0:di=38;5;27:ln=38;5;51:mh=44;38;5;15:pi=40;38;5;11:so=38;5;13:do=38;5;5:bd=48;5;232;38;5;11:cd=48;5;232;38;5;3:or=48;5;232;38;5;9:mi=05;48;5;232;38;5;15:su=48;5;196;38;5;15:sg=48;5;11;38;5;16:ca=48;5;196;38;5;226:tw=48;5;10;38;5;16:ow=48;5;10;38;5;21:st=48;5;21;38;5;15:ex=38;5;34:*.tar=38;5;9:*.tgz=38;5;9:*.arc=38;5;9:*.arj=38;5;9:*.taz=38;5;9:*.lha=38;5;9:*.lz4=38;5;9:*.lzh=38;5;9:*.lzma=38;5;9:*.tlz=38;5;9:*.txz=38;5;9:*.tzo=38;5;9:*.t7z=38;5;9:*.zip=38;5;9:*.z=38;5;9:*.Z=38;5;9:*.dz=38;5;9:*.gz=38;5;9:*.lrz=38;5;9:*.lz=38;5;9:*.lzo=38;5;9:*.xz=38;5;9:*.bz2=38;5;9:*.bz=38;5;9:*.tbz=38;5;9:*.tbz2=38;5;9:*.tz=38;5;9:*.deb=38;5;9:*.rpm=38;5;9:*.jar=38;5;9:*.war=38;5;9:*.ear=38;5;9:*.sar=38;5;9:*.rar=38;5;9:*.alz=38;5;9:*.ace=38;5;9:*.zoo=38;5;9:*.cpio=38;5;9:*.7z=38;5;9:*.rz=38;5;9:*.cab=38;5;9:*.jpg=38;5;13:*.jpeg=38;5;13:*.gif=38;5;13:*.bmp=38;5;13:*.pbm=38;5;13:*.pgm=38;5;13:*.ppm=38;5;13:*.tga=38;5;13:*.xbm=38;5;13:*.xpm=38;5;13:*.tif=38;5;13:*.tiff=38;5;13:*.png=38;5;13:*.svg=38;5;13:*.svgz=38;5;13:*.mng=38;5;13:*.pcx=38;5;13:*.mov=38;5;13:*.mpg=38;5;13:*.mpeg=38;5;13:*.m2v=38;5;13:*.mkv=38;5;13:*.webm=38;5;13:*.ogm=38;5;13:*.mp4=38;5;13:*.m4v=38;5;13:*.mp4v=38;5;13:*.vob=38;5;13:*.qt=38;5;13:*.nuv=38;5;13:*.wmv=38;5;13:*.asf=38;5;13:*.rm=38;5;13:*.rmvb=38;5;13:*.flc=38;5;13:*.avi=38;5;13:*.fli=38;5;13:*.flv=38;5;13:*.gl=38;5;13:*.dl=38;5;13:*.xcf=38;5;13:*.xwd=38;5;13:*.yuv=38;5;13:*.cgm=38;5;13:*.emf=38;5;13:*.axv=38;5;13:*.anx=38;5;13:*.ogv=38;5;13:*.ogx=38;5;13:*.aac=38;5;45:*.au=38;5;45:*.flac=38;5;45:*.mid=38;5;45:*.midi=38;5;45:*.mka=38;5;45:*.mp3=38;5;45:*.mpc=38;5;45:*.ogg=38;5;45:*.ra=38;5;45:*.wav=38;5;45:*.axa=38;5;45:*.oga=38;5;45:*.spx=38;5;45:*.xspf=38;5;45:",
            "MAIL": "/var/mail/root",
            "PATH": "/usr/lib64/ccache:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin",
            "PHPSTORM_VM_OPTIONS": "/opt/soft/idea-IU-212.5284.40/ja-netfilter-all/vmoptions/phpstorm.vmoptions",
            "PWD": "/root",
            "PYCHARM_VM_OPTIONS": "/opt/soft/idea-IU-212.5284.40/ja-netfilter-all/vmoptions/pycharm.vmoptions",
            "QT_GRAPHICSSYSTEM_CHECKED": "1",
            "SHELL": "/bin/bash",
            "SHLVL": "2",
            "SSH_CLIENT": "192.168.1.180 13510 22",
            "SSH_CONNECTION": "192.168.1.180 13510 192.168.1.180 22",
            "SSH_TTY": "/dev/pts/4",
            "TERM": "xterm-256color",
            "USER": "root",
            "WEBSTORM_VM_OPTIONS": "/opt/soft/idea-IU-212.5284.40/ja-netfilter-all/vmoptions/webstorm.vmoptions",
            "XDG_DATA_DIRS": "/root/.local/share/flatpak/exports/share:/var/lib/flatpak/exports/share:/usr/local/share:/usr/share",
            "XDG_RUNTIME_DIR": "/run/user/0",
            "XDG_SESSION_ID": "1811",
            "XMODIFIERS": "@im=ibus",
            "_": "/usr/bin/python"
        },
        "ansible_fibre_channel_wwn": [],
        "ansible_fips": false,
        "ansible_form_factor": "Desktop",
        "ansible_fqdn": "gp-datanode01",
        "ansible_hostname": "gp-datanode01",
        "ansible_hostnqn": "",
        "ansible_interfaces": [ "enp2s0", "lo", "docker0", "virbr0-nic", "virbr0" ],
        "ansible_is_chroot": false,
        "ansible_iscsi_iqn": "iqn.1994-05.com.redhat:2959aa9543ae",
        "ansible_kernel": "3.10.0-1160.83.1.el7.x86_64",
        "ansible_kernel_version": "#1 SMP Wed Jan 25 16:41:43 UTC 2023",
        "ansible_lo": {},
        "ansible_local": {},
        "ansible_lsb": {},
        "ansible_lvm": {},
        "ansible_machine": "x86_64",
        "ansible_machine_id": "ee26cddaa16d4dc5b7b74475be2cde56",
        "ansible_memfree_mb": 9436,
        "ansible_memory_mb": {
            "nocache": {
                "free": 11547,
                "used": 4283
            },
            "real": {
                "free": 9436,
                "total": 15830,
                "used": 6394
            },
            "swap": {
                "cached": 98,
                "free": 52766,
                "total": 54063,
                "used": 1297
            }
        },
        "ansible_memtotal_mb": 15830,
        "ansible_mounts": [],
        "ansible_nodename": "gp-datanode01",
        "ansible_os_family": "RedHat",
        "ansible_pkg_mgr": "yum",
        "ansible_proc_cmdline": {
            "BOOT_IMAGE": "/vmlinuz-3.10.0-1160.83.1.el7.x86_64",
            "LANG": "zh_CN.UTF-8",
            "crashkernel": "auto",
            "nouveau.modeset": "0",
            "quiet": true,
            "rd.driver.blacklist": "nouveau",
            "rd.lvm.lv": [ "centos/root", "centos/swap"],
            "rhgb": true,
            "ro": true,
            "root": "/dev/mapper/centos-root",
            "spectre_v2": "retpoline"
        },
        "ansible_processor": [
            "0","GenuineIntel","Intel(R) Core(TM) i5-9500F CPU @ 3.00GHz",
            "1","GenuineIntel","Intel(R) Core(TM) i5-9500F CPU @ 3.00GHz",
            "2","GenuineIntel","Intel(R) Core(TM) i5-9500F CPU @ 3.00GHz",
            "3","GenuineIntel","Intel(R) Core(TM) i5-9500F CPU @ 3.00GHz",
            "4","GenuineIntel","Intel(R) Core(TM) i5-9500F CPU @ 3.00GHz",
            "5","GenuineIntel","Intel(R) Core(TM) i5-9500F CPU @ 3.00GHz"
        ],
        "ansible_processor_cores": 6,
        "ansible_processor_count": 1,
        "ansible_processor_nproc": 6,
        "ansible_processor_threads_per_core": 1,
        "ansible_processor_vcpus": 6,
        "ansible_product_name": "MS-7C31",
        "ansible_product_serial": "Default string",
        "ansible_product_uuid": "ACCC6BD6-CA0C-BF1A-A0AD-2CF05D43376E",
        "ansible_product_version": "1.0",
        "ansible_python": {
            "executable": "/usr/bin/python",
            "has_sslcontext": true,
            "type": "CPython",
            "version": {
                "major": 2,
                "micro": 5,
                "minor": 7,
                "releaselevel": "final",
                "serial": 0
            },
            "version_info": [ 2, 7, 5, "final", 0 ]
        },
        "ansible_python_version": "2.7.5",
        "ansible_real_group_id": 0,
        "ansible_real_user_id": 0,
        "ansible_selinux": {
            "status": "disabled"
        },
        "ansible_selinux_python_present": true,
        "ansible_service_mgr": "systemd",
        "ansible_ssh_host_key_ecdsa_public": "AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEgfGf/mU+hxKcs4m2mOL17tbhib8hws4VCed/KYrRRc/VsVWZjfA9iNvGJzwf/ezo2L7XsmZnOcOpMVc80SNIw=",
        "ansible_ssh_host_key_ecdsa_public_keytype": "ecdsa-sha2-nistp256",
        "ansible_ssh_host_key_ed25519_public": "AAAAC3NzaC1lZDI1NTE5AAAAIKjWxOFkKC5d1ZWKbX0esy8vmGREoNRJncp6epHTJw7v",
        "ansible_ssh_host_key_ed25519_public_keytype": "ssh-ed25519",
        "ansible_ssh_host_key_rsa_public": "AAAAB3NzaC1yc2EAAAADAQABAAABAQDIsp37iSdPGf1I7yoJohoMA8gSP8J2jHA1wJbV83gvRxBcqP6XTPE13qcspqdYCUF0zPxoB81H1OwkLlrg85rc8rfdabp2ALfZEaw1TM+aF8/3TBDGHvqYpW9MDNAbxhCdRGbkhfzKPpguKNgkXFz5IKArmepsiIR1jDfJHZNqfxe3iqW4BKEfrz7FHqi5b/fxyWm0EGlcPHXlhw6kfJugDknuK2rcPZ3M+QGFtUKDWznv9RwDjVgJbhNXOcXZH+BypmikL6AfiYeBFPygYH+QjlsBFvZXTKbRZO8yTk/WPYQXI1t4quMtnY6H841huSkw1LSzDOAtjA4mavWjAhWv",
        "ansible_ssh_host_key_rsa_public_keytype": "ssh-rsa",
        "ansible_swapfree_mb": 52766,
        "ansible_swaptotal_mb": 54063,
        "ansible_system": "Linux",
        "ansible_system_capabilities": [],
        "ansible_system_capabilities_enforced": "True",
        "ansible_system_vendor": "Micro-Star International Co., Ltd.",
        "ansible_uptime_seconds": 173504,
        "ansible_user_dir": "/root",
        "ansible_user_gecos": "root",
        "ansible_user_gid": 0,
        "ansible_user_id": "root",
        "ansible_user_shell": "/bin/bash",
        "ansible_user_uid": 0,
        "ansible_userspace_architecture": "x86_64",
        "ansible_userspace_bits": "64",
        "ansible_virbr0": {},
        "ansible_virbr0_nic": {},
        "ansible_virtualization_role": "host",
        "ansible_virtualization_tech_guest": [],
        "ansible_virtualization_tech_host": [
            "kvm"
        ],
        "ansible_virtualization_type": "kvm",
        "discovered_interpreter_python": "/usr/bin/python",
        "gather_subset": [
            "all"
        ],
        "module_setup": true
    },
    "changed": false
}

例子

- hosts: all
  vars_files: ./vars1.yml
  tasks:
    - name: 输出变量
      debug:
        msg: facts变量  ip -> {{ansible_default_ipv4.address}}
register变量(寄存器)
- hosts: test
  tasks:
    - name: get date
      command: date +%F
      register: date
    - name: 输出date
      debug:
        msg: "{{ date.stdout }}"
template模板(jinja2格式)
下载目录: {{download_path}}
环境目录: {{env_path}}
软件目录: {{soft_path}}
jinja2
  • 列表 [item1,item2]
  • 元组 {item1,item2}
  • 字典 {key1,value1}
  • 逻辑运算 and,or,not
  • 比较操作 ,!=,>,>=,<,<=
  • 算术运算 +,-,*,/,//,%,**
  • 流表达式 for,if,when

内置过滤器/插件

变量判断
  • defined:判断变量是否已定义,已定义则返回真

  • undefined:判断变量是否未定义,未定义则返回真

  • none:判断变量的值是否为空,如果变量已定义且值为空,则返回真

    - when: var2 is undefined
    

2. handlers 触发器

https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_handlers.html

handlers是在当前剧本的所有tasks运行完成后,再执行的

剧本1->handlers->剧本2->handlers

- name: 当nginx.conf更改时,调用重载配置(剧本1)
  hosts: test
  tasks:
    - name: 更改conf
      copy:
        src: nginx.conf
        dest: /etc/nginx/conf.d/
        backup: true
      notify:
        - nginx reloaded
  handlers:
    - name: nginx reloaded
      systemd:
        name: nginx
        state: reloaded


- name: 更改hello文件(剧本2)
  hosts: test
  tasks:
    - name: 更改hello
      copy:
        src: hello.txt
        dest: /tmp/hello.txt
      notify:
        - change
  handlers:
    - name: change
      debug:
        msg: "我不干净了"
Naming handlers
tasks:
  - name: Restart everything
    command: echo "this task will restart the web services"
    notify: "restart web services"

handlers:
  - name: Restart memcached
    service:
      name: memcached
      state: restarted
    listen: "restart web services"

  - name: Restart apache
    service:
      name: apache
      state: restarted
    listen: "restart web services"

3. when 条件

https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_conditionals.html#conditionals

https://zhuanlan.zhihu.com/p/587770251

可以与facts变量和register变量一起使用

- name: 给gp-master和gp-datanode01推送配置
  hosts: all
  tasks:
    - name: push conf
      copy: 
        content: "我是配置"
        dest: '/tmp/test.conf'
      when: (ansible_hostname is match("gp-master|gp-datanode01"))


- name: 匹配系统版本
  hosts: all
  tasks:
    - name: Centos 7 
      debug:
        msg: "Centos 7"
      when:
        - ansible_distribution == 'CentOS'
        - ansible_distribution_major_version == '7'


4. with_* loop 循环

https://blog.csdn.net/qq_35887546/article/details/105251517

https://www.cnblogs.com/ccbloom/p/15508665.html

with_random_choice 随机获得列表中的一个值

https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_loops.html#with-random-choice

with_items 循环读取并赋值给{{item}}

https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_loops.html#with-items

- hosts: test
  gather_facts: false
  vars:
    items:
      - QL
      - World
  tasks:
    - name: Hello with_items
      debug:
        msg: "Hello {{ item }}"
      with_items:
        - World
        - QL

    - name: Hello loop
      debug:
        msg: "Hello2 {{ item }}"
      loop: 
        - World
        - QL

    - name: Hello loop {{items}}
      debug:
        msg: "Hello3 {{ item }}"
      loop: "{{items}}"

    - name: Hello loop ojb
      debug:
        msg: "name=> {{ item.name }}  value=>{{item.value}}"
      loop:
        - { name : 'QL' , value : '666' }
        - { name : 'QAQ' , value : '777'}
        - { name : 'Q_Q' , value : '888'}

#result
TASK [Hello with_items] *********************************************************************************
ok: [192.168.1.180] => (item=World) => {
    "msg": "Hello World"
}
ok: [192.168.1.180] => (item=QL) => {
    "msg": "Hello QL"
}

TASK [Hello loop] ***************************************************************************************
ok: [192.168.1.180] => (item=World) => {
    "msg": "Hello2 World"
}
ok: [192.168.1.180] => (item=QL) => {
    "msg": "Hello2 QL"
}

TASK [Hello loop ['QL', 'World']] ***********************************************************************
ok: [192.168.1.180] => (item=QL) => {
    "msg": "Hello3 QL"
}
ok: [192.168.1.180] => (item=World) => {
    "msg": "Hello3 World"
}

loop 和 with_* 的区别

https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_loops.html#comparing-loop-and-with

loop

https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_loops.html#loops

#字典转items
- name: Using dict2items
  ansible.builtin.debug:
    msg: "{{ item.key }} - {{ item.value }}"
  loop: "{{ tag_data | dict2items }}"
  vars:
    tag_data:
      Environment: dev
      Application: payment

#将输入值转化为列表
loop: "{{ query('inventory_hostnames', 'all') }}"
loop: "{{ lookup('inventory_hostnames', 'all', wantlist=True) }}"

#带下标
- name: Count our fruit
  ansible.builtin.debug:
    msg: "{{ item }} with index {{ my_idx }}"
  loop:
    - apple
    - banana
    - pear
  loop_control:
    index_var: my_idx

#带暂停
- name: Create servers, pause 3s before creating next
  community.digitalocean.digital_ocean:
    name: "{{ item }}"
    state: present
  loop:
    - server1
    - server2
  loop_control:
    pause: 3

5. tag 标签

https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_tags.html#tags

#ansible-playbook 对于tags的指令
#跳过 不匹配这些值的 剧本和任务
--skip-tags
#仅运行 匹配的 剧本和任务
-t(--tags)
#列出剧本中所有的tags
--list-tags

#例
ansible-playbook echo_vars2.yml --list-tags

ansible-playbook echo_vars2.yml -t gp-master

ansible-playbook echo_vars2.yml --skip-tags gp-master

echo_vars2.yml (须执行 group_vars 步骤)

- hosts: gp-master
  gather_facts: false
  tasks:
    - name: gp-master 的端口
      debug:
        msg: "{{port}}"
      tags: gp-master

- hosts: gp-datenode01
  gather_facts: false
  tasks:
    - name: gp-datenode01 的端口
      debug:
        msg: "{{port}}"
      tags: gp-datenode01

- hosts: gp-datenode02
  gather_facts: false
  tasks:
    - name: gp-datenode02 的端口
      debug:
        msg: "{{port}}"
      tags: gp-datenode02

- hosts: all
  gather_facts: false
  tasks:
    - name: all 的端口
      debug:
        msg: "{{port}}"
      tags: all

6. include_* import_* 包含/引入

include_* 为动态加载,即执行到再加载

import_* 为静态加载,即导入剧本时加载所有剧本内容(变量等)

https://blog.csdn.net/y1431096034/article/details/89211694
https://www.cnblogs.com/mauricewei/p/10054041.html

import_playbook

导入剧本

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/import_playbook_module.html#ansible-builtin-import-playbook-module-import-a-playbook

include_tasks

动态加载剧本(在执行play之前才会加载自己变量)

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/include_tasks_module.html#ansible-builtin-include-tasks-module-dynamically-include-a-task-list

import_tasks

静态加载剧本(在playbooks解析阶段将父task变量和子task变量全部读取并加载)

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/import_tasks_module.html#ansible-builtin-import-tasks-module-import-a-task-list

include_role

加载角色并执行

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/include_role_module.html#ansible-builtin-include-role-module-load-and-execute-a-role

import_role

导入角色到剧本中

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/import_role_module.html#ansible-builtin-import-role-module-import-a-role-into-a-play

例子
- name: Include a play after another play
  import_playbook: otherplays.yaml

- name: Run tasks/other.yaml instead of 'main'
  include_role:
    name: myrole
    tasks_from: other

- name: Import task list in play
  import_tasks:
    file: stuff.yaml

- name: Apply tags to tasks within included file when using free-form
  include_tasks: install.yml


- name: All Run Tasks
  hosts: all
  tasks:    
    - name: This fails because I'm inside a play already
      import_playbook: stuff.yaml

    - name: Apply conditional to all imported tasks
      import_tasks: stuff.yaml

    - name: Include task list in play
      include_tasks:
        file: stuff.yaml

7. roles

角色允许您根据已知的文件结构自动加载相关的变量,文件,任务,处理程序和其他Ansible工件. 按照角色对内容进行分组后,您可以轻松地重用它们并与其他用户共享它们

https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_reuse_roles.html#roles

roles/
    basic/               # 这个等级代表一个"role"
        tasks/            #
            main.yml      #  <-- 如果有必要,任务文件可以包括更小的文件
        handlers/         #
            main.yml      #  <-- handlers文件
        templates/        #  <-- 模板文件夹
            ntp.conf.j2   #  <------- (建议以.j2结尾)模板文件
        files/            #
            bar.txt       #  <-- 复制文件
            foo.sh        #  <-- 脚本文件
        vars/             #
            main.yml      #  <-- 与此角色关联的变量
        defaults/         #
            main.yml      #  <-- 此角色的默认低优先级变量
        meta/             #
            main.yml      #  <-- 角色依赖关系
        library/          # 角色还可以包括自定义模块
        module_utils/     # 角色还可以包含自定义的module_utils
        lookup_plugins/   # 或者其他类型的插件,比如本例中的查找

    QL/                   # 与上面的"basic"相同的结构,用于"QL"角色
    QAQ/                  # ""
    QoQ/                  # ""
role环境结构
mkdir ./roles
#新建角色名
mkdir ./roles/QL
cd ./roles/QL

#新建目录列表
#默认
mkdir tasks handlers templates files vars
#完整
mkdir tasks handlers templates files vars defaults meta library module_utils lookup_plugins

tree -F
└── QL/
    ├── defaults/
    ├── files/
    ├── handlers/
    ├── library/
    ├── lookup_plugins/
    ├── meta/
    ├── module_utils/
    ├── tasks/
    ├── templates/
    └── vars/
例子
原始playbook脚本
- name: 更改hello文件
  hosts: test
  vars:
    text: QL
  tasks:
    - name: 推送hello
      template:
        src: hello.j2
        dest: /tmp/hello.txt
      notify:
        - change
  handlers:
    - name: hello.txt被改变
      debug:
        msg: "hello被改变了"
#Hello.j2
Hello {{text}}
改造
  • roles_test.yml
- name: roles脚本测试例子
  hosts: all
  gather_facts: false
  roles: 
    - role: QL
  • /roles/QL/vars/main.yml
text: QL
  • /roles/QL/tasks/main.yml
- name: 更改hello
  template:
    src: hello.j2
    dest: /tmp/hello.txt
  notify:
    - change
- name: debug模式下输出
  debug:
    msg: "{{ text }}"
  when: debug is defined
  • /roles/QL/handlers/main.yml
- name: change
  debug:
    msg: "hello被改变了"
  • /roles/QL/templates/hello.j2
#Hello.j2  
Hello {{text}}
目录结构
#tree -F
.
├── roles/
│   └── QL/
│       ├── files/
│       ├── handlers/
│       │   └── main.yml
│       ├── tasks/
│       │   └── main.yml
│       ├── templates/
│       │   └── hello.j2
│       └── vars/
└── roles_test.yml
执行
ansible-playbook roles_test.yml

#触发debug模式下输出text变量
ansible-playbook roles_test.yml -e "debug=1"

#手动修改text变量
ansible-playbook roles_test.yml -e "debug=1 text=QL"

8. become 权限

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/index.html#become-plugins

https://docs.ansible.com/ansible/latest/plugins/become.html#become-plugin-list

9. failed_when

https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_error_handling.html#defining-failure

10. register

Playbook 剧本例程

初始化环境

- name: Eclipse安装
  hosts: all
  vars:
    # 下载路径
    download_path: /opt/download
    # 软件安装路径
    soft_path: /opt/soft
    # 环境路径
    env_path: /opt/env
  tasks:
    - name: 初始化download目录
      file:
        path: "{{ item }}"
        state: directory
      loop:
        - download_path
        - soft_path
        - env_path

Eclipse安装

- name: Eclipse安装
  hosts: gp-master
  tasks:
    - name: download eclipse-java-2021-12
      get_url: 
        url: 'https://archive.eclipse.org/technology/epp/downloads/release/2021-12/R/eclipse-java-2021-12-R-linux-gtk-x86_64.tar.gz'
        dest: '/opt/download/eclipse-java-2021-12-R-linux-gtk-x86_64.tar.gz'
        force: true
    - name: unzip eclipse-java-2021-12
      unarchive:
        src: '/opt/download/eclipse-java-2021-12-R-linux-gtk-x86_64.tar.gz'
        dest: /opt/soft/
        remote_src: true
    - name: download eclipse-java-2021-12
      get_url: 
        url: 'https://ftp.yz.yamagata-u.ac.jp/pub/eclipse/technology/babel/babel_language_packs/latest/BabelLanguagePack-eclipse-zh_4.22.0.v20211218020001.zip'
        dest: '/opt/download/BabelLanguagePack-eclipse-zh_4.22.0.v20211218020001.zip'
        force: true
    - name: unzip BabelLanguagePack-eclipse-zh_4.22.0
      unarchive:
        src: '/opt/download/BabelLanguagePack-eclipse-zh_4.22.0.v20211218020001.zip'
        dest: /opt/soft/
        remote_src: true
    - name: add desktop link
      copy: 
        content: |
          [Desktop Entry]
          Encoding=UTF-8
          Name=eclipse
          Comment=Eclipse
          Exec=/opt/soft/eclipse/eclipse
          Icon=/opt/soft/eclipse/icon.xpm
          Terminal=false
          StartupNotify=true
          Type=Application
          Categories=Application;Development;
        dest: '~/桌面/Eclipse.desktop'

LibreOffice安装

- name: LibreOffice安装
  hosts: gp-master
  tasks:
    - name: unzip 英文主程序
      unarchive:
        src: 'https://mirrors.cloud.tencent.com/libreoffice/libreoffice/stable/7.5.0/rpm/x86_64/LibreOffice_7.5.0_Linux_x86-64_rpm.tar.gz'
        dest: /opt/download/
        remote_src: true
    - name: unzip 中文包
      unarchive:
        src: 'https://mirrors.cloud.tencent.com/libreoffice/libreoffice/stable/7.5.0/rpm/x86_64/LibreOffice_7.5.0_Linux_x86-64_rpm_langpack_zh-CN.tar.gz'
        dest: /opt/download/
        remote_src: true
    - name: unzip 中文帮助doc
      unarchive:
        src: 'https://mirrors.cloud.tencent.com/libreoffice/libreoffice/stable/7.5.0/rpm/x86_64/LibreOffice_7.5.0_Linux_x86-64_rpm_helppack_zh-CN.tar.gz'
        dest: /opt/download/
        remote_src: true
    - name: 安装主程序
      shell: 'rpm -ivh --force --nodeps /opt/download/LibreOffice_7.5.0.3_Linux_x86-64_rpm/RPMS/*.rpm'
    - name: 安装中文包
      shell: 'rpm -ivh --force --nodeps  /opt/download/LibreOffice_7.5.0.3_Linux_x86-64_rpm_langpack_zh-CN/RPMS/*.rpm'
    - name: 安装中文doc
      shell: 'rpm -ivh --force --nodeps  /opt/download/LibreOffice_7.5.0.3_Linux_x86-64_rpm_helppack_zh-CN/RPMS/*.rpm'
    - name: 清理环境
      shell: rm -rf /opt/download/LibreOffice_*

Ansible-Lint 格式化

https://ansible-lint.readthedocs.io/

格式化配置

配置项列表

ansible-lint -v -T

# List of tags and rules they cover
command-shell:  # Specific to use of command and shell modules
  - command-instead-of-module
  - command-instead-of-shell
  - inline-env-var
  - no-changed-when
  - risky-shell-pipe
core:  # Related to internal implementation of the linter
  - internal-error
  - load-failure
  - parser-error
  - syntax-check
  - warning
  - schema
deprecations:  # Indicate use of features that are removed from Ansible
  - deprecated-bare-vars
  - deprecated-local-action
  - deprecated-module
  - no-jinja-when
  - role-name
experimental:  # Newly introduced rules, by default triggering only warnings
  - warning
  - args
  - no-log-password
  - only-builtins
  - sanity
formatting:  # Related to code-style
  - yaml
  - fqcn
  - jinja
  - key-order
  - no-tabs
  - playbook-extension
  - risky-octal
idempotency:  # Possible indication that consequent runs would produce different results
  - latest
  - no-changed-when
  - package-latest
idiom:  # Anti-pattern detected, likely to cause undesired behavior
  - command-instead-of-module
  - command-instead-of-shell
  - empty-string-compare
  - inline-env-var
  - literal-compare
  - loop-var-prefix
  - name
  - no-handler
  - no-relative-paths
  - run-once
  - var-naming
metadata:  # Invalid metadata, likely related to galaxy, collections or roles
  - galaxy
  - meta-incorrect
  - meta-no-info
  - meta-no-tags
  - meta-runtime
  - meta-video-links
  - role-name
opt-in:  # Rules that are not used unless manually added to `enable_list`
  - empty-string-compare
  - no-log-password
  - no-prompting
  - no-same-owner
  - only-builtins
risk:
  - no-free-form
security:  # Rules related o potentially security issues, like exposing credentials
  - no-log-password
syntax:
  - args
  - no-free-form
unpredictability:  # Warn about code that might not work in a predictable way
  - avoid-implicit
  - ignore-errors
  - partial-become
  - risky-file-permissions
unskippable:  # Indicate a fatal error that cannot be ignored or disabled
  - load-failure
  - syntax-check
yaml:  # External linter which will also produce its own rule codes
  - yaml

配置文件

VSCode中可如下配置

//使用默认basic配置
"ansible.validation.lint.arguments": "--profile=basic",

//启用自定义配置
"ansible.validation.lint.arguments": "-c /root/.config/ansible-lint.yml"

.config/ansible-lint.yml

#个人使用习惯
skip_list:
  - fqcn
  - yaml
  - no-free-form
  - ignore-errors
  - name
  - jinja[spacing]
  - risky-file-permissions
  - no-changed-when
  - package-latest
  - command-instead-of-shell
  - deprecated-bare-vars

PS:

There appears to be both ‘k=v’ shorthand syntax and YAML in this task. Only one syntax may be used.

#Categories=Application;Development;   
Categories='Application;Development;'
#或脚本对齐问题

以下操作不会正常使用

- shell: |
    cat <<EOF
    This is a test.
    EOF

Ansible实际上会用前导空格呈现文本,这意味着shell永远不会在一行的开头找到字符串EOF. 您可以通过如下方式使用cmd参数来避免

- shell:
    cmd: |
      cat <<EOF
      This is a test.
      EOF