微服务架构下自动化升级应用程序模块框架脚本

一、背景:

应用程序采用的是微服务架构,底座,子应用,工具互不干扰,独立运行,因此需要升级模块需要经历复杂的手续。

以底座为例子,首先需要去CI服务器拿包,再调用升级服务器接口,创建修改应用的接口,以post请求方式,请求体很长
创建或修改应用后,需要再次调用上传升级包的接口,上传升级包,还需要计算文件MD5.每次需要用windows的CMD命令执行,在升级子应用就需要重复一遍以上内容。

CertUtil -hashfile "C:\path\tofile\example.txt" MD5

再是发布版本接口,这个接口相对简单,发布完成后,需要从用户视角调用升级相关接口,查看升级连接返回的信息是否正确,

升级服务器只有开发提供的postman配置文件,打开导入即用。
简单来说这个流程不算复杂,但是重复性太强了,不够自动化,因此考虑设计一套简单的自动化升级

二、从CI执行机拿包

1、utils.py文件

先按照手动升级流程思路来确保自动化脚本编写思路,首先考虑的是从服务器拿包,定义一个pkg文件夹用来存放包
先写一个简单的工具,创建一个utils.py文件,里面存放一些方法用来处理和升级服务器不挂钩的功能,比如从服务器拿包和计算文件md5值

utils.py文件代码如下

def get_pkg(app,file_save_path,branch="develop"):
    '''
    从服务器下载文件
    :param app: 下载底座还是子应用包
    :param branch:分支,默认develop,也可以选择master
    :return:
    '''
    url = f'{download_url}/{branch}/{app}/{app}.zip'
    print(f"url:{url}\napp:{app}\nbranch:{branch}")
    res =requests.get(url=url,stream=True)
    if res.status_code == 200:
        total_size = int(res.headers.get('content-length', 0))
        downloaded_size = 0
        with open(file_save_path,"wb") as f:
            for chunk in res.iter_content(chunk_size=1024):
                downloaded_size += len(chunk)
                f.write(chunk)
                progress = (downloaded_size / total_size) * 100
                # 打印下载进度
                print(f"\r下载进度: {progress:.2f}%", end="")
        print("文件下载成功")
        return True
    else:
        print("文件下载失败,状态码:", res.status_code)
        return False

def calculate_md5(file_path):
    '''
    计算文件md5值
    :param file_path:
    :return:
    '''
    hash_md5 =hashlib.md5()
    with open(file_path,"rb") as f:
        for chunk in iter(lambda: f.read(4096), b""):
            #iter函数是Python的内置函数,它可以接受两个参数。第一个参数是一个可调用对象(在这里是我们的lambda表达式),
            # 第二个参数是一个哨兵值。iter会重复调用这个可调用对象,直到它返回的值等于哨兵值。
            # b"":这是一个空的字节字符串,它在这里作为哨兵值。当f.read(4096)到达文件末尾时,
            # 它会返回一个空的字节字符串b"",这时iter函数就会停止迭代。
            hash_md5.update(chunk)
    return hash_md5.hexdigest()

if __name__ == '__main__':
    print(calculate_md5(r'D:\Users\User\Desktop\CI\pkg\base.zip'))
    get_pkg("base",r'D:\Users\User\Desktop\CI\pkg\base.zip')

2、config.py配置文件

用来存放配置文件数据,解API耦合

config.py代码:
HOST_UPGRADE = "10.10.10.10:40"
HOST_APP_INFO = "10.10.10.10:41"
download_url="http://10.10.10.110:9999"
json_data = {
    "base": {
        "app_name": "base",
        "description": "base",
        "author": "base",
        "app_type": "uninstall",
        "label": "tool",
        "is_internal": False,
        "version": "5.0.4 BUILD 20240118082647",
    
    },
    "app2": {
        "app_name": "app2",
        "description": "app2",
        "author": "app2",
        "app_type": "uninstall",
        "label": "tool",
        "is_internal": True,
        "version": "5.0.6 BUILD 20240118083318",

    },
    "app1": {
        "app_name": "app1",
        "description": "app1",
        "author": "app1",
        "app_type": "uninstall",
        "label": "tool",
        "is_internal": True,
        "version": "5.0.11 BUILD 20240118083318",
 
}

form_data ={
    "app_name":"app",
    "version":"xxx",
    "pre_version":None,
    "md5":"md5",
    "type":"full_upgrade",
}

三、升级服务器API

升级服务器API模块代码,主要是针对三个升级服务器接口

1、api.py文件

import requests
from upgreade.config import HOST_UPGRADE, json_data, form_data, HOST_APP_INFO
from utils import calculate_md5


class UpgradeApi():

    #创建或修改应用版本接口url
    url = "http://"+HOST_UPGRADE+"/version"

    @classmethod
    def upgrade_acheck_base(cls,app,version):
        '''
        创建或修改应用版本接口
        :param app:
        :param version:
        :return:
        '''
        data =json_data[app]
        data["version"] =version
        print(f"data:{data}\nversion:{version}")
        return requests.post(url=cls.url,json=data)

   
    @classmethod
    def upload_pkg(cls,app,version,file_path):
        '''
        上传升级包接口
        :param app:
        :param version:
        :param file:
        :return:
        '''
        url = "http://"+HOST_UPGRADE+"/manager/pkg"
        data = form_data
        if app == "acheck-base":
            app = "base"
        data["app_name"]=app
        data["version"] =version
        data["md5"]=calculate_md5(file_path)

        print(f"data:{data}")
        with open(file_path,"rb") as f:
            files = {'file': (file_path, f)}  # 'file'是服务器端接收文件的字段名
            res =requests.post(url=url,data=form_data,files=files)
        return res

    @classmethod
    def public_version(cls,app,version):
        '''
        发布版本接口
        :param app:
        :param version:
        :return:
        '''
        url = "http://"+HOST_UPGRADE+"/manager/version"
        if app == "acheck-base":
            app = "base"
        date={
            "app_name":app,
            "version":version
        }
        return requests.put(url=url,json=date)

class GetUpgradeInfo():
    '''
    用户视角获取升级服务器相关接口
    '''
    @staticmethod
    def getlist():
        url = "http://"+HOST_APP_INFO+"/list"
        res =requests.get(url=url)
        print(res.json()["data"])
    @classmethod
    def getdownloadurl(cls,app):
        url = "http://"+HOST_APP_INFO+"/list"
        params={
            "app_name":app,
        }
        res = requests.get(url=url)
        print(res.json())


if __name__ == '__main__':
    # res=UpgradeApi.upgrade_acheck_base("5.0.7 BUILD 20240118082647")
    # print(res.json())
    GetUpgradeInfo.getdownloadurl("base")

四、自动化升级主函数

框架雏形就有了 ,这时候就可以写一个主函数,串联起全部功能

1、main.py文件

from upgreade.api import UpgradeApi
from utils import get_pkg

class Upgrade():
    @classmethod
    def upgrade(cls,app,file_path,version):
        '''
        发布升级主函数
        :param app: 需要升级的子应用
        :param file_path:下载文件路径和上传升级路径
        :param version:
        :return:
        '''
        #首先需要下载包
        print(f"app:{app}")
        res =get_pkg(app,file_path)
        if res :
            print("下载成功")
        #创建或修改应用版本
        if app == "base":
            UpgradeApi.upgrade_base(version)
        elif app == "app2":
            UpgradeApi.upgrade_app2(version)
        elif app == "app1":
            UpgradeApi.upgrade_app1(version)
        else:
            print("app输入异常")

        #上传升级包

        res =UpgradeApi.upload_pkg(app,version,file_path)
        print(res.json())
        if res.json()["message"] == "success":
            print("上传升级包成功")
        else:
            print("升级包上传失败")
            break

        #发布版本
        res =UpgradeApi.public_version(app,version)
        print(f"发布{res.json()}")
        if res.json()["message"] == "success":
            print("发布成功")
        else:
            print("发布失败")

if __name__ == '__main__':
    Upgrade.upgrade("base", r'D:\Users\User\Desktop\CI\pkg\base.zip',"5.0.7 BUILD 20240118082647")

五、运行效果及后言

1、运行效果

app:base
url:http://10.10.10.110:9999/develop/base/base.zip
app:acheck-base
branch:develop
下载进度: 100.00%文件下载成功
下载成功
{'code': 0, 'details': '', 'message': 'success'}
升级包上传成功
发布{'code': 0, 'data': {}, 'message': 'success'}
发布成功

2、后言

整体框架思路设计就是这样,如果后续有新的工具加入,只要在config添加相关信息,也可以直接用来自动升级,脚本设计的比较粗糙,先凑合着用,感兴趣的同学可以将print调试代码,搞成日志形式。后续如果有需要会考虑把整个框架打包,可以提供给其他同事使用。

所谓的自动化就是简化测试工作中,所有需要经常重复的流程,变成自动化执行,自动化执行可以提高工作效率。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值