2014年5月15日木曜日

ruby-ldapでエントリを再帰的に削除する

※途中、試行錯誤の過程でボツにしたコードも載せてるので、結論だけ見たい方は途中の過程をすっ飛ばして下の方をご覧ください。

ruby-ldapを使ってrubyからLDAPの操作をしている時に子エントリを持つエントリを削除しようとするとエラーが発生し、"Operation not allowed on non-leaf” と言われます。

ruby-ldapの場合は特にエントリを再帰的に削除してくれるような便利なメソッドなんか用意されていません。ですので、先に全ての子エントリを削除するコードを自力で実装しないといけません。

最初に思いついたのは、エラーの発生を捕捉し、子エントリがあって処理に失敗した場合には各子エントリに対して再帰処理をかける方法です。

ということで最初に書いたコードがこちら。

# 指定DNを子も含めて再帰的に削除する
# ldap_connはLDAP接続を返すメソッドとして別途定義
def ldap_delete_r(dn)
  begin
    ldap_conn.delete(dn)
  rescue LDAP::ResultError
    if ldap_conn.err == 66 # "Operation not allowed on non-leaf"
      ldap_conn.search(dn,  LDAP::LDAP_SCOPE_ONELEVEL, '(objectclass=*)', ['dn']) do |entry|
        ldap_delete_r(entry.get_dn)
      end
    else
      raise
    end
  end
end

これで一応望み通りに動作しますが、ちょっとスマートではありません。
rubyに限らず一般的に例外処理のためのbegin〜rescue〜end節のような構文は処理が重いので、できれば例外捕捉をしなくて済む方法が望ましいです。
さらに、削除試行して失敗してから子エントリを検索していますが、そもそも子エントリを先に検索すればそ無駄に失敗する削除処理をしなくても済むはずです。

よって、削除処理の前に子エントリを検索しに行き、ヒットした各子エントリに対して再帰処理をかければよさそうです。子エントリがヒットしなければそのままエントリを削除します。

ということで修正したコードがこちら。

# 指定DNを子も含めて再帰的に削除する
# ldap_connはLDAP接続を返すメソッドとして別途定義
def ldap_delete_r(dn)
  ldap_conn.search(dn, LDAP::LDAP_SCOPE_ONELEVEL, '(objectclass=*)', ['dn']) do |entry|
    ldap_delete_r(entry.get_dn)
  end
  ldap_conn.delete(dn)
end

この方がスマートですね。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

0 件のコメント:

コメントを投稿