gitzone

git-based zone management tool for static and dynamic domains
git clone https://git.parazyd.org/gitzone
Log | Files | Refs

commit 35bdb5882b1690a23e3ef13439e144d17b3a5af4
parent b2e775044d4def727650a3f599955c7459fe7e38
Author: tg(x) <*@tg-x.net>
Date:   Sun, 27 Feb 2011 01:12:30 +0100

made repo name independent from user name (thx loupgaroublond), renamed some config variables, gitzone-shell: default repo dir changed to ~/zones/$LOGNAME

Diffstat:
MREADME.org | 10++++++----
Mbin/gitzone | 60++++++++++++++++++++++++++++--------------------------------
Mbin/gitzone-shell | 11++++++++---
Metc/gitzone.conf | 15+++++++++------
4 files changed, 51 insertions(+), 45 deletions(-)

diff --git a/README.org b/README.org @@ -28,10 +28,10 @@ key management. - create a zones repo for each user and set receive.denyCurrentBranch to ignore, this allows pushing to a checked out repository. The checked out files are used for incrementing serials and validating the zones with named-checkzone. - : # cd ~$user - : # git init zones - : # ln -s zones $username # needed for named-checkzone - : # cd zones + : # mkdir -p ~$user/zones + : # cd ~$user/zones + : # git init $user + : # cd $user : # git config receive.denyCurrentBranch ignore : # cd hooks : # ln -s /usr/libexec/gitzone/pre-receive @@ -80,6 +80,8 @@ use the auto increment feature you also need to pull after a push as the receive hooks on the server make commits to the repository during a push. #+BEGIN_EXAMPLE + % git clone ns.example.net:zones/$user zones + % # or if you're using gitzone-shell you can use any path: % git clone ns.example.net:zones % cd zones % # edit files diff --git a/bin/gitzone b/bin/gitzone @@ -12,14 +12,17 @@ use warnings; use strict; use POSIX qw/strftime/; use Cwd qw/cwd realpath/; -use File::Basename qw/fileparse/; +use File::Basename qw/fileparse basename/; -our ($zone_dir, $git, $named_checkzone, $rndc, $class, $default_view, $update_record, $user_includes, $max_depth, $zones, $verbosity); +@ARGV >= 2 or die "Usage: gitzone /path/to/gitzone.conf <command>\n"; +basename(realpath) eq '.git' or die "gitzone has to be run from a .git directory\n"; +chdir '..'; + +our ($zone_dir, $git, $named_checkzone, $rndc, $class, $default_view, $update_record, $unrestricted_includes, $max_depth, $repos, $verbosity); our $user = getpwuid $<; +our $repo = basename realpath; -@ARGV >= 2 or die "Usage: gitzone /path/to/gitzone.conf <command>\n"; my ($config_file, $cmd) = @ARGV; - do $config_file or die "Can't load config: $!\n"; my $lock_file = realpath '.gitzone-lock'; @@ -58,20 +61,20 @@ sub git { return $_; } -# Load BIND config files specified in the $zones config variable. -# First load the -default key, then the $user key. -sub load_zones_config { +# Load BIND config files specified in the $repos config variable. +# First load the -default key, then the $repo key. +sub load_repos_config { my $key = shift || '-default'; # move files not in a dir to a . dir for easier processing - for my $file (keys %{$zones->{$key}}) { - next if ref $zones->{$key}->{$file} eq 'HASH'; - $zones->{$key}->{'.'}->{$file} = $zones->{$key}->{$file}; - delete $zones->{$key}->{$file}; + for my $file (keys %{$repos->{$key}}) { + next if ref $repos->{$key}->{$file} eq 'HASH'; + $repos->{$key}->{'.'}->{$file} = $repos->{$key}->{$file}; + delete $repos->{$key}->{$file}; } - for my $dir (keys %{$zones->{$key}}) { - my $d = $zones->{$key}->{$dir}; + for my $dir (keys %{$repos->{$key}}) { + my $d = $repos->{$key}->{$dir}; for my $file (keys %$d) { $d->{$file} = $default_view if $d->{$file} eq 1; $d->{$file} = [$d->{$file}] if ref $d->{$file} ne 'ARRAY'; @@ -80,7 +83,7 @@ sub load_zones_config { open FILE, '<', $file or die $!; while (<FILE>) { if (/^\s*zone\s+"([^"]+)"/) { - $zones->{$user}->{$dir}->{$1} = $d->{$file}; + $repos->{$repo}->{$dir}->{$1} = $d->{$file}; } } close FILE; @@ -89,7 +92,7 @@ sub load_zones_config { } } - load_zones_config($user) if $key eq '-default'; + load_zones_config($repo) if $key eq '-default'; } sub process_files { @@ -122,11 +125,11 @@ sub process_file { $changed = 1; } elsif (/^(\W*\$INCLUDE\W+)(\S+)(.*)$/) { my ($a,$inc_file,$z) = ($1,$2,$3); - if ($user_includes) { - # check $INCLUDE lines for files outside the user dir - unless ($inc_file =~ m,^$user/, && $inc_file !~ /\.\./) { + unless ($unrestricted_includes) { + # check $INCLUDE lines for files outside the repo dir + unless ($inc_file =~ m,^$repo/, && $inc_file !~ /\.\./) { close FILE; - die "Error in $file:$n: invalid included file name, it should start with: $user/\n"; + die "Error in $file:$n: invalid included file name, it should start with: $repo/\n"; } } } else { @@ -186,13 +189,9 @@ sub check_zones { # skip files with errors and those that are not in the config my ($zone, $dir) = fileparse $file; $dir = substr $dir, 0, -1; - next unless $files{$file} > 0 && exists $zones->{$user}->{$dir}->{$zone}; + next unless $files{$file} > 0 && exists $repos->{$repo}->{$dir}->{$zone}; - if ($user_includes) { - print `$named_checkzone -w .. '$zone' '$user/$file'`; - } else { - print `$named_checkzone '$zone' '$file'`; - } + print `$named_checkzone -w .. '$zone' '$repo/$file'`; clean_exit 1 if $?; # error, reject push push @zones, $file; } @@ -206,7 +205,7 @@ sub install_zones { git 'checkout -f master'; git 'reset --hard new'; - chdir "$zone_dir/$user" or die $!; + chdir "$zone_dir/$repo" or die $!; git "clone $cwd ." unless -d '.git'; git 'fetch'; git 'reset --hard remotes/origin/master'; @@ -214,7 +213,7 @@ sub install_zones { for my $file (@zones) { my ($zone, $dir) = fileparse $file; $dir = substr $dir, 0, -1; - my $view = $zones->{$user}->{$dir}->{$zone}; + my $view = $repos->{$repo}->{$dir}->{$zone}; print "$_/$zone: ", `$rndc reload '$zone' $class $_` for @$view; } @@ -223,7 +222,6 @@ sub install_zones { sub pre_receive { my ($old, $new, $ref); - chdir '..'; while (<STDIN>) { # <old-value> SP <new-value> SP <ref-name> LF print if $verbosity >= 1; @@ -246,7 +244,7 @@ sub pre_receive { # parse diff output, add only valid zone names to %files for parsing $files{$1} = 0 while m,^:(?:[\w.]+\s+){5}([a-z0-9./-]+)$,gm; - load_zones_config; + load_repos_config; process_files; if (@zones) { @@ -266,13 +264,12 @@ sub pre_receive { sub post_receive { print "\n"; - chdir '..'; open FILE, '<', $list_file or die $!; push @zones, split /[\s\n\r]+/ while <FILE>; close FILE; - load_zones_config; + load_repos_config; install_zones; print "Done. Don't forget to pull if you use auto increment.\n"; } @@ -286,7 +283,6 @@ sub update_record { my $changed = 0; my @newfile; - chdir $user; git 'checkout -f master'; open FILE, '<', $file or die "$file: $!"; diff --git a/bin/gitzone-shell b/bin/gitzone-shell @@ -1,7 +1,11 @@ #!/bin/sh # only repo allowed for git pull/push -repo='zones' +repo=$LOGNAME +# directory the repo is in, relative to $HOME +repo_dir='zones' +#repo_dir='.' + # allow ssh key add/del/list commands if this file exists allow_key_mgmt_file='.ssh/authorized_keys_edit_allowed' @@ -20,10 +24,11 @@ if [ "$1" != "-c" ]; then error; fi cmd=$2 if [[ "$cmd" == git-upload-pack* ]]; then - $git upload-pack $repo + $git upload-pack $repo_dir/$repo elif [[ "$cmd" == git-receive-pack* ]]; then - $git receive-pack $repo + $git receive-pack $repo_dir/$repo elif [[ "$cmd" == update-record* ]]; then + cd $repo_dir/$repo/.git $gitzone $config update-record "$cmd" elif [ -f $allow_key_mgmt_file ]; then if [ "$cmd" == list-keys ]; then diff --git a/etc/gitzone.conf b/etc/gitzone.conf @@ -4,6 +4,7 @@ # # this file is parsed as Perl code and you can use the following variables: # $user - name of the user gitzone is invoked by +# $repo - name of the repository gitzone is invoked for # directory where the zone files are copied to (no trailing slash) # there should be one directory for each user here chowned to them @@ -17,9 +18,10 @@ $rndc = '/usr/sbin/rndc'; # update-record command: 1 = enabled, 0 = disabled $update_record = 1; -# restrict includes to user directories -# $INCLUDE file names should be prefixed with <username>/ in this case -$user_includes = 1; +# unrestricted includes: 1 = enabled, 0 = disabled (default) +# by default a restriction applies to $INCLUDE file names, +# they should be prefixed with <repo>/ and nothing else is allowed in parent dirs +$unrestricted_includes = 0; # max depth to follow INCLUDED_BY files $max_depth = 256; @@ -31,6 +33,7 @@ $verbosity = 0; $class = 'IN'; # default view of the zones (optional) $default_view = ''; +#$default_view = $repo; # $zones defines which files in a user's repo can be loaded as zone files. # @@ -48,11 +51,11 @@ $default_view = ''; # # The -default key is tried first for every user, then it's merged with the user-specific config. -$zones = { +$repos = { # -default => { -# "/etc/bind/users/$user.conf" => 1, # allow every zone from this file, use the default view for them +# "/etc/bind/repos/$repo.conf" => 1, # allow every zone from this file, use the default view for them # }, -# user1 => { # /etc/bind/users/user1.conf is loaded first and merged with the config below, as specified in -default above +# user1 => { # /etc/bind/repos/user1.conf is loaded first and merged with the config below, as specified in -default above # 'example.com' => 1, # allow example.com, use the default view for it # 'example.net' => 'extern', # allow example.net, use the extern view for it # 'example.org' => [qw(view1 view2)], # allow example.org, use both view1 & view2 for it