首先看頁面
在按下提交按鈕后后端開始執行發布程序(jenkins),執行完成之后(成功/失敗)返回如下結果
在Console Output 頁面可以詳細看到Jenkins執行過程(Python-Jenkins的功能)
每次操作記錄都會寫入到MySQL
應用和IP對應關系
引子
Jenkins雖然很方便很自動化了,但是總會有定制化的場景和需求,本例在Jenkins自動構建的基礎之上再進一步的減少操作流程,讓日常測試人員的升級、版本管理更加高效,將項目迭代的流程打包成“一鍵發布”。
本例的前提是Jenkins自動化構建已經存在,CMDB已建立完善
研發流程簡介
略...
軟件版本簡介
- OS RHEL6.5
- Python 2.6.6
- Django 1.6.8
- Jenkins 2.131
- Gitlab gitlab-ce-7.14.0-ce.0.el6.x86_64.rpm
- JAVA 1.8.0_91
公司網絡環境復雜,對穩定性和安全性較高,所以軟件版本比較老舊
Django目錄結構簡介
[root@BETA-CMDB-24 opt]# tree /opt/yjbops/ /opt/yjbops/ ├── amail ├── cmdb ├── django_wsgi.py ├── log │ ├── amail_uwsgi.log │ ├── yjbops_access_log │ ├── yjbops_error_log │ ├── yjbops__uwsgi.log │ └── yjbops_uwsgi.log ├── manage.py ├── minionconf ├── motjob ├── mtrade ├── ops -------本例主目錄 │ ├── admin.py │ ├── __init__.py │ ├── models.py ------- 模型(mysql) │ ├── models.pyc │ ├── urls.py ------- 路由(url) │ ├── views.pyc ------- 視圖 │ └── views.pyc ├── pubs │ ├── admin.py │ ├── commonlist.py │ ├── common.py │ ├── common.pyc │ ├── html_helper_alist.py │ ├── html_helper_list.py │ ├── html_helper.py │ ├── __init__.py │ ├── models.py │ ├── tests.py │ ├── urls.py │ ├── views.py ├── stop.sh ├── templates │ ├── amail │ ├── cmdb │ ├── master │ ├── minionconf │ ├── motjob │ ├── mtrade │ ├── ops ------- 本例頁面主目錄 │ │ ├── app_list.html │ │ ├── from.html │ │ ├── index.html │ │ ├── ips_list.html │ │ ├── release.html -------- 發布頁面 │ │ └── release_record.html -------- 歷史記錄展示頁面 │ ├── pubs │ └── registration │ ├── login.html │ └── profile.html ├── upload │ └── 20160927.xlsx ├── uwsgi.xml ├── wsgi.py └── yjbops ├── __init__.py ├── settings.py ├── urls.py ├── wsgi.py
Django路由
url(r'^index/', views.index), url(r'^release/', views.release), url(r'^release_record/', views.release_record), url(r'^app_list/', views.app_list), url(r'^ips_list/', views.ips_list),
這里只描述項目下面的路由配置
發布頁面
視圖函數
def release(request): ret = { 'applist': None, 'envlist': None, 'app_name': None, 'jira_url':None, 'svn_url':None, 'git_url':None, 'svn_num':None, 'git_id':None, 'time':time.strftime('%Y-%m-%d %H:%M:%S'), 'ips': None, 'console_status': None, 'currnet_buildnum': None, 'console_output': None } jenkins_server_url = 'http://192.168.24.191:8080/jenkins/' user_id = 'testuser' api_token = '7ca1a78d7eb1149137d432c4cf3aaeb3' server = jenkins.Jenkins(jenkins_server_url, username=user_id, password=api_token) job_name = 'FZ.TradeDeployPythonMySQL' ### Py-MySQL conn = MySQLdb.connect(host='127.0.0.1', user='root', passwd='123321', db='ops01') cur = conn.cursor() ### 定義觸發jenkins所需參數 iplist = [] app_name = '' app_del = '' svn_url = '' svn_num = '' jira_url = '' IPs = '' stages_name = '' ### 下拉框 applist = models.Cmdb_app.objects.raw('select * from cmdb_app order by id; ') envlist = models.Cmdb_env.objects.raw('select * from cmdb_env order by id; ') ### 獲取用戶輸入 if request.method == 'POST': app_name = request.POST.get('appname', None) jira_url = request.POST.get('jira', None) svn_num = request.POST.get('svn', None) stages_name = request.POST.get('envname', None) is_empty = all([app_name, jira_url, svn_num, stages_name, ]) if is_empty: ret['status'] = '服務名:%s JIRA單:%s SVN版本:%s 發布環境:%s'.decode('utf-8') % (app_name, jira_url, svn_num, stages_name) ip_sql = 'select ip from cmdb_ip where app_id in (select id from cmdb_app where appname="%s") and env_id in (select id from cmdb_env where envname="%s");' % (app_name, stages_name) ipsCount = cur.execute(ip_sql) res = cur.fetchall() for i in res: iplist.append(i[0]) IPs = ' '.join(iplist) svnCount = cur.execute('select appsvn from cmdb_app where appname="%s"; ' % (app_name)) svn_url = cur.fetchall()[0][0] gitCount = cur.execute('select appgit from cmdb_app where appname="%s"; ' % (app_name)) git_url = cur.fetchall()[0][0] rmdirCount = cur.execute('select appdel from cmdb_app where appname="%s"; ' % (app_name)) app_del_src = cur.fetchall()[0][0] if '/' not in app_del_src: app_del = app_del_src ### 執行帶參數的 jenkins job param_dict = {'app_name': app_name, 'app_del': app_del, 'svn_url': svn_url, 'svn_num': svn_num, 'jira_url': jira_url, 'IPs': IPs, 'stages_name': stages_name} server.build_job(job_name, parameters=param_dict) # 觸發遠程 jenkins job time.sleep(5) # 為了產生最新一次的 id 防止報錯 currnet_buildnum = server.get_job_info(job_name)['lastBuild']['number'] print 'currnet_buildnum',currnet_buildnum while True: time.sleep(1) # 1 秒鍾監測一次 currnet_buildnum_1 = server.get_job_info(job_name)['lastBuild']['number'] print 'currnet_buildnum_1',currnet_buildnum_1 build_status = server.get_build_info(job_name, currnet_buildnum)['building'] print build_status # False if not build_status: # job 執行結束 print '執行結束...' console_output = server.get_build_console_output(job_name, currnet_buildnum) # 構建詳情 # 取到 git 號 和 執行狀態 for i in console_output.split('\n'): b = i.encode('utf-8') print b,type(b) if b.startswith("項目") and 'git' in b: git_id = re.findall('\w{7}', b)[0] if 'Finished' in b and 'SUCCESS' in b: console_status = 'SUCCESS' if 'Finished' in b and 'FAILURE' in b: console_status = 'FAILURE' ret['time'] = time.strftime('%Y-%m-%d %H:%M:%S') ret['app_name'] = app_name ret['jira_url'] = jira_url ret['svn_url'] = svn_url ret['git_url'] = git_url ret['svn_num'] = svn_num ret['git_id'] = git_id ret['ips'] = IPs ret['console_status'] = console_status ret['currnet_buildnum'] = str(currnet_buildnum) # 最新的構建號 ret['console_output'] = console_output # 錄入本次升級記錄 models.Cmdb_record.objects.create(appname = app_name, build_id = currnet_buildnum, ips = IPs, svn_num = svn_num, git_num = git_id, jira_num = jira_url, console_status = console_status, time = time.strftime('%Y%m%d%H%M%S'), ) break else: print 'building...' continue else: ret['status'] = '程序目錄填寫有誤,請核對mysql數據並重新發布' exit() else: ret['status'] = '請填寫所有選項' cur.close() conn.close() ret['applist'] = applist # 服務名下拉框 ret['envlist'] = envlist # 發布環境下拉框 return render_to_response('ops/release.html', ret)
多表查詢使用了原生的SQL沒有用Django的ORM框架
模板
<label> 服務名 </label> <select name="appname"> {% for item in applist %} <option value="{{ item.appname }}"> {{ item.appname }} </option> {% endfor %} </select> ... <dl id="dt-list-1"> <dd><b>AppName :</b> {{ app_name }}</dd> <dd><b>JIRA_URL :</b> <a href={{ jira_url }}>{{ jira_url }}</a></dd> <dd><b>SVN_URL :</b> <a href={{ svn_url }}>{{ svn_url }} </a></dd> <dd><b>GIT_URL :</b> {{ git_url }}</dd> <dd><b>SVN_NUM :</b> {{svn_num}}</dd> <dd><b>GIT_NUM :</b> {{git_id}}</dd> <dd><b>EXEC_IPs :</b> {{ips}}</dd> <dd><b>STATUS :</b> {{console_status}}</dd> <dd><b>Comments :</b> {{time}} 交易組-自動化部署</dd> </dl>
python-jenkins用法介紹
官方文檔 :jenkins 官方wiki(觸發job方式): https://wiki.jenkins-ci.org/display/JENKINS/Remote+access+API
官方文檔 :Python-Jenkins官網:https://pypi.python.org/pypi/python-jenkins/
官方文檔 :Python-Jenkins Doc:http://python-jenkins.readthedocs.io/en/latest/index.html
官方文檔 :Python-Jenkins API:http://python-jenkins.readthedocs.io/en/latest/api.html