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

这些功能函数主要是完成上传、解压、校验、覆盖、备份等功能,代码可能写的不够优雅,但是肯定可用(我们正式环境也一样只是敏感信息剔除替换了)。
1、zip(文件)更新包上传,实现从本地上传zip包或从ftp服务器上直接拉取zip包的功能。
本地上传zip更新包

#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包

#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

2、校验文件内容

def md5sum(filename):
	fd = open(filename,"r")
	fcont = fd.read()
	fd.close()
	fmd5 = hashlib.md5(fcont)
	return fmd5.hexdigest()

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

#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

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

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

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

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

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

#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

转载请注明出处:http://www.xiaomastack.com/2014/10/13/release-2/ 谢谢!

发表评论:

你的电子邮件地址将不会被公开.

− 5 = 1