aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorJoachim Tingvold <joachim@tingvold.com>2014-04-06 03:11:04 +0200
committerJoachim Tingvold <joachim@tingvold.com>2014-04-06 03:11:04 +0200
commit2a0c0a3dbbdf7fa5040953c0b0d88ad6f62c011e (patch)
tree92c7cbf54272466b46f64e5dc8d1ddb429858836 /tools
parentfe0be5960aac1f9bb600dbf853d862a9f4e60de8 (diff)
Initial commit. Source; TG13-goodiebag.
Diffstat (limited to 'tools')
-rw-r--r--tools/README139
-rw-r--r--tools/TODO26
-rwxr-xr-xtools/apply-baseupdate.sh14
-rwxr-xr-xtools/create-shellconf.pl51
-rwxr-xr-xtools/dhcp6-nets.pl12
-rwxr-xr-xtools/dlink-ng2dns.pl77
-rwxr-xr-xtools/fetch-debinstall.sh17
-rwxr-xr-xtools/fetch-portlist.sh42
-rwxr-xr-xtools/generate-dnsrr.pl147
-rwxr-xr-xtools/init-sshkeys.sh14
-rwxr-xr-xtools/install-dependencies.sh53
-rwxr-xr-xtools/make-accesspoints.pl24
-rwxr-xr-xtools/make-base-requires.sh60
-rwxr-xr-xtools/make-bind-include.pl51
-rwxr-xr-xtools/make-dhcpd-include.pl18
-rwxr-xr-xtools/make-dhcpd.pl104
-rwxr-xr-xtools/make-first-zones.pl124
-rwxr-xr-xtools/make-linknet-hosts.pl34
-rwxr-xr-xtools/make-missing-conf.pl187
-rwxr-xr-xtools/make-named.pl156
-rwxr-xr-xtools/make-pxeboot.sh26
-rwxr-xr-xtools/make-reverse4-files.pl164
-rwxr-xr-xtools/make-switch-placements.pl88
-rwxr-xr-xtools/make-switches.pl33
-rwxr-xr-xtools/update-baseservice.sh29
-rwxr-xr-xtools/update-tools.sh21
26 files changed, 1711 insertions, 0 deletions
diff --git a/tools/README b/tools/README
new file mode 100644
index 0000000..2276ebb
--- /dev/null
+++ b/tools/README
@@ -0,0 +1,139 @@
+Outline:
+------------------------------------------------------------------
+
+ 1 Install OS on three boxes
+ 2 Bootstrap:
+ * Install tgmanage on one, the bootstrap (tools, include, netlist.txt)
+ * Install dependencies on bootstrap
+ * Push SSH key key to the other boxes (init-sshkeys.sh)
+ * Update configuration
+ * Update netlist.txt
+ * Bootstrap the primary and secondary (make-base-requires.sh)
+ 3 Create new networks/scopes/zones Update during the party using
+ update-baseservice.sh from bootstrap
+ 4 Apply changes usling tools/apply-baseupdate.sh (reloads bind, restarts dhcpd)
+ 5 Changes to generated scopes, pools, zones are done on the primary, in the files
+ 6 If tools need patching, patch on boot and push with update-tools.sh
+ 7 Before wednesday evening, the infra.tgXX.gathering.org zone should be updated!
+ * Only use make-base-requires.sh during bootstrap !!!!!!! :P
+
+Detailed instructions and description:
+==================================================================
+
+1: Install Debian
+------------------------------------------------------------------
+
+The following three hosts/servers are normally used:
+ * A 'bootstrap' box. This server will be used to configure
+ the first TG-servers, and may end up hosting the switch-config and NMS.
+ * The server to use as Primary DNS and DHCP server
+ * The server to use as Secondary DNS and SMTP.
+Add the three hosts to /etc/hosts, DNS is not available yet...
+
+2: Perform bootstrapping.
+------------------------------------------------------------------
+
+Start by placing the 'tgmanage' directory as '/root/tgmanage' on the bootstrap
+box. Change into the 'tgmanage' directory. Next, run
+'tools/install-dependencies.sh boot'
+
+
+Edit 'include/config.local.pm' and update for this year's TG. Use
+'tools/create-shellconf.pl' to extract configuration from the perl module to
+create/update the 'include/tgmanage.cfg.sh' configuration script.
+
+
+The tools make extensive use of key-based SSH logins, to make this work
+seamlessly, run 'tools/init-sshkeys.sh' to create an RSA priv/pub keypair, and
+push the pubkey to the Primary and Secondary boxes.
+
+
+The Network-list is _not_ automagically updated. A copy of last year's
+netlist.txt should be included in the goodiebag. With that as a base, update
+for this year's address plan. Remember that client nets in the hall are
+supposed to be pulled from switches.txt ...
+The rest of the information needed should be pulled from techwiki.g.o The
+format of the file is: one net per line, lines starting with # are skipped,
+format of each net-line is:
+176.110.124.0 24 noc
+# <network adress> <prefixlen> <network-name>
+
+
+Run 'tools/make-base-requires.sh'. This script will log in on the Primary and
+Secondary boxes, install dependencies and the BIND/DHCP packages, create all
+needed directories, create the initial configuration files.
+
+A short listing of the tasks of scripts called by make-base-requires:
+tools/install-dependencies.sh Installs needed base software to boot, primary and secondary
+tools/make-named.pl Basic BIND setup (creates named.conf et.al)
+tools/make-first-zones.pl Creates static zone-files (tgname, infra, ipv6zone)
+tools/make-reverse4-files.pl Creates reverse-zones for IPv4
+tools/make-dhcpd.pl Sets up the base setup for DHCP
+NOTE: these scripts are run by tools/make-base-requires.sh, you should not need to
+run these individually
+
+3++: Update during the party using update-baseservice.sh from bootstrap
+------------------------------------------------------------------
+
+After 'tools/make-base-requires.sh' has been run, further updating should be
+managed by the following three files:
+tools/update-baseservice.sh Used to add/update bind and DHCP configuration
+tools/apply-baseupdate.sh Used to reload bind and restart DHCP
+tools/update-tools.sh Used to push changes to the tgmanage toolchain
+
+This means, after the base setup is completed, updating and managing the
+configuration is done by updating netlist.txt and running tools/update-baseservice.sh
+from the bootstrap box, or from the NMS box if the toolchain gets moved there during
+the party.
+
+To create a new DHCP scope, add DNS forward and reverse zone for a new network:
+
+ * Add the network to netlist.txt
+ * Run tools/update-baseservice.sh to generate new .conf and .zone files
+ * Run tools/apply-baseupdate.sh to load new configuration
+
+To do changes to DHCP config after the scope .conf file has been created
+(read: later in the party), log in to the primary/dhcp server, and make
+the changes in the appropriate .conf file ..
+
+To do DNS changes to the main DNS zone or the infra-zone, make the changes
+in the appropriate zone file on the primary DNS server.
+
+To add DNS records to any other DNS zone (forward or reverse), you have
+to use 'nsupdate'. To simplify the process, use tools/generate-dnsrr.pl
+Usage on this tool is documented in the "header" of the script...
+
+
+The update prosess is handled by a bunch of "sub-tools", these should typically
+not need to be run individually:
+tools/make-bind-include.pl Run via update-baseservice, adds new net's to DNS include
+tools/make-dhcpd-include.pl Run via update-baseservice, adds new net's to DHCP include
+tools/make-missing-conf.pl Run via update-baseservice, adds missing net-conf to BIND/DHCP
+
+
+7: Generation of linknet dns content
+------------------------------------------------------------------
+
+Format for linknet.txt is documented in make-linknet-hosts.pl
+
+Generate IPv4 infra hostnames and IP address assignments
+by using tools/generate-dnsrr.pl
+
+> cat linknet.txt | tools/make-linknet-hosts.pl | tools/generate-dnsrr.pl --domain infra.tgXX.gathering.org
+Output from this shuld go in infra.tgXX.gathering.org.zone on primary
+
+> cat linknet.txt | tools/make-linknet-hosts.pl | tools/generate-dnsrr.pl --domain infra.tgXX.gathering.org -ns -rev
+Output from this should go as input to nsupdate, see doc in generate-dnsrr.pl
+
+
+Other stuff....
+------------------------------------------------------------------
+Files that are not used? Need to revisit these files...
+
+>tools/make-switch-placements.pl
+
+Updates positions for switches in NMS map (png)
+
+> tools/make-switches.pl
+> tools/fetch-portlist.sh
+
diff --git a/tools/TODO b/tools/TODO
new file mode 100644
index 0000000..70898a3
--- /dev/null
+++ b/tools/TODO
@@ -0,0 +1,26 @@
+make-first-zones.pl does not add AAAA records for NS'es (pri/sec)
+None of the tools add IPv4 reverse for pri/sec
+nsupdate log for adding reverse after building base-requires:
+
+ nsupdate -k Kdhcp_updater.+157+57267.key
+ server 176.110.126.2
+ prereq nxdomain 2.126.110.176.in-addr.arpa.
+ update add 2.126.110.176.in-addr.arpa. 3600 in ptr abscess.tg12.gathering.org.
+ send
+ prereq nxdomain 2.125.110.176.in-addr.arpa.
+ update add 2.125.110.176.in-addr.arpa. 3600 in ptr acetat.tg12.gathering.org.
+ send
+ prereq nxdomain 3.125.110.176.in-addr.arpa.
+ update add 3.125.110.176.in-addr.arpa. 3600 in ptr abc.tg12.gathering.org.
+ send
+
+Another handy dump, not a TODO-item, just a reminder:
+
+ prereq nxdomain 3.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.5.2.1.0.a.6.7.0.8.9.7.0.1.0.a.2.ip6.arpa.
+ update add 3.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.5.2.1.0.a.6.7.0.8.9.7.0.1.0.a.2.ip6.arpa. 3600 IN PTR abc.tg12.gathering.org.
+ send
+
+
+Uhm, our $dhcp_server1 = "176.110.126.2"; <- wtf?
+
+Opps, forgot to asdd CiscoWLC magic to make-dhcpd.pl includes...
diff --git a/tools/apply-baseupdate.sh b/tools/apply-baseupdate.sh
new file mode 100755
index 0000000..055320c
--- /dev/null
+++ b/tools/apply-baseupdate.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+set -e
+
+source include/tgmanage.cfg.sh
+if [ -z ${PRIMARY} ]
+then
+ echo "Not configured!";
+ exit 1;
+fi;
+
+ssh -l root ${PRIMARY} "/etc/init.d/isc-dhcp-server restart"
+ssh -l root ${PRIMARY} "/usr/sbin/rndc reload"
+ssh -l root ${SECONDARY} "/usr/sbin/rndc reload"
diff --git a/tools/create-shellconf.pl b/tools/create-shellconf.pl
new file mode 100755
index 0000000..8e2582d
--- /dev/null
+++ b/tools/create-shellconf.pl
@@ -0,0 +1,51 @@
+#!/usr/bin/perl -I /root/tgmanage
+use strict;
+
+BEGIN {
+ require "include/config.pm";
+ eval {
+ require "include/config.local.pm";
+ };
+}
+
+my $bind_base = "/etc/bind/";
+my $dhcpd_base = "/etc/dhcp/";
+
+my $shellconf_file = "include/tgmanage.cfg.sh";
+
+my $tgname = $nms::config::tgname;
+
+my $pri_a = $nms::config::pri_a;
+my $pri_ptr = $nms::config::pri_ptr;
+my $pri_v6 = $nms::config::pri_v6;
+
+my $sec_a = $nms::config::sec_a;
+my $sec_ptr = $nms::config::sec_ptr;
+my $sec_v6 = $nms::config::sec_v6;
+
+my $ddns_key = $nms::config::ddns_key;
+
+my $base_ipv4net = $nms::config::base_ipv4net;
+my $base_ipv4prefix = $nms::config::base_ipv4prefix;
+
+my $base_ipv6net = $nms::config::base_ipv6net;
+my $base_ipv6prefix = $nms::config::base_ipv6prefix;
+
+open CFG, ">" . $shellconf_file or die ($! . " " . $shellconf_file );
+
+print CFG "# This file is autogenerated by tools/create-shellconf.pl,\n";
+print CFG "# using data from nms::config.\n";
+print CFG "#\n";
+print CFG "# Do you need new common/configuration variables?\n";
+print CFG "# Add/update include/config.local.pm and tools/create-shellconf.pl\n\n";
+print CFG "PRIMARY=\"$pri_a.$tgname.gathering.org\"\n";
+print CFG "SECONDARY=\"$sec_a.$tgname.gathering.org\"\n";
+print CFG "TGNAME=\"$tgname\"\n\n";
+print CFG "PRI_PTR=\"$pri_ptr\"\n";
+print CFG "SEC_PTR=\"$sec_ptr\"\n\n";
+print CFG "DDNS_KEY=\"$ddns_key\"\n\n";
+print CFG "BASEV4=\"$base_ipv4net\"\n";
+print CFG "PREFIXV4=\"$base_ipv4prefix\"\n";
+print CFG "BASEV6=\"$base_ipv6net\"\n";
+print CFG "PREFIXV6=\"$base_ipv6prefix\"\n";
+close CFG;
diff --git a/tools/dhcp6-nets.pl b/tools/dhcp6-nets.pl
new file mode 100755
index 0000000..3866ac5
--- /dev/null
+++ b/tools/dhcp6-nets.pl
@@ -0,0 +1,12 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+
+while(<STDIN>){
+ my ($row, $v6) = split;
+ $v6 =~ s/::1/::/;
+
+ print "subnet6 $v6 {\n";
+ print "\toption domain-name \"$row.tg13.gathering.org\";\n";
+ print "}\n\n";
+}
diff --git a/tools/dlink-ng2dns.pl b/tools/dlink-ng2dns.pl
new file mode 100755
index 0000000..2b6f965
--- /dev/null
+++ b/tools/dlink-ng2dns.pl
@@ -0,0 +1,77 @@
+#!/usr/bin/perl
+use strict;
+
+BEGIN {
+ require "include/config.pm";
+ eval {
+ require "include/config.local.pm";
+ };
+}
+
+use Net::IP;
+use Getopt::Long;
+
+my ($delete);
+
+if (@ARGV > 0) {
+ GetOptions(
+ 'del|delete' => \$delete,
+ )
+}
+
+print "server $nms::config::pri_ptr\n";
+
+while (<STDIN>)
+{
+ my ( $sysname, $distro, $ponum, $cidr, $ipaddr, $gwaddr, $v6addr, @ports ) = split;
+
+
+ my $ip = new Net::IP($ipaddr);
+
+ my $v4gw = new Net::IP($gwaddr);
+
+ ( my $gw6 = $v6addr ) =~ s/\/.*//;
+ my $v6gw = new Net::IP($gw6);
+
+ my $fqdn = $sysname . "." . $nms::config::tgname . ".gathering.org.";
+ my $sw_fqdn = $sysname . "-sw." . $fqdn;
+ my $text_info = $distro . " - " . join(' + ', @ports) . ", po" . $ponum . ", gwaddr " . $gwaddr;
+
+ # A-record to the switch
+ print "prereq nxdomain " . $sw_fqdn . "\n" unless $delete;
+ print "update add " . $sw_fqdn . " \t 3600 IN A \t " . $ipaddr . "\n" unless $delete;
+ print "update delete " . $sw_fqdn . " \t IN A\n" if $delete;
+ print "send\n";
+
+ # PTR to the switch
+ print "prereq nxdomain " . $ip->reverse_ip() . "\n" unless $delete;
+ print "update add " . $ip->reverse_ip() . " \t 3600 IN PTR \t " . $sw_fqdn . "\n" unless $delete;
+ print "update delete " . $ip->reverse_ip() . " \t IN PTR\n" if $delete;
+ print "send\n";
+
+ # TXT-record with details
+ print "update delete " . $sw_fqdn . " IN TXT\n" unless $delete;
+ print "update add " . $sw_fqdn . " \t 3600 IN TXT \t \"" . $text_info . "\"\n" unless $delete;
+ print "update delete " . $sw_fqdn . " \t IN TXT\n" if $delete;
+ print "send\n";
+
+ # A and AAAA-record to the gateway/router
+ print "prereq nxrrset gw." . $fqdn . " IN A\n" unless $delete;
+ print "update add gw." . $fqdn . " \t 3600 IN A \t " . $gwaddr . "\n" unless $delete;
+ print "update delete gw." . $fqdn . " \t IN A\n" if $delete;
+ print "send\n";
+ print "prereq nxrrset gw." . $fqdn . " IN AAAA\n" unless $delete;
+ print "update add gw." . $fqdn . " \t 3600 IN AAAA \t " . $gw6 . "\n" unless $delete;
+ print "update delete gw." . $fqdn . " \t IN AAAA\n" if $delete;
+ print "send\n";
+
+ # PTR to the gateway/router
+ print "prereq nxdomain " . $v4gw->reverse_ip() . "\n" unless $delete;
+ print "update add " . $v4gw->reverse_ip() . " \t 3600 IN PTR \t gw." . $fqdn . "\n" unless $delete;
+ print "update delete " . $v4gw->reverse_ip() . " \t IN PTR\n" if $delete;
+ print "send\n";
+ print "prereq nxdomain " . $v6gw->reverse_ip() . "\n" unless $delete;
+ print "update add " . $v6gw->reverse_ip() . " \t 3600 IN PTR \t gw." . $fqdn . "\n" unless $delete;
+ print "update delete " . $v6gw->reverse_ip() . " \t IN PTR\n" if $delete;
+ print "send\n";
+}
diff --git a/tools/fetch-debinstall.sh b/tools/fetch-debinstall.sh
new file mode 100755
index 0000000..069e39a
--- /dev/null
+++ b/tools/fetch-debinstall.sh
@@ -0,0 +1,17 @@
+#!/bin/bash -xe
+INSTALLER_DEST=$1
+DEBINSTROOT=http://ftp.no.debian.org/debian/dists
+
+mkdir -p ${INSTALLER_DEST}/{squeeze,wheezy}/{amd64,i386}
+for DIST in squeeze wheezy
+do
+ for ARCH in i386 amd64;
+ do
+ for FILE in initrd.gz linux
+ do
+ wget ${DEBINSTROOT}/${DIST}/main/installer-${ARCH}/current/images/netboot/debian-installer/${ARCH}/${FILE} \
+ -O ${INSTALLER_DEST}/${DIST}/${ARCH}/${FILE}
+ done
+ done
+done
+
diff --git a/tools/fetch-portlist.sh b/tools/fetch-portlist.sh
new file mode 100755
index 0000000..94ca41c
--- /dev/null
+++ b/tools/fetch-portlist.sh
@@ -0,0 +1,42 @@
+print_range() {
+ FIRST=$1
+ LAST=$2
+ if [ "$1" = "$2" ]; then
+ echo $FIRST
+ else
+ echo $FIRST-$LAST
+ fi
+}
+
+walk_ports() {
+ IP=$1
+ COMMUNITY=$2
+
+ FIRST_PORT=
+ LAST_PORT=
+
+ for PORT in $( snmpwalk -Os -m IF-MIB -v 2c -c $COMMUNITY $IP ifDescr 2>/dev/null | grep -E 'GigE|Ethernet' | cut -d. -f2 | cut -d" " -f1 ); do
+ if ! snmpget -m IF-MIB -v 2c -c $COMMUNITY $IP ifHCInOctets.$PORT 2>/dev/null | grep -q 'No Such Instance'; then
+ if [ "$LAST_PORT" ] && [ `expr $LAST_PORT + 1` = $PORT ]; then
+ LAST_PORT=$PORT
+ else
+ if [ "$LAST_PORT" ]; then
+ print_range $FIRST_PORT $LAST_PORT
+ fi
+ FIRST_PORT=$PORT
+ LAST_PORT=$PORT
+ fi
+ fi
+ done
+
+ print_range $FIRST_PORT $LAST_PORT
+}
+
+COMMUNITY=$1
+IP=$2
+SYSNAME=$3
+PORTS=$( walk_ports $IP $COMMUNITY | tr "\n" "," | sed 's/,$//' )
+
+echo "insert into switchtypes values ('$SYSNAME','$PORTS',true);"
+echo "insert into switches values (default,'$IP','$SYSNAME','$SYSNAME',null,default, default, '1 minute', '$COMMUNITY');"
+
diff --git a/tools/generate-dnsrr.pl b/tools/generate-dnsrr.pl
new file mode 100755
index 0000000..789f268
--- /dev/null
+++ b/tools/generate-dnsrr.pl
@@ -0,0 +1,147 @@
+#!/usr/bin/perl -I /root/tgmanage
+#
+# USAGE:
+# Generate BIND Zone-file data based on the file hosts-to-add.txt
+# cat hosts-to-add.txt | tools/generate-dnsrr.pl
+#
+# Generate input data for nsupdate, to add FORWARD records based on hosts-to-add.txt
+# cat hosts-to-add.txt | tools/generate-dnsrr.pl --domain foo.tgXX.gathering.org -ns
+#
+# Generate input data for nsupdate, to add REVERSE records based on hosts-to-add.txt
+# cat hosts-to-add.txt | tools/generate-dnsrr.pl --domain foo.tgXX.gathering.org -ns -rev
+#
+# Generate input data for nsupdate, to DELETE forward records based on hosts-to-add.txt
+# cat hosts-to-DELETE.txt | tools/generate-dnsrr.pl --domain foo.tgXX.gathering.org -ns -del
+#
+# Generate input data for nsupdate, to DELETE reverse records based on hosts-to-add.txt
+# cat hosts-to-DELETE.txt | tools/generate-dnsrr.pl --domain foo.tgXX.gathering.org -ns -rev -del
+#
+# Command-syntax to send this to nsupdate, running it on the DNS server:
+# cat file.txt | tools/generate-dnsrr.pl --dom foo -ns | ssh $dnsserver "nsupdate -k /etc/bind/Kdhcp_updater.+157+XXXXX"
+#
+# Format of input:
+# hostname ipv4-adress ipv6-address
+# If any of ipv4-address or ipv6-address are NOT set for the host, specify "nope"
+# Lines starting with # will (should) be skipped (comments)
+#
+# Example:
+#
+# host1 192.168.0.1 2001:db8:f00::1
+# host2 nope 2001:db8:f00::2
+# host3 192.168.0.3 nope
+# # comment, to be ignored.
+# host4 192.168.0.4
+
+use strict;
+use warnings;
+use lib '..';
+BEGIN {
+ require "include/config.pm";
+ eval {
+ require "include/config.local.pm";
+ };
+}
+use Net::IP;
+use Getopt::Long;
+
+my ($delete, $auto, $nsupdate, $reverse, $domain);
+
+if (@ARGV > 0) {
+ GetOptions(
+ 'del|delete' => \$delete,
+ 'a|auto' => \$auto,
+ 'ns|nsupdate' => \$nsupdate,
+ 'r|reverse' => \$reverse,
+ 'domain=s' => \$domain
+ )
+}
+
+if ($nsupdate || $reverse){
+ unless (defined($domain)){
+ print "Missing domain.\n";
+ exit 1 unless defined($domain);
+ }
+}
+
+$domain = "." . $domain if defined($domain);
+
+print "server $nms::config::pri_ptr\n" if ($nsupdate || $reverse);
+
+while (<STDIN>) {
+ next if /^(#|\s+$)/; # skip if comment, or blank line
+
+ my ($hostname, $ipv4, $ipv6) = split;
+ $hostname = lc($hostname);
+
+ unless ($ipv6){
+ if ($auto){
+ # Get IPv6-address based on IPv4-address
+
+ my ($first, $second, $third, $fourth) = split('\.', $ipv4);
+ $ipv6 = $nms::config::base_ipv6net . $third . "::" . $fourth;
+ }
+ }
+
+ if ($reverse){
+ # print ptr
+ print_ptr($hostname, $ipv4, $ipv6);
+ } else {
+ # print forward
+ print_fwd($hostname, $ipv4, $ipv6);
+ }
+}
+
+sub print_ptr{
+ my ($hostname, $ipv4, $ipv6) = @_;
+
+ # IPv4
+ unless ( $ipv4 eq "nope" ) {
+ my $v4 = new Net::IP($ipv4);
+
+ print "prereq nxdomain " . $v4->reverse_ip() . "\n" unless $delete;
+ print "update add " . $v4->reverse_ip() . " 3600 IN PTR " . $hostname . $domain .".\n" unless $delete;
+ print "update delete " . $v4->reverse_ip() . " IN PTR\n" if $delete;
+ print "send\n";
+ }
+
+ # IPv6
+ if (( not ($ipv6 eq "nope") ) && ( $ipv6 )) {
+ my $v6 = new Net::IP($ipv6);
+
+ print "prereq nxdomain " . $v6->reverse_ip() . "\n" unless $delete;
+ print "update add " . $v6->reverse_ip() . " 3600 IN PTR " . $hostname . $domain . ".\n" unless $delete;
+ print "update delete " . $v6->reverse_ip() . " IN PTR\n" if $delete;
+ print "send\n";
+ }
+}
+
+sub print_fwd{
+ my ($hostname, $ipv4, $ipv6) = @_;
+
+ if ($nsupdate){
+
+ unless ( $ipv4 eq "nope" ) {
+ # IPv4
+ print "prereq nxrrset " . $hostname . $domain . " IN A\n" unless $delete;
+ print "update add " . $hostname . $domain . " 3600 IN A $ipv4\n" unless $delete;
+ print "update delete " . $hostname . $domain . " IN A\n" if $delete;
+ print "send\n";
+ }
+ if (( not ($ipv6 eq "nope") ) && ( $ipv6 )) {
+ # IPv6
+ print "prereq nxrrset " . $hostname . $domain . " IN AAAA\n" unless $delete;
+ print "update add " . $hostname . $domain . " 3600 IN AAAA $ipv6\n" unless $delete;
+ print "update delete " . $hostname . $domain . " IN AAAA\n" if $delete;
+ print "send\n";
+ }
+ } else {
+ # IPv4
+ unless ( $ipv4 eq "nope" ) {
+ printf ("%-24s%s\t%s\t%s\n", $hostname, "IN", "A", $ipv4);
+ }
+ # IPv6
+ if (( not ($ipv6 eq "nope") ) && ( $ipv6 )) {
+ printf ("%-24s%s\t%s\t%s\n", $hostname, "IN", "AAAA", $ipv6) if ($ipv6);
+ }
+ }
+}
diff --git a/tools/init-sshkeys.sh b/tools/init-sshkeys.sh
new file mode 100755
index 0000000..9427bad
--- /dev/null
+++ b/tools/init-sshkeys.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+set -e
+
+source include/tgmanage.cfg.sh
+if [ -z ${PRIMARY} ]
+then
+ echo "Not configured!";
+ exit 1;
+fi;
+
+ssh-keygen -P '' -f ~/.ssh/id_rsa -b 2048
+ssh-copy-id root@${PRIMARY}
+ssh-copy-id root@${SECONDARY}
diff --git a/tools/install-dependencies.sh b/tools/install-dependencies.sh
new file mode 100755
index 0000000..bf68134
--- /dev/null
+++ b/tools/install-dependencies.sh
@@ -0,0 +1,53 @@
+#!/bin/bash -e
+
+if [ "$1" != "master" -a "$1" != "slave" -a "$1" != "boot" ]; then
+ echo "Run as $0 <boot|master|slave>"
+ exit
+fi
+
+# OK, we know the content of $0 is OK. I prefer sane names.
+ROLE=$1;
+
+# Start by installing common packages. Remember to update
+# this when a new common dependency is discovered, plx.
+apt-get -y install \
+ vim-nox \
+ git \
+ ntp \
+ screen \
+ dnsutils \
+ build-essential \
+ libnet-ip-perl \
+ libnetaddr-ip-perl \
+ libnet-telnet-cisco-perl \
+ libnet-ping-external-perl \
+ perl-modules \
+ libdbi-perl \
+ libdbd-pg-perl \
+ libnet-telnet-perl
+
+if [ "${ROLE}" == "boot" ]; then
+ # Install-tasks specific for the _bootstrab box_ here
+ echo "Installing for bootstrap"
+ apt-get -y install \
+ bind9utils
+fi
+
+if [ "${ROLE}" == "master" ]; then
+ # Install-tasks specific for the _primary_ here
+ echo "Installing for primary/master"
+ apt-get -y install \
+ isc-dhcp-server \
+ bind9utils \
+ bind9
+fi
+
+if [ "${ROLE}" == "slave" ]; then
+ # Install-tasks specific for the _secondary_ here
+ echo "Installing for secondary/slave"
+ apt-get -y install \
+ bind9utils \
+ bind9
+fi
+
+echo "Dependency installation for ${ROLE} complete."
diff --git a/tools/make-accesspoints.pl b/tools/make-accesspoints.pl
new file mode 100755
index 0000000..b84321a
--- /dev/null
+++ b/tools/make-accesspoints.pl
@@ -0,0 +1,24 @@
+#! /usr/bin/perl
+use strict;
+use warnings;
+
+while (<>) {
+ my @arr = split " ";
+ my $ap = 'ap-'.$arr[0];
+ my $core = $arr[1];
+ # Trekk fra 1
+ $core =~ s/^(distro)(\d+)$/$1.($2-1)/e;
+
+ # Fjerde kabel er aksesspunkt
+ my $blade;
+ my $port;
+ if ($arr[5] =~ /^Gi(\d+)\/(\d+)$/) {
+ $blade = $1;
+ $port = $2;
+ } else {
+ die "Unknown port: ".$arr[5];
+ }
+ printf "INSERT INTO switches(ip, sysname, switchtype) values(inet '127.0.0.1', '%s', 'ciscoap');\n", $ap;
+ printf "INSERT INTO uplinks SELECT (SELECT switch FROM switches WHERE sysname = '%s') AS switch, (SELECT switch FROM switches WHERE sysname = '%s') AS coreswitch, %d AS blade, %d AS port;\n", $ap, $core, $blade, $port;
+ printf "INSERT INTO ap_poll(switch) SELECT switch FROM switches WHERE sysname = '%s';\n", $ap;
+}
diff --git a/tools/make-base-requires.sh b/tools/make-base-requires.sh
new file mode 100755
index 0000000..d19ffd9
--- /dev/null
+++ b/tools/make-base-requires.sh
@@ -0,0 +1,60 @@
+#!/bin/bash
+
+set -e
+
+BASE="/etc";
+if [ "$1" != "" ]
+then
+ BASE=$1
+ echo "Using base path ${BASE}"
+fi
+
+source include/tgmanage.cfg.sh
+if [ -z ${PRIMARY} ]
+then
+ echo "Not configured!";
+ exit 1;
+fi;
+
+tools/update-tools.sh
+ssh -l root ${PRIMARY} "~/tgmanage/tools/install-dependencies.sh master"
+ssh -l root ${SECONDARY} "~/tgmanage/tools/install-dependencies.sh slave"
+
+if [ "${BASE}" == "/etc" ]; then
+ ssh -l root ${PRIMARY} "cp -pR /etc/bind /etc/bind.dist"
+ ssh -l root ${PRIMARY} "cp -pR /etc/dhcp /etc/dhcp.dist"
+ ssh -l root ${SECONDARY} "cp -pR /etc/bind /etc/bind.dist"
+
+ set +e
+ ssh -l root ${PRIMARY} "rm /etc/bind/named.conf"
+ ssh -l root ${PRIMARY} "rm /etc/dhcp/dhcpd.conf"
+ ssh -l root ${SECONDARY} "rm /etc/bind/named.conf"
+ set -e
+fi
+
+ssh -l root ${PRIMARY} "mkdir -p ${BASE}/bind/conf-master/"
+ssh -l root ${PRIMARY} "mkdir -p ${BASE}/bind/reverse/"
+ssh -l root ${PRIMARY} "mkdir -p ${BASE}/bind/dynamic/"
+ssh -l root ${PRIMARY} "mkdir -p ${BASE}/dhcp/conf.d/"
+ssh -l root ${PRIMARY} "~/tgmanage/tools/make-named.pl master ${BASE}"
+ssh -l root ${PRIMARY} "~/tgmanage/tools/make-dhcpd.pl ${BASE}"
+ssh -l root ${PRIMARY} "~/tgmanage/tools/make-first-zones.pl ${BASE}"
+ssh -l root ${PRIMARY} "~/tgmanage/tools/make-reverse4-files.pl master ${BASE}"
+
+ssh -l root ${SECONDARY} "mkdir -p ${BASE}/bind/conf-slave/"
+ssh -l root ${SECONDARY} "mkdir -p ${BASE}/bind/slave/"
+ssh -l root ${SECONDARY} "~/tgmanage/tools/make-named.pl slave ${BASE}"
+ssh -l root ${SECONDARY} "~/tgmanage/tools/make-reverse4-files.pl slave ${BASE}"
+
+set +e
+ssh -l root ${PRIMARY} "chown -R bind.bind ${BASE}/bind"
+ssh -l root ${SECONDARY} "chown -R bind.bind ${BASE}/bind"
+set -e
+
+ssh -l root ${PRIMARY} "echo THIS COPY OF TGMANAGE IS MANAGED FROM BOOTSTRAP SERVER > ~/tgmanage/NOTICE"
+ssh -l root ${SECONDARY} "echo THIS COPY OF TGMANAGE IS MANAGED FROM BOOTSTRAP SERVER > ~/tgmanage/NOTICE"
+
+# No point in _not_ running update-baseservice at this point....
+tools/update-baseservice.sh ${BASE}
+
+# all done.
diff --git a/tools/make-bind-include.pl b/tools/make-bind-include.pl
new file mode 100755
index 0000000..d688dec
--- /dev/null
+++ b/tools/make-bind-include.pl
@@ -0,0 +1,51 @@
+#!/usr/bin/perl -I /root/tgmanage
+
+# TODO: Port this to the "master|slave base" parameter syntax!
+
+use strict;
+
+unless ( (($#ARGV == 0 ) || ( $#ARGV == 1))
+ && (( $ARGV[0] eq "master" ) || ( $ARGV[0] eq "slave" )) )
+{
+ print STDERR "Invalid usage!\ncat netnames.txt | $0 <master|slave> [basedir]\n";
+ exit 1;
+}
+
+my $role = $ARGV[0];
+
+my $base = "/etc";
+$base = $ARGV[1] if $#ARGV == 1;
+$base .= "/" if not $base =~ m/\/$/ and not $base eq "";
+
+my $bind_base = $base . "bind/";
+my $masterinclude = $bind_base . "named.master-include.conf";
+my $slaveinclude = $bind_base . "named.slave-include.conf";
+
+my $glob;
+my @configs;
+
+if ( $role eq "master" )
+{
+ $glob = $bind_base . "conf-master/*.conf";
+ @configs = glob($glob);
+
+ open CONF, ">" . $masterinclude or die ( $! . " " . $masterinclude);
+ foreach my $config ( @configs )
+ {
+ print CONF "include \"" . $config . "\";\n";
+ }
+ close CONF;
+}
+
+if ( $role eq "slave" )
+{
+ $glob = $bind_base . "conf-slave/*.conf";
+ @configs = glob($glob);
+
+ open CONF, ">" . $slaveinclude or die ( $! . " " . $slaveinclude);
+ foreach my $config ( @configs )
+ {
+ print CONF "include \"" . $config . "\";\n";
+ }
+ close CONF;
+}
diff --git a/tools/make-dhcpd-include.pl b/tools/make-dhcpd-include.pl
new file mode 100755
index 0000000..ded5551
--- /dev/null
+++ b/tools/make-dhcpd-include.pl
@@ -0,0 +1,18 @@
+#!/usr/bin/perl -I /root/tgmanage
+use strict;
+my $base = "/etc";
+$base = $ARGV[0] if $#ARGV > -1;
+$base .= "/" if not $base =~ m/\/$/ and not $base eq "";
+
+my $dhcpd_base = $base . "dhcp/";
+my $includeconfig = $dhcpd_base . "generated-include.conf";
+
+my $glob = $dhcpd_base . "conf.d/*.conf";
+my @configs = glob($glob);
+
+open CONF, ">" . $includeconfig or die ( $! . " " . $includeconfig);
+foreach my $config ( @configs )
+{
+ print CONF "include \"" . $config . "\";\n";
+}
+close CONF;
diff --git a/tools/make-dhcpd.pl b/tools/make-dhcpd.pl
new file mode 100755
index 0000000..2cf388a
--- /dev/null
+++ b/tools/make-dhcpd.pl
@@ -0,0 +1,104 @@
+#!/usr/bin/perl -I /root/tgmanage
+use strict;
+
+use Net::IP;
+use Net::IP qw(:PROC);
+
+BEGIN {
+ require "include/config.pm";
+ eval {
+ require "include/config.local.pm";
+ };
+}
+
+my $base = "/etc";
+$base = $ARGV[0] if $#ARGV > -1;
+$base .= "/" if not $base =~ m/\/$/ and not $base eq "";
+
+my $dhcpd_base = $base . "dhcp/";
+my $dhcpd_conf = $dhcpd_base . "dhcpd.conf";
+my $dhcp_pxeconf = $dhcpd_base . "pxe-boot.conf";
+my $dhcp_ciscoapconf = $dhcpd_base . "ciscowlc.conf";
+
+my $tgname = $nms::config::tgname;
+my $pri_ptr = $nms::config::pri_ptr;
+my $pri_net = $nms::config::pri_net;
+my $sec_ptr = $nms::config::sec_ptr;
+my $pxe_server = $nms::config::pxe_server;
+my $ddns_key = $nms::config::ddns_key;
+my $ciscowlc_a = $nms::config::ciscowlc_a;
+
+my $range = new Net::IP( $pri_net ) or die ("oopxos");
+my $mask = $range->mask();
+my ($net, undef) = split "/", $pri_net;
+
+
+# Create PXE-boot configuration file for DHCP on master.
+if ( not -f $dhcpd_conf )
+{
+ print STDERR "Creating file " . $dhcpd_conf . "\n";
+ open DHCPDFILE, ">" . $dhcpd_conf or die ( $! . " " . $dhcpd_conf);
+
+ print DHCPDFILE <<"EOF";
+# GENERATED BY make-dhcpd.pl
+#
+# Central concept: as little config in the main .conf,
+# include almost everything from separate files..
+#
+# log-facility local7;
+option domain-name "$tgname.gathering.org";
+option domain-name-servers $pri_ptr, $sec_ptr;
+default-lease-time 3600;
+max-lease-time 7200;
+authoritative;
+
+ddns-update-style interim;
+key DHCP_UPDATER {
+ algorithm HMAC-MD5.SIG-ALG.REG.INT;
+ secret $ddns_key;
+}
+
+subnet $net netmask $mask {}
+
+include "/etc/dhcp/revzones.conf";
+include "/etc/dhcp/generated-include.conf";
+include "/etc/dhcp/pxe-boot.conf";
+include "/etc/dhcp/ciscowlc.conf";
+
+EOF
+ close DHCPDFILE;
+}
+
+# Create PXE-boot configuration file for DHCP on master.
+if ( not -f $dhcp_pxeconf )
+{
+ print STDERR "Creating file " . $dhcp_pxeconf . "\n";
+ open PXEFILE, ">" . $dhcp_pxeconf or die ( $! . " " . $dhcp_pxeconf);
+
+ print PXEFILE "next-server " . $pxe_server . ";\n";
+ print PXEFILE "filename \"pxelinux.0\";\n";
+
+ close PXEFILE;
+}
+
+
+# Create PXE-boot configuration file for DHCP on master.
+if ( not -f $dhcp_ciscoapconf )
+{
+ print STDERR "Creating file " . $dhcp_ciscoapconf . "\n";
+ open CISCOFILE, ">" . $dhcp_ciscoapconf or die ( $! . " " . $dhcp_pxeconf);
+
+ print CISCOFILE <<"EOF";
+option space CiscoAP;
+option CiscoAP.server-address code 241 = array of ip-address;
+set vendor-string = option vendor-class-identifier;
+
+class "cisco-aps" {
+ match if substring (option vendor-class-identifier, 0, 8) = "Cisco AP";
+ vendor-option-space CiscoAP;
+ option CiscoAP.server-address $ciscowlc_a;
+}
+EOF
+ close CISCOFILE;
+}
+
diff --git a/tools/make-first-zones.pl b/tools/make-first-zones.pl
new file mode 100755
index 0000000..1227129
--- /dev/null
+++ b/tools/make-first-zones.pl
@@ -0,0 +1,124 @@
+#!/usr/bin/perl -I /root/tgmanage
+use strict;
+
+use Net::IP;
+
+BEGIN {
+ require "include/config.pm";
+ eval {
+ require "include/config.local.pm";
+ };
+}
+
+my $base = "/etc";
+$base = $ARGV[0] if $#ARGV > -1;
+$base .= "/" if not $base =~ m/\/$/ and not $base eq "";
+
+my $tgname = $nms::config::tgname;
+my $pri_a = $nms::config::pri_a;
+my $pri_ptr = $nms::config::pri_ptr;
+my $pri_v6 = $nms::config::pri_v6;
+my $sec_a = $nms::config::sec_a;
+my $sec_ptr = $nms::config::sec_ptr;
+my $sec_v6 = $nms::config::sec_v6;
+my $ipv6zone = $nms::config::ipv6zone;
+
+# FIXME: THIS IS NOT APPRORPIATE!
+my $serial = `date +%Y%m%d01`;
+chomp $serial;
+# FIXME
+
+my $zonefile;
+
+$zonefile = $base . "bind/" . $tgname . ".gathering.org.zone";
+if ( not -f $zonefile )
+{
+ print $zonefile . "\n";
+ open MAINZONE, ">" . $zonefile or die $! . " " . $zonefile;
+
+ print MAINZONE <<"EOF";
+\$TTL 3600
+@ IN SOA $pri_a.$tgname.gathering.org. abuse.gathering.org. (
+ $serial; serial
+ 3600 ; refresh
+ 1800 ; retry
+ 608400 ; expire
+ 3600 ) ; minimum and default TTL
+
+ IN NS ns1.$tgname.gathering.org.
+ IN NS ns2.$tgname.gathering.org.
+
+ns1 IN A $pri_ptr
+ns1 IN AAAA $pri_v6
+ns2 IN A $sec_ptr
+ns2 IN AAAA $sec_v6
+$pri_a IN A $pri_ptr
+$pri_a IN AAAA $pri_v6
+$sec_a IN A $sec_ptr
+$sec_a IN AAAA $sec_v6
+
+; Generated by make-all-config.sh on the bootstrapping/nms server.
+; Will not be overwritten unless it is missing ;)
+
+EOF
+ close MAINZONE;
+}
+else { print "Skipped TG-zone, file exists.\n"; }
+
+$zonefile = $base . "bind/infra." . $tgname . ".gathering.org.zone";
+if ( not -f $zonefile )
+{
+ print $zonefile . "\n";
+ open MAINZONE, ">" . $zonefile or die $! . " " . $zonefile;
+
+ print MAINZONE <<"EOF";
+\$TTL 3600
+@ IN SOA $pri_a.$tgname.gathering.org. abuse.gathering.org. (
+ $serial; serial
+ 3600 ; refresh
+ 1800 ; retry
+ 608400 ; expire
+ 3600 ) ; minimum and default TTL
+
+ IN NS $pri_a.$tgname.gathering.org.
+ IN NS $sec_a.$tgname.gathering.org.
+
+; Generated by make-all-config.sh on the bootstrapping/nms server.
+; Will not be overwritten unless it is missing ;)
+EOF
+ close MAINZONE;
+}
+else { print "Skipped infra-zone, file exists.\n"; }
+
+$zonefile = $base . "bind/" . $ipv6zone . ".zone";
+if ( not -f $zonefile )
+{
+ print $zonefile . "\n";
+ open IPV6ZONE, ">" . $zonefile or die $! . " " . $zonefile;
+
+ print IPV6ZONE <<"EOF";
+; autogenerated, and updated from dhcpd -- DO NOT TOUCH!
+\$TTL 3600
+@ IN SOA ns1.$tgname.gathering.org. abuse.gathering.org. (
+ $serial; serial
+ 3600 ; refresh
+ 1800 ; retry
+ 608400 ; expire
+ 3600 ) ; minimum and default TTL
+
+ IN NS ns1.$tgname.gathering.org.
+ IN NS ns2.$tgname.gathering.org.
+
+; WARNING! Do not edit this file directly!
+; on the bootstrapping/nms server!
+
+EOF
+ my $ip_pri = new Net::IP( $pri_v6 ) or die ( "Error, new Net::IP for " . $pri_v6 );
+ my $ip_sec = new Net::IP( $sec_v6 ) or die ( "Error, new Net::IP for " . $sec_v6 );
+ print IPV6ZONE $ip_pri->reverse_ip() . " IN PTR ns1.$tgname.gathering.org.\n";
+ print IPV6ZONE $ip_pri->reverse_ip() . " IN PTR $pri_a.$tgname.gathering.org.\n";
+ print IPV6ZONE $ip_sec->reverse_ip() . " IN PTR ns2.$tgname.gathering.org.\n";
+ print IPV6ZONE $ip_sec->reverse_ip() . " IN PTR $sec_a.$tgname.gathering.org.\n";
+ close IPV6ZONE;
+}
+else { print "Skipped v6-reverse-zone, file exists.\n"; }
diff --git a/tools/make-linknet-hosts.pl b/tools/make-linknet-hosts.pl
new file mode 100755
index 0000000..d535832
--- /dev/null
+++ b/tools/make-linknet-hosts.pl
@@ -0,0 +1,34 @@
+#!/usr/bin/perl
+use NetAddr::IP;
+use Net::IP;
+#
+# Input file format:
+#
+# ipv4-link-network router1 router2
+#
+# e.g.
+# 151.216.0.2 telegw nocgw
+# 151.216.0.4 telegw cam
+# 151.216.0.6 nocgw coren
+# 151.216.0.8 telegw pressegw
+#
+# Note: IPv6 linknets use link-local adresses, so they are not included in list.
+#
+while (<STDIN>) {
+ next if /^(#|\s+$)/; # skip if comment, or blank line
+
+ my ($ipv4_raw, $from, $to) = split;
+ my $ipv4;
+
+ # Assumes ipv4 address is the first address in a /31 :-))
+ $ipv4 = NetAddr::IP->new($ipv4_raw."/31") unless $ipv4=~/no/;
+ printf STDERR "Missing IPv4 scope for linket %s -> %s\n", $from, $to if not $ipv4;
+ next if not $ipv4;
+
+
+ # generate-dnsrr.pl format:
+ # hostname ipv4 ipv6 (with nope as valid null argument)
+ my $ipv4_other = $ipv4 +1;
+ printf("%s-%s %s nope\n", $from, $to, $ipv4->addr);
+ printf("%s-%s %s nope\n", $to, $from, $ipv4_other->addr);
+}
diff --git a/tools/make-missing-conf.pl b/tools/make-missing-conf.pl
new file mode 100755
index 0000000..f0fb0a0
--- /dev/null
+++ b/tools/make-missing-conf.pl
@@ -0,0 +1,187 @@
+#!/usr/bin/perl -I /root/tgmanage
+use strict;
+
+BEGIN {
+ require "include/config.pm";
+ eval {
+ require "include/config.local.pm";
+ };
+}
+
+
+use Net::IP;
+use Net::IP qw(:PROC);
+
+# FIXME: THIS IS NOT APPRORPIATE!
+my $serial = `date +%Y%m%d01`;
+chomp $serial;
+# FIXME
+
+unless ( (($#ARGV == 0 ) || ( $#ARGV == 1))
+ && (( $ARGV[0] eq "master" ) || ( $ARGV[0] eq "slave" )) )
+{
+ print STDERR "Invalid usage!\ncat netnames.txt | $0 <master|slave> [basedir]\n";
+ exit 1;
+}
+
+my $role = $ARGV[0];
+
+my $base = "/etc";
+$base = $ARGV[1] if $#ARGV == 1;
+$base .= "/" if not $base =~ m/\/$/ and not $base eq "";
+
+
+print STDERR "Role is " . $role . "\n";
+print STDERR "Base dir is " . $base . "\n";
+
+my $bind_base = $base . "bind/";
+my $dhcpd_base = $base . "dhcp/";
+
+my $dhcp_dynconf_dir = $dhcpd_base . "conf.d/";
+my $bind_conf_master = $bind_base . "conf-master/";
+my $bind_conf_slave = $bind_base . "conf-slave/";
+
+my $tgname = $nms::config::tgname;
+
+my $pri_a = $nms::config::pri_a;
+my $pri_ptr = $nms::config::pri_ptr;
+my $pri_v6 = $nms::config::pri_v6;
+
+my $sec_a = $nms::config::sec_a;
+my $sec_ptr = $nms::config::sec_ptr;
+my $sec_v6 = $nms::config::sec_v6;
+
+my $ext_xfer = $nms::config::ext_xfer;
+my $ext_ns = $nms::config::ext_ns;
+
+my $ddns_key = $nms::config::ddns_key;
+
+my $base_ipv4net = $nms::config::base_ipv4net;
+my $base_ipv4prefix = $nms::config::base_ipv4prefix;
+
+my $ddns_to = $nms::config::ddns_to;
+
+my $base_ipv4 = new Net::IP( $base_ipv4net . "/" . $base_ipv4prefix );
+
+$base_ipv4net =~ m/^(\d+)\.(\d+)\.(\d+)\..*/;
+my ( $cp_oct, $cs_oct, $ct_oct ) = ( $1, $2, $3 );
+
+while ( <STDIN> )
+{
+ next if ( $_ =~ m/^#/);
+ my $line = $_;
+ chomp $line;
+ die ("Invalid format on input") if not $line =~ m/^(\d+)\.(\d+)\.(\d+)\.(\d+)\s+(\d+)\s+([\w|-]+)\s*.*/;
+ my ( $p_oct, $s_oct, $t_oct, $f_oct, $size, $name ) = ( $1, $2, $3, $4, $5, $6 );
+
+
+ my $dhconfig = $dhcp_dynconf_dir . $name . ".conf";
+ my $master_config = $bind_conf_master . $name . ".conf";
+ my $slave_config = $bind_conf_slave . $name . ".conf";
+ my $zone_file = $bind_base . "dynamic/$name.$tgname.gathering.org.zone";
+
+ my $net_base = $p_oct . "." . $s_oct . "." . $t_oct;
+ my $net = $net_base . "." . $f_oct;
+ my $range = new Net::IP( $net . "/" . $size ) or die ("oopxos");
+
+ # Create configuration files for DHCP on master/primary
+ if ( ( not -f $dhconfig ) && ( $role eq "master" ) )
+ {
+ print STDERR "Creating file " . $dhconfig . "\n";
+ my $numhosts = $range->size();
+ my $mask = $range->mask();
+ my $router = $net_base . "." . ($f_oct+1);
+ my $first = $net_base . "." . ( $f_oct + 5 );
+
+ my $last = $first;
+ if ( $size < 24 )
+ {
+ # Net::IP iteration is crazyslow. So, we stopped using iterations.
+ my $last_ip = $range->last_ip();
+ $last_ip =~ m/(\d+)\.(\d+)\.(\d+)\.(\d+)/;
+ $last = sprintf("%d.%d.%d.%d", $1, $2, $3, $4-2);
+ }
+ else { $last = $net_base . "." . ( $f_oct + $numhosts - 2 ); }
+
+ #print STDERR "Name : " . $name . "\n";
+ #print STDERR "Net : " . $net . "\n";
+ #print STDERR "Mask : " . $mask . "\n";
+ #print STDERR "Router : " . $router . "\n";
+ #print STDERR "Size : " . $size . "\n";
+ #print STDERR "Numhosts : " . $numhosts . "\n";
+ #print STDERR "First : " . $first . "\n";
+ #print STDERR "Last : " . $last . "\n";
+
+ open DFILE, ">" . $dhconfig or die ( $! . " " . $dhconfig);
+
+ print DFILE "zone $name.$tgname.gathering.org {\n";
+ print DFILE " primary $ddns_to;\n";
+ print DFILE " key DHCP_UPDATER;\n";
+ print DFILE "}\n\n";
+
+ print DFILE "subnet $net netmask $mask {\n";
+ print DFILE " authoritative;\n";
+ print DFILE " option routers $router;\n";
+ print DFILE " option domain-name \"$name.$tgname.gathering.org\";\n";
+ print DFILE " ddns-domainname \"$name.$tgname.gathering.org\";\n";
+ print DFILE " range $first $last;\n";
+ print DFILE " ignore client-updates;\n";
+ print DFILE "}\n\n";
+
+ close DFILE;
+ }
+
+ # Create zone files for bind9 on master/primary
+ if ( ( not -f $zone_file ) && ( $role eq "master" ) )
+ {
+ print STDERR "Creating file " . $zone_file . "\n";
+ open ZFILE, ">" . $zone_file or die ( $! . " " . $zone_file);
+ print ZFILE << "EOF";
+; Base reverse zones are updated from dhcpd -- DO NOT TOUCH!
+\$TTL 3600
+@ IN SOA $pri_a.$tgname.gathering.org. abuse.gathering.org. (
+ $serial ; serial
+ 3600 ; refresh
+ 1800 ; retry
+ 608400 ; expire
+ 3600 ) ; minimum and default TTL
+
+ IN NS $pri_a.$tgname.gathering.org.
+ IN NS $sec_a.$tgname.gathering.org.
+\$ORIGIN $name.$tgname.gathering.org.
+EOF
+ close ZFILE;
+ }
+
+
+ # Create bind9 configuration files for zones.
+ my $bind_file = "";
+ $bind_file = $master_config if ( $role eq "master");
+ $bind_file = $slave_config if ( $role eq "slave");
+ die ("WTF, role does not match 'master' or 'slave'" ) if ( $bind_file eq "");
+
+ if ( not -f $bind_file )
+ {
+ print STDERR "Creating file " . $bind_file . "\n";
+ open NFILE, ">" . $bind_file or die ( $! . " " . $bind_file);
+
+ print NFILE "zone \"$name.$tgname.gathering.org\" {\n";
+ if ( $role eq "master" ) {
+ print NFILE " type master;\n";
+ print NFILE " notify yes;\n";
+ print NFILE " allow-update { key DHCP_UPDATER; };\n";
+ print NFILE " file \"dynamic/$name.$tgname.gathering.org.zone\";\n";
+ }
+ else
+ {
+ print NFILE " type slave;\n";
+ print NFILE " notify no;\n";
+ print NFILE " masters { bootstrap; };\n";
+ print NFILE " file \"slave/$name.$tgname.gathering.org.zone\";\n";
+ }
+ print NFILE " allow-transfer { ns-xfr; };\n";
+ print NFILE "};\n";
+
+ close NFILE;
+ }
+}
diff --git a/tools/make-named.pl b/tools/make-named.pl
new file mode 100755
index 0000000..7e543e1
--- /dev/null
+++ b/tools/make-named.pl
@@ -0,0 +1,156 @@
+#!/usr/bin/perl -I /root/tgmanage
+use strict;
+
+BEGIN {
+ require "include/config.pm";
+ eval {
+ require "include/config.local.pm";
+ };
+}
+
+
+use Net::IP;
+use Net::IP qw(:PROC);
+
+unless ( (($#ARGV == 0 ) || ( $#ARGV == 1))
+ && (( $ARGV[0] eq "master" ) || ( $ARGV[0] eq "slave" )) )
+{
+ print STDERR "Invalid usage!\ncat netnames.txt | $0 <master|slave> [basedir]\n";
+ exit 1;
+}
+
+my $role = $ARGV[0];
+
+my $base = "/etc";
+$base = $ARGV[1] if $#ARGV == 1;
+$base .= "/" if not $base =~ m/\/$/ and not $base eq "";
+
+my $bind_base = $base . "bind/";
+my $named_file = $bind_base . "named.conf";
+
+if ( -f $named_file )
+{
+ print STDERR $named_file . " already exists. Cowardly refusing to continue\n";
+ exit;
+}
+
+my $tgname = $nms::config::tgname;
+
+my $pri_a = $nms::config::pri_a;
+my $pri_ptr = $nms::config::pri_ptr;
+my $pri_v6 = $nms::config::pri_v6;
+
+my $sec_a = $nms::config::sec_a;
+my $sec_ptr = $nms::config::sec_ptr;
+my $sec_v6 = $nms::config::sec_v6;
+my $ipv6zone = $nms::config::ipv6zone;
+my $ext_xfer = $nms::config::ext_xfer;
+my $ext_ns = $nms::config::ext_ns;
+
+my $ddns_key = $nms::config::ddns_key;
+
+my $base_ipv4net = $nms::config::base_ipv4net;
+my $base_ipv4prefix = $nms::config::base_ipv4prefix;
+
+my $base_ipv6net = $nms::config::base_ipv6net;
+my $base_ipv6prefix = $nms::config::base_ipv6prefix;
+
+my $noc_nett = $nms::config::noc_nett;
+
+my $ddns_to = $nms::config::ddns_to;
+
+my $pxe_server = $nms::config::ddns_to;
+
+my $run = `date +%Y%m%d-%H%M`;
+
+open NFILE, ">" . $named_file or die ( $! . " " . $named_file );
+
+chomp $run;
+print NFILE <<EOF;
+// This named.conf was generated by make-named.pl at $run
+// The current version of make-named.pl should not overwrite this file.
+acl tg-nett { $base_ipv4net/$base_ipv4prefix; $base_ipv6net:/$base_ipv6prefix; 127.0.0.0/8; ::1; };
+acl ns-xfr { $ext_ns; $sec_ptr; $sec_v6; $pri_ptr; $pri_v6; $noc_nett; };
+acl ripe-xfr { $ext_ns; $sec_ptr; $sec_v6; $pri_ptr; $pri_v6; $ext_xfer; };
+
+options {
+ directory "/etc/bind";
+ allow-recursion { tg-nett; };
+ allow-query { any; };
+ allow-transfer { ns-xfr; };
+ recursion yes;
+ auth-nxdomain no;
+ listen-on-v6 { any; };
+};
+
+key DHCP_UPDATER {
+ algorithm HMAC-MD5.SIG-ALG.REG.INT;
+ secret $ddns_key;
+};
+EOF
+
+if ( $role eq "master" )
+{
+ print NFILE <<EOF;
+
+zone "$tgname.gathering.org" {
+ type master;
+ file "$tgname.gathering.org.zone";
+ notify yes;
+ allow-transfer { ns-xfr; };
+};
+
+zone "infra.$tgname.gathering.org" {
+ type master;
+ file "infra.$tgname.gathering.org.zone";
+ notify yes;
+ allow-transfer { ns-xfr; };
+};
+
+zone "$ipv6zone" {
+ type master;
+ allow-update { key DHCP_UPDATER; };
+ notify yes;
+ file "$ipv6zone.zone";
+ allow-transfer { ns-xfr; ripe-xfr; };
+};
+
+include "/etc/bind/named.conf.default-zones";
+include "named.reverse4.conf";
+include "named.master-include.conf";
+EOF
+}
+
+if ( $role eq "slave" )
+{
+ print NFILE <<EOF;
+
+masters bootstrap { $pri_ptr; };
+
+zone "$tgname.gathering.org" {
+ type slave;
+ file "slave/$tgname.gathering.org";
+ notify no;
+ masters { bootstrap; };
+};
+
+zone "infra.$tgname.gathering.org" {
+ type slave;
+ file "slave/infra.$tgname.gathering.org";
+ notify no;
+ masters { bootstrap; };
+};
+
+zone "$ipv6zone" {
+ type slave;
+ notify no;
+ masters { bootstrap; };
+ file "slave/$ipv6zone:";
+ allow-transfer { ns-xfr; ripe-xfr; };
+};
+
+include "named.conf.default-zones";
+include "named.slave-reverse4.conf";
+include "named.slave-include.conf";
+EOF
+}
diff --git a/tools/make-pxeboot.sh b/tools/make-pxeboot.sh
new file mode 100755
index 0000000..0d53e6a
--- /dev/null
+++ b/tools/make-pxeboot.sh
@@ -0,0 +1,26 @@
+#!/bin/bash
+#
+# TODO: This tool assumes that the bootstrap box
+# is used as the PXE server. This should be updated
+# to use the configuration information in config.local.pm ...
+
+apt-get install tftpd-hpa
+apt-get install nfs-kernel-server
+
+cat << END > /etc/default/tftpd-hpa
+TFTP_USERNAME="tftp"
+TFTP_DIRECTORY="/var/lib/tftpboot"
+TFTP_ADDRESS="0.0.0.0:69"
+TFTP_OPTIONS="--secure"
+END
+
+/etc/init.d/tftpd-hpa restart
+
+mkdir -p /var/lib/tftpboot
+cp -R pxe/* /var/lib/tftpboot
+
+tools/fetch-debinstall.sh /var/lib/tftpboot/debian
+# tools/fetch-ubuntulive.sh <- this tool does not exist xD
+# NOTE! The pxe/ directory contains an 'ubuntu' menu...
+# The files required to booting Ubuntu installer or live
+# must be fetched manually (for now)
diff --git a/tools/make-reverse4-files.pl b/tools/make-reverse4-files.pl
new file mode 100755
index 0000000..d20ea37
--- /dev/null
+++ b/tools/make-reverse4-files.pl
@@ -0,0 +1,164 @@
+#!/usr/bin/perl -I /root/tgmanage
+use strict;
+
+BEGIN {
+ require "include/config.pm";
+ eval {
+ require "include/config.local.pm";
+ };
+}
+
+
+use Net::IP;
+use Net::IP qw(:PROC);
+
+# FIXME: THIS IS NOT APPRORPIATE!
+my $serial = `date +%Y%m%d01`;
+chomp $serial;
+# FIXME
+
+unless ( (($#ARGV == 0 ) || ( $#ARGV == 1))
+ && (( $ARGV[0] eq "master" ) || ( $ARGV[0] eq "slave" )) )
+{
+ print STDERR "Invalid usage!\n$0 <master|slave> [basedir]\n";
+ exit 1;
+}
+
+my $role = $ARGV[0];
+
+my $base = "/etc";
+$base = $ARGV[1] if $#ARGV == 1;
+$base .= "/" if not $base =~ m/\/$/ and not $base eq "";
+
+
+my $bind_base = $base . "bind/";
+my $dhcpd_base = $base . "dhcp/";
+
+my $dhcp_revzones_file = $dhcpd_base . "revzones.conf";
+my $bind_pri_revzones_file = $bind_base . "named.reverse4.conf";
+my $bind_sec_revzones_file = $bind_base . "named.slave-reverse4.conf";
+
+my $tgname = $nms::config::tgname;
+
+my $pri_a = $nms::config::pri_a;
+my $pri_ptr = $nms::config::pri_ptr;
+my $pri_v6 = $nms::config::pri_v6;
+
+my $sec_a = $nms::config::sec_a;
+my $sec_ptr = $nms::config::sec_ptr;
+my $sec_v6 = $nms::config::sec_v6;
+
+my $ext_xfer = $nms::config::ext_xfer;
+my $ext_ns = $nms::config::ext_ns;
+
+my $ddns_key = $nms::config::ddns_key;
+
+my $base_ipv4net = $nms::config::base_ipv4net;
+my $base_ipv4prefix = $nms::config::base_ipv4prefix;
+
+my $noc_nett = $nms::config::noc_nett;
+my $noc_nett_v6 = $nms::config::noc_nett_v6;
+
+my $ddns_to = $nms::config::ddns_to;
+
+my $pxe_server = $nms::config::ddns_to;
+
+my $base_ipv4 = new Net::IP( $base_ipv4net . "/" . $base_ipv4prefix );
+
+$base_ipv4net =~ m/^(\d+)\.(\d+)\.(\d+)\..*/;
+my ( $p_oct, $s_oct, $t_oct ) = ( $1, $2, $3 );
+
+$pri_ptr =~ m/^(\d+)\.(\d+)\.(\d+)\.(\d+).*/;
+my ( $pp_oct, $ps_oct, $pt_oct, $pf_oct) = ( $1, $2, $3, $4 );
+$sec_ptr =~ m/^(\d+)\.(\d+)\.(\d+)\.(\d+).*/;
+my ( $sp_oct, $ss_oct, $st_oct, $sf_oct) = ( $1, $2, $3, $4 );
+
+if ( $role eq "master" )
+{
+ open DFILE, ">" . $dhcp_revzones_file or die $!;
+ open NFILE, ">" . $bind_pri_revzones_file or die $!;
+}
+elsif ( $role eq "slave" )
+{
+ open SFILE, ">" . $bind_sec_revzones_file or die $!;
+}
+else
+{
+ die ("WTF, role is neither 'master' or 'slave'");
+}
+
+while (1)
+{
+
+ my $block = $p_oct . "." . $s_oct . "." . $t_oct . ".0/24";
+ my $current = new Net::IP( $block ) or die ("new Net::IP failed for " . $block);
+
+ my $rev_zone = $t_oct . "." . $s_oct . "." . $p_oct . ".in-addr.arpa";
+
+ if ( $role eq "master" )
+ {
+ # Generating IPv4-related reverse-stuff for
+ # both bind9 and dhcp on master.
+
+ print DFILE "zone " . $rev_zone . " { primary " . $ddns_to . "; key DHCP_UPDATER; }\n";
+
+ print NFILE "zone \"". $rev_zone ."\" {\n";
+ print NFILE " type master;\n";
+ print NFILE " allow-update { key DHCP_UPDATER; };\n";
+ print NFILE " notify yes;\n";
+ print NFILE " allow-transfer { $sec_ptr; $ext_xfer; $noc_nett; $noc_nett_v6; };\n";
+ print NFILE " file \"reverse/". $rev_zone .".zone\";\n";
+ print NFILE "};\n\n";
+
+ my $zfilename = $bind_base . "reverse/" . $rev_zone . ".zone";
+ open ZFILE, ">", $zfilename;
+
+ print ZFILE "; " . $zfilename . "\n";
+ print ZFILE <<"EOF";
+; Base reverse zones are updated from dhcpd -- DO NOT TOUCH!
+\$TTL 3600
+@ IN SOA ns1.$tgname.gathering.org. abuse.gathering.org. (
+ $serial ; serial
+ 3600 ; refresh
+ 1800 ; retry
+ 608400 ; expire
+ 3600 ) ; minimum and default TTL
+
+ IN NS ns1.$tgname.gathering.org.
+ IN NS ns2.$tgname.gathering.org.
+
+\$ORIGIN $rev_zone.
+EOF
+ if ( ($pt_oct == $t_oct) && ($ps_oct == $s_oct) )
+ {
+ print ZFILE $pf_oct . " IN PTR ns1.$tgname.gathering.org.\n";
+ }
+ if ( ($st_oct == $t_oct) && ($ss_oct == $s_oct) )
+ {
+ print ZFILE $sf_oct . " IN PTR ns2.$tgname.gathering.org.\n";
+ }
+ }
+ else
+ {
+ # AKA "if not master", as in "is slave".
+ # A lot less work: update the named.slave-reverse4.conf file..
+ print SFILE "zone \"". $rev_zone ."\" {\n";
+ print SFILE " type slave;\n";
+ print SFILE " notify no;\n";
+ print SFILE " file \"slave/". $rev_zone .".cache\";\n";
+ print SFILE " masters { bootstrap; };\n";
+ print SFILE " allow-transfer { $ext_xfer; $noc_nett; $noc_nett_v6; };\n";
+ print SFILE "};\n\n";
+ }
+
+ if ( $current->last_int() == $base_ipv4->last_int() )
+ {
+ print STDERR "Reached last IP network. Finished\n";
+ last;
+ }
+ $t_oct++;
+}
+# Close all files, even those that have never been opened ;)
+close DFILE;
+close NFILE;
+close SFILE;
diff --git a/tools/make-switch-placements.pl b/tools/make-switch-placements.pl
new file mode 100755
index 0000000..58538e2
--- /dev/null
+++ b/tools/make-switch-placements.pl
@@ -0,0 +1,88 @@
+#! /usr/bin/perl
+use strict;
+use warnings;
+
+my $switchtype = "dlink3100";
+
+print "begin;\n";
+print "delete from placements where switch in (select switch from switches where switchtype = '$switchtype');\n";
+
+my %ip;
+my $i = 1;
+while (<STDIN>) {
+ chomp;
+ my @info = split(/ /);
+
+ if (scalar @info < 5) {
+ die "Unknown line: $_";
+ }
+ my ($x, $y, $xx, $yy);
+
+ my $name = $info[0];
+ if ($name =~ /^e\d+-\d+$/) {
+ $name =~ /e(\d+)-(\d+)/;
+ my ($e, $s) = ($1, $2);
+
+ $x = int(220 + (($e-1)/2) * 21.5);
+ $y = undef;
+
+ $x += 10 if ($e >= 11);
+ $x += 10 if ($e >= 27);
+ $x += 10 if ($e >= 43);
+ $x += 10 if ($e >= 59);
+
+ if ($s > 2) {
+ $y = 310 - 84 * ($s-2);
+ } else {
+ $y = 507 - 84 * ($s);
+ }
+
+ $xx = $x + 14;
+ $yy = $y + 84;
+
+ # Justeringer
+ $y += 42 if $name eq "e1-4";
+ $y += 28 if $name eq "e3-4";
+ $y += 14 if $name eq "e5-4";
+
+ $yy -= 14 if $name eq "e77-1";
+ $yy -= 28 if $name eq "e79-1";
+ $yy -= 42 if $name eq "e81-1";
+ $yy -= 56 if $name eq "e83-1";
+ } elsif ($name =~ /^creative(\d+)$/) {
+ my $s = $1;
+ if ($s < 3) {
+ if ($s == 1) {
+ $x = 1190;
+ $y = 278;
+ } else {
+ $x = 1180;
+ $y = 230;
+ }
+ $xx = $x+35;
+ $yy = $y+19;
+ $yy += 6;
+ } else {
+ $x = 1056;
+ $y = 296 - 22 * ($s-3);
+ if ($s <= 4) {
+ $xx = $x+100;
+ } elsif ($s <= 7) {
+ $xx = $x+70;
+ } elsif ($s <= 8) {
+ $xx = $x+55;
+ } else {
+ $xx = $x+35;
+ }
+ $yy = $y+19;
+ $yy -= 5 if $s == 3;
+ }
+ } else {
+ die "Unknown switch: $name";
+ }
+
+ print "insert into placements select switch, box '(($x,$y),($xx,$yy))' from switches where sysname = '$name';\n";
+ $i++;
+}
+
+print "end;\n";
diff --git a/tools/make-switches.pl b/tools/make-switches.pl
new file mode 100755
index 0000000..a2f5d22
--- /dev/null
+++ b/tools/make-switches.pl
@@ -0,0 +1,33 @@
+#! /usr/bin/perl
+use strict;
+use warnings;
+
+my $switchtype = "dlink3100";
+
+print "begin;\n";
+print "delete from temppoll;\n";
+print "delete from dhcp;\n";
+print "delete from switches where switchtype = '$switchtype';\n";
+#print "SELECT pg_catalog.setval('switches_switch_seq', 1, false);\n";
+print "SELECT pg_catalog.setval('polls_poll_seq', 1, false);\n";
+
+my %ip;
+my $i = 1;
+while (<STDIN>) {
+ chomp;
+ my @info = split(/ /);
+
+ if (scalar @info < 5) {
+ die "Unknown line: $_";
+ }
+
+ my $name = $info[0];
+ my $range = $info[3];
+ my $ip = $info[4];
+
+ print "insert into switches (ip, sysname, switchtype) values ('$ip', '$name', '$switchtype');\n";
+ print "insert into dhcp select switch, '$range' from switches where sysname = '$name';\n";
+}
+close HOSTS;
+
+print "end;\n";
diff --git a/tools/update-baseservice.sh b/tools/update-baseservice.sh
new file mode 100755
index 0000000..5908941
--- /dev/null
+++ b/tools/update-baseservice.sh
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+set -e
+
+BASE="";
+if [ -n $1 ]
+then
+ BASE=$1
+ echo "Using base path ${BASE}"
+fi
+
+source include/tgmanage.cfg.sh
+if [ -z ${PRIMARY} ]
+then
+ echo "Not configured!";
+ exit 1;
+fi;
+
+cat netlist.txt | ssh -l root ${PRIMARY} "~/tgmanage/tools/make-missing-conf.pl master ${BASE}"
+ssh -l root ${PRIMARY} "~/tgmanage/tools/make-dhcpd-include.pl ${BASE}"
+ssh -l root ${PRIMARY} "~/tgmanage/tools/make-bind-include.pl master ${BASE}"
+
+set +e
+ssh -l root ${PRIMARY} "chown bind.bind /etc/bind/dynamic/*.zone";
+set -e
+
+cat netlist.txt | ssh -l root ${SECONDARY} "~/tgmanage/tools/make-missing-conf.pl slave ${BASE}"
+ssh -l root ${SECONDARY} "~/tgmanage/tools/make-bind-include.pl slave ${BASE}"
+
diff --git a/tools/update-tools.sh b/tools/update-tools.sh
new file mode 100755
index 0000000..99f712a
--- /dev/null
+++ b/tools/update-tools.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+set -e
+
+source include/tgmanage.cfg.sh
+if [ -z ${PRIMARY} ]
+then
+ echo "Not configured!";
+ exit 1;
+fi;
+
+ssh -l root ${PRIMARY} "mkdir -p ~/tgmanage"
+ssh -l root ${SECONDARY} "mkdir -p ~/tgmanage"
+
+scp -r netlist.txt root@${PRIMARY}:tgmanage/
+scp -r tools root@${PRIMARY}:tgmanage/
+scp -r tools root@${SECONDARY}:tgmanage/
+scp -r include root@${PRIMARY}:tgmanage/
+scp -r include root@${SECONDARY}:tgmanage/
+scp -r clients root@${PRIMARY}:tgmanage/
+scp -r clients root@${SECONDARY}:tgmanage/