ansible
ansible安装
#!/bin/bash
: <<!
**********************************************************
* Name : 安装ansible
* Author : 黄登基
* Email : huangdengji@126.com
* Last modified : 2021-11-02 10:30
* Filename : openldap_install
* Version : 1.0
* Description : 目前在 CentOS 7.x 运行稳定,这个脚本需要使用 root 用户运行
* *******************************************************
!
wget https://www.python.org/ftp/python/3.6.15/Python-3.6.15.tar.xz
tar -xf Python-3.6.15.tar.xz
cd Python-3.6.15 || exit
#编辑 取消注释 如下几行:
# ./Modules/Setup.dist
# 大约在 209 行
# 209 SSL=/usr/local/ssl
# 210 _ssl _ssl.c \
# 211 -DUSE_SSL -I$(SSL)/include -I$(SSL)/include/openssl \
# 212 -L$(SSL)/lib -lssl -lcrypto
./configure --prefix=/usr/local --with-ensurepip=install --enable-shared
make && make altinstall
ln -s /usr/local/bin/pip3.6 /usr/local/bin/pip
pip install virtualenv -i http://pypi.douban.com/simple --trusted-host pypi.douban.com
useradd deploy
su - deploy
#使用deploy用户执行下面操作
virtualenv -p /usr/local/bin/python3.6 .py3-a2.9-env
source /home/deploy/.py3-a2.9-env/bin/activate
#下载ansible https://github.com/ansible/ansible.git
git clone https://github.com/ansible/ansible.git
#stable-2.9 分支
git checkout stable-2.9
source /home/deploy/.py3-a2.9-env/ansible/hacking/env-setup -p
pip install cryptography -i http://pypi.douban.com/simple --trusted-host pypi.douban.com
pip install paramiko -i http://pypi.douban.com/simple --trusted-host pypi.douban.com
pip install pyyaml -i http://pypi.douban.com/simple --trusted-host pypi.douban.com
pip install jinja2 -i http://pypi.douban.com/simple --trusted-host pypi.douban.com
ansible --version
ansible配置
#在.bash_profile追加环境变量切换
echo "source /home/deploy/.py3-a2.9-env/bin/activate" >>.bash_profile
echo "source /home/deploy/.py3-a2.9-env/ansible/hacking/env-setup -p" >>.bash_profile
cat >sudeploy.sh <<EOF
#!/bin/bash
chown -R deploy:deploy /home/deploy
su - deploy
EOF
#免密登录配置
cat ~/.ssh/id_*.pub | ssh root@210.26.116.128 'cat >> .ssh/authorized_keys'
cat ~/.ssh/id_*.pub | ssh root@210.26.116.90 'cat >> .ssh/authorized_keys'
ansible操作
ping检查
ansible all -i root@210.26.116.128,root@210.26.116.90 -m ping
复制文件
ansible all -i root@210.26.116.128,root@210.26.116.90 -m copy -a "src=/opt/shell-util/utils.sh dest=/tmp/utils.sh"
资源查询
ansible all -i inventory.ini --list-hosts
ansible southeast -i inventory.ini --list-hosts
查看文档
ansible-doc
ansible-doc -l
ansible-doc -l | grep copy
ansible-doc -l copy
ansible-doc copy
ansible-doc -s copy
编写资源菜单
cat >hosts <<EOF
[dbserver]
root@210.26.116.128
[webserver]
root@210.26.116.90
EOF
查看资源列表
ansible all hosts --list-hosts
ansible webserver -i hosts --list-hosts
commond 执行命令
ansible all -i hosts -a "echo 'hello'"
ansible all -i hosts -a "hostname -i"
shell 执行命令
ansible all -i hosts -m shell -a "hostname -i"
ansible all -i hosts -m shell -a "echo 'hello' | grep -o e"
script
cat >a.sh <<EOF
touch /tmp/testfile
EOF
ansible webserver -i hosts -m script -a "/home/deploy/.py3-a2.9-env/workspace/a.sh"
ansible webserver -i hosts -m shell -a "ls /tmp/testfile"
copy
ansible webserver -i hosts -m copy -a "src=nginx-1.20.1.tar.gz dest=/tmp/nginx-1.20.1.tar.gz"
ansible webserver -i hosts -m shell -a "file /tmp/nginx-1.20.1.tar.gz"
ansible webserver -i hosts -m copy -a "src=nginx-1.20.1.tar.gz dest=/tmp/nginx-1.20.1.tar.gz backup=yes"
nsible all -i hosts -m copy -a "src=nginx-1.20.1.tar.gz dest=/tmp/nginx-1.20.1.tar.gz backup=yes group=nobody owner=nobody"
ansible all -i hosts -m copy -a "src=nginx-1.20.1.tar.gz dest=/tmp/nginx-1.20.1.tar.gz backup=yes group=nobody owner=nobody mode=755"
yum_repository
# 添加 epel yum源
ansible dbserver -i hosts -m yum_repository -a "name=epel baseurl='http://download.fedoraproject.org/pub/epel/$releaserver/$basearch' description='EPEL YUM REPO'"
# 查看 epel yum源
ansible dbserver -i hosts -m shell -a "cat /etc/yum.repos.d/epel.repo"
#删除 epel yum源
ansible dbserver -i hosts -m yum_repository -a "name=epel state=absent"
systemd
# 重启systemd
ansible dbserver -i hosts -m systemd -a "daemon_reload=yes"
# 启动nginx服务
ansible dbserver -i hosts -m systemd -a "name=nginx state=started"
# 停止nginx服务
ansible dbserver -i hosts -m systemd -a "name=nginx state=stopped"
# 重启nginx服务
ansible dbserver -i hosts -m systemd -a "name=nginx state=restarted"
# 重启nginx服务
ansible dbserver -i hosts -m systemd -a "name=nginx enable=yes"
group
# 添加组
ansible dbserver -i hosts -m group -a "name=db_admin"
#删除组
ansible dbserver -i hosts -m group -a "name=db_admin state=absent"
user
# 加密密码
pass=$(echo "123456" | openssl passwd -1 -stdin)
# 添加用户 foo,密码123456
ansible all -i hosts -m user -a "name=foo password=${pass}"
#创建huangdengji用户,生成密钥对,秘钥类型:ecdsa
ansible all -i hosts -m user -a "name=huangdengji generate_ssh_key=yes ssh_key_type=ecdsa"
#创建用户tom,失效时间20211105 追加的db_admin组中
ansible all -i hosts -m user -a "name=tom expires=$(date +%s -d 20211105) groups=db_admin append=yes"
#创建用户tom,失效时间20211105 追加的db_admin,db2组中
ansible all -i hosts -m user -a "name=tom expires=$(date +%s -d 20211105) groups=db_admin,db2 append=yes"
file
# 创建文件
ansible all -i hosts -m file -a "path=/tmp/foo.conf state=touch"
#创建文件,指定group、owner
ansible all -i hosts -m file -a "path=/tmp/foo.conf state=touch group=0644 group=nobody owner=nobody"
#创建软连接
ansible all -i hosts -m file -a "src=/tmp/foo.conf dest=/tmp/link.con state=link"
#创建目录
ansible all -i hosts -m file -a "path=/tmp/testdir state=directory"
#删除软连接
ansible all -i hosts -m file -a "path=/tmp/link.conf state=absent"
#删除文件夹
ansible all -i hosts -m file -a "path=/tmp/testdir state=absent"
#删除文件
ansible all -i hosts -m file -a "path=/tmp/foo.conf state=absent"
cron
#添加定时任务
ansible all -i hosts -m cron -a "name='create new job' minute='0' job='ls -alh > /dev/null'"
#删除定时任务
ansible all -i hosts -m cron -a "name='create new job' state=absent"
debug
#变量打印
ansible all -i hosts -m debug -a "var=role" -e "role=web"
#格式化变量打印
ansible all -i hosts -m debug -a "msg='role is {{role}}'" -e "role=web"
template
cat >hello_word.j2 <<EOF
Hello {{var}} !!!
EOF
# 模板方式复制文件
ansible all -i hosts -m template -a "src=hello_word.j2 dest=/tmp/hello_word.txt" -e "var=word"
# 查看复制文件
ansible all -i hosts -a "cat /tmp/hello_word.txt"
lineinfile
#删除 Hello开头的一行
ansible all -i hosts -m lineinfile -a "path=/tmp/hello_word.txt regexp='^Hello' state=absent"
#替换 Hello开头的一行
ansible all -i hosts -m lineinfile -a "path=/tmp/hello_word.txt regexp='^Hello' line='are you a pig?' state=present"
blockinfile
#/tmp/hello_word.txt追加两行
ansible all -i hosts -m blockinfile -a "path=/tmp/hello_word.txt block='i am girl\nyou know a?'"
#/tmp/hello_word.txt 删除追加的两行
ansible all -i hosts -m blockinfile -a "path=/tmp/hello_word.txt block='i am girl\nyou know a?' state=absent"
全局变量
cat >a.json <<EOF
{"name1":"zhangsan","type":"school"}
EOF
ansible all -i localhost, -m debug -a "msg='name1 is {{name1}}, type is {{type}}'" -e @a.json
cat >a.yaml <<EOF
---
name1: hdj
type: home
...
EOF
ansible all -i localhost, -m debug -a "msg='name1 is {{name1}}, type is {{type}}'" -e @a.yaml
剧本变量
cat >playbook/testplay_vars.yaml <<EOF
---
- name: test play vars
hosts: all
vars:
user: lilei
home: /home/lilei
tasks:
- name: create the user {{user}}
user:
name: "{{user}}"
home: "{{home}}"
...
EOF
ansible-playbook -i root@210.26.116.128, /home/deploy/.py3-a2.9-env/workspace/playbook/testplay_vars.yaml -C
###资产变量
cat >hosts_use_vars <<EOF
[webserver]
root@210.26.116.128 var1=test1 var2=test2
root@210.26.116.98
EOF
ansible root@210.26.116.128 -i hosts_use_vars -m debug -a "msg='{{var1}} {{var2}}'"
#资产变量 组变量
cat >hosts_use_vars <<EOF
[webserver]
root@210.26.116.128
root@210.26.116.98
[webserver:vars]
home="/home/centos"
EOF
ansible all -i hosts_use_vars -m debug -a "msg='{{home}}'"
# 资产变量 主机变量 组变量 ,主机变量优先主机组变量
cat >hosts_use_var_vars <<EOF
[webserver]
root@210.26.116.128 user=test
root@210.26.116.98
[webserver:vars]
user="centos"
EOF
ansible all -i hosts_use_var_vars -m debug -a "msg='{{user}}'"
# 资产变量 变量继承
cat >hosts_use_var_extends <<EOF
[webserver]
root@210.26.116.128
[dbserver]
root@210.26.116.98
[allserver]
[allserver:children]
webserver
dbserver
[allserver:vars]
user="centos"
EOF
ansible all -i hosts_use_var_extends -m debug -a "msg='{{user}}'"
inventory内置变量
cat >hosts_use_inventory_var_pass <<EOF
[webserver_centos]
210.26.116.128 ansible_ssh_user=centos ansible_ssh_pass="hdj123!2"
[dbserver_centos]
210.26.116.90 ansible_ssh_user=centos ansible_ssh_pass="hdj123!2"
EOF
ansible all -i hosts_use_inventory_var_pass -m shell -a "id"
facts变量
ansible all -i hosts_use_inventory_var_pass -c local -m setup
# facts 过滤
ansible all -i hosts_use_inventory_var_pass -m setup -a "filter=*memory*"
ansible all -i hosts_use_inventory_var_pass -m setup -a "filter=*mount*"
#facts变量使用
cat >facts.yaml <<EOF
---
- name: print facts variable
hosts: all
tasks:
- name: print facts variable
debug:
msg: "Thre default ipv4 address is {{ansible_default_ipv4.address}}"
EOF
ansible-playbook -i hosts facts.yaml
#关闭facts变量收集 gather_facts: no
cat >facts_no.yaml <<EOF
---
- name: pwd ~
hosts: all
gather_facts: no
remote_user: root
tasks:
- name: pwd ~
shell: "ls /"
EOF
ansible-playbook -i 210.26.116.128, facts_no.yaml
变量注册
cat >facts_register.yaml <<EOF
---
- name: install a package and print the result
hosts: all
gather_facts: no
tasks:
- name: install nginx package
yum: name=nginx state=present
register: install_result
- name: print result
debug: var=install_result
EOF
ansible-playbook -i hosts facts_register.yaml
#变量优先级: -e全局变量 > playbook.yaml中变量 > 资产主机变量 > 资产组变量
cat >facts_priority.yaml <<EOF
---
- name: test variable priority
hosts: all
vars:
user: mysql
tasks:
- name: print the user value
debug: msg='the value is {{user}}'
EOF
ansible-playbook -i hosts_use_var_vars facts_priority.yaml -e "user=www"
ansible-playbook -i hosts_use_var_vars facts_priority.yaml
条件判断when
cat >site.yaml <<EOF
---
- name: test when playbook example
hosts: webserver
gather_facts: no
tasks:
- name: yum nginx
yum: name=nginx state=present
- name: update nginx conf
copy: src=nginx.conf dest=/etc/nginx/
- name: check nginx syntax
shell: /usr/sbin/nginx -t
register: nginxSyntax
- name: print nginx syntax
debug: var=nginxSyntax.rc
- name: start nginx server
service: name=nginx state=started
when: nginxSyntax.rc == 0
EOF
ansible-playbook -i hosts site.yaml
tags
cat >site.yaml <<EOF
---
- name: test when,with_item playbook example
hosts: webserver
gather_facts: no
vars:
createUser:
- tomcat
- www
- mysql
tasks:
- name: create user
user: name="{{item}}" state=present
with_items: "{{createUser}}"
- name: yum nginx
yum: name=nginx state=present
- name: update nginx conf
copy: src=nginx.conf dest=/etc/nginx/
tags: updateconfig
- name: check nginx syntax
shell: /usr/sbin/nginx -t
register: nginxSyntax
tags: updateconfig
- name: check nginx running
stat: path=/var/run/nginx.pid
register: nginxrunning
tags: updateconfig
- name: print nginx syntax
debug: var=nginxSyntax.rc
tags: updateconfig
- name: print nginx running
debug: var=nginxrunning
tags: updateconfig
- name: start nginx server
service: name=nginx state=started
when:
- nginxSyntax.rc == 0
- nginxrunning.stat.exists == false
tags: updateconfig
- name: restart nginx server
service: name=nginx state=restarted
when:
- nginxSyntax.rc == 0
- nginxrunning.stat.exists == true
tags: updateconfig
EOF
#只执行 updateconfig tag的task。
ansible-playbook -i hosts site.yaml -t updateconfig
handlers
cat >site.yaml <<EOF
---
- name: test when,with_item playbook example
hosts: webserver
gather_facts: no
vars:
createUser:
- tomcat
- www
- mysql
tasks:
- name: create user
user: name="{{item}}" state=present
with_items: "{{createUser}}"
- name: yum nginx
yum: name=nginx state=present
- name: update nginx conf
copy: src=nginx.conf dest=/etc/nginx/
tags: updateconfig
notify: restart nginx server
- name: check nginx syntax
shell: /usr/sbin/nginx -t
register: nginxSyntax
tags: updateconfig
- name: check nginx running
stat: path=/var/run/nginx.pid
register: nginxrunning
tags: updateconfig
- name: print nginx syntax
debug: var=nginxSyntax.rc
tags: updateconfig
- name: print nginx running
debug: var=nginxrunning
tags: updateconfig
- name: start nginx server
service: name=nginx state=started
when:
- nginxSyntax.rc == 0
- nginxrunning.stat.exists == false
tags: updateconfig
handlers:
- name: restart nginx server
service: name=nginx state=reloaded
when:
- nginxSyntax.rc == 0
- nginxrunning.stat.exists == true
tags: updateconfig
EOF
#只执行 updateconfig tag的task,当nginx.conf改变了才触发重启服务task
ansible-playbook -i hosts site.yaml -t updateconfig
jinja2
cat >nginx.j2 <<EOF
user root;
{# get cpu process #}
worker_processes {{ ansible_processor_vcpus }};
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
client_max_body_size 100m;
server {
listen 8888;
server_name {{ ansible_default_ipv4.address }};
#autoindex on;
root /www;
location / {
root /www/site;
index index.html index.htm;
}
}
}
EOF
#tags-handlers-template
cat >template_nginx_conf.yaml <<EOF
---
- name: test when,with_item,template playbook example
hosts: webserver
vars:
createUser:
- tomcat
- www
- mysql
tasks:
- name: create user
user: name="{{item}}" state=present
with_items: "{{createUser}}"
- name: yum nginx
yum: name=nginx state=present
- name: update nginx conf
template: src=nginx.j2 dest=/etc/nginx/nginx.conf
tags: updateconfig
notify: restart nginx server
- name: check nginx syntax
shell: /usr/sbin/nginx -t
register: nginxSyntax
tags: updateconfig
- name: check nginx running
stat: path=/var/run/nginx.pid
register: nginxrunning
tags: updateconfig
- name: print nginx syntax
debug: var=nginxSyntax.rc
tags: updateconfig
- name: print nginx running
debug: var=nginxrunning
tags: updateconfig
- name: start nginx server
service: name=nginx state=started
when:
- nginxSyntax.rc == 0
- nginxrunning.stat.exists == false
tags: updateconfig
handlers:
- name: restart nginx server
service: name=nginx state=reloaded
when:
- nginxSyntax.rc == 0
- nginxrunning.stat.exists == true
tags: updateconfig
EOF
#根据nginx.j2模板替换CPU核心数和服务器ip地址
ansible-playbook -i hosts template_nginx_conf.yaml -t updateconfig
ansible all -i root@210.26.116.90, -m shell -a "cat /etc/nginx/nginx.conf"
role
mkdir -p role/nginx
cd role/nginx/ || exit
mkdir {files,handles,tasks,templates,vars}
#for d in $(ls); do touch "${d}"/main.yaml; done
#rm -rf nginx/files/main.yaml
cp ../nginx.j2 nginx/templates/
cat >nginx/handles/main.yaml <<EOF
---
- name: restart nginx server
service: name=nginx state=reloaded
when:
- nginxSyntax.rc == 0
- nginxrunning.stat.exists == true
tags: updateconfig
EOF
cat >nginx/tasks/main.yaml <<EOF
- name: create user
user: name="{{item}}" state=present
with_items: "{{createUser}}"
- name: yum nginx
yum: name=nginx state=present
- name: update nginx conf
template: src=nginx.j2 dest=/etc/nginx/nginx.conf
tags: updateconfig
notify: restart nginx server
- name: check nginx syntax
shell: /usr/sbin/nginx -t
register: nginxSyntax
tags: updateconfig
- name: check nginx running
stat: path=/var/run/nginx.pid
register: nginxrunning
tags: updateconfig
- name: print nginx syntax
debug: var=nginxSyntax.rc
tags: updateconfig
- name: print nginx running
debug: var=nginxrunning
tags: updateconfig
- name: start nginx server
service: name=nginx state=started
when:
- nginxSyntax.rc == 0
- nginxrunning.stat.exists == false
tags: updateconfig
EOF
cat >nginx/vars/main.yaml <<EOF
createUser:
- tomcat
- www
- mysql
EOF
cat >nginx_deploy.yaml <<EOF
---
- name: role deploy nginx
hosts: webserver
roles:
- nginx
EOF
cd ..
ansible-playbook -i hosts role/nginx_deploy.yaml
#目录结构
tree role
# role
# ├── nginx
# │ ├── files
# │ │ └── nginx.j2
# │ ├── handles
# │ │ └── main.yaml
# │ ├── tasks
# │ │ └── main.yaml
# │ ├── templates
# │ │ ├── main.yaml
# │ │ └── nginx.j2
# │ └── vars
# │ └── main.yaml
# └── nginx_deploy.yaml
# 6 directories, 7 files
import role
cat >role/nginx_deploy_import_role.yaml <<EOF
---
- name: role deploy inport role nginx playbook example
hosts: webserver
tasks:
- debug:
msg: "befor we run our role"
- import_role:
name: nginx
- debug:
msg: "agter we run our role"
EOF
ansible-playbook -i hosts role/nginx_deploy_import_role.yaml
ansible-playbook -i hosts role/nginx_deploy_import_role.yaml -t updateconfig
#此时目录结构
tree role
# role
# ├── nginx
# │ ├── files
# │ │ └── nginx.j2
# │ ├── handles
# │ │ └── main.yaml
# │ ├── tasks
# │ │ └── main.yaml
# │ ├── templates
# │ │ ├── main.yaml
# │ │ └── nginx.j2
# │ └── vars
# │ └── main.yaml
# ├── nginx_deploy_import_role.yaml
# └── nginx_deploy.yaml
# 6 directories, 8 files
ansible-galaxy
#https://galaxy.ansible.com/
#下载nginx role
ansible-galaxy collection install community.mysql
#初始化huangdengji.nginx role
ansible-galaxy init huangdengji.nginx
#得到目录
tree huangdengji.nginx
# huangdengji.nginx
# ├── defaults
# │ └── main.yml
# ├── files
# ├── handlers
# │ └── main.yml
# ├── meta
# │ └── main.yml
# ├── README.md
# ├── tasks
# │ └── main.yml
# ├── templates
# ├── tests
# │ ├── inventory
# │ └── test.yml
# └── vars
# └── main.yml
# 8 directories, 8 files
ansible优化
开启ssh长连接
#去掉 ansible.cfg中ssh下的 长连接配置前的 #,修改ControlPersist的长连接断开时长值,下面这句
#ssh_args = -C -o ControlMaster=auto -o ControlPersist=86400s
cat >ping.yaml <<EOF
---
- name: ping
hosts: all
tasks:
- ping:
EOF
#执行一次ping后,ss -nat #可以看到ESTAB 连接
ansible-playbook -i hosts ping.yaml
开启pipeline
#ansible.cfg 添加:
#pipelining = True
#执行ping,看不到put
ansible-playbook -i hosts ping.yaml -vvv
–limit
#使用--limit,可以覆盖inventory中的选择器
ansible-playbook -i hosts ping.yaml --limit dbserver -vvv
fact 缓存本地文件中
#ansible.cfg 添加:
# gathering = smart #智能方式获取fact
# fact_caching = jsonfile #json文件方式缓存
# fact_caching_connection=/dev/shm/ansiable_fact_cache/ #缓存地址
# fact_caching_timeout=120 #缓存120秒后失效
#配置之后,执行ansible命令后,120秒内再不重新获取fact,直接从本地/dev/shm/ansiable_fact_cache/目录中获取
fact 缓存redis中
#ansible.cfg 添加:
# gathering = smart #智能方式获取fact
# fact_caching = reids #redis方式缓存
# fact_caching_connection=localhost:6379:0:password #缓存地址 格式: 地址:端口:库索引:密码 此处密码不可以加双引号
# fact_caching_timeout=120 #缓存120秒后失效
#安装redis模块
pip install redis
#再执行ansible命令后,会将fact信息缓存到redis中
修改playbook默认返回为json
#ansible.cfg 添加:
# stdout_callback = json
#此时执行playbook后,返回json格式
#修改ad-hock默认返回为json
# bin_ansible_callbacks = True
#此时执行ad-hock后,返回json格式
inventory
多个inventory
#可以跟多个 -i
ansible -i 1.yaml -i 2.yaml xxxx
#可以跟一个目录,目录下的文件后者可以是 yaml/yml/json/没有文件后缀
ansible -i inventory xxxx
#可以直接修改ansible.cfg 中inventory的值,此值可以接收文件或者目录,如果是目录,目录下的文件后者可以是 yaml/yml/json/没有文件后缀,支持可执行文件如:.py/.sh/等等
动态inventory脚本
cat >inventory.py <<EOF
#!/usr/bin/env python
import json
import sys
import argparse
def lists():
dic = {}
host_list = ['210.26.116.128', '210.26.116.98']
hosts_dict = {'hosts': host_list}
dic['computes'] = hosts_dict
return json.dumps(dic, indent=4)
def hosts(name):
dic = {'ansible_ssh_pass': 'hdj123!2'}
return json.dumps(dic)
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('-l', '--list', help='host list', action='store_true')
parser.add_argument('-H', '--host', help='hosts vars')
args = vars(parser.parse_args())
if args['list']:
print( lists() )
elif args['host']:
print( hosts(args['host']) )
else:
parser.print_help()
EOF
chmod +x inventory.py
inventory.py
inventory.py -H 210.26.116.90
inventory.py -l
ansible all -i inventory.py --list-host
log_files使用
查看log_plays说明
ansible-doc -t callback log_plays
调用日志写入文件
#ansible.cfg 添加:
# callback_whitelist = timer, log_plays #添加白名单
# [callback_log_plays]
# log_folder=/tmp/ansible/hosts/ #日志目录
#此时执行playbook之后就可以再/tmp/ansible/hosts/下找到命令的日志
#添加下行,ad-hock也会记录日志
# bin_ansible_callbacks = True
自定义回调插件
实现将回调信息写入到mysql库中
cat >~/.ansible/plugins/callback/mysql_log_plays.py <<EOF
# (C) 2021, huangdengji, <huangdengji@126.com>
from __future__ import (absolute_import, division, print_function)
from ansible.plugins.callback import CallbackBase
from ansible.parsing.ajson import AnsibleJSONEncoder
from ansible.module_utils.common._collections_compat import MutableMapping
from ansible.module_utils._text import to_bytes
from ansible.utils.path import makedirs_safe
from ansible.errors import AnsibleError
from ansible.module_utils._text import to_native
import json
import time
import os
import getpass
try:
import pymysql as mysqldb
pwd = "password"
database = "db"
except ImportError as e:
try:
import MySQLdb as mysqldb
pwd = "passwd"
database = "database"
except ImportError:
raise AnsibleError("can not find pymysql or mysqldb model")
__metaclass__ = type
DOCUMENTATION = '''
callback: mysql_log_plays
type: notification
short_description: write playbook output to mysql table
version_added: historical
description:
- This callback writes playbook output to a mysql table ,use create db table sql;
- CREATE DATABASE IF NOT EXISTS ansible_db CHARACTER SET utf8 COLLATE utf8_general_ci;
- USE ansible_db;
- CREATE TABLE $(ansible_send_result) ( $(id) bigint(20) NOT NULL AUTO_INCREMENT, $(host) varchar(200) COLLATE utf8mb4_unicode_ci NOT NULL, $(user) varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL, $(category) varchar(2000) COLLATE utf8mb4_unicode_ci NOT NULL, $(result) text COLLATE utf8mb4_unicode_ci NOT NULL, PRIMARY KEY ($(id)) ) ENGINE = InnoDB AUTO_INCREMENT = 14 CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
requirements:
- Whitelist in configuration
- A valid MySQL connection configuration
options:
log_host:
version_added: '2.9'
default: localhost
description: the mysql host.
env:
- name: ANSIBLE_MYSQL_LOG_HOST
ini:
- section: callback_mysql_log_plays
key: log_host
log_port:
version_added: '2.9'
default: 3306
description: the mysql port.
env:
- name: ANSIBLE_MYSQL_LOG_PORT
ini:
- section: callback_mysql_log_plays
key: log_port
type: int
log_user:
version_added: '2.9'
default: root
description: the mysql user.
env:
- name: ANSIBLE_MYSQL_LOG_USER
ini:
- section: callback_mysql_log_plays
key: log_user
log_pwd:
version_added: '2.9'
default: 123456
description: the mysql user password.
env:
- name: ANSIBLE_MYSQL_LOG_PWD
ini:
- section: callback_mysql_log_plays
key: log_pwd
log_db:
version_added: '2.9'
default: ansible
description: the mysql database.
env:
- name: ANSIBLE_MYSQL_LOG_DB
ini:
- section: callback_mysql_log_plays
key: log_db
log_table:
version_added: '2.9'
default: ansible_send_result
description: the mysql host.
env:
- name: ANSIBLE_MYSQL_LOG_TABLE
ini:
- section: callback_mysql_log_plays
key: log_table
'''
# NOTE: in Ansible 1.2 or later general logging is available without
# this plugin, just set ANSIBLE_LOG_PATH as an environment variable
# or log_path in the DEFAULTS section of your ansible configuration
# file. This callback is an example of per hosts logging for those
# that want it.
class CallbackModule(CallbackBase):
"""
logs playbook results, per host, in /var/log/ansible/hosts
"""
CALLBACK_VERSION = 2.0
CALLBACK_TYPE = 'notification'
CALLBACK_NAME = 'mysql_log_plays'
CALLBACK_NEEDS_WHITELIST = True
TIME_FORMAT = "%b %d %Y %H:%M:%S"
MSG_FORMAT = "%(now)s - %(category)s - %(data)s\n\n"
def __init__(self):
super(CallbackModule, self).__init__()
def set_options(self, task_keys=None, var_options=None, direct=None):
super(CallbackModule, self).set_options(
task_keys=task_keys, var_options=var_options, direct=direct)
self.log_host = self.get_option("log_host")
self.log_port = self.get_option("log_port")
self.log_user = self.get_option("log_user")
self.log_pwd = self.get_option("log_pwd")
self.log_db = self.get_option("log_db")
self.log_table = self.get_option("log_table")
self.user = getpass.getuser()
def _get_connect(self):
db_cfg = {
"host": self.log_host,
"port": self.log_port,
"user": self.log_user,
pwd: self.log_pwd,
database: self.log_db
}
try:
db = mysqldb.connect(**db_cfg)
cursor = db.cursor()
except Exception as e:
raise AnsibleError("%s" % to_native(e))
return db, cursor
def log2mysql(self, host, category, data):
if isinstance(data, MutableMapping):
if '_ansible_verbose_override' in data:
# avoid logging extraneous data
data = 'omitted'
else:
data = data.copy()
invocation = data.pop('invocation', None)
data = json.dumps(data, cls=AnsibleJSONEncoder)
if invocation is not None:
data = json.dumps(invocation) + " => %s " % data
sql = """
insert into {}(host,user,category,result)
values(%s,%s,%s,%s)
""".format(self.log_table)
db, cursor = self._get_connect()
try:
cursor.execute(sql, (host, self.user, category, data))
db.commit()
except Exception as e:
raise AnsibleError("%s" % to_native(e))
finally:
cursor.close()
db.close()
def runner_on_failed(self, host, res, ignore_errors=False):
self.log2mysql(host, 'FAILED', res)
def runner_on_ok(self, host, res):
self.log2mysql(host, 'OK', res)
def runner_on_skipped(self, host, item=None):
self.log2mysql(host, 'SKIPPED', '...')
def runner_on_unreachable(self, host, res):
self.log2mysql(host, 'UNREACHABLE', res)
def runner_on_async_failed(self, host, res, jid):
self.log2mysql(host, 'ASYNC_FAILED', res)
def playbook_on_import_for_host(self, host, imported_file):
self.log2mysql(host, 'IMPORTED', imported_file)
def playbook_on_not_import_for_host(self, host, missing_file):
self.log2mysql(host, 'NOTIMPORTED', missing_file)
EOF
自定义插件调用
#/etc/ansible/ansible.cfg中加入下面配置
# callback_whitelist 后面追加mysql_log_plays
# [callback_mysql_log_plays]
# log_host=xx
# log_port=3306
# log_db=ansible_db
# log_user=root
# log_pwd=xx
# log_table=ansible_send_result
#下面这句看mysql_log_plays的帮助文档
ansible-doc -t callback mysql_log_plays
#之后所有执行都会写入到mysql表中