Как стать автором
Обновить

Автоматизация SVN + Apache + LDAP

Время на прочтение7 мин
Количество просмотров11K
По выше упомянутой связке много чего написано, однако, я вечно чувствовал некие неудобства при заведении нового репозитория: необходимо было завести новый локейшн в конфигурационном файле, создать репозиторий с помощью svnadmin, перезапустить apache. Когда такую работу приходиться выполнять раз в месяц — это терпимо, однако, когда такую работу приходиться выполнять по несколько раз в неделю, стоит задуматься об автоматизации этого процесса. Собственно об этом речь и идёт под катом.


Забегая вперёд, хочу начать именно с конфигурации самого 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 всё ясно, теперь приступим к реализации скрипта с помощью которого мы будем создавать новые репозитории. Скрипт должен
  1. Создать пустой репозиторий
  2. Создать конфигурационный файл для репозитоия
  3. Разослать членам группы, которой предоставлено право вносить изменения в репозиторий, информационное письмо


Приступим.


Я использовал 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. Код неидеален, так что с радостью приму любые замечания.
Теги:
Хабы:
Всего голосов 20: ↑18 и ↓2+16
Комментарии27

Публикации

Истории

Работа

Ближайшие события

7 – 8 ноября
Конференция byteoilgas_conf 2024
МоскваОнлайн
7 – 8 ноября
Конференция «Матемаркетинг»
МоскваОнлайн
15 – 16 ноября
IT-конференция Merge Skolkovo
Москва
22 – 24 ноября
Хакатон «AgroCode Hack Genetics'24»
Онлайн
28 ноября
Конференция «TechRec: ITHR CAMPUS»
МоскваОнлайн
25 – 26 апреля
IT-конференция Merge Tatarstan 2025
Казань