#!/usr/bin/perl use strict; use warnings; use English; use Getopt::Long; use Pod::Usage; use NGCP::API::Client; use Readonly; use XML::Simple; use Template; use Email::Sender::Simple qw(); use Email::Simple; use Email::Simple::Creator; use Email::Sender::Transport::Sendmail qw(); Readonly my @required => qw(); Readonly my $config_file => '/etc/ngcp-panel/provisioning.conf'; my $page_size = 10; my $opts = { verbose => 0, }; my $config; GetOptions( $opts, "help|h" => \&usage, "verbose", ) or usage(); sub check_params { my @missing; foreach my $param (@required) { push @missing, $param unless $opts->{$param}; } usage(join(' ', @missing)) if scalar @missing; return; } sub usage { my $msg = shift; pod2usage(-exitval => $msg ? 1 : 0, -verbose => 99, -message => $msg ? $msg =~ /not found/i ? $msg : "Missing parameters: $msg" : '', ); return; } sub load_config { $config = XML::Simple->new()->XMLin($config_file, ForceArray => [ 'credit_warnings' ]) or die "Cannot load config: $config_file: $ERRNO"; return; } sub send_email { my ($cwarning, $contracts) = @_; my $template = get_email_template() || return; my $vars = { domain => $cwarning->{domain}, threshold => $cwarning->{threshold}, adminmail => $config->{adminmail} }; foreach my $data (@{$contracts}) { if (exists $data->{threshold}) { $vars->{contracts} .= sprintf <{contracts} .= sprintf <new(); map { my $out; $tt->process(\$template->{$_}, $vars, \$out); $out and $template->{$_} = $out; } keys %{$template}; my $transport = Email::Sender::Transport::Sendmail->new; my $email = Email::Simple->create( header => [ To => ref $cwarning->{recipients} eq 'ARRAY' ? join(', ', @{$cwarning->{recipients}}) : $cwarning->{recipients}, From => $template->{from_email}, Subject => $template->{subject}, ], body => $template->{body}, ); Email::Sender::Simple->send($email, { transport => $transport }) or die sprintf "Cannot send credit warning notification to %s: $ERRNO", $email->header('To'); return; } sub get_data { my ($uri, $link, $process_code) = @_; $process_code = sub { my $data = shift; return 0; } unless 'CODE' eq ref $process_code; my $client = new NGCP::API::Client; $client->set_verbose($opts->{verbose}); $client->set_page_rows($page_size); my @result = (); while (my $res = $client->next_page($uri)) { die $res->result unless $res->is_success; my $res_hash = $res->as_hash; my $data = $res_hash->{_embedded}{'ngcp:'.$link}; if ('ARRAY' eq ref $data) { unless (&$process_code($data)) { push(@result,@$data); } } elsif ($data) { unless (&$process_code([$data])) { push(@result,$data); } } } return \@result; } sub get_email_template { my $templates_data = get_data('/api/emailtemplates/', 'emailtemplates'); foreach my $template (@{$templates_data}) { next unless $template->{name} eq 'credit_warning_default_email'; return $template; } return; } sub main { check_params(); load_config(); my $cwarnings = ref $config->{credit_warnings} eq 'ARRAY' ? $config->{credit_warnings} : [ $config->{credit_warnings} ]; foreach my $cwarning (@{$cwarnings}) { unless ($cwarning->{recipients}) { die "No recipients defined for domain: $cwarning->{domain}"; } unless ($cwarning->{domain}) { die "Missing domain in a credit warning check"; } my @contracts; get_data(sprintf('/api/customerbalances/?no_count=true&domain=%s&prepaid=1', $cwarning->{domain}), 'customerbalances', sub { my $balances = shift; foreach my $balance (@{$balances}) { my $ratio = $balance->{ratio} // 1.0; my $threshold = $cwarning->{threshold} * $ratio; next if $balance->{cash_balance} >= $threshold; my $data = { map { $_ => $balance->{$_} } qw(id cash_balance) }; $data->{threshold} = $threshold if $ratio < 1.0; push @contracts,$data; } return 1; } ); if (@contracts) { eval { send_email($cwarning, \@contracts); }; print $EVAL_ERROR if $EVAL_ERROR; } } return; } main(); exit 0; __END__ =head1 NAME ngcp-credit-warning - checks for contract balances above credit warning thresholds =head1 SYNOPSIS B [I...] =head1 DESCRIPTION B checks for contract balances above credit warning thresholds and sends email notifications about the incidents. =head1 OPTIONS =over 8 =item B<--verbose> Show additional debug information. Default false. =item B<--help> Print a brief help message. =back =head1 EXIT STATUS Exit code 0 means everything is ok otherwise 1. =head1 SEE ALSO NGCP::API::Client =head1 BUGS AND LIMITATIONS Please report problems you notice to the Sipwise Development Team . =head1 AUTHOR Kirill Solomko =head1 LICENSE Copyright (C) 2016 Sipwise GmbH, Austria This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see .