--- a/Build.PL Sat Jan 22 00:05:44 2011 +0100
+++ b/Build.PL Sun Jan 23 00:21:14 2011 +0100
@@ -10,9 +10,13 @@
dist_version => "0.1",
create_license => 1,
license => "gpl",
- requires => { perl => "5.10.0", },
- build_requires => { "Pod::Coverage" => 0, },
- script_files => [glob "bin/*"], # avoid .swp files
+ requires => {
+ perl => "5.10.0",
+ "Net::LibIDN" => "0",
+ "Template" => "0"
+ },
+ build_requires => { "Pod::Coverage" => 0, "Test::Command" => "0.08" },
+ script_files => [glob "bin/*"], # avoid .swp files
);
$build->create_build_script;
--- a/bin/zone-mk Sat Jan 22 00:05:44 2011 +0100
+++ b/bin/zone-mk Sun Jan 23 00:21:14 2011 +0100
@@ -1,119 +1,120 @@
#!/usr/bin/perl
+use 5.010;
use warnings;
use strict;
-use FindBin;
+use Pod::Usage;
+use if $ENV{DEBUG} => "Smart::Comments";
+use Cwd qw(abs_path);
+use File::Path qw(make_path);
+use File::Basename;
+use Getopt::Long;
+use Net::LibIDN qw(:all);
use DNStools::Config qw(get_config);
-
-my %config;
+use Template;
-if (@ARGV < 2) {
- print "usage: zone-mk kundennummer domain ... \n";
- exit 1;
-}
+my $CHARSET = "UTF-8";
+
+my $opt_force = 0;
+
+MAIN: {
+
+ my %cf = get_config;
-# oeffnet Konfigurations- und Templatefiles - relativ oder absolut
-my @templc = (
- "$FindBin::Bin/templates/named.config",
- "/etc/dnstools/templates/named.config"
-);
-my @templz =
- ("$FindBin::Bin/templates/named.zone", "/etc/dnstools/templates/named.zone");
+ GetOptions(
+ "f|force" => \$opt_force,
+ "h|help" => sub { pod2usage(-verbose => 1, -exit => 0) },
+ "m|man" => sub {
+ pod2usage(
+ -verbose => 2,
+ -noperldoc => system("perldoc -V &>/dev/null"),
+ -exit => 0
+ );
+ },
+ )
+ and @ARGV >= 2
+ or pod2usage;
-for (grep { -f } @templc) {
- open(TEMPCONF, $_) or die "Can't open $_: $!\n";
-}
-unless (seek(TEMPCONF, 0, 0)) {
- die "Can't open template (searched: @templc)\n";
-}
+ my $customer = shift;
+
+ die "$cf{master_dir}: $!" if not -d -r -x $cf{master_dir};
+ die "$cf{zone_conf_dir}: $!" if not -d -r -x $cf{zone_conf_dir};
-for (grep { -f } @templz) {
- open(TEMPZONE, $_) or die "Can't open $_: $!\n";
-}
-unless (seek(TEMPZONE, 0, 0)) {
- die "Can't open template (searched: @templz)\n";
-}
+ # legt fuer jede domain in @ARGV ein verzeichnis in $master_dir an.
+ # schreibt aus den angegebenen templates die dateien $zonefile und $config
+ # in die entsprechenden verzeichnisse.
+ for my $utf8domain (@ARGV) {
+
+ my $domain = idn_to_ascii($utf8domain, $CHARSET);
+ my $zonefile = "$cf{master_dir}/$domain/$domain";
+ my $configfile = "$cf{zone_conf_dir}/$domain";
+ my $now = time;
+ make_path dirname $zonefile;
-%config = get_config();
+ if (-f $zonefile and not $opt_force) {
+ say "skipping $utf8domain: zone file '$zonefile' exists.";
+ next;
+ }
+
+ if (-f $configfile and not $opt_force) {
+ say "skipping $utf8domain: config file '$configfile' exists.";
+ next;
+ }
-my $primary = $config{primary};
-my $secondary = $config{secondary};
-my $zone_conf_dir = $config{zone_conf_dir};
-my $master_dir = $config{master_dir};
-my $customer = shift @ARGV;
-chomp(my $primary_ip = `dig +short $primary`);
-chomp(my $secondary_ip = `dig +short $secondary`);
-chomp(my $this_host = `hostname -f`);
-chomp(my $this_ip = `hostname -i`);
-chomp(my $this_domain = `hostname -d`);
-chomp(my $time = `date +%Y%m%d00`);
-chomp(my $start = `date -I`);
-my $hostmaster = "hostmaster.$this_domain";
+ say "domain $utf8domain ($domain) for $customer.";
-unless (-d $master_dir and -r $master_dir) {
- die "$master_dir: $!\n";
+ my %vars = (
+ domain => $domain,
+ utf8domain => $utf8domain,
+ now => $now,
+ zonefile => abs_path($zonefile),
+ customer => $customer,
+ hostmaster => $cf{hostmaster},
+ primary => $cf{primary},
+ secondary => $cf{secondary},
+ );
+
+ my $tt = Template->new(INCLUDE_PATH => $cf{template_dir})
+ or die "$Template::ERROR\n";
+
+ $tt->process("named.zone", \%vars, $zonefile) || die $tt->error;
+ $tt->process("named.config", \%vars, $configfile) || die $tt->error;
+
+ }
+
}
-unless (-d $zone_conf_dir and -r $zone_conf_dir) {
- die "$master_dir: $!\n";
-}
+__END__
+
+=head1 NAME
-# legt fuer jede domain in @ARGV ein verzeichnis in $master_dir an.
-# schreibt aus den angegebenen templates die dateien $zonefile und $config
-# in die entsprechenden verzeichnisse.
-for (@ARGV) {
+ zone-mk - create a new zone
- chomp(my $domain = `idn --quiet "$_"`);
- my $zonefile = "$master_dir/$domain/$domain";
- my $config = "$zone_conf_dir/$domain";
- my $utf8domain = "$_";
+=head1 SYNOPSIS
- unless (-d "$master_dir/$domain") {
- `mkdir $master_dir/$domain`;
- }
+ zone-mk [-f|--force] <customer-id> <domain>...
+
+=head1 DESCRIPTION
- if (-f $zonefile) {
- $zonefile =~ s#/.*/##;
- print "$zonefile exists. Skipping $domain\n";
- next;
- }
- if (-f $config) {
- $config =~ s#/.*/##;
- print "$config exists. Skipping $domain\n";
- next;
- }
+B<zone-mk> creates a new DNS zone file and the config snipped.
- print "$domain ($_) for $customer \n";
+=head1 OPTIONS
- my @tempzone = <TEMPZONE>;
- for (@tempzone) {
- s#<start>#$start#;
- s#<domain>#$domain#;
- s#<time>#$time#;
- s#<primary>#$primary#;
- s#<secondary>#$secondary#;
- s#<hostmaster>#$hostmaster#;
- s#<customer>#$customer#;
- s#<utf8domain>#$utf8domain#;
- }
+=over
+
+=item B<-f>|B<--force>
- open(ZONEOUT, ">$zonefile");
- print ZONEOUT @tempzone;
- close(ZONEOUT);
+Crate zone file and config even if they exist. (default: off)
+
+=item B<-h>|B<--help>
- my @tempconf = <TEMPCONF>;
- for (@tempconf) {
- s#<domain>#$domain#;
- s#<start>#$start#;
- s#<customer>#$customer#;
- s#<utf8domain>#$utf8domain#;
- s#<file>#$master_dir/$domain/$domain#;
- s#<primary_ip>#$primary_ip#;
- s#<secondary_ip>#$secondary_ip#;
- }
+=item B<-m>|B<--man>
+
+=back
- open(CONFOUT, ">$config");
- print CONFOUT @tempconf;
- close(CONFOUT);
-}
+=head1 FILES
+
+The F<dnstools.conf> is used.
+
+=cut
--- a/dnstools.conf.example Sat Jan 22 00:05:44 2011 +0100
+++ b/dnstools.conf.example Sun Jan 23 00:21:14 2011 +0100
@@ -1,16 +1,19 @@
-bind_dir = ./bind # bind-Hauptverzeichnis
-master_dir = ./bind/master # Verzeichnis für die einzelnen Zonen-Verzeichnisse
-zone_conf_dir = ./bind/zones.d # Verzeichnis für die Zonen-Konfigurationdateien
+bind_dir = ./bind # bind's config directory (named.conf)
+master_dir = ./bind/master # location of the master zone directories
+zone_conf_dir = ./bind/zones.d # location of configs for the zones
key_counter_end = 15 # Anzahl der Signierungen bis zum Key-Rollover
sign_alert_time = 168 # Warn-Zeitraum vor dem Ablauf einer Zone-Signatur in h
abl_zeit = 24 # Dauer des Key-Rollover (2 Schluessel) in h
secondary = hh.schlittermann.de
-primary = pu.schlittermann.de
+primary = pu.schlittermann.de
+hostmaster = hostmaster@schlittermann.de
indexzone = idx.net.schlittermann.de # Name der Indexdatei
+template_dir = ./templates
+
#this_host
#this_ip
#this_domain
--- a/lib/DNStools/Config.pm Sat Jan 22 00:05:44 2011 +0100
+++ b/lib/DNStools/Config.pm Sun Jan 23 00:21:14 2011 +0100
@@ -12,12 +12,9 @@
# read configuration
my @configs =
- @_
- ? @_
- : (
- $ENV{DNSTOOLS_CONF}, "dnstools.conf",
- "$ENV{HOME}/.dnstools.conf", "/etc/dnstools.conf"
- );
+ @_ ? @_
+ : defined $ENV{DNSTOOLS_CONF} ? $ENV{DNSTOOLS_CONF}
+ : ("dnstools.conf", "$ENV{HOME}/.dnstools.conf", "/etc/dnstools.conf");
my %config;
# the first config FILE
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/t/01-zone-mk Sun Jan 23 00:21:14 2011 +0100
@@ -0,0 +1,39 @@
+use strict;
+use warnings;
+
+use Test::More;
+use File::Temp;
+use Net::LibIDN qw(:all);
+
+my $CMD = "perl -Mblib blib/script/zone-mk";
+
+system("$CMD -h &>/dev/null");
+is($? => 0, "exit on help");
+
+system("$CMD -m &>/dev/null");
+is($? => 0, "exit on man");
+
+system("$CMD &>/dev/null");
+ok($? > 0, "error on missing args");
+
+my $master_dir = File::Temp->newdir;
+my $config_dir = File::Temp->newdir;
+my $tmp = File::Temp->new;
+$ENV{DNSTOOLS_CONF} = $tmp->filename;
+
+print $tmp <<__EOF;
+master_dir = $master_dir
+zone_conf_dir = $config_dir
+hostmaster = hostmaster\@schlittermann.de
+template_dir = ./templates
+__EOF
+
+system("$CMD xxx müller.de &>/dev/null");
+is($? => 0, "created zone");
+
+my $domain = idn_to_ascii("müller.de", "UTF-8");
+ok(-s "$master_dir/$domain/$domain", "zone file $domain");
+ok(-s "$config_dir/$domain", "config file $domain");
+
+
+done_testing;
--- a/templates/named.config Sat Jan 22 00:05:44 2011 +0100
+++ b/templates/named.config Sun Jan 23 00:21:14 2011 +0100
@@ -1,10 +1,10 @@
-zone "<domain>" {
-// Start: <start>
-// Invoice: <customer>
-// UTF8: <utf8domain>
+[% USE iso = date(format => '%Y-%m-%dT%H:%M:%S') -%]
+zone "[% domain %]" {
+// Start: [% iso.format(now) %]
+// Invoice: [% customer %]
+// UTF8: [% utf8domain %]
type master;
- file "<file>";
- allow-transfer { localhost; <primary_ip>; <secondary_ip>; };
+ file "[% zonefile %]";
+ allow-transfer { localhost; slaves; };
allow-query { any; };
- also-notify { <primary_ip>; };
};
--- a/templates/named.zone Sat Jan 22 00:05:44 2011 +0100
+++ b/templates/named.zone Sun Jan 23 00:21:14 2011 +0100
@@ -1,17 +1,19 @@
-$ORIGIN <domain>.
+[% USE iso = date(format => '%Y-%m-%dT%H:%M:%S') %]
+[% USE serial = date(format => '%Y%m%d00') -%]
+$ORIGIN [% domain %].
$TTL 1d
-@ IN SOA <primary>. <hostmaster>. (
- <time> ; serial
+@ IN SOA [% primary %]. [% hostmaster %]. (
+ [% serial.format(now) %] ; serial
1d ; refresh
2h ; retry
7d ; expire
- 1d ; default ttl
+ 5m ; negative ttl
)
- IN TXT "invoice: <customer>"
- IN TXT "start: <start>"
- IN TXT "utf8: <utf8domain>"
+ IN TXT "invoice: [% customer %]"
+ IN TXT "start: [% now %] [% iso.format(now) %]
+ IN TXT "utf8: [% utf8domain %]"
- IN NS <primary>.
- IN NS <secondary>.
+ IN NS [% primary %].
+ IN NS [% secondary %].