From 14dbc9d0b824bc02467d0a9133c7d44b6e739c0a Mon Sep 17 00:00:00 2001 From: Michael Prokop Date: Mon, 22 Feb 2016 23:00:51 +0100 Subject: [PATCH] MT#16719 Support cloning of host sections When setting up carrier environments we have to deal with many similar nodes, often involving >10 proxy pairs. By default we create prx01a and prx01b sections only. Provide --clone-from= --clone-to= options as convenience helpers so the operator can clone a specific host definition and just needs to adapt IP addresses accordingly afterwards. Use example to clone the prox01a host definition to prox02a, prox03a,.... up to prox10a: for host in {02..10} ; do ngcp-network --clone-from=prx01a --clone-to=prx${host}a done If the peer setting (as used in carrier environments) is present in the source host config (--clone-from=...) then we automatically set the peer for the destination, like: | # ngcp-network --clone-from=prx01a --clone-to=prx01b | Setting peer of host 'prx01b' to 'prx01a' | Finished cloning host section 'prx01a' to 'prx01b'. | Please do not forget to manually adjust '/etc/ngcp-config/network.yml'! and: | # ngcp-network --clone-from=prx01a --clone-to=prx04a | Setting peer of host 'prx04a' to 'prx04b' | Finished cloning host section 'prx01a' to 'prx04a'. | Please do not forget to manually adjust '/etc/ngcp-config/network.yml'! Change-Id: I6c30a2ce58dd8bc66247cfdd0028c18736173e99 --- sbin/ngcp-network | 79 +++++++++++++++++++++++++++++++++++++++++++++- testsuite/cpanfile | 1 + 2 files changed, 79 insertions(+), 1 deletion(-) diff --git a/sbin/ngcp-network b/sbin/ngcp-network index 568b5772..cf9e2a57 100755 --- a/sbin/ngcp-network +++ b/sbin/ngcp-network @@ -15,6 +15,7 @@ use Net::Netmask; use Pod::Usage; use Regexp::IPv6 qw($IPv6_re); use Socket; +use Storable qw(dclone); use Sys::Hostname; use YAML::Tiny; @@ -33,6 +34,8 @@ my $bond_miimon; my $bond_mode; my $bond_slaves; my $broadcast; +my $clone_from; +my $clone_to; my $dbnode; my @dns_nameservers; my $gateway; @@ -65,6 +68,8 @@ GetOptions( 'bond-mode=s' => \$bond_mode, 'bond-slaves=s' => \$bond_slaves, 'broadcast=s' => \$broadcast, + 'clone-from=s' => \$clone_from, + 'clone-to=s' => \$clone_to, 'dbnode:i' => \$dbnode, 'dns=s' => \@dns_nameservers, 'gateway=s' => \$gateway, @@ -128,7 +133,8 @@ if ($ip_v6) { } foreach my $opt ( - $bond_miimon, $bond_mode, $broadcast, $dbnode, @dns_nameservers, + $bond_miimon, $bond_mode, $broadcast, $clone_from, + $clone_to, $dbnode, @dns_nameservers, $gateway, @set_interface, $host, $hwaddr, $internal_iface, $ip, $ip_v6, $move_from, $move_to, $netmask, $peer, @remove_host, @@ -390,6 +396,58 @@ sub set_dbnode { return; } +sub clone_settings { + my $from = shift; + my $to = shift; + + if ( defined $from && !defined $to ) { + croak '--clone-from option must be used with --clone-to option together'; + } + + if ( !defined $from && defined $to ) { + croak '--clone-to option must be used with --clone-from option together'; + } + + # ha, nothing to do for us + if ( !defined $from && !defined $to ) { + return; + } + + logger("clone from = $from"); + logger("clone to = $to"); + + if ( !defined $yaml->[0]->{hosts}->{$from} ) { + croak "Host '$from' doesn\'t exist, refusing to clone settings."; + } + + $yaml->[0]->{hosts}->{$to} = dclone($yaml->[0]->{hosts}->{$from}); + + # adjust peer on-the-fly to prevent user mistakes + if ( defined $yaml->[0]->{hosts}->{$from}->{peer} ) { + + if ( $to !~ /[ab]$/ ) { + carp "Target host $from not ending with 'a' or 'b', skipping automatic peer config."; + } else { + logger('Target host matching ".*[ab]$" pattern'); + + my $other_node; + if ( $to =~ /a$/ ) { + $other_node = $to =~ s/a$/b/r; + } else { + $other_node = $to =~ s/b$/a/r; + } + print "Setting peer for host '$to' to '$other_node'.\n"; + $yaml->[0]->{hosts}->{$to}->{peer} = $other_node; + } + } + + print "Finished cloning host section '$from' to '$to'.\n" or croak 'Output error'; + print "Please do not forget to manually adjust '$outputfile'!\n" or croak 'Output error'; + + return; +} + + sub move_settings { my $from = shift; my $to = shift; @@ -503,6 +561,7 @@ if ( defined $dbnode && ( !defined $move_from || !defined $move_to ) ) move_settings( $move_from, $move_to ); +clone_settings ( $clone_from, $clone_to ); open my $fh, '>', "$outputfile" or croak "Could not open $outputfile for writing"; @@ -545,6 +604,23 @@ Set bond_slaves configuration to specified argument. Set broadcast configuration to specified argument. +=item B<--clone-from=> + +Clone specified HOST section, using specified HOST setting as its source. +Please do not forget to manually adjust the resulting configuration file, no +further checks like duplicated IPs are performed. Needs to be used in +combination with the '--clone-to=' option. + +This option is useful especially in carrier setups with plenty of similar +web/db/proxy/.... systems, where the host definition of a host like 'prx01a' +should be used as base for another host 'prx02a'. Usage example: +'--clone-from=prx01a --clone-to=prx02a' + +=item B<--clone-to=> + +Clone specified HOST section, using specified HOST setting as its destination. +Refer to '--clone-from=' for further information. + =item B<--dbnode=> Set dbnode configuration to specified number argument. If no value @@ -705,6 +781,7 @@ Usage examples useful especially on sip:provider PRO systems: Usage examples useful especially on sip:carrier systems: ngcp-network --host=proxy2 --set-interface=eth0 --ip=192.168.10.42 --netmask=255.255.255.0 + ngcp-network --clone-from=prx01a --clone-to=prx02a =head1 REQUIRED ARGUMENTS diff --git a/testsuite/cpanfile b/testsuite/cpanfile index 4f8f9338..34a0612e 100644 --- a/testsuite/cpanfile +++ b/testsuite/cpanfile @@ -1,4 +1,5 @@ requires 'Carp'; +requires 'Data::Clone'; requires 'Data::Validate::IP'; requires 'Getopt::Long'; requires 'IO::Interface';