• django项目实现应用系统的自动更新


    需求:有多个应用系统部署在不同的WINDOWS机器上,应用通过IIS对外发布,并且同一个应用都有在多台机器上面实现负载均衡,每次应用发布更新手工处理不仅效率低,还存在一定的误操作的风险,为提高工作效率,使用DJANGO发布的站点对各个应用实现自动更新

    1、应用系统信息的表结构

    models.py

    class systeminfo(models.Model):
        id = models.IntegerField(primary_key=True)
        dnsname = models.CharField(max_length=50)
        systemurl = models.CharField(max_length=100)

    #用于保存应用系统的域名和应用的UNC路径(相对于部署DJANGO服务器的UNC),两个键最好联合唯一,避免重复更新

    后台数据库为SQLITE3,SETTINGS.PY的部份配置如下:

    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
        }
    }
     

    更新数据库

    python manage.py makemigrations

    python manage.py migrate

    2、为了实现系统的自动更新,必须先录入应用系统的基础的UNC信息到数据库

    urls.py加入:

    url(r'^addsysteminfo/$',views.addsysteminfo,name='addsysteminfo'),

    views.py写入addsysteminfo

    def addsysteminfo(request):
        if request.method=="POST":
            dnss=request.POST.get("dnsnames")
            urls=request.POST.get("systemurls")

            try:

                addlist=models.systeminfo(dnsname=dnss,systemurl=urls)
                addlist.save()
                return render(request,"addsysteminfo.html",{"login_err":"okay"})
            except Exception:
                 return render(request,"addsysteminfo.html",{"login_err":"fail"})
        else:
            return render(request,"addsysteminfo.html",{"login_err":"noset"})

    前端的addsysteminfo.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <form id="loginForm" action="{% url 'addsysteminfo' %}" method="POST"> {% csrf_token %}
    系统域名<input type="text" class="form-control" name="dnsnames" placeholder="系统域名"></br>
    系统URL<input type="text" class="form-control" name="systemurls" placeholder="系统URL"></br>

    <button class="btn btn-success btn-block" type="submit">
                                <b>提交</b>
                            </button>

    <h4 ><b>{{ login_err }}</b></h4>
        </form>
    </body>
    </html>

    录入系统信息的界面如下:

    应用系统做有负载均衡,多个UNC则录入多条记录

    3、实现应用系统自动更新的功能

    urls.py添加

    url(r'^uploads/$',views.uploads,name='uploads'),

    views.py写入该方法,目前只接受上传.ZIP的更新包

    def uploads(request):
        if request.method == "POST":
            dnss=request.POST.get("dns")
            request.encoding="utf-8"
            myFile =request.FILES.get("myfile", None)
            
            if not myFile:
                # returnHttpResponse("no files for upload!")
                return render(request,"uploads.html",{"login_err":"no files"})
            destination = open(os.path.join(".uploads",myFile.name),'wb+')
            for chunk in myFile.chunks():
                destination.write(chunk)
            destination.close()
            filepath=".\uploads\"+myFile.name

            try:
                sourcefiles=dbs2.openfiles(filepath,dnss)
            except Exception:
                return HttpResponse("UPFILE IS OK!,BUT CAN'T UPDATE"+filepath+dnss)


            try:
                #infolist=models.systeminfo.objects.get(dnsname=dnss)
                infolists=models.systeminfo.objects.all().values('systemurl').filter(dnsname=dnss)
                if not len(infolists):
                    return HttpResponse("not exists the system "+dnss)
                for dicts in infolists:
                    targetfile=dicts['systemurl']
                    try:
                        dbs2.copyfiles(str(sourcefiles),str(targetfile))
                    except Exception:
                        return HttpResponse("copy files fail")


            except Exception:
                return HttpResponse("not exists the system "+dnss)


            return HttpResponse("OKAY!")
            # return render(request,"uploads.html",{"login_err":"okay"})
        else:
            return render(request,"uploads.html",{"login_err":"noset"})
     

    调用了dbs2.py的两个方法:

    openfiles方法解压文件到指定的目录,并返回路径,相当于更新当中源文件夹的路径

    def openfiles(files,dnss):
        nowtime=time.strftime('%Y-%m-%d-%H-%M-%S',time.localtime(time.time()))+""
        z=zipfile.ZipFile(files,'r')
        #dnss=dnss+str(nowtime)
        dnss=str(dnss)+str(nowtime)
        paths="d:\uploads\"+dnss
        z.extractall(path=paths)
        #z.extractall(path='.\uploads\'+dnss)
        #return dnss
        return paths

    copyfiles方法:更新应用系统,更新前先备份被更新的文件到指定的目录

    def copyfiles(sourceDir, targetDir):
        if sourceDir.find(".svn") > 0:
            return
        for file in os.listdir(sourceDir):
            sourceFile = os.path.join(sourceDir, file)
            targetFile = os.path.join(targetDir, file)
            if os.path.isfile(sourceFile):
                if os.path.exists(targetDir):
                    #if os.path.exists(targetFile) and (os.path.getsize(targetFile) != os.path.getsize(sourceFile)):
                    if os.path.exists(targetFile):           #如果更新是替换现有的旧文件,则准备备份,并建立好对应的目录结构,以备还原
                        #nowtime=time.strftime('%Y-%m-%d-%H-%M-%S',time.localtime(time.time()))+""
                        nowtime=time.strftime('%Y-%m-%d-%H-%M',time.localtime(time.time()))+""       

                                                                           #时间精确到分钟,一次更新如果在几分钟内完成,可能备份文件在几个文件夹内
                        #bak=sourceDir+"bak\bak"
                        p1=os.path.dirname(sourceFile)        
                        p1=p1[11:]                                           #因为文件解压在D:uploads下,此处减掉前面D:uploads路径的11个字符
                        bak="D:\appbak\"+nowtime+"\"+p1
                        if not os.path.exists(bak):
                            os.makedirs(bak)

                        bakfile=os.path.join(bak,file)
                        # print bakfile
                        open(bakfile,"wb").write(open(targetFile,"rb").read())         #先备份文件
                        open(targetFile, "wb").write(open(sourceFile, "rb").read())
                    else:
                        open(targetFile, "wb").write(open(sourceFile, "rb").read())
                if not os.path.exists(targetDir):
                    os.makedirs(targetDir)
                    if not os.path.exists(targetFile):
                        open(targetFile, "wb").write(open(sourceFile, "rb").read())
            if os.path.isdir(sourceFile):
                First_Directory = False
                copyfiles(sourceFile, targetFile)

    前端的uploads.html

    <!DOCTYPE html>
    <html lang="UTF-8">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <form enctype="multipart/form-data" action="/uploads/" method="post">
        {% csrf_token %}
       <input type="file" name="myfile" />请上传.ZIP格式的更新包,目录结构为双击点开.ZIP即为应用的顶级目录
       <br/>
       <input type="submit" value="更新应用" />
        </br>
        应用域名<input type="text" class="form-control" name="dns" placeholder="应用域名">
        </br>
        <h4 ><b>{{ login_err }}</b></h4><br/><br/>
    ZIP范例</br>
    <img src="http://www.test.com/zip.jpg"/>
    </form>
    </body>
    </html>

    此时用户只需要上传更新包,并录入应用的域名,即可完成应用系统的更新

    注意:如果目标应用服务器即拷贝文件的目的路径,如果为LINUX系统,应用服务器可使用SAMBA服务发布共享,比如操作系帐号root,对应新建samba帐号,smbpasswd  -a  roo,密码可以设置为与操作一致。

    另外如果部署DJANGO的服务器为WINDOWS服务器,可在WINDOWS服务器上面建立同名同密码的root帐号,再用root帐号启动对应的程序程。

  • 相关阅读:
    python-django学习
    c++异常处理
    Python输入输出
    Python变量
    Python异常处理
    Python起源与发展
    vsftpd基于mysql的认证方式
    vsftpd搭建ftp服务,并实现虚拟用户访问
    httpd结合php的fpm模式
    编译安装apache
  • 原文地址:https://www.cnblogs.com/TOLLA/p/9646885.html
Copyright © 2020-2023  润新知