Redmine チケットと注記データをデータベースに直接インポートする
弊社では一部の社内サービスに Redmine を利用していますが、つい先日ストレージ障害でサーバーの再構築を余儀なくされ、前回のバックアップ以降のデータが欠如した状態に陥りました。
ということで、メールや Slack の通知に残るチケットや注記の断片をピックアップして、再度インポートするという少々面倒な作業を行うことになりました。
チケット復元方法の検討
チケットの挿入方法としては下記の 3 つの方法が考えられます。
- CSV インポート
- REST API による登録
- データベースに直接登録
1 は Redmine の標準機能です。 2 は自前でツールを作るか、 Redmineチケット★一括★ のようなソフトを利用することになります。
これらはいずれも元々 Redmine に内蔵されている機能なので安心感はあります。ただ、チケット自体は作成できても、注記を追加することができないため、今回の目的には沿いませんでした。
また、チケットの番号も従来と同じに戻したいので、結局のところ、データベースに直接挿入するのが楽だと判断しました。
今回はサーバーのタイムスタンプが古い状態で、それ以後に追加されたチケットや注記のデータをデータベースに直接挿入する方法をまとめておきます。
データベースに外部からログインできるように設定
Redmine のデータベースは PostgreSQL でした。素直に psql で操作してもいいのですが、いろいろ見ながらデータを操作することを考えるとクライアントツールから接続できたほうが便利です。
PostgresSQL は初期設定で外部ホストからの接続を受け付けませんので、まずそれを設定変更します。
ちなみに今回のサーバーは CentOS 7 です。
postgresql.conf の編集
まず、外部向けの TCP ポートでリッスンするように設定します。
設定ファイル postgresql.conf を開きます。
# vi /var/lib/pgsql/data/postgresql.conflisten_addresses と port のコメントアウトを解除して、下記のように設定します。
listen_addresses = '*'
port = 5432pg_hba.conf の編集
pg_hba.conf を編集して、外部ホストからの接続を受け付けるようにします。
# vi /var/lib/pgsql/data/pg_hba.conf次の 1 行を最終行に追加します。
host all all 192.168.1.0/24 trust192.168.1.0/24 は接続を受け付けるホストのネットワークを指定しますので、適宜修正してください。
この記述でこのネットワークからであれば すべてのユーザーですべてのデータベースにアクセスできる ようになります。非常にデンジャラスな設定なので、メンテが終了したら、設定を解除しましょう。
PostgreSQL の再起動
設定ファイルの編集が終わったら再起動しておきます。
# systemctl restart postgresqlファイアウォールのポート解放
まだこのままでは接続できないので、ファイアウォールで PostgreSQL のポートを開放します。
デフォルトでポスグレの設定ファイルが firewalld に含まれているので、 add-service で postgresql を指定するだけで設定できます。
設定が完了したら firewalld を再起動しておきます。
# firewall-cmd --add-service=postgresql --zone=public --permanent
# firewall-cmd --list-services --zone=public --permanent
# systemctl restart firewalldデータベース構造の確認
とりあえずググる
Redmine の ER 図を書いてくださっている先人の方々がいらっしゃるのですが、細かいことを書いておられる人は少なかったです。
下記の記事は機能ごとにどのようなテーブルにレコードが生成されるかをまとめてあるので、役に立ちました。記事自体は 8 年前と古いですが、構造は変わっていないようなので問題ありません。
チケットに関係するテーブル
チケットに関係する主なデータテーブルは下記の通りです。
| テーブル名 | 説明 |
|---|---|
| issues | チケット |
| journals | チケットの変更記録(注記もここ) |
| journal_details | 変更記録の詳細 |
| attachments | 添付ファイルの情報 |
とりあえず issues テーブルが中心になるので、これにレコードを追加して、その id で journals や attachments を追加していくことになります。
データの追加
issues テーブル
エクセルなどでデータを作成し、 issues テーブルにデータを挿入します。今回は Excel ファイルからの登録に Navicat Premium を使用しました。
issues テーブルのカラム定義は下記の通りです。トラッカーやプロジェクトなど外部キーになっている ID はそれぞれのテーブルの ID を事前に調べておき、数値で指定しておきます。
| カラム | 説明 |
|---|---|
| id | チケットID |
| tracker_id | トラッカーのID |
| project_id | プロジェクトID |
| subject | 題名 |
| description | 説明 |
| due_date | 期日 |
| category_id | カテゴリーID |
| status_id | ステータスID |
| assined_to_id | 担当者ID |
| priority_id | 優先度ID |
| fixed_version_id | バージョンID |
| author_id | チケット作成者ID |
| lock_version | |
| created_on | 作成日 |
| updated_on | 更新日 |
| start_date | 開始日 |
| done_ratio | 進捗率 |
| estimated_hours | 予定工数 |
| parent_id | 親チケットID |
| root_id | ルートチケットID |
| lft | |
| rgt | |
| is_private | プライベートフラグ |
| closed_on | 終了日 |
journals テーブル
注記は journals テーブルの 1 レコードとして登録します。
notes に注記内容を記述します。
チケットに対する注記の場合は journalized_type は常に 'Issue' 、 journalized_id にチケット ID を指定します。
| カラム | 説明 |
|---|---|
| id | |
| journalized_id | チケットのID |
| journalized_type | 記録元のデータ (チケットの場合は Issue を指定) |
| user_id | ユーザーID |
| notes | 注記の内容 |
| created_on | 日付 |
テーブルのシーケンスを最新に進める
手動で追加したテーブルについてシーケンスを進めておきます。ただこの手順は必要ないかもしれませんので、不要な場合はスキップしてください。
SELECT setval('issues_id_seq'::regclass, 12345);
SELECT setval('journals_id_seq'::regclass, 123456);添付ファイル
添付ファイルについては attachements テーブルが情報を格納する器ですが、ファイルそのものは files ディレクトリに格納されます。
このため GUI から通常の手順でファイルを添付したあと、 journals からアップロード履歴を消し、 attachements のアップロード日時を変更する、という方法をとりました。
あとがき
完全な手順ではないですが、 Redmine でトラブった方の助けになれば幸いです。




