dovecotの認証にmysqlを使った時、ログインのクエリを1つにする

メールサーバ立てるぞ。

環境

dovecot --version 2.2.18

dovecotというimapサーバの認証にmysqlを使う場合、そのままだとpasswordとユーザ名を取得するクエリを別々で投げるんだけど、設定すれば1クエリで押さまるらしい。
http://www.dovecot.jp/doc/dovecot-sql-example.conf, http://www.dovecot.jp/wiki/UserDatabase.Prefetch.txt にある翻訳されてる情報は1系だけどは2系とほとんど同じみたい。

http://wiki2.dovecot.org/UserDatabase/Prefetch を見て

/etc/dovecot/conf.d/auth-sql.conf.ext

userdb {
  driver = sql
  args = /etc/dovecot/dovecot-sql.conf.ext
}

をアンコメントして,
password_query のgid, home, uidというcolun_nameにuserfhdb_というプレフィックスをつけておしまし。

before

SELECT name as user, domain, password, CONCAT("/home/virtual/", dir) as home, '5000' as uid, '5000' as gid FROM anonymous_mailboxes WHERE name = 'koji' AND domain = 'hoge.com'
SELECT CONCAT("/home/virtual/", dir) as home, '5000' as uid, '5000' as gid FROM anonymous_mailboxes WHERE name = 'koji' AND domain = 'hoge.com'

after

SELECT name as user, domain, password, CONCAT("/home/virtual/", dir) as userdb_home, '5000' as userdb_uid, '5000' as userdb_gid FROM anonymous_mailboxes WHERE name = 'koji' AND domain = 'hoge.com'

になりました。

次はクォーターあたりやります。

imapログインした時にメールのルートディレクトリはどこを見ているか

maildirに配送したというログがあるのに、telnetからimapログインしたけど受け取っているはずのメールがなかった。
調べた結果、imapログインした時に見ているメールのルートディレクトリが別のところみてた。(x select inboxするとmaildir一式作成するんだね...)

環境

imapログインした時に見ているメールのルートディレクトリは、/etc/dovecot/dovecot-sql.conf.ext の usedb に書いている homeカラムかと思ったら
/etc/dovecot/conf.d/10-mail.conf にある mail_location を見ていたのでした。

なのでpostfixが配送しているディレクトリがdovcotからルートディレクトリになるようmail_locationを変更します。

mail_location = maildir:/home/virtual/%d/%n

(userdbではuidとgidだけ返せばいいってことっぽい。)

ちなみに/etc/postfix/vmailbox.mysql

query = select CONCAT(domain, '/', name, '/') from anonymous_mailboxes where name = '%u' AND domain = '%d'

公式ドキュメントを眺めた

http://wiki2.dovecot.org/VirtualUsers/Home
homeカラムではなくてmailカラムにルートディレクトリのパスを返していればmail_locationを上書きしてくれるっぽい。
とりあえず、今の環境では特異なディレクトリ名になることはないのでmail_locationに直書きでいいや。

# userdb query to retrieve the user information. It can return fields:
#   uid - System UID (overrides mail_uid setting)
#   gid - System GID (overrides mail_gid setting)
#   home - Home directory
#   mail - Mail location (overrides mail_location setting)

postgresqlと複合indexとiowait

rails4.2.0

muninを見ているとぺろぺろあんてなのサーバでiowaitが徐々に増えていることに気がついてスロークエリを探しました。
最近https://twitter.com/prprantena に1時間起きで取り込んだ記事を垂れ流すようにしたのでそのネットワークioかと思ったんですが、日々増えているのでDBあたりかなと思って、スロークエリをログに書き出す設定を有効にしてログ見てました。

# /etc/postgresql/9.4/main/postgresql.conf
log_min_duration_statement = 500

遅いクエリでてきました。

SELECT "word_tags"."name" FROM "word_tags" INNER JOIN "word_taggings" ON "word_tags"."id" = "word_taggings"."word_tag_id" WHERE "word_taggings"."post_id" = $1  [["post_id", 245009]]

explainするとpost_id の検索でindexが使われていないことが発覚。

2.1.1 :004 > Post.first.word_tags.explain
 => EXPLAIN for: SELECT "word_tags".* FROM "word_tags" INNER JOIN "word_taggings" ON "word_tags"."id" = "word_taggings"."word_tag_id" WHERE "word_taggings"."post_id" = $1 [["post_id", 243762]]
                                      QUERY PLAN
---------------------------------------------------------------------------------------
 Nested Loop  (cost=0.29..33102.66 rows=51 width=19)
   ->  Seq Scan on word_taggings  (cost=0.00..32710.34 rows=51 width=4)
         Filter: (post_id = 243762)
   ->  Index Scan using word_tags_pkey on word_tags  (cost=0.29..7.68 rows=1 width=19)
         Index Cond: (id = word_taggings.word_tag_id)
(5 rows)

db/schema.rb を見るとindexを貼った痕跡ある。

  add_index "word_taggings", ["post_id"], name: "index_word_taggings_on_post_id", using: :btree
  add_index "word_taggings", ["word_tag_id", "post_id"], name: "index_word_taggings_on_word_tag_id_and_post_id", using: :btree
  add_index "word_taggings", ["word_tag_id"], name: "index_word_taggings_on_word_tag_id", using: :btree

psql からindexが貼られているかの確認すると、post_id と word_tag_id にindexがなかった( ;´Д`)

antena_development=# \d index_word_taggings_on_post_id
Did not find any relation named "index_word_taggings_on_post_id".

複合index使っていないっぽいので削除して、改めて単一indexをつけました。

class RemoveIndexWordTaggingsOnWordTagIdAndPostId < ActiveRecord::Migration
  def up
    remove_index :word_taggings, name: :index_word_taggings_on_word_tag_id_and_post_id # 複合

    add_index "word_taggings", ["post_id"], name: "index_word_taggings_on_post_id", using: :btree
    add_index "word_taggings", ["word_tag_id"], name: "index_word_taggings_on_word_tag_id", using: :btree
  end

  def down
    add_index "word_taggings", ["word_tag_id", "post_id"], name: "index_word_taggings_on_word_tag_id_and_post_id"

    remove_index :word_taggings, name: :index_word_taggings_on_post_id
    remove_index :word_taggings, name: :index_word_taggings_on_word_tag_id
  end
end

これでiowait減りそうです。

 => EXPLAIN for: SELECT "word_tags".* FROM "word_tags" INNER JOIN "word_taggings" ON "word_tags"."id" = "word_taggings"."word_tag_id" WHERE "word_taggings"."post_id" = $1 [["post_id", 243762]]
                                                 QUERY PLAN
------------------------------------------------------------------------------------------------------------
 Nested Loop  (cost=0.72..455.48 rows=51 width=19)
   ->  Index Scan using index_word_taggings_on_post_id on word_taggings  (cost=0.43..63.16 rows=51 width=4)
         Index Cond: (post_id = 243762)
   ->  Index Scan using word_tags_pkey on word_tags  (cost=0.29..7.68 rows=1 width=19)
         Index Cond: (id = word_taggings.word_tag_id)
(5 rows)


複合indexをつけると包括しているキーにはindex貼らない仕様?そもそも複合indexは不要?add_indexのmigrationで単一はindexが貼られなかった?かは不明。
とりあえずpostgresqlよくわからん( ;´Д`)

virtual_alias_maps と virtual_mailbox_maps

postfix で virtual_alias_maps で @example.jp があると、virtual_mailbox_maps に foo@example.jp があっても先に @example.jp に引っかかってしまい foo@example.jp の mailbox に辿り着かなくて悩んだ件。

まんまこれ。
http://www.kawaz.jp/pukiwiki/?Postfix%2Fvirtual_alias_maps%A4%C7%A5%DE%A5%C3%A5%C1%A4%B9%A4%EB%A4%C8virtual_mailbox_maps%A4%CF%BB%B2%BE%C8%A4%B5%A4%EC%A4%CA%A4%A4%E6%AB

以下の設定だと、 hoge1234@prpr-antena.com へメール送るとlocalがmail_userに配送(.forwardが発火)するだけで`prpr-antena.com/hoge1234/`にあるmaildirには配送してくれない。
メール受信した時に何か処理を実行したいってことなんだけど、今の状況だと肝心のメールが受信できていない状況。

# /etc/postdix/main.cf
virtual_mailbox_maps = hash:/etc/postfix/vmailbox
virtual_alias_maps = hash:/etc/postfix/virtual
mydestination = localhost
# /etc/postfix/virtual
hoge1234@prpr-antena.com mail_user@localhost
# /etc/postfix/vmailbox
hoge1234@prpr-antena.com prpr-antena.com/hoge1234/


virtual_alias_maps でマッチする(不適切な表現っぽい)ものがあると、virtual_mailbox_maps は参照しないらしいので、↑のようなことになっているとのこと。


どうやらvirtual_alias_maps にキーと同じ値を入れておけば、ループしないよう(?)に virtual_mailbox_maps を参照してくれるらしい。

# /etc/postfix/virtual
hoge1234@prpr-antena.com mail_user@localhost, hoge1234@prpr-antena.com

できました。

rails generatorを自作

いつも同じことしているので作ってみた。
https://github.com/jiikko/admin_generator
generatorのシンタックスがシンプルなので量産できそう。

$ bundle exec rails g admin_generator:admin install
     gemfile  sorcery
       exist  app/controllers
      create  app/controllers/admin/base_controller.rb
      create  app/controllers/admin/home_controller.rb
      create  app/controllers/admin/sessios_controller.rb
       exist  app/views
      create  app/views/admin/home/index.html.slim
      create  app/views/admin/sessions/new.html.erb
    generate  sorcery:install
      create  config/initializers/sorcery.rb
    generate  model User --skip-migration
      invoke  active_record
      create    app/models/user.rb
      invoke    test_unit
      create      test/models/user_test.rb
      create      test/fixtures/users.yml
      insert  app/models/user.rb  
      insert  app/models/user.rb
      create  db/migrate/20150710150000_sorcery_core.rb
    generate  sorcery:install
        gsub  config/initializers/sorcery.rb
      insert  app/models/user.rb
      create  db/migrate/20150710150002_sorcery_activity_logging.rb
      create  db/migrate/20150710150003_sorcery_brute_force_protection.rb
       route  namespace :admin do
    root 'home#index'
  end

毎回作っているローカル用のunicorn.conf.rbとかのgenerator作れば楽できそうと思った。とても眠い。

routeのネストってできないのかな。

参考: http://guides.rubyonrails.org/generators.html

バーチャルドメインで受け取ったメールをコマンドに渡す

歌丸です。

$ postconf | grep versio
mail_version = 2.11.3
# /etc/postfix/virtual
root@jiikko.com deployer@localhost
root@prpr-antena.com deployer@localhost
# /etc/postfix/main.cf
virtual_mailbox_domains = prpr-antena.com, jiikko.com
virtual_mailbox_base = /home/virtual
virtual_mailbox_maps = hash:/etc/postfix/vmailbox
virtual_minimum_uid = 5000
virtual_uid_maps = static:5000
virtual_gid_maps = static:5000
virtual_alias_maps = hash:/etc/postfix/virtual

mydestination = localhost
# /etc/aliases
deployer: "| mail hoge@icloud.com"

ミソはmydestinationにlocalhostを指定するところ。
mydestinationを指定すると外に配送しないでローカルに配送してくれる。

なんでlocalhostを指定しているかというと。
/etc/postfix/virtualで

root@prpr-antena.com deployer

と書くと

root@prpr-antena.com deployer@prpr-antena.com 

と解釈されているらしくunknown userになった。なのでlocalhostを指定してる。

命名めんどくない?

https://github.com/zdennis/activerecord-import/blob/master/lib/activerecord-import/import.rb
https://github.com/zdennis/activerecord-import/blob/master/lib/activerecord-import/active_record/adapters/mysql2_adapter.rb

./lib/activerecord-import/import.rb に ActiveRecord::Import::Import というクラスを定義してなかったり、ネームスペースとディレクトリ階層を合わせていないっぽい。
autoloadに頼っていないとしてもクラス名とファイルは同じにしたほうがよくない?
たまにファイル探すのめんどくない?
ディレクトリ名とネームスペースを別々で命名するのめんどくない?