Jenkins API+Pipeline深度實踐之input的自動化


本文分享的小Tips是在我前面的文章DevOps建設之基於釘釘OA審批流的自動化上線中提到的,當通過API自動觸發Jenkins Pipeline流水線執行時,如果原來的流水線中定義了在構建正式開始后還需要接收用戶input的步驟,想要自動繞過或自動執行input的方法

1、pipeline input概述

首先回過頭再來看看pipeline input的語法及功能,參考我之前總結的pipeline input語法

input指令stage允許使用input step提示輸入。在stage將暫停任何后options已被應用,並在進入前agent塊為stage或評估when的條件stage。如果input批准,stage則將繼續。作為input提交的一部分提供的任何參數將在其余的環境中可用stage

可選項

  • message
    必需的,這將在用戶提交時顯示給用戶input
  • id
    可選標識符input,默認為stage名稱
  • ok
    input表單上“確定”按鈕的可選文本
  • submitter
    可選的逗號分隔列表,這些列表允許用戶提交此用戶或外部組名input。默認為允許任何用戶。
  • submitterParameter
    環境變量的可選名稱,用該submitter名稱設置(如果存在)
  • parameters
    提示提交者提供的可選參數列表。請參閱Pipeline parameters以獲取更多信息

2、背景概述

基於上面的語法描述,我這里線上發布流水線中input的功能僅僅是需要用戶進行確認,所以沒有傳遞任何參數,通過這種簡單的input控制及timeout超時機制,實現了用戶選擇參數並點擊開始構建后需要在60秒內二次確認的功能,流水線的部分內容如下

stage('Deploy to prod'){
    when {
        environment name: 'PerformType', value: 'Deploy'
    }
    steps{
        timeout(time:60, unit:'SECONDS') {
        input "確認要部署到線上環境嗎?"              
            script{
                try {
                    ...
                }
                catch (exc) {
                    ...
                    throw(exc)
                }
            }
        }
    }
}

到這里問題就產生了,input的過程是在流水線運行過程中動態出現的,如果是想要在釘釘OA審批通過后自動通過調用jenkins api並傳入參數讓整個流水線自動執行,並且自動進行input的確認操作或者繞過input,應該怎么做呢?

3、推理及測試

剛開始沒有任何思路,唯一想到的辦法就是把input的過程從pipeline中去除掉,這樣就沒有任何煩惱了

但是為了保留原有pipeline設計的完整性,顯然這種做法不夠友好,只是避開了這個難點,是不可取的

通過查找發現這方面的資料很少,最終有用的資料如下

input語法中可選字段包含id,每個input步驟都有一個唯一的ID。在生成的URL中可以使用它來繼續或中止

例如,可以使用特定的ID來機械地響應來自某些外部過程/工具的輸入

這篇文章中講到了如何通過Jenkins REST API恢復暫停的管道?作為參考起到了一定幫助

為了完成整個自動化input的過程,具體的演進流程如下

3.1 通過Crumb安全操作Jenkins

Crumb指的是JenkinsCSRF tokenJenkins服務器為了阻止不安全的跨域請求,默認開啟了CSRF保護,參考Jenkins遠程API訪問

Jenkins的CSRF配置可以在「系統管理」——> 「全局安全配置」——> 「CSRF Protection」相關配置中關閉此保護,跨站請求偽造這是一個很常見的安全問題,為了安全起見建議不關閉。如果關閉,這里的內容可以略過。

Jenkins開啟CSRF保護后,可以通過固定的接口獲得一個安全的Crumb以便於通過API操作Jenkins,以curl請求為例,請求的可選方式一般是兩種,如下

方法一:
curl -u <username>:<password> 'https://jenkins.ssgeek.com/crumbIssuer/api/xml?xpath=concat(//crumbRequestField,":",//crumb)'
Jenkins-Crumb:dc78dfb9615fb56bbf2001fb99c64dbd3331c5e14c8d4edd54722e7ca790529e%

方法二:
curl -u <username>:<password> 'https://jenkins.ssgeek.com/crumbIssuer/api/json'
{"_class":"hudson.security.csrf.DefaultCrumbIssuer","crumb":"52d605f43328f15303c2e68eb492b9656e229ce124c2f5f2e39b6f552f54e4ac","crumbRequestField":"Jenkins-Crumb"}%

以上兩種方式都可以獲取一個Crumb,然后就能帶着它去請求JenkinsAPI

curl -u <username>:<password> -X POST -H "Jenkins-Crumb:b220147dbdf3cfebbeba4c29048c2e33" -d <data> 'https://jenkins.ssgeek.com/<jenkins api url>'

3.2 通過Token安全操作Jenkins

在官方文檔的描述中有這樣一句話:API tokens are preferred instead of crumbs for CSRF protection.

意為在開啟了CSRF的情況下,首選的是通過API token操作而不是crumb,這里的API token指的就是Jenkins中用戶的API token

可以通過「用戶」——> 「設置」——> 「API Token」——> 「添加新Token」來獲得一個api token,有了這個Token之后,以curl請求為例操作JenkinsAPI方式如下

curl -u user_id:user_api_token -X POST -d <data> 'https://jenkins.ssgeek.com/<jenkins api url>'

3.3 API操作

參考上面的文檔資料使用Jenkins REST API恢復暫停的管道

對於input有這樣的api接口地址可以使用,用於將輸入發送到等待的輸入步驟。url格式如下

http://<JenkinsURL>/<JobURL>/<Build#>/input/<InputID>/submit

需要滿足的條件

  • 如果Jenkins啟用了CSRF保護,則您需要使用CrumbAPI Token

  • 請求通過POST方式發送

  • 需要提供參數名為proceed的值,並且以OK作為參數值

  • 為了提供數據,需要帶有json格式的參數,這些參數就是在input階段需要接收的參數,格式為

    {
        "parameter":[
            {
                "name":"param1",
                "value":"valueOfParam1"
            },
            {
                "name":"param2",
                "value":"valueOfParam2"
            }
        ]
    }
    

    如果沒有發送有效的json參數,則流水線也將繼續進行,只是不會獲得任何參數(這也可能導致流水線最終執行失敗),如果成功則返回302狀態碼並重定向到用戶界面

  • 必須填寫input id,因此要從外部連接到的input步驟配置唯一的id

  • 也可以使用下面的url,如果流水線成功,則返回狀態碼為200且響應為空

    http://<Jenkins URL>/job/<YOUR_PROJECT>/<BUILD_NUMBER>/wfapi/inputSubmit
    

其他可用的api接口地址以及作用

  • 用於中止流水線
http://<Jenkins URL>/job/<YOUR_PROJECT>/<BUILD_NUMBER>/input/<INPUT_ID>/abort
  • 不傳入任何參數並繼續進行流水線
http://<Jenkins URL>/job/<YOUR_PROJECT>/<BUILD_NUMBER>/input/<INPUT_ID>/proceedEmpty

對於本文中我的需求,只需要在input執行時自動確認且無需傳入任何參數即可,因此使用的接口地址為上面的最后一種(其余接口地址未測試)

3.4 input的改造

為了實現在input執行時自動確認,需要對流水線的input部分進行改造,加入一個固定的id即可

由於定義的id都是固定的,因此可以利用腳本對所有的流水線涉及到這種input的部分批量更新,這里就不列出具體方法了

最終我的流水線調整如下

stage('Deploy to prod'){
    when {
        beforeInput true
        environment name: 'PerformType', value: 'Deploy'
    }
    options {
        timeout(time:60, unit:'SECONDS')
    }
    input {
        message "確認要部署到線上環境嗎?"
        id "CustomId"
    }
    steps{
        script{
            try {
                ...
            }
            catch (exc) {
                ...
                throw(exc)
            }
        }
    }
}

4、自動化input的最終實現

經過上面的推理和測試,解決了通過API自動執行input進行流水線確認的問題

這里還剩下最后一個問題,通過測試發現,想要自動執行input過程,其接口對應的url地址並不是一直存在的,而是在流水線執行開始后到達input的時候才會出現,出現時通過瀏覽器訪問查看如下

而其余時間發送請求都會返回404狀態碼,此時是無法接收post請求的,因此想要自動化執行input並不只是簡單的向接口發送POST請求了

我這里的解決思路

在發送流水線開始執行的請求后,立即通過代碼循環請求並判斷接口地址返回的狀態碼是否是200

如果不是,那么表示流水線還沒執行到這里;如果是,就可以完美的向這個地址發送自動執行的請求了

python語言調用Jenkins api為例,用到了python-jenkins這個包,在觸發構建時使用build_job這個方法,這個方法返回值剛好是job任務的build number,這恰好是接口地址組成中需要的一部分

好了,上最終的部分代碼

def auto_job_input(self, server_url, job_name, build_number):
    """
    根據input階段生成的url http狀態碼,判斷當前job流水線運行的stage否進行到了input步驟
    自動執行input or 繼續判斷
    :param job_name:
    :param build_number:
    :return:
    """
    # https://jenkins.ssgeek.com/job/input-demo/64/input
    get_url = server_url + "/job/" + job_name + "/" + str(build_number) + "/input"
    # https://jenkins.ssgeek.com/job/input-demo/64/input/CustomId/proceedEmpty
    post_url = get_url + "/CustomId/proceedEmpty"
    s = requests.Session()
    res_code_get = s.get(url=get_url, auth=('user_id', 'user_token')).status_code
    while res_code_get != 200:
        res_code_get = s.get(url=get_url, auth=('user_id', 'user_token')).status_code
    res_code_post = s.post(url=post_url, auth=('user_id', 'user_token'), data=None).status_code
    return res_code_post

關鍵部分代碼量很少,利用request並且攜帶認證參數進行請求,如果有大佬有更好的方案歡迎與我交流

5、小結

到這里,通過一步步推理演進,在流水線中input的自動化執行就完美實現了,最終既實現了調用api觸發自動構建並執行input進行自動確認,同時也保留了原流水線的input設計,對原有流水線只需要做很小的調整。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM