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

View file

@ -28,6 +28,7 @@ In this document:
* <a href="#_personal_branches">"personal" branches</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="#_disabling_write_access_to_take_backups">disabling write access to take backups</a>
* <a href="#_INconvenience_features">INconvenience features</a>
* <a href="#_deleting_a_repo">deleting a repo</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
`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>
#### 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
the config file). Wildcards are not supported; patches welcome ;-)
**NOTE: This needs a specific secondary update hook**. Creating a secondary
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):
Note: please see [this][diswr] for more on this.
#!/bin/bash
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
[diswr]: http://github.com/sitaramc/gitolite/blob/pu/doc/3-faq-tips-etc.mkd#_disabling_write_access_to_take_backups
<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
# ----------------------------------------------------------------------------

View file

@ -246,6 +246,9 @@ my $aa = ($verb =~ $R_COMMANDS ? 'R' : 'W');
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/;
# check if repo is write-enabled
&check_repo_write_enabled($repo) if $aa eq 'W';
# ----------------------------------------------------------------------------
# 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