経緯
オンプレ側のActiveDirectoryデータとクラウド側のGoogleDirectoryデータを同期させる必要が最近あり、GoogeleAppsを契約しているベンダーから見積もりをもらったところ なんと予算の10倍以上 ... 正式な見積もりを貰う前に営業の方と相談してて、双方で大体このくらいあればいけるよねーなんて話したので正直この金額にはちょっとびっくり。
正式な見積もりをもらってなかったり、金額感の見込みが甘いってところはおっしゃる通りだけど、どっちにしてもこの金額では発注できない(仮に予算前に見積もりをもらってても)のでGolangでツールを自作してみた。
仕様
ベンダーに依頼した内容は「Google製のDirectorySync使ってもいいのでADに登録してある情報をAppsに送信して」というものだったが、どうせ自作するのであればADに登録するところも自作しようということで、
- 総務よりもらった人事データのCSVをパース
- Apps側の情報と比較
- 変更がある人を対象にしてAppsとADの両方を更新
という流れにしてみた。
Appsの更新はGolang用SDKを使い、ADの更新にはコマンドライン経由で dsmod
を利用する。
ちなみに、ハマりながらも特に問題なく作れた。見込みより開発時間が長くかかってしまったけど(こちらもまた見込みが甘い)...
Apps側の罠
Appsへのユーザー情報の登録は admin.User
型の情報を作って操作するだけなので、プログラミング自体はそれほど問題ではなかった。
まあ、 admin.User
の Emails
や Organizations
等には専用の型があるのに、なぜか取得したデータは interface{}
型になっているって言う点はあったけど。でもキャストしてあげれば特に問題はない。
だが、一旦登録した Emails
や Organizations
を削除しようとするとちょっと問題が発生する。
Emails
や Organization
の値は文字列型になっているのだが、そこに空文字を渡すとエラーが発生する。なので、値だけではなく配下のスライスを全てを削除してやれと考えて nil
を指定すると、今度は変更点なしと解釈されてデータの更新対象にはならなくなる。
うーんどうしようと思って手元のコードでいろいろ試してみたが、正解は Web上のTryItでnilを送り込むという方法 だった。ライブラリ経由だと簡単に操作できるが、一番確実なのはAPI直叩きだってことを痛感させられた。
AD側の罠
ADは exec.Command("dsmod", command[1:]...).CombineOutput()
で操作できる。 Output()
ではなく CombineOutput()
を使うことでエラーが発生したときの内容も一緒に取得できる。
Golangの exec
は優秀?で、オプションに渡す文字列は内部文字コード(UTF8)のままで問題ないし、 []command
にオプション文字列を個別に入れておけば "
で囲んでおく必要もない。戻り値までは自動的に内部文字コードにしてくれないので、 [chardet][] を利用したり Shift-JIS
決め打ちしたりして文字コード変換を行わなくてはいけないが、ここは仕方ないだろう。
で、ハマったのがオプション文字列に /
始まりの引数を指定すると、その引数を dsmod
がスイッチと解釈してオプションがずれてしまうという点。もしかしたら解釈してるのは dsmod
よりも下のレイヤーかもしれないけど。
所属部署を /営業本部/営業部/営業課
のように階層的に表したい僕としては、ちょっと致命的。"
で囲んでもダメだし、 \
でクオートしてみてもダメ。
うーんどうしようと思って /
を別の区切りにしようかと考えついたのだが、 /
を \
にするとWindowsみたいでかっこ悪いし、 /
を :
にすると昔のMacみたいで古臭い。
結局は 文字列の先頭にスペースを入れて対応 というなんともアナログな対処方法。まあどうせ見るときはWindowsのテキストボックの中だからスペース一つあっても気づかれないでしょ。ってことで。ちょっとイマイチだけどね。
まとめ
どちらも技術的なやり方では解決できず最後は別のやり方で対応したし、この文章の内容も罠という罠ではないし対処方といっても大したことをやってなので、全体をまとめても全てにおいて大したことはやってない。
技術的に正しいことをやろうとして悩むよりは、別のやり方の方が早い場合が多いのは経験上良く知っているはず。
今後は別のやり方も考えてそのやり方で対応できることを確認したうえで、まだ時間に余裕があれば正しいやり方を模索するっていうやり方を癖つけていきたい。
なにしろ僕達の時間は有限なんだから。