#!/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' => sub { 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 $missing = shift; pod2usage( -exitval => $missing ? 1 : 0, -verbose => 1, -message => $missing ? "Missing parameters: $missing" : '', ); return; } sub load_config { $config = XML::Simple->new()->XMLin( $config_file, ForceArray => [ 'credit_warnings' ], ) or die "Cannot load config: $config_file: $ERRNO\n"; 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}) { $vars->{contracts} .= sprintf ('contract_id: %s cash_balance: %s', @{$data}{qw(id cash_balance)}); $vars->{contracts} .= ' external_id: '. $data->{external_id} if $data->{external_id}; $vars->{contracts} .= ' threshold: '. $data->{threshold} if $data->{threshold}; $vars->{contracts} .= "\n"; } my $tt = Template->new(); foreach my $field (keys %{$template}) { my $out; $tt->process(\$template->{$field}, $vars, \$out); $template->{$field} = $out if $out; } 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\n", $email->header('To'); return; } sub get_data { my ($uri, $link, $process_code) = @_; $process_code = sub { return 0 } if 'CODE' ne ref $process_code; my $client = NGCP::API::Client->new( verbose => $opts->{verbose}, page_rows => $page_size, ); my @result = (); while (my $res = $client->next_page($uri)) { return [] unless check_api_error($res); 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 check_api_error { my $res = shift; if ($res->is_success) { return 1; } else { die($res->result . "\n") if ( $res->is_client_error or ($res->is_server_error and not scalar grep { $_ == $res->code; } qw(502 503 504)) ); return 0; } } 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}\n"; } unless ($cwarning->{domain}) { die "Missing domain in a credit warning check\n"; } 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 external_id) }; $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 0; } exit main(); __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 =over =item B<0> Command completed successfully. =item B<1> Command failed with errors. =back =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 .