По выше упомянутой связке много чего написано, однако, я вечно чувствовал некие неудобства при заведении нового репозитория: необходимо было завести новый локейшн в конфигурационном файле, создать репозиторий с помощью svnadmin, перезапустить apache. Когда такую работу приходиться выполнять раз в месяц — это терпимо, однако, когда такую работу приходиться выполнять по несколько раз в неделю, стоит задуматься об автоматизации этого процесса. Собственно об этом речь и идёт под катом.
Забегая вперёд, хочу начать именно с конфигурации самого apache.
Главный конфигурационный файл /etc/httpd/conf/httpd.conf
Собственно тут всё ясно (это дефолтное расположение конфигов при установке apache из стандартных репозиториев CentOS 5.6)
Файл /etc/httpd/conf.d/subversion.conf
В этом конфигурационном файле описывается собственно конфигурация репозитория. Тут стоит отметить что мы выносим все локейшены в конфигурационные файлы в директорию conf.d/subversion.d. Зачем это надо? Во-первых нам проще отслеживать какие репозиотории включены, во-вторых мы избавляемся от парсинга конфига при запуске скрипта (об этом ниже).
Файл /etc/httpd/conf.d/subversion.d/example_repo.conf
Тут мы указываем имя и местоположение репозитория, указываем с помощью какой учётной записи мы будет просматривать каталог AD (да в данном случае используется AD), пароль от этой учётной записи, строку и фильтр для поиска. Далее с помощью директории мы указываем, что просмотр репозитория позволен всем пользователям авторизованным в домене (однако можно указать конкретную группу в домене). Далее следующей директорией мы указываем какой группе пользователей в домене (в данном случае это example_group) разрешается производить все остальные действия с репозиторием.
С конфигурацией apache всё ясно, теперь приступим к реализации скрипта с помощью которого мы будем создавать новые репозитории. Скрипт должен
Я использовал python версии 2.7, установленным из исходных кодов с опциями --prefix=/opt/python2.7 --with-threads --enable-unicode=ucs4 --includedir=/usr/include --disable-ipv6. Так же будет необходимо установить модуль python-ldap (я использовал setuptools). Ниже приведён собственно сам скрипт.
Как видно из скрипта, каждое действие я распихал по отдельным функциям. Хочу обратить внимание, что файл конфигурации для репозитория создаётся из темплейта skeleton.tpl, который необходимо положить внутрь директории /etc/httpd/conf.d/subversion.d. Содержимое темплейта
Собственно всё. Однако, пользователям надо предоставить список репозиториев, через который они могут попасть в любой репозиторий и скачать оттуда нужный файл. Делаеться это в файле /etc/httpd/conf.d/subversion.conf добавлением директивы SVNListParentPath On. Однако, необходимо чтобы страничка с меню выглядела в корпоративном стиле. И снова на помощь я вызвал python. В скрипт инициализации apache /etc/init.d/httpd, в функцию start(), добавил строчку
Файл /opt/svn/repo/svn_gen
Тут я специально убрал ссылки на css, чтобы не выдавать организацию в которой работаю (цвета уж больно узнаваемы), но как вы поняли, вы можете реализовать страничку по своему вкусу. В данном случаем можно так же использовать темплейт, однако скрипт svn_gen был написан ещё до того, как мне надоело добавлять репозитории ручками.
Что хотелось бы реализовать в будущем
P.S. Ссылка на архив со скриптами и теплейтом addsvnrepo.tar
P.S.S. Код неидеален, так что с радостью приму любые замечания.
Забегая вперёд, хочу начать именно с конфигурации самого apache.
Главный конфигурационный файл /etc/httpd/conf/httpd.conf
......
# Load config files from the config directory "/etc/httpd/conf.d".
#
Include conf.d/*.conf
......
Собственно тут всё ясно (это дефолтное расположение конфигов при установке apache из стандартных репозиториев CentOS 5.6)
Файл /etc/httpd/conf.d/subversion.conf
LoadModule dav_svn_module modules/mod_dav_svn.so
LoadModule authz_svn_module modules/mod_authz_svn.so
LoadModule authnz_ldap_module modules/mod_authnz_ldap.so
<VirtualHost *:5553>
ServerName svn.company.ru
ServerAdmin svn_admin@company.ru
DocumentRoot /opt/svn/repo
LimitRequestBody 2147483647
CustomLog /var/log/httpd/subversion.log combined
ErrorLog /var/log/httpd/subversion-error.log
<IfModule rewrite_module>
RewriteLogLevel 0
RewriteEngine On
RewriteCond "%{REQUEST_METHOD}" !"^(GET|POST|HEAD)$"
RewriteCond "%{REQUEST_FILENAME}" "^/([^/\.]+)$"
RewriteCond "/opt/svn/repo/%1" -d
RewriteRule "^/([^/\.]+)$" "/$1/" [passthrough]
</IfModule>
Include conf.d/subversion.d/*.conf
</VirtualHost>
В этом конфигурационном файле описывается собственно конфигурация репозитория. Тут стоит отметить что мы выносим все локейшены в конфигурационные файлы в директорию conf.d/subversion.d. Зачем это надо? Во-первых нам проще отслеживать какие репозиотории включены, во-вторых мы избавляемся от парсинга конфига при запуске скрипта (об этом ниже).
Файл /etc/httpd/conf.d/subversion.d/example_repo.conf
<Location "/example_repo/">
DAV svn
SVNPath /opt/svn/repo/example_repo
SVNListParentPath on
AuthType Basic
AuthName "SVN Server"
AuthBasicProvider ldap
AuthzLDAPAuthoritative Off
AuthLDAPBindDN "cn=ldpcat,cn=users,dc=company,dc=ru"
AuthLDAPBindPassword "12345678"
AuthLDAPURL ldap://ldap.company.ru:389/ou=user,dc=company,dc=ru?sAMAccountName?sub?(objectClass=*)
AuthBasicAuthoritative off
<Limit GET PROPFIND>
Require valid-user
</Limit>
<Limit GET PROFIND PROPPATCH DELETE MERGE PUT POST MKCOL MKACTIVITY COPY MOVE LOCK UNLOCK>
Require ldap-group cn=example_group,ou=user,dc=company,dc=ru
</Limit>
</Location>
Тут мы указываем имя и местоположение репозитория, указываем с помощью какой учётной записи мы будет просматривать каталог AD (да в данном случае используется AD), пароль от этой учётной записи, строку и фильтр для поиска. Далее с помощью директории мы указываем, что просмотр репозитория позволен всем пользователям авторизованным в домене (однако можно указать конкретную группу в домене). Далее следующей директорией мы указываем какой группе пользователей в домене (в данном случае это example_group) разрешается производить все остальные действия с репозиторием.
С конфигурацией apache всё ясно, теперь приступим к реализации скрипта с помощью которого мы будем создавать новые репозитории. Скрипт должен
- Создать пустой репозиторий
- Создать конфигурационный файл для репозитоия
- Разослать членам группы, которой предоставлено право вносить изменения в репозиторий, информационное письмо
Приступим.
Я использовал python версии 2.7, установленным из исходных кодов с опциями --prefix=/opt/python2.7 --with-threads --enable-unicode=ucs4 --includedir=/usr/include --disable-ipv6. Так же будет необходимо установить модуль python-ldap (я использовал setuptools). Ниже приведён собственно сам скрипт.
#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
import os
import ldap
import ldap.sasl
import sys
import smtplib
from email.mime.text import MIMEText
server_init_file = '/etc/init.d/httpd'
apache_config_dir = '/etc/httpd/conf.d/subversion.d/'
repo_path = '/opt/svn/repo/'
user_owner_repo = 'apache'
group_owner_repo = 'apache'
mail_server = 'mail.company.ru'
mail_smtp_port = 25
mail_from = 'redmine@company.ru'
list_mail = [ ]
root_svn_url = 'http://svn.company.ru/'
if len(sys.argv)<=2:
print u"Нет параметров командной строки"
print u"в качестве параметра укажи имя репозитория и группу с правом на запись"
print u"Пример: addsvnrepo example_repo example_group"
sys.exit()
server = 'ldap://ldap'
user_id = 'ldpcat'
pw = '12345678'
dn_search = 'OU=User,DC=company,DC=ru'
repo_name = sys.argv[1]
group_commit = sys.argv[2]
if repo_name != None:
print "Создаю репозиторий "+repo_name
else:
sys.exit()
def main():
try:
con = ldap.initialize(server)
con.set_option(ldap.OPT_REFERRALS, 0)
con.simple_bind_s(user_id, pw)
print 'Подключение выполнено'
except ldap.INVALID_CREDENTIALS:
print "Ваш логин или пароль неверны"
sys.exit()
except ldap.LDAPError, e:
if type(e.message) == dict and e.message.has_key('desc'):
print 'Error - ' + e.message['desc']
else:
print 'Error - ' + str(e)
sys.exit()
finally:
print 'Подлючено'
search(con, group_commit)
repo_create()
config_write()
server_reload()
mailer()
def search(con, group_commit):
try:
base_dn = 'dc=company,dc=ru'
filter = "(memberOf=CN="+group_commit+","+dn_search+")"
attrs = ['mail']
timeout = 3
results = con.search_s(base_dn, ldap.SCOPE_SUBTREE, filter, attrs)
for dn,entry in results:
if dn != None:
list_mail.extend(entry['mail'])
con.unbind()
print list_mail
print u"Подключение закрвыто"
except ldap.LDAPError, e:
print 'Error - ' + str(e)
sys.exit()
def mailer():
text = u'Репозитоий '
text2 = repo_name
text3 = u' создан.\nРепозиторий доступен по адрессу '
text4 = root_svn_url+repo_name
text5 = u'/\nС наилучшими пожеланиями!\nРобот'
text_s = text+text2+text3+text4+text5
subj = u'Создан репозиторий '+repo_name
msg = MIMEText(text_s, "", "cp1251")
msg['Subject'] = subj
msg['From'] = mail_from
msg['To'] = ', '.join( list_mail )
print u"Мы им отправим"
print msg['To']
s = smtplib.SMTP(mail_server, mail_smtp_port)
s.sendmail(msg['From'], list_mail, msg.as_string())
s.quit()
print u"Отправили...."
def repo_create():
svnadmin_create_msg = result = os.popen("svnadmin create "+repo_path+repo_name).read()
print svnadmin_create_msg
chmod_msg = result = os.popen("chown -R "+user_owner_repo+":"+group_owner_repo+" "+repo_path+repo_name).read()
print chmod_msg
def config_write():
if os.path.exists(apache_config_dir+repo_name+".conf") :
print u"Файл конфигурации уже существует"
sys.exit()
else:
print "Создаём файл конфигурации......"
f1 = open(apache_config_dir+repo_name+".conf", 'w')
f = open(apache_config_dir+"skeleton.tpl", 'r')
body_config = f.read()
f.close()
f1.write(body_config.format(repo_name, repo_path, group_commit, server, dn_search))
f1.close()
def server_reload():
print u'Перезагружаем apache.......'
reload_msg = result = os.popen(server_init_file+" restart").read()
print reload_msg
if __name__=="__main__":
main()
Как видно из скрипта, каждое действие я распихал по отдельным функциям. Хочу обратить внимание, что файл конфигурации для репозитория создаётся из темплейта skeleton.tpl, который необходимо положить внутрь директории /etc/httpd/conf.d/subversion.d. Содержимое темплейта
<Location "/{0}/">
DAV svn
SVNPath {1}{0}
SVNListParentPath on
AuthType Basic
AuthName "SVN Server"
AuthBasicProvider ldap
AuthzLDAPAuthoritative Off
AuthLDAPBindDN "cn=ldpcat,cn=users,dc=company,dc=ru"
AuthLDAPBindPassword "12345678"
AuthLDAPURL {3}/{4}?sAMAccountName?sub?(objectClass=*)
AuthBasicAuthoritative off
<Limit GET PROPFIND>
Require valid-user
</Limit>
<Limit PROPPATCH DELETE MERGE PUT POST MKCOL MKACTIVITY COPY MOVE LOCK UNLOCK>
Require ldap-group cn={2},{4}
</Limit>
</Location>
Собственно всё. Однако, пользователям надо предоставить список репозиториев, через который они могут попасть в любой репозиторий и скачать оттуда нужный файл. Делаеться это в файле /etc/httpd/conf.d/subversion.conf добавлением директивы SVNListParentPath On. Однако, необходимо чтобы страничка с меню выглядела в корпоративном стиле. И снова на помощь я вызвал python. В скрипт инициализации apache /etc/init.d/httpd, в функцию start(), добавил строчку
/opt/svn/repo/svn_gen > /opt/svn/repo/index.html
Файл /opt/svn/repo/svn_gen
#!/usr/bin/env python2.7
import os
sdir='/opt/svn/repo/'
r, d, f = os.walk(sdir).next()
lb=len(d)
y=0
addrrepo='http://svn.company.ru/'
print "<ul>"
while y<lb:
print "<li>"
print "<a href='"
print addrrepo+d[y]
print "/"
print "'"
print ">"
print d[y]
print "</a>"
print "<br \>"
y=y+1
else:
print "</ul>"
print "<hr /"
print '<h2>PopoWeb Server running on BolgenOS Server 1.6(fundamentally new system of Denis Popov)</ h2>'
Тут я специально убрал ссылки на css, чтобы не выдавать организацию в которой работаю (цвета уж больно узнаваемы), но как вы поняли, вы можете реализовать страничку по своему вкусу. В данном случаем можно так же использовать темплейт, однако скрипт svn_gen был написан ещё до того, как мне надоело добавлять репозитории ручками.
Что хотелось бы реализовать в будущем
- Добавление конфигов уже для существующих репозиториев
- Отключение и подключение репозиториев
- Вывод списка репозиториев с подробностями (отключен/подключен, какая группа может коммитить
- Импорт из других репозиториев
- В идеале создание группы и добавление пользователей в неё. Однако добавление объектов в AD не в моей
компетенциизоне ответственности
P.S. Ссылка на архив со скриптами и теплейтом addsvnrepo.tar
P.S.S. Код неидеален, так что с радостью приму любые замечания.