授之以渔-运维平台发布模块三(Jenkins篇)

接上篇《授之以渔-运维平台发布模块二(Jenkins篇)》,今天介绍下项目的回滚机制。

我的平台用到Jenkins API的创建项目,删除,更新,查看变更,构建。

一、利用Jenkins-python 创建项目

    def create_job(self, name, config_xml):
        if self.job_exists(name):
            raise JenkinsException('job[%s] already exists' % (name))

        headers = {'Content-Type': 'text/xml'}
        self.jenkins_open(urllib2.Request(
            self.server + CREATE_JOB % locals(), config_xml, headers))
        if not self.job_exists(name):
            raise JenkinsException('create[%s] failed' % (name))

我的平台需要做的就是传递一个项目名称,一个config_xml(配置文档),在用程序生成config_xml,我传递了下面几个参数:svn_daysToKeep,svn_numToKeep,svn_name,svn_publish_address,svn_address,svn_name,svn_name
svn_daysToKeep:构建项目保存时间,过了时间会自动删除以前的
svn_numToKeep:构建项目保存版本号数量,过了数量会自动删除以前的
svn_name:构建项目名称
svn_publish_address:发布地址(RPM包安装地址,构建FPM请参看之前的文章)
svn_address:SVN地址
config_xml如下:

"""<?xml version='1.0' encoding='UTF-8'?>
<project>
  <actions/>
  <description></description>
  <logRotator class="hudson.tasks.LogRotator">
    <daysToKeep>%s</daysToKeep>
    <numToKeep>%s</numToKeep>
    <artifactDaysToKeep>-1</artifactDaysToKeep>
    <artifactNumToKeep>-1</artifactNumToKeep>
  </logRotator>
  <keepDependencies>false</keepDependencies>
  <properties>
    <hudson.plugins.batch__task.BatchTaskProperty plugin="batch-task@1.16">
      <tasks>
        <hudson.plugins.batch__task.BatchTask>
          <name>%s</name>
            <script>mkdir -p /home/release/$JOB_NAME  && fpm -s dir -x .svn -t rpm -n $JOB_NAME -v $BUILD_NUMBER --prefix %s -C /var/lib/jenkins/workspace/$JOB_NAME -p  /home/release/$JOB_NAME  ./ && createrepo --update /home/release/$JOB_NAME/  && curl -d "job_id=$JOB_NAME" http://172.18.18.24/cmdb/salt_jenkins_post/</script>
        </hudson.plugins.batch__task.BatchTask>
      </tasks>
    </hudson.plugins.batch__task.BatchTaskProperty>
  </properties>
  <scm class="hudson.scm.SubversionSCM" plugin="subversion@1.45">
    <locations>
      <hudson.scm.SubversionSCM_-ModuleLocation>
        <remote>%s</remote>
        <local>.</local>
        <depthOption>infinity</depthOption>
        <ignoreExternalsOption>false</ignoreExternalsOption>
      </hudson.scm.SubversionSCM_-ModuleLocation>
    </locations>
    <excludedRegions></excludedRegions>
    <includedRegions></includedRegions>
    <excludedUsers></excludedUsers>
    <excludedRevprop></excludedRevprop>
    <excludedCommitMessages></excludedCommitMessages>
    <workspaceUpdater class="hudson.scm.subversion.UpdateUpdater"/>
    <ignoreDirPropChanges>false</ignoreDirPropChanges>
    <filterChangelog>false</filterChangelog>
  </scm>
  <canRoam>true</canRoam>
  <disabled>false</disabled>
  <blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
  <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
  <triggers/>
  <concurrentBuild>false</concurrentBuild>
  <builders/>
  <publishers>
    <hudson.tasks.Mailer plugin="mailer@1.5">
      <recipients>21186716@qq.com</recipients>
      <dontNotifyEveryUnstableBuild>false</dontNotifyEveryUnstableBuild>
      <sendToIndividuals>true</sendToIndividuals>
    </hudson.tasks.Mailer>
    <hudson.plugins.batch__task.BatchTaskInvoker plugin="batch-task@1.16">
      <configs>
        <hudson.plugins.batch__task.BatchTaskInvoker_-Config>
          <project>%s</project>
          <task>%s</task>
        </hudson.plugins.batch__task.BatchTaskInvoker_-Config>
      </configs>
      <threshold>
        <name>UNSTABLE</name>
        <ordinal>1</ordinal>
        <color>YELLOW</color>
      </threshold>
    </hudson.plugins.batch__task.BatchTaskInvoker>
  </publishers>
  <buildWrappers/>
</project>"""%(svn_daysToKeep,svn_numToKeep,svn_name,svn_publish_address,svn_address,svn_name,svn_name)

有了项目名和配置文件,只需要调用jenkins-python接口即可:

from cmdb.myapi.jenkins import jenkins_remote
J = jenkins_remote.Jenkins(jenkins服务器地址,jenkins用户名,jenkins token)
J.create_job(项目名, 项目的config_xml)

至于Jenkins的Token如何生成呢?

登录系统-点击右上角你的用户名称

Paste_Image.png

点击设置-点击Show API Token

Paste_Image.png

二、利用Jenkins-python 构建项目

    def build_job(self, name, parameters=None, token=None):
        if not self.job_exists(name):
            raise JenkinsException('no such job[%s]' % (name))
        return self.jenkins_open(urllib2.Request(
            self.build_job_url(name, parameters, token)))

构建一样要用token,然后的动作就是传入项目名了。

怎么判断一次构建是否完成呢?

    def get_job_info(self, name):
        try:
            response = self.jenkins_open(urllib2.Request(
                self.server + JOB_INFO % locals()))
            if response:
                return json.loads(response)
            else:
                raise JenkinsException('job[%s] does not exist' % name)
        except urllib2.HTTPError:
            raise JenkinsException('job[%s] does not exist' % name)
        except ValueError:
            raise JenkinsException(
                "Could not parse JSON info for job[%s]" % name)

返回结果

>>> J.get_job_info('bbs.youth.cn')
{u'scm': {}, u'color': u'blue', u'lastSuccessfulBuild': {u'url': u'http://172.18.11.98:8080/job/bbs.youth.cn/137/', u'number': 137}, u'actions': [{}, {}], u'lastCompletedBuild': {u'url': u'http://172.18.11.98:8080/job/bbs.youth.cn/137/', u'number': 137}, u'lastUnsuccessfulBuild': None, u'upstreamProjects': [], u'lastFailedBuild': None, u'healthReport': [{u'iconUrl': u'health-80plus.png', u'score': 100, u'description': u'Build stability: No recent builds failed.'}], u'queueItem': None, u'lastBuild': {u'url': u'http://172.18.11.98:8080/job/bbs.youth.cn/137/', u'number': 137}, u'lastStableBuild': {u'url': u'http://172.18.11.98:8080/job/bbs.youth.cn/137/', u'number': 137}, u'description': u'\u9752\u7f51\u8bba\u575b', u'downstreamProjects': [], u'concurrentBuild': False, u'lastUnstableBuild': None, u'buildable': True, u'displayNameOrNull': None, u'inQueue': False, u'keepDependencies': False, u'name': u'bbs.youth.cn', u'displayName': u'bbs.youth.cn', u'builds': [{u'url': u'http://172.18.11.98:8080/job/bbs.youth.cn/137/', u'number': 137}, {u'url': u'http://172.18.11.98:8080/job/bbs.youth.cn/136/', u'number': 136}, {u'url': u'http://172.18.11.98:8080/job/bbs.youth.cn/135/', u'number': 135}, {u'url': u'http://172.18.11.98:8080/job/bbs.youth.cn/134/', u'number': 134}, {u'url': u'http://172.18.11.98:8080/job/bbs.youth.cn/133/', u'number': 133}, {u'url': u'http://172.18.11.98:8080/job/bbs.youth.cn/132/', u'number': 132}, {u'url': u'http://172.18.11.98:8080/job/bbs.youth.cn/131/', u'number': 131}, {u'url': u'http://172.18.11.98:8080/job/bbs.youth.cn/130/', u'number': 130}, {u'url': u'http://172.18.11.98:8080/job/bbs.youth.cn/129/', u'number': 129}, {u'url': u'http://172.18.11.98:8080/job/bbs.youth.cn/128/', u'number': 128}], u'url': u'http://172.18.11.98:8080/job/bbs.youth.cn/', u'firstBuild': {u'url': u'http://172.18.11.98:8080/job/bbs.youth.cn/128/', u'number': 128}, u'nextBuildNumber': 138, u'property': [{}]}

本次成功构建的版本号lastSuccessfulBuild的number是137,我需要现将本次构建的nextBuildNumber存入数据库的svn_next_no字段里(比如138),下次构就通过while循环获取get_job_info来获得lastSuccessfulBuild的number(最后一次成功构建的版本号),直到项目从137变成138后,在和数据库中的nextBuildNumber(下次构建的版本号)进行对比,如果一样我就认为项目构建成功了。

我的平台代码如下:

# -*- coding: utf-8 -*-
from cmdb.models import *
from cmdb.myredis.redis_conect import *
from cmdb.myapi.jenkins import jenkins_remote

from django.conf import settings

import time


def release_build_f(job):
    J = jenkins_remote.Jenkins(settings.JENKINS['server'],settings.JENKINS['username'],settings.JENKINS['token'])
    """初始化检测构建项目的当前版本号和下一次版本号"""
    if Svn.objects.get(svn_name=job).svn_next_no == "None" or int(Svn.objects.get(svn_name=job).svn_next_no) != int(J.get_job_info(job)['lastSuccessfulBuild']['number']):
        Svn.objects.filter(svn_name=job).update(svn_next_no = J.get_job_info(job)['nextBuildNumber'])
    else:
        pass
    """构建项目"""
    J.build_job("%s"%job)
    """进入监测版本号变更循环"""
    while True:
        try:
            """如当前构建版本号等于下次构建版本号,跳出循环"""
            time.sleep(5)
            if int(J.get_job_info(job)['lastSuccessfulBuild']['number']) == int(Svn.objects.get(svn_name=job).svn_next_no):
                """跳出"""
                break
        except Exception as err:
            break
            return ("构建异常",err)
    """项目发布后同步构建项目的当前版本号和下一次版本号"""
    try:
        Svn.objects.filter(svn_name=job).update(svn_no = J.get_job_info(job)['lastSuccessfulBuild']['number'],
                                                svn_next_no = J.get_job_info(job)['nextBuildNumber'],
                                                svn_time = '%s %s' %( str(J.get_build_info(job,J.get_job_info(job)['lastSuccessfulBuild']['number'])['id']).split('_')[0],
                                                                      str(J.get_build_info(job,J.get_job_info(job)['lastSuccessfulBuild']['number'])['id']).split('_')[1].replace('-',':'))
        )
    except Exception as err:
        print err
    """清空项目对应的发布状态缓存"""
    try:
        r = redis_conect_db6()
        r.delete(*r.keys('%s*' % job))
    except:
        pass
    return ("%s进入构建队列,版本变更为%s,10秒钟后刷新更新页面"%(job, J.get_job_info(job)['lastSuccessfulBuild']['number']))

三、利用Jenkins-python 查看构建项目变更

    def get_build_info(self, name, number):
        try:
            response = self.jenkins_open(urllib2.Request(
                self.server + BUILD_INFO % locals()))
            if response:
                return json.loads(response)
            else:
                raise JenkinsException('job[%s] number[%d] does not exist'
                                       % (name, number))
        except urllib2.HTTPError:
            raise JenkinsException('job[%s] number[%d] does not exist'
                                   % (name, number))
        except ValueError:
            raise JenkinsException(
                'Could not parse JSON info for job[%s] number[%d]'
                % (name, number)
            )

我们需要传入项目名,然后就是需要查看项目变更的构建版本号

返回结果

>>> J.get_build_info('bbs.youth.cn',137)
{u'building': False, u'changeSet': {u'items': [], u'kind': u'svn', u'revisions': [{u'module': u'http://172.18.11.96/svndata/bbs_youth/trunk', u'revision': 209}]}, u'builtOn': u'', u'description': None, u'artifacts': [], u'timestamp': 1497414529627, u'number': 137, u'actions': [{u'causes': [{u'userName': u'\u5f20\u5e06', u'userId': u'zhangfan', u'shortDescription': u'Started by user \u5f20\u5e06'}]}, {}, {}, {}], u'id': u'2017-06-14_12-28-49', u'keepLog': False, u'url': u'http://172.18.11.98:8080/job/bbs.youth.cn/137/', u'culprits': [], u'result': u'SUCCESS', u'executor': None, u'duration': 1535, u'fullDisplayName': u'bbs.youth.cn #137', u'estimatedDuration': 1865}

changeSet里msg就是变更内容啦

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

推荐阅读更多精彩内容