はじめに
GitLabのサブグループ以下にある複数プロジェクトのCI/CDパイプラインの実行状況を一覧化したいなーと思ったときのメモ。
やりたいこと
GitLab CI/CDパイプライン上でGitLab APIを叩いて、結果をPagesにデプロイします。
このとき、APIの結果を集計したかったので、python-gitlab
を使用します。
環境
GitLab.comで構築・実行
やったこと
用意したのは以下の3つのファイル。
-
monitor.py
... GitLab APIを叩いて、HTMLを作成 -
.gitlab-ci.yml
... パイプライン定義 -
Dockerfile
...monitor.py
を動かすcontainer imageの定義(なくてもいい)
import gitlab
import pandas as pd
import datetime
from zoneinfo import ZoneInfo
import os
GITLAB_URL = os.getenv('CI_SERVER_URL')
TOKEN = os.getenv('TOKEN')
GITLAB_GROUP_ID = os.getenv('GITLAB_GROUP_ID')
html_template = '''
<html>
<head>
<meta charset="utf-8">
<title>GitLab Pipeline Monitor</title>
</head>
<body>
<h1>GitLab Pipeline Monitor</h1>
GitLab URL: {GITLAB_URL} <br>
GitLab Group: {GITLAB_GROUP} <br>
Updated: {UPDATED_AT} <br>
Summary:
{SUMMARY}
<hr>
{TABLE}
</body>
</html>
'''
def main():
attr = ['project_id', 'project_name', 'pipeline_updated_at', 'pipeline_status']
gl = gitlab.Gitlab(url=GITLAB_URL, private_token=TOKEN)
df_all = pd.DataFrame(columns=attr)
gl_group = gl.groups.get(id=GITLAB_GROUP_ID)
dt_now = datetime.datetime.now(ZoneInfo("Asia/Tokyo")).strftime('%Y年%m月%d日 %H:%M:%S')
for i in gl_group.projects.list(iterator=True):
data = {x: '' for x in attr}
data['project_id'] = [i.id]
data['project_name'] = [i.name]
pipelines = gl.projects.get(i.id).pipelines.list(order_by='updated_at', sort='desc')
if len(pipelines) == 0:
data['pipeline_updated_at'] = ['not run']
data['pipeline_status'] = ['not run']
else:
latest_pipeline = pipelines[0]
data['pipeline_updated_at'] = [latest_pipeline.updated_at]
data['pipeline_status'] = [latest_pipeline.status]
df_tmp = pd.DataFrame(data, columns=attr)
df_all = pd.concat([df_all, df_tmp], axis=0)
df_counts = pd.DataFrame(df_all['pipeline_status'].value_counts())
html = html_template.format(
GITLAB_URL=GITLAB_URL,
GITLAB_GROUP=gl_group.name,
UPDATED_AT=dt_now,
SUMMARY=df_counts.to_html(),
TABLE=df_all.to_html(index=False))
with open('index.html', mode='w') as f:
f.write(html)
if __name__ == '__main__':
main()
環境変数は以下の2つ。
-
TOKEN
... GitLabのパーソナルトークン。 -
GITLAB_GROUP_ID
... 取得対象のサブグループID
処理内容ですが、
gl = gitlab.Gitlab(url=GITLAB_URL, private_token=TOKEN)
でGitLabインスタンスを作成。
gl_group = gl.groups.get(id=GITLAB_GROUP_ID)
で対象のサブグループを取得しています。
gl_group.projects.list(iterator=True)
でサブグループ以下のプロジェクトを全量取得してループしています。
ここで、公式ドキュメントにも記載されていますが、iterator=True
あるいはget_all=True
をオプションで指定しないと、全プロジェクト取得できないところが注意。
あとは、結果をpandas
のDataFrame
に入れて集計、整理してto_html()
でHTMLとして取得しています。
stages:
- build
- monitor
- deploy
variables:
IMAGE: ${CI_REGISTRY}/${CI_PROJECT_PATH}/gitlab-pipeline-monitor
docker-build:
stage: build
image: docker:19.03
services:
- name: docker:19.03-dind
only:
- tags
script:
- docker login -u $CI_REGISTRY_USER -p $CI_JOB_TOKEN $CI_REGISTRY
- docker build -t ${IMAGE} .
- docker images
- docker push ${IMAGE}:latest
monitor:
stage: monitor
image: ${IMAGE}:latest
only:
- web
- schedule
script:
- python monitor.py
artifacts:
paths:
- ./index.html
pages:
stage: deploy
only:
- web
- schedule
script:
- mkdir public
- mv ./index.html public/
- ls public/
artifacts:
paths:
- public
CI/CDパイプライン定義については大したことはしておらず、monitor.py
で出力されたindex.html
をpages
ジョブでGit Lab Pagesとしてデプロイしています。
GitLab Pagesはpages
というジョブ名、deploy
というステージにする必要があるところだけ注意です。
FROM python:3.11
RUN pip install --no-cache-dir python-gitlab==3.13.0
RUN pip install --no-cache-dir pandas==1.5.3
Dockerfileはこのくらいならなくてもいいですし、本来requirements.txt
とかを用意しておくのが普通かと思いますが、2つだけだしいっか、ということで、少し雑です。
結果
パイプラインで実行した結果、Pagesにデプロイできました。
まとめ
python-gitlabでGitLabのパイプライン状況を一覧表示するHTMLをGitLab Pagesにデプロイしてみました。
パイプラインをスケジュール実行すれば、定期的に状況が可視化できるかと。
なお、ソースコードはGitLab.comで公開しています。
ご参考までに。