You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
244 lines
6.5 KiB
244 lines
6.5 KiB
#!/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 => 1,
|
|
-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 <<EOF_RATIO, @{$data}{qw(id cash_balance threshold)};
|
|
contract_id: %s cash_balance: %s (threshold: %s)
|
|
EOF_RATIO
|
|
} else {
|
|
$vars->{contracts} .= sprintf <<EOF, @{$data}{qw(id cash_balance)};
|
|
contract_id: %s cash_balance: %s
|
|
EOF
|
|
}
|
|
}
|
|
|
|
my $tt = Template->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<ngcp-credit-warning> [I<options>...]
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
B<This program> 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 <support@sipwise.com>.
|
|
|
|
=head1 AUTHOR
|
|
|
|
Kirill Solomko <ksolomko@sipwise.com>
|
|
|
|
=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 <http://www.gnu.org/licenses/>.
|