まだ環境が固まっておらずちょっと書いてみたものです。
テストクラスはしかかり中です。
Jenkinsの情報をちょっと取得したい
要はJenkins画面を解放せずともChatOpsで情報をとれるようにしたいわけなのですが
まだ環境固まっておらず、とりあえず実験的にJenkinsAPIを叩いて
JOB情報取ってきたり、JOB起動できるようにしてみました。
ChatOps提供あればJOB起動のコードは書かなくてもOKになるはずなのですけどね。
# !/opt/anaconda3/bin/python3
# -*- coding: utf-8 -*-
'''RocketChat Jenkins情報取得
Jenkins情報をRocketChatのチャンネルに提供する
Jenkinsの設定によりCSRF対策が行われている
そのためauth情報だけでなくJenkins-Crumb情報が必要となる。
1.adminのTOKEN情報
→ adminユーザコンソールからパーソナルアクセストークンを生成する。
都度生成なのでメモるのを忘れないようにする。
2.Jenkins-Crumb情報取得方法
→ コマンドを発行する必要がる。以下実行してその戻りにより得られる
adminのTOKEN設定が設定になっている。
curl -u 'admin:ADMINS_TOKEN' 'http://xxxxxxx/crumbIssuer/api/xml?xpath=concat(//crumbRequestField,":",//crumb)'
3.結果送信は自前ライブラリを使用する様にして下さい。ここでは実装しません。
RocketChatChannelManager -> sendMessageToRocketChat(channel, msg)1
Todo:
'''
################################################
# library
################################################
import json
import requests
import pandas as pd
import sys
from datetime import datetime
from dateutil import parser
from pprint import pprint
from pytz import timezone
################################################
# 環境変数取得
################################################
#
#
# HEADERS定義
# headers = {
# 'Jenkins-Crumb': '4d0e2b6e2f75aff392422caa2fb7b1f924a4c518c4561743273953b05c0cabdb'}
# 認証定義
# AUTH = ('admin', '11062c796463d71a04e56e5c2cf49a26fa')
#
# URL = 'http://192.168.179.3:3000'
#
################################################
# RocketChatJenkinsManager
################################################
class RocketChatJenkinsManager(object):
def __init__(self, HEADERS, AUTH, URL):
# 引数チェック 型
if not isinstance(HEADERS, dict):
print(f'引数:HEADERSの型が正しくありません dict <-> {type(HEADERS)}')
raise TypeError
# 引数チェック 型
if not isinstance(AUTH, tuple):
print(f'引数:AUTHの型が正しくありません tuple <-> {type(AUTH)}')
raise TypeError
# 引数チェック 型
if not isinstance(URL, str):
print(f'引数:URLの型が正しくありません str <-> {type(URL)}')
raise TypeError
# インスタンス生成
self.HEADERS = HEADERS
self.AUTH = AUTH
self.URL = URL
def exchangeUnixtimeToTimestamp(self, unixtime):
'''unixtimeをtimestampに変換する
Args:
unixtime: float
Returns:
timestamp: str
Raises:
TypeError
Examples:
>>> jenkins = RocketChatJenkinsManager(HEADERS, AUTH, URL)
>>> jenkins.exchangeUnixtimeToTimestamp(1610870939803)
-> '2021/01/17 17:08:59'
Note:
'''
# 引数チェック 型
#if not isinstance(unixtime, int):
# print(f'引数:unixtimeの型が正しくありません int <-> {type(unixtime)}')
# raise TypeError
timestamp_succsessful = float(unixtime)
return datetime.fromtimestamp(timestamp_succsessful/1000.).strftime('%Y/%m/%d %H:%M:%S')
def getJenkinsJobList(self):
'''Jenkins 利用可能JOB一覧を取得する
利用可能JenkinsJOB一覧をPandas DataFrameで返す。
Args:
無し
Returns:
pd.DataFrame
Jobname, Params, JobDescription, ExecCount, URL
Raises:
API実行時のエラー
Examples:
>>> jenkins = RocketChatJenkinsManager(HEADERS, AUTH, URL)
>>> df = jenkins.getJenkinsJobList()
Note:
'''
# Columns定義(データ取得)
columns_in_df = ['JobName', 'JobDescription', 'ExecCount', 'URL','Params']
# Columns定義(データ出力)
columns_out_df = ['JobName', 'Params', 'JobDescription', 'ExecCount', 'URL']
# API定義
ENDPOINT = '/api/json'
QUERY = '?depth=1&tree=jobs[displayName,description,lastCompletedBuild[number,url],actions[parameterDefinitions[name]]]'
API = f'{self.URL}{ENDPOINT}{QUERY}'
# 取得処理
try:
response = requests.post(
API,
auth=self.AUTH,)
except Exception as e:
print(f'API実行エラー: {API}')
print(f'Error: {e}')
return False
else:
# 仮の入れ物を用意
_list1 = []
_list2 = []
# 取得responseから情報取得
## Job基本情報取得
for _ in response.json()['jobs']:
_list1.append([_['displayName'],
_['description'],
_['lastCompletedBuild']['number'],
_['lastCompletedBuild']['url']])
## 可変であるパラメータ取得
_list3 = []
for __ in _['actions']:
if (__ != {}) & (__ != {'_class': 'com.cloudbees.plugins.credentials.ViewCredentialsAction'}):
_key = ''
for ___ in __['parameterDefinitions']:
_key += f"param: {___['name']} "
_list3.append(_key)
_list2.append(_list3)
## 出力フォーマット処理
df1 = pd.DataFrame(_list1)
df2 = pd.DataFrame(_list2)
df = pd.concat([df1, df2], axis=1)
df.columns = columns_in_df
# 出力微調整
return df[columns_out_df]
def execJenkinsJobListNoParameters(self, jobname):
'''指定したJenkinsJOB(パラメータなし)をリモート実行する
ここでの役割はJenkinsJobをリモート実行するのみであり
そのJob実行結果はハンドリングしていない。
そもそも非同期実行の仕組みになっている。
Args:
jobname: str JenkinsJob名、ただしパラメータ定義のないJob
Return:
response: <Response [201]> 実行スケジュールに渡しました
Raises:
API実行時のエラー
Examples:
>>> jenkins = RocketChatJenkinsManager(HEADERS, AUTH, URL)
>>> jenkins.execJenkinsJobListNoParameters('test_hubot')
Note:
'''
# 引数チェック 型
if not isinstance(jobname, str):
print(f'引数:jobnameの型が正しくありません str <-> {type(jobname)}')
raise TypeError
# API定義
ENDPOINT = f'/job/{jobname}/build'
API = f'{self.URL}{ENDPOINT}'
# Job投入
try:
response = requests.post(
API,
headers=self.HEADERS,
auth=self.AUTH,)
except Exception as e:
print(f'API実行エラー: {API}')
print(f'Error: {e}')
return False
else:
# Jobリモート投入成功を伝える
print(f'{jobname}をリモート実行しました')
print(response)
return '201'
def execJenkinsJobListWithParameters(self, jobname):
'''指定したJenkinsJOB(パラメータ設定あり)をリモート実行する
ここでの役割はJenkinsJobをリモート実行するのみであり
そのJob実行結果はハンドリングしていない。
そもそも非同期実行の仕組みになっている。
Args:
jobname: str JenkinsJob名、ただしパラメータ定義のないJob
Return:
response: <Response [201]> 実行スケジュールに渡しました
Raises:
API実行時のエラー
Examples:
>>> jenkins = RocketChatJenkinsManager(HEADERS, AUTH, URL)
>>> jenkins.execJenkinsJobListWithParameters('test_hubot')
Note:
'''
# 引数チェック 型
if not isinstance(jobname, str):
print(f'引数:jobnameの型が正しくありません str <-> {type(jobname)}')
raise TypeError
# API定義
ENDPOINT = f'/job/{jobname}/buildWithParameters'
API = f'{self.URL}{ENDPOINT}'
# Job投入
try:
response = requests.post(
API,
headers=self.HEADERS,
auth=self.AUTH,)
except Exception as e:
print(f'API実行エラー: {API}')
print(f'Error: {e}')
return False
else:
# Jobリモート投入成功を伝える
print(f'{jobname}をリモート実行しました')
print(response)
return '201'
def _lastBuildTimestamp(self, jobname):
'''指定したJenkinsJOB(パラメータ設定あり)の最終実行時間を取得する
Args:
jobname: str JenkinsJob名、ただしパラメータ定義のないJob
Retur:
timestamp: str 最後の成功Build時間 YYYY/MM/DD HH:MM:SS
Raises:
API実行時のエラー
Examples:
>>> jenkins = RocketChatJenkinsManager(HEADERS, AUTH, URL)
>>> jenkins.lastSuccessfulBuildTimestamp('test_hubot')
Note:
'''
# 引数チェック 型
if not isinstance(jobname, str):
print(f'引数:jobnameの型が正しくありません str <-> {type(jobname)}')
raise TypeError
# API定義
ENDPOINT = f'/job/{jobname}/lastBuild/api/json'
API = f'{self.URL}{ENDPOINT}'
# JOBパラメータ定義
params = (
('pretty', 'true'),
)
# Job投入
try:
response = requests.post(
API,
headers=self.HEADERS,
params=params,
auth=self.AUTH,)
except Exception as e:
print(f'API実行エラー: {API}')
print(f'Error: {e}')
return False
else:
# unixtimeをtimestampへ変換して戻す
return(self.exchangeUnixtimeToTimestamp(response.json()['timestamp']))
def _lastSuccessfulBuildTimestamp(self, jobname):
'''指定したJenkinsJOB(パラメータ設定あり)の最終成功時間を取得する
Args:
jobname: str JenkinsJob名、ただしパラメータ定義のないJob
Retur:
timestamp: str 最後の成功Build時間 YYYY/MM/DD HH:MM:SS
Raises:
API実行時のエラー
Examples:
>>> jenkins = RocketChatJenkinsManager(HEADERS, AUTH, URL)
>>> jenkins.lastSuccessfulBuildTimestamp('test_hubot')
Note:
'''
# 引数チェック 型
if not isinstance(jobname, str):
print(f'引数:jobnameの型が正しくありません str <-> {type(jobname)}')
raise TypeError
# API定義
ENDPOINT = f'/job/{jobname}/lastSuccessfulBuild/api/json'
API = f'{self.URL}{ENDPOINT}'
# JOBパラメータ定義
params = (
('pretty', 'true'),
)
# Job投入
try:
response = requests.post(
API,
headers=self.HEADERS,
params=params,
auth=self.AUTH,)
except Exception as e:
print(f'API実行エラー: {API}')
print(f'Error: {e}')
return False
else:
# unixtimeをtimestampへ変換して戻す
return(self.exchangeUnixtimeToTimestamp(response.json()['timestamp']))
def _lastFailedBuildTimestamp(self, jobname):
'''指定したJenkinsJOB(パラメータ設定あり)の最終失敗時間を取得する
Args:
jobname: str JenkinsJob名、ただしパラメータ定義のないJob
Retur:
timestamp: str 最後の成功Build時間 YYYY/MM/DD HH:MM:SS
Raises:
API実行時のエラー
Examples:
>>> jenkins = RocketChatJenkinsManager(HEADERS, AUTH, URL)
>>> jenkins.lastFailedBuildTimestamp('test_hubot')
Note:
'''
# 引数チェック 型
if not isinstance(jobname, str):
print(f'引数:jobnameの型が正しくありません str <-> {type(jobname)}')
raise TypeError
# API定義
ENDPOINT = f'/job/{jobname}/lastFailedBuild/api/json'
API = f'{self.URL}{ENDPOINT}'
# JOBパラメータ定義
params = (
('pretty', 'true'),
)
# Job投入
try:
response = requests.post(
API,
headers=self.HEADERS,
params=params,
auth=self.AUTH,)
except Exception as e:
print(f'API実行エラー: {API}')
print(f'Error: {e}')
return False
else:
# unixtimeをtimestampへ変換して戻す
return(self.exchangeUnixtimeToTimestamp(response.json()['timestamp']))
def getJobInformation(self, jobname):
'''指定したJenkinsJOB(パラメータ設定あり)の実行情報を取得する
Args:
jobname: str JenkinsJob名、ただしパラメータ定義のないJob
Return:
joburl: str
job情報: DataFrame
Raises:
API実行時のエラー
Examples:
>>> jenkins = RocketChatJenkinsManager(HEADERS, AUTH, URL)
>>> jenkins.getJobInformation('test_hubot')
Note:
'''
# 引数チェック 型
if not isinstance(jobname, str):
print(f'引数:jobnameの型が正しくありません str <-> {type(jobname)}')
raise TypeError
# API定義
ENDPOINT = f'/job/{jobname}/api/json'
API = f'{self.URL}{ENDPOINT}'
# JOBパラメータ定義
params = (
('pretty', 'true'),
)
# Job投入
try:
response = requests.post(
API,
headers=self.HEADERS,
params=params,
auth=self.AUTH,)
except Exception as e:
print(f'API実行エラー: {API}')
print(f'Error: {e}')
return False
else:
# JobLinkPath生成
joburl = f"{response.json()['url']}"
# 基本情報をまとめる
_list = []
_list.append([f"Job名", f"{response.json()['displayName']}"])
_list.append([f"Job詳細", f"{response.json()['description']}"])
_list.append([f"HealthReport", f"{response.json()['healthReport'][0]['description']}"])
_list.append([f"JobStatus Color", f"{response.json()['color']}"])
# _list.append([f"Job最新実行:失敗判定", f"{response.json()['lastUnstableBuild']}"])
_list.append([f"Job最終BuildNo.", f"{response.json()['lastBuild']['number']}"])
_list.append([f"Job最終Build時間", f"{self._lastBuildTimestamp(jobname)}"])
_list.append([f"Job最終成功BuildNo.", f"{response.json()['lastSuccessfulBuild']['number']}"])
_list.append([f"Job最終成功BuildURL", f"[link]({response.json()['lastSuccessfulBuild']['url']}consoleText)"])
_list.append([f"Job最終成功Build時間", f"{self._lastSuccessfulBuildTimestamp(jobname)}"])
_list.append([f"Job最終失敗BuildNo.", f"{response.json()['lastFailedBuild']['number']}"])
_list.append([f"Job最終失敗BuildURL", f"[link]({response.json()['lastFailedBuild']['url']}consoleText)"])
_list.append([f"Job最終失敗Build時間", f"{self._lastFailedBuildTimestamp(jobname)}"])
# DataFrame生成
df = pd.DataFrame(_list)
df.columns = ['項目', 'ステータス']
return joburl, df