Введение и отмазка
Доброго времени утра,
Возможно, всё о чём я сейчас буду рассказывать делается проще, правильнее, уже сделано, придумали ещё австралопитеки. Возможно это даже будет воспринято как издевательство над всем упомянутым, а вы зря потратите несколько минут своего драгоценного времени. Знайте — я предупреждал!
Если ещё не закрыли статью — обрисую ситуацию:
Что у нас есть
У нас есть 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 деревьях ничего особенного не наблюдаю. В принципе, интервалы и конфигурации тоже можно закешировать, что я наверное и сделаю, если возникнут тормоза.
Если за неделю ничего не отвалится — пробовать пропихнуть в официальную ветку, как считаете?