模拟 saltstack/ansible 系列三(基于短连接实现saltstack主要功能)
前言
前面讲了基于SSH的ansible实现,今天我来讲讲基于短连接方式的saltstack实现。
为什么要讲基于短连接的saltstack实现呢?
前面不是说saltstack是基于长连接的吗?原因就在于当你掌握了短连接的实现后,长连接就水到渠成了,你也更能理解到短连接和长连接实现的一个区别
Agent设计
不管是短连接实现还是长连接实现,都需要在远程主机起一个服务来承担Agent角色,就如同saltstack的salt-minion一样。
下面我们就基于flask
来简单实现一个短连接形式的agent(考虑性能的话可以使用sanic
,这里用flask
的原因是本人团队内部培训时,我主要培训的是flask
)
由于flask
属于第三方库,所以需要使用如下命令先行安装
pip install flask 复制代码
如果想做成和salt-minion二进制模式启动的话,我们还需要安装一个额外的模块pyinstaller
pip install pyinstaller 复制代码
以下是flask作为一个服务端基本的代码: app.py
from flask import Flask app = Flask(__name__) @app.route("/") def hello_world(): return "Hello, World!" if __name__ == "__main__": app.run(host="0.0.0.0", port=8080, debug=True) 复制代码
当我们执行这个代码时,程序将会监听8080
端口,请求http://127.0.0.1:8080
将会返回Hello, World!
$ python3 app.py * Serving Flask app 'app' (lazy loading) * Environment: production WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. * Debug mode: on * Running on all addresses. WARNING: This is a development server. Do not use it in a production deployment. * Running on http://127.0.0.1:8080/ (Press CTRL+C to quit) * Restarting with stat * Debugger is active! * Debugger PIN: 142-934-530 $ http http://127.0.0.1:8080 HTTP/1.0 200 OK Content-Length: 13 Content-Type: text/html; charset=utf-8 Date: Wed, 24 Nov 2021 14:46:12 GMT Server: Werkzeug/2.0.2 Python/3.10.0 Hello, World! 复制代码
此时,我们可以通过pyinstaller
将该程序编译成一个二进制程序
pyinstaller -F app.py 复制代码
saltstack功能分析与代码实现
连接远程主机
基于短连接实现的agent,连接远程主机功能只需要判断接口是否能通即可,如上我们请求http://127.0.0.1:8080
时返回200状态码,即可认为成功连接远程主机。
test.ping
ping功能的实现,我们可以写个ping接口,然后返回pong来实现,或者根据返回状态码是否为200来判断
我们把上边的app.py修改一下,加上ping接口
from flask import Flask app = Flask(__name__) @app.route("/ping", methods=["GET"]) def ping(): return "pong" if __name__ == "__main__": app.run(host="0.0.0.0", port=8080, debug=True) 复制代码
此时我们请求http://127.0.0.1:8080/ping
则会返回pong,此时即可认为远程主机在线
$ http http://127.0.0.1:8080/ping HTTP/1.0 200 OK Content-Length: 4 Content-Type: text/html; charset=utf-8 Date: Wed, 24 Nov 2021 15:04:58 GMT Server: Werkzeug/2.0.2 Python/3.10.0 pong 复制代码
cmd.run
执行命令我们可以再写一个接收POST请求的接口,接收一个参数,用于命令的传入,然后根据传入的命令在本地主机执行命令,获取命令返回的结果后响应给客户端。
我们把上边的app.py增加一个cmd接口
from flask import Flask, request import subprocess app = Flask(__name__) @app.route("/ping", methods=["GET"]) def ping(): return "pong" @app.route("/cmd", methods=["post"]) def cmd(): body = request.json cmd = body.get("cmd") # 基于subprocess.Popen方法执行本地shell命令 proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE) if proc: result = proc.stdout.read() return result else: return None if __name__ == "__main__": app.run(host="0.0.0.0", port=8080, debug=True) 复制代码
此时我们请求http://127.0.0.1:8080/cmd
,传入命令,则会返回命令结果
$ http http://127.0.0.1:8080/cmd cmd='df -h' HTTP/1.0 200 OK Content-Length: 590 Content-Type: text/html; charset=utf-8 Date: Wed, 24 Nov 2021 15:25:24 GMT Server: Werkzeug/2.0.2 Python/3.8.10 Filesystem Size Used Avail Use% Mounted on udev 957M 0 957M 0% /dev tmpfs 198M 1.1M 197M 1% /run /dev/sda1 20G 1.5G 18G 8% / tmpfs 990M 0 990M 0% /dev/shm tmpfs 5.0M 0 5.0M 0% /run/lock tmpfs 990M 0 990M 0% /sys/fs/cgroup /dev/sda15 98M 290K 98M 1% /boot/efi /dev/loop0 61M 61M 0 100% /snap/lxd/21843 /dev/loop2 29M 29M 0 100% /snap/snapd/13643 /dev/loop1 58M 58M 0 100% /snap/core20/1244 tmpfs 198M 0 198M 0% /run/user/1000 复制代码
上传文件
执行命令我们可以再写一个接收文件的接口,将客户端上传过来的文件保存到本地,可以接收一个目标目录的参数,用做存放文件的目录
我们把上边的app.py增加一个upload_file接口
from flask import Flask, request import subprocess app = Flask(__name__) @app.route("/ping", methods=["GET"]) def ping(): return "pong" @app.route("/cmd", methods=["post"]) def cmd(): body = request.json cmd = body.get("cmd") # 基于subprocess.Popen方法执行本地shell命令 proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE) if proc: result = proc.stdout.read() return result else: return None @app.route("/upload_file", methods=["post"]) def upload_file(): # 从请求中获取文件,如果上传的不是以file为key的文件,则认为未上传文件 if "file" not in request.files: return "not find file in request.files" file = request.files["file"] # 如果请求没有带dest参数,则dest默认为/opt dest = request.args.get("dest", "/opt") if file: file.save(dest) return "file uploaded successfully" return "upload error" if __name__ == "__main__": app.run(host="0.0.0.0", port=8080, debug=True) 复制代码
客户端代码如下:
def upload_file(src, dest): resp = requests.post( "http://127.0.0.1:8080/upload_file?dest=" + dest, files={"file": open(src, "rb")}, ) if resp.status_code == 200: return resp.text else: return None 复制代码
此时客户端请求http://127.0.0.1:8080/upload_file
,传入参数,则上传文件成功
下载文件
下载文件我们可以写个接口,接收文件所在目录地址和文件名2个参数
我们把上边的app.py增加一个download_file接口
from flask import Flask, request import subprocess app = Flask(__name__) @app.route("/ping", methods=["GET"]) def ping(): return "pong" @app.route("/cmd", methods=["post"]) def cmd(): body = request.json cmd = body.get("cmd") # 基于subprocess.Popen方法执行本地shell命令 proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE) if proc: result = proc.stdout.read() return result else: return None @app.route("/upload_file", methods=["post"]) def upload_file(): # 从请求中获取文件,如果上传的不是以file为key的文件,则认为未上传文件 if "file" not in request.files: return "not find file in request.files" file = request.files["file"] # 如果请求没有带dest参数,则dest默认为/opt dest = request.args.get("dest", "/opt") if file: file.save(dest) return "file uploaded successfully" return "upload error" @app.route("/download_file", methods=["post"]) def download_file(): body = request.json directory = body.get("directory") filename = body.get("filename") # send_from_directory用于发送本地的文件 return send_from_directory( directory=directory, filename=filename, as_attachment=True ) if __name__ == "__main__": app.run(host="0.0.0.0", port=8080, debug=True) 复制代码
客户端代码如下:
def download_file(src, dest): filename = src.split("/")[-1] directory = src.replace(filename, "") print(directory, filename) data = {"directory": directory, "filename": filename} resp = requests.post("http://127.0.0.1:8080/download_file", json=data) if resp.status_code == 200: with open(dest, "wb") as f: f.write(resp.content) return True else: return False 复制代码
以上接口基本上实现saltstack常用功能。下一文章我们来讲讲长连接实现saltstack基本功能
伪原创工具 SEO网站优化 https://www.237it.com/
作者:jackless
链接:https://juejin.cn/post/7035631025371742221