Python读取Ansible playbooks返回信息

一.背景及概要设计

当公司管理维护的服务器到达一定规模后,就必然借助远程自动化运维工具,而ansible是其中备选之一。Ansible基于Python开发,集合了众多运维工具(puppet、chef、func、fabric)的优点,实现了批量系统配置、批量程序部署、批量运行命令等功能。Ansible是借助ssh来和远程主机通讯的,不需要在远程主机上安装client/agents。因为上手容易,配置简单、功能强大、扩展性强,在生产应用中得到了广泛的应用。使用过程中,读取、解析、判断、保存Ansible playbooks 的执行返回信息是重要一坏。本文详细描述如何实现Python读取Ansible playbooks 执行返回信息,并且保存到数据库中。

Ansible playbooks 的返回信息,有相应的格式。

例如:

PLAY [play to setup web server] *****************************************************TASK [Gathering Facts] **************************************************************
ok: [172.177.117.129]
ok: [172.177.117.130]TASK [Installed the latest httpd version] ***********************************************
ok: [172.177.117.129]
ok: [172.177.117.130]TASK [restart service] ***********************************************************
changed: [172.177.117.129]
changed: [172.177.117.130]PLAY RECAP **************************************************************************
172.177.117.129 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
172.177.117.130 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

从上面的例子可以看出,返回的运行信息还是很丰富的,从中可以得出play、task的名字、每个task执行情况,以及play运行情况的概况。

即:

 When you run a playbook, Ansible returns information about connections, the name lines of all your plays and tasks, whether each task has succeeded or failed on each machine, and whether each task has made a change on each machine. At the bottom of the playbook execution, Ansible provides a summary of the nodes that were targeted and how they performed. General failures and fatal “unreachable” communication attempts are kept separate in the counts.

重点及难点:从结果中找出规律,格式化结果,怎么用正则表达式取得想要的信息。

二.表设计

通过对Ansible playbooks返回信息的分析,可以将其分成两类(或者说两部分),一是play的整体执行情况(主要信息为PLAY RECAP ),另一个是每个task的执行详情。因此,我们设计了两张表。

2.1 设计用来保存【最终执行结果】的表

ansible_play_recap

2.2 设计用来保存【各执行步骤详情】的表

ansible_task_palydetail

注意:

(1)可以根据需要,在表中增加一列ansible_cmd,用来保存执行的ansible的命令。

(2)为什么会有看着奇怪的manager_ip、clustername?因为,这份代码来自于对DB 集群的 部署 和 管理,可根据实际需要,修改取舍(即你的代码可以把他们去掉)。

三.Models设计

3.1 AnsiblePlayRecap的定义

class AnsiblePlayRecap(models.Model):"""保存ansible最终执行结果的表"""id = models.AutoField('自增id', primary_key=True)manager_ip = models.CharField('MHA Manager IP', max_length=100)clustername = models.CharField('HA 集群名字', max_length=200, default='')playname = models.CharField('Ansible剧本名称', max_length=360, default='')playrecap_serverip = models.CharField('受管节点', max_length=50, default='')playrecap_ok_qty = models.CharField('此节点成功运行的task个数', max_length=10, default='')playrecap_changed_qty = models.CharField('产生效果的task个数', max_length=10, default='')playrecap_unreachable = models.CharField('相应的远程节点是否不可达', max_length=10, default='')playrecap_failed_qty = models.CharField('执行失败的task个数', max_length=10, default='')playrecap_skipped_qty = models.CharField('跳过的task的个数', max_length=10, default='')playrecap_rescued_qty = models.CharField('抢救的task的个数', max_length=10, default='')playrecap_ignored_qty = models.CharField('忽略的task的个数', max_length=10, default='')create_time = models.DateTimeField('插入时间', auto_now=True)create_user = models.CharField('操作人', max_length=50, default='')class Meta:db_table = 'ansible_play_recap'verbose_name = '保存ansible最终执行结果的表'

AnsibleTaskDetail的定义

class AnsibleTaskDetail(models.Model):"""保存各task执行详情的表"""id = models.AutoField('自增id', primary_key=True)manager_ip = models.CharField('MHA Manager IP', max_length=100)clustername = models.CharField('HA 集群名字', max_length=200, default='')playname = models.CharField('Ansible剧本名称', max_length=360, default='')task_serverip = models.CharField('受管节点', max_length=50, default='')taskname = models.CharField('任务名称', max_length=360, default='')task_status = models.CharField('任务执行结果', max_length=50, default='')task_result_type = models.CharField('执行结果的错误类型', max_length=10, default='')task_messages = models.TextField('Task运行返回信息')create_time = models.DateTimeField('插入时间', auto_now=True)create_user = models.CharField('操作人', max_length=50, default='')class Meta:db_table = 'ansible_task_palydetail'verbose_name = '保存各执行步骤详情的表'

四.生成SQL脚本

由model所在的项目名称,通过运行 python manage.py生成

假如项目名称用XXXX代替

---生成脚本

python manage.py makemigrations XXXX

---显示刚才生成的SQL脚本(0006为版本序列号)

python manage.py sqlmigrate XXXX 0006

五. 主要功能代码

调用代码,需传入的参数有三个,

(1)shell_command 餐宿 -----即要执行的Ansible Playbook 命令;

(2)manager_ip参数

(3)cluster_name 参数--- 这两个命令前面已解释了,因为我们的这份代码,其功能是为了维护数据库集群的。在其他场景下,这两个参数可以去掉。

5.1 执行ansible 命令

声明关于正则的模式;连接远程ansible主机;获取ansible 执行结果;

from .ansible import ParamikoHelper##paramiko 是一个用于在Python中执行远程操作的模块,支持SSH协议。它可以用于连接到远程服务器,执行命令、上传和下载文件,以及在远程服务器上执行各种操作。##字符串中关于IP地址的正则表达式## ^:匹配字符串的开头。((25[0-5]|2[0-4]\d|[01]?\d\d?)\.):匹配一个数字和一个点号,这个数字的取值范围是0到255。## {3}:匹配前面的表达式三次。(25[0-5]|2[0-4]\d|[01]?\d\d?):   配一个数字,这个数字的取值范围是0到255。$:匹配字符串的结尾。## 使用正则表达式匹配IP地址# 字符串是IP地址ip_pattern = r'^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$'##字符串是IP地址开头的ipstart_pattern = r'^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)'##字符串包含IPipcontain_pattern = r'((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)'   ##字符串包含IP,并且IP地址是以': ['字符开头,以']'字符结尾ipcontain_pattern_plus = r'(\: \[)((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}((25[0-5]|2[0-4]\d|[01]?\d\d?)\])' ansible_ip = '你的ansible server IP'ssh_port = 你的ssh_portssh_username = '免密登录设置的账号'ph = ParamikoHelper(remote_ip=ansible_ip,remote_ssh_port=ssh_port,ssh_username=ssh_username)stdin, stdout, stderr = ph.exec_shell(shell_command)processor_result = stdout.readlines() #readlines()列表形式返回全文,每行作为一个字符串作为列表元素

5.2 开始逐行解析返回的结果

先判断这一行是否以Server IP开头(是的话,就是 PLAY RECAP 中的内容 ),

还要判断这一行 是否 有 以': ['字符开头,以']'字符结束的Server IP(如果是的话,很可能就是task部分的内容)

两个判断是各自独立的,相互没有关系依赖。

### 先赋值,否则有可能报错:UnboundLocalError: local variable 'XXXXX' referenced before assignmentrplayname = ''rtask_result_type =''###for pr_line in processor_result:logger.warning(f'{pr_line}')## 判断这个字符串是不是以IP地址开头ip_result = re.search(ipstart_pattern, pr_line)## 判断这个字符串是不是包含IP地址,并且IP以': ['字符开头,以']'字符结束  ip_plus_result = re.search(ipcontain_pattern_plus, pr_line) ##获取playname start

5.3获取playname 和taskname

根据是否含有'PLAY ['字符、'TASK ['字符进行判断和提取。

##获取playnameif 'PLAY [' in pr_line:##使用的正则表达式'\[(.*?)\]',其中'\'为转移符,用于表示左右中括号的匹配,'?'表示非贪婪模式,这个模式会匹配最短的符合要求的字符串。## [0],因正则匹配后,放回的是数组,通过[0],转换为字符串。rplayname = re.findall(r'\[(.*?)\]', pr_line)[0]##获取task 的名称elif 'TASK [' in pr_line:rtaskname = re.findall(r'\[(.*?)\]', pr_line)[0]

5.4 获取 paly 执行概况

即PLAY RECAP 部分内容,主要依据是这行的字符是以IP地址开头的。 

## 判断这个字符串是不是以IP地址开头elif ip_result: #字符串是IP地址开头的## 此时pr_line的字符串格式如下:## pr_line = '172.173.17.18               : ok=5    changed=2    unreachable=1    failed=0    skipped=6    rescued=7    ignored=8'rserverip = ip_result.group() ## 匹配的server IP## print(rserverip) ##打印IP地址## 正则表达式,\s+ ,将一个以多个空格或制表符为分隔符的字符串拆分成一个列表pr_line_lst = re.split(r"\s+", pr_line)##分割后为: ['172.173.17.18', ':', 'ok=5', 'changed=2', 'unreachable=1', 'failed=0', 'skipped=6', 'rescued=7', 'ignored=8']for pr_arry in pr_line_lst:if 'ok=' in pr_arry:rplayrecap_ok_qty = pr_arry.split("ok=")[1] ##记得:字符串切割后返回的是数组,所以取第二个元素if 'changed=' in pr_arry:rplayrecap_changed_qty = pr_arry.split("changed=")[1]if 'unreachable=' in pr_arry:rplayrecap_unreachable = pr_arry.split("unreachable=")[1]if 'failed=' in pr_arry:rplayrecap_failed_qty = pr_arry.split("failed=")[1]if 'skipped=' in pr_arry:rplayrecap_skipped_qty = pr_arry.split("skipped=")[1]if 'rescued=' in pr_arry:rplayrecap_rescued_qty = pr_arry.split("rescued=")[1]if 'ignored=' in pr_arry:rplayrecap_ignored_qty = pr_arry.split("ignored=")[1]

5.5 将paly 概况数据插入表中

Django 框架,关于Model数据的写入。

### 开始向表[ansible_play_recap]中插入数据,保存ansible最终执行结果的表AnsiblePlayRecap.objects.create(manager_ip=manager_ip,clustername=cluster_name,playname=rplayname,playrecap_serverip=rserverip,playrecap_ok_qty=rplayrecap_ok_qty,playrecap_changed_qty=rplayrecap_changed_qty,playrecap_unreachable=rplayrecap_unreachable,playrecap_failed_qty=rplayrecap_failed_qty,playrecap_skipped_qty=rplayrecap_skipped_qty,playrecap_rescued_qty=rplayrecap_rescued_qty,playrecap_ignored_qty=rplayrecap_ignored_qty, create_user='Archery System')

5.6 获取task执行情况,并将数据保存到表中

如果这一行数据包含Server IP地址,并且这个 IP以': ['字符开头,以']'字符结尾的,那么这行记录的就是这个task在某受管节点的执行情况。

## 判断这个字符串是不是包含IP地址,并且IP以': ['字符开头,以']'字符结尾elif ip_plus_result: ##字符串包含IP,并且IP地址是以': ['字符开头,以']'字符结尾if 'ok: [' in pr_line:rtask_status = 'ok'rtask_messages = '' ## 赋值空##查找server IPresult = re.search(ipcontain_pattern, pr_line)rserverip = result.group() ## 匹配的server IP  ## print(rserverip)elif 'changed: [' in pr_line:rtask_status = 'changed'rtask_messages = '' ## 赋值空##查找server IPresult = re.search(ipcontain_pattern, pr_line)rserverip = result.group() ## 匹配的server IP## 有些 返回的change 中还有其他信息,例如:changed: [192.168.168.192] => (item=perl-Parallel-ForkManager-1.18-2.el7.noarch.rpm)## 此时判断下,是否包含 '] =>',如果包含,赋值给  if '] => ' in pr_line:rtask_messages= pr_line.split("] => ")[1]elif 'skipping: [' in pr_line:rtask_status = 'skipping'rtask_messages = '' ## 赋值空##查找server IPresult = re.search(ipcontain_pattern, pr_line)rserverip = result.group() ## 匹配的server IPelif 'fatal: [' in pr_line:rtask_status = 'fatal'rtask_messages = '' ## 赋值空rtask_result_type ='FAILED'##查找server IPresult = re.search(ipcontain_pattern, pr_line)rserverip = result.group() ## 匹配的server IPif 'FAILED! =>' in pr_line:rtask_messages= pr_line.split("FAILED! =>")[1]else:rtask_status = 'NA'rtask_messages = '未知状态,请DBAcheck......' + pr_line### 开始向表中插入数据AnsibleTaskDetail.objects.create(manager_ip=manager_ip,clustername=cluster_name,playname=rplayname,playrecap_serverip=rserverip,taskname=rtaskname,task_status=rtask_status,task_result_type=rtask_result_type,task_messages=rtask_messages,create_user='Archery System')

5.7 去除干扰项和无效项

      elif len(pr_line) == 0 or pr_line == '\n' or ('PLAY RECAP *******' in  pr_line): ###判断是否空 或只是 简单的换行符,再或者包含指定字符print("这一行为空行 或 说明行,无需记录!")

5.8 补充有效项

当执行task返回OK时,,后面跟个IP,再后面一般不跟啥了;但是有时候还会由跟东西的。啥时候跟呢? 例如:task #debug: # msg: "你想要的返回信息。。。。。。" 这类命令时。

else:rtask_status = 'Mostly OK'rtask_result_type = 'debug+msg'   ##'经常出现在task中有debug:msg:的时候'rtask_messages =  pr_line### 开始向表中插入数据AnsibleTaskDetail.objects.create(manager_ip=manager_ip,clustername=cluster_name,playname=rplayname,playrecap_serverip=rserverip,taskname=rtaskname,task_status=rtask_status,task_result_type=rtask_result_type,task_messages=rtask_messages,create_user='Archery System')###这段处理的情形不好想像,比较难懂,举个例子## ok: [192.168.168.192] =>         ##  {##     "msg": "MySQL Replication Health is OK!"## }##需要注意的时,相应的在表中也会保留多行数据。因为我们时逐行获取,逐行解析,逐行报错的。不过庆幸的时,顺序都是对的。

六. 其他说明

6.1 必须说明的是:上面的Python代码针对的是ansible host 文件保存的是Server IP,如果是域名,那么关于IP的正则是不可用的,代码必须调整。

6.2  补充几个task的返回信息的示例,方便理解代码。

示例 1ok: [192.168.168.192] => {\n', '    "msg": "MySQL Replication Health is OK!"\n', '}\n
示例 2
changed: [192.168.168.192] => (item=perl-Parallel-ForkManager-1.18-2.el7.noarch.rpm)示例 3fatal: [192.168.168.192]: FAILED! => {"changed": false, "msg": "No package matching "test" found available, installed or updated", "rc": 126, "results": ["No package matching "test" found available, installed or updated']}""" 
示例 4
skipping: [192.168.168.192]示例 5changed: [192.168.168.192]示例 6 ok: [192.168.168.192]

 6.3 Python读取Ansible playbooks返回信息只是平台的一个小功能,整个系统平台采用的是Django框架。

文章转载自:东山絮柳仔

原文链接:https://www.cnblogs.com/xuliuzai/p/17850437.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/176065.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

nuxt、vue实现PDF和视频文件的上传、下载、预览

上传 上传页面 <el-form-item :label"(form.ququ3 1 ? 参培 : form.ququ3 2 ? 授课 : ) 证明材料" prop"ququ6"><PdfUpload v-model"form.ququ6" :fileType"[pdf, mp4, avi, ts]"></PdfUpload> </el-form-i…

亚马逊,shein,temu如何避免爆品评分低被强制下架

近期&#xff0c;一些Temu卖家反映产品下架问题&#xff0c;无论是日出千单的爆品还是其他商品&#xff0c;都有可能面临下架的风险。这其中最主要的原因之一是产品质量问题&#xff0c;导致消费者差评较多&#xff0c;评分降至4.2分或4.0分以下时&#xff0c;平台可能会强制下…

EfficientViT:具有级联群体注意力的内存高效Transformer

EfficientViT: Memory Efficient Vision Transformer with Cascaded Group Attention 1、介绍2、使用 Vision Transformer 加快速度2.1 内存效率2.2 计算效率2.3 参数效率 3、Efficient Vision Transformer3.1 EfficientViT 构建模块3.3 EfficientViT 网络架构 4、实验5、结论 …

YOLOv8独家原创改进: AKConv(可改变核卷积),即插即用的卷积,效果秒杀DSConv | 2023年11月最新发表

💡💡💡本文全网首发独家改进:可改变核卷积(AKConv),赋予卷积核任意数量的参数和任意采样形状,为网络开销和性能之间的权衡提供更丰富的选择,解决具有固定样本形状和正方形的卷积核不能很好地适应不断变化的目标的问题点,效果秒殺DSConv 1)AKConv替代标准卷积进行…

如何在vs2019及以后版本(如vs2022)上添加 添加ActiveX控件中的MFC类

有时候我们在MFC项目开发过程中&#xff0c;需要用到一些微软已经提供的功能&#xff0c;如VC使用EXCEL功能&#xff0c;这时候我们就能直接通过VS2019到如EXCEL.EXE方式&#xff0c;生成对应的OLE头文件&#xff0c;然后直接使用功能&#xff0c;那么&#xff0c;我们上篇文章…

【Docker】python flask 项目如何打包成 Docker images镜像 上传至阿里云ACR私有(共有)镜像仓库 集成Drone CI

一、Python环境编译 1、处理好venv环境 要生成正常的 requirements.txt 文件&#xff0c;我们就需要先将虚拟环境处理好 创建虚拟环境&#xff08;可选&#xff09;&#xff1a; 在项目目录中&#xff0c;你可以选择使用虚拟环境&#xff0c;这样你的项目依赖将被隔离在一个…

C++基础 -6-二维数组,数组指针

二维数组在内存中的存放方式和一维数组完全相同 下表把二维数组抽象成了行列形式方便理解 a[0]指向第一行首元素地址 a指向第一行的首地址 所以a地址和a[0]地址相同,因为起点相同 但a[0]1往右偏移 但a1往下方向偏移 方便理解 an控制行 a[0]n控制列(相当于*an) 数组指针指向二…

食材管家,轻松搞定!商户选择生鲜配送系统的原因

随着消费者对生鲜食品的需求不断增加&#xff0c;生鲜市场逐渐成为了电商领域中的热门行业。而生鲜配送系统&#xff0c;则是生鲜电商发展中不可或缺的一部分。本文将探讨商户选择生鲜配送系统的几个原因。 1. 提高效率 生鲜配送系统通过智能化的订单处理、路线规划和配送优化…

【MySQL系列】PolarDB入门使用

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

不用render_template函数,把html代码放在py文件里,不用单独写html文件

3.猜拳游戏&#xff1a;石头、剪刀、布的游戏 ##不用render_template函数&#xff0c;把html代码放在py文件里&#xff0c;不用单独写html文件 from flask import Flask, request import randomapp Flask(__name__)app.route(/) def index():#下面form标签虽然放在注释里&…

Scanner常用知识点

在Java中&#xff0c;Scanner类是用于读取用户输入的工具类&#xff0c;可以从多种输入源读取数据&#xff0c;如标准输入流、文件或字符串。以下是一些Scanner类的常用知识点&#xff1a; Scanner的初始化&#xff1a;在使用Scanner类之前&#xff0c;需要先将其导入到你的Ja…

Pycharm在debug问题解决方案

Pycharm在debug问题解决方案 前言一、Frames are not available二、查看变量时一直显示collecting data并显示不了任何内容 前言 Pycharm在debug时总是出现一些恼人的问题&#xff0c;以下是博主在训练中遇到的问题及在网上找到的可用解决方案&#xff1a; 一、Frames are not…

C语言基础篇5:指针(二)

接上篇&#xff1a;C语言基础篇5&#xff1a;指针(一) 4 指针作为函数参数 4.1 指针变量作为函数的参数 指针型变量可以作为函数的参数&#xff0c;使用指针作为函数的参数是将函数的参数声明为一个指针&#xff0c;前面提到当数组作为函数的实参时&#xff0c;值传递数组的地址…

搭建你自己的网盘-个人云存储的终极解决方案-nextcloud (一)

在当今数字化时代&#xff0c;我们越来越多地依赖云存储来保存和共享我们的个人和工作文件。而自己搭建网盘不仅可以提供更大的存储空间和更高的隐私保护&#xff0c;还可以让我们完全掌控我们的数据。 在之前我分享过一个文件共享站-Pingvin Share 。 但是今天我将带来一个文件…

西工大网络空间安全学院计算机系统基础实验零

首先&#xff0c;下载VMware17 Pro workstation。为什么要下载VMware17 Pro workstation呢&#xff1f;因为计算机系统基础实验有四个大部分&#xff1a;利用位运算实现诸如a*b&#xff0c;a/b&#xff0c;a*(2^4)等运算&#xff1b;C语言循环语句、switch语句等语句与汇编代码…

【开源】基于Vue+SpringBoot的大学生相亲网站

项目编号&#xff1a; S 048 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S048&#xff0c;文末获取源码。} 项目编号&#xff1a;S048&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块三、系统展示四、核心代码4.1 查询会员4…

OpenVINO异步Stable Diffusion推理优化方案

文章目录 Stable Diffusion 推理优化背景技术讲解&#xff1a;异步优化方案思路&#xff1a;异步推理优化原理OpenVINO异步推理Python API同步和异步实现方式对比 oneflow分布式调度优化优势&#xff1a;实现思路 总结&#xff1a; Stable Diffusion 推理优化 背景 2022年&am…

服务器中启动和停止项目

服务器中启动和停止项目 一、前言二、使用命令启动和关闭项目1、启动项目2、停止项目 三、使用可执行脚本启动和关闭项目1、启动项目2、停止项目 一、前言 在服务器上部署项目&#xff0c;一般就是将项目挂在后台&#xff0c;如果是微服务首选docker-compose&#xff0c;但如果…

深入解析Windows操作系统——系统结构

文章目录 需求和设计目标总体结构可移植性对称多处理可伸缩性 关键的系统组件Windows子系统Ntdll.dll执行体内核硬件支持硬件抽象层HAL设备驱动程序 Windows驱动程序模型执行体组件常用的绝大多数函数名前缀 系统进程空闲进程中断和DPCSystem进程和系统线程会话管理器Winlogon、…

OkHttp的配置

一、拦截器 1.添加拦截器的作用&#xff1a; 每次在请求过程中就会回调一次intercept方法 2.拦截器的回调方法里我们可以做那些事情&#xff1a; 当前的请求还没有发给服务器&#xff0c;比如我们在与服务器通信的时候&#xff0c;一个应用中很多地方都会跟服务器发起通信。…