基础自动化发布SDK,Python版

为了让初级工程师也能快速的编写发布脚本,为此而编写了以下基础自动化发布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: 本脚是较久以前编写,如需要在生产或其他环境使用,请另行改造)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,711评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,932评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,770评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,799评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,697评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,069评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,535评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,200评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,353评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,290评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,331评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,020评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,610评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,694评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,927评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,330评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,904评论 2 341

推荐阅读更多精彩内容

  • Python 面向对象Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对...
    顺毛阅读 4,205评论 4 16
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,563评论 18 139
  • http://python.jobbole.com/85231/ 关于专业技能写完项目接着写写一名3年工作经验的J...
    燕京博士阅读 7,543评论 1 118
  • 所谓的 glob 模式是指 shell 所使用的简化了的正则表达式。星号(*)匹配零个或多个任意字符;[abc]匹...
    我是强强阅读 252评论 0 0
  • 听了今天的彭彭的新课,才发现为什么平常宝宝要是用了一个而且,我们大人都感觉很不同,今天和宝宝聊天的时候我刻意的听,...
    幽香_5126阅读 161评论 0 0