-
思路分析:
(1).查看InCAM/InCAMPro资料库路径;# 进入InCAM/InCAMPro资料库配置文件(dblist.xml)路径,查看配置文件资料库配置路径 # vim /incam/server/site_data/dblist.xml
如下图获取资料库路径为"/incam/camdb":
(2).获取资料库路径挂载点,在终端执行"df -h"指令;# df -h
如下图获取资料库挂载分区及详细的使用状况:
(3).获取server实际路径:# ls -al /incam/server
如下图获取server实际路径为"/backup/share/server":
(4).获取server实际路径挂载点,在终端执行"df -h"指令;# df -h
如下图获取server挂载分区及详细的使用状况:
-
编写监控代码(监控CAM资料库及server空间状况):
#!/usr/bin/env py3k import re import sys import os import time sys.path.append("/incam/server/site_data/scripts/py3_package") import sendMail # 开发日志 _header = { '脚本名称': '磁盘空间预警程式', '开发人员': 'Twei Tang', '开发时间': '2022年11月18日', '版本信息': 'A.1.0', '联系方式': ( '邮箱地址<>', '微信号码<358143105>', '手机号码<13627441202>' ), '开发信息': ( '无' ), '修改信息': ( '初始版本(A.1.0),首次开发测试,暂无版本变更信息' ), '沟通记录': ( '无' ) } if __name__ == "__main__": _back_time = time.strftime('%Y-%m-%d %H:%M:%S') _log_time = time.strftime('%Y-%m-%d-%H') _dict = {} _ser_dict = {} # _db_size_path = os.environ.get("INCAM_DIR") + "/tmp/db_size.213" # 自动任务懒得写环境变量,直接使用绝对路径 _db_size_path = "/incam/tmp/db_size.213" _server_size_path = "/incam/tmp/server_size.213" try: os.system(f"rm -rf {_db_size_path}") os.system(f"rm -rf {_server_size_path}") except BaseException as e: print(e) # 某某服务器server路径 _ser_grep = "/backup" try: os.system(f"df -h |grep {_ser_grep} > {_server_size_path}") except BaseException as e: print(e) # 某某服务器CAM资料库存储路径 _grep = "/incam/camdb" try: os.system(f"df -h |grep {_grep} > {_db_size_path}") except BaseException as e: print(e) _ser_cut = 0 _ser_cut_size = 80 # server空间预警值 if os.path.exists(_server_size_path): with open(_server_size_path, "r") as f: _lines = f.readlines() _size = re.sub(" +", " ", _lines[0]) _tmp_list = _size.split() if _ser_grep == "/backup": _ser_dict["磁盘路径:"] = _tmp_list[0] _ser_dict["磁盘容量:"] = _tmp_list[1] _ser_dict["已用空间:"] = _tmp_list[2] _ser_dict["剩余空间:"] = _tmp_list[3] _ser_dict["使用比率:"] = _tmp_list[4] _ser_dict["映射路径:"] = _tmp_list[5] _ser_cut = float(_tmp_list[4].strip('%')) _cut = 0 _cut_size = 90 # CAM资料库空间预警值 if os.path.exists(_db_size_path): with open(_db_size_path, "r") as f: _lines = f.readlines() _size = re.sub(" +", " ", _lines[0]) _tmp_list = _size.split() if _grep == "/incam/camdb": _dict["磁盘路径:"] = _tmp_list[0] _dict["磁盘容量:"] = _tmp_list[1] _dict["已用空间:"] = _tmp_list[2] _dict["剩余空间:"] = _tmp_list[3] _dict["使用比率:"] = _tmp_list[4] _dict["映射路径:"] = _tmp_list[5] _cut = float(_tmp_list[4].strip('%')) else: _dict["磁盘路径:"] = "你的服务器IP地址:/incam/camdb" _dict["磁盘容量:"] = _tmp_list[0] _dict["已用空间:"] = _tmp_list[1] _dict["剩余空间:"] = _tmp_list[2] _dict["使用比率:"] = _tmp_list[3] _dict["映射路径:"] = _tmp_list[4] _cut = float(_tmp_list[3].strip('%')) if len(_dict.keys()) > 0 and _cut >= _cut_size or len(_ser_dict.keys()) > 0 and _ser_cut >= _ser_cut_size: if len(_dict.keys()) > 0 and _cut >= _cut_size: _string = "<br>".join([k + v for k, v in _dict.items()]) _string += f'<br>存储空间超预警值({_cut_size}%)!' if len(_ser_dict.keys()) > 0 and _ser_cut >= _ser_cut_size: _string = "<br>".join([k + v for k, v in _ser_dict.items()]) _string += f'<br>存储空间超预警值({_ser_cut_size}%)!' att_list = [] _log = "某某服务器CAM资料库存储空间告警!<br>" + _string mess_list = [f'<tr bgcolor=#DDDDDD><th>disk_space_warning.py</th><th>{_back_time}</th><th align=left>{_log}</th></tr>'] mess_text = "\n".join(mess_list) html_text = f''' <p>某某服务器存储空间预警</p> <table border=2 bordercolor=#1212FC> <tr border=2 bgcolor=#FF6666><th>程序</th><th>时间</th><th>预警信息</th></tr> {mess_text} </table> ''' _to_list = ["用户邮箱1", "用户邮箱2"] try: SM = sendMail.MailMain("某某服务器(disk_space_warning.py)", "[email protected]", _to_list, f"{html_text}", f"某某服务器存储空间预警") if len(att_list) > 0: SM.SendMail(text_type="html", att_type=att_list) else: SM.SendMail(text_type="html") except BaseException as e: # 错误日志记录 _error_log = f"/incam/server/logs/存储空间预警邮件发送失败日志/{_log_time}.log" if not os.path.exists(f"/incam/server/logs/存储空间预警邮件发送失败日志"): os.mkdir(f"/incam/server/logs/存储空间预警邮件发送失败日志") if not os.path.exists(_error_log): os.system(f"touch {_error_log}") with open(_error_log, "a", encoding="utf-8") as f: f.write(f"Error: 无法发送邮件, 详情:{e}\n") try: os.system(f"rm -rf {_db_size_path}") os.system(f"rm -rf {_server_size_path}") except BaseException as e: print(e) sys.exit()
-
配置脚本自动执行:
- 创建自动执行任务计划
(1).进入root用户,终端下输入su回车
(2).编辑任务计划$ su 密码: <输入密码后回车>
# crontab -e # 输入以下内容后按"Esc"键,然后输入"x"回车保存退出 # ======================================================== # 服务器磁盘监控(08:00) 00 08 * * * /usr/bin/py3k 监控脚本路径/disk_space_warning.py >/incam/server/logs/crontab.log 2>&1 # 服务器磁盘监控(12:00) 0 12 * * * /usr/bin/py3k 监控脚本路径/disk_space_warning.py >/incam/server/logs/crontab.log 2>&1 # 服务器磁盘监控(17:30) 30 17 * * * /usr/bin/py3k 监控脚本路径/disk_space_warning.py >/incam/server/logs/crontab.log 2>&1 # ========================================================
- 自动任务执行效果
- 自动邮件信息:
- 自动运维扩展:
-
思考?
我已经监控到了空间告警,如何自动触发保护机制阻止磁盘继续写入数据? -
思路?
InCAM/InCAMPro在保存的时候将修改的数据写入硬盘存储,那我们是不是可以通过限制保存动作临时禁止写入数据(空间释放后自动恢复写入),避免极端环境下系统人员不能及时释放磁盘空间时让用户有机会自行处理,问题的核心就是怎么限制用户保存,刚刚好InCAM/InCAMPro软件有line_hooks机制,支持指令前置(.pre)及后置(.post)钩子,我们可以使用保存指令前置钩子(save_job.pre)拦截保存指令,思路清晰我们直接上代码,看看如何实现磁盘写入自我保护机制. -
实现:
编写save_job.pre钩子脚本:
脚本路径及名称不可变,需遵守软件内部机制,
脚本路径:“/incam/server/site_data/hooks/line_hooks/save_job.pre”(按大家的实际情况来)
行业中一般大家都使用官方推荐的CSH写hooks,作者所在公司之前也是这样用CSH编写save_job.pre,按照本人习惯一般会使用Python编写(后续博文教大家用python写hooks),但是我比较懒不想用Python重构save_job.pre我又想用Python写怎么办,没关系,Python是胶水语言不是白叫的,在CSH中调用一样很方便,这就给我们创造了偷懒的条件,我一样用Python写主要执行逻辑,话不多说先上主体Python代码.#!/usr/bin/env python3 # 系统包 import sys import re import time # 自定义包 sys.path.append("/incam/server/site_data/scripts/py3_package") import MainClasses from GuiClasses import * # 开发日志 _header = { '脚本名称': '保存料号前置程式', '开发人员': 'Twei Tang', '开发时间': '2022年10月19日', '版本信息': 'A.1.0', '联系方式': ( '邮箱地址<>', '微信号码<358143105>', '手机号码<13627441202>' ), '开发信息': ( '无' ), '修改信息': ( '基带版本(A.1.0),首次开发测试,暂无版本变更信息' ), '沟通记录': ( '无' ) } if __name__ == "__main__": app = QApplication(sys.argv) Gui = MainGui() Do = MainClasses.Main() _dict = {} _db_size_path = os.environ.get("INCAM_DIR") + "/tmp/db_size.213" _db_size_stut = os.environ.get("INCAM_DIR") + "/tmp/db_size.ng" try: os.system(f"rm -rf {_db_size_path}") os.system(f"rm -rf {_db_size_stut}") except BaseException as e: print(e) _grep = "/incam/camdb" os.system(f"df -h |grep {_grep} > {_db_size_path}") _cut = 0 _cut_size = 98 # 极端空间值,达到后推送锁死指令 if os.path.exists(_db_size_path): with open(_db_size_path, "r") as f: _lines = f.readlines() _size = re.sub(" +", " ", _lines[0]) _tmp_list = _size.split() if _grep == "/incam/camdb": _dict["磁盘路径:"] = _tmp_list[0] _dict["磁盘容量:"] = _tmp_list[1] _dict["已用空间:"] = _tmp_list[2] _dict["剩余空间:"] = _tmp_list[3] _dict["使用比率:"] = _tmp_list[4] _dict["映射路径:"] = _tmp_list[5] _cut = float(_tmp_list[4].strip('%')) else: _dict["磁盘路径:"] = "你的服务器IP地址:/incam/camdb" _dict["磁盘容量:"] = _tmp_list[0] _dict["已用空间:"] = _tmp_list[1] _dict["剩余空间:"] = _tmp_list[2] _dict["使用比率:"] = _tmp_list[3] _dict["映射路径:"] = _tmp_list[4] _cut = float(_tmp_list[3].strip('%')) if len(_dict.keys()) > 0 and _cut > _cut_size: _string = "<br>".join([k + v for k, v in _dict.items()]) _string += f'<br>存储空间超预警值({_cut_size}%),禁止写入!' _string += f'<br>------------------------------------' _string += f'<br>注意事项:' _string += f'<br>1.清除非正式料号扩充空间以恢复保存功能;' _string += f'<br>2.联系工程技术中心软件部协助处理!' with open(_db_size_stut, "w", encoding="utf-8") as f: f.write(_string) # Gui.warningbox(mess=_string) try: os.system(f"rm -rf {_db_size_path}") except BaseException as e: print(e) sys.exit()
代码的主体逻辑与我们的前面预警脚本一致,不同点在于一个是邮件通知提醒,一个是记录结果并传递给软件line_hooks中的钩子脚本,接下来我们看看save_job.pre接收到信息后如何拦截用户指令的,我们上代码(CSH写的save_job.pre):
#!/bin/csh source $1 # 用Python写个弹窗,避免使用PAUSE alias mesbox "python3 /incam/server/site_data/scripts/Test/twei/mesbox.py" # 磁盘空间预警机制,超过预警值禁止CAM数据写入,Twei Tang添加,2022/10/19 python3 "/incam/server/site_data/scripts/Test/twei/line_hooks/save_job.py" if (-e $INCAM_DIR/tmp/db_size.ng) then COM skip_current_command # 这就软件的拦截指令,它会阻止马上要执行的动作 mesbox `cat $INCAM_DIR/tmp/db_size.ng` rm -rf "$INCAM_DIR/tmp/db_size.ng" endif exit
CSH代码仅仅只是接收了传递的参数,根据参数结果拦截了指令,并且将我们的预警信息及处理方式直接弹窗传达到用户,到了这里怎么让用户自行恢复保存就太简单了,删除不必要的垃圾料号,释放存储空间后就自动恢复保存功能了,一套自动运维项目我们就完成了!
-
自动弹窗信息: