Zabbix api概述
• Zabbix API允许你以编程方式检索和修改Zabbix的配置,并提供对历史数据的访问。它广泛用于:
– 创建新的应用程序以使用Zabbix
– 将Zabbix与第三方软件集成
– 自动执行常规任务
JSON-RPC
• Zabbix API是基于Web的API,作为Web前端的一部分提供。它使用JSON-RPC 2.0协议,这意味着两件事:
– 该API包含一组独立的方法
– 客户端和API之间的请求和响应使用JSON格式进行编码
API结构
• Zabbix API包含许多方法,这些方法都名义上分组为单组的API
• 每个方法执行一个特定任务。例如,方法host.create 隶属于 host 这个API ,用于创建新主机
• 历史上,API有时被称为“类”
• 大多数API至少包含四种方法: get,、create、update 和 delete ,分别是检索、创建、更新和删除数据。但是某些API提供一套完全不同的一组方法。
执行请求
• 设置前端后,,就可以使用远程HTTP请求来调用API。为此,需要向api_jsonrpc.php 位于前端目录中的文件发送HTTP POST请求。
• 请求的 Content-Type 头部必须设置为以下值之一:
– application/json-rpc
– application/json
– application/jsonrequest
官方文档页:https://www.zabbix.com/documentation/3.4/zh/manual
这里演示的环境路径是:/var/www/html/
那么zabbix api地址是:http://192.168.2.55/api_jsonrpc.php
通过zabbix提供的API接口,就可以使用python与其交互
import requests
import json
url = 'http://192.168.2.55/api_jsonrpc.php'
headers = {'Content-Type': 'application/json-rpc'}
###################################
# 获取zabbix api版本信息
# data = {
# "jsonrpc": "2.0", # zabbix固定值
# "method": "apiinfo.version", # 官方手册页上查询到的
# "params": [], # 参数
# "id": 101 # 作业ID,随便指定一个值即可
# }
###################################
#工作流程
# • 在访问大多数Zabbix中的任何数据之前,需要登录并获取身份验证令牌
# • 取得令牌后,访问其他数据只要出示该令牌即可,不需要再进行身份验证
# • 通过zabbix api提供的各种方法实现数据的检索、项目的创建等
# 获取令牌,使用 user.login 方法登录并获取身份验证令牌
#jsonrpc - API使用的JSON-RPC协议的版本; Zabbix API实现JSON-RPC版本2.0
#• method - 调用的API方法
#• params - 将被传递给API方法的参数
#• id - 请求的任意标识符
#• auth -用户认证令牌; 因为我们还没有一个,它的设置None
#• 如果你正确提供了凭据,API返回的响应将包含用户
身份验证令牌
# data = {
# "jsonrpc": "2.0",
# "method": "user.login",
# "params": {
# "user": "admin",
# "password": "123456"
# },
# "id": 1
# }
# 7f3dd136e378e30935a83ae0ceea8099
##################################
#检索主机
#• 有一个有效的用户身份验证令牌,可以用来访问Zabbix中的数据
#• 使用 host.get 方法检索所有已配置主机的ID、主机名和接口。auth 属性设置为获得的身份验证令牌
# 获取主机信息
# data = {
# "jsonrpc": "2.0",
# "method": "host.get",
# "params": {
# "output": "extend",
# "filter": {
# # "host": [
# # "Zabbix server",
# # "Linux server"
# # ]
# }
# },
# "auth": "7f3dd136e378e30935a83ae0ceea8099",
# "id": 1
# }
###################################
# 删除主机
# data = {
# "jsonrpc": "2.0",
# "method": "host.delete",
# "params": [
# "10255",
# ],
# "auth": "7f3dd136e378e30935a83ae0ceea8099a",
# "id": 1
# }
###################################
# 取出Linux Servers组号
# data = {
# "jsonrpc": "2.0",
# "method": "hostgroup.get",
# "params": {
# "output": "extend",
# "filter": {
# "name": [
# "Linux servers"
# ]
# }
# },
# "auth": "7f3dd136e378e30935a83ae0ceea8099",
# "id": 1
# }
# groupid: 2
###################################
# 取出Template OS Linux模板的ID
# data = {
# "jsonrpc": "2.0",
# "method": "template.get",
# "params": {
# "output": "extend",
# "filter": {
# "host": [
# "Template OS Linux",
# ]
# }
# },
# "auth": "7f3dd136e378e30935a83ae0ceea8099",
# "id": 1
# }
# 'templateid': '10001'
###################################
# 创建主机
data = {
"jsonrpc": "2.0",
"method": "host.create",
"params": {
"host": "nsd1812web1",
"interfaces": [
{
"type": 1,
"main": 1,
"useip": 1,
"ip": "192.168.4.2",
"dns": "",
"port": "10050"
}
],
"groups": [
{
"groupid": "2"
}
],
"templates": [
{
"templateid": "10001"
}
],
"inventory_mode": 0,
"inventory": {
"macaddress_a": "123456789012",
"macaddress_b": "fsdalkjfsdaljfdsa"
}
},
"auth": "7f3dd136e378e30935a83ae0ceea8099",
"id": 1
}
###################################
r = requests.post(url, data=json.dumps(data), headers=headers)
print(r.json())
############################################################################
Ansible简介
• Ansible是一个配置管理和配置工具,类似于Chef,Puppet或Salt
• 这是一款很简单也很容易入门的部署工具,它使用SSH连接到服务器并运行配置好的任务
• 服务器上不用安装任何多余的软件,只需要开启ssh,所有工作都交给client端的ansible负责
准备环境,启动三台虚拟机:
node4.tedu.cn | 192.168.4.4/24 |
---|---|
node5.tedu.cn | 192.168.4.5/24 |
node6.tedu.cn | 192.168.4.6/24 |
名称解析(在192.168.4.254主机上配置,并将配置后的/etc/hosts文件拷贝至以上3台主机对应的目录):
[root@room9pc01 ~]# for i in {4..6}
> do
> echo -e "192.168.4.$i\tnode$i.tedu.cn\tnode$i" >>/etc/hosts
> done
收集主机密钥:
[root@room9pc01 ~]# ssh-keyscan 192.168.4.{4..6} node{4..6} node{4..6}.tedu.cn >> ~/.ssh/known_hosts
安装ansible
[root@room9pc01 ansible_pkg]# ls
ansible-2.7.2.tar.gz
asn1crypto-0.24.0-py2.py3-none-any.whl
bcrypt-3.1.4-cp36-cp36m-manylinux1_x86_64.whl
cffi-1.11.5-cp36-cp36m-manylinux1_x86_64.whl
cryptography-2.4.2-cp34-abi3-manylinux1_x86_64.whl
idna-2.7-py2.py3-none-any.whl
Jinja2-2.10-py2.py3-none-any.whl
MarkupSafe-1.1.0-cp36-cp36m-manylinux1_x86_64.whl
paramiko-2.4.2-py2.py3-none-any.whl
pyasn1-0.4.4-py2.py3-none-any.whl
pycparser-2.19.tar.gz
PyNaCl-1.3.0-cp34-abi3-manylinux1_x86_64.whl
PyYAML-3.13.tar.gz
setuptools-40.6.2-py2.py3-none-any.whl
six-1.11.0-py2.py3-none-any.whl
[root@room9pc01 ansible_pkg]# pip3 install *
配置ansible的基础应用环境
[root@room9pc01 ~]# mkdir myansible
[root@room9pc01 ~]# cd myansible
[root@room9pc01 myansible]# vim ansible.cfg
[defaults]
inventory = hosts
remote_user = root
[root@room9pc01 myansible]# vim hosts
[dbservers]
node4.tedu.cn
[webservers]
node5.tedu.cn
node6.tedu.cn
[root@room9pc01 myansible]# ansible all -m ping -k
使用playbook
• Playbooks是Ansible的配置、部署、编排语言。
• 它们可以被描述为一个需要希望远程主机执行命令的方案,或者一组程序运行的命令集合
• Playbook由一到多个Play组成
• 每个play可以指定哪些主机执行哪些任务
• 执行任务一般通过调用模块来实现
Yaml简介
• Playbooks的格式是YAML
• 语法做到最小化,意在避免 playbooks 成为一种编程语言或是脚本
• 使用 YAML 是因为它像 XML 或 JSON 是一种利于人们读写的数据格式
Yaml语法
• 每一个 YAML 文件都是从一个列表开始
• 列表中的每一项都是一个键值对, 通常它们被称为一个“哈希 或“字典”
• 所有的 YAML 文件开始行都应该是 —。这是 YAML 格式的一部分,表明一个文件的开始
• 列表中的所有成员都开始于相同的缩进级别,并且使用一个 "- " 作为开头(一个横杠和一个空格)
• 一个字典是由一个简单的 键: 值 的形式组成(冒号后面必须是一个空格)
配置VIM
• Yaml的缩进不能使用tab键
• 建议缩进为两个空格
• 为了实现yml文件按tab键缩进两个空格,可以按以下方式对vim进行定制
[root@room9pc01 myansible]# vim ~/.vimrc
set ai
set ts=4
set et
set encoding=utf8
autocmd FileType yaml setlocal sw=2 ts=2 et ai
创建playbook,实现免密登陆
[root@room9pc01 myansible]# ansible-doc autorized_key
[root@room9pc01 myansible]# ssh-keygen //生成密钥
[root@room9pc01 myansible]# vim auth.yml
---
- name: user auth key
hosts: all
tasks:
- name: upload root pub key
authorized_key:
user: root
state: present
key: "{{ lookup('file', '/root/.ssh/id_rsa.pub') }}"
[root@room9pc01 myansible]# ansible-playbook --syntax-check auth.yml //检查yml脚本语法
playbook: auth.yml
[root@room9pc01 myansible]# ansible-playbook auth.yml -k
通过playbook配置yum
[root@room9pc01 myansible]# mkdir files
[root@room9pc01 myansible]# vim files/server.repo
[server]
name= server
baseurl=ftp://192.168.4.254/rhel7
enabled=1
gpgcheck=0
[root@room9pc01 myansible]# vim yum.yml
---
- name: upload yum repo file
hosts: all
tasks:
- name: upload server.repo
copy:
src: files/server.repo
dest: /etc/yum.repos.d/server.repo
[root@room9pc01 myansible]# ansible-playbook --syntax-check yum.yml
[root@room9pc01 myansible]# ansible-playbook yum.yml
[root@room9pc01 myansible]# ansible dbservers -m yum -a "list=mariadb-server" //检查web服务器是否安装了mariadb-server
案例:通过playbook在dbservers上配置mariadb,在webservers上配置apache
[root@room9pc01 myansible]# vim lamp.yml
---
- name: configure dbservers
hosts: dbservers
tasks:
- name: install mariadb
yum:
name: mariadb-server
state: present
- name: start mariadb
service:
name: mariadb
state: started
enabled: yes
- name: configure webservers
hosts: webservers
tasks:
- name: install apache
yum:
name: [httpd, php, php-mysql]
state: latest
- name: start httpd
service:
name: httpd
state: started
enabled: yes
[root@room9pc01 myansible]# ansible-playbook --syntax-check lamp.yml
[root@room9pc01 myansible]# ansible-playbook lamp.yml
#####################################################################################
ansible编程基础
ansible python api
官方手册页:https://docs.ansible.com/ ->Ansible Documentation -> 搜索python api。把python api example中的代码复制粘贴到adhoc.py
命名元组
• 命名元组与普通元组一样,有相同的表现特征,其添加的功能就是可以根据名称引用元组中的项
• collections 模块提供了namedtuple()函数,用于创建自定义的元组数据类型
>>> from collections import namedtuple
>>> Point = namedtuple('Point', ['x', 'y', 'z'])
>>> p1 = Point(10, 20, 25)
>>> len(p1)
3
>>> p1[0]
10
>>> p1[1:]
(20, 25)
>>> p1.x
10
>>> p1.y
20
>>> p1.z
25
Ansible常用属性
• from ansible.parsing.dataloader import DataLoader
– 用来加载解析yaml文件或JSON内容,并且支持vault的解密
• from ansible.vars.manager import VariableManager
– 管理变量的类,包括主机,组,扩展等变量
• from ansible.inventory.manager import InventoryManager
– 用于创建主机清单,主机清单的源采用配置文件或是逗号分开主机名字符串
• from ansible.playbook.play import Play
– 用于创建play对象,能够通过play_source提供的信息自动创建任务对象
• from ansible.executor.task_queue_manager import TaskQueueManager
– 用于处理进程池中的多进程。队列管理器负责加载play策略插件,以便在选定的主机上执行任务
• import ansible.constants as C
– 存储ansible一些预定义变量
ad-hoc模式
使用TaskQueueManager
• 创建TaskQueueManager实例,用于管理子进程、通过主机列表和任务建立对象
• TaskQueueManager需要主机清单参数、主机变量参数、连接选项等
• 不管是执行ad-hoc还是playbook都需要以下模块
#!/usr/bin/env python
import shutil
from collections import namedtuple
from ansible.parsing.dataloader import DataLoader
from ansible.vars.manager import VariableManager
from ansible.inventory.manager import InventoryManager
from ansible.playbook.play import Play
from ansible.executor.task_queue_manager import TaskQueueManager
import ansible.constants as C
play_source = dict(
name = "Ansible Play",
hosts = 'localhost',
gather_facts = 'no',
tasks = [
dict(action=dict(module='shell', args='mkdir /tmp/mytestdir'),
register='shell_out'),
]
)
play = Play().load(play_source, variable_manager=variable_manager,
loader=loader)
设置参数
• 运行命令时有很多参数要指定,这些参往往很长,可
以先把它们提前定义出来
Options = namedtuple('Options', ['connection', 'module_path', 'forks',
'become', 'become_method', 'become_user', 'check', 'diff'])
options = Options(connection='local', module_path=[''], forks=10,
become=None, become_method=None, become_user=None,
check=False, diff=False)
loader = DataLoader()
passwords = dict(vault_pass='secret')
inventory = InventoryManager(loader=loader, sources='localhost,')
variable_manager = VariableManager(loader=loader,
inventory=inventory)
######################################################################
[root@room9pc01 day03]# vim adhoc.py
import shutil
from collections import namedtuple
from ansible.parsing.dataloader import DataLoader
from ansible.vars.manager import VariableManager
from ansible.inventory.manager import InventoryManager
from ansible.playbook.play import Play
from ansible.executor.task_queue_manager import TaskQueueManager
import ansible.constants as C
# since API is constructed for CLI it expects certain options to always be set, named tuple 'fakes' the args parsing options object
# 此处定义了执行ansible命令时的选项
# connection定义连接方式,local表示本机,ssh表示ssh,smart表示自动选择
# module_path指定自定义的模块位置
# forks指定启动的进程数目
# become:如果使用普通用户远程登陆服务器,那么切换成其他用户该怎么切换
# check: 不真正执行操作,而是预言操作的结果
# diff 显示修改小文件前后的变化
Options = namedtuple('Options', ['connection', 'module_path', 'forks', 'become', 'become_method', 'become_user', 'check', 'diff'])
options = Options(connection='ssh', module_path=['/to/mymodules'], forks=10, become=None, become_method=None, become_user=None, check=False, diff=False)
# initialize needed objects
# DataLoader用于查找并解析yaml、json、ini文件,把它们转换成python的数据类型
loader = DataLoader() # Takes care of finding and reading yaml, json and ini files
# 设置密码
passwords = dict()
# create inventory, use path to host config file as source or hosts in a comma separated string
# 定义主机清单,可以将各主机用逗号隔开的字符串,也可以指定文件路径列表
# inventory = InventoryManager(loader=loader, sources='localhost,')
inventory = InventoryManager(loader=loader, sources=['myansible/hosts'])
# variable manager takes care of merging all the different sources to give you a unifed view of variables available in each context
# 变量管理器
variable_manager = VariableManager(loader=loader, inventory=inventory)
# create datastructure that represents our play, including tasks, this is basically what our YAML loader does internally.
play_source = dict(
name = "Ansible Play", # play的名字
hosts = 'webservers', # 指定在哪些主机上执行命令
gather_facts = 'no',
tasks = [
dict(action=dict(module='shell', args='ls'), register='shell_out'),
dict(action=dict(module='debug', args=dict(msg='{{shell_out.stdout}}')))
]
)
# Create play object, playbook objects use .load instead of init or new methods,
# this will also automatically create the task objects from the info provided in play_source
# 通过上面的配置,创建一个play
play = Play().load(play_source, variable_manager=variable_manager, loader=loader)
# Run it - instantiate task queue manager, which takes care of forking and setting up all objects to iterate over host list and tasks
# 创建任管理器,执行play
tqm = None
try:
tqm = TaskQueueManager(
inventory=inventory,
variable_manager=variable_manager,
loader=loader,
options=options,
passwords=passwords,
)
result = tqm.run(play) # most interesting data for a play is actually sent to the callback's methods
finally:
# we always need to cleanup child procs and the structres we use to communicate with them
if tqm is not None:
tqm.cleanup()
# Remove ansible tmpdir
shutil.rmtree(C.DEFAULT_LOCAL_TMP, True)
########################################################################################
[root@room9pc01 myansible]# vim adhoc2.py
import shutil
from collections import namedtuple
from ansible.parsing.dataloader import DataLoader
from ansible.vars.manager import VariableManager
from ansible.inventory.manager import InventoryManager
from ansible.playbook.play import Play
from ansible.executor.task_queue_manager import TaskQueueManager
import ansible.constants as C
def adhoc(sources=None, hosts=None, module=None, args=None):
Options = namedtuple('Options', ['connection', 'module_path', 'forks', 'become', 'become_method', 'become_user', 'check', 'diff'])
options = Options(connection='ssh', module_path=['/to/mymodules'], forks=10, become=None, become_method=None, become_user=None, check=False, diff=False)
loader = DataLoader()
passwords = dict()
inventory = InventoryManager(loader=loader, sources=sources)
variable_manager = VariableManager(loader=loader, inventory=inventory)
play_source = dict(
name="Ansible Play", # play的名字
hosts=hosts, # 指定在哪些主机上执行命令
gather_facts='no',
tasks=[
dict(action=dict(module=module, args=args), register='shell_out'),
]
)
play = Play().load(play_source, variable_manager=variable_manager, loader=loader)
tqm = None
try:
tqm = TaskQueueManager(
inventory=inventory,
variable_manager=variable_manager,
loader=loader,
options=options,
passwords=passwords,
)
result = tqm.run(play)
finally:
if tqm is not None:
tqm.cleanup()
shutil.rmtree(C.DEFAULT_LOCAL_TMP, True)
if __name__ == '__main__':
sources = ['hosts']
hosts = 'webservers'
module = 'shell'
args = 'useradd alice'
adhoc(sources, hosts, module, args)
[root@room9pc01 myansible]# python3 adhoc2.py
##############################################################################
[root@room9pc01 myansible]# vim runpb.py
from collections import namedtuple
from ansible.parsing.dataloader import DataLoader
from ansible.vars.manager import VariableManager
from ansible.inventory.manager import InventoryManager
from ansible.executor.playbook_executor import PlaybookExecutor
Options = namedtuple(
'Options',
[
'connection',
'remote_user',
'ask_sudo_pass',
'verbosity',
'ask_pass',
'module_path',
'forks',
'become',
'become_method',
'become_user',
'check',
'listhosts',
'listtasks',
'listtags',
'syntax',
'sudo_user',
'sudo',
'diff'
]
)
options = Options(
connection='smart',
remote_user=None,
ask_pass=None,
sudo_user=None,
forks=5,
sudo=None,
ask_sudo_pass=False,
verbosity=5,
module_path=None,
become=None,
become_method=None,
become_user=None,
check=False,
diff=False,
listhosts=None,
listtasks=None,
listtags=None,
syntax=None
)
loader = DataLoader()
passwords = dict()
def runpb(pb_path, sources):
inventory = InventoryManager(loader=loader, sources=sources)
variable_manager = VariableManager(loader=loader, inventory=inventory)
playbook = PlaybookExecutor(
playbooks=pb_path,
inventory=inventory,
variable_manager=variable_manager,
loader=loader,
options=options,
passwords=passwords
)
result = playbook.run()
return result
if __name__ == '__main__':
runpb(pb_path=['lamp.yml'], sources=['hosts'])
#####################################################################################################
ansible模块开发
官方模块
• Ansible官方已经提供了大量模块,在编写模块之前,可以查看是否已有现成模块
• 官方已发布模块
– http://docs.ansible.com/ansible/modules.html
• 官方正在开发的模块
– https://github.com/ansible/ansible/labels/module
模块执行流程
• 将模块文件读入内存,然后添加传递给模块的参数,最后将模块中所需要的类添加到内存,由zipfile压缩后,再由base64进行编码,写入到模板文件内
• 通过默认的连接方式(一般是ssh),ansible连接到远程主机,创建临时目录,并关闭连接
• 打开另外一个ssh连接,将模板文件以sftp方式传送到刚刚创建的临时目录中,写完后关闭连接
• 打开一个ssh连接将任务对象赋予可执行权限,执行成功后关闭连接
• 最后,ansible将再打开一个新连接来执行模块,并删除临时目录及其所有内容
• 模块的结果是从标准输出stdout中获取json格式的字符串。ansible将解析和处理此字符串
[root@room9pc01 myansible]# mkdir library //自定义模块目录
[root@room9pc01 myansible]# cd library/
[root@room9pc01 library]# pwd
/root/桌面/myansible/library
[root@room9pc01 library]# export ANSIBLE_LIBRARY=/root/桌面/myansible/library //使用 ANSIBLE_LIBRARY环境变量指定自定义模块存放路径
编写模块,用于在远程主机上将一个文件拷贝到目标位置
[root@room8pc16 library]# vim mycopy.py
import shutil
from ansible.module_utils.basic import AnsibleModule
def main():
module = AnsibleModule(
argument_spec=dict(
yuan=dict(required=True, type='str'),
mubiao=dict(required=True, type='str')
)
)
shutil.copy(module.params['yuan'], module.params['mubiao'])
module.exit_json(changed=True)
if __name__ == '__main__':
main()
[root@room8pc16 myansible]# ansible dbservers -m mycopy -a "yuan=/etc/hosts mubiao=/tmp/zj.txt"
[root@node4 ~]# ls /tmp/zj.txt
/tmp/zj.txt
案例:
- 测试把一张图片放到web服务器的根目录下,如url是:http://192.168.4.5/people.jpg
- 通过ansible使用download模块,要求dbservers下载图片到/home下
[root@room9pc01 myansible]# ansible dbservers -m download -a "url=http://192.168.4.5/people.jpg local=/home/"
执行时报错,提示没有wget模块。原因是ansible会将download模块拷贝到远程dbservers服务器,在dbservers上执行download,但是dbservers上没有安装wget模块。因此需要在dbservers上安装wget模块
[root@room9pc01 ~]# pip3 download wget --trusted-host mirrors.163.com //下载wget模块
[root@room9pc01 ~]# scp wget-3.2.zip 192.168.4.4:/tmp
[root@node4 ~]# ls /tmp
zj.txt
wget-3.2.zip
[root@node4 ~]# cd /tmp
[root@node4 tmp]# unzip wget-3.2.zip
[root@node4 tmp]# cd wget-3.2/
[root@node4 wget-3.2]# python setup.py install //dbservers上安装wget模块
[root@node4 wget-3.2]# python
>>> import wget
>>>
########################################################################
[root@room9pc01 myansible]# cd library/
[root@room9pc01 library]# vim download.py
import wget
from ansible.module_utils.basic import AnsibleModule
def main():
module = AnsibleModule(
argument_spec=dict(
url=dict(required=True, type='str'),
local=dict(required=True, type='str')
)
)
wget.download(module.params['url'], module.params['local'])
module.exit_json(changed=True)
if __name__ == '__main__':
main()
[root@room9pc01 library]# cd ..
[root@room9pc01 myansible]# ansible dbservers -m download -a "url=http://192.168.4.5/people.jpg local=/home/" //ansible执行自定义download模块
node4.tedu.cn | CHANGED => {
"changed": true
}
[root@node4 ~]# ls /home //图片下载到dbservers对应目录下
lisi people.jpg
ansible-cmdb模块
用于将ansible收集下来的主机信息转换成html页面
[root@room9pc01 ansible-cmdb_pkgs]# pip3 install *
[root@room9pc01 ansible-cmdb_pkgs]# vim /usr/local/bin/ansible-cmdb
8 PY_BIN=$(which python3) # 第8行改为python3,默认是python2
[root@room9pc01 myansible]# ansible all -m setup --tree /tmp/out # 通过setup模块收集远程主机信息并保存到/tmp/out/目录
[root@room9pc01 myansible]# ansible-cmdb /tmp/out/ > /tmp/hosts.html # 利用ansible-cmdb分析/tmp/out/下的文件,生成html
[root@room9pc01 myansible]# firefox /tmp/hosts.html