【python】使用python写windows服务
背景
运维windows服务器的同学都知道,windows服务器进行批量管理的时候非常麻烦,没有比较顺手的工具,虽然saltstack和ansible都能够支持windows操作,但是使用起来总感觉不太舒服,比如ansible使用的winrm进行远程操作,需要提前在windows上进行设置,并且要求操作系统版本和powershell版本,根据个人使用经验,经常存在链接不上,连接慢,或者推送失败的问题,较高的失败率对于自动化运维体系的建立不利,所以与其受制于人,不如自己动手写一个agent,完全自己控制。
技术平台
服务器:windows服务器,测试过win2008r2、win2012、win7和win10.其他版本不知道怎么样。
开发语言:python
python模块:pywin32(python中的windows库),pyinstaller(用于将py文件生成exe程序),flask(web服务器)。以上三个模块都可以通过pip安装。以及一些python内置模块
优势:完全自己控制,根据自己需要开发功能。服务器端不需要安装任何其他依赖(不需要安装python环境,exe自带运行环境)
流程结构
代码实现
agent的实现代码如下,代码有详细的注释,就不解释了。
# -*- coding:utf-8 -*-
import win32serviceutil
import win32service
import win32event
from flask import Flask
from flask import request
import sys
import os
import zipfile
import requests
import shutil
import re
import time
#设置编码
reload(sys)
sys.setdefaultencoding('utf-8')
################################################################
##########自定义函数区##########################################
################################################################
#下载文件函数
def get_url_file(url):
#下载到临时目录,如果临时目录不存在就创建一个
download_path = "D:\\tmp\\%s" % (time.time())
if os.path.exists(download_path):
pass
else:
os.makedirs(download_path)
r = requests.get(url, stream=True)
#解析文件名,如url为:http://www.ftp.com/test.zip那么文件名就是test.zip,并下载和写入文件
filename = "%s\\%s" % (download_path, url.split('/')[-1])
with open(filename, "wb") as pdf:
for chunk in r.iter_content(chunk_size=1024):
if chunk:
pdf.write(chunk)
return {'filename':filename,'download_path':download_path} def config_zabbix(hostname):
#复制一份C:\\zabbix\\zabbix_agentd_win.conf.bak的zabbix模板文件,并修改其中的Hostname=new为新的hostname,然后生成新的配置文件。
try:
open('C:\\zabbix\\zabbix_agentd_win.conf', 'w').write(re.sub(r'Hostname=new', 'Hostname=%s' % hostname, open('C:\\zabbix\\zabbix_agentd_win.conf.bak').read()))
except:
return "error"
# 重启zabbix agent服务
service_list = os.popen('net start').read()
if service_list.find('Zabbix Agent') == -1:
try:
os.system('net start "Zabbix Agent"')
except:
return "error"
else:
try:
os.system('net stop "Zabbix Agent')
except:
return "error"
try:
os.system('net start "Zabbix Agent')
except:
return "error"
return "ok" # 加压缩文件函数
def un_zip(file_name,dest_path):
zip_file = zipfile.ZipFile(file_name)
file_pre = file_name.split('\\')[-1].split('.')[0]
for names in zip_file.namelist():
zip_file.extract(names, dest_path)
zip_file.close()
return (dest_path + '\\' + file_pre)
###################################################################
#############自定义函数区结束######################################
################################################################### #windows服务中显示的名字
class zlsService(win32serviceutil.ServiceFramework):
_svc_name_ = 'zls_agent' ###可以根据自己喜好修改
_svc_display_name_ = 'zls_agent' ###可以根据自己喜好修改
_svc_description_ = 'zls_agent' ###可以根据自己喜好修改 def __init__(self,args):
win32serviceutil.ServiceFramework.__init__(self,args)
self.stop_event = win32event.CreateEvent(None, 0, 0, None)
self.run = True def SvcDoRun(self):
app = Flask(__name__)
##############################################################
#########flask路由设置区,自定义功能也放在这里################
##############################################################
#推送文件服务,比如传入一个url和目标地址,装有本agent的客户端就会下载这个url并把文件放在指定位置
@app.route('/transferfile', methods=['GET', 'POST'])
def transferfile():
if request.method == "GET":
url = request.args.get('url')
dest = request.args.get('dest')
try:
down_data = get_url_file(url)
filename = down_data['filename']
download_path = down_data['download_path']
except BaseException, e:
return "download url file error : %s" % e
# 加压缩文件
try:
filepath = un_zip(filename,download_path)
except BaseException, e:
return "un zip error : %s" % e
# 删除压缩文件
try:
os.remove(filename)
except:
pass
# 复制文件内容到指定目录
try:
shutil.copytree('%s' % filepath.replace('\\', '\\\\'), '%s' % dest)
except BaseException, e:
return "copy file error: %s" % e
# d删除解压缩文件夹
try:
shutil.rmtree(filepath.replace('\\', '\\\\'))
except:
pass
return "ok"
#修改配置文件路由,用来远程修改zabbix配置文件,比如curl http://server_ip:50000/zabbix?hostname="zabbix_agent"就会把位于服务器上的zabbix_agentd配置文件中的Hostname修改为Hostname=zabbix_agent。
@app.route('/zabbix', methods=['GET', 'POST'])
def config_zabbix_func():
if request.method == "GET":
hostname = request.args.get('hostname')
result = config_zabbix(hostname)
return result
#测试路由,用来测试agent是否正在运行,返回ok表示正在运行
@app.route('/', methods=['GET', 'POST'])
def test():
if request.method == "GET":
return "ok"
#使用flask自带的web服务器,监听本地所有地址的50000端口
##############################################################
#############自定义功能区结束#################################
##############################################################
app.run(host='0.0.0.0', port=50000)
def SvcStop(self):
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
win32event.SetEvent(self.stop_event)
self.ReportServiceStatus(win32service.SERVICE_STOPPED)
self.run = False if __name__ == '__main__':
import sys
import servicemanager
if len(sys.argv) == 1:
try:
evtsrc_dll = os.path.abspath(servicemanager.__file__)
servicemanager.PrepareToHostSingle(zlsService) #如果修改过名字,名字要统一
servicemanager.Initialize('zlsService',evtsrc_dll) #如果修改过名字,名字要统一
servicemanager.StartServiceCtrlDispatcher()
except win32service.error as details:
import winerror
if details == winerror.ERROR_FAILED_SERVICE_CONTROLLER_CONNECT:
win32serviceutil.usage()
else:
win32serviceutil.HandleCommandLine(zlsService) #如果修改过名字,名字要统一
生成exe程序
安装完成pyinstaller以后,打开命令行窗口
输入:pyinstaller -F windows_service.py
说明:-F表示生成一个单一的exe文件。其他选项使用pyinstaller --help查看。
执行完成后,提示生成exe程序
找到这个程序
将程序复制到测试服务器上,安装
以管理员身份打开cmd,中输入 windows_servcie.exe install
提示安装成功
启动服务,然后设置成自动启动
测试,浏览器中访问IP:50000端口,返回ok表示agent运行正常
后续:
想要卸载服务,可以使用
重要说明:
以上的测试,均在测试环境中进行,不要用在正式环境,因为这个agent没有加密通信,存在被人攻击的危险!!!
实际使用过程中,一定要对通信进行加密,可以使用https或者在命令中加入token,对token进行认证,只有正确的token才执行命令,或者使用rsa证书加密,这里就不再举例。
此agent只是给了三个示例性应用,实际用的时候,可以根据自己需要在函数区和路由定义区加入自己的程序,比如把这个agent做成监控系统,获取本地信息穿给服务端,在此抛砖引玉,剩下的就看自己的发挥了。
【python】使用python写windows服务的更多相关文章
- 用python写windows服务
用python写windows服务(1) 以python2.5 为例需要软件 * python 2.5 * pywin32(与2.5 版本相匹配的) Service Control Ma ...
- 不用写Windows服务实现定时器功能(FluentScheduler )
MacBook Pro 只有四个 USB Type-C 接口是否错了? 一项新技术的诞生总会对已存在的事物造成冲击或影响,如果大家都害怕冲击与影响,那这个世界永远像现在不变就行了,大家都好好的,待在自 ...
- c#写windows服务
序言 前段时间做一个数据迁移项目,刚开始用B/S架构做的项目,但B/S要寄存在IIs中,而IIs又不稳定因素,如果重启IIs就要打开页面才能运行项目.有不便之处,就改用Windows服务实现.这篇就总 ...
- c#写windows服务(转)
序言 前段时间做一个数据迁移项目,刚开始用B/S架构做的项目,但B/S要寄存在IIs中,而IIs又不稳定因素,如果重启IIs就要打开页面才能运行项目.有不便之处,就改用Windows服务实现.这篇就总 ...
- c#写windows服务 小demo
前段时间做一个数据迁移项目,刚开始用B/S架构做的项目,但B/S要寄存在IIs中,而IIs又不稳定因素,如果重启IIs就要打开页面才能运行项目.有不便之处,就改用Windows服务实现.这篇就总结下, ...
- C# 使用vs2013 写 windows服务
第一步:添加windows服务项目 并起一个 好看的名字 第二步:添加安装程序 第三步:右键点击serviceProcessInstaller1属性,在Account中选择LocalSystem 第四 ...
- 使用C#写windows服务
首先,创建一个windows服务项目
- Python搭建调用本地dll的Windows服务(浏览器可以访问,附测试dll64位和32位文件)
一.前言说明 博客声明:此文链接地址https://www.cnblogs.com/Vrapile/p/14113683.html,请尊重原创,未经允许禁止转载!!! 1. 功能简述 (1)本文提供生 ...
- VS2010 中,windows服务不能添加 System.Web 引用
今天在写windows服务的时候,右键添加引用->.NET中没有找到System.Web,在->Recent中找到System.Web,但添加完后却显示黄色叹号,最后百度一下解决了这个问题 ...
随机推荐
- Dedecms 数据库结构分析
本文主要是为了今后对Dedecms做二次开发所写.安装后dedecms的数据库结构,如(图1)所示, 安装后的dedecms一共有 86 张数据表. 主要数据结构表 dede_addonarticle ...
- 同步数据库到Codis代码
同步mysql数据库到codis缓存中 public void syncRule() { // 根据时间戳获取Mycat中规则表数据 logger.info("start ..." ...
- 【2048小游戏】——原生js爬坑之封装行的移动算法&事件
引言:2048小游戏的核心玩法是移动行,包括横行和纵行,玩家可以选择4个方向,然后所有行内的数字就会随着行的移动而向特定的方向移动.这个行的移动是一个需要重复调用的算法,所以这里就要将一行的移动算法封 ...
- 2016.7.5 如何在maven中添加所需依赖(只知道jar包的部分名字的情况)
(1)进入官网仓库 http://mvnrepository.com/ (2)输入需要的jar包名 比如这里的jota-time (3)寻找需要的版本,并选取需要的版本 (4)复制需要的maven依赖 ...
- 路飞学城Python爬虫课第一章笔记
前言 原创文章,转载引用务必注明链接.水平有限,如有疏漏,欢迎指正. 之前看阮一峰的博客文章,介绍到路飞学城爬虫课程限免,看了眼内容还不错,就兴冲冲报了名,99块钱满足以下条件会返还并送书送视频. 缴 ...
- codeforces 204(Div.1 A) Little Elephant and Interval(贪心)
题意: 有一种个位数与最高位数字相等的数字,求在l,r的范围内,这样的数字的个数. 思路: 找下规律就知道当当n>10的时候除去个位以后的答案等于n/10,然后考虑第一个数字是否小于最后一个.小 ...
- 怎么学习PS快?
PS快速入门笔记 软件界面: 菜单栏, 工具箱 工具属性栏 悬浮面板 画布 ctrl + N 新建画布 如果需要出图:分辨率:300 颜色模式:CMYK 屏幕显示: 分辨率: 72 颜色模式: ...
- struts2获取服务器临时目录
CreateTime--2017年9月7日08:57:39 Author:Marydon struts2获取服务器(tomcat.WebLogic)的临时目录 需要导入: import java. ...
- Attribute "resultType" must be declared for element type "insert".
这是mybatis插入数据库之后出现的问题,至于为什么出现这个问题,是因为插入的时候你照抄了查询的语句,插入的时候只有id属性和parameterType属性,并没有“resultType”属性,要注 ...
- Android TelephonyManager类的使用
TelephonyManager类主要提供了一系列获取手机与通讯相关的状态和信息的get方法,包含手机用户的信息.手机SIM的状态.电信网络的状态等. TelephonyManager类的对象的获取: ...