V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
wsgzao
V2EX  ›  程序员

Jenkins export and import jobs 迁移导出导入任务实践小结

  •  
  •   wsgzao ·
    wsgzao · 2020-01-07 15:25:13 +08:00 · 1787 次点击
    这是一个创建于 1563 天前的主题,其中的信息可能已经有所发展或是发生改变。

    前言

    我遇到的 Jenkins 迁移项目并非可以通过简单的物理文件复制就可以轻松解决,需要考虑上千个不同项目的 jobs 分离,Jenkins 1.x 和 2.x 大版本兼容性,Jenkins Plugins 插件,Jenkins Credentials 凭证,Jenkins Restrict 节点约束,按 view 分类不同项目的 jobs 等各种因素。这次对 Jenkins 迁移做了大量的研究和实践,希望总结出来的方法能对各位有帮助。

    Jenkins export and import jobs 迁移导出导入任务实践小结

    更新历史

    2020 年 01 月 06 日 - 初稿

    阅读原文 - https://wsgzao.github.io/post/jenkins-import/

    扩展阅读

    Jenkins Plugins Index


    export and import jobs in Jenkins

    Is it possible to exchange jobs between 2 different Jenkins'? I'm searching for a way to export/import jobs.

    Solutions/Answers:

    Solution 1:

    Jenkins has a rather good wiki, albeit hard to read when you’re new to CI software…

    They offer a simple solution for moving jobs between servers

    The trick probably was the need to reload config from the Jenkins Configuration Page.

    Solution 2:

    Probably use jenkins command line is another option, see https://wiki.jenkins-ci.org/display/JENKINS/Jenkins+CLI

    • create-job: Creates a new job by reading stdin as a configuration XML file.
    • get-job: Dumps the job definition XML to stdout

    So you can do

    java -jar jenkins-cli.jar -s http://server get-job myjob > myjob.xml
    java -jar jenkins-cli.jar -s http://server create-job newmyjob < myjob.xml
    
    

    It works fine for me and I am used to store in inside my version control system

    Solution 3:

    A one-liner:

    $ curl -s http://OLD_JENKINS/job/JOBNAME/config.xml | curl -X POST 'http://NEW_JENKINS/createItem?name=JOBNAME' --header "Content-Type: application/xml" -d @-
    
    

    With authentication:

    $ curl -s http:///<USER>:<API_TOKEN>@OLD_JENKINS/job/JOBNAME/config.xml | curl -X POST 'http:///<USER>:<API_TOKEN>@NEW_JENKINS/createItem?name=JOBNAME' --header "Content-Type: application/xml" -d @-
    
    

    With Crumb, if CSRF is active (see details here):

    Get crumb with:

    $ CRUMB_OLD=$(curl -s 'http://<USER>:<API_TOKEN>@OLD_JENKINS/crumbIssuer/api/xml?xpath=concat(//crumbRequestField,":",//crumb)')
    $ CRUMB_NEW=$(curl -s 'http://<USER>:<API_TOKEN>@NEW_JENKINS/crumbIssuer/api/xml?xpath=concat(//crumbRequestField,":",//crumb)')
    
    

    Apply crumb with -H CRUMB:

    $ curl -s -H $CRUMB_OLD http:///<USER>:<API_TOKEN>@OLD_JENKINS/job/JOBNAME/config.xml | curl -X POST -H $CRUMB_NEW 'http:///<USER>:<API_TOKEN>@NEW_JENKINS/createItem?name=JOBNAME' --header "Content-Type: application/xml" -d @-
    
    

    Solution 4:

    There’s a plugin called Job Import Plugin that may be what you are looking for. I have used it. It does have issues with importing projects from a server that doesn’t allow anonymous access.

    For Completeness: If you have command line access to both, you can do the procedure already mentioned by Khez for Moving, Copying and Renaming Jenkins Jobs.

    Solution 5:

    Go to your Jenkins server’s front page, click on REST API at the bottom of the page:

    Create Job

    To create a new job, post config.xml to this URL with query parameter name=JOBNAME. You need to send a Content-Type: application/xml header. You’ll get 200 status code if the creation is successful, or 4xx/5xx code if it fails. config.xml is the format Jenkins uses to store the project in the file system, so you can see examples of them in the Jenkins home directory, or by retrieving the XML configuration of existing jobs from /job/JOBNAME/config.xml.

    Solution 6:

    In my Jenkins instance (version 1.548) the configuration file is at:

    /var/lib/jenkins/jobs/-the-project-name-/config.xml

    Owned by jenkins user and jenkins group with 644 permissions. Copying the file to and from here should work. I haven’t tried changing it directly but have backed-up the config from this spot in case the project needs to be setup again.

    Solution 7:

    Job Import plugin is the easy way here to import jobs from another Jenkins instance. Just need to provide the URL of the source Jenkins instance. The Remote Jenkins URL can take any of the following types of URLs:

    • http://$JENKINS – get all jobs on remote instance

    • http://$JENKINS/job/$JOBNAME – get a single job

    • http://$JENKINS/view/$VIEWNAME – get all jobs in a particular view

    Solution 8:

    Thanks to Larry Cai’s answer I managed to create a script to backup all my Jenkins jobs. I created a job that runs this every week. In case someone finds it useful, here it is:

    #!/bin/bash
    #IFS for jobs with spaces.
    SAVEIFS=$IFS
    IFS=$(echo -en "\n\b")
    for i in $(java -jar /run/jenkins/war/WEB-INF/jenkins-cli.jar -s http://server:8080/ list-jobs);
    do
      java -jar /run/jenkins/war/WEB-INF/jenkins-cli.jar -s http://server:8080/ get-job ${i} > ${i}.xml;
    done
    IFS=$SAVEIFS
    mkdir deploy
    tar cvfj "jenkins-jobs.tar.bz2" ./*.xml
    
    

    Solution 9:

    Jenkins export jobs to a directory

     #! /bin/bash
        SAVEIFS=$IFS
        IFS=$(echo -en "\n\b")
        declare -i j=0
        for i in $(java -jar jenkins-cli.jar -s http://server:8080/jenkins list-jobs  --username **** --password ***);
        do
        let "j++";
        echo $j;
        if [ $j -gt 283 ] // If you have more jobs do it in chunks as it will terminate in the middle of the process. So Resume your job from where it ends.
         then
        java -jar jenkins-cli.jar -s http://lxvbmcbma:8080/jenkins get-job --username **** --password **** ${i} > ${i}.xml;
        echo "done";
        fi
        done
    
    

    Import jobs

    for f in *.xml;
    do
    echo "Processing ${f%.*} file.."; //truncate the .xml extention and load the xml file for job creation
    java -jar jenkins-cli.jar -s http://server:8080/jenkins create-job ${f%.*}  < $f
    done
    
    

    Solution 10:

    Simple php script worked for me.

    Export:

    // add all job codes in the array
    $jobs = array("job1", "job2", "job3");
    
    foreach ($jobs as $value)
    {
        fwrite(STDOUT, $value. " \n") or die("Unable to open file!");
        $path = "http://server1:8080/jenkins/job/".$value."/config.xml";
        $myfile = fopen($value.".xml", "w");
        fwrite($myfile, file_get_contents($path));
        fclose($myfile);
    }
    
    

    Import:

    <?php
    
    // add all job codes in the array
    $jobs = array("job1", "job2", "job3");
    
    foreach ($arr as $value)
    {
        fwrite(STDOUT, $value. " \n") or die("Unable to open file!");
        $cmd = "java -jar jenkins-cli.jar -s http://server2:8080/jenkins/ create-job ".$value." < ".$value.".xml";
        echo exec($cmd);
    }
    
    

    Solution 11:

    This does not work for existing jobs, however there is Jenkins job builder.

    This allows one to keep job definitions in yaml files and in a git repo which is very portable.

    Solution 12:

    For those of us in the Windows world who may or may not have Bash available, here’s my PowerShell port of Katu and Larry Cai‘s approach. Hope it helps someone.

    ##### Config vars #####
    $serverUri = 'http://localhost:8080/' # URI of your Jenkins server
    $jenkinsCli = 'C:\Program Files (x86)\Jenkins\war\WEB-INF\jenkins-cli.jar' # Path to jenkins-cli.jar on your machine
    $destFolder = 'C:\Jenkins Backup\' # Output folder (will be created if it doesn't exist)
    $destFile = 'jenkins-jobs.zip' # Output filename (will be overwritten if it exists)
    ########################
    
    $work = Join-Path ([System.IO.Path]::GetTempPath()) ([System.IO.Path]::GetRandomFileName())
    New-Item -ItemType Directory -Force -Path $work | Out-Null # Suppress output noise
    echo "Created a temp working folder: $work"
    
    $jobs = (java -jar $jenkinsCli -s $serverUri list-jobs)
    echo "Found $($jobs.Length) existing jobs: [$jobs]"
    
    foreach ($j in $jobs)
    {
        $outfile = Join-Path $work "$j.xml"
        java -jar $jenkinsCli -s $serverUri get-job $j | Out-File $outfile
    }
    echo "Saved $($jobs.Length) jobs to temp XML files"
    
    New-Item -ItemType Directory -Force -Path $destFolder | Out-Null # Suppress output noise
    echo "Found (or created) $destFolder folder"
    
    $destPath = Join-Path $destFolder $destFile
    Get-ChildItem $work -Filter *.xml |
        Write-Zip -Level 9 -OutputPath $destPath -FlattenPaths |
        Out-Null # Suppress output noise
    echo "Copied $($jobs.Length) jobs to $destPath"
    
    Remove-Item $work -Recurse -Force
    echo "Removed temp working folder"
    
    

    Solution 13:

    It is very easy just download plugin name

    Job Import Plugin

    Enter the URL of your Remote Jenkins server and it will import the jobs automatically

    Solution 14:

    The most easy way, with direct access to the machine is to copy the job folder from first jenkins to another one (you can exclude workspaces – workspace folder), because the whole job configuration is stored in the xml file on the disk.

    Then in the new jenkins just reload configuration in the global settings (admin access is required) should be enough, if not, then you will need to restart Jenkins tool.

    Another way can be to use plugins mentioned above this post.

    edit: – in case you can probably also exclude modules folders

    Jenkins 迁移方案小结

    上面列举有 14 种方法居多,但大多数是基于方案 4 进行扩展

    上面列举的方案基本已经非常全了,感觉是不是有点眼花?其实归纳总结主要有以下 4 种

    1. 官方的 Moving/copying/renaming jobs,即所谓的物理文件迁移,如果情况复杂此方案不推荐
    2. 基于 Jenkins CLI,该方案需要依赖 jenkins-cli.jar 包括 java 使用范围具有一定局限性,不推荐
    3. 基于类似 Job Import Plugin 插件形式,该类方案普适性较差,不推荐
    4. 基于 Jenkins REST API,核心是获取<jenkinshost>/job/<jobname>/config.xml,效果最佳

    REST API

    Many objects of Jenkins provide the remote access API. They are available at /.../api/ where "..." portion is the object for which you'd like to access.

    XML API

    Access data exposed in HTML as XML for machine consumption. Schema is also available. You can also specify optional XPath to control the fragment you'd like to obtain (but see below). For example, ../api/xml?xpath=//[0].

    For XPath that matches multiple nodes, you need to also specify the "wrapper" query parameter to specify the name of the root XML element to be create so that the resulting XML becomes well-formed.

    Similarly exclude query parameter can be used to exclude nodes that match the given XPath from the result. This is useful for trimming down the amount of data you fetch (but again see below). This query parameter can be specified multiple times.

    XPath filtering is powerful, and you can have it only return a very small data, but note that the server still has to build a full DOM of the raw data, which could cause a large memory spike. To avoid overloading the server, consider using the tree parameter, or use the xpath parameter in conjunction with the tree parameter. When used together, the result of the tree parameter filtering is built into DOM, then the XPath is applied to compute the final return value. In this way, you can often substantially reduce the size of DOM built in memory.

    JSON API

    Access the same data as JSON for JavaScript-based access. tree may be used.

    Python API

    Access the same data as Python for Python clients. This can be parsed into Python object as eval(urllib.urlopen("...").read()) and the resulting object tree is identical to that of JSON. However, when you do this, beware of the security implication. If you are connecting to a non-trusted Jenkins, the server can send you malicious Python programs.

    In Python 2.6 or later you can safely parse this output using ast.literal_eval(urllib.urlopen("...").read())

    For more information about remote API in Jenkins, see the documentation.

    https://jenkins.io/redirect/remote-api

    使用 cURL 和 Jenkins REST API

    使用 Jenkins REST API 建议关闭 CSRF 防护

    # To retrieve the job config.xml
    curl -X GET '<jenkinshost>/job/<jobname>/config.xml' -u username:API_TOKEN -o <jobname>.xml
    
    # to use this config to create a new job
    curl -s -XPOST '<jenkinshost>/createItem?name=<jobname>' -u username:API_TOKEN --data-binary @<jobname>.xml -H "Content-Type:text/xml"
    
    # get all jenkins jobs
    curl -X GET '<jenkinshost>/api/json?pretty=true' -u username:API_TOKEN -o jobs.json
    
    # get jenkins view
    curl -X GET '<jenkinshost>/view/<viewname>/api/json' -u username:API_TOKEN -o view.json
    
    

    Obviously, replace:

    • username API_TOKEN with your username and password/API_Token
    • jenkinshost with your Jenkins URL
    • jobname with the name of the job that you created via the UI

    JSON to CSV Converter

    mkdir config_xml
    vim jobs.txt
    vim jenkins_jobs_migration.sh
    
    #/bin/bash
    source_jenkins_host="xxx"
    source_jenkins_username="xxx"
    source_jenkins_password="xxx"
    
    target_jenkins_host="xxx"
    target_jenkins_username="xxx"
    target_jenkins_password="xxx"
    
    pull() {
        for line in `cat jobs.txt`
        do
            echo ${line}
            curl -X GET ${source_jenkins_host}job/${line}/config.xml -u ${source_jenkins_username}:${source_jenkins_password} -o config_xml/${line}.xml
        done
    }
    
    push() {
        for line in `cat jobs.txt`
        do
            echo $line
            curl -s -XPOST ${target_jenkins_host}createItem?name=${line} -u ${target_jenkins_username}:${target_jenkins_password} --data-binary @config_xml/${line}.xml -H "Content-Type:text/xml"
        done
    
    }
    
    case "$1" in
        push)
            push
            ;;
        pull)
            pull
            ;;
        *)
            echo "Usage: $NAME {pull|push}"
            exit 1
            ;;
    esac
    
    

    使用 python 编写 api_jenkins.py 核心逻辑

    暂不方便公开

    1. 支持读取 context.json 配置文件使用 pipeline.j2 模板自动生成不同类型的 pipeline.xml 导入文件
    2. 支持按 view 或者 job export 导出 job config.xml 配置信息
    3. 支持按 view 或者 job import 导入 job config.xml 配置信息

    Jenkins Backup

    archive jenkins setting and plugins

    大家应该都知道 Jenkins 备份插件目前主要就 2 种选择:

    严格意义上来说应该只能选择 Periodic Backup,但是如果是需要定期备份自然离不开编写 Bash 脚本

    jenkins-backup-script

    参考文章

    Export/import jobs in Jenkins

    Moving/copying/renaming jobs

    Jenkins CLI

    How to create a job using the REST API and cURL?

    Jenkins Remote access API

    目前尚无回复
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   4676 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 42ms · UTC 01:09 · PVG 09:09 · LAX 18:09 · JFK 21:09
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.