|
问题1:发布代码这种事,开发嫌慢,运维嫌烦,策划和测试狂催,如果开发直接提交svn后线上代码也是最新的就大家都不用烦了.
问题2:小公司电脑少,svn只有一个,永远不够用啊,各种文件和代码堆堆堆,时间一长就连自己也不知道放哪里了,如果一台机有多个svn目录独立控制,那就简单了.
我相信上面两个问题在大部分公司都存在,代码发布和文件管理是任何公司都有的核心功能,当然了,有的公司技术强大,用高大上git必须比svn好用,不过大部分还是svn为主,要解决上面两个问题,那就看下面了.
先来看看原理图:
问题一的解决方案
问题的关键就在钩子脚本,一会看一下详细的.
问题二的解决方案
问题的关键就是利用apache多域控制多端口,不同的端口指向不同的svn数据库,这样就可以做到单机多svn目录.
下面来说怎么安装和配置整套应用
1.安装应用
说到安装方法,那当然是yum最简单,呵呵~!我也就不纠结太多了,纠结编译安装的,可以看着下面的软件逐个去弄,这真的不是问题,编译参数我在附录贴一下.
顺便说说,我是在centos7.2安装的,所以按道理是通用的了.
#安装依赖包
yum install -y Python pyOpenSSL zlib* apr* swig* neon*
#安装libiconv,这个yum不了,只能编译,但是也很简单就是了
wget "http://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.14.tar.gz"
tar xf libiconv-1.14.tar.gz
cd libiconv-1.14
./configure --prefix=/usr/local/libiconv
make
make install
#安装apache服务
yum install -y httpd
#安装svn服务和httpd模块
yum install -y subversion mod_dav_svn 这个就安装完了,如果硬要编译的话,嗯~!那可是一长串,我表示不太喜欢,反正这些需求都是内部的,能用就行,性能都不是重点.
2.配置apache和关联svn
理论上apache安装完就能用,但是这个并不是重点,他和svn两者要配合使用,那必然是有关联的地方,而因为是yum安装的,http的conf目录在/etc下面,
先配置apache的基本配置,
#创建运行用户,注意不要创建/sbin/nologin的用户使用在apache+svn上,因为会导致钩子脚本无法使用
groupadd www
useradd www -g www
#修改httpd.conf,里面东西太多,只说几个重点
vim /etc/httpd/conf/httpd.conf
#配置端口,默认80,你喜欢改什么都可以,不冲突就行
Listen 8001
#运行用户和用户组,你创什么就用什么,要保证是可以运行脚本的权限/bin/bash
User www
Group www 然后其他默认就可以了.
然后配置两者关联的相关配置配置
#配置subversion.conf文件如下内容
vim /etc/httpd/conf.modules.d/10-subversion.conf
LoadModule dav_svn_module modules/mod_dav_svn.so
LoadModule authz_svn_module modules/mod_authz_svn.so
LoadModule dontdothat_module modules/mod_dontdothat.so
Dav svn
SVNListParentPath on
#----允许在网页上显示svn父目录list --记住,注释不要和配置项写到同一行,否则会出错..
SVNParentPath "/data/svn"
AuthType Basic
#----连接框提示
AuthName "Subversion Repository"
#----用户密码配置文件
AuthUserFile /etc/svn/passwd
#----用户权限配置文件
AuthzSVNAccessFile /etc/svn/authz
#----限制登录配置,可细化到只允许那个IP登录,这里注释了,暂时不使用
# Order Allow,Deny
# Allow from 127.0.0.1
# Allow from {任何IP类型}
# Deny from All
Require valid-user
#可以再加一个Location来实现多svn仓库,类似这样
#
#中间省略...
#
再然后修改一些权限的问题和启动apache
#修改数据仓库目录/data/svn权限(后面用到)
chown www:www -R /data/svn
chmod 777 -R /data/svn
#关闭SELinux
setenforce 0
#重启apache服务
service httpd restart 这样apache部分就完毕了
3.创建svn数据仓库
首先要强调,svn的数据仓库和我们认知的checkout出来的svn文件目录不同,svn的数据仓库他是经过编码的二进制文件,不能直接解析,和我们能直接操作的svn文件夹是两回事,我们提交和下载的文件都是经过编码解析的,大家心里要又这个概念.
下面来看操作
#创建仓库目录
mkdir -p /data/svn/test_1
#创建svn仓库
svnadmin create /data/svn/test_1
#配置改仓库的配置文件
vim /data/svn/test_1/conf/svnserve.conf
#禁用匿名用户并开启验证用户权限。
anon-access = none
auth-access = write
4.创建svn用户
还记得关联svn时apache配置的用户认证相关目录么,没错,是/etc/svn,另外,因为用了apache,所以用户的密码不再是传统svn的明文保存,需要通过htpasswd来加密配置,所以要独立开来讲讲
#进入目录
cd /etc/svn
#使用htpasswd创建用户,首次创建用户会建立新文件,删除旧文件,前面是用户,后面是密码
htpasswd -cb passwd test 123
#添加/修改用户
htpasswd -b passwd new-user new-password
#删除用户
htpasswd -D passwd new-user 然后相关的用户名和密码就会加密保存在/etc/svn/passwd里面,有兴趣的可以看一下文件内容,是密文存储的.
5.配置svn权限
和密码认证文件一样的位置,主要要注意的地方是他分为组权限,不同的组可以有不同的权限,没规定什么名字,可以细化到目录,其实也就只分读和写两个权限,
#编辑authz文件,设置guest组包含test和abc两个用户,devl组aaa和bbb两个用户。
vim /etc/svn/authz
[groups]
guest = test,abc
devl = aaa,bbb
#配置组权限,设置根目录下guest组为可读写,其他用户为可读。
[/]
@guest = rw
* = r
#设置test_1目录下devl组为可读,其他没权限
[test_1:/]
@g_developer = r
* =
#设置test_1目录下tags文件夹devl组为可读写,其他没权限
[test_1:/tags]
@g_developer = rw
* = 权限配置就这么完毕了,然后,并不需要启动svn程序,就可以使用的了,因为apache会调用插件,不需要svn程序额外启动,相当方便,减少一个程序占用内存.
6.创建钩子脚本
关于钩子脚本的用途,就是说在提交/更新/删除各种场景发生前后执行的脚本的意思,是svn自带的功能,非常方便,这也是自动发布代码的关键所在.
svn也自带一些模板,就在数据仓库目录里面
ll /data/svn/test_1/hooks/
-rw-r--r-- 1 www www 1977 9月 13 10:33 post-commit.tmpl
-rw-r--r-- 1 www www 1638 9月 13 10:33 post-lock.tmpl
-rw-r--r-- 1 www www 2289 9月 13 10:33 post-revprop-change.tmpl
-rw-r--r-- 1 www www 1567 9月 13 10:33 post-unlock.tmpl
-rw-r--r-- 1 www www 3426 9月 13 10:33 pre-commit.tmpl
-rw-r--r-- 1 www www 2434 9月 13 10:33 pre-lock.tmpl
-rw-r--r-- 1 www www 2786 9月 13 10:33 pre-revprop-change.tmpl
-rw-r--r-- 1 www www 2122 9月 13 10:33 pre-unlock.tmpl
-rw-r--r-- 1 www www 2780 9月 13 10:33 start-commit.tmpl 有心研究的可以慢慢研究,下面这个就是提交后执行的那个脚本post-commit,只要有提交动做,这个脚本就会执行.
#创建或修改post-commit,成功提交后执行的钩子
vim /data/svn/test_1/hooks/post-commit
#!/bin/bash
SVN=/usr/bin/svn
LOG=/var/log/svnup-houtai.log
wwwurl=/data/htdocs/
export LANG=zh_CN.UTF-8
export PATH
cat $LOG >> ${LOG}.bak
echo "" > $LOG
echo `date` >> $LOG
echo "##############################" >> $LOG
cd ${wwwurl};$SVN co --username test --password '123' http://192.168.1.86:8001/svn/test_1 www >> $LOG
echo "##############################" >> $LOG
wait========================================= 升级版钩子脚本,远程checkout,要预先使用ssh-keygen做好免密码登录
#!/bin/bash
SVN=/usr/bin/svn
LOG=/var/log/svnup-newips.log
export LANG=zh_CN.UTF-8
export PATH
cat $LOG >> ${LOG}.bak
echo "" > $LOG
echo `date` >> $LOG
echo "##############################" >> $LOG
commend="$SVN co --username test --password '123' http://192.168.1.86:8001/svn/newips /data/htdocs/www "
auto_scp() {
ip=10.29.66.55
PORT=22
expect$LOG
echo "##############################" >> $LOG
wait ===========================================
重点解析下,注意空格分割
SVN co --username test --password '123' http://192.168.1.86:8001/svn/test www svn是命令,co是更新数据的意思,username就是用户,password就是密码,http后面那串就是svn地址,最后的www意思是创建并更新到什么目录的意思,例如我的代码是放在/data/htdocs的www目录,如果有就更新,如果没就创建了再更新.
所以这句的意思就是把svn仓库的文件更新到/data/htdocs/www代码目录里面,你的代码目录如果叫app,那最后的www就可以改成app.
而这个目录要是一开始就配置成nginx等web系统的php或者java代码目录的话,那么只要你提交svn代码,通过钩子脚本的运行,你的代码目录也会同时更新,也就是我开头说的---代码直接发布系统.
然后还没完,因为这个是要apache执行的,而apache的执行用户是www,所以要做脚本运行就要操作这一步
#设置post-commit执行权限,不然会报错的
chmod 777 /data/svn/test_1/hooks/post-commit
#切换用户执行下脚本,如果不执行,可能钩子也是不生效的,因为有应答提醒
su - www /data/svn/test_1/hooks/post-commit
上一次登录:二 9月 13 12:01:08 CST 2016pts/0 上
-----------------------------------------------------------------------
注意! 你的密码,对于认证域:
Subversion Repository
只能明文保存在磁盘上! 如果可能的话,请考虑配置你的系统,让 Subversion
可以保存加密后的密码。请参阅文档以获得详细信息。
你可以通过在“/home/www/.subversion/servers”中设置选项“store-plaintext-passwords”为“yes”或“no”,
来避免再次出现此警告。
-----------------------------------------------------------------------
保存未加密的密码(yes/no)?yes
ll /data/svn/test_1/hooks/post-commit
总用量 40
-rwxrwxrwx 1 www www 416 9月 13 12:07 post-commit 然后,你的就可以用了
有些时候,我们的svn要求必须有做注释,方便翻(zhao)查(ren)数(bei)据(guo),所以就有了第二个脚本,强制提交时输入注释:
#这个是要求在提交时触发的钩子,当然就不是原本那个文件了
vim /data/svn/test_1/hooks/pre-commit
#!/bin/bash
REPOS="$1"
TXN="$2"
SVNLOOK=/usr/bin/svnlook
LOGMSG=$($SVNLOOK log -t "$TXN" "$REPOS" | grep "[a-zA-Z0-9]" | wc -c)
if [ "$LOGMSG" -lt 3 ]; then
echo -e "\n 提交文件时必须添加注释,提交中止."1>&2
exit 1
fi
#别忘记切换用户执行以下,和上面一样操作就可以了,
su - www /data/svn/test_1/hooks/pre-commit 其中注意,
LOGMSG=$($SVNLOOK log -t "$TXN" "$REPOS" | grep "[a-zA-Z0-9]" | wc -c)
是统计这个注释有多少个字母和数字的字符总数量的意思.中文不能被统计,所以要注意注释的格式,
if [ "$LOGMSG" -lt 3 ]; then
是限制输入字数的意思,这里是至少3个字符的意思可以更多,也可以更少,大家看自己偏好.
7.测试
其实钩子脚本里面也有地址测试,不过也可以自己测试,无论是windows还是linux都用这个地址http://192.168.1.86:8001/svn/test_1
svn co http://192.168.1.86:8001/svn/test_1 /data/htdocs/www --username=test --password=123 windows的怎么测我就不多说了,就是界面而已.
8.备份/还原svn数据仓库
这个算是个基本需求吧,不过我觉得一定情况来说其实有点鸡肋,一般来说svn都是很多人一起用,每个人电脑里面的文件就是一个备份,还特地去备份和还原就有点多此一举的感觉,除非说这个svn数据非常多,重新上传超级费时间,或者说非常在意svn存放的注释记录和版本记录,那倒是说得过去,上面纯属个人简介,下面转回正题.
备份的方式现在有三种,其实有很多同类文章了,我也就不想详细介绍了,
1)svnadmin dump
2)svnadmin hotcopy
3)svnsync.
第三种除了特定场景几乎没人用,也很少例子,第二种在以前资源紧张的旧服务器倒是有优势,现在也是没什么优势了,先看第一种.
#第一种方法备份命令,详细参数请看下面
svnadmin dump /data/svn/[你的svn目录] --deltas > test-svn-7.dump 2>/dev/null
#参数说明:
-r [--revision]: 指定备份的版本号(或X:Y范围)
--incremental: 以增量方式进行转存
--deltas: 使用压缩,消耗更多cpu资源
-q [--quiet]: 在标准错误输出不显示进度(仅错误)
#备份完了还想加大压缩比,那就在tar一下吧,
tar zcf test-svn-7.tar.gz test-svn-7.dump 然后来看第二种
#第二种方法备份命令,其实也等于直接拷贝
svnadmin hotcopy /data/svn/[你的svn目录] /root/[目的备份svn目录]
#这个文件夹肯定是和原本的一样大,所以你更加需要压缩
tar zcf test-svn-7.tar.gz /root/test-svn 然后,就看怎么恢复了,第二种方式就不用说了,都是一个完整目录了,直接改配置文件或者复制到相关http目录就完全能用起来了,主要来看第一种,
#第一种方式恢复命令,先创建一个新的版本库
svnadmin create /svn/project/test1
#先还原完全备份,
svnadmin load /svn/project/test1 < test-svn-7.dump
#如果有做增量备份,再还原增量备份的内容
svnadmin load /svn/project/test1 < svn.bak.1 这样就完成了备份和恢复了.
9.搭建用户密码自助修改功能
如果大家用起来,就会发现这个svn的账户密码,必须管理员来添加和修改.其实不算很方便,然而创建密码用的工具htpasswd本身是具有加密功能的,单纯用脚本调用修改又变得很麻烦,网上很多同类的文章也都是忽略了加密算法问题,造成实现不了的情况,我也是翻查了很多资料,然后分析了脚本得出这个结果.
那要怎么办呢?经过分析和权衡利弊,总算找到一个姑且能算是解决的方法,不过有一个大坑,而这个坑的解决方案,就得看有没有高手去破解算法了,我暂时是没有办法的了.
好了,转回正题,我们用的方法,其实就是cgi方法的变种,网上一搜一大堆的ChangePasswd.cgi,不过如果你按他们的方法做,一般情况下是失败的,也就是因为我说的算法问题,这个cgi的perl脚本里的crypt函数的算法和htpasswd的算法是不一样的,所以无论你怎么改,都会提示旧密码错误.不过从另一方面来说也有好的一面,密码那么容易被破解,那这个加密算法还真是失败透了.
先来看ChangePasswd.ini,只是个配置文件了,记得给读的权限啊
#打开
vim ChangePasswd.ini
[path]
authuserfile=/etc/svn/passwd
logfile=/var/www/cgi-bin/ChangePasswd.log
[setup]
pwdminlen=6
[html]
title=SVN用户密码自助修改
description=SVN用户密码自助修改
yourname=用户名
oldpwd=旧密码
newpwd1=新密码
newpwd2=确认新密码
btn_change=修 改
btn_reset=重 置
changepwdok=成功修改密码
changepwdfailed=修改密码失败
servererror=服务器错误
passmustgreater=新密码位数必须大于
twopassnotmatched=两密码不一致
entername=请输入用户名
enterpwd=密码未输入
errorpwd=你的密码不正确
back=返回 需要改的只有两个地方,authuserfile就是你svn密码存放文件,logfile就是你日志的文件了,通常你保证能读写就好了.
再看重点的ChangePasswd.cgi,这个就是执行文件,要给执行权限
#!/usr/bin/perl -w
use strict;
use CGI;
my $time = localtime;
my $remote_id = $ENV{REMOTE_HOST} || $ENV{REMOTE_ADDR};
my $admin_email = $ENV{SERVER_ADMIN};
my $cgi = new CGI;
my $pwd_not_alldiginal = "密码不能全为数字";
my $pwd_not_allchar = "密码不能全为字符";
my $user_not_exists ="该用户不存在";
my $file_not_found ="文件不存在,请联系管理员";
my $authuserfile;
my $logfile;
my $pwdminlen;
my $title;
my $description;
my $yourname;
my $oldpwd;
my $newpwd1;
my $newpwd2;
my $btn_change;
my $btn_reset;
my $changepwdok;
my $changepwdfailed;
my $oldpwderror;
my $passmustgreater;
my $twopassnotmatched;
my $entername;
my $enterpwd;
my $errorpwd;
my $back;
&IniInfo;
if ($cgi -> param())
{#8
my $User = $cgi->param('UserName');
my $UserPwd = $cgi->param('OldPwd');
my $UserNewPwd = $cgi->param('NewPwd1');
my $MatchNewPwd = $cgi->param('NewPwd2');
if (!$User)
{&Writer_Log("Enter no user name");
&otherhtml($title,$entername,$back);}
elsif (!$UserPwd )
{&Writer_Log("Enter no OldPasswd");
&otherhtml($title,$enterpwd,$back); }
elsif (length($UserNewPwd) |
|