2012/11/05

【解決】GitLabでGit HTTPが使えない問題 (※サブディレクトリ環境)

昨日に引き続き、GitLabの話です。
GitLab 2.7から"Git HTTP"(Git Smart-HTTP)が実装されていたのですが、

いつもはSSH経由で利用しているため、これまでは使っていませんでした。
(※ Git HTTP = HTTP経由でGitLabを通してリポジトリにアクセスする機能)

さて...今日はこのGit HTTP機能をいざ使ってみようと...

GitLab3.0の画面。[SSH]ボタンと並んだ [HTTPS]ボタンをクリックすると
Git HTTPによるURLが表示される。
(URLは、プロジェクトの通常のURLに".git"を付加したものとなる)
表示されたURLをブラウザから開いてみる...と...
回やっても認証画面がwww

正しいメールアドレス+パスワードを入力しているのに
401エラーが出るという・・・(汗;)w

ところで。GitLabでは、サブディレクトリ下での運用を本来サポートしていません。
ですので、私はリバースプロキシ(nginx)を通して少々無理やり運用しています。
(それについては、記事:Gitlabの導入 (Unicorn+nginxでサブディレクトリへ配置)を参照)

今回は恐らく、そのための問題なのだろう...と仮定して調べてみました。
(他の可能性としては、gitlab.ymlの設定ミスもありますが、今回は問題ありませんでした。)

→ 結果...その通り!やはりサブディレクトリ下で運用していることが問題なようですorz

とりあえず...手探りで試行錯誤してみましたので、
対策方法を以下に残しておきます。

[注意] GitLabのサブディレクトリでの運用が本来サポート外であるうえに、
私はいまのところ Ruby/Unicornに全く詳しくありませんww
そのため保障はできませんが、参考にまで。
...もっと良い方法があればアドバイスお願いします m(_ _)m )





/gitlab/lib/gitlab/backend/grack_auth.rb : 17行目付近〜

@env['PATH_INFO'] = @request.path
@env['SCRIPT_NAME'] = ""

# Find project by PATH_INFO from env
#if m = /^\/([\w-]+).git/.match(@request.path_info).to_a #コメントアウト
if m = /^(\/([\w-]+))*?\.git/.match(@request.path_info).to_a
    self.project = Project.find_by_path(m.last)
    if m2 = /\/([\w-]+*?.git\/.*)/.match(@request.path).to_a
        @env['PATH_INFO'] = "/#{m2.last}"
    end
    return false unless project
end

変更点としてはこれくらいです。



以下に、何を行ったかの解説&メモを書いておきます。

まずGitLabでは、Grackというモジュールを用いることで
このGit HTTPを実現しているようです。
GitLabのルーター(/gitlab/config/routes.rb)はユーザからアクセスを受けると、
Git HTTPのためのアクセスをここで受け取ります。

Grackの認証(Basic認証)には、GitLab上のアカウント情報が用いられます。
実際にその処理を行なっているのは/gitlab/backend/grack_auth.rb ですね。


上のgrack_auth.rbでコメントアウトした行とその次行の
# if m = /^\/([\w-]+).git/.match(@request.path_info).to_a
    self.project = Project.find_by_path(m.last)
はリクエストされたパス(@request.path_info)からプロジェクト名を抜き出しています。
本来、パスが"/hoge.git/aaaa"だとしたら、
hogeという部分が正規表現で抜き出され、self.projectに代入されるわけです。

ただ当然これでは、パスがサブディレクトリを含んでいると正しく抜き出せないですね。

ですので...コメントアウトした行の代わりにこのように追加しました:
if m = /^(\/([\w-]+))*?\.git/.match(@request.path_info).to_a

これにより、サブディレクトリであっても正しくプロジェクト名が抜き出せます。

さて...この修正だけで、事態(?)には光が見えてきます(笑)w
プロジェクト名が正しく抜き出せなかったために、
プロジェクトを探せず、401エラーになっていたようです。

これでとりあえず、401エラーが改善し、認証は正常に通るようになります。

が...。

ここでまだ、git cloneしてもうまく行かないはず・・・。

Grackの認証が済むと...
プロジェクト名やパスを環境変数(@env)で渡して次の処理を
/gitlab/vendor/bundle/ruby/*.*.*/bundler/gems/grack-*/lib/grack/*.rb
が行うわけですが・・・。

ここでリポジトリ上のファイルを読み込む時・・・
サブディレクトリのせいでパスを正常に扱えず、ファイルが見つからないのですw
なのでエラーとなります。

この対策のために、前のステップでパスを直しておくことにしました。
先ほどとおなじくgrack_auth.rbでやってしまいましょうw

以上の理由から、先ほどの行の後に2行追加しました:

        if m2 = /\/([\w-]+*?.git\/.*)/.match(@request.path).to_a
                @env['PATH_INFO'] = "/#{m2.last}"

正規表現マッチもあれな書き方ですが、未だ詳しくないので許してください(><;)

これににより、環境変数に入れるパスからサブディレクトリ部分が削られます。
つまり、本来、GitLabが意図しているパスになるわけです(>ω<)♪

これで一応、解決です。

試しに...クライアントから
$ git clone https://example.com/git/hoge.git
を実行してみてください。正しくcloneできるはずです。

今回は以上となります。

今回もこのヒントを得るためにGitHubやコミュニティを参考にさせていただきました。
ありがとうございました m(_ _)m♪


p.s.

そもそもサブディレクトリじゃなくルートでGitLabを運用したらいいのに...
と思われる方もいらっしゃるかもしれません・・・。

私は学生個人でサーバを運用しています。
そしてこういったものに、HTTPSは必須だと考えております。
ところで、ルートディでGitLabを運用するには、当然、サブドメインなり別サーバ/IPアドレスなりの方法を取らなければなりませんが、
それをするとなると、サーバ証明書もGitLab用に別途用意することになります・・・。
サブドメインでも使える証明書は高価ですし・・・。
そこまでの余裕は無いのです(´・ω・`)...。

尚、GitLabはサブディレクトリへの対応を実装することは今のところないそうです。


0 件のコメント:

コメントを投稿

お気軽にコメントをお寄せください m(_ _)m♪
"コメントの記入者"欄から[名前/URL]を選ぶと、登録なしでコメント投稿していただけます。