初めに
Redmine向けチケット作成ソフトを扱ったときに, きちんと動作するかcurl
を使ってテストしたのでその方法を説明します.
ここでは, 以下のチケット作成ソフトをもとにしています.
Github redmine-ticket-creater
環境
Python(3.12.3)
Redmine(6.0.4)
Pythonライブラリ
fastAPI(0.116.1)
requests
json
os
チケット作成プログラム
以下がチケット作成プログラムです.
#app.py
# --- 設定 ---
from fastapi import FastAPI, Request
import requests
import os
# --- 設定はすべて環境変数で ---
REDMINE_URL = os.getenv("REDMINE_URL")
API_KEY = os.getenv("REDMINE_API_KEY")
PROJECT_ID = os.getenv("REDMINE_PROJECT_ID")
TRACKER_ID = int(os.getenv("REDMINE_TRACKER_ID")) # 例: 1=Bug, 10=1次調査 など
OPEN_STATUS_ID = int(os.getenv("REDMINE_OPEN_STATUS_ID")) # 例: 1=未着手
CLOSE_STATUS_ID = int(os.getenv("REDMINE_CLOSE_STATUS_ID")) # 例: 8=完了
app = FastAPI()
# チケット作成
def create_redmine_issue(subject, description):
url = f"{REDMINE_URL}/issues.json"
headers = {"X-Redmine-API-Key": API_KEY, "Content-Type": "application/json"}
payload = {
"issue": {
"project_id": PROJECT_ID,
"tracker_id": TRACKER_ID,
"subject": subject,
"description": description,
"status_id": OPEN_STATUS_ID
}
}
r = requests.post(url, json=payload, headers=headers)
if r.status_code == 201:
return r.json()["issue"]["id"]
else:
print(f"Create error: {r.text}")
return None
# チケット検索(未完了のみ)
def find_existing_issue(subject):
url = f"{REDMINE_URL}/issues.json?project_id={PROJECT_ID}&subject=~{subject}&status_id=open"
headers = {"X-Redmine-API-Key": API_KEY}
r = requests.get(url, headers=headers)
if r.status_code == 200 and r.json()["issues"]:
return r.json()["issues"][0]
return None
# チケットを完了に
def close_redmine_issue(issue_id):
url = f"{REDMINE_URL}/issues/{issue_id}.json"
headers = {"X-Redmine-API-Key": API_KEY, "Content-Type": "application/json"}
payload = {"issue": {"status_id": CLOSE_STATUS_ID}}
r = requests.put(url, json=payload, headers=headers)
return r.status_code == 200
@app.post("/webhook")
async def webhook(request: Request):
data = await request.json()
alerts = data.get("alerts", [])
result = []
for alert in alerts:
labels = alert.get("labels", {})
alertname = labels.get("alertname", "unknown")
instance = labels.get("instance", "unknown")
status = alert.get("status", "")
subject = f"{alertname}:{instance}"
description = alert.get("annotations", {}).get("summary", "")
if status == "firing":
# firing時は同じsubjectの未完了チケットがなければ新規作成
issue = find_existing_issue(subject)
if not issue:
issue_id = create_redmine_issue(subject, description)
result.append({"created": issue_id})
else:
result.append({"already_exists": issue["id"]})
elif status == "resolved":
# resolved時は同じsubjectの未完了チケットがあれば完了にする
issue = find_existing_issue(subject)
if issue:
close_redmine_issue(issue["id"])
result.append({"closed": issue["id"]})
else:
result.append({"no_open_issue": subject})
return {"result": result}
ディレクトリ構成
c0117304@c0117304-test:~$s
└─tickets-auto-close/
├─app.py
└─venv
準備
python3を使って仮想環境で動かすので, 諸々インストールが必要です.
既にインストールしてある環境でもう一度実行しているので, 若干出力が違う場合があります.
・python3の確認
UbuntuではPythonがあらかじめ入っています.
c0117304@c0117304-test:~$ sudo apt install python3
[sudo] password for c0117304:
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
python3 is already the newest version (3.12.3-0ubuntu2).
0 upgraded, 0 newly installed, 0 to remove and 75 not upgraded.
c0117304@c0117304-test:~$
以下でバージョンを確認できます.
c0117304@c0117304-test:~$ python3 --version
Python 3.12.3
c0117304@c0117304-test:~$
・仮想環境をインストールします
c0117304@c0117304-test:~/tickets-auto-close$ sudo apt update
sudo apt install python3-venv
Hit:1 http://jp.archive.ubuntu.com/ubuntu noble InRelease
Get:2 http://jp.archive.ubuntu.com/ubuntu noble-updates InRelease [126 kB]
Get:3 http://jp.archive.ubuntu.com/ubuntu noble-backports InRelease [126 kB]
Get:4 http://jp.archive.ubuntu.com/ubuntu noble-updates/main amd64 Packages [1,238 kB]
Get:5 http://security.ubuntu.com/ubuntu noble-security InRelease [126 kB]
Get:6 http://jp.archive.ubuntu.com/ubuntu noble-updates/main amd64 Components [163 kB]
Get:7 http://jp.archive.ubuntu.com/ubuntu noble-updates/restricted amd64 Components [212 B]
Get:8 http://jp.archive.ubuntu.com/ubuntu noble-updates/universe amd64 Packages [1,106 kB]
Get:9 http://jp.archive.ubuntu.com/ubuntu noble-updates/universe Translation-en [282 kB]
Get:10 http://jp.archive.ubuntu.com/ubuntu noble-updates/universe amd64 Components [377 kB]
Get:11 http://jp.archive.ubuntu.com/ubuntu noble-updates/multiverse amd64 Components [940 B]
Get:12 http://jp.archive.ubuntu.com/ubuntu noble-backports/main amd64 Components [7,060 B]
Get:13 http://jp.archive.ubuntu.com/ubuntu noble-backports/restricted amd64 Components [216 B]
Get:14 http://jp.archive.ubuntu.com/ubuntu noble-backports/universe amd64 Components [28.4 kB]
Get:15 http://jp.archive.ubuntu.com/ubuntu noble-backports/multiverse amd64 Components [212 B]
Get:16 http://security.ubuntu.com/ubuntu noble-security/main amd64 Packages [986 kB]
Get:17 http://security.ubuntu.com/ubuntu noble-security/main Translation-en [175 kB]
Get:18 http://security.ubuntu.com/ubuntu noble-security/main amd64 Components [21.5 kB]
Get:19 http://security.ubuntu.com/ubuntu noble-security/restricted amd64 Packages [1,373 kB]
Get:20 http://security.ubuntu.com/ubuntu noble-security/restricted Translation-en [294 kB]
Get:21 http://security.ubuntu.com/ubuntu noble-security/restricted amd64 Components [212 B]
Get:22 http://security.ubuntu.com/ubuntu noble-security/universe amd64 Packages [872 kB]
Get:23 http://security.ubuntu.com/ubuntu noble-security/universe Translation-en [192 kB]
Get:24 http://security.ubuntu.com/ubuntu noble-security/universe amd64 Components [52.3 kB]
Get:25 http://security.ubuntu.com/ubuntu noble-security/multiverse amd64 Components [212 B]
Fetched 7,547 kB in 10s (748 kB/s)
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
86 packages can be upgraded. Run 'apt list --upgradable' to see them.
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
python3-venv is already the newest version (3.12.3-0ubuntu2).
0 upgraded, 0 newly installed, 0 to remove and 86 not upgraded.
(venv) c0117304@c0117304-test:~/tickets-auto-close$
venvは実行したディレクトリにインストールされるので注意してください.
・仮想環境を作成する
venvがあるディレクトリで実行してください
c0117304@c0117304-test:~/tickets-auto-close$ python3 -m venv venv
(venv) c0117304@c0117304-test:~/tickets-auto-close$
・仮想環境を有効化する
c0117304@c0117304-test:~/tickets-auto-close$ source venv/bin/activate
(venv) c0117304@c0117304-test:~/tickets-auto-close$
・fastapi, uvicorn, requestをインストールする
c0117304@c0117304-test:~/tickets-auto-close$ pip install fastapi uvicorn requests
Requirement already satisfied: fastapi in ./venv/lib/python3.12/site-packages (0.116.1)
Requirement already satisfied: uvicorn in ./venv/lib/python3.12/site-packages (0.35.0)
Requirement already satisfied: requests in ./venv/lib/python3.12/site-packages (2.32.4)
Requirement already satisfied: starlette<0.48.0,>=0.40.0 in ./venv/lib/python3.12/site-packages (from fastapi) (0.47.1)
Requirement already satisfied: pydantic!=1.8,!=1.8.1,!=2.0.0,!=2.0.1,!=2.1.0,<3.0.0,>=1.7.4 in ./venv/lib/python3.12/site-packages (from fastapi) (2.11.7)
Requirement already satisfied: typing-extensions>=4.8.0 in ./venv/lib/python3.12/site-packages (from fastapi) (4.14.1)
Requirement already satisfied: click>=7.0 in ./venv/lib/python3.12/site-packages (from uvicorn) (8.2.1)
Requirement already satisfied: h11>=0.8 in ./venv/lib/python3.12/site-packages (from uvicorn) (0.16.0)
Requirement already satisfied: charset_normalizer<4,>=2 in ./venv/lib/python3.12/site-packages (from requests) (3.4.2)
Requirement already satisfied: idna<4,>=2.5 in ./venv/lib/python3.12/site-packages (from requests) (3.10)
Requirement already satisfied: urllib3<3,>=1.21.1 in ./venv/lib/python3.12/site-packages (from requests) (2.5.0)
Requirement already satisfied: certifi>=2017.4.17 in ./venv/lib/python3.12/site-packages (from requests) (2025.7.9)
Requirement already satisfied: annotated-types>=0.6.0 in ./venv/lib/python3.12/site-packages (from pydantic!=1.8,!=1.8.1,!=2.0.0,!=2.0.1,!=2.1.0,<3.0.0,>=1.7.4->fastapi) (0.7.0)
Requirement already satisfied: pydantic-core==2.33.2 in ./venv/lib/python3.12/site-packages (from pydantic!=1.8,!=1.8.1,!=2.0.0,!=2.0.1,!=2.1.0,<3.0.0,>=1.7.4->fastapi) (2.33.2)
Requirement already satisfied: typing-inspection>=0.4.0 in ./venv/lib/python3.12/site-packages (from pydantic!=1.8,!=1.8.1,!=2.0.0,!=2.0.1,!=2.1.0,<3.0.0,>=1.7.4->fastapi) (0.4.1)
Requirement already satisfied: anyio<5,>=3.6.2 in ./venv/lib/python3.12/site-packages (from starlette<0.48.0,>=0.40.0->fastapi) (4.9.0)
Requirement already satisfied: sniffio>=1.1 in ./venv/lib/python3.12/site-packages (from anyio<5,>=3.6.2->starlette<0.48.0,>=0.40.0->fastapi) (1.3.1)
(venv) c0117304@c0117304-test:~/tickets-auto-close$
・REDMINE_URL, REDMINE_API_KEY, REDMINE_PROJECT_ID, REDMINE_TRACKER_ID, REDMINE_OPEN_STATUS_ID, REDMINE_CLOSE_STATUS_IDの環境変数をexportで入力します
export REDMINE_URL="http://your-redmine-server:port_number"
export REDMINE_API_KEY="your_redmine_api_key"
export REDMINE_PROJECT_ID="your_project_id"
export REDMINE_TRACKER_ID="project_tracker_id"
export REDMINE_OPEN_STATUS_ID="open_status_id"
export REDMINE_CLOSE_STATUS_ID="close_status_id"
REDMINE_URL → <"redmineがあるIPアドレスorホスト名":"ポート番号">
REDMINE_API_KEY → redmineにログインし, 右上の個人設定を開くと右側に"APIアクセスキー"があります.
REDMINE_PROJECT_I → redmineでチケットを登録するプロジェクトの識別子をいれてください.
REDMINE_TRACKER_ID → チケットトラッキングのどこに出力するか.デフォルトなら1でBugに登録されます.
REDMINE_OPEN_STATUS_ID → チケットが作成されたときのステータスID. 1なら未着手になります.
REDMINE_CLOSE_STATUS_ID → チケットがResolvedされたときのステータスID. 8なら完了になります.
・fastAPIを実行する
c0117304@c0117304-test:~/tickets-auto-close$ uvicorn app:app --reload --host 0.0.0.0 --port 5005
INFO: Will watch for changes in these directories: ['/home/c0117304/Alert-Ticket-Grouping']
INFO: Uvicorn running on http://0.0.0.0:5005 (Press CTRL+C to quit)
INFO: Started reloader process [4225] using StatReload
INFO: Started server process [4227]
INFO: Waiting for application startup.
INFO: Application startup complete.
これでfastAPIが立ち上がりました.
テストしてみる
以下の入力で実際にAlertmanagerからくる情報を想定してJSON方式で直接入力します. http://localhost:5005/webhook
の部分は実行する環境にあわせてIPアドレスやポート番号を変更してください.
status
は現在もアラートの状態になっていることを示すfiring
,
alertname
はアラートの名前, instance
はホストの名前を入れます.
summary
は何も入ってなくても大丈夫です.
curl -X POST http://localhost:5005/webhook \
-H "Content-Type: application/json" \
-d '{
"alerts": [
{
"status": "firing",
"labels": {
"alertname": "Qiita_Manual_Alert",
"instance": "testhost"
},
"annotations": {
"summary": "Webhookテスト"
}
}
]
}'
チケットが作成されたかを確認します. Redmineをブラウザ( http://<redmineの配置されている対象のIP or Host名>:<公開したPort>
)で開き, 自分で指定したプロジェクトを開いてください.
きちんとQiita_Manual_Alert
のチケットが作成されました.
おわりに
これでチケットをきちんと作成できるかテストできるので, 導入の際は試してみてください.