由于有段时间一个项目要上Tmall 聚石塔服务,那么按照传统的部署方式已不能满足需求.主要原因如下是, Tmall 聚石塔使用的是docker服务,docker服务的话无ssh命令操作启动服务极其不便. 有通过ssh通道去操作,很多情况下是对失败的,无法控制操作结果. 于是乎我就研究了一下,聚石塔的Api,那么再于是乎呢就有了如下简略的自动发布Api服务脚本. 如有看官不满于此脚本功能请自行开发.
本脚本使用Python编写,本脚本适用于发布JAVA编写的服务.
下面脚本分为两部分,一是配置部分,二是操作部分:
1.###jushita_config 配置部分
config={
'remote_host' : 'x.x.x.x', ###发布到聚石塔主机上用于聚石塔docker服务去自动下载之用
'push_path':'/data/codebackup/', ###聚石塔主机上存储路径
'deploy_url':'http://x.x.x.x/', ###此URL是提供给聚石塔自动下载的URL
'build_command':'git checkout develop && git pull && mvn clean install -Dmaven.test.skip=true',###编译命令
'sync_command':'scp -r ', ###同步编译后的war包
'TestTomcat':
{
'TestNodeID':[${id}],
'build_dir':'${dir}',
'war_filename':'test.war',
'war_path_dir':'${dir}/target/'
}, ###这子配置可以多个配置用于自定义的其他服务
}
2.发布具体操作部分
#!/bin/env python
# -*- coding: utf-8 -*-
### author by 天擎
import time,sys,os,time
import hashlib,hmac,urllib2,urllib,json
from paramiko import SSHClient,AutoAddPolicy
from jushita_config import config
###define request api timestamp
def gettimestamp():
timestamp = str(int(time.time()*1000))
return timestamp
###get sign
def getsign(data={},popkey='secretkey'):
if data:
dlist=[]
getstr=''
secretvalue=data.get(popkey)
for k in data:
if k != popkey:
mergestr=k+data.get(k)
dlist.append(mergestr)
stlist=sorted(dlist)
for i in stlist:
getstr += i
getstr = secretvalue + getstr + secretvalue
getstr = getstr.encode('utf-8')
return hmac.new(secretvalue,getstr).hexdigest().upper()
###request api
def callapi(url=None,calldata={},sign=None,method='GET',popkey='secretkey'):
calldata.pop(popkey)
urldata=urllib.urlencode(calldata)
if method == 'POST':
request = urllib2.Request(url,data=urldata)
elif method == 'GET':
request = urllib2.Request(url + '?' + urldata)
request.add_header('Authorization',sign)
response = urllib2.urlopen(request)
return response.read()
###switch url
def swurl(url=None,op=None,opcommand=None):
commlist=('container','command','host','service','node','image')
if not opcommand:
opcommand=''
if op in commlist:
return url + "/"+ op + opcommand
###get getcontainer messages
def getcontainers(tdict={},getcommand=None):
tdict = json.loads(tdict)
tlist = []
if tdict and getcommand:
for j in tdict['data']:
storelist = []
v = dict(j.get('nodes')[0])
tname = j.get('name')
tnodeid = v['containers'][0].get('nodeId')
print tname + ": " + str(tnodeid)
###get operating result
def commandget(gdict={}):
if gdict.get('message') and gdict['message'] == 'success':
print '++++++++++++++++ Waiting deploy result ... +++++++++++++++'
while True:
time.sleep(10)
commandid = gdict['data']['commandId']
commandcalldata = {
'accesskey' : basedata['accesskey'],
'secretkey' : basedata['secretkey'],
'timestamp' : gettimestamp()
}
comsign = getsign(commandcalldata)
opcommand = '/' + commandid
comurl = swurl(url=sourceurl,op='command',opcommand=opcommand)
comdict = callapi(comurl,commandcalldata,sign=comsign,method='GET')
pcomdict = json.loads(comdict,encoding='utf-8')
if 'data' in pcomdict.keys():
if pcomdict['data']['status'] == 'DONE':
print 'Deploy DONE.'
print '=============== Deploy Success ^_^ ================='
break
else:
print 'Deploy Waiting...'
print 'Status: %s' %(pcomdict['data']['status'])
else:
print 'Query data error , Upcoming retry .'
#print unicode(comdict,'utf-8')
else:
print '=============== Deploy Failed ::>_<:: ================='
sys.exit(1)
###build project
def buildproject(buildcommand=None,buildpath=None):
if os.path.isdir(buildpath) and buildcommand:
try:
os.chdir(buildpath)
result = os.system(buildcommand)
except Exception,e:
print Exception,":",e
return result
###rsync project to jushita
def projectsync(remoteip=None,remotepath=None,localpath=None,projectname=None,pushurl=None):
localpath = localpath + projectname
projectname = timestamp + projectname
if os.path.exists(localpath):
synccommand = tconfig['sync_command'] + localpath + ' '+ 'root@'+ remoteip + ':' + remotepath + projectname
result = os.system(synccommand)
if result:
result = 0
return result
else:
return pushurl + projectname
###ssh remote command
def sshexec(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=20)
stdin, stdout, stderr = client.exec_command(sshcmd,get_pty=True,timeout=120)
if stdout:
for std in stdout.readlines():
print std
else:
print 'remote exec error !'
finally:
client.close()
else:
print "exec parameter is empty ."
###get getcontainer nodeid
def getnodeid():
calldata={
'accesskey':'xx',
'secretkey':'xxx',
'timestamp':gettimestamp()
}
geturl = swurl(url=sourceurl,op='service',opcommand='')
sign = getsign(calldata)
tdict = callapi(url=geturl,calldata=calldata,sign=sign,method='GET')
nodeid = str(getcontainers(tdict,getcommand='containers'))
print nodeid
if __name__ == '__main__':
###define source data
gdict = {}
basedata = {
'accesskey':'xx',
'secretkey':'xxx'
}
sourceurl = 'http://open-ews.cloud.tmall.com/api/v1'
timestamp = time.strftime("%Y%m%d%H%M%S-")
svrlist = ('TestTomcat')
###print nodeid
if sys.argv[1] == 'getnodeid':
getnodeid()
sys.exit(0)
### build and deploy
project = sys.argv[1]
projectenv = sys.argv[2]
if projectenv =='TestNodeID':
buildcommand = tconfig['build_command']
else:
print 'ENV imput error.'
sys.exit(1)
buildpath = tconfig[project]['build_dir']
if project in svrlist:
projectpath = tconfig[project]['war_path_dir']
projectname = tconfig[project]['war_filename']
projectnodeid = tconfig[project][projectenv]
pushurl = tconfig['deploy_url']
remoteip = tconfig['remote_host']
remotepath = tconfig['push_path']
if project == svrlist[0]:
projectenv = 'TestNodeID'
for nodeid in projectnodeid:
buildresult = buildproject(buildcommand,buildpath)
if buildresult:
print 'Build Error ...'
sys.exit(1)
else:
print 'Build Succes ...'
pushurl = projectsync(remoteip,remotepath,projectpath,projectname,pushurl)
if pushurl:
print 'PushUrl: %s' %(pushurl)
print 'NodeID: %s' %(nodeid)
if nodeid and pushurl:
nodecalldata = {
'accesskey' : basedata['accesskey'],
'secretkey' : basedata['secretkey'],
'node_id' : nodeid,
'url' : pushurl,
'method' : 'PARALLEL',
'timestamp' : gettimestamp()
}
resign = getsign(nodecalldata)
opcommand = '/' + str(nodeid) + '/'+ 'uploadStart'
nodeurl = swurl(url=sourceurl,op='node',opcommand=opcommand)
redict = callapi(nodeurl,nodecalldata,sign=resign,method='POST')
gdict = json.loads(redict)
commandget(gdict)
print 'The deploy process end .'
else:
print 'Sync Error ...'
if project in svrdeplist:
buildproject(buildcommand,buildpath)
print 'Building process end.'