为了让初级工程师也能快速的编写发布脚本,为此而编写了以下基础自动化发布SDK,方便工程师集成。
# -*- coding: utf8 -*-
'''
author by 天擎
This's deploy SDK.
'''
import os,sys,time,json
import urllib,urllib2,shutil,requests
from paramiko import SSHClient,AutoAddPolicy,SSHException,ssh_exception
reload(sys)
sys.setdefaultencoding('utf-8')
class deployutils:
def __doc__(self):
pass
def __init__(self,auth):
self.auth=auth
def timestamp(self):
timestamp = time.strftime("%Y%m%d-%H%M%S")
return timestamp
def rcopy(self,fsrc,fdst):
if os.path.exists(fsrc):
try:
if os.path.isfile(fsrc) and not os.path.isfile(fdst):
shutil.copy2(fsrc,fdst)
elif os.path.isdir(fsrc) and not os.path.isdir(fdst):
shutil.copytree(fsrc,fdst,symlinks=True,ignore=None)
except Exception,e:
print e
sys.exit(1)
else:
print 'source File or Dir not exists...'
sys.exit(1)
# backup('/root/anaconda-ks.cfg','/root','test.txt')
def backup(self,srcfile,dstdir,filename,prename=""):
prename = self.timestamp()
filename = dstdir + "/" + filename + prename
try:
result=self.rcopy(srcfile,filename)
except Exception ,e:
print e
result=0
finally:
return result
# sshexec('192.168.1.1','ls /root',user='docker')
def sshexec(self, remoteip=None,sshcmd=None, port=22, user='root'):
if remoteip and sshcmd:
client = SSHClient()
client.set_missing_host_key_policy(AutoAddPolicy())
try:
print 'invoke remote host ...'
client.connect(remoteip, port, username=user, timeout=120)
stdin, stdout, stderr = client.exec_command(sshcmd, get_pty=True, timeout=120)
if stdout:
for std in stdout.readlines():
print std.strip('\n')
exit_status = stdout.channel
if exit_status.recv_exit_status() == 1:
print 'exec command ,system exit status 1.'
return False
elif exit_status.recv_exit_status() == 0:
return True
elif stderr.read():
print 'remote exec error !'
return False
else:
print 'remote exec error !'
return False
except ssh_exception.NoValidConnectionsError,e:
print e
print '%s lose connect.'%(remoteip)
return 'retry'
except SSHException,e:
print e
finally:
client.close()
else:
print "exec parameter is empty ."
return False
# rsync file to remote ip
def rsync(self, localpath=None, remoteip=None, remotepath=None, user='root'):
if os.path.exists(localpath):
synccommand="scp -r " + localpath + " " + user + '@' + remoteip + ":" + remotepath
print synccommand
result = os.system(synccommand)
if result:
return 1
else:
return 0
# build release
def build(self, buildpath=None, buildcmd=None):
if os.path.isdir(buildpath) and buildcmd:
try:
from subprocess import Popen,check_output, PIPE, STDOUT
os.chdir(buildpath)
out = Popen(buildcmd,shell=True,stdout=PIPE, stderr=STDOUT,close_fds=True)
while True:
line = out.stdout.readline()
if not line and out.poll() is not None:
break
else:
print line.strip('\n')
if out.returncode == 0:
return True
else:
return False
finally:
pass
# post json data to db
def postJson(self, url=None, calldata={}, method='POST'):
urldata = urllib.urlencode(calldata)
### print url + '?' + urldata
if method == 'POST':
request = urllib2.Request(url, data=urldata)
elif method == 'GET':
request = urllib2.Request(url + '?' + urldata)
response = urllib2.urlopen(request)
if response.code == 200:
print response.read()
return True
else:
print 'Request % code not is 200.' %(url)
return False
# request remote url
def upProxy(self, url=None, pdata='', method='PUT'):
if url:
if method == "PUT":
result = requests.put(url,timeout=30,data=pdata,auth=self.auth)
if result.status_code == 200 and result.content == 'true':
return True
else:
return False
elif method == "DELETE":
result = requests.delete(url,timeout=30,data=pdata,auth=self.auth)
if result.status_code == 200 and result.content == 'true':
return True
else:
return False
elif method == "GET":
result = requests.get(url,timeout=30,auth=self.auth)
if result.status_code == 200:
return True
else:
return False
else:
print 'url empty.'
return False
#query upstream ips
def getServiceIps(self,url='',gdata={}):
if url and gdata:
getIps = requests.get(url,params=gdata,timeout=30)
#print getIps.url
if getIps.status_code == 200:
adlist = []
for ilist in getIps.json():
adlist.append(ilist['value'])
if adlist:
return adlist
else:
return False
else:
return False
else:
print "URL is None."
return False
#get rm release paths
def getRmPaths(self,url='',pdata={}):
if url and pdata:
getpaths = requests.post(url,data=pdata,timeout=30)
if getpaths.status_code == 200:
outList = []
#print getpaths.text
for ilist in getpaths.json():
if 'error_code' not in ilist:
outList.append(ilist['project_value'])
else:
print '%s,Operating rules are not satisfied.' %ilist
if outList:
return outList
else:
return False
else:
return False
else:
print "url or post params is None."
return False
# set nginx upstream proxy rule
def upstreamOp(self,url, pname, ip, op='down',weight='100'):
if pname and ip:
putData= '%s/%s' %(pname,ip)
urlData = url + putData
try:
if op == 'down':
pdata = '{"weight":' + weight + ', "max_fails":2, "fail_timeout":10, "down":1}'
if self.upProxy(urlData,pdata=pdata,method='PUT'):
print 'op offine.'
return True
else:
return False
elif op =='up':
pdata = '{"weight":' + weight + ', "max_fails":2, "fail_timeout":10, "down":0}'
if self.upProxy(urlData,pdata=pdata,method='PUT'):
print 'op online.'
return True
else:
return False
except Exception ,e:
print 'op server list error.'
print e
# set online or set offline
def onOff(self, inop):
if inop == 'Offine':
return 'down'
elif inop == 'Online':
return 'up'
# check url health
def checkUrl(self,url):
try:
result = requests.get(url,timeout=2,auth=self.auth)
#if result.status_code == 200:
if result.status_code == 200 and result.json()['code'] == "200":
return True
except Exception:
#print "check %s error." %(url)
return False
# build MySheBao Common
def buildCommon(self,releasename):
from config import config
buildpath = config['Common']['buildpath']
buildcmd = config['Common']['buildcmd']
buildcmd = buildcmd.replace('develop',releasename)
try:
if buildpath and buildcmd:
buildrlt = self.build(buildpath,buildcmd)
if buildrlt:
return True
else:
return False
else:
print 'buildpath or buildcmd is None.'
return False
except Exception ,e:
print e
def batchDeploy(self,projectname,node,config,userdata,op=None):
releasetime = self.timestamp()
getenv = projectname
projectname = getenv.split(":")[0]
remoteuser = config['remoteuser']
posturl = config['posturl']
geturl = config['geturl']
upurl = config['upurl']
downloadip = config['downloadip']
downloadurl = config['downloadurl']
rcodeln = config[projectname]['rcodeln']
localdir = config[projectname]['localdir']
buildpath = config[projectname]['buildpath']
rcodedir = config['rcodedir']
buildcmd = config['buildcmd']
projectenv = config['env']
# put release
print "############## put release ###############"
rd = rRedis()
getRelease = str(rd.rget(getenv))
print getRelease
if getRelease:
rcodedir = rcodedir + projectname + getRelease
else:
print 'Please select the Build job, run the compiler first.'
sys.exit(1)
releasename = projectname + getRelease
remoterlt = False
if op:
remoterlt = self.upstreamOp(upurl,projectname,node,'down')
else:
remoterlt = True
### restart remote app
if remoterlt:
ip = node.split (':')[0]
command = 'rm -f ' + rcodeln + '; rm -rf ' + rcodeln.split('.war')[0]
remoterlt = self.sshexec(ip, command,user=remoteuser)
### download release
if remoterlt:
wgetcmd = 'wget -O '+ rcodeln + ' ' + downloadurl + releasename
#print wgetcmd
remoterlt = self.sshexec(ip, wgetcmd,user=remoteuser)
if remoterlt:
time.sleep(3)
restart = config[projectname]['restart']
remoterlt = self.sshexec(ip, restart,user=remoteuser)
if remoterlt:
processid = 'ps aux|grep ' + rcodeln.split('webapps')[0] + '|grep -v grep'
remoterlt = self.sshexec(ip,processid,user=remoteuser)
if remoterlt:
### post release data
postdata = {
'username': userdata['username'],
'password': userdata['password'],
'project_name': projectname,
'project_key': getRelease,
'project_value': releasename + "," + rcodeln,
'member_ip': node,
'project_env':projectenv
}
print getRelease
if self.postJson(posturl, postdata):
remoterlt = True
else:
remoterlt = False
if remoterlt:
return True
else:
return False
def rollBack(self,projectname,node,config,op=None):
getenv = projectname
projectname = getenv.split(":")[0]
remoteuser = config['remoteuser']
posturl = config['posturl']
upurl = config['upurl']
downloadip = config['downloadip']
downloadurl = config['downloadurl']
rcodeln = config[projectname]['rcodeln']
# put release
print "############## rollback release ###############"
rd = rRedis()
getRelease = str(rd.rget(getenv))
print getRelease
if getRelease:
releasename = projectname + getRelease
if op:
remoterlt = self.upstreamOp(upurl,projectname,node,'down')
else:
remoterlt = True
### restart remote app
if remoterlt:
ip = node.split (':')[0]
command = 'rm -f ' + rcodeln + '; rm -rf ' + rcodeln.split('.war')[0]
remoterlt = self.sshexec(ip, command,user=remoteuser)
### download release
if remoterlt:
wgetcmd = 'wget -O '+ rcodeln + ' ' + downloadurl + releasename
remoterlt = self.sshexec (ip, wgetcmd, user=remoteuser)
if remoterlt:
time.sleep(5)
restart = config[projectname]['restart']
remoterlt = self.sshexec(ip, restart,user=remoteuser)
if remoterlt:
processid = 'ps aux|grep ' + rcodeln.split('webapps')[0] + '|grep -v grep'
remoterlt = self.sshexec(ip,processid,user=remoteuser)
if remoterlt:
return True
else:
return False
else:
print 'get release error.'
return False
def batchOnline(self,projectname,node,config):
upurl = config['upurl']
#### checkUrl ok and op online
checkurl = 'http://' + node + "/"+ projectname + "/checkhealth"
if self.checkUrl(checkurl):
print "%s ok." %(checkurl)
if self.upstreamOp(upurl,projectname,node,'up'):
#print "op upstream %s ok" %(node)
return False
else:
#print "%s not ready" %(node)
return node
def checkAppStatus(self,projectname,node,config):
checkurl = 'http://' + node + "/"+ projectname + "/checkhealth"
print checkurl
if self.checkUrl(checkurl):
print "%s ok." %(checkurl)
return False
else:
#print "%s not ready" %(node)
return node
### op redis
class rRedis:
def __init__(self,host='127.0.0.1',port='6379',password=None):
import redis
try:
self.rdpool = redis.ConnectionPool(host=host, port=port,password=password)
self.rdop = redis.Redis(connection_pool=self.rdpool)
except Exception, e:
print 'redis connect failed.'
print e
def rset(self, key,value):
if key and value:
try:
self.rdop.set(key,value,ex=99999999)
except Exception ,e:
print 'redis set error.'
print e
return False
return True
else:
print 'error,key or value is empty.'
def rget(self, key):
if key:
result = self.rdop.get(key)
if result:
return result
else:
return False
def rclose(self):
self.rdpool.release(self.rdpool.get_connection(self.rdpool))
print 'close redis connect.'
(ps: 本脚是较久以前编写,如需要在生产或其他环境使用,请另行改造)
网友评论