gitbucketのActiveDirectory認証の設定例

gitbucket(takezoe/gitbucket · GitHub)

がお手軽にgithub cloneを構築できるのですごく良いです。

社内のActiveDirectoryと連携できれば便利なので、以下を参考に色々やってました。

https://github.com/takezoe/gitbucket/wiki/LDAP-Authentication-Settings

GitBucketのユーザ認証をActiveDirectoryと連携する - C Sharpens you up

が、上手く行きません。以下のように認証エラーが出ます。

[LDAP: error code 49 - 80090308: LdapErr: DSID-0C0903A9, comment: AcceptSecurityContext error, data 773, v1db1 ]

ActiveDirectoryの知識が全く無いので、色々な構成があるのかもしれませんが、

結局、以下のような設定で上手く行ったので設定例を共有しておきます。 似たような事例で困っている人がいたら参考にしてください。

私の環境での設定例

  • LDAP Host : (社内のActiveDorectoryホスト)
  • LDAP Port : 389
  • Bind DN : user@domain.local (FQDNでユーザーアカウントのみを設定。cn=等は不要)
  • Bind Password : 上記ユーザーのパスワード
  • Base DN : OU=hoge,DC=domain,DC=local(環境毎に異なる)
  • User name attribute : sAMAccountName
  • Full name attribute : displayName
  • Mail address attribute : mail

上記の設定で、社内ActiveDirectoryと連携し、アカウントのみでログイン可能となりました。 また、メールアドレス、フルネームも問題なく連携されました。

Rのインストール、RODBCでDBテーブルのDELTE,INSERTを行う。

Rはじめました。
統計解析やるぞーって段階ではなく、Rの実行環境を作ってる最中です。
データベースとの連携で色々面倒だったのでメモ。

Linux(Cent OS)への導入

(最新だとわかりませんが)CentOS 6.4には、yumにRはありませんのでEPEL導入します。
導入後もRのライブラリインストールでこけたりするので、どちらにしろEPELは入れたほうがいい。 sudo rpm -Uvh http://ftp-srv2.kddilabs.jp/Linux/distributions/fedora/epel/6/x86_64/epel-release-6-8.noarch.rpm
sudo yum install R
あと、必要ならR Studio Server入れます。 RStudio
R Studio ServerすごいよR Studio Server。

RODBC, XMLを使うならこれらのライブラリから参照されるヘッダファイルが必要なのでインストール
sudo yum install unixODBC unixODBC-devel libxml2-devel
今後も必要に応じて追加していく。

あとは、DB用意したり、ODBCドライバ用意したり、 /etc/odbc.ini を書いたりする。

RODBCの利用

Rを起動し、

    #パッケージインストール,初回のみ
    install.packages("RODBC")
    library(RODBC)
    # ODBC名を引数に渡す。ユーザー、パスワードが必要なら引数を追加。
    conn <-odbcConnect("myodbc")
    # テーブルの全データ取得
    data <- sqlFetch(conn, "Table")
    # 適当にデータ加工
    
    # テーブルにデータ反映。第三引数がないと、第二引数の変数名(この場合data)でテーブルをcreateする。
    sqlSave(conn, data , "Table2")

SQL書かなくてもDBへデータ反映できるのはすばらしい!
のだけど、このsqlSave() デフォルトの動作は指定されたテーブルをcreateする。
(既存テーブルがある場合は実行不可で、 実行前に sqlDrop(conn, "Table2") を実行する。)
Delete&Insertでどうにかできないものか。

エラー

sqlSave()の引数を見てみると、saferオプションがある。TRUEだとCleate, FALSEだとテーブルがなければcreate,あればDELETE&INSERTを行うとあるので、これで解決
sqlSave(conn, data, "Table", safer=FALSE)
と思いきや、こんなエラー

Query: INSERT INTO `Member` ( `ID`, `NAME`, `AGE`, `GENDER` ) VALUES ( ?,?,?,?,? )
Binding: 'ID' DataType 4, ColSize 10
Binding: 'NAME' DataType -9, ColSize 120
Binding: 'AGE' DataType 4, ColSize 10
Binding: 'GENDER' DataType -8, ColSize 1
Parameters:
no: 1: ID 1/***/no: 2: NAME test/***/no: 3: AGE 32/***/no: 4: GENDER 0/***/
 *** caught segfault ***
address 0x2028b3780, cause 'memory not mapped'

Traceback:
 1: .Call(C_RODBCUpdate, attr(channel, "handle_ptr"), as.character(query),     data, ds - 1L, params, as.integer(vflag))
 2: odbcUpdate(channel, query, mydata, coldata[m, ], test = test,     verbose = verbose, nastring = nastring)
 3: sqlwrite(channel, tablename, dat, verbose = verbose, fast = fast,     test = test, nastring = nastring)
 4: sqlSave(conn, data, "Member", verbose = TRUE, safer = FALSE)

SEGVやめて、、、。ちなみにWin版だとこんなログ。

 odbcUpdate(channel, query, mydata, coldata[m, ], test = test,  : 
  missing columns in 'data'

解決

何か、列数とパラメータ数あってないぞ。

    Query: INSERT INTO `Member` ( `ID`, `NAME`, `AGE`, `GENDER` ) VALUES ( ?,?,?,?,? )

というわけで、よく見てみると、通常のsqlSaveでテーブルcreateした場合、一番最初にrownamesという列が勝手に追加されている。
設定されているのはデータフレームの行番号みたいで、これはデータフレームをcsvとかに出力した場合でも付与されるので、よくある話なのかな?
というわけで、解決方法は以下の通り。

sqlSave(conn, data, "Table", safer=FALSE, rownames=FALSE) 引数 rownames=FALSE を追加すれば,rownames列は設定されず、データフレーム内のデータのみでINSERTを行ってくれる。

ちなみに、ODBCドライバのせいかはよくわからないが、テーブル名やカラム名の大文字、小文字の違いよってもエラーが出たりするので、解決しない場合はDB側にも調査が必要。

SIerから転職します

9月末をもって現職のSIerから転職する事になりました。
転職先は今流行りのWeb系ではなく、ITコンサルとかSIとかをやる会社で、10月より働き始めます。
僕には華々しい実績があるわけではありませんが、 現職のこと、転職のことなんかを簡単にまとめ、誰かの参考になったら幸いだし、 数年後自分でこのエントリを見て気持ちの変化が無いかを確認してみたいと思う。

おおざっぱにまとめると

転職の理由を一言で言えば、"俺10年くらい仕事でJavaしかやってないけど、このままだと10年後もJavaやってんじゃないの?" という思いに尽きる。
(Javaをdisるわけではなく、それしか選択肢が無いという状況をどうにかしたい)
別に仕事があるならそれでいいじゃんという人もいると思うが、個人的にはエンジニアとしてこれからも生きていくならもっと面白いと思うことをやって行きたいと思った次第。

あんた誰?

都内の某中堅独立系SIerに9年ほど勤務したことになった。
金融、流通、通信等に主な顧客を持ち、客先常駐にてSIまたは運用を行うよくあるSIerだと思う。 社名をgoogle先生に尋ねれば、ブラックが関連検索に出てくるけど、別にブラックだと思った事はない。上には上が、下には下がいるだけのことで、仕事を仕事と割り切れば普通に働けるいい会社だと思う。
私自身は金融部門のSEとして、信販とか銀行だとかを相手にSEとして仕事をやっていた。 プログラム、設計、テスト、お客様との仕様に関する打ち合わせなど一通りの経験は積ませてもらい、 一応リーダーなんかもやっている。
割と環境に恵まれた感はあり、色々と責任ある仕事は任せてもらえたし、毎日終電なんて言う事はほとんどなかった。
ただし、金融のシステムは規模が大きく、複数のITベンダー入り交じりで2,3年かけて開発を行う事がザラである。 また技術も主体的に選ぶ事ができなくて、大体は頭にNとかIとかHとかがつく会社がサーバー、言語、フレームワーク、ミドルウェアを決めてしまっていることがほとんどだ。
そこから仕様を決めて開発をやっていくのも面白かったんだけど、

  • ちゃんとユニットテスト作ってJenkinsでCI回して楽しようよ
  • RedmineとかTrac導入してエクセルで課題管理やめようよ
  • エクセル、ワード以外にもっといい設計書のフォーマットってあるんじゃないの?
  • RubyとかScalaとかやろうよ

みたいな、技術策定、プロセス改善みたいなことって今の委託の立場だとできないなーとここ数年くすぶっていたし、暇がある時に興味があることについて調べたり勉強会行ってみたり、自宅でコード書いたりするようになった。

転職について

というわけで、上記のくすぶりが転職する理由となった。
(現職に思う所が全く無かったわけでないけれども) 転職先の候補としては、エンジニアとして経験を積めることが第一で

  • 技術志向で主体的にSI,IT導入ができるSIer,コンサル
  • 内製でITサービスを提供している事業会社

に絞った。プレゼン作成とかベンダコントロールに明け暮れるような仕事はしたくなかった。どんなポジションになったとしてもコード書いたり、設計したりと手を動かす余地は残していたかったから。
前者、後者とも複数の企業に応募し、前者に属する、とある企業から内定を頂き社員の方に刺激を受けた事もあり、良い経験ができると思い、転職することになった。
後者に属する企業にも興味はあったし内定を頂いた会社もあったのが、その企業が提供しているサービスや事業領域に強い興味と知識が無いと、結局の所サービスの改善とかに結びつくようなものを作れないんじゃないかと思い、今は腕を磨きつつ、これは面白いと思える物が見つかったときにあらためて考えてみようと判断した。(あと単純に、金融系の経験だとスキルマッチしにくいという点もあったんだけど)

転職活動

リクナビ、転職エージェント、greenなんかは一通りやった。 勉強したせいかのアウトプットのため、ブログ作ったりgithubでアプリ公開とかをやったりした。
転職の決め手となったのはCodeIQで、ウチ来ない問題に応募した所、転職先の企業からオファーをもらった。
自分の書いたコードを見てもらっているので、企業側は履歴書から判断できない実スキルを知る事ができるし、応募者側も自分の力量を認めてもらえた感があるので双方前向きな気持ちで選考できたんじゃないかと思う。
というわけで、CodeIqに参加している会社で、興味のある会社がにあるんだったらじゃんじゃんコード書いて応募すればいいと思うし、企業さん側もCodeIQに参加してみてはと思う。

まとめ

僕が就職した10年前ってこれからはJavaの時代、しかもJ2EEはすごいぜみたいな感じだったと記憶しています。 それが現在では、Java自体もSpringからEODみたいな考え方が生まれて開発しやい方向に進化したし、RoRみたいなLL言語フルスタックフレームワークが台頭したし、WebはAJAXから始まるUI周りの進化が著しいし、iPhone,Andoroidの誕生、基盤系ではクラウドが当たり前みたいな感じで、この10年間だけでも本当に色々なことがあったなと思うし、これらについて今の職場で触れる機会があんまりないことに惜しいなと思っていた。(金融系の基幹業務は、こういう流行が一番最後に来る場所だと思っている)
今のIT界隈は、オープンな技術要素やクラウド基盤を組み合わせる事で、アイデアを素早く実現したり、今まで色々な制約があってできなかった事ができてしまったりと、色々と面白い仕事ができそうなんじゃないかと個人的に思っている。
別に転職先が自分の夢が全て叶う場所だとは思っていないけど、今より自分のやりたい事ができるのは確実だと思うので、期待と不安を混じらせつつ次の一歩を踏み出します。

ConcurrentHashMapを使うならatomicなメソッドを使おう

ConcurrentHashMapを使うときの注意点

タイトルの通りです。

ConcurrentHashMapは同期を取りつつ、パフォーマンスも優れたとても優秀なやつで、最近Webアプリケーションで、キャッシュみたいなものを作るときに使いました。

とはいえ同期を取るとはいっても以下のようなキーの存在を確認して、putするような複合アクションの呼び出し(いわゆるcheck-then-act)では同期されません。(別にこれは、従来のHahMapとかCollections.syncronizedMapとかでも同じです)

  // atomicではない操作。
    if(!map.containsKey(key)) {
        map.put(key, value);
    }

以下が実証コードで、実行すると高い確率で複数スレッドで同一キーへのputを行います。
(今回のケースだとあまり問題にならないですが、valueを更新するような操作だと更新内容が喪失する可能性はあります。
また同期化されない処理は後々厄介なバグを生んだりするそうです。参考資料より。)

Atomicな操作

で、こんな時のためにConcurrentHashMapには、キーがなければ値を追加するという上記のような操作を行うputIfAbsentメソッドがあります。

  // 上とほぼ同等な内容だが、atomicな操作。
    map.putIfAbsent(key, value)

atomicなメソッドはほかに、replace, removeなんかがあります。 というわけで、もし既存のソースでMapをConcurrentHashMapに置き換える時は、上記のようは複合アクションを行っていないかも確認した方が良いという話でした。

参考資料

Java並行処理プログラミング ―その「基盤」と「最新API」を究める―

Java並行処理プログラミング ―その「基盤」と「最新API」を究める―

play2.1で個人的なものを作った

play framework 2.1で個人的な課題を解消するためのサービスを作ってみた。
github https://github.com/kencharos/yakimashi/
herokuでのサンプル http://yakimashi.herokuapp.com/

動機

家族が増えて以来写真を撮ることが多くなり、写真は自分のMacbookiPhotoで管理しているんだけど、
家族が写真を見たりするときに面倒。
またプリントしてアルバムに残したり、親戚に送ったりするので、写真の一覧を紙に印刷して、家族でこの写真は誰々に何枚みたいな作業を数か月に1回くらいやっている。
写真の一覧だと細部がわかりにくかったりするし、集計がすげえ面倒。
というわけでこれらを解消するためのものを勉強がてら作ろうというのが動機。

要望

  • 家族各自のPC,iPadから見れる。
  • 写真の一覧、詳細を確認できる。
  • 写真ごとに送る人の設定とかができる。
  • 基本的に家族でしか使わないからユーザー管理とかしない。

構成要素

勉強のため自分の仕事であんまり触ってないものを中心にやってみた。

  • play framework2.1 + scala
  • mongoDB (playとの接続はplay-salatプラグインが超便利)
  • metadata extractor (JPGのEXIF取得javaライブラリ)
  • jquery + colorbox
  • LESS
  • css3
  • github
  • heroku

メモ、忘備録

作っていてはまったことやこれはすげえと思ったことなど。

  • 雑感として,playだとコード量がとても少ない(多分javascriptの方が多い。)。とはいえ学習コストは他のフレームワーク同様高いと感じた。
  • 色々な方式をscalaの文法や関数でなるべく対処しようとしているんだと思うんだけど、おまじないとしか思えない記述が多すぎて色々戸惑う。(下のformの宣言とか、formの検証とか最初はよくわからなかった)
  • playでformとcaseクラス、JSONとcaseクラスの変換を宣言的に記述できて面白い。

また、上記で特定の項目だけcaseクラスに設定したくないとか単純にマッピングできない場合にも対応できていて○

  • play、サーバー起動中の修正が再起動なしで反映されて楽。
  • ただし、コンパイルが微妙に遅く、viewとかrouteもコンパイルされるので、画面をちょっと直して5,6秒待つみたいなケースがある。
  • view templateは@に続く箇所にscalaコードを記述できるので色々できるんだけど慣れるまで微妙。
  • viewで使用するデータは、viewで宣言した引数のみで、JSPみたいな暗黙なリクエストとかセッションみたいなものは(宣言しない限り)出てこない。

viewの描画が関数の呼び出しになっているので、viewで色々できる危険性が減っている、、のかな。

  • Actionを合成することで、Action前後のログ出力とか、ログイン判定とかができる。
  • mongoDBが便利すぎて笑える。1対多のデータをそのままコレクションに突っ込めるとか。
  • play-salatも超便利。case classのコンパニオンに特定のクラスを継承するだけで、CRUD諸々の機能が追加される。
  • heroku でmongoHQを使う場合、herokuの環境変数(heroku configで確認)に、MONGOHQ_URLというmonngoDBのurlが設定されるのでこの値を設定する。設定するには、Procfileを作成し以下の形式でconf/application.confのプロパティを上書きする。
  • -Dmongodb.default.uri="$MONGOHQ_URL"

playコマンドがヒープ不足で失敗する時

ちょっと興味があって[www.playframework.com/:title=Playframework]を触っています。
自宅のmacと会社のWindowsPCにそれぞれPlay2.1の環境を作って共有しているんだけど、
WindowsPCでPlayプロジェクトでplayコマンドをうつと、以下のようにコンソールにで起動に失敗する。

Error occurred during initialization of VM
Could not reserve enough space for object heap
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.

PCのスペックはWin7 32bit メモリ2G
ヒープ領域が確保できないようなので、playのスクリプトを見てみると、
/framework/build.bat
が本体のようでこのファイルの中に、

java -Xms512M -Xmx1024M -Xss1M -XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=256M %DEBUG_PARAM% %JAVA_OPTS% -Dfile.encoding=UTF-8 -Dplay.version="%PLAY_VERSION%" -Dsbt.ivy.home="%~dp0..\repository" -Dplay.home="%~dp0." -Dsbt.boot.properties="%fp%sbt/sbt.boot.properties" -jar "%~dp0sbt\sbt-launch.jar" %*

とあるのでここを編集する。
Xms,Xmx,Xss,MaxPermSize全てのオプションを削除しても起動したのだけど、Xmxのでフォルトは64Mで心もとないので、Xmxを768Mに修正して無事起動した。
色々試した所、上記のPCのスペックだと、ヒープ領域とパーマネント領域の合計が1150Mを超えると失敗するようだった。
というかデフォルトでXmxが1Gは随分と富豪だなと感じる。

google driveのOCRを試すWebアプリを作ってみた

Ruby 認定資格Gold合格したので、何か作ろうかなと考えていた所、
Google DriveのOCRって使い物になるのかなと思い、
ファイルをアップロードしたらGoogle Driveに登録して、OCRのテキストを取得するような物を作ってみた。

Trying Google Drive OCR
利用するにあたって、GoogleのアカウントとDriveの利用、OAuth認証が必要です。
また、ここでアップロードされたファイルは、Driveに保存されます。

イメージはこちら

見て分かる通り、Driveに元画像とOCRの解析結果テキストが一つになった文書が作成されます。
テキストだけの取得は、色々調べたけどどうしてもページ内に埋め込めず断念。
というか、 OCRの精度は低い。あと日本語もまだ対応してないっぽい。


以下は作成時のメモ

Google Drive SDKのドキュメントはこちらにある。
Google Drive SDK — Google Developers
SDKAPIがあって、SDKChrome Web Storeに色々登録しろとか書いてあるけど、今回みたいなDriveへのファイルの登録とか取得だけだったらAPIだけでいい。SDKはDriveのUIに作成したアプリのメニューを追加したり連携したりする場合に使う。


APIを使う場合は、Google API ConsoleGoogle Accounts から、Drive APIを有効にし、Client IDとsecretを発行する。

今回作ったソースは https://github.com/kencharos/google-drive-oc-ruby に。
初めてGitをまともに使ったので、色々と変な事している気がする。
個人で実行する場合は上記のClient IDとsecretを、crient_secret.jsonに記載する。


アプリケーションは、heroku上で、sinatra,datamapper,haml などで作りました。
sinatraとてもいいです。


なお、herokuではファイルアップロードが一切できないと勘違い*1しており、最初はブラウザ側でFile APIを使用してbase64エンコードしてサーバーに送り、サーバー側でエンコードするような処理をしてた。
ファイル選択時にプレビュー出るのはその名残。


今回、初めてgit,github,ruby,herokuを使ってみました。
職場の、java, 占有ロックが基本の某バージョン管理ツール、起動するまで5分かかるサーバーという環境に比べると
色々と快適すぎて涙が出ます。


今後は、Rspec, Scala、html5の各API、ましなUI などもやってみる。


作成にあたり、以下のページを参考にさせていただきました。ありがとうございます。
Heroku上でSinatraアプリを動かすまでのまとめ - まちゅダイアリー(2011-10-02)
HerokuアプリをGitHubにもプッシュする - アインシュタインの電話番号
HerokuとGitHubの両方にプッシュする時の秘密にしたい値の扱い - アインシュタインの電話番号

*1:ファイルを書き込める領域が無いだけで、tmpfileは使える