美文网首页运维驿站python自动化运维DevOPS
授之以渔-运维平台发布模块三(Jenkins篇)

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

作者: 大Q的梦想 | 来源:发表于2017-06-16 14:34 被阅读648次

    接上篇《授之以渔-运维平台发布模块二(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就是变更内容啦

    相关文章

      网友评论

      • 6ccd0e3a3588:您好,远程操作jenkins的话,是不是要在安全设置里面把 ‘’ 防止跨站点请求伪造‘’勾选去掉,这样还安全吗?
      • bd5ebd3aa5e4:帆总,写的够详细

      本文标题:授之以渔-运维平台发布模块三(Jenkins篇)

      本文链接:https://www.haomeiwen.com/subject/epopqxtx.html