首先看页面
在按下提交按钮后后端开始执行发布程序(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:
1. 安装
sudo pip install python-jenkins
2. 进入python命令环境或创建新的.py文件jenkinsApiTest.py
import jenkins
#定义远程的jenkins master server的url,以及port
jenkins_server_url='xxxx:xxxx'
#定义用户的User Id 和 API Token,获取方式同上文
user_id='xxxx'
api_token='xxxx'
#实例化jenkins对象,连接远程的jenkins master server
server=jenkins.Jenkins(jenkins_server_url, username=user_id, password=api_token)
#构建job名为job_name的job(不带构建参数)
server.build_job(job_name)
#String参数化构建job名为job_name的job, 参数param_dict为字典形式,如:param_dict= {"param1":“value1”, “param2”:“value2”}
server.build_job(job_name, parameters=param_dict)
#获取job名为job_name的job的相关信息
server.get_job_info(job_name)
#获取job名为job_name的job的最后次构建号
server.get_job_info(job_name)['lastBuild']['number']
#获取job名为job_name的job的某次构建的执行结果状态
server.get_build_info(job_name,build_number)['result']
#判断job名为job_name的job的某次构建是否还在构建中
server.get_build_info(job_name,build_number)['building']
3. 更多其他的API可以参考Python-Jenkins API:http://python-jenkins.readthedocs.io/en/latest/api.html
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