pf-tools/pf-tools: 13 new changesets

parmelan-guest at users.alioth.debian.org parmelan-guest at users.alioth.debian.org
Mon Nov 22 10:03:33 UTC 2010


details:   http://hg.debian.org/hg/pf-tools/pf-tools/rev/c7fc608106e2
changeset: 1037:c7fc608106e2
user:      Thomas Parmelan <tom+pf-tools at ankh.fr.EU.org>
date:      Thu Nov 18 18:38:48 2010 +0100
description:
make_interfaces_file() now takes named arguments

details:   http://hg.debian.org/hg/pf-tools/pf-tools/rev/edd35d081e43
changeset: 1038:edd35d081e43
user:      Thomas Parmelan <tom+pf-tools at ankh.fr.EU.org>
date:      Thu Nov 18 19:08:12 2010 +0100
description:
New make_zone_file() function + tests

details:   http://hg.debian.org/hg/pf-tools/pf-tools/rev/b6953b2c6294
changeset: 1039:b6953b2c6294
user:      Thomas Parmelan <tom+pf-tools at ankh.fr.EU.org>
date:      Thu Nov 18 19:10:55 2010 +0100
description:
Rename make_zone_for_site() to __build_zone() and move towards the end of the file with other private functions

details:   http://hg.debian.org/hg/pf-tools/pf-tools/rev/332414a94ada
changeset: 1040:332414a94ada
user:      Thomas Parmelan <tom+pf-tools at ankh.fr.EU.org>
date:      Thu Nov 18 23:21:57 2010 +0100
description:
__build_zone() now takes named arguments

details:   http://hg.debian.org/hg/pf-tools/pf-tools/rev/f60925c5f0f2
changeset: 1041:f60925c5f0f2
user:      Thomas Parmelan <tom+pf-tools at ankh.fr.EU.org>
date:      Thu Nov 18 23:37:14 2010 +0100
description:
More tests for __build_zone()

details:   http://hg.debian.org/hg/pf-tools/pf-tools/rev/73098c5041b5
changeset: 1042:73098c5041b5
user:      Thomas Parmelan <tom+pf-tools at ankh.fr.EU.org>
date:      Fri Nov 19 00:00:01 2010 +0100
description:
Fix tests for make_resolv_conf_file()

details:   http://hg.debian.org/hg/pf-tools/pf-tools/rev/5cea11979d4e
changeset: 1043:5cea11979d4e
user:      Thomas Parmelan <tom+pf-tools at ankh.fr.EU.org>
date:      Fri Nov 19 00:13:13 2010 +0100
description:
__build_interfaces() now takes named arguments

details:   http://hg.debian.org/hg/pf-tools/pf-tools/rev/f092fb7b8c60
changeset: 1044:f092fb7b8c60
user:      Thomas Parmelan <tom+pf-tools at ankh.fr.EU.org>
date:      Fri Nov 19 08:48:57 2010 +0100
description:
New __make_file() function + tests

details:   http://hg.debian.org/hg/pf-tools/pf-tools/rev/4bba68d92bc7
changeset: 1045:4bba68d92bc7
user:      Thomas Parmelan <tom+pf-tools at ankh.fr.EU.org>
date:      Sat Nov 20 11:32:40 2010 +0100
description:
make_sources_list_file(), __build_sources_list() and tests

details:   http://hg.debian.org/hg/pf-tools/pf-tools/rev/92677d022426
changeset: 1046:92677d022426
user:      Thomas Parmelan <tom+pf-tools at ankh.fr.EU.org>
date:      Sat Nov 20 11:34:12 2010 +0100
description:
move __build_sources_list() towards the end of the file

details:   http://hg.debian.org/hg/pf-tools/pf-tools/rev/1ee5f40d5689
changeset: 1047:1ee5f40d5689
user:      Thomas Parmelan <tom+pf-tools at ankh.fr.EU.org>
date:      Sun Nov 21 00:38:54 2010 +0100
description:
New function: __build_interface_lines_ref()

details:   http://hg.debian.org/hg/pf-tools/pf-tools/rev/7e40bebcf425
changeset: 1048:7e40bebcf425
user:      Thomas Parmelan <tom+pf-tools at ankh.fr.EU.org>
date:      Mon Nov 22 09:05:34 2010 +0100
description:
mk_sourceslist, make_sources_list_file() and __build_sources_list(): use an array ref instead of a scalar for the list of additional sections (+ tests)

details:   http://hg.debian.org/hg/pf-tools/pf-tools/rev/dd4873cacd2e
changeset: 1049:dd4873cacd2e
user:      Thomas Parmelan <tom+pf-tools at ankh.fr.EU.org>
date:      Mon Nov 22 11:01:19 2010 +0100
description:
__build_sources_list(): listen to perlcritic and don't use a multiple-statements map

diffstat:

2 files changed, 29 insertions(+), 10 deletions(-)
t/20.zone.t            |   34 ++++++++++++++++++++++++++--------
templates/sources.list |    5 +++--

diffs (1991 lines):

diff -r 75b485e19166 -r dd4873cacd2e lib/PFTools/Utils.pm
--- a/lib/PFTools/Utils.pm	Thu Nov 18 16:55:31 2010 +0100
+++ b/lib/PFTools/Utils.pm	Mon Nov 22 11:01:19 2010 +0100
@@ -47,7 +47,6 @@
     Fix_hosts
     Mk_dhcp
     Mk_PXE_bootfile
-    Mk_sourceslist
     Change_kopt_for_hostname
 
     Search_and_replace
@@ -56,7 +55,8 @@
 our @EXPORT_OK = qw(
     make_interfaces_file
     make_resolv_conf_file
-    make_zone_for_site
+    make_sources_list_file
+    make_zone_file
 );
 
 ########################################################################
@@ -102,6 +102,8 @@
     return ( $pf_config, $global_struct );
 }
 
+# FIXME convert to __make_file()
+# builds both the preseed and PXE files
 sub Mk_PXE_bootfile {
     my ( $hostname, $host_ref, $pxe_template_filename, $preseed_template,
         $default_preseed, $pf_script, $pf_config )
@@ -174,131 +176,33 @@
     return $pxe_boot_file;
 }
 
-=head2 make_zone_for_site( $zone_name, $site_name, $global_config )
+=head2 make_zone_file($arguments_ref)
 
-This function creates the zone file content for the I<$zone_name> zone on site
-I<$site_name>. I<$global_config> references the global configuration hash. It
-returns a reference to the array of lines.
+This function creates a zone file. It takes the
+following named arguments in %{$arguments_ref}:
+
+=over
+
+=item I<zone_name> the zone name
+
+=item I<site_name> the site name
+
+=item I<filename> the output file name
+
+=item I<global_config> a reference to the global configuration hash
 
 =cut
 
-sub make_zone_for_site {
-    my ( $zone_name, $site_name, $global_config ) = @_;
+sub make_zone_file {
+    my ($arguments_ref) = @_;
 
-    if ( not $zone_name ) {
-        croak q{ERROR: Invalid empty $zone_name};
-    }
-    if ( ref $zone_name ) {
-        croak q{ERROR: Invalid non-scalar $zone_name};
+    unless ( ref $arguments_ref eq 'HASH' ) {
+        croak q{ERROR: Invalid $arguments_ref};
     }
 
-    if ( not $site_name ) {
-        croak q{ERROR: Invalid empty $site_name};
-    }
-    if ( ref $site_name ) {
-        croak q{ERROR: Invalid non-scalar $site_name};
-    }
+    __make_file( { file_type => q{zone}, %{ $arguments_ref } } );
 
-    if ( not $global_config ) {
-        croak q{ERROR: Invalid empty $global_config};
-    }
-    if ( ref $global_config ne 'HASH' ) {
-        croak q{ERROR: Invalid non-hashref $global_config};
-    }
-
-    # This is not a complete check but it will catch obvious errors,
-    # like $global_config referencing a non-config hash
-    if ( not exists $global_config->{'ZONE'} ) {
-        croak q{ERROR: Invalid $global_config hashref: no 'ZONE' key found};
-    }
-
-    my $zone_ref = $global_config->{'ZONE'}->{'BY_NAME'}->{$zone_name};
-    if ( not $zone_ref ) {
-        croak qq{ERROR: Unknown zone_name: $zone_name};
-    }
-
-    my $zone_part = $zone_ref->{'BY_SITE'}->{$site_name};
-    if ( not $zone_part ) {
-        croak qq{ERROR: Unknown site_name: $zone_name};
-    }
-
-    # Building Header (SOA, NS an MX fields)
-    my $zone_result = __make_zone_header( $zone_name, $site_name, $zone_ref );
-
-    ### Building Networks part
-    push @{$zone_result},
-        q{;;},
-        q{;; Networks},
-        q{;;============================================================================},
-        q{};
-
-    my $network_order_ref
-        = $global_config->{'ZONE'}->{'BY_NAME'}->{$zone_name}
-        ->{'__network_order'}->{$site_name};
-    foreach my $network ( @{$network_order_ref} ) {
-        my $head = qq{; $network};
-        if ( $zone_part->{$network}->{'comment'} ) {
-            $head .= ": $zone_part->{$network}->{'comment'}";
-        }
-
-        push @{$zone_result},
-            $head,
-            q{;----------------------------------------------------------------------------};
-
-        foreach my $spec ( 'network', 'netmask', 'broadcast', 'gateway' ) {
-            my $value = $zone_part->{$network}->{$spec};
-            next unless defined $value;
-            push @{$zone_result},
-                sprintf( q{%-29s IN %s},
-                qq{$spec.$network}, $zone_part->{$network}->{$spec} );
-        }
-
-        push @{$zone_result}, q{};
-    }
-
-    ### Servers
-    push @{$zone_result},
-        q{},
-        q{},
-        q{;;},
-        q{;; Servers},
-        q{;;============================================================================},
-        q{};
-
-    my $hostclass_order_ref
-        = $global_config->{'ZONE'}->{'BY_NAME'}->{$zone_name}
-        ->{'__hostclass_order'}->{$site_name};
-    foreach my $server ( @{$hostclass_order_ref} ) {
-        my $head = qq{; $server};
-
-        if ( $zone_part->{$server}->{'comment'} ) {
-            $head .= ": $zone_part->{$server}->{'comment'}";
-        }
-
-        push @{$zone_result},
-            $head,
-            q{;----------------------------------------------------------------------------};
-
-        foreach my $field ( sort keys %{ $zone_part->{$server} } ) {
-            next if $field eq 'comment';
-
-            if ( ref $zone_part->{$server}->{$field} eq 'ARRAY' ) {
-                foreach my $elt ( @{ $zone_part->{$server}->{$field} } ) {
-                    push @{$zone_result},
-                        sprintf( q{%-29s IN %s}, $field, $elt );
-                }
-            }
-            else {
-                push @{$zone_result},
-                    sprintf( q{%-29s IN %s},
-                    $field, $zone_part->{$server}->{$field} );
-            }
-        }
-
-        push @{$zone_result}, q{};
-    }
-
-    return $zone_result;
+    return 1;
 }
 
 =head2 make_resolv_conf_file( $hostname, $global_config, $site_name, $filename );
@@ -310,70 +214,13 @@
 =cut
 
 sub make_resolv_conf_file {
-    my ( $hostname, $global_config, $site_name, $filename ) = @_;
+    my ($arguments_ref) = @_;
 
-    if ( not $hostname ) {
-        croak q{ERROR: Invalid empty $hostname};
-    }
-    if ( ref $hostname ) {
-        croak q{ERROR: Invalid non-scalar $hostname};
+    unless ( ref $arguments_ref eq 'HASH' ) {
+        croak q{ERROR: Invalid $arguments_ref};
     }
 
-    if ( not $global_config ) {
-        croak q{ERROR: Invalid empty $global_config};
-    }
-    if ( ref $global_config ne 'HASH' ) {
-        croak q{ERROR: Invalid non-hashref $global_config};
-    }
-
-    # This is not a complete check but it will catch obvious errors,
-    # like $global_config referencing a non-config hash
-    if ( not exists $global_config->{'ZONE'} ) {
-        croak q{ERROR: Invalid $global_config hashref: no 'ZONE' key found};
-    }
-
-    if ( not $site_name ) {
-        croak q{ERROR: Invalid empty $site_name};
-    }
-    if ( ref $site_name ) {
-        croak q{ERROR: Invalid non-scalar $site_name};
-    }
-
-    if ( not $filename ) {
-        croak q{ERROR: Invalid empty $filename};
-    }
-    if ( ref $filename ) {
-        croak q{ERROR: Invalid non-scalar $filename};
-    }
-
-    my $host_props = get_host_config( $hostname, $global_config, $site_name );
-    my $domain = get_zone_from_hostname( $hostname, $global_config, $site_name );
-
-    my @dns = split qr{ \s* [,] \s* }xms, $host_props->{'dns'}->{'resolver'};
-
-    my $out_fh = IO::File->new( $filename, q{>} );
-    unless ($out_fh) {
-        croak qq{ERROR: open $filename: $OS_ERROR};
-    }
-
-    my @lines = (
-        q{###############################################},
-        q{# This file was auto-genrated by mk_resolvconf},
-        q{},
-        qq{search $domain},
-        q{},
-    );
-
-    foreach my $ip_type ( qw( ipv4 ipv6 ) ) {
-        foreach my $dns (@dns) {
-            my $resolved = Resolv( q{cnf}, $ip_type, $dns, $global_config, $site_name );
-            foreach my $ip ( @{$resolved} ) {
-                push @lines, qq{nameserver $ip};
-            }
-        }
-    }
-
-    __write_array_to_filehandle( $out_fh, $filename, \@lines, qq{\n} );
+    __make_file( { file_type => q{resolv.conf}, %{ $arguments_ref } } );
 
     return 1;
 }
@@ -547,50 +394,45 @@
     return [ @{$dhcp_headers}, @dhcp_subnets, @dhcp_hosts ];
 }
 
-sub Mk_sourceslist {
-    my ($hostname, $site_name, $dst, $sections, $template, $backports,
-        $global_config, $pf_config
-        )
-        = @_;
+=head2 make_sources_list_file($arguments_ref)
 
-    my $host_ref = get_host_config( $hostname, $global_config, $site_name );
-    my $mode = $host_ref->{'deployment'}->{'mode'};
+This function creates the I<sources.list> file. It takes the following named
+arguments in I<%{$arguments_ref}: 
 
-    $template ||= join q{/}, $pf_config->{'path'}->{'templates_dir'},
-        $pf_config->{$mode}->{'sources_list'};
+=over
 
-    my $tpl = Template::Tiny->new( TRIM => 1 );
-    my $sources_template = __read_file_in_scalar($template);
-    my $sources_subst = {
-        'mode'             => $host_ref->{'deployment'}->{'mode'},
-        'distrib'          => $host_ref->{'deployment'}->{'distrib'},
-        'default_sections' => $pf_config->{$mode}->{'default_sections'},
-        'custom_sections'  => $sections
-    };
-    my $sources_content = q{};
-    $tpl->process( \$sources_template, $sources_subst, \$sources_content );
+=item I<hostname> the host name
 
-    if ($backports) {
-        my $back_src = $mode eq 'debian' ? $mode . "-backports" : $mode;
-        $sources_content .= <<"BACKPORTS_TEXT";
+=item I<site_name> the site name
 
-deb http://mirrors.private/$back_src $host_ref->{'deployment'}->{'distrib'}-backports $pf_config->{$mode}->{'default_sections'}
+=item I<sections> a whitespace-separated list of repository sections (ie:
+q{common} or q{common foo1 foo2})
 
-BACKPORTS_TEXT
+=item I<template> the filename of the sources.list template
+
+=item I<backports> whether to add an entry for backports (used as a boolean)
+
+=item I<global_config> a reference to the global configuration hash
+
+=item I<pf_config> a reference to the pf-tools configuration hash
+
+=back
+
+=cut
+
+sub make_sources_list_file {
+    my ($arguments_ref) = @_;
+
+    unless ( ref $arguments_ref eq 'HASH' ) {
+        croak q{ERROR: Invalid $arguments_ref};
     }
 
-    $sources_content .= qq{\n};
-
-    my $dst_fh = IO::File->new( $dst, q{>} );
-    unless ($dst_fh) {
-        croak qq{ERROR: open $dst: $OS_ERROR};
-    }
-
-    __write_scalar_to_filehandle($dst_fh, $dst, $sources_content);
+    __make_file( { file_type => q{sources.list}, %{ $arguments_ref } } );
 
     return 1;
 }
 
+# FIXME convert to __make_file()
 sub Change_kopt_for_hostname {
     my ($hostname, $site_name, $grub_src, $dst, $grub_version, $global_config,
         $pf_config
@@ -646,35 +488,35 @@
     return 1;
 }
 
-=head2 make_interfaces_file( $hostname, $global_config, $pf_config, $site_name, $filename );
+=head2 make_interfaces_file($arguments_ref)
 
-Writes the I<interfaces> configuration for I<$hostname> at I<$site_name> to
-I<$filename>. I<$global_config> is a reference to the global configuration
-hash. I<$pf_config> is a reference to the pf-tools configuration hash.
+This function writes the I<interfaces> configuration file. It takes the
+following named arguments in %{$arguments_ref}:
+
+=over
+
+=item I<hostname> the host name
+
+=item I<site_name> the site name
+
+=item I<global_config> a reference to the global configuration hash
+
+=item I<pf_config> a reference to the pf-tools configuration hash
+
+=item I<filename> the output file name
+
+=back
 
 =cut
 
 sub make_interfaces_file {
-    my ( $hostname, $global_config, $pf_config, $site_name, $filename ) = @_;
+    my ($arguments_ref) = @_;
 
-    # NOTE: all parameters (except $filename) are properly checked by
-    # make_interfaces() => no need to check them twice
-
-    if ( not $filename ) {
-        croak q{ERROR: Invalid empty $filename};
-    }
-    if ( ref $hostname ) {
-        croak q{ERROR: Invalid non-scalar $filename};
+    unless ( ref $arguments_ref eq 'HASH' ) {
+        croak q{ERROR: Invalid $arguments_ref};
     }
 
-    my $lines_ref = __build_interfaces( $hostname, $global_config, $pf_config, $site_name );
-
-    my $out_fh = IO::File->new( $filename, q{>} );
-    unless ($out_fh) {
-        croak qq{ERROR: open $filename: $OS_ERROR};
-    }
-
-    __write_array_to_filehandle( $out_fh, $filename, $lines_ref, qq{\n} );
+    __make_file( { file_type => q{interfaces}, %{ $arguments_ref } } );
 
     return 1;
 }
@@ -1017,16 +859,21 @@
     return $preseed_filename;
 }
 
-=head2 __build_interfaces( FIXME)
+=head2 __build_interfaces($arguments_ref)
 
-FIXME
+Builds the content for the I<interfaces> configuration file for I<hostname> at
+I<site_name>. I<global_config> is a reference to the global configuration
+hash. I<pf_config> is a referenfe to the pf-tools configuration hash. This
+function takes named arguments in I<%{$arguments_ref}> and returns a reference
+to an array of lines.
 
 =cut
 
-# FIXME more generic build_foo (using File::Tmp and __move_if_different, but also handling STDOUT)
+sub __build_interfaces {
+    my ($arguments_ref) = @_;
 
-sub __build_interfaces {
-    my ( $hostname, $global_config, $pf_config, $site_name ) = @_;
+    my ( $hostname, $global_config, $pf_config, $site_name )
+        = @{$arguments_ref}{qw( hostname global_config pf_config site_name )};
 
     if ( not $hostname ) {
         croak q{ERROR: Invalid empty $hostname};
@@ -1068,85 +915,15 @@
         croak q{ERROR: Invalid non-scalar $site_name};
     }
 
-    my $resolve    = 0;
     my $host_ref   = get_host_config( $hostname, $global_config, $site_name );
+
     my $interfaces = {};
     my $routes     = {};
-
     foreach my $iface ( 'lo', sort keys %{ $host_ref->{'interfaces'} } ) {
         push @{ $interfaces->{'__order'} }, $iface;
-
-        my $if_part = $host_ref->{'interfaces'}->{$iface};
-        my $if_method
-            = $if_part->{'method'}
-            ? $if_part->{'method'}
-            : $iface eq 'lo' ? q{loopback}
-            :                  q{static};
-        push @{ $interfaces->{$iface} },
-            qq{auto $iface},
-            qq{iface $iface inet $if_method};
-
-        if (( $if_part->{'method'} and $if_part->{'method'} eq 'dhcp' )
-            or $iface eq 'lo'
-            )
-        {
-            next;
-        }
-
-        foreach my $ip_type ( 'ipv4', 'ipv6' ) {
-            next if not $pf_config->{'features'}->{$ip_type};
-
-            my $ip = NetAddr::IP->new( $if_part->{$ip_type} );
-            if ( $if_part->{'slaves'} ) {
-                push @{ $interfaces->{$iface} },
-                    qq{\tslaves\t\t} . $if_part->{'slaves'};
-            }
-            push @{ $interfaces->{$iface} },
-                qq{\taddress\t\t} . $ip->addr(),
-                qq{\tnetmask\t\t} . $ip->mask(),
-                qq{\tnetwork\t\t} . $ip->network()->addr(),
-                qq{\tbroadcast\t} . $ip->broadcast()->addr();
-
-            # Routes
-            my $suffix = get_suffix_from_ip_type( $ip_type );
-            foreach my $route ( @{ $if_part->{ '@route' . $suffix } } ) {
-                if ( $route =~ m{ \A (\S+) \s* (?: via (?: \S+ ) )? \z }xms )
-                {
-                    my $destination = $1;
-                    push @{ $routes->{$destination} }, qq{$iface $route};
-                }
-            }
-
-            # 802.1Q VLAN ID
-            if ( $iface =~ m{ \A ([^.]+) [.] \d+ \z }xms ) {
-                my $raw_device = $1;
-                push @{ $interfaces->{$iface} },
-                    qq{\tvlan_raw_device\t$raw_device};
-
-                # Set MTU to 1496 unless told otherwise
-                if ($if_part->{'iface_opt'}
-                    and $if_part->{'iface_opt'} !~ m{ mtu }xms
-                    )
-                {
-                    $if_part->{'iface_opt'} .= q{, mtu 1496};
-                }
-                else {
-                    $if_part->{'iface_opt'} = q{mtu 1496};
-                }
-            }
-
-            # Options
-            if ( $if_part->{'iface_opt'} ) {
-                foreach my $option (
-                    split qr{ \s* [,] \s* }xms,
-                    $if_part->{'iface_opt'}
-                    )
-                {
-                    push @{ $interfaces->{$iface} },
-                        qq{\tup\t\t/sbin/ip link set $iface $option};
-                }
-            }
-        }
+        $interfaces->{$iface}
+            = __build_interface_lines_ref( $iface, $routes, $host_ref,
+            $pf_config );
     }
 
 DESTINATION:
@@ -1163,21 +940,26 @@
                 push @{ $interfaces->{$if} },
                     qq{\tup\t\t/sbin/ip route add $dst scope global via $gw dev $if};
             }
+
             next DESTINATION;
         }
 
-        # Only one route
+        # Only one route...
         my ($entry) = @{ $routes->{$dest} };
         my ( $if, $dst, $via, $gw ) = split qr{ \s+ }xms, $entry;
+
+        # ... default route
         if ( $dst eq 'default' ) {
             unless ( defined $gw ) {
                 croak
                     qq{ERROR: host $hostname: default route needs a gateway};
             }
             push @{ $interfaces->{$if} }, qq{\tgateway\t\t$gw};
+
             next DESTINATION;
         }
 
+        # ... device route
         push @{ $interfaces->{$if} },
             qq{\tup\t\t/sbin/ip route add $entry dev $if};
     }
@@ -1194,6 +976,415 @@
     }
 
     return \@lines;
+}
+
+=head2 __build_interface_lines_ref( $iface, $routes, $host_ref, $pf_config )
+
+Builds a list of configuration lines for an interface and returns a reference
+to it. Also, fill %{$routes}.
+
+=cut
+
+sub __build_interface_lines_ref {
+    my ($iface, $routes, $host_ref, $pf_config) = @_;
+
+    my @iface_lines;
+
+    my $if_part = $host_ref->{'interfaces'}->{$iface};
+    my $if_method
+        = $if_part->{'method'} ? $if_part->{'method'}
+        : $iface eq 'lo'       ? q{loopback}
+        :                        q{static};
+    push @iface_lines,
+        qq{auto $iface},
+        qq{iface $iface inet $if_method};
+
+    if ( ( $if_part->{'method'} and $if_part->{'method'} eq 'dhcp' )
+        or $iface eq 'lo' )
+    {
+        return \@iface_lines;
+    }
+
+    if ( $if_part->{'slaves'} ) {
+        push @iface_lines, qq{\tslaves\t\t} . $if_part->{'slaves'};
+    }
+
+    foreach my $ip_type ( 'ipv4', 'ipv6' ) {
+        next if not $pf_config->{'features'}->{$ip_type};
+
+        my $ip = NetAddr::IP->new( $if_part->{$ip_type} );
+        push @iface_lines,
+            qq{\taddress\t\t} . $ip->addr(),
+            qq{\tnetmask\t\t} . $ip->mask(),
+            qq{\tnetwork\t\t} . $ip->network()->addr(),
+            qq{\tbroadcast\t} . $ip->broadcast()->addr();
+
+        # Routes
+        # FIXME add tests cases for non-default routes
+        my $suffix = get_suffix_from_ip_type($ip_type);
+        foreach my $route ( @{ $if_part->{ '@route' . $suffix } } ) {
+            if ( $route =~ m{ \A (\S+) \s* (?: via (?: \S+ ) )? \z }xms ) {
+                my $destination = $1;
+                push @{ $routes->{$destination} }, qq{$iface $route};
+            }
+        }
+
+        # 802.1Q VLAN ID
+        if ( $iface =~ m{ \A ([^.]+) [.] \d+ \z }xms ) {
+            my $raw_device = $1;
+            push @iface_lines, qq{\tvlan_raw_device\t$raw_device};
+
+            # Set MTU to 1496 unless told otherwise
+            if (    $if_part->{'iface_opt'}
+                and $if_part->{'iface_opt'} !~ m{ mtu }xms )
+            {
+                $if_part->{'iface_opt'} .= q{, mtu 1496};
+            }
+            else {
+                $if_part->{'iface_opt'} = q{mtu 1496};
+            }
+        }
+
+        # Options
+        if ( $if_part->{'iface_opt'} ) {
+            foreach my $option ( split qr{ \s* [,] \s* }xms,
+                $if_part->{'iface_opt'} )
+            {
+                push @iface_lines,
+                    qq{\tup\t\t/sbin/ip link set $iface $option};
+            }
+        }
+    }
+
+    return \@iface_lines;
+}
+
+=head2 __build_resolv_conf($arguments_ref)
+
+Writes the I<resolv.conf> configuration for I<hostname> at I<site_name>.
+I<global_config> is a reference to the global configuration hash.  This
+function takes named arguments in I<%{$arguments_ref}> and returns a reference
+to an array of lines.
+
+=cut
+
+sub __build_resolv_conf {
+    my ($arguments_ref) = @_;
+
+    my ( $hostname, $global_config, $site_name )
+        = @{$arguments_ref}{qw( hostname global_config site_name )};
+
+    if ( not $hostname ) {
+        croak q{ERROR: Invalid empty $hostname};
+    }
+    if ( ref $hostname ) {
+        croak q{ERROR: Invalid non-scalar $hostname};
+    }
+
+    if ( not $global_config ) {
+        croak q{ERROR: Invalid empty $global_config};
+    }
+    if ( ref $global_config ne 'HASH' ) {
+        croak q{ERROR: Invalid non-hashref $global_config};
+    }
+
+    # This is not a complete check but it will catch obvious errors,
+    # like $global_config referencing a non-config hash
+    if ( not exists $global_config->{'ZONE'} ) {
+        croak q{ERROR: Invalid $global_config hashref: no 'ZONE' key found};
+    }
+
+    if ( not $site_name ) {
+        croak q{ERROR: Invalid empty $site_name};
+    }
+    if ( ref $site_name ) {
+        croak q{ERROR: Invalid non-scalar $site_name};
+    }
+
+    my $host_props = get_host_config( $hostname, $global_config, $site_name );
+    my $domain = get_zone_from_hostname( $hostname, $global_config, $site_name );
+
+    my @dns = split qr{ \s* [,] \s* }xms, $host_props->{'dns'}->{'resolver'};
+
+    my @lines = (
+        q{#},
+        q{# This file was auto-generated by mk_resolvconf -- DO NOT EDIT!},
+        q{#},
+        q{},
+        qq{search $domain},
+        q{},
+    );
+
+    foreach my $ip_type ( qw( ipv4 ipv6 ) ) {
+        foreach my $dns (@dns) {
+            my $resolved = Resolv( q{cnf}, $ip_type, $dns, $global_config, $site_name );
+            foreach my $ip ( @{$resolved} ) {
+                push @lines, qq{nameserver $ip};
+            }
+        }
+    }
+
+    push @lines, q{};
+
+    return \@lines;
+}
+
+=head2 __build_zone($arguments_ref)
+
+This function creates the zone file content for the I<zone_name> zone on site
+I<site_name>. I<global_config> references the global configuration hash. It
+takes named arguments in I<%{$arguments_ref}> and returns a reference to the
+array of lines.
+
+=cut
+
+sub __build_zone {
+    my ($arguments_ref) = @_;
+
+    my ( $zone_name, $site_name, $global_config )
+        = @{$arguments_ref}{qw( zone_name site_name global_config )};
+
+    if ( not $zone_name ) {
+        croak q{ERROR: Invalid empty $zone_name};
+    }
+    if ( ref $zone_name ) {
+        croak q{ERROR: Invalid non-scalar $zone_name};
+    }
+
+    if ( not $site_name ) {
+        croak q{ERROR: Invalid empty $site_name};
+    }
+    if ( ref $site_name ) {
+        croak q{ERROR: Invalid non-scalar $site_name};
+    }
+
+    if ( not $global_config ) {
+        croak q{ERROR: Invalid empty $global_config};
+    }
+    if ( ref $global_config ne 'HASH' ) {
+        croak q{ERROR: Invalid non-hashref $global_config};
+    }
+
+    # This is not a complete check but it will catch obvious errors,
+    # like $global_config referencing a non-config hash
+    if ( not exists $global_config->{'ZONE'} ) {
+        croak q{ERROR: Invalid $global_config hashref: no 'ZONE' key found};
+    }
+
+    my $zone_ref = $global_config->{'ZONE'}->{'BY_NAME'}->{$zone_name};
+    if ( not $zone_ref ) {
+        croak qq{ERROR: Unknown zone_name: $zone_name};
+    }
+
+    my $zone_part = $zone_ref->{'BY_SITE'}->{$site_name};
+    if ( not $zone_part ) {
+        croak qq{ERROR: Unknown site_name: $zone_name};
+    }
+
+    # Building Header (SOA, NS an MX fields)
+    my $header_lines_ref
+        = __make_zone_header( $zone_name, $site_name, $zone_ref );
+    my @lines = @{$header_lines_ref};
+
+    ### Building Networks part
+    push @lines,
+        q{;;},
+        q{;; Networks},
+        q{;;============================================================================},
+        q{};
+
+    my $network_order_ref
+        = $global_config->{'ZONE'}->{'BY_NAME'}->{$zone_name}
+        ->{'__network_order'}->{$site_name};
+    foreach my $network ( @{$network_order_ref} ) {
+        my $head = qq{; $network};
+        if ( $zone_part->{$network}->{'comment'} ) {
+            $head .= ": $zone_part->{$network}->{'comment'}";
+        }
+
+        push @lines,
+            $head,
+            q{;----------------------------------------------------------------------------};
+
+        foreach my $spec ( 'network', 'netmask', 'broadcast', 'gateway' ) {
+            my $value = $zone_part->{$network}->{$spec};
+            next unless defined $value;
+            push @lines,
+                sprintf( q{%-29s IN %s},
+                qq{$spec.$network}, $zone_part->{$network}->{$spec} );
+        }
+
+        push @lines, q{};
+    }
+
+    ### Servers
+    push @lines,
+        q{},
+        q{},
+        q{;;},
+        q{;; Servers},
+        q{;;============================================================================},
+        q{};
+
+    my $hostclass_order_ref
+        = $global_config->{'ZONE'}->{'BY_NAME'}->{$zone_name}
+        ->{'__hostclass_order'}->{$site_name};
+    foreach my $server ( @{$hostclass_order_ref} ) {
+        my $head = qq{; $server};
+
+        if ( $zone_part->{$server}->{'comment'} ) {
+            $head .= ": $zone_part->{$server}->{'comment'}";
+        }
+
+        push @lines,
+            $head,
+            q{;----------------------------------------------------------------------------};
+
+        foreach my $field ( sort keys %{ $zone_part->{$server} } ) {
+            next if $field eq 'comment';
+
+            if ( ref $zone_part->{$server}->{$field} eq 'ARRAY' ) {
+                foreach my $elt ( @{ $zone_part->{$server}->{$field} } ) {
+                    push @lines,
+                        sprintf( q{%-29s IN %s}, $field, $elt );
+                }
+            }
+            else {
+                push @lines,
+                    sprintf( q{%-29s IN %s},
+                    $field, $zone_part->{$server}->{$field} );
+            }
+        }
+
+        push @lines, q{};
+    }
+
+    return \@lines;
+}
+
+=head2 __build_sources_list($arguments_ref)
+
+This function creates the I<sources.list> file content and returns a reference
+to the array of lines. It takes the following named arguments in
+I<%{$arguments_ref}: 
+
+=over
+
+=item I<hostname> the host name
+
+=item I<site_name> the site name
+
+=item I<sections_ref> a reference to a list of repository sections
+
+=item I<template> the filename of the sources.list template
+
+=item I<backports> whether to add an entry for backports (used as a boolean)
+
+=item I<global_config> a reference to the global configuration hash
+
+=item I<pf_config> a reference to the pf-tools configuration hash
+
+=back
+
+=cut
+
+sub __build_sources_list {
+    my ($arguments_ref) = @_;
+
+    my ($hostname, $site_name, $sections_ref, $template, $backports,
+        $global_config, $pf_config
+        )
+        = @{$arguments_ref}{
+        qw(
+            hostname site_name sections_ref template backports
+            global_config pf_config
+            )
+        };
+
+    # NOTE: hostname and global_config are properly checked in
+    # get_host_config(), so there's no need to check them here.
+
+    if ( not $template ) {
+        croak q{ERROR: Invalid empty $template};
+    }
+    if ( ref $template ) {
+        croak q{ERROR: Invalid non-scalar $template};
+    }
+
+    # FIXME is site_name optional or not?
+
+    if ( not $sections_ref ) {
+        croak q{ERROR: Invalid empty $sections_ref};
+    }
+    if ( ref $sections_ref ne 'ARRAY' ) {
+        croak q{ERROR: Invalid non-array-ref $sections_ref};
+    }
+    if ( not @{$sections_ref} ) {
+        croak q{ERROR: Invalid empty-array-ref $sections_ref};
+    }
+
+    my @sections = ();
+    foreach my $section ( @{$sections_ref} ) {
+
+        # Remove leading and trailink whitespace
+        $section =~ s{ \A \s* (\S*) \s* \z }{$1}xms;
+        if ( not $section ) {
+            croak
+                q{ERROR: Invalid empty or blank section in array-ref $sections_ref};
+        }
+        push @sections, $section;
+    }
+    my $sections = join q{ }, @sections;
+
+    # $backports is optional
+    if ( ref $backports ) {
+        croak q{ERROR: Invalid non-scalar $backports};
+    }
+
+    if ( ref $global_config ne 'HASH' ) {
+        croak q{ERROR: Invalid non-hashref $global_config};
+    }
+
+    # This is not a complete check but it will catch obvious errors,
+    # like $global_config referencing a non-config hash
+    if ( not exists $global_config->{'ZONE'} ) {
+        croak q{ERROR: Invalid $global_config hashref: no 'ZONE' key found};
+    }
+
+    my $host_ref = get_host_config( $hostname, $global_config, $site_name );
+    my $deployment_mode = $host_ref->{'deployment'}->{'mode'};
+
+    $template ||= join q{/}, $pf_config->{'path'}->{'templates_dir'},
+        $pf_config->{$deployment_mode}->{'sources_list'};
+
+    my $tpl              = Template::Tiny->new( TRIM => 1 );
+    my $sources_template = __read_file_in_scalar($template);
+    my $sources_subst    = {
+        'mode'    => $deployment_mode,
+        'distrib' => $host_ref->{'deployment'}->{'distrib'},
+        'default_sections' =>
+            $pf_config->{$deployment_mode}->{'default_sections'},
+        'custom_sections' => $sections,
+    };
+    my $sources_content = q{};
+    $tpl->process( \$sources_template, $sources_subst, \$sources_content );
+
+    # FIXME why not in the template?
+    if ($backports) {
+        my $dash_backports
+            = $deployment_mode eq q{debian} ? q{-backports} : q{};
+        my $back_src = $deployment_mode . $dash_backports;
+        $sources_content .= <<"BACKPORTS_TEXT";
+
+deb http://mirrors.private/$back_src $host_ref->{'deployment'}->{'distrib'}-backports $pf_config->{$deployment_mode}->{'default_sections'}
+
+BACKPORTS_TEXT
+    }
+
+    # This cannot be in the template because of the TRIM option
+    $sources_content .= qq{\n};
+
+    return [$sources_content];
 }
 
 =head2 __get_kpkg_from_kernel( $pxefilename, $deploymode )
@@ -1437,16 +1628,8 @@
 sub __write_scalar_to_filehandle {
     my ($fh, $filename, $scalar) = @_;
 
-    # IO::File does not implement filename()
-    #my $filename = $fh->filename();
-
-    unless ( $fh->print($scalar) ) {
-        croak qq{ERROR: write $filename: $OS_ERROR};
-    }
-
-    unless ( $fh->close() ) {
-        croak qq{ERROR: close $filename: $OS_ERROR};
-    }
+    # FIXME should be q{}, but wait for proper tests to really correct it
+    __write_array_to_filehandle( $fh, $filename, [$scalar], qq{\n} );
 
     return 1;
 }
@@ -1479,5 +1662,84 @@
     }
 }
 
+=head2 __make_file($arguments_ref)
+
+This function creates a specific file. It takes the
+following named arguments in %{$arguments_ref}:
+
+=over
+
+=item I<file_type> the type of file to create. The allowed types are
+I<interfaces>, I<resolv.conf> and I<zone>.
+
+=item I<filename> the output file name
+
+All other named arguments are passed to the specialized function to which the
+content creation for this I<file_type> is delegated.
+
+The content is written to a temporary file and only moved to I<filename> if it
+is different from the original content. STDOUT is also supported (if
+I<filename> is '-').
+
+=cut
+
+sub __make_file {
+    my ($arguments_ref) = @_;
+
+    my %build_content_for = (
+        interfaces      => \&__build_interfaces,
+        q{resolv.conf}  => \&__build_resolv_conf,
+        q{sources.list} => \&__build_sources_list,
+        zone            => \&__build_zone,
+    );
+
+    # NOTE: all other parameters are properly checked by
+    # __build_FOO() => no need to check them here
+
+    my ( $file_type, $filename )
+        = @{$arguments_ref}{qw( file_type filename )};
+
+    if ( not $file_type ) {
+        croak q{ERROR: Invalid empty $file_type};
+    }
+    if ( ref $file_type ) {
+        croak q{ERROR: Invalid non-scalar $file_type};
+    }
+    if ( not exists $build_content_for{$file_type} ) {
+        croak qq{ERROR: Unknown file_type: $file_type};
+    }
+
+    if ( not $filename ) {
+        croak q{ERROR: Invalid empty $filename};
+    }
+    if ( ref $filename ) {
+        croak q{ERROR: Invalid non-scalar $filename};
+    }
+
+    my $lines_ref = $build_content_for{$file_type}->($arguments_ref);
+
+    # Either STDOUT or a tempfile...
+    my ($out_fh, $out_fn);
+    if ( $filename eq q{-} ) {
+        $out_fh = IO::File->new();
+        unless ( $out_fh->fdopen( fileno(STDOUT), q{>} ) ) {
+            croak qq{ERROR: fdopen STDOUT: $OS_ERROR};
+        }
+        $out_fn = $filename;
+    }
+    else {
+        $out_fh = File::Temp->new( unlink => 0 );    # will croak() on error
+        $out_fn = $out_fh->filename();
+    }
+
+    __write_array_to_filehandle( $out_fh, $out_fn, $lines_ref, qq{\n} );
+
+    if ( $filename ne q{-} ) {
+        __move_if_different( $out_fn, $filename );
+    }
+
+    return 1;
+}
+
 1;    # Magic true value required at end of module
 
diff -r 75b485e19166 -r dd4873cacd2e sbin/mk_interfaces
--- a/sbin/mk_interfaces	Thu Nov 18 16:55:31 2010 +0100
+++ b/sbin/mk_interfaces	Mon Nov 22 11:01:19 2010 +0100
@@ -30,7 +30,7 @@
 use Sys::Hostname;
 
 use PFTools::Structqueries;
-use PFTools::Utils qw( make_interfaces_file );
+use PFTools::Utils qw( Init_TOOLS make_interfaces_file );
 
 #################################
 # VARS
@@ -95,11 +95,13 @@
 }
 
 make_interfaces_file(
-    $options->{'host'},
-    $GLOBAL_STRUCT,
-    $PF_CONFIG,
-    $options->{'site'},
-    $options->{'output'},
+    {
+        hostname      => $options->{'host'},
+        global_config => $GLOBAL_STRUCT,
+        pf_config     => $PF_CONFIG,
+        site_name     => $options->{'site'},
+        filename      => $options->{'output'},
+    }
 );
 
 exit 0;
diff -r 75b485e19166 -r dd4873cacd2e sbin/mk_resolvconf
--- a/sbin/mk_resolvconf	Thu Nov 18 16:55:31 2010 +0100
+++ b/sbin/mk_resolvconf	Mon Nov 22 11:01:19 2010 +0100
@@ -28,7 +28,7 @@
 use Sys::Hostname;
 
 use PFTools::Structqueries;
-use PFTools::Utils qw( make_resolv_conf_file );
+use PFTools::Utils qw( Init_Tools make_resolv_conf_file );
 
 #################################
 # VARS
@@ -92,15 +92,13 @@
         || get_uniq_site_from_hostname( $options->{'host'}, $GLOBAL_STRUCT );
 }
 
-unless(
-    make_resolv_conf_file(
-        $options->{'host'},
-        $GLOBAL_STRUCT,
-        $options->{'site'},
-        $options->{'output'}
-    )
-) {
-    die "An error occured during build of file $options->{'output'}";
-}
+make_resolv_conf_file(
+    {
+        hostname      => $options->{'host'},
+        global_config => $GLOBAL_STRUCT,
+        site_name     => $options->{'site'},
+        filename      => $options->{'output'},
+    }
+);
 
 exit 0;
diff -r 75b485e19166 -r dd4873cacd2e sbin/mk_sitezone
--- a/sbin/mk_sitezone	Thu Nov 18 16:55:31 2010 +0100
+++ b/sbin/mk_sitezone	Mon Nov 22 11:01:19 2010 +0100
@@ -26,7 +26,7 @@
 use Getopt::Long qw( :config ignore_case_always bundling );
 use IO::File;
 
-use PFTools::Utils qw( make_zone_for_site );
+use PFTools::Utils qw( Init_TOOLS make_zone_file );
 
 #################################
 # VARS
@@ -91,17 +91,15 @@
     die "Site $options->{'site'} is not defined into global configuration";
 }
 
-my $zone = make_zone_for_site(
-    $GLOBAL_STRUCT->{'SITE'}->{'BY_NAME'}->{$options->{'site'}}->{'zone'},
-    $options->{'site'},
-    $GLOBAL_STRUCT
+my $zone_name
+    = $GLOBAL_STRUCT->{'SITE'}->{'BY_NAME'}->{ $options->{'site'} }->{'zone'};
+make_zone_file(
+    {
+        zone_name     => $zone_name,
+        site_name     => $options->{'site'},
+        filename      => $options->{'output'},
+        global_config => $GLOBAL_STRUCT,
+    }
 );
 
-my $output_fh = IO::File->new ( '>' . $options->{'output'} )
-    or die "Unable to open destination $options->{'output'} : $OS_ERROR";
-$output_fh->print( join "\n", @{$zone} )
-    or die "Unable to write on destination $options->{'output'} : $OS_ERROR";
-$output_fh->close()
-    or die "Unable to close destination$options->{'output'} : $OS_ERROR";
-
 exit 0;
diff -r 75b485e19166 -r dd4873cacd2e sbin/mk_sourceslist
--- a/sbin/mk_sourceslist	Thu Nov 18 16:55:31 2010 +0100
+++ b/sbin/mk_sourceslist	Mon Nov 22 11:01:19 2010 +0100
@@ -27,7 +27,7 @@
 use Sys::Hostname;
 
 use PFTools::Structqueries;
-use PFTools::Utils;
+use PFTools::Utils qw( Init_TOOLS make_sources_list_file );
 
 ############################################
 # Vars
@@ -37,7 +37,7 @@
     'host|h=s',
     'site|s=s',
     'tpl|t=s',
-    'a|add=s',
+    'add|a=s@',
     'config|c=s',
     'store=s',
     'backport|b',
@@ -47,12 +47,11 @@
 my $options = {
     'help'      => 0,
     'host'      => hostname,
-    'add'       => '',
+    'add'       => [],
     'backport'  => 0,
     'output'    => '-',
 };
 
-my $SECTIONS          = "common";
 my $PF_CONFIG         = {};
 my $GLOBAL_STRUCT     = {};
 
@@ -67,29 +66,32 @@
 
 Synopsis : $program [--help] [-h|--host hostname <hostname>] [-s|--site <site_name>]
 			[-o|--output <sources.list dest>] [ -t|--tpl <sources.list template>] [-b|--backports]
-			[-a|--add <sections to add>] [-c|--config <pf_tools_file>] [--store <filename>]
+			[-a|--add <section to add>] [-c|--config <pf_tools_file>] [--store <filename>]
 
 	This tool permits to build the sources.list file according to distribution defined
 	in private-network file from PF-Tools configuration. It can also add some sections
 	to custom repository
 
-	--help			Displays this message and exits
+	--help			Display this message and exit
 
-	-h | --host		Defines here the hostname you want to build the sources.list
+	-h | --host		Define here the hostname you want to build the sources.list
 
-	-s | --site		Defines here the site on which the hostname is defined
+	-s | --site		Define here the site on which the hostname is defined
 
-	-o | --output		Defines here where to build the sources.list file
+	-o | --output	Define here where to build the sources.list file
 
-	-t | --tpl		Defines here where to find the sources.list template. If not defined
+	-t | --tpl		Define here where to find the sources.list template. If not defined
 				the program will use template path issued from pf-tools.conf file
 
-	-a | --add		Defines here the list(comma-separated) of sections you want to add into custom repository
+	-a | --add		Define here the section you want to add to the custom repository (in
+                    addtion to the "common" section).  For multiple values, specify multiple
+                    times (-a section1 -a section2) or use a comma-separated list
+                    (-a section1,section2).
 
-	-b | --backports	Adds the backport repository from offical source according to hostname's
-				deployment mode
+	-b | --backports	Add the backport repository from offical sources according to
+                    hostname's deployment mode
 
-	-c | --config		Define here where is the pf-tools.conf file
+	-c | --config	Define here where is the pf-tools.conf file
 
 	--store			Define here where the storable file which contains the global structure is
 
@@ -131,22 +133,21 @@
         || get_uniq_site_from_hostname( $options->{'host'}, $GLOBAL_STRUCT );
 }
 
-$options->{'add'} =~ s{,}{ }g;
-$SECTIONS .= " " . $options->{'add'};
-$SECTIONS =~ s{\A \s*}{}xms; # Removing trailing space(s)
-unless( 
-    Mk_sourceslist(
-        $options->{'host'},
-        $options->{'site'},
-        $options->{'output'},
-        $SECTIONS,
-        $options->{'tpl'},
-        $options->{'backport'},
-        $GLOBAL_STRUCT,
-        $PF_CONFIG
-    )
-) {
-    die q{ERROR: An error occured during sources.list generation};
-}
+my @sections = (q{common});
+push @sections, split qr{ \s* [,] \s* }xms, join q{,}, @{ $options->{'add'} };
+
+make_sources_list_file(
+    {
+        hostname      => $options->{'host'},
+        site_name     => $options->{'site'},
+        filename      => $options->{'output'},
+        sections      => \@sections,
+        template      => $options->{'tpl'},
+        backports     => $options->{'backport'},
+        global_config => $GLOBAL_STRUCT,
+        pf_config     => $PF_CONFIG,
+    }
+);
 
 exit 0;
+
diff -r 75b485e19166 -r dd4873cacd2e t/20.zone.t
--- a/t/20.zone.t	Thu Nov 18 16:55:31 2010 +0100
+++ b/t/20.zone.t	Mon Nov 22 11:01:19 2010 +0100
@@ -92,47 +92,99 @@
 
 
 ########################################################################
-note('Testing PFTools::Utils::make_zone_for_site');
-can_ok( 'PFTools::Utils', qw( make_zone_for_site ) );
+note('Testing PFTools::Utils::__build_zone');
+can_ok( 'PFTools::Utils', qw( __build_zone ) );
 
-throws_ok { make_zone_for_site(); }
+throws_ok { PFTools::Utils::__build_zone(); }
 qr{ \A ERROR: [ ] Invalid [ ] empty [ ] [\$] zone_name }xms
     => q{Dies if empty $zone_name};
 
-throws_ok { make_zone_for_site( {} ); }
+throws_ok { PFTools::Utils::__build_zone( { zone_name => {} } ); }
 qr{ \A ERROR: [ ] Invalid [ ] non-scalar [ ] [\$] zone_name }xms
     => q{Dies if non-scalar $zone_name};
 
-throws_ok { make_zone_for_site( q{name} ); }
+throws_ok { PFTools::Utils::__build_zone( { zone_name => q{name} } ); }
 qr{ \A ERROR: [ ] Invalid [ ] empty [ ] [\$] site_name }xms
     => q{Dies if empty $site_name};
 
-throws_ok { make_zone_for_site( q{name}, {} ); }
+throws_ok {
+    PFTools::Utils::__build_zone(
+        {
+            zone_name => q{name},
+            site_name => {},
+        }
+    );
+}
 qr{ \A ERROR: [ ] Invalid [ ] non-scalar [ ] [\$] site_name }xms
     => q{Dies if non-scalar $site_name};
 
-throws_ok { make_zone_for_site( q{name}, q{site} ); }
+throws_ok {
+    PFTools::Utils::__build_zone(
+        {
+            zone_name => q{name},
+            site_name => q{site},
+        }
+    );
+}
 qr{ \A ERROR: [ ] Invalid [ ] empty [ ] [\$] global_config }xms
     => q{Dies if empty $global_config};
 
-throws_ok { make_zone_for_site( q{name}, q{site}, q{ref} ); }
+throws_ok {
+    PFTools::Utils::__build_zone(
+        {
+            zone_name     => q{name},
+            site_name     => q{site},
+            global_config => q{ref},
+        }
+    );
+}
 qr{ \A ERROR: [ ] Invalid [ ] non-hashref [ ] [\$] global_config }xms
     => q{Dies if non-hashref $global_config};
 
-throws_ok { make_zone_for_site( q{name}, q{site}, {} ); }
+throws_ok {
+    PFTools::Utils::__build_zone(
+        {
+            zone_name     => q{name},
+            site_name     => q{site},
+            global_config => {},
+        }
+    );
+}
 qr{ \A ERROR: [ ] Invalid [ ] [\$] global_config [ ] hashref:
     [ ] no [ ] 'ZONE' [ ] key [ ] found }xms
     => q{Dies if non-config hashref $global_config};
 
-throws_ok { make_zone_for_site( q{name}, q{site}, $global_config ); }
+throws_ok {
+    PFTools::Utils::__build_zone(
+        {
+            zone_name     => q{name},
+            site_name     => q{site},
+            global_config => $global_config,
+        }
+    );
+}
 qr{ \A ERROR: [ ] Unknown [ ] zone_name: [ ] }xms
     => q{Dies if unknown zone_name};
 
-throws_ok { make_zone_for_site( q{private}, q{site}, $global_config ); }
+throws_ok {
+    PFTools::Utils::__build_zone(
+        {
+            zone_name     => q{private},
+            site_name     => q{site},
+            global_config => $global_config
+        }
+    );
+}
 qr{ \A ERROR: [ ] Unknown [ ] site_name: [ ] }xms
     => q{Dies if unknown site_name};
 
-$result = make_zone_for_site( q{private}, q{cbv4-pfds}, $global_config );
+$result = PFTools::Utils::__build_zone(
+    {
+        zone_name     => q{private},
+        site_name     => q{cbv4-pfds},
+        global_config => $global_config,
+    }
+);
 $expected_result = [
     ';;',
     ';; BIND configuration file for zone: private',
@@ -247,75 +299,155 @@
 
 
 ########################################################################
+note('Testing PFTools::Utils::make_zone_file');
+can_ok( 'PFTools::Utils', qw( make_zone_file ) );
+
+throws_ok { make_zone_file(); }
+qr{ \A ERROR: [ ] Invalid [ ] [\$] arguments_ref }xms
+    => q{Dies if no args};
+
+my $test_output_file = q{test.zone};
+$result = make_zone_file(
+    {
+        zone_name     => q{private},
+        site_name     => q{cbv4-pfds},
+        filename      => $test_output_file,
+        global_config => $global_config,
+    }
+);
+ok $result => q{Returns true on success};
+
+$result = PFTools::Utils::__read_file_in_array( $test_output_file, 1 );
+
+is_deeply $result, $expected_result
+    => q{Returns the expected result for host cbv4-rdeploy01 site cbv4'}
+    or note explain $result;
+
+ok unlink($test_output_file)
+    => q{Removed the test-generated zone file};
+
+
+########################################################################
 note('Testing PFTools::Utils::make_resolv_conf_file');
 can_ok( 'PFTools::Utils', qw( make_resolv_conf_file ) );
 
 throws_ok { make_resolv_conf_file(); }
+qr{ \A ERROR: [ ] Invalid [ ] [\$] arguments_ref }xms
+    => q{Dies if no args};
+
+throws_ok { make_resolv_conf_file( {} ); }
+qr{ \A ERROR: [ ] Invalid [ ] empty [ ] [\$] filename }xms
+    => q{Dies if empty $filename};
+
+throws_ok { make_resolv_conf_file( { filename => {} } ); }
+qr{ \A ERROR: [ ] Invalid [ ] non-scalar [ ] [\$] filename }xms
+    => q{Dies if non-scalar $filename};
+
+throws_ok { make_resolv_conf_file( { filename => q{filename} } ); }
 qr{ \A ERROR: [ ] Invalid [ ] empty [ ] [\$] hostname }xms
     => q{Dies if empty $hostname};
 
-throws_ok { make_resolv_conf_file( {} ); }
+throws_ok {
+    make_resolv_conf_file(
+        {
+            filename => q{filename},
+            hostname => {},
+        }
+    );
+}
 qr{ \A ERROR: [ ] Invalid [ ] non-scalar [ ] [\$] hostname }xms
     => q{Dies if non-scalar $hostname};
 
-throws_ok { make_resolv_conf_file( q{hostname} ); }
-qr{ \A ERROR: [ ] Invalid [ ] empty [ ] [\$] global_config }xms
+throws_ok {
+    make_resolv_conf_file(
+        {
+            filename => q{filename},
+            hostname => q{name},
+        }
+    );
+}
+qr{ \A ERROR: [ ] Invalid [ ] empty [ ] [\$] global_config}xms
     => q{Dies if empty $global_config};
 
-throws_ok { make_resolv_conf_file( q{hostname}, q{global_config} ); }
-qr{ \A ERROR: [ ] Invalid [ ] non-hashref [ ] [\$] global_config }xms
+throws_ok {
+    make_resolv_conf_file(
+        {
+            filename      => q{filename},
+            hostname      => q{name},
+            global_config => q{global_config},
+        }
+    );
+}
+qr{ \A ERROR: [ ] Invalid [ ] non-hashref [ ] [\$] global_config [ ]}xms
     => q{Dies if non-hashref $global_config};
 
-throws_ok { make_resolv_conf_file( q{name}, {} ); }
+throws_ok {
+    make_resolv_conf_file(
+        {
+            filename      => q{filename},
+            hostname      => q{name},
+            global_config => {},
+        }
+    );
+}
 qr{ \A ERROR: [ ] Invalid [ ] [\$] global_config [ ] hashref:
     [ ] no [ ] 'ZONE' [ ] key [ ] found }xms
     => q{Dies if non-config hashref $global_config};
 
-throws_ok { make_resolv_conf_file( q{hostname}, $global_config ); }
+throws_ok {
+    make_resolv_conf_file(
+        {
+            filename      => q{filename},
+            hostname      => q{hostname},
+            global_config => $global_config,
+        }
+    );
+}
 qr{ \A ERROR: [ ] Invalid [ ] empty [ ] [\$] site_name }xms
     => q{Dies if empty $site_name};
 
-throws_ok { make_resolv_conf_file( q{hostname}, $global_config, {} ); }
+throws_ok {
+    make_resolv_conf_file(
+        {
+            filename      => q{filename},
+            hostname      => q{name},
+            global_config => $global_config,
+            site_name     => {},
+        }
+    );
+}
 qr{ \A ERROR: [ ] Invalid [ ] non-scalar [ ] [\$] site_name }xms
     => q{Dies if non-scalar $site_name};
 
-throws_ok { make_resolv_conf_file( q{hostname}, $global_config, q{site_name} ); }
-qr{ \A ERROR: [ ] Invalid [ ] empty [ ] [\$] filename }xms
-    => q{Dies if empty $filename};
-
-throws_ok { make_resolv_conf_file( q{hostname}, $global_config, q{site_name}, {} ); }
-qr{ \A ERROR: [ ] Invalid [ ] non-scalar [ ] [\$] filename }xms
-    => q{Dies if non-scalar $filename};
-
-throws_ok { make_resolv_conf_file( q{hostname}, $global_config, q{cbv4}, q{filename} ); }
-qr{ \A ERROR: [ ] Unknown [ ] hostname [ ] }xms
-    => q{Dies if unknown $hostname};
-
-throws_ok { make_resolv_conf_file( q{cbv4-spawn00}, $global_config, q{cbv4}, q{filename} ); }
-qr{ \A ERROR: [ ] Unknown [ ] hostname [ ] }xms
-    => q{Dies if unknown $hostname};
-
-my $test_resolv_conf_file = q{test.resolv.conf};
-$result = make_resolv_conf_file( q{cbv4-rdeploy01}, $global_config, q{cbv4}, $test_resolv_conf_file );
+$test_output_file = q{test.resolv.conf};
+$result           = make_resolv_conf_file(
+    {
+        hostname      => q{cbv4-rdeploy01},
+        global_config => $global_config,
+        site_name     => q{cbv4},
+        filename      => $test_output_file,
+    }
+);
 ok $result => q{Returns true on success};
 
-$result = PFTools::Utils::__read_file_in_array( $test_resolv_conf_file, 1 );
+$result = PFTools::Utils::__read_file_in_array( $test_output_file, 1 );
 $expected_result = [
-    q{###############################################},
-    q{# This file was auto-genrated by mk_resolvconf},
+    q{#},
+    q{# This file was auto-generated by mk_resolvconf -- DO NOT EDIT!},
+    q{#},
     q{},
     q{search private},
     q{},
     q{nameserver 10.1.167.0},
     q{nameserver 10.1.167.1},
+    q{},
 ];
-
 
 is_deeply $result, $expected_result
     => q{Returns the expected result for host cbv4-rdeploy01 site cbv4'}
     or note explain $result;
 
-ok unlink($test_resolv_conf_file)
+ok unlink($test_output_file)
     => q{Removed the test-generated resolv.conf file};
 
 
@@ -327,81 +459,356 @@
 qr{ \A ERROR: [ ] Invalid [ ] empty [ ] [\$] hostname }xms
     => q{Dies if empty $hostname};
 
-throws_ok { PFTools::Utils::__build_interfaces( {} ); }
+throws_ok { PFTools::Utils::__build_interfaces( { hostname => {} } ); }
 qr{ \A ERROR: [ ] Invalid [ ] non-scalar [ ] [\$] hostname }xms
     => q{Dies if non-scalar $hostname};
 
-throws_ok { PFTools::Utils::__build_interfaces( q{hostname} ); }
+throws_ok {
+    PFTools::Utils::__build_interfaces( { hostname => q{hostname} } );
+}
 qr{ \A ERROR: [ ] Invalid [ ] empty [ ] [\$] global_config }xms
     => q{Dies if empty $global_config};
 
-throws_ok { PFTools::Utils::__build_interfaces( q{hostname}, q{global_config} ); }
+throws_ok {
+    PFTools::Utils::__build_interfaces(
+        {
+            hostname      => q{hostname},
+            global_config => q{global_config},
+        }
+    );
+}
 qr{ \A ERROR: [ ] Invalid [ ] non-hashref [ ] [\$] global_config }xms
     => q{Dies if non-hashref $global_config};
 
-throws_ok { PFTools::Utils::__build_interfaces( q{name}, {} ); }
+throws_ok {
+    PFTools::Utils::__build_interfaces(
+        {
+            hostname      => q{name},
+            global_config => {},
+        }
+    );
+}
 qr{ \A ERROR: [ ] Invalid [ ] [\$] global_config [ ] hashref:
     [ ] no [ ] 'ZONE' [ ] key [ ] found }xms
     => q{Dies if non-config hashref $global_config};
 
-throws_ok { PFTools::Utils::__build_interfaces( q{hostname}, $global_config ); }
+throws_ok {
+    PFTools::Utils::__build_interfaces(
+        {
+            hostname      => q{hostname},
+            global_config => $global_config,
+        }
+    );
+}
 qr{ \A ERROR: [ ] Invalid [ ] empty [ ] [\$] pf_config }xms
     => q{Dies if empty $pf_config};
 
-throws_ok { PFTools::Utils::__build_interfaces( q{hostname}, $global_config, q{pf_config} ); }
+throws_ok {
+    PFTools::Utils::__build_interfaces(
+        {
+            hostname      => q{hostname},
+            global_config => $global_config,
+            pf_config     => q{pf_config},
+        }
+    );
+}
 qr{ \A ERROR: [ ] Invalid [ ] non-hashref [ ] [\$] pf_config }xms
     => q{Dies if non-hashref $pf_config};
 
-throws_ok { PFTools::Utils::__build_interfaces( q{hostname}, $global_config, {} ); }
+throws_ok {
+    PFTools::Utils::__build_interfaces(
+        {
+            hostname      => q{hostname},
+            global_config => $global_config,
+            pf_config     => {},
+        }
+    );
+}
 qr{ \A ERROR: [ ] Invalid [ ] [\$] pf_config [ ] hashref:
     [ ] no [ ] 'vcs' [ ] key [ ] found }xms
     => q{Dies if non-config hashref $pf_config};
 
-throws_ok { PFTools::Utils::__build_interfaces( q{hostname}, $global_config, $pf_config ); }
+throws_ok {
+    PFTools::Utils::__build_interfaces(
+        {
+            hostname      => q{hostname},
+            global_config => $global_config,
+            pf_config     => $pf_config,
+        }
+    );
+}
 qr{ \A ERROR: [ ] Invalid [ ] empty [ ] [\$] site_name }xms
     => q{Dies if empty $site_name};
 
-throws_ok { PFTools::Utils::__build_interfaces( q{hostname}, $global_config, $pf_config, {} ); }
+throws_ok {
+    PFTools::Utils::__build_interfaces(
+        {
+            hostname      => q{hostname},
+            global_config => $global_config,
+            pf_config     => $pf_config,
+            site_name     => {},
+        }
+    );
+}
 qr{ \A ERROR: [ ] Invalid [ ] non-scalar [ ] [\$] site_name }xms
     => q{Dies if non-scalar $site_name};
 
-$result = PFTools::Utils::__build_interfaces( q{cbv4-rdeploy01}, $global_config, $pf_config, q{cbv4} );
+$result = PFTools::Utils::__build_interfaces(
+    {
+        hostname      => q{cbv4-spawn01},
+        global_config => $global_config,
+        pf_config     => $pf_config,
+        site_name     => q{cbv4-pfds},
+    }
+);
 $expected_result = [
-    q{#},
-    q{# This file was auto-generated by mk_interfaces -- DO NOT EDIT!},
-    q{#},
-    q{},
-    q{auto lo},
-    q{iface lo inet loopback},
-    q{},
-    q{auto eth0},
-    q{iface eth0 inet static},
+    qq{#},
+    qq{# This file was auto-generated by mk_interfaces -- DO NOT EDIT!},
+    qq{#},
+    qq{},
+    qq{auto lo},
+    qq{iface lo inet loopback},
+    qq{},
+    qq{auto bond0},
+    qq{iface bond0 inet static},
+    qq{\tslaves\t\teth2 eth3},
+    qq{\taddress\t\t192.168.1.98},
+    qq{\tnetmask\t\t255.255.255.0},
+    qq{\tnetwork\t\t192.168.1.0},
+    qq{\tbroadcast\t192.168.1.255},
+    qq{},
+    qq{auto eth0},
+    qq{iface eth0 inet static},
     qq{\taddress\t\t10.1.167.1},
     qq{\tnetmask\t\t255.255.0.0},
     qq{\tnetwork\t\t10.1.0.0},
     qq{\tbroadcast\t10.1.255.255},
-    q{},
+    qq{},
+    qq{auto eth0.39},
+    qq{iface eth0.39 inet static},
+    qq{\taddress\t\t10.2.167.1},
+    qq{\tnetmask\t\t255.255.0.0},
+    qq{\tnetwork\t\t10.2.0.0},
+    qq{\tbroadcast\t10.2.255.255},
+    qq{\tvlan_raw_device\teth0},
+    qq{\tup\t\t/sbin/ip link set eth0.39 mtu 1496},
+    qq{},
+    qq{auto eth4},
+    qq{iface eth4 inet static},
+    qq{\taddress\t\t10.3.1.42},
+    qq{\tnetmask\t\t255.255.255.0},
+    qq{\tnetwork\t\t10.3.1.0},
+    qq{\tbroadcast\t10.3.1.255},
+    qq{},
+    qq{auto eth5},
+    qq{iface eth5 inet static},
+    qq{\taddress\t\t10.3.2.42},
+    qq{\tnetmask\t\t255.255.255.0},
+    qq{\tnetwork\t\t10.3.2.0},
+    qq{\tbroadcast\t10.3.2.255},
+    qq{},
 ];
+
+is_deeply $result, $expected_result
+    => q{Returns the expected result for host cbv4-spawn01 site cbv4-pfds'}
+    or note explain $result;
+
+########################################################################
+note('Testing PFTools::Utils::make_interfaces_file');
+can_ok( 'PFTools::Utils', qw( make_interfaces_file ) );
+
+throws_ok { make_interfaces_file(); }
+qr{ \A ERROR: [ ] Invalid [ ] [\$] arguments_ref }xms
+    => q{Dies if no args};
+
+$test_output_file = q{test.interfaces};
+$result = make_interfaces_file(
+    {
+        hostname      => q{cbv4-spawn01},
+        global_config => $global_config,
+        pf_config     => $pf_config,
+        site_name     => q{cbv4-pfds},
+        filename      => $test_output_file,
+    }
+);
+ok $result => q{Returns true on success};
+
+$result = PFTools::Utils::__read_file_in_array( $test_output_file, 1 );
+
+is_deeply $result, $expected_result
+    => q{Returns the expected result for host cbv4-spawn01 site cbv4-pfds'}
+    or note explain $result;
+
+ok unlink($test_output_file)
+    => q{Removed the test-generated interfaces file};
+
+########################################################################
+note('Testing PFTools::Utils::__build_sources_list');
+can_ok( 'PFTools::Utils', qw( __build_sources_list ) );
+
+throws_ok { PFTools::Utils::__build_sources_list(); }
+qr{ \A ERROR: }xms
+    => q{Dies if no $arguments_ref};
+
+throws_ok { PFTools::Utils::__build_sources_list( {} ); }
+qr{ \A ERROR: }xms
+    => q{Dies if empty $arguments_ref};
+
+throws_ok { PFTools::Utils::__build_sources_list( { template => q{} } ); }
+qr{ \A ERROR: [ ] Invalid [ ] empty [ ] [\$] template }xms
+    => q{Dies if empty $template};
+
+throws_ok { PFTools::Utils::__build_sources_list( { template => {} } ); }
+qr{ \A ERROR: [ ] Invalid [ ] non-scalar [ ] [\$] template }xms
+    => q{Dies if non-scalar $template};
+
+throws_ok {
+    PFTools::Utils::__build_sources_list(
+        { template => q{template}, hostname => q{}, sections_ref => q{} }
+    );
+}
+qr{ \A ERROR: [ ] Invalid [ ] empty [ ] [\$] sections_ref }xms
+    => q{Dies if empty $sections_ref};
+
+throws_ok {
+    PFTools::Utils::__build_sources_list(
+        { template => q{template}, hostname => q{}, sections_ref => {} }
+    );
+}
+qr{ \A ERROR: [ ] Invalid [ ] non-array-ref [ ] [\$] sections_ref }xms
+    => q{Dies if non-array-ref $sections_ref};
+
+throws_ok {
+    PFTools::Utils::__build_sources_list(
+        { template => q{template}, hostname => q{}, sections_ref => [] }
+    );
+}
+qr{ \A ERROR: [ ] Invalid [ ] empty-array-ref [ ] [\$] sections_ref }xms
+    => q{Dies if empty-array-ref $sections_ref};
+
+throws_ok {
+    PFTools::Utils::__build_sources_list(
+        { template => q{template}, hostname => q{}, sections_ref => [q{}] }
+    );
+}
+qr{ \A ERROR: [ ] Invalid [ ] empty [ ] or [ ] blank [ ] section [ ] in [ ] array-ref [ ] [\$] sections_ref }xms
+    => q{Dies if empty section in array-ref $sections_ref};
+
+throws_ok {
+    PFTools::Utils::__build_sources_list(
+        { template => q{template}, hostname => q{}, sections_ref => [q{ }] }
+    );
+}
+qr{ \A ERROR: [ ] Invalid [ ] empty [ ] or [ ] blank [ ] section [ ] in [ ] array-ref [ ] [\$] sections_ref }xms
+    => q{Dies if blank section in array-ref $sections_ref};
+
+throws_ok {
+    PFTools::Utils::__build_sources_list(
+        {
+            template     => q{template},
+            sections_ref => [q{section}],
+            backports    => {}
+        }
+    );
+}
+qr{ \A ERROR: [ ] Invalid [ ] non-scalar [ ] [\$] backports }xms
+    => q{Dies if non-scalar $backports};
+
+throws_ok {
+    PFTools::Utils::__build_sources_list(
+        {
+            template      => q{template},
+            sections_ref  => [q{section}],
+            hostname      => q{hostname},
+            global_config => q{foo},
+        }
+    );
+}
+qr{ \A ERROR: [ ] Invalid [ ] non-hashref [ ] [\$] global_config }xms
+    => q{Dies if non-hashref $global_config};
+
+throws_ok {
+    PFTools::Utils::__build_sources_list(
+        {
+            template      => q{template},
+            sections_ref  => [q{section}],
+            hostname      => q{hostname},
+            global_config => {},
+        }
+    );
+}
+qr{ \A ERROR: [ ] Invalid [ ] [\$] global_config [ ] hashref: }xms
+    => q{Dies if non-config hashref $global_config};
+
+throws_ok {
+    PFTools::Utils::__build_sources_list(
+        {
+            template      => q{template},
+            sections_ref  => [q{section}],
+            hostname      => q{hostname},
+            global_config => $global_config,
+            hostname      => q{},
+        }
+    );
+}
+qr{ \A ERROR: [ ] Invalid [ ] empty [ ] [\$] hostname }xms
+    => q{Dies if empty $hostname};
+
+throws_ok {
+    PFTools::Utils::__build_sources_list(
+        {
+            template      => q{template},
+            sections_ref  => [q{section}],
+            hostname      => q{hostname},
+            global_config => $global_config,
+            hostname      => {},
+        }
+    );
+}
+qr{ \A ERROR: [ ] Invalid [ ] non-scalar [ ] [\$] hostname }xms
+    => q{Dies if non-scalar $hostname};
+
+my $test_sections_ref = [qw(common uncommon)];
+
+$expected_result = <<'EOT';
+#
+# Generated by mk_sourceslist -- DO NOT EDIT!
+#
+
+deb http://mirrors.private/debian lenny main contrib non-free
+deb http://mirrors.private/debian-custom lenny-custom common uncommon
+deb http://mirrors.private/debian-security lenny/updates main contrib non-free
+
+EOT
+
+########################################################################
+note('Testing PFTools::Utils::make_sources_list_file');
+can_ok( 'PFTools::Utils', qw( make_sources_list_file ) );
+
+throws_ok { make_sources_list_file(); }
+qr{ \A ERROR: [ ] Invalid [ ] [\$] arguments_ref }xms
+    => q{Dies if no args};
+
+$test_output_file = q{test.sources.list};
+$result = make_sources_list_file(
+    {
+        hostname      => q{cbv4-rdeploy01},
+        site_name     => q{cbv4},
+        filename      => $test_output_file,
+        sections_ref  => $test_sections_ref,
+        template      => q{templates/sources.list},
+        global_config => $global_config,
+        pf_config     => $pf_config,
+    }
+);
+ok $result => q{Returns true on success};
+
+$result = PFTools::Utils::__read_file_in_scalar( $test_output_file );
 
 is_deeply $result, $expected_result
     => q{Returns the expected result for host cbv4-rdeploy01 site cbv4'}
     or note explain $result;
 
-
-########################################################################
-note('Testing PFTools::Utils::make_interfaces_file');
-can_ok( 'PFTools::Utils', qw( make_interfaces_file ) );
-
-my $test_interfaces_file = q{test.interfaces};
-$result = make_interfaces_file( q{cbv4-rdeploy01}, $global_config, $pf_config, q{cbv4}, $test_interfaces_file );
-ok $result => q{Returns true on success};
-
-$result = PFTools::Utils::__read_file_in_array( $test_interfaces_file, 1 );
-
-is_deeply $result, $expected_result
-    => q{Returns the expected result for host cbv4-rdeploy01 site cbv4'}
-    or note explain $result;
-
-ok unlink($test_interfaces_file)
+ok unlink($test_output_file)
     => q{Removed the test-generated interfaces file};
 
diff -r 75b485e19166 -r dd4873cacd2e templates/sources.list
--- a/templates/sources.list	Thu Nov 18 16:55:31 2010 +0100
+++ b/templates/sources.list	Mon Nov 22 11:01:19 2010 +0100
@@ -1,8 +1,8 @@
-# Generated by mk_sourceslist : DO NOT EDIT MANUALLY !
-# Except if you know what you're doing
+#
+# Generated by mk_sourceslist -- DO NOT EDIT!
+#
 
 deb http://mirrors.private/[% mode %] [% distrib %] [% default_sections %]
+deb http://mirrors.private/[% mode %]-custom [% distrib %]-custom [% custom_sections %]
+deb http://mirrors.private/[% mode %]-security [% distrib %]/updates [% default_sections %]
 
-deb http://mirrors.private/[% mode %]-custom [% distrib %]-custom [% custom_sections %]
-
-deb http://mirrors.private/[% mode %]-security [% distrib %]/updates [% default_sections %]



More information about the pf-tools-commits mailing list