より安全にadhoqを実行したい
追記:だいたいの内容が反映された、adhoq v0.4.0がリリースされていますので、ご利用ください。
adhoqを使うと、管理画面などで任意のSQLができるようになって便利そうだ。 ただ調査をしていると、sandbox機構は、Transactionを実行してRollbackする、という方式になっているので、アプリケーション実行ユーザーがDROP TABLEできる権限で動いていたりすると、DROP TABLEなどすることができてしまうので、通常のアプリケーションユーザーとは別のユーザーで実行したかった。(アプリケーションユーザーがDROP TABLEできない方がのぞましいが。
また、本番と同じ系統で任意のSQLを実行できるようにした場合、重いSQLなどを実行されてしまったときに本番で別の部分がSlow queryになってしまうので、サービスから隔離した系統で実行させたいというのもあった。
Adhoqの設定には、 config.database_connection
というものがあって、ここを置きかえればよさそうにも思えるが、
https://github.com/esminc/adhoq/blob/master/lib/adhoq.rb#L17
config.database_connection = proc { ActiveRecord::Base.connection }
ここを置きかえただけだと、Adhoqのユーザーの入力したSQL実行終了後に、Adhoqのレコード入れるときなどのconnectionを元に戻すことができないので、うまくいかないっぽかったのでAdhoqそのものを変更した。
Comparing esminc:master...walf443:connection_switchable · esminc/adhoq · GitHub
インターフェースを変えてしまうのでPRにして通るかどうかわからないし英語で書いてうまく伝わるかなー、といった感じだったのでひとまずブログで書いてみた。
なお、手元ではreadonlyな接続を利用するのに、switch_pointとあわせて利用していて、上記のパッチに加えて、
# config/initializers/adhoq.rb Adhoq.configure do |config| config.hidden_model_names = %w[SwitchPoint::Proxy::MainReadonly] end module AdhoqReadonlyable def with_connection result = nil SwitchPoint.with_readonly_all do result = yield(ApplicationRecord.connection) end result end end Adhoq::Executor::ConnectionWrapper.prepend(AdhoqReadonlyable)
といった感じにして、connectionまわりを差し変えている。
また、触っていて、いくつか気になったところを見つけたのでいくつか別途PRにした。
- クエリのページのN+1クエリの修正 github.com
- テーブル一覧を表示しようとすると全テーブルのcountを取得しようとする問題の修正 github.com
https://github.com/esminc/adhoq/commit/c104c36018744f22fccd537177b8cfa38051a27b
SQLが実行できなかったときに失敗状態にならない問題を修正 Fix exexution failure handling by walf443 · Pull Request #160 · esminc/adhoq · GitHub