版本更新发布WEB化(2)_自定义功能函数

前言

这些功能函数主要是完成上传、解压、校验、覆盖、备份等功能,代码可能写的不够优雅,但是肯定可用(我们正式环境也一样只是敏感信息剔除替换了)。

更新包上传

zip(文件)更新包上传,实现从本地上传zip包或从ftp服务器上直接拉取zip包的功能。
本地上传zip更新包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#fname是通过html标签<input type="file" name="zipname" />获取的
#path是上传文件保存的目录

def uploadedFile(path, fname):
try:
if not os.path.exists(path):
os.makedirs(path)
file_name = path + fname.name
destination = open(file_name, 'wb+')
for chunk in fname.chunks():
destination.write(chunk)
destination.close()
os.chmod(file_name,stat.S_IRUSR|stat.S_IWUSR|stat.S_IRGRP|stat.S_IROTH)
return '0'
except Exception, e:
return e
```

从ftp服务器上直接拉取zip包

``` python
#fname是通过html标签<input type="text" class="form-control" name="filename" placeholder="Input Zip Name">获取的
#flag项目标识符

def ftpDownload(filename, flag):
server = ['ftp server ip', '21', 30]
project1 = ['ftp用户名', 'ftp密码']
project2 = ['ftp用户名', 'ftp密码']
#每个项目有不同的子项目,这样就会有不同子项目的目录
sub subproject1 = ['sub1/', 'sub2/', 'sub3/']
subproject2 = ['sub1/', 'sub2/', 'sub3/']
localdir = '/opt/git/'
zipname = filename + '.zip'
#/////////////////////////#
ftp = FTP()
ftp.connect(server[0], server[1], server[2])
if flag == 'a' or flag == 'b' or flag == 'f':
ftp.login(project1[0], project1[1])
if flag == 'a':
ftp.cwd(subproject1[0]) downzip = localdir + subproject[0] + 'upload/' + zipname
elif flag == 'b':
ftp.cwd(subproject1[1]) downzip = localdir + subproject[1] + 'upload/' + zipname
elif flag == 'f':
ftp.cwd(subproject1[1]) downzip = localdir + subproject[2] + 'upload/' + zipname
else:
ftp.login(project2[0], project2[1])
if flag == 'c':
ftp.cwd(subproject2[0]) downzip = localdir + subproject2[0] + 'upload/' + zipname
elif flag == 'd':
ftp.cwd(subproject[1]) downzip = localdir + subproject2[1] + 'upload/' + zipname
elif flag == 'e':
ftp.cwd(subproject[2]) downzip = localdir + subproject2[2] + 'upload/' + zipname
files = ftp.nlst()
if zipname in files:
f = open(downzip, 'wb')
ftp.retrbinary('RETR %s'%(zipname), f.write)
ftp.delete(zipname)
f.close()
ftp.close()
return '0'
ftp.close()
return False
校验文件

校验文件内容

1
2
3
4
5
6
def md5sum(filename):
fd = open(filename,"r")
fcont = fd.read()
fd.close()
fmd5 = hashlib.md5(fcont)
return fmd5.hexdigest()
校验更新包

zip包解压和校验,大致思路如下:
如果不是回滚包则做解压和校验的操作,如果是回滚包则只做解压的操作,
按照zip包提供的文件逐一对每个文件解压并记录校验值,将校验值存放到列表upmd5list[],
读取readme.txt文件中的校验值并将读取到的校验值存放到列表remd5list[],
upmd5list[]remd5list[]排序后比较,来判断实际校验值与提供的校验值是否相等。
zip包的文件采用的是相对全路径

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#basedir是所有项目的根目录/opt/git/
#zipname是zip包名
def unzip(basedir, zipname):
filename = zipname.replace(r'.zip', '')
tempdir = basedir + r'temp'
if r'old.zip' in zipname:
proname = basedir.split(r'/')[-2]
backdir = basedir + proname + r'.back/'
zipname = backdir + zipname
else:
zipname = basedir + r'upload/' + zipname
if zipfile.is_zipfile(zipname):
zipFile = zipfile.ZipFile(zipname)
upmd5list = []
remd5list = []
for file in zipFile.namelist():
zipFile.extract(file, tempdir)
filepath = tempdir + r'/' + file
if os.path.isfile(filepath) and r'readme.txt' not in file:
upmd5list.append({file.replace(filename + '/' , ''): md5sum(filepath)})
if r'readme.txt' in file:
pass
zipFile.close()
#//////////////////////////#
if r'old.zip' in zipname:
return True
#//////////////////////////#
try:
readme = open(tempdir + r'/' + filename +r'/readme.txt', "r")
except:
shutil.rmtree(tempdir + r'/' + filename, True)
return False
try:
allmd5 = readme.read()
finally:
readme.close()
allmd5 = allmd5.split('#')[1].split("\n")
readmd5 = []
for md5 in allmd5:
if md5 != '\r' and md5 != '':
md5 = md5.replace('\r', '').split("\t")
readmd5.append({md5[0]:md5[1]})
#////////////////////////#
readmd5.sort()
upmd5list.sort()
if readmd5 == upmd5list:
return True
else:
return False
else:
return False
文件更新和备份

文件替换并将被替换的原文件打包,大体思路如下:
用解压到temp目录的文件替换.work目录中的文件,没有文件就是拷贝了、没有目录就创建,
将被替换的文件按照相对全路径打包成update01.old.zip的zip包,可以回滚到update01更新前的状态,
打包文件存放在.back目录(.back、.work等目录就是将项目代码目录加上的后缀便于识别如:project1.work、project1.server、project.back目录等)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
def mkzip(basedir, zipname):
proname = basedir.split(r'/')[-2]
filename = zipname.replace(r'.zip', '')
zipname = basedir + r'upload/' + zipname
tempdir = basedir + r'temp/' + filename
workdir = basedir + proname + r'.work'
if zipfile.is_zipfile(zipname):
upzip = zipfile.ZipFile(zipname)
backzip = basedir + proname + r'.back/' + filename + r'.old.zip'
newzip = zipfile.ZipFile(backzip, 'w')
#打包被更新文件到back目录后再更新work目录
for file in upzip.namelist():
tempfile = file.replace(filename, tempdir)
workfile = file.replace(filename, workdir)
if os.path.isdir(tempfile):
if not os.path.exists(workfile):
os.makedirs(workfile)
os.chmod(workfile,stat.S_IRUSR|stat.S_IWUSR|stat.S_IXUSR|stat.S_IRGRP|stat.S_IROTH)
else:
if os.path.exists(workfile):
newzip.write(workfile, file, zipfile.ZIP_DEFLATED)
if r'readme.txt' not in tempfile:
shutil.copyfile(tempfile, workfile)
os.chmod(workfile,stat.S_IRUSR|stat.S_IWUSR|stat.S_IRGRP|stat.S_IROTH)
upzip.close()
newzip.close()
shutil.rmtree(tempdir,True) os.chmod(backzip,stat.S_IRUSR|stat.S_IWUSR|stat.S_IRGRP|stat.S_IROTH) return True
else:
return False
文件回滚

回滚文件,大体思路如下:
将.back目录中的update.old.zip包中的备份文件替换.work目录中的同名文件或直接拷贝
例如update01.old.zip包只能回滚到update01更新包之前的状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def backzip(basedir, zipname):
proname = basedir.split(r'/')[-2]
filename = zipname.replace(r'.zip', '')
zipname = basedir + proname + r'.back/' + filename + r'.old.zip'
tempdir = basedir + r'temp/' + filename
workdir = basedir + proname + r'.work'
if zipfile.is_zipfile(zipname):
upzip = zipfile.ZipFile(zipname)
for file in upzip.namelist():
tempfile = file.replace(filename, tempdir)
workfile = file.replace(filename, workdir)
shutil.copyfile(tempfile, workfile)
upzip.close()
shutil.rmtree(tempdir,True)
return True
else:
return False
更新提交

提交下发更新文件,其中自定义的saltAPI类下篇专门介绍。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#slsfile是salt服务器上的sls文件
#gname是salt的分组后的组名
#falg标识是发布到正式环境还是发布到测试环境
def updateObject(workdir, serverdir, slsfile, gname, comminfo, flag):
workdir = r'/opt/git/' + workdir
serverdir = r'/opt/git/' + serverdir
sapi = saltAPI()
params = {'client':'local', 'tgt':'git server服务器的key', 'fun':'git.add', 'arg1':workdir, 'arg2':workdir}
Info = sapi.saltCmd(params)
params = {'client':'local', 'tgt':'git server服务器的key', 'fun':'git.status', 'arg1':workdir}
Info.append(sapi.saltCmd(params))
params = {'client':'local', 'tgt':'git server服务器的key', 'fun':'git.commit', 'arg1':workdir, 'arg2':comminfo}
Info.append(sapi.saltCmd(params))
params = {'client':'local', 'tgt':'git server服务器的key', 'fun':'git.push', 'arg1':workdir, 'arg2':serverdir, 'arg3':r"branch='master'"}
Info.append(sapi.saltCmd(params))
#//////////////////#
if flag:
params = {'client':'local', 'tgt':'测试环境服务器的key', 'fun':'state.sls', 'arg1':slsfile}
pullinfo = sapi.saltCmd(params)
else:
params = {'client':'local', 'tgt':gname, 'expr_form':'nodegroup', 'fun':'state.sls', 'arg1':slsfile}
pullinfo = sapi.saltCmd(params)
#///////////////#
repullinfo = []
for key in pullinfo[0]:
repullinfo.append(key)
repullinfo.append(pullinfo[0][key].values()[0]['name'])
repullinfo.append(pullinfo[0][key].values()[0]['result'])
res = [Info[1][0]['git server服务器的key'], Info[2][0]['git server服务器的key'], repullinfo]
return res
----------------本文结束 感谢阅读----------------