需求:有多个应用系统部署在不同的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 ></br>

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

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

 

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

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

应用系统做有负载均衡,多个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帐号启动对应的程序程。