gitolite-down: disable write-access to take backups

(we quietly do not document the 'able' adc, which is now the most
"official" adc in the sense that it has a new test, t64-write-able!)

other notes: fix bug in 'able' (not setting $loc)
This commit is contained in:
Sitaram Chamarty 2010-11-16 20:09:45 +05:30
parent 16ab95665c
commit 7313d48247
6 changed files with 204 additions and 19 deletions

View file

@ -18,6 +18,7 @@ do
locs="$locs $HOME" locs="$locs $HOME"
;; ;;
* ) * )
loc="$GL_REPO_BASE_ABS/$1.git"
[ -d $loc ] && locs="$locs $GL_REPO_BASE_ABS/$1.git" [ -d $loc ] && locs="$locs $GL_REPO_BASE_ABS/$1.git"
[ -d $loc ] || echo "ignoring $1..." [ -d $loc ] || echo "ignoring $1..."
;; ;;
@ -25,6 +26,8 @@ do
shift shift
done done
[[ -z "$locs" ]] && die "give me '@all' or some reponame"
case $op in case $op in
en|enable ) en|enable )
for l in $locs for l in $locs
@ -35,9 +38,13 @@ case $op in
dis|disable ) dis|disable )
# bashism # bashism
read msg <<<$(cat) read msg <<<$(cat)
echo disabling following locations with message:
echo $msg
echo
for l in $locs for l in $locs
do do
echo $msg > $l/.gitolite.down echo $msg > $l/.gitolite.down
echo $l
done done
;; ;;
* ) * )

View file

@ -28,6 +28,7 @@ In this document:
* <a href="#_personal_branches">"personal" branches</a> * <a href="#_personal_branches">"personal" branches</a>
* <a href="#_custom_hooks_and_custom_git_config">custom hooks and custom git config</a> * <a href="#_custom_hooks_and_custom_git_config">custom hooks and custom git config</a>
* <a href="#_bypassing_gitolite">bypassing gitolite</a> * <a href="#_bypassing_gitolite">bypassing gitolite</a>
* <a href="#_disabling_write_access_to_take_backups">disabling write access to take backups</a>
* <a href="#_INconvenience_features">INconvenience features</a> * <a href="#_INconvenience_features">INconvenience features</a>
* <a href="#_deleting_a_repo">deleting a repo</a> * <a href="#_deleting_a_repo">deleting a repo</a>
* <a href="#_helping_with_gitweb">helping with gitweb</a> * <a href="#_helping_with_gitweb">helping with gitweb</a>
@ -540,6 +541,33 @@ is NOT available if you bypass gitolite. Mucking with that repo in this
manner is strongly discouraged, as in "are you feeling lucky today?". Use manner is strongly discouraged, as in "are you feeling lucky today?". Use
`gl-dont-panic` if you need to do some server-side surgery for that repo. `gl-dont-panic` if you need to do some server-side surgery for that repo.
<a name="_disabling_write_access_to_take_backups"></a>
##### disabling write access to take backups
If you want to take normal, OS-level, backups of the system, you might want
git to be quiescent during that time, so that the backup is clean. The best
way to do this is to disable write-access to the server for the duration of
the backup.
Here's how:
cd $HOME # if running as "git" user, else "cd ~git" or whatever
echo writes disabled during backup window > .gitolite.down
# << RUN YOUR BACKUP COMMAND(s) HERE >>
rm .gitolite.down
I leave it to you to
* make sure that if the backup script fails, the `.gitolite.down` file is
still removed (or not; maybe your policy is that if the backup failed, no
further writes are allowed. Whatever...)
* if you're extremely paranoid (even I wouldn't worry about this!) make sure
that no push is *in progress* by checking for any `git-receive-pack`
processes in a `ps` output.
<a name="_INconvenience_features"></a> <a name="_INconvenience_features"></a>
#### INconvenience features #### INconvenience features

View file

@ -189,26 +189,9 @@ You can also do this for one or more individual repos; in place of `@all`,
just use a space separated list of reponames (exactly as they would appear in just use a space separated list of reponames (exactly as they would appear in
the config file). Wildcards are not supported; patches welcome ;-) the config file). Wildcards are not supported; patches welcome ;-)
**NOTE: This needs a specific secondary update hook**. Creating a secondary Note: please see [this][diswr] for more on this.
update hook is described in the sections on "custom hooks" and "hook chaining"
in doc/2. You need code like this in `update.secondary` (don't forget to
`chmod +x` the file):
#!/bin/bash [diswr]: http://github.com/sitaramc/gitolite/blob/pu/doc/3-faq-tips-etc.mkd#_disabling_write_access_to_take_backups
for f in $HOME/.gitolite.down $PWD/.gitolite.down
do
if [ -f $f ]
then
echo >&2
echo '*** ABORT ***' >&2
echo >&2
cat $f >&2
exit 1
fi
done
exit 0
<a name="_bonus_restricted_admin"></a> <a name="_bonus_restricted_admin"></a>

View file

@ -787,6 +787,16 @@ sub can_read {
); );
} }
# helper to manage "disabling" a repo or the whole site for "W" access
sub check_repo_write_enabled {
my ($repo) = shift;
for my $d ("$ENV{HOME}/.gitolite.down", "$ENV{GL_REPO_BASE_ABS}/$repo.git/.gitolite.down") {
next unless -f $d;
die $ABRT . `cat $d` if -s $d;
die $ABRT . "writes are currently disabled\n";
}
}
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
# setup the ~/.ssh/authorized_keys file # setup the ~/.ssh/authorized_keys file
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------

View file

@ -246,6 +246,9 @@ my $aa = ($verb =~ $R_COMMANDS ? 'R' : 'W');
die "$aa access for $repo DENIED to $user die "$aa access for $repo DENIED to $user
(Or there may be no repository at the given path. Did you spell it correctly?)\n" unless $perm =~ /$aa/; (Or there may be no repository at the given path. Did you spell it correctly?)\n" unless $perm =~ /$aa/;
# check if repo is write-enabled
&check_repo_write_enabled($repo) if $aa eq 'W';
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
# over to git now # over to git now
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------

154
t/t64-write-able Normal file
View file

@ -0,0 +1,154 @@
# vim: syn=sh:
for bc in 0 1
do
cd $TESTDIR
$TESTDIR/rollback || die "rollback failed"
editrc GL_BIG_CONFIG $bc
editrc GL_WILDREPOS 1
rm -rf /tmp/glt-adc
mkdir /tmp/glt-adc || die "mkdir /tmp/glt-adc failed"
cp ../contrib/adc/* /tmp/glt-adc
echo "\$GL_ADC_PATH = '/tmp/glt-adc';" | addrc
runremote rm -f .gitolite.down
# ----------
name "INTERNAL"
echo "
@leads = u1 u2
@devs = u1 u2 u3 u4
repo foo
RW+ = u1
@gbar = bar/CREATOR/..*
repo @gbar
C = @leads
RW+ = @leads
RW = @devs
" | ugc
expect_push_ok "master -> master"
name "u1 push foo"
cd ~/td
rm -rf foo
runlocal git clone u1:foo
expect "warning: You appear to have cloned an empty repository."
cd foo
mdc; mdc
runlocal git push origin master
expect_push_ok "master -> master"
name "u2 create and push bar/u2/r1"
cd ~/td
runlocal git clone u2:bar/u2/r1
expect "Initialized empty Git repository in /home/gitolite-test/repositories/bar/u2/r1.git/"
expect "warning: You appear to have cloned an empty repository."
cd r1
mdc; mdc
runlocal git push origin master
expect_push_ok "master -> master"
name "disable entire site"
runremote ls -al .gitolite.down
expect "ls: cannot access .gitolite.down: No such file or directory"
(echo first line; echo second line) | runlocal ssh gitolite able dis
expect "give me '@all' or some reponame"
(echo first line; echo second line) | runlocal ssh gitolite able dis @all
expect "disabling following locations with message:"
expect "first line second line"
expect "/home/gitolite-test"
runremote ls -al .gitolite.down
expect "^.rw------- 1 gitolite-test gitolite-test .. ... .. ..:.. .gitolite.down"
name "u1 push foo fail"
cd ~/td/foo
mdc; mdc
runlocal git push origin master
expect ABORTING
expect "first line second line"
expect "fatal: The remote end hung up unexpectedly"
name "u2 create and push bar/u2/r1 fail"
cd ~/td/r1
mdc; mdc
runlocal git push origin master
expect ABORTING
expect "first line second line"
expect "fatal: The remote end hung up unexpectedly"
name "enable entire site"
runlocal ssh gitolite able en
expect "give me '@all' or some reponame"
runlocal ssh gitolite able en @all
expect "removed ./home/gitolite-test/.gitolite.down."
runremote ls -al .gitolite.down
expect "ls: cannot access .gitolite.down: No such file or directory"
name "u1 push foo"
cd ~/td/foo
mdc; mdc
runlocal git push origin master
expect_push_ok "master -> master"
name "u2 create and push bar/u2/r1"
cd ~/td/r1
mdc; mdc
runlocal git push origin master
expect_push_ok "master -> master"
name "disable foo"
runlocal ssh u1 able dis foo
expect "just .what. are you trying to pull, young man"
echo foo down|runlocal ssh gitolite able dis foo
expect "disabling following locations with message:"
expect "foo down"
expect "/home/gitolite-test/repositories/foo.git"
runremote ls -al /home/gitolite-test/repositories/foo.git/.gitolite.down
expect ".rw------- 1 gitolite-test gitolite-test . ... .. ..:.. /home/gitolite-test/repositories/foo.git/.gitolite.down"
name "u1 push foo fail"
cd ~/td/foo
mdc; mdc
runlocal git push origin master
expect ABORTING
expect "foo down"
expect "fatal: The remote end hung up unexpectedly"
name "u2 create and push bar/u2/r1"
cd ~/td/r1
mdc; mdc
runlocal git push origin master
expect_push_ok "master -> master"
name "enable foo, disable bar/u2/r1"
runlocal ssh u1 able en foo
expect "just .what. are you trying to pull, young man"
runlocal ssh gitolite able en foo
expect "removed ./home/gitolite-test/repositories/foo.git/.gitolite.down."
echo bar/u2/r1 down | runlocal ssh u1 able dis foo
expect "just .what. are you trying to pull, young man"
echo bar/u2/r1 down | runlocal ssh gitolite able dis bar/u2/r1
expect "disabling following locations with message:"
expect "bar/u2/r1 down"
expect "/home/gitolite-test/repositories/bar/u2/r1.git"
runremote ls -al /home/gitolite-test/repositories/bar/u2/r1.git/.gitolite.down
expect ".rw------- 1 gitolite-test gitolite-test .. ... .. ..:.. /home/gitolite-test/repositories/bar/u2/r1.git/.gitolite.down"
name "u1 push foo"
cd ~/td/foo
mdc; mdc
runlocal git push origin master
expect_push_ok "master -> master"
name "u2 create and push bar/u2/r1i fail"
cd ~/td/r1
mdc; mdc
runlocal git push origin master
expect ABORTING
expect "bar/u2/r1 down"
expect "fatal: The remote end hung up unexpectedly"
name "INTERNAL"
done