2014-12-08:已不再擔任SCM和CI的職位,Jenkins系列的文章如無必要不會再維護。
2014-07-25:更新shell腳本
2014-06-05:更新shell腳本
2014-01-09:更新shell腳本,修改Jenkins文件刪除后不能自動從版本控制刪除的bug
是不是有過這種經歷:某天手賤,把某一個配置更改了。然后只能在那兒苦逼的看着,然后的然后把以前的配置重新配一次。坑爹的是以前配置的什么都忘記了。。。尼瑪,坑啊( ⊙ o ⊙ )!
某天在群里和一群人吹牛逼,突然冒出一個人說手賤把某個job刪除了,有沒有辦法恢復。然后我們果斷的告訴了ta實情。然后這聊天的主題就跑到把jenkins加入到版本控制中。我也曾經手賤過。運氣好,前幾天要測試一些東西,在另一台機器上面還有備份。所以折騰折騰,就寫了這篇文章。
系統:CentOS 5.8、6.4
版本控制軟件:Subversion 1.7+
思路:寫一個腳本(shell)定時去跑一次add、delete和commit。
- 建立普通用戶
用一個用戶會出問題,jenkins構建的時候會直接報錯。
這個問題的解決方法:將用戶目錄下.subversion的auth目錄刪除就可以了
useradd froad #建立普通用戶跑Jenkins,root用戶用了跑shell腳本
#啟動Jenkins略過
#因為我是用root用戶登錄,然后 su froad切換的,所以就沒有設置密碼。 - 安裝Subversion1.7以上版本(當做客戶端給root用戶使用)
。其實有用的就是bin/svn這個程序而已。如果你安裝了Subversion edge 直接把bin和lib目錄拷貝過來就行了。為什么要用1.7以上的?因為1.7后.svn目錄只有一個了。我嫌以前的版本.svn目錄太多了,煩!提供個解壓即可用的svn(從subversion edge中拷貝出來的) 點我去下載 - 遠程Subversion的一些准備工作
如果你喜歡可以創建一個新的庫和用戶,如果你不like,隨便你!
- 檢出svn目錄
[root@localhost ~]# /home/froad/svn/bin/svn co https://192.168.xxx.xxx/svn/Jenkins/trunk /home/froad/.jenkins/ --username jenkins #說明:/home/froad/.jenkins這個參數可以直接把檢出的.svn目錄放到.jenkins目錄,我是懶人不想在mv一次。--username是svn的用戶 #svn語法:svn co url path --username xxx Error validating server certificate for 'https://192.168.xxx.xxx:443': - The certificate is not issued by a trusted authority. Use the fingerprint to validate the certificate manually! - The certificate hostname does not match. Certificate information: - Hostname: froad-jskfb - Valid: from Apr 16 03:04:08 2013 GMT until Apr 14 03:04:08 2023 GMT - Issuer: (null), (null), (null), (null), (null) ((null)) - Fingerprint: D6:EB:58:xxxxxxxxxxxxxxxFC:7D:04:64 (R)eject, accept (t)emporarily or accept (p)ermanently? p #說明:R 拒絕 t 暫時接受 p 永久接受 Authentication realm: <https://192.168.xxx.xxx:443> VisualSVN Server Password for 'jenkins': ************* #說明:輸入你的用戶密碼 ----------------------------------------------------------------------- ATTENTION! Your password for authentication realm: <https://192.168.xxx.xxx:443> VisualSVN Server can only be stored to disk unencrypted! You are advised to configure your system so that Subversion can store passwords encrypted, if possible. See the documentation for details. You can avoid future appearances of this warning by setting the value of the 'store-plaintext-passwords' option to either 'yes' or 'no' in '/root/.subversion/servers'. ----------------------------------------------------------------------- Store password unencrypted (yes/no)? yes #說明:存儲未加密的密碼 Checked out revision 1. #現在版本庫都檢出了,下面的就簡單了。add一下,然后commit一下。打完收工。 #如果你是這么想的,那么結果會郁悶死你。接着往下看吧。
- 更改Jenkins的workspace目錄
為什么要更改workspace目錄呢?因為里面有個搗蛋的目錄.svn。這個目錄是個深坑,開始我花了大力氣去忽略這個目錄。坑爹的是,如果我把工作目錄清空了,然后在構建就會一直報錯。因為SVNkit跑去找JENKINS_HOME下的.svn目錄(這個目錄就是我們上面檢出的)。
測試的時候是直接把.svn目錄檢出到test_007ka目錄。大家將就看。除了目錄不一樣,其他沒有區別。
SVNkit會先去找.svn目錄,如果到頂層目錄還是沒有找到.svn目錄,就會在workspace目錄檢出。這是svn和git的一個特性。哪兒看到的?那個《git權威指南》。
系統管理→系統設置→主目錄(的右邊問號下面)→高級(是不是忽略了啊\(^o^)/~)→工作空間根目錄- ${JENKINS_HOME} — Jenkins home directory.#JENKINS_HOME這個參數不用說了
- ${ITEM_ROOTDIR} — Root directory of a job for which the default workspace is allocated.#ITEM_ROOTDIR:默認的工作空間目錄。完整的路徑就是JENKINS_HOME/jobs/xxxx/workspace
- ${ITEM_FULL_NAME} — '/'-separated job name, like "foo/bar".#ITEM_FULL_NAME:job的名稱,這個就是我們需要的。
-
點開后面的問號可以看見3個參數(配置路徑需要的):
我們只需要把workspace目錄趕出JENKINS_HOME目錄就行了。上配置:
workspace:/home/froad/workspace/${ITEM_FULL_NAME} #前面的目錄隨便你改,只需要在最后帶上${ITEM_FULL_NAME} JENKINS_HOME:/home/froad/.jenkins #給你們對比着看 #好了,這下.svn目錄不打架了。我也不用頭疼了。
- 刪除已經存在的workspace目錄
find . -type d -name "workspace"|xargs rm -rf #看見find后面的那個點了么,改成你的路徑就行了
- 配置Subversion忽略目錄
貌似將JENKINS_HOME目錄直接提交到Subversion,數據量不是一般的高啊!我這個Jenkins才跑3個月都10Gb了。
如果要提交上去,花費的時間,不是一般的長啊。
注意:你用的什么用戶,就在用戶目錄下面改。我用的root用戶。
進入用戶目錄的.subversion打開config文件,找到global-ignores。大概在105行。
把global-ignores前的#去掉,注意#后面的空格要刪掉。然后在=后面添加 modules
modules目錄是maven項目產生的,我的Jenkins就是這個目錄大。把這個目錄刪除了也就幾百Mb。如果你有其他目錄想忽略,請自行添加,記得用空格分隔就行了。
-
寫個shell腳本svn_commit.sh
這個腳本隨便你放在哪兒,我想偷懶。直接放在Jenkins的主目錄,順便也版本控制下。。O(∩_∩)O~
聲明:腳本寫的很丑,勿噴!#!/bin/bash # ------------------------------------------------------ # Jenkins的Subversion備份腳本 # 請將本腳本放到JENKINS_HOME目錄 # 作者:zjl # version:4.1 # time:2014-07-25 17:36 # # 更新日志 # version:4.1 # 修護刪除文件導致版本過時提交失敗的bug # version:4.0 # 修護從${TMP_STATUS_LOG}文本讀取一行,變量前空格丟失的bug # 修護從${TMP_STATUS_LOG}文本截取文件名某些情況錯誤的bug # 優化腳本對特殊路徑的處理 # 添加svn commit失敗郵件告警功能 # 刪除add 、commit時強制指定的用戶 # version:2.0 # 修改Jenkins文件刪除后不能自動從版本控制刪除的bug # 檢出命令:svn co https://192.168.xxx.xxx/svn/Jenkins/trunk /home/froad/.jenkins/ --username jenkins # # ------------------------------------------------------ # 獲取當前系統時間分割日志文件(如果錯誤時郵件內容過大,可以將時間寫的更精確) # 精確到分鍾 # DATE=`date "+%Y%m%d%H%M"` # 精確到小時 DATE=`date "+%Y%m%d%H"` # SVN_HOME的路徑 SVN_HOME="/home/froad/svn" # SVN程序的路徑 SVN="${SVN_HOME}/bin/svn" # JENKINS_HOME的路徑 JENKINS_HOME="/home/froad/jenkins" # 郵件告警設置 # 收件人(多個收件人用空格或逗號分隔) MAIL_TO="xxx@qq.com" # 偽造發件人(不能和收件人的郵件后綴相同,否則發送不了郵件) MAIL_FROM="jenkins_svn@163.com" # 主題/標題 MAIL_SUBJECT="[ERROR]Jenkins SVN commit fail !" # 郵件發送類型 # 0:通用普通,163、QQ等郵箱會識別成垃圾郵件 # 1:Centos 6.x Mail version 12.4 7/29/08. # 2:Centos 5.x Mail version 8.1 6/6/93. # 請根據自己的Mail版本選擇使用 MAIL_TYPE="1" # 日志文件 LOG_HOME="/root/.subversion/logs" LOG_FILE="${LOG_HOME}/svn_commit_${DATE}.log" # svn_status日志文件 TMP_STATUS_LOG="${LOG_HOME}/status.log" # svn_add 方法已停止使用,由svn_status代替。 #function svn_add() #{ #使用svn add命令將文件添加到版本控制 # "${SVN}" add "${JENKINS_HOME}/*" --force &>>"${LOG_FILE}" #退出碼 # EXIT_NUM=$? # echo "svn add退出碼:${EXIT_NUM} !" >>"${LOG_FILE}" #} function send_mail(){ # 檢查郵件參數 # 收件人為空 if [ -z "${MAIL_TO}" ];then echo "[error]MAIL_TO 參數為空!">>"${LOG_FILE}" return fi # 偽造發件人發送時,發件人為空 if [ "${MAIL_TYPE}"=="1" -o "${MAIL_TYPE}"=="2" ];then if [ -z "${MAIL_FROM}" ];then echo "[error]MAIL_FROM 參數為空!">>"${LOG_FILE}" return fi fi # LC_ALL=zh_CN.UTF-8 保證發送郵件時中文不會亂碼 # mail相關請查看 http://ju.outofmemory.cn/entry/24406 if [ "${MAIL_TYPE}"=="1" ] ;then # 1:Centos 6.x Mail version 12.4 7/29/08. LC_ALL=zh_CN.UTF-8 mail -s "${MAIL_SUBJECT}" -r "${MAIL_FROM}" "${MAIL_TO}" < "${LOG_FILE}" elif [ "${MAIL_TYPE}"=="2" ] ;then # 2:Centos 5.x Mail version 8.1 6/6/93. LC_ALL=zh_CN.UTF-8 mail -s "${MAIL_SUBJECT}" "${MAIL_TO}" -- -f "${MAIL_FROM}" < "${LOG_FILE}" else # 0:通用普通,163、QQ等郵箱會識別成垃圾郵件 # 注意:此方法可能會被163等郵箱識別為垃圾郵件 LC_ALL=zh_CN.UTF-8 mail -s "${MAIL_SUBJECT}" "${MAIL_TO}" < "${LOG_FILE}" fi } function svn_status()\ { # 使用svn status命令判斷文件是否刪除、修改或者其他操作 "${SVN}" status "${JENKINS_HOME}" > "${TMP_STATUS_LOG}" # 從文件中讀取一行 cat "${TMP_STATUS_LOG}" | while read line;do # 從文本中讀取回來的內容必須用引號,不然前面的空格會丟失 # 獲取第一個字符,根據第一個字符判斷情況 l=`echo "${line}"|cut -c1` # 獲取文件的相對路徑(獲取第8個字符后的所有內容,前6個字符是svn的狀態,2個字符間隔) # 詳細狀態請查詢:http://www.subversion.org.cn/svnbook/nightly/svn.ref.svn.c.status.html f=`echo "${line}" | cut -c9-` # 狀態為A(增加)時,不需要任何操作,直接返回。 if [ "${l}" == "A" ];then continue fi # 狀態為D(刪除)時,不需要任何操作,直接返回。 if [ "${l}" == "D" ];then continue fi # 狀態為M(修改)時,不需要任何操作,直接返回。 if [ "${l}" == "M" ];then continue fi # 狀態為I(忽略)時,不需要任何操作,直接返回。 if [ "${l}" == "I" ];then continue fi # 狀態為?(未受控制)時,調用add命令然后返回。ps:不知道怎么的有時候從文件中讀取回來的?變成了0 if [ "${l}" == "0" ] || [ "${l}" == "?" ];then "${SVN}" add "${JENKINS_HOME}/${f}" >>"${LOG_FILE}" continue fi # 狀態為!(丟失或者不完整)時,調用delete命令然后返回。 if [ "${l}" == "!" ];then "${SVN}" delete "${JENKINS_HOME}/${f}" >>"${LOG_FILE}" continue fi echo "[info]其他情況:${line}" >>"${LOG_FILE}" done # 刪除臨時文件 # rm -rf ${TMP_STATUS_LOG} } function svn_update() { echo "svn update ...">>"${LOG_FILE}" "${SVN}" update &>>"${LOG_FILE}" svn_commit } function svn_commit() { # 使用svn commit命令提交到服務器 "${SVN}" commit --message="crontab commit" &>>"${LOG_FILE}" EXIT_NUM=$? if [ ! ${EXIT_NUM} == "0" ];then if [ -z ${ISOUTOFDATE} ] ;then # 確保這個if只執行一次 ISOUTOFDATE="1" # 判斷是否需要更新后在嘗試提交(默認查找最后10行,-n xx指定行數) isUpdate=`tail "${LOG_FILE}" | grep "is out of date"` echo "[debug]+:${isUpdate}" if [ ! -z "${isUpdate}" ];then svn_update return fi fi echo "[error]退出碼:${EXIT_NUM} svn commit失敗,請查看日志!">>"${LOG_FILE}" # 調用發送mail方法 send_mail return fi echo "svn commit退出碼:${EXIT_NUM} !">>"${LOG_FILE}" } echo "[begin] 當前時間:`date "+%Y%m%d_%H%M%S"`" >>"${LOG_FILE}" if [ ! -d "${LOG_HOME}" ];then mkdir -p "${LOG_HOME}" fi # 進入到svn工作目錄,防止出現稀奇古怪的錯誤 cd "${JENKINS_HOME}" # 調用方法 svn_status svn_commit echo "[end] 當前時間:`date "+%Y%m%d_%H%M%S"`" >>"${LOG_FILE}" # 輸出空行隔離 echo >>"${LOG_FILE}"
腳本寫好了,建議先運行一次。測試下有沒有錯誤。
- 添加定時提交
crontab -u root -e
*/30 * * * * sh /home/froad/.jenkins/svn_commit.sh #每30分鍾提交一次 - 一個備份插件
Jenkins Job Configuration History Plugin,可以記錄配置的更改。可以記錄誰,什么時間,修改了什么。
- 結尾
普通用戶開機自動啟動Jenkins:
su 用戶名 -c "sh path" #例如:su froad -c "sh /usr/local/jenkins/bin/startup.sh" 將上面的命令加入到/etc/rc.d/rc.local文件中
非root用戶不能使用1024以下的端口,比較麻煩。有不懂的,下面留言。有好的建議,下面留言。歡迎交流!