自动化运维开发-ansible接口(ansible自动化运维实例)

网友投稿 314 2022-08-22


自动化运维开发-ansible接口(ansible自动化运维实例)

目录​

​​探测模块和工具 2​​​

​​存活扫描nmap|telnetlib 2​​​

​​主机登录探测pexpect|paramiko 2​​​

​​ansible运维 4​​​

​​ansible开发: 5​​​

​​核心类 5​​​

​​ad-hoc模式调用 6​​​

​​playbook模式调用 7​​​

​​callback改写 7​​​

​​自动化任务接口设计 9​​​

​​数据库事件记录和状态记录 9​​​

自动化资产扫描发现(服务端扫描发现):​

1、抽象与约定:​

主机类型,Centos4-6、Ubuntu12-14;​

判断是linux系统,22、202、2022;​

安全规则,开放允许探测协议和登录的限制;​

网络设备都开通了snmp服务,且community都已经统一;​

虚拟机不再运行容器等虚拟资产;​

2、整体探测流程:​

存活探测-->获取存活的ip列表;​

主机探测-->获取系统信息(SN、系统版本(cat /etc/issue+cat /etc/redhat-release|uname|lsb_release)、MAC(cat /sys/class/net/eth*/address|ifconfig eth0|ip a|esxcfg-vmknic -l)、主机名(hostname|uname -a|cat /etc/sysconfig/network)、服务器机型(dmidecode -s system-manufacturer|dmidecode -s system-product-name|dmidecode -s system-serial-number));​

主机关系探测-->识别宿主机和虚拟机关系;​

网络设备探测-->网络设备信息(SN、设备名等);​

cat /sys/class/net/[^vtlsb]*/address # 获取mac,排除v|t|l|s|b开头的​

esxcfg-vmknic -l | awk '{print $8}' | grep ':' # esxi主机​

cat /sys/class/net/[^vtlsb]*/address || esxcfg-vmknic -l | awk '{print $8}' | grep ':' # 前一条未执行成功再执行后一条​

yum -y install dmidecode​

探测协议:​


特性

用途

icmp

无连接

网络探测、网络质量

tcp

有连接

应用服务

资产扫描:​

服务器资产信息:硬件服务器、kvm服务器、esx虚拟机;​

未知设备ip列表:网络设备、其它设备;​

探测模块和工具​

存活扫描nmap|telnetlib​

nmap,是一款用于网络发现和安全审计的网络安全工具,pip install python-nmap==0.6.1;​

nmap -n -sP 192.168.8.70 # arp,在局域网内仅发送一个包,询问谁是8.70,在整个网段扫描时效率高,而ping发送2个包且是icmp;192.168.8.70上运行tcpdump -np -i eth0 src host 192.168.8.119;echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_all​

nmap -n -PE 192.168.8.70 # tcp,判断该主机哪些端口存活​

nmap -n -sP -PE 192.168.1.0/24 # arp和tcp都探测,从多个角度判断服务端的存活状态,且准确(即使服务端忽略或关闭icmp)​

import nmap​

nm = nmap.PortScanner()​

nm.scan(hosts='192.168.1.0/24', arguments="-n -sP -PE")​

nm.all_hosts() # ip列表​

import telnetlib​

tm = telnetlib.Telnet(host='192.168.1.101', port='22', timeout=4)​

txt = tm.read_until('\n', timeout=5) # 检测到换行​

re.search('ssh', txt)​

主机登录探测pexpect|paramiko​

用一系列的验证方式循环进行ssh登录,得到正确的登录方式;​

ssh -l root 192.168.1.101 -p 22 # 账号密码登录​

ssh -i /tmp/id_rsa -l test 192.168.1.101 -p 22 # 密钥登录,私钥​

pexpect,用来通过启动子程序,使用正则对程序输出作出特定响应,以此实现与其自动交互的py模块;​

缺陷,依赖终端命令的方式,不同的ssh登录环境兼容较差;​

核心类、函数:​

run(),直接进程运行,直接返回结果和状态;​

spawn(),启动子进程运行,有丰富的方法实现对子程序的控制,读取缓冲区,正则匹配成功(1发送指令(send|sendline|sendcontrol(char))读取缓冲区进入循环,2让出子进程会话终端接管(intract)进入终端交互模式),正则匹配不成功(timeout等待超时|pexpect.EOF子程序退出),打印输出匹配的缓冲区结果(before|after)​

import pexpect​

pexpect.run(command='ls /tmp', withexiststatus=1) # 命令执行后返回的结果和状态,二元组,1成功0失败​

ssh = pexpect.spanwn('ssh root@192.168.1.101 -p22') # 类的实例化,chk = pexpect.spawn(' ls -l /tmp/')同chk = pexpect.spawn('ls', ['-l', '/tmp/'])​

i = ssh.expect(['password:', 'continue connecting (yes/no)?'], timeout=5) # 缓冲区内容匹配,匹配成功返回0,没有匹配到则等待子程序超时,默认30s;支持正则ssh.expect('[p,P]assword:'),$在expect中就是本身的意义,不是正则中的结尾;匹配多个结果,ssh.expect([pexpect.TIMEOUT,pexpect.EOF,'password:']),返回匹配列表中的索引号,如匹配到了'password:'则返回2​

if i == 0:​

向子程序发送指令​

elif i == 1:​

ssh.sendline('yes\n')​

ssh.expect('password: ')​

ssh.sendline('pwd')​

index = ssh.expect(['#', pexpect.EOF, pexpect.TIMEOUT])​

if index == 0:​

print('logging in as root')​

终端会话,进入终端​

elif index == 1:​

print('logging process exit')​

elif index == 2:​

print('logging timeout exit')​

paramiko,基于py实现的ssh远程安全连接,用于ssh远程执行命令、文件传输等功能的ssh客户端模块;​

import paramiko​

ssh = paramiko.SSHClient()​

ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())​

ssh.connect('192.168.1.101', '22', 'test', '123456') # 账号密码​

key = paramiko.RSAKey.from_private_key_file('/tmp/id_rsa')​

ssh.connect('192.168.1.101', '22', 'test', pkey=key) # 密钥​

stdin, stdout, stdout = ssh.exec_command('ls /tmp/')​

stdout.read()​

资产扫描-snmp网络设备​

资产扫描-docker容器扫描​

docker ps | awk -F '->' '{print $1}' | grep -v 'CONTAINER' | awk 'BEGIN{FS~/s+/;}{print $NF" "$1" "$2;}' | sed s/0.0.0.0://​

资产扫描-KVM虚拟机扫描​

是否存在进程qume-kvm|docker-containerd|vmx,vmx为vmware宿主机;​

cat /sys/class/net/vnet0/address # 虚机和宿主机的mac相同,判断哪些虚机在一物理机上​

资产扫描-SDK调用扫描ESXI​

dmidecode -s system-serial-number # 虚机的uuid,再通过sdk或api获取所拥有的虚机的uuid,ANSIBLE_CONFIG=/etc/ansible/ansible.cfg​

./ansible.cfg # 执行命令的当前路径​

~/ansible.cfg​

/etc/ansible/ansible.cfg​

ansible.cfg​

[defaults]​

inventory = /etc/ansible/hosts​

library = /usr/share/ansible​

forks = 5​

sudo_user = root​

remote_port = 22​

host_key_checking = False # 设置是否检查ssh主机的密钥​

timeout = 20​

log_path = /var/log/ansible.log # 默认不记录​

private_key_file = /path/to/file.pem # 用ssh私钥登录时使用的密钥路径​

/etc/ansible/hosts​

[test] # 组名​

192.168.1.11:22 ansible_ssh_user=root ansible_ssh_pass='123456' # yum -y install sshpass​

192.168.1.12:22 ansible_ssh_user=root ansible_ssh_private_key_file=/home/ssh_keys/id_rsa​

test1 ansible_ssh_host=192.168.1.13 ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_private_key_file=/home/ssh_keys/id_rsa # 别名+ssh用户+ssh私钥​

ansible [options]​

ansible-playbook playbook.yml [options]​

ansible all --list-hosts​

ansible 192.168.1.* -a 'ls /tmp'​

ad-hoc模式,短简命令(临时命令),多台主机上(查看某个进程是否启动|拷贝指定日志文件到本地);​

playbook模式;​

ansible开发:​

import ansible​

print(ansible.__version__) # 2.4.1.0​

核心类​

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​

from ansible.plugins.callback import CallbackBase​

核心类

用途

所在的模块路径

DataLoader

读取yaml|json格式的文件

ansible.parsing.dataloader

Play

存储执行hosts的角色信息

ansible.playbook.play

TaskQueueManager

ansible底层用到的任务队列

ansible.executor.task_queue_manager

PlaybookExecutor

核心类执行playbook剧本

ansible.executor.playbook_executor

CallbackBase

状态回调,各种成功|失败的状态

ansible.plugins.callback

InventoryManager

导入inventory文件

ansible.inventory.manager

VariableManager

存储各类变量信息

ansible.vars.manager

Host,Group

操作单个主机或主机组信息

ansible.inventory.host

InventoryManager --> VariableManager --> ad-hoc模式调用|playbook模式调用;​

loader = DataLoader()​

inventory = InventoryManager(loader=loader, sources=['/etc/ansible/hosts'])​

inventory.get_group_dict() # 查看主机组资源,返回字典,key为组名,value为主机列表,{'all': ['192.168.1.112', '192.168.1.113], 'test_group1': ['192.168.1.112'], 'test_group2': ['192.168.1.113']}​

inventory.get_hosts()​

inventory.add_host(host='192.168.1.122', port=22, group='test_group2') # 添加主机到指定主机组​

host=inventory.get_host(hostname='192.168.1.112') # 获取指定的主机对象​

variable = VariableManager(loader=loader, inventory=inventory)​

variable.get_vars() # 查看变量​

varialbe.get_vars(host=host)​

varialbe.set_host_variable(host=host, varname='ansible_ssh_pass', value='123456') # 设置主机变量​

varialbe.get_vars(host=host)​

variable.extra_vars={'myweb': 'test', 'myname': 'jowin'} # 设置扩展变量​

varialbe.get_vars(host=host)​

variable.get_vars()​

ad-hoc模式调用​

执行对象(命令)和模块,Play;​

资源资产配置清单,InventoryManager和VarialbeManager;​

执行选项,Options;​

loader = DataLoader()​

inventory = InventoryManager(loader=loader, source=['imoocc_hosts'])​

variable_manager = VariableManager(loader=loader, inventory=inventory)​

from collections import namedtuple​

Options = namedtuple('Options', ['connection', 'remote_user', 'ask_sudo_pass', 'verbosity', 'ack_pass', 'module_path', 'forks', 'become', 'become_method', 'become_user', 'check', 'listhosts', 'listtasks', 'listtags', 'syntax', 'sudo_user', 'sudo', 'diff'])​

options = Options(cnotallow='smart', remote_user=None, ack_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=False, listtasks=None, listtags=None, syntax=None) # smart表示连接远程主机,local连接本地主机​

play_source = dict(name='ansible play ad-hoc test', hosts='192.168.1.110', gateher_facts='no', tasks=[dict(actinotallow=dict(module='shell', args='touch /tmp/ad_hoc_test'))])​

play = Play().load(play_source, variable_manager=varialbe_manager, loader=loader)​

passwords = dict() # hosts文件中已定义了用户名和密码​

tqm = TaskQueueManager(inventory=inventory, variable_manager=varialbe_manager, loader=loader, optinotallow=options, passwords=passwords)​

result = tqm.run(play)​

playbook模式调用​

palybook = PlayBookExecutor(playbooks=['test.yml'], inventory=inventory, variable_manager=varialbe_manager, loader=loader, optinotallow=options, passwords=passwords)​

playbook.run()​

callback改写​

原因是为了自定义输出;​

通过子类继承CallbackBase父类;​

通过子类改写父类的部分方法,如v2_runner_on_unreacheable|v2_runner_on_ok|v2_runner_on_failed;​

class ModelResultsCollector(CallbackBase):​

def __init__(self, *args, **kwargs):​

super(ModelResultsCollector, self).__init__(*args, **kwargs)​

self.host_ok = {}​

self.host_failed = {}​

self.host_unreachable = {}​

def v2_runner_on_ok(self, result, *args, **kwargs):​

self.host_ok[result._host.get_name()] = result​

def v2_runner_on_failed(self, result, *args, **kwargs):​

self.host_failed[result._host.get_name()] = result​

def v2_runner_on_unreachable(self, result):​

self.host_unreachable[result._host.get_name()] = result​

callback = ModelResultsCollector()​

tqm = TaskQueueManager(inventory=inventory, variable_manager=variable_manager, loader=loader, optinotallow=options, passwords=passwords, stdout_callback=callback)​

result = tqm.run(play)​

print(callback.host_ok.items())​

result_raw = {'success': {}, 'failed': {}, 'unreachable': {}}​

for host, result in callback.host_ok.items():​

result_raw['success'][host] = result._result​

for host, result in callback.host_failed.items():​

result_raw['failed'][host] = result._result​

for host, result in callback.host_unreachable.items():​

result_raw['unreachable'][host] = result._result​

print(result_raw)​

class PlayBookResultsCollector(CallbackBase):​

CALLBACK_VERSION = 2.0​

def __init__(self, *args, **kwargs):​

super(PlayBookResultsCollector, self).__init__(*args, **kwargs)​

self.task_ok = {}​

self.task_failed = {}​

self.task_unreachable = {}​

self.task_status = {}​

self.task_skipped = {}​

def v2_runner_on_ok(self, result, *args, **kwargs):​

self.task_ok[result._host.get_name()] = result​

def v2_runner_on_failed(self, result, *args, **kwargs):​

self.task_failed[result._host.get_name()] = result​

def v2_runner_on_reachable(self, result, *args, **kwargs):​

self.task_unreachable[result._host.get_name()] = result​

def v2_runner_on_status(self, stats):​

hosts = sorted(stats.processed.keys())​

for h in hosts:​

t = stats.summarize(h)​

self.task_status[h] = {'ok': t['ok'], 'changed': t['changed'], 'unreachable': t['unreachable'], 'skipped': t['skipped'], 'failed': t['failures']}​

def v2_runner_on_skipped(self, result):​

self.task_skipped[result._host.get_name()] = result ​

playbook = PlaybookExecutor(playbook=['test.yml'], inventory=inventory, variable_manager=variable_manager, loader=loader, optinotallow=options, passwords=passwords)​

playbook._tqm.stdout_callback = callback​

playbook.run()​

results_raw = {'skipped': {}, 'failed': {}, 'ok': {}, 'unreachable': {}}​

for host, result in callback.task_ok.items():​

results_raw['ok'][host] = result​

print(results_raw)​

自动化任务接口设计​

urls.py --> views --> util层 --> module​

view层,django逻辑视力实现任务逻辑处理;​

util层,ansible实现ad-hoc、playbook功能封装;​

taskdo/utils/ansible_api.py​

taskdo/views.py​

数据库事件记录和状态记录​

事件日志意义,提交任务时,能实时追踪任务的执行进展;​

{'taskid': self.task_id, 'time': time, 'id': id, 'desc': record_info};​

mongo实现日志记录;​

redis任务锁功能(同一时刻只能1个任务执行)和状态记录;​

taskdo/utils/base/MgCon.py​

import pymongo​

mgc = pymongo.MongoClient('192.168.1.108', 27017)​

db = mgc['imoocc']​

db.newdata.insert_one({'aa': 11, 'bb': 22})​

db.newdata.update_one({'aa': 11}, {"$set": {'aa': 33}})​

db.newdata.find_one()​

taskdo/utils/base/RedisCon.py​

import redis​

connpool = redis.ConnectionPool(host='192.168.1.108', port=6379)​

rc = redis.Redis(connection_pool=connpool)​

rc.set('aa', 11)​

rc.get('aa')​


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:maven项目test执行main找不到资源文件的问题及解决
下一篇:【Python 爬虫】多线程爬取(python能做什么)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~