はじめに
前回、Redmine 6.xへの移行に備え、本番とは完全に切り離した Side-by-Side 構成の検証環境(redmine-clone)を構築しました。
今回取り組んだのは、長年利用してきたプラグイン、 redmine_dmsf を完全に取り除く作業です。
DMSFは非常に高機能なプラグインですが、現在の筆者の運用では役目を終えており、Redmine 6.xへの移行を見据えてアンインストールすることにしました。
ところが、標準的なアンインストール手順では途中で何度もエラーが発生し、作業はまったく進みません。
ロールバック
↓
エラー修正
↓
もう一度ロールバック
↓
別のエラー
まさにモグラ叩きです。
最終的には発想を切り替え、「過去のマイグレーションを修正しながら戻す」のではなく、「今後二度と利用しない」という前提で、プラグインを外科手術のように切除する方法を選択しました。
この記事は、その作業記録です。
今回の前提
今回の作業は、前回構築した 検証環境 (redmine-clone) を対象に実施しています。
| 項目 | 内容 |
|---|---|
| 対象環境 | redmine-clone |
| Redmine | 5.1系 |
| Ruby | 3.2系 |
| Rails | 6.1 |
| Database | MySQL 8.x |
| 対象プラグイン | redmine_dmsf |
本番環境では絶対に実施せず、必ず検証環境で確認してから行ってください。
今回の方針
通常であれば
sudo -u www-data bundle exec rake redmine:plugins:migrate VERSION=0
でロールバックするのが正攻法です。
しかし今回は、
- Rails側の仕様変更
- 古いマイグレーションコード
- 運用期間中に蓄積したデータ
これらが複雑に絡み合い、途中でロールバックが停止しました。
そこで今回は
「DMSFを今後一切利用しない」
ことを前提に、
- DMSFテーブルを削除
- マイグレーション履歴を削除
- プラグイン本体を撤去
という外科手術方式を採用しています。
作業前にMySQLバックアップを取得する
これから実施する操作は、テーブル削除やマイグレーション履歴の削除を伴います。
やり直しができるよう、必ずダンプを取得してから作業します。
※DB名、ユーザー名は自分の環境に合わせてください。
mysqldump \
--single-transaction \
--routines \
--triggers \
--default-character-set=utf8mb4 \
-u redmine_clone \
-p \
redmine_clone \
> redmine_clone_before_dmsf.sql
今回の作業では、このダンプが最後の保険になります。
最初に試した方法--NG
まずは標準手順どおりロールバックを試みました。
sudo -u www-data \
bundle exec rake \
redmine:plugins:migrate \
NAME=redmine_dmsf \
VERSION=0 \
RAILS_ENV=production
ところが、ここから長い戦いが始まります。
発生したエラー
1. Rails 6.1との仕様不整合
最初に発生したのは
ArgumentError: wrong number of arguments
というエラーでした。
原因は、古いマイグレーションで利用されている
t.index_exists?
の引数仕様が、現在のActiveRecordと一致していなかったためです。
2. 存在しないインデックス
修正すると、今度は
No indexes found...
で停止しました。
ロールバックコードは「存在するはず」と考えているインデックスが、現在のデータベースには存在しません。
過去十数年の運用の中でスキーマが変化していたことが原因でした。
3. nil参照によるクラッシュ
さらに進めると
undefined method 'id' for nil
で停止。
古いマイグレーションでは、存在する前提のデータが既になくなっており、ロールバック中にクラッシュしました。
今回の教訓
ここまでで感じたことは一つです。
標準手順だからといって、必ず最後まで実行できるとは限らない。
10年以上前に書かれたマイグレーションコードを、現在のRailsで逆方向へ実行する。
これは思っている以上に難しく、途中で止まる可能性があります。
一つ修正しても、次のマイグレーションで別のエラーが出る。今回の作業は、まさにモグラ叩きでした。
方針転換 ― 外科手術で切除する
今回はDMSFを再利用する予定はありません。
そこで、「きれいにロールバックする」ではなく、「安全に切除する」 という考え方へ切り替えました。
Step1 DMSFテーブルを削除する
まず外部キー制約を一時的に無効化します。
mysql -u redmine-clone -p
※本番環境のアカウントではログインしないこと。非常に悪い意味で眠気が吹っ飛びます。
USE redmine_clone;
SET FOREIGN_KEY_CHECKS=0;
続いて関連テーブルを削除します。
DROP TABLE IF EXISTS
dmsf_file_revisions,
dmsf_files,
dmsf_folder_permissions,
dmsf_folders,
dmsf_links,
dmsf_locks,
dmsf_public_urls,
dmsf_workflow_step_actions,
dmsf_workflow_step_assignments,
dmsf_workflow_steps,
dmsf_workflows;
最後に外部キー制約を戻します。
SET FOREIGN_KEY_CHECKS=1;
Step2 マイグレーション履歴を削除する
続いて
schema_migrations
からDMSFの履歴を削除します。
DELETE
FROM schema_migrations
WHERE version LIKE '%-redmine_dmsf';
注意
この操作は「今後DMSFを利用しない」ことを前提としています。
データを保持したまま将来的に再利用する予定がある場合は、この方法は適しません。
Step3 状態確認
再度ロールバックを実行します。
sudo -u www-data \
bundle exec rake \
redmine:plugins:migrate \
NAME=redmine_dmsf \
VERSION=0 \
RAILS_ENV=production
正常終了していれば
echo $?
0
となります。
Step4 プラグイン本体を退避する
最後にプラグイン本体を退避します。
sudo mkdir -p \
/home/www-data/retired_plugins
sudo mv \
plugins/redmine_dmsf \
/home/www-data/retired_plugins/
Passengerを利用している場合は再起動します。
sudo touch tmp/restart.txt
apaceの再起動でもOKです。
sudo systemctrl reload apache2.service
動作確認
ここまで終わったら、
- Redmineが起動する
- Administration → Plugins にDMSFが表示されない
- エラーログにDMSF関連エラーが出ていない
- プロジェクトが正常に閲覧できる
ことを確認します。
問題がなければ、DMSFの切除は完了です。
おわりに
今回一番苦労したのは、アンインストールの方法そのものではありません。
**「標準手順が最後まで通らない」**ことでした。
最初はマイグレーションを一つずつ修正してロールバックしようと考えていましたが、進むたびに新しいエラーが現れ、終わりが見えませんでした。
そこで発想を変え、「もう利用しないものは、安全を確認したうえで切除する」という方針に切り替えたことで、ようやく前へ進むことができました。
もちろん、この方法は誰にでも勧められるものではありません。テーブルやマイグレーション履歴を直接操作するため、十分なバックアップと、失敗してもやり直せる検証環境があることが大前提です。
前回構築した redmine-clone は、まさにそのための環境でした。
標準手順が通らない場面ほど、「何度でもやり直せる環境」があることの価値を強く実感しています。
そして、この作業によってようやく、Redmine 6.xへの移行に向けた大きな障害を一つ取り除くことができました。
コメントを残す