Automation SVN + Apache + LDAP

A lot of things have been written on the above mentioned link, however, I always felt some inconvenience when opening a new repository: it was necessary to create a new location in the configuration file, create a repository using svnadmin, and restart apache. When such work has to be done once a month, this is tolerable, however, when such work has to be done several times a week, it is worth considering automation of this process. Actually, we are talking about this under the cut.


Looking ahead, I want to start with the configuration of apache itself.

Main configuration file /etc/httpd/conf/httpd.conf
......
# Load config files from the config directory "/etc/httpd/conf.d".#Include conf.d/*.conf
......

Actually, everything is clear here (this is the default location of the config when installing apache from the standard CentOS 5.6 repositories)

/etc/httpd/conf.d/subversion.conf file
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
     RewriteEngineOnRewriteCond"%{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>

This configuration file describes the actual repository configuration. It is worth noting that we put all the locations in the configuration files into the conf.d / subversion.d directory. Why is this necessary? Firstly, it’s easier for us to track which repositories are included, and secondly, we get rid of the parsing of the config when the script starts (more on that below).
File /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
   <LimitGET PROPFIND>
          Require valid-user
   </Limit>
   <LimitGET PROFIND PROPPATCH DELETE MERGE PUT POST MKCOL MKACTIVITY COPYMOVELOCK UNLOCK>
           Require ldap-group cn=example_group,ou=user,dc=company,dc=ru
   </Limit>
 </Location>

Here we indicate the name and location of the repository, indicate with which account we will look at the AD directory (yes, in this case, AD is used), the password for this account, a string and a search filter. Further, using the directory, we indicate that viewing the repository is allowed to all users authorized in the domain (however, you can specify a specific group in the domain). Next, the next directory, we indicate which group of users in the domain (in this case, example_group) is allowed to perform all other actions with the repository.

Everything is clear with the apache configuration, now we will begin to implement a script with which we will create new repositories. The script should
  1. Create an empty repository
  2. Create configuration file for repository
  3. Send an information letter to the members of the group that has the right to make changes to the repository


Let's get started.


I used python version 2.7 installed from source with options --prefix = / opt / python2.7 --with-threads --enable-unicode = ucs4 --includedir = / usr / include --disable-ipv6. It will also be necessary to install the python-ldap module (I used setuptools). Below is the actual script itself.
#!/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:
	printu"Нет параметров командной строки"printu"в качестве параметра укажи имя репозитория и группу с правом на запись"printu"Пример: 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()
defmain():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()
defsearch(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
            printu"Подключение закрвыто"except ldap.LDAPError, e:
            print'Error - ' + str(e)
            sys.exit()
defmailer():
		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 )
		printu"Мы им отправим"print msg['To']
		s = smtplib.SMTP(mail_server, mail_smtp_port)
		s.sendmail(msg['From'], list_mail, msg.as_string())
		s.quit()
		printu"Отправили...."defrepo_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
defconfig_write():if os.path.exists(apache_config_dir+repo_name+".conf") :
		printu"Файл конфигурации уже существует"
		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() 
defserver_reload():printu'Перезагружаем apache.......'
	reload_msg = result = os.popen(server_init_file+" restart").read()
	print reload_msg
if __name__=="__main__":
    main()


As you can see from the script, I pushed each action into separate functions. I want to note that the configuration file for the repository is created from the skeleton.tpl template, which must be put inside the /etc/httpd/conf.d/subversion.d directory. Template Content
<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
<LimitGET PROPFIND>
       Require valid-user
</Limit>
<Limit PROPPATCH DELETE MERGE PUT POST MKCOL MKACTIVITY COPYMOVELOCK UNLOCK>
                Require ldap-group cn={2},{4}
</Limit>
</Location>


Actually everything. However, users need to provide a list of repositories, through which they can get into any repository and download the desired file from there. This is done in the /etc/httpd/conf.d/subversion.conf file by adding the SVNListParentPath On directive. However, it is necessary that the page with the menu look in a corporate style. And again, I called python to help. In the apache initialization script /etc/init.d/httpd, in the start () function, added the line
/opt/svn/repo/svn_gen > /opt/svn/repo/index.html

File / opt / svn / repo / svn_gen
#!/usr/bin/env python2.7import 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+1else:
         print"</ul>"print"<hr /"print'<h2>PopoWeb Server running on BolgenOS Server 1.6(fundamentally new system of Denis Popov)</    h2>'

Here I specifically removed the links to css, so as not to give out the organization in which I work (the colors are too recognizable), but as you understand, you can implement the page to your liking. In this case, you can also use the template, however, the svn_gen script was written even before I was tired of adding repositories with pens.

What I would like to implement in the future
  • Adding configs already for existing repositories
  • Disabling and connecting repositories
  • List repositories with details (disconnected / connected, which group can commit
  • Import from other repositories
  • Ideally, create a group and add users to it. However, the addition of objects in AD is not in my competence area of responsibility


PS Link to the archive with scripts and teplayte addsvnrepo.tar
PSS The code is not perfect, so I will gladly accept any comments.

Also popular now: