paramiko.ssh

paramiko.ssh,第1张

关于Python paramikomo模块 上传文件时报错的问题记录

前言:公司的java项目,目前没有实现cicd都是手动上传jar包更新的,为了提高自己的工作效率,所以使用了python脚本实现自动化一键部署上线更新。

具体实现

1、目录结构如下:

2、配置文件:没做备注的应该也很好看懂

3、脚本源代码:

# coding:utf-8
import time
import paramiko
import json

print("=" * 50)
D_R = input("请选择你要进行的 *** 作0发布/1回滚(默认为0):") or "0"

# 上传文件函数
def put_file(ip, port, user, passwd, src_path, dis_path):
    # 指定 目标主机的IP和端口
    transport = paramiko.Transport(ip, port)
    # 建立连接
    transport.connect(username=user, password=passwd)
    sftp = paramiko.SFTPClient.from_transport(transport)
    # 上传
    kk = sftp.put(src_path, dis_path)
    print(kk)
    # 关闭连接
    transport.close()


# 执行命令
def to_script(ip, port, user, passwd, bash, model=0):
    # 创建SSH对象
    ssh = paramiko.SSHClient()
    # 允许连接不在know_hosts文件中的主机
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    # 连接服务器
    ssh.connect(hostname=ip, port=port, username=user, password=passwd)
    if model == 0:
        stdin, stdout, stderr = ssh.exec_command(bash)
        time.sleep(5)
        res, err = stdout.read(), stderr.read()
        result = res if res else err
        print(result.decode().strip())
    else:
        chan = ssh.invoke_shell()
        out = chan.send(bash)
        print(out)
        time.sleep(2)
    # 关闭连接
    ssh.close()


# 生成启停脚本
def re_shell(pck_name, conf):
    start_bash = 'nohup  java  -jar -Dfile.encoding="utf-8"  -Dlog4j2.formatMsgNoLookups=true -Xms512m -Xmx512m ' + pck_name + '.jar >nohup.out &'
    stop_bash = "SPRINGBOOT_JAR_NAME='" + pck_name + ".ja[r]'\n"
    start_file = open('start.sh', 'r+', encoding='UTF-8')
    stop_modu_file = open('stop-modu.sh', 'r', encoding='UTF-8')
    stop_file = open('stop.sh', 'wb')
    config_file = open('ip_conf.txt', 'r+', encoding='UTF-8')

    start_file.write(start_bash.strip())
    start_file.close()

    config_file.write(conf.replace("'", '"').strip())
    config_file.close()

    stop_modu_text = stop_modu_file.read()
    stop_file.write(stop_bash.encode('utf-8'))
    stop_file.write(stop_modu_text.encode('utf-8'))
    stop_file.close()


# 处理配置文件
host_list = []  # 主机信息


def read_conf_to_dict():  # 解析配置文件
    f = open('ip_conf.txt', 'r', encoding='UTF-8')
    for i in f.readlines():
        line = i.strip()
        kk = json.loads(line)
        host_list.append(kk)
    f.close()


read_conf_to_dict()

# 执行参数
ip_list = host_list[0].get('ip').split()  # ip 列表
host_port = host_list[0].get('port')  # 端口
host_user = host_list[0].get('user')  # 用户名
host_passwd = host_list[0].get('passwd')  # 密码
src = host_list[0].get('file_name') + ".jar"  # 源文件
host_dist = host_list[0].get('dist_name')  # 目标路径
vaersion = host_list[0].get('vaersion')  # 是否第一次上传

# 需要执行的命令
mkdir_shell = "mkdir " + host_dist + "package/ -p"
stop_shell = 'cd ' + host_dist + '&& sh stop.sh'
start_shell = 'cd ' + host_dist + ' && sh start.sh \n'
bak_shell = "cd " + host_dist + ";mv " + src + " package/" + src + "-`date +%F`" + "-v" + str(vaersion)

print("=" * 50)
if D_R == "0":
    if vaersion == 0:
        print("您正在创建一个新项目!")
    else:
        print("这是您第" + str(vaersion) + "次更新!")

    host_list[0]['vaersion'] = vaersion + 1
    re_shell(host_list[0].get('file_name'), str(host_list[0]))

    for ip in ip_list:
        print("=" * 50)
        print("[" + ip + "]", end="")
        # 第一次上传
        if vaersion == 0:
            # 创建目录
            to_script(ip, host_port, host_user, host_passwd, mkdir_shell)
            # 上传脚本
            put_file(ip, host_port, host_user, host_passwd, "stop.sh", host_dist + "stop.sh")
            put_file(ip, host_port, host_user, host_passwd, "start.sh", host_dist + "start.sh")

        # 第一次 发布不需要执行打包
        if vaersion != 0:
            to_script(ip, host_port, host_user, host_passwd, bak_shell)

        # 上传jar包
        put_file(ip, host_port, host_user, host_passwd, src, host_dist + src)

        # 第一次 发布不需要执行停止
        if vaersion != 0:
            to_script(ip, host_port, host_user, host_passwd, stop_shell)

        # 启动
        to_script(ip, host_port, host_user, host_passwd, start_shell, 1)
        if vaersion == 0:
            print("完成!!!")
        else:
            print("完成!!!")
elif D_R == "1":
    print("您正在进行回滚 *** 作,完成后将回到指定版本!")
    print("=" * 50)
    vs = input("请选择你要回退到那个版本:")
    Rellbak_shell = "cd " + host_dist + ";rm -rf " + src + ";cp package/" + src + "-*" + "-v" + vs + " " + src
    for ip in ip_list:
        print("=" * 50)
        print("[" + ip + "]")
        # 停止进程
        to_script(ip, host_port, host_user, host_passwd, stop_shell)
        # 解压指定版本
        to_script(ip, host_port, host_user, host_passwd, Rellbak_shell)
        # 启动
        to_script(ip, host_port, host_user, host_passwd, start_shell, 1)
    print("=" * 50)
    print("完成!!!")
else:
    print("请输入正确的参数!!!!\n参数0为正常更新发布,参数1为回滚,默认为 0 !!")

print("=" * 50)

由于是脚本所以没有考虑太多的交互和异常处理!!!!至于启动和停止脚本需要根据项目不同进行调整!!!如果想照搬还是不建议的,还是要看懂然后自己能根据不完整的做出来就很Nice!!!不说了咱们回到正题。

具体报错信息如下

Linux下

PyCharm中

说明:

刚开始的时候按照上面的代码进行上线更新都没有问题,但是后来换到了其他服务器上时就开始报上面的错误了,网上找了很多教程都没有解决问题。

我是如何排查的:

1、第一反应就是账号密码错误,但是不是
2、ip或者端口错误,但是也不是
3、权限的问题,经过排查还是不是
4、难道服务器做了限制?? 但是我使用xftp是可以连接上传的,所以也可排除了

我是如何解决的:

破不得以我根据把报错信息,去看了源码:
C:\Users\admin\AppData\Local\Programs\Python\Python310\lib\site-packages\paramiko\transport.py

结合我们自己写的代码和源码,可以发现
官方希望我们传入的Ip和port是一个元组,而我们传入的只是两个分开 变量 transport = paramiko.Transport(ip, port) 所以导致了问题的出现!!!!
作用我只只需要这样修改一下源代码就Ok了:
transport = paramiko.Transport((ip, port)) 没错就是加一个括号十七成为一个元组!!!

结语:虽然问题很小但是还是卡了我很久,可能是因为太菜了吧!!!哈哈哈!!!希望可以帮到大家!!如果有大神知道为啥之前没有传入元组也可以成功欢迎留言科普!!!

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/886222.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-14
下一篇 2022-05-14

发表评论

登录后才能评论

评论列表(0条)

保存