読者です 読者をやめる 読者になる 読者になる

Kuroko2でReadOnly権限を追加するgemを作りました

まずKuroko2とは??やKuroko2の素晴らしさには過去書いた下記の記事を見てもらえると 🙏 hatappi.hateblo.jp

Kuroko2に関しては画面上からScriptを定義したり定期実行をしてその実行ログなどが見られる
ただ権限管理のような機能は現状ない。第三者のアクセスに関してはIP制限なりBasic認証で防げば良いと思う

ただ小さなチームで運用していく中ではScriptを追加したり更新したりはしては困るけど実行結果や内容の確認などで閲覧だけ許したい時があるのかなと思います。 僕はありました

なので作りました 👍

github.com

使い方に関してはgem内の README.md に記載されていて
generatorでmigrationファイルを作成して後はKuroko2の設定ファイルにextensionとして今回のgemのconcernを追加するだけで使用できます

Kuroko2には自作したConcernを追加できる

Kuroko2では設定ファイル(config/kuroko2.yml)に下記のようにKuroko2内で使用したいConcernを追加することが出来る

default: &default
  extentions:
    controller:
      - '::Kuroko2ReadOnly::RequestHandler'

仕組みとしてはKuroko2のengine.rbで設定ファイルされたものがincludeされている
今回のgemもこちらの機能を使用している

追加したConcern

今回は下記のようなConcernを追加しました
中身はシンプルでReadOnlyの時はGETリクエスト以外はExceptionを出すだけです

require 'active_support'

module Kuroko2ReadOnly
  module RequestHandler
    extend ::ActiveSupport::Concern
    included do
      before_action :get_request_only
    end

    private

    def get_request_only
      if current_user && current_user.read_only?
        raise ::Kuroko2ReadOnly::AccessDenied unless request.get?
      end
    end
  end
end

おまけ

今回はConcernだけでなく自分以外のユーザーのReadOnlyにするかどうかを設定する画面をMountableEngineで追加しました
viewを作る際にスタイルなどを1からあてるのは骨がおれるのでKuroko2に依存するgemでもあるのでlayoutもKuroko2のものを使用しました

使用自体は下記のように指定するだけでKuroko2ReadOnlyのMountableEngine内のViewでもKuroko2のlayoutが使用できます

class Kuroko2ReadOnly::ApplicationController < ActionController::Base
  layout 'layouts/kuroko2/application'
  ~~~
end

ただこれだけではうまくいかない!!
Kuroko2内のlayoutで定義されている osd_path のようなKuroko2内のroutesで定義されている
もしKuroko2ReadOnlyから使用するのであれば kuroko2.omd_pathのように指定しなければならない
ただ今回はKuroko2のgemのlayoutを使用しているので、指定ができない

なので…

module Kuroko2ReadOnly
  module ApplicationHelper
    def method_missing(method, *args, &block)
      if (method.to_s.end_with?('_path') || method.to_s.end_with?('_url')) && kuroko2.respond_to?(method)
        kuroko2.send(method, *args)
      else
        super
      end
    end
  end
end

このようなものを追加しました これは定義されていないメソッドなどが呼ばれた時にcallされる method_missing をoverrideしているもので、仮に omd_path のようなpathがわたってきてKuroko2ReadOnlyないでは定義されてないがKuroko2側にあるpathの場合はKuroko2でsendして呼び出しそのパス情報を返すようにします

これにより何とか今回使用するGemからKuroko2のlayoutを使用できるようになりました

f:id:hatappi1225:20170306012424p:plain

最後に

使ってなにか不便があればISSUEやTwitterなどでメンションください 🙏

Job管理をAirflowからKuroko2に乗り換えたら幸せになった

Speeeアドベントカレンダー 2日目の記事です。

前日の記事は@hiragramTravisCIでiOSの依存ライブラリの更新を自動化する - TECHNICA Speee engineer blog

エンジニアの@hatappiです。 前年度のアドベントカレンダーでこんな記事書いてました。 hatappi.hatenablog.com

要するに定期処理をうまいこと実現したい!そのためにAirflowを使ってはどうかっていう記事です
※ Airflowはデータパイプラインのスケジュールとかモニタリングできるツールです。簡単にいうとジョブ管理ができるシステム

Airflowを使うと

  • 定期実行したい
  • 成功、失敗において通知したい
  • 画面上から再実行したい
  • logを画面からおいたい

といった定期処理でやりたいことを実現できるので、あれから実際に会社でも導入して
現在稼働しておりディレクターの方が画面上から再実行しており エンジニアが再取得の対応をしなくてもよくなりました 🎉

ただ タスクをPythonでかかないといけない
これがちょっと辛い
※これはPythonが悪いわけではなく単にRubyを書いていてPythonに慣れてないだけなんですが

会社ではRubyを使うので、どうしてもでないかぎりRubyで扱えると嬉しい
Rubyで扱えると

  • プロジェクトに他の人が入っても、このジョブは何をやっているか把握しやすい
  • ドキュメントにのってなくても最悪ソースを追うことができる
  • 何か不具合があったらコミットできる

1年前に記事を書いた時はRuby製の良いものがなく クックパッドのジョブ管理システム kuroko2 の紹介 - クックパッド開発者ブログ この記事をみて良いなと思いつつAirflowを導入したのが良い思い出。 そんな中今年Kuroko2がOSS化しました!
めでたい 🎉

github.com

使ってみたのですが まず感想から言うと ジョブ管理でしたいことがシンプルに始められるのでよさげ

ジョブ管理では

  • 通知機能
  • GUIでのリトライ処理
  • logの閲覧
  • ジョブの実行環境の分散

があると良いのですがAirflowも網羅してましたがKuroko2も網羅してます
これ以外にもタスクの実行時間やメモリ使用量をグラフで見れたり
GoogleOAuth認証 も標準でついてます

通知機能

Airflowの時は自分で通知タスクを作りジョブのcallbackに通知タスクを設定するコードでかいてましたが、
Kuroko2ではSlackやHipChatや他のwebhookを設定するだけでタスクの実行にあわせて通知してくれます。

f:id:hatappi1225:20161201192515p:plain

またエラーの時はメンションつけたりメッセージを追加したい時もFailure notification textに追加するだけで通知される
このちょっと痒いところに手が届く感じが良い

f:id:hatappi1225:20161201192717p:plain

GUIでのリトライ処理

GUIで単に再実行できるだけでなく、定期実行の場合次の日にタスクが走った時に
実行するか、エラーが解消されるまでキャンセルするかなども画面上から設定できる
Airflowの時はコードでそれを記載しないといけなかった...

f:id:hatappi1225:20161201192755p:plain

logの閲覧

標準出力やエラーなどを各ジョブごとにブラウザから確認が出来るので
エラーがおきた際もなぜ起きたかなどをサーバーに確認せずともGUIから確認できる 設定すればCloudWatch Logsに流すなんてことも出来る

ジョブの実行環境の分散

アプリケーションが大きくなるにつれて色んなバッチができて、動いているバッチがメモリ食いつぶして 他のジョブに影響が出たりしたことはないだろうか Kuroko2では実行する環境を別サーバーにわけることが出来るのでこれも回避できる

workerをそれぞれのインスタンスで起動させる際に環境変数QUEUE に任意の値を設定し jobの定義でコマンド実行前に QUEUE に設定した名前を指定するだけ

QUEUE=hoge でworkerを立ち上げた時はjobの定義にて

queue: hoge
execute: bundle exec rails hoge:fuga

この他のKuroko2のアーキテクチャなどの紹介は クックパッドのジョブ管理システム kuroko2 の紹介 - クックパッド開発者ブログ が詳しいです

実用編

ローカルで試す分にはKuroko2にProcfileが用意されているので foremanコマンドを実行すれば良いので時間はかからないと思う
ただ実運用となるとデプロイしたりworkerやschedulerを再起動させたりしたい
Kuroko2のWebは通常のrailsプロジェクト作成時にKuroko2のアプリケーションテンプレートを流しただけなのでCapistrano使うなりすれば実現できる

executor, processor, schedulerの各プロセスをどう再起動するかに関しては
Kurko2にSystemdのサービスのサンプル用意されてる kuroko2/docs/systemd at master · cookpad/kuroko2 · GitHub が使える

ただ起動はされるが、僕のDebian jessie環境では再起動すると停止されずに次のプロセスが立ち上がってしまい最初それに気づかないままworkerがメモリを食いつぶす事件があったのでpidの場所を定義するようにしてあげた
stopするときはQUITシグナルを送っているので今やっている処理を終えるととまってくれる

gist.github.com

ここまで定義すれば後はCapistranoならdeploy後にhookするなどして再起動してあげれば終わり

最後に

定期実行の話をするとcronからJenkins, Rundeckとか今色々選択肢がある
今回紹介した部分は他のシステムでも実現可能だがRubyを普段から使っており慣れているならジョブ管理としてKuroko2はオススメです
メンテナンスや拡張して独自タスクをかくときもRubyでかけるしなにより手の込んだセットアップやプラグインの追加の必要なくシンプルにジョブ管理をはじめられるのが最高です
今後も使っていこうと思います!