#!/usr/bin/perl -CSD # Purpose: template toolkit helper script ################################################################################ use strict; use warnings; use English; use YAML::XS qw(LoadFile); use Template; use Hash::Merge qw(merge); use DBI; use Capture::Tiny qw(capture); sub sync_extra_sockets; sub db_connect; my $dbh; my $tt = Template->new({ ABSOLUTE => 1, RELATIVE => 1 }); my $config = {}; foreach my $file (@ARGV) { $config = merge($config, LoadFile($file)); } # rw connection to central node my $dbhost = $config->{database}->{central}->{dbhost}; my $dbport = $config->{database}->{central}->{dbport}; open my $SWFH, '<', '/etc/mysql/sipwise.cnf'; my $dbpass = join ' ', <$SWFH>; close $SWFH; $dbpass =~ s/^.*SIPWISE_DB_PASSWORD=\'([^\']+)\'.*$/$1/; chomp $dbpass; my $dbuser = 'sipwise'; my $dbname = $config->{ossbss}->{provisioning}->{database}->{name}; unless(defined $dbhost) { print "Error: Could not determine provisioning db hostname\n"; exit 1; } unless(defined $dbport) { print "Error: Could not determine provisioning db port\n"; exit 1; } unless(defined $dbname) { print "Error: Could not determine provisioning db name\n"; exit 1; } unless(defined $dbuser) { print "Error: Could not determine provisioning db user\n"; exit 1; } unless(defined $dbpass) { print "Error: Could not determine provisioning db password\n"; exit 1; } $dbh = db_connect(); exit 1 unless(sync_extra_sockets($dbh, $config->{kamailio}->{lb}->{extra_sockets}, 1, 1, 1)); exit 1 unless(sync_rtp_interfaces($dbh, { map {my $tmp = $_; $tmp =~ s/:.*//; ($_ => $_, $tmp => $tmp)} @{$config->{rtp_interfaces}} }, 1, 1, 1)); exit 1 unless(sync_smsc_peers($dbh, { map { ($_->{id} => $_->{id}) } @{$config->{sms}->{smsc}} }, 0, 1, 0)); exit 1 unless(sync_general_timezone($dbh, $config->{general}->{timezone})); exit 1 unless(sync_db_timezones($dbh)); $dbh->disconnect; exit 0; sub db_connect { my $dbh = DBI->connect("DBI:mysql:database=${dbname};host=${dbhost};port=${dbport}", $dbuser, $dbpass, { PrintError => 1 }); unless(defined $dbh) { print "Error: Could not connect to database '$dbname' at '$dbhost:$dbport' as '${dbuser}': $DBI::errstr\n"; exit 1; } return $dbh; } sub generic_enum_sync { my $dbh = shift; my $config_hash = shift; my $usr_pref = shift; my $dom_pref = shift; my $peer_pref = shift; my $pref_name = shift; my $sth = $dbh->prepare("select id from voip_preferences where attribute=?"); $sth->execute($pref_name); my $res = $sth->fetchrow_hashref(); unless(defined $res) { print "Error: Could not find preference '$pref_name' in db\n"; return; } my $pref_id = $res->{id}; $sth->finish; my $enum_insert_sth = $dbh->prepare("insert into voip_preferences_enum (preference_id, label, value, usr_pref, dom_pref, peer_pref) values(?, ?, ?, ?, ?, ?)"); my $enum_update_sth = $dbh->prepare("update voip_preferences_enum set value=? where id=?"); my $enum_delete_sth = $dbh->prepare("delete from voip_preferences_enum where id=?"); $sth = $dbh->prepare("select id, label, value from voip_preferences_enum where preference_id=?"); $sth->execute($pref_id); my $db_hash = $sth->fetchall_hashref('label'); $sth->finish; foreach my $row (keys %{$db_hash}) { $row = $db_hash->{$row}; next if($row->{label} eq 'default'); if(!exists $config_hash->{$row->{label}}) { print "$pref_name $row->{label} does not exist anymore in config, delete from db\n"; $enum_delete_sth->execute($row->{id}); } elsif($config_hash->{$row->{label}} ne $row->{value}) { print "update $pref_name $row->{label}=$row->{value} to $row->{label}=$config_hash->{$row->{label}} in db\n"; $enum_update_sth->execute($config_hash->{$row->{label}}, $row->{id}); delete $config_hash->{$row->{label}}; } else { print "$pref_name $row->{label}=$row->{value} is sync between config and db\n"; delete $config_hash->{$row->{label}}; } } foreach my $label(keys %{$config_hash}) { print "insert new $pref_name $label=$config_hash->{$label} from config into db\n"; $enum_insert_sth->execute($pref_id, $label, $config_hash->{$label}, $usr_pref ? 1 : 0, $dom_pref ? 1 : 0, $peer_pref ? 1: 0); } $enum_insert_sth->finish; $enum_update_sth->finish; $enum_delete_sth->finish; return 1; } ## kamailio.lb.extra_sockets handling: ############################## sub sync_extra_sockets { return generic_enum_sync(@_, 'outbound_socket'); } ## rtp_* interfaces handling: ############################## sub sync_rtp_interfaces { return generic_enum_sync(@_, 'rtp_interface'); } # ## smsc_* interfaces handling: ############################## sub sync_smsc_peers { return generic_enum_sync(@_, 'smsc_peer'); } ## general.timezone handling: ############################## sub sync_general_timezone { my $dbh = shift; my $tz = shift; unless ($tz) { print "Error: general.timezone value is not set\n"; return; } my $pe = $dbh->{PrintError}; $dbh->{PrintError} = 0; $dbh->do(<{PrintError} = $pe; if ($DBI::err) { print "Error: Could not insert into ngcp.timezone: $DBI::errstr\n"; return; } return 1; } ## /usr/share/zoneinfo into MariaDB ############################## sub sync_db_timezones { my $dbh = shift; my ($out, $err, $rc) = capture { system('/usr/bin/mysql_tzinfo_to_sql /usr/share/zoneinfo'); }; if ($rc) { print "Error: $err\n"; return; } my ($tzinfo_version, undef, undef) = capture { system('dpkg -s tzdata | grep Version:'); }; unless ($tzinfo_version && $tzinfo_version =~ /Version:\s*(\S+)/) { print "Error: Could not retrieve tzdata package version\n"; return; } $tzinfo_version = $1; my $pe = $dbh->{PrintError}; $dbh->{PrintError} = 0; my $sql = ''; my $p_rs = $RS; eval { $dbh->begin_work() or die "Cannot start tx: ".$DBI::errstr; my ($cur_tzinfo_version) = $dbh->selectrow_array(<do('USE mysql') or die "Cannot use mysql database: $DBI::errstr\n"; while ($sql = <$sql_stream>) { map { $dbh->do($_) or die "Cannot insert timezone data: $DBI::errstr\n"; } split /;\s+/, $sql; # multiple one line statements } close $sql_stream; $dbh->do(<{PrintError} = $pe; if ($err) { print $err,"sql: $sql\n"; $dbh->rollback(); return; } $dbh->commit(); return 1; } ## END OF FILE #################################################################