zone-mk works now hs12
authorHeiko Schlittermann <hs@schlittermann.de>
Sun, 23 Jan 2011 00:21:14 +0100
branchhs12
changeset 87 6d624831079f
parent 86 dc8741bbad33
child 88 0e1e5027e9c0
child 89 6c76123f3901
zone-mk works now
Build.PL
bin/zone-mk
dnstools.conf.example
lib/DNStools/Config.pm
t/01-zone-mk
templates/named.config
templates/named.zone
--- 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 %].