Pull to refresh

Mercurial hgwebdir через FCGI + несколько разных хранилищ

Reading time5 min
Views1.9K

Введение и отмазка


Доброго времени утра,

Возможно, всё о чём я сейчас буду рассказывать делается проще, правильнее, уже сделано, придумали ещё австралопитеки. Возможно это даже будет воспринято как издевательство над всем упомянутым, а вы зря потратите несколько минут своего драгоценного времени. Знайте — я предупреждал!

Если ещё не закрыли статью — обрисую ситуацию:

Что у нас есть


У нас есть nginx, mercurial несколько самостоятельных проектов, на каждый из которых имеется 3-4 репозитория. Ещё у нас иногда могут появляться сторонние разработчики, которым часть этих проектов показывать совершенно не обязательно.

Что со всем этим делать?


Для начала напомню (или расскажу, если кто не знает), что у Mercurial существует довольно много вариантов предоставления доступа к репозиториям.

Одним из самых правильных и удобных является hgwebdir, по ссылке описано множество методов подключения этого интрумента к различным веб-серверам, однако в нашем случае мы будем использовать nginx+fcgi.

Конфигурируем nginx


О самом nginx рассказывать не буду, приведу только пример рабочей конфигурации с https:
server { 
        listen <адрес>:443; 
        server_name hg1.whatever.com; 
         
        access_log  /var/log/nginx/hg1.access.log; 
        error_log   /var/log/nginx/hg2.error.log; 
 
        ssl                     on; 
        ssl_protocols           SSLv3 TLSv1; 
         
        ssl_certificate         /etc/nginx/ssl/hg/hgmaincert.pem; 
        ssl_certificate_key     /etc/nginx/ssl/hg/hgmaincert.key;  
 
        location / { 
            fastcgi_pass unix:/var/run/hgwebdir.fcgi.socket; 
            fastcgi_param       PATH_INFO       $fastcgi_script_name; 
            fastcgi_param       QUERY_STRING    $query_string; 
            fastcgi_param       REQUEST_METHOD  $request_method; 
            fastcgi_param       CONTENT_TYPE    $content_type; 
            fastcgi_param       CONTENT_LENGTH  $content_length; 
            fastcgi_param       SERVER_PROTOCOL $server_protocol; 
            fastcgi_param       SERVER_PORT     $server_port; 
            fastcgi_param       SERVER_NAME     $server_name; 
        }        
}


Конфигурируем fcgi


Основная задача — получить демона, который бы запускал наше fcgi приложение. Как получить этого демона — зависит от вашей ОС, если попросите — дополню статью описанием для Ubuntu (по сути для Linux вообще).
Сам fcgi гейт выглядит примерно так:
#!/usr/bin/python2.6 

from mercurial import demandimport; demandimport.enable()
from mercurial.hgweb.hgwebdir_mod import hgwebdir
from mercurial.hgweb.request import wsgiapplication
from flup.server.fcgi import WSGIServer

def make_web_app():
    return hgwebdir("path_to/hgweb.config")
                    
WSGIServer(wsgiapplication(make_web_app)).run()


Поехали!..


Ну а дальше запускаем nginx, fcgi, пишем конфиг hgweb.config, согласно документации, добавляем туда коллекции наших проектов, и радуемся жизни… или не очень радуемся.
Дело в том, что hgwebdir сваливает все проекты в одну кучу — разграничить права то мы можем, но список репозиториев всё равно будет виден всем и непередаваемо ужасен.

Допиливаем hgwebdir


Что можно сделать теперь? Создать несколько поддоменов, с разными именами, насоздовать несколько fcgi демонов, добавить правила или даже хосты в nginx… получится не слабый такой зоопарк.

Вот с этого места можно начинать кидать помидоры, но мне в голову пришла мысль — если hgwebdir не умеет работать с несколькими конфигами — надо его заставить. Для этого добавим в конфигурацию хоста в nginx нужные нам алиасы:

        server_name hg1.whatever.com; 
        server_name hg2.whatever.com; 
        server_name hg3.whatever.com; 


Если же потребуется авторизация — придётся использовать несколько директив server, и include, чтобы вынести общую часть. А когда в nginx можно будет использовать auth_basic внутри if — можно будет сделать и без инклюда.

Рядом с гейтом, создадим модуль hgtreewebdir.py:
from mercurial.hgweb.hgwebdir_mod import hgwebdir 
 
class hgtreewebdir(hgwebdir): 
         
    refreshinterval = 0  # = 0, хабр есть ноли!
     
    def __init__(self, conf, baseui=None, virtuals={}): 
        self.baseconf = conf 
        self.virtuals = virtuals 
        hgwebdir.__init__(self, conf, baseui) 
         
         
    def run_wsgi(self, req): 
        if self.virtuals != {}: 
            virtual = req.env.get("HTTP_HOST"""
            if virtual in self.virtuals: 
                self.conf = self.virtuals[virtual] 
                return hgwebdir.run_wsgi(self, req)  
        self.conf = self.baseconf 
        return hgwebdir.run_wsgi(self, req)


Код самого гейта изменим следующим образом:

#!/usr/bin/python2.6 

from mercurial import demandimport; demandimport.enable()
from hgtreewebdir_mod import hgtreewebdir
from mercurial.hgweb.request import wsgiapplication
from flup.server.fcgi import WSGIServer

def make_web_app():
    return hgtreewebdir("path_to_configs/mainhgweb.config",
               virtuals={
                   "hg2.whatever.com""path_to_configs/hg2hgweb.config",
                   "hg3.whatever.com""path_to_configs/hg3hgweb.config"
               })
WSGIServer(wsgiapplication(make_web_app)).run()


Минусы и заключение


В данном варианте, интервал обновления изменён с 20 до 0, это может привести к нагрузкам на сервер вцелом, но я пока на 3 деревьях ничего особенного не наблюдаю. В принципе, интервалы и конфигурации тоже можно закешировать, что я наверное и сделаю, если возникнут тормоза.

Если за неделю ничего не отвалится — пробовать пропихнуть в официальную ветку, как считаете?
Tags:
Hubs:
Total votes 8: ↑7 and ↓1+6
Comments5

Articles