diff --git a/bin/ngcp-api_ping b/bin/ngcp-api_ping old mode 100644 new mode 100755 index 1e35d94..6091e1b --- a/bin/ngcp-api_ping +++ b/bin/ngcp-api_ping @@ -1,125 +1,92 @@ #!/usr/bin/perl use strict; use warnings; -use Config::Tiny; use English; use Getopt::Long; -use JSON qw(); -use LWP::UserAgent; +use NGCP::API::Client; use Pod::Usage; -use IO::Socket::SSL; +use Readonly; + +Readonly my @required => qw(); -my $config = Config::Tiny->read('/etc/default/ngcp-api'); my $opts = { - host => '127.0.0.1', - port => 1443, - auth_user => 'administrator', - auth_pwd => 'administrator', verbose => 0, - admin => 0 }; -if ($config) { - $opts->{host} = $config->{_}->{NGCP_API_IP}; - $opts->{port} = $config->{_}->{NGCP_API_PORT}; - $opts->{sslverify} = $config->{_}->{NGCP_API_SSLVERIFY} || 'yes'; -} - GetOptions( $opts, - "help|h" => sub { pod2usage(-exitval =>0); }, - "host=s", - "port=i", - "auth_user=s", - "auth_pwd=s", + "help|h" => \&usage, "verbose", - "man" => sub { pod2usage(-exitval => 0, -verbose => 2); }, -) or pod2usage(2); +) or usage(); -sub main { - my $urlbase = 'https://'.$opts->{host}.':'.$opts->{port}; - my $ua = LWP::UserAgent->new(); - if($opts->{sslverify} eq 'no') { - $ua->ssl_opts( - verify_hostname => 0, - SSL_verify_mode => IO::Socket::SSL::SSL_VERIFY_NONE, - ); - } - $ua->credentials($opts->{host}.':'.$opts->{port}, 'api_admin_http', - $opts->{auth_user}, $opts->{auth_pwd}); - # debug!! - if($opts->{verbose}) { - $ua->show_progress(1); - $ua->add_handler("request_send", sub { shift->dump; return }); - $ua->add_handler("response_done", sub { shift->dump; return }); - } - my $url = $urlbase . '/api/domains/'; - my $res = do_request($ua, $url); - if($res->is_success) { - print "API up\n"; - } else { - die $res->as_string; +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 => 99, + -sections => [ qw(NAME OPTIONS USAGE) ], + -message => $missing ? "Missing parameters: $missing" : '', + ); return; } -sub do_request { - my $ua = shift; - my $url = shift; - my $req = HTTP::Request->new('GET', $url); - $req->header('Content-Type' => 'application/json'); - $req->header('Prefer' => 'return=representation'); +sub main { + check_params(); + my $client = new NGCP::API::Client; + my $uri = '/api/domains/'; + $client->set_verbose($opts->{verbose}); + my $res = $client->request("GET", $uri); + my $rc = 0; + if (defined $res->as_hash->{total_count}) { + print "API is up\n"; + } else { + print "API is down\n"; + $rc = 1; + } - return $ua->request($req); + exit $rc; + + return; } main(); +exit 0; + __END__ + =head1 NAME ngcp-api_ping - check NGCP API status -=head1 SYNOPSIS - -ngcp-api_ping [options] - =head1 OPTIONS =over 8 =item B<-help> -Print a brief help message and exits. - -=item B<-auth_user> - -Authentication username . Defaults to 'administrator'. - -=item B<-auth_pwd> - -Authentication password . Defaults to 'administrator'. - -=item B<-host> - -Host where the send queries. Defaults to '127.0.0.1'. - -=item B<-port> - -Port where the send queries. Defaults to 1443. +Print a brief help message. =item B<-verbose> -See debug information. Default false. +Show additional debug information. Default false. =back -=head1 DESCRIPTION +=head1 USAGE -B<This program> will check NGCP API. +ngcp-api_ping [options] -=head1 USAGE +=head1 DESCRIPTION -ngcp-api-check -host 1.2.3.4 +B<This program> checks if NGCP API is running. =head1 REQUIRED ARGUMENTS @@ -127,18 +94,20 @@ None =head1 EXIT STATUS -Exit code 0 means that everything should have went fine otherwise error. +Exit code 0 means everything is fine otherwise 1. + +=head1 CONFIGURATION =head1 DIAGNOSTICS -=head1 CONFIGURATION +=head1 SEE ALSO -/etc/default/ngcp-api for default values +NGCP::API::Client =head1 DEPENDENCIES ngcp-api_ping relies on a bunch of Perl modules, all of them specified as -dependencies through the ngcp-ossbss-clients-perl Debian package. +dependencies through the ngcp-panel Debian package. =head1 INCOMPATIBILITIES @@ -153,17 +122,21 @@ Development Team <support@sipwise.com>. Victor Seva <vseva@sipwise.com> -=head1 LICENSE +=head1 LICENSE AND COPYRIGHT + +Copyright (C) 2016 Sipwise GmbH, Austria -Copyright (c) 2015 Sipwise GmbH, Austria. -All rights reserved. You may not copy, distribute -or modify without prior written permission from -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. -=head1 LICENSE AND COPYRIGHT +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. -Copyright (c) 2015 Sipwise GmbH, Austria. -You should have received a copy of the licence terms together with the -software. +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. =cut diff --git a/bin/ngcp-create_customer b/bin/ngcp-create_customer index c9f669f..90d86e6 100755 --- a/bin/ngcp-create_customer +++ b/bin/ngcp-create_customer @@ -1,99 +1,70 @@ #!/usr/bin/perl use strict; use warnings; -use Config::Tiny; use English; use Getopt::Long; -use JSON qw(); -use LWP::UserAgent; use Pod::Usage; -use IO::Socket::SSL; +use NGCP::API::Client; +use Readonly; + +Readonly my @required => qw(billing_profile_id contact_id); -my $config = Config::Tiny->read('/etc/default/ngcp-api'); my $opts = { - billing_id => 1, - contact_id => 1, - type => 'sipaccount', - host => '127.0.0.1', - port => 1443, - auth_user => 'administrator', - auth_pwd => 'administrator', - verbose => 0 + type => 'sipaccount', + status => 'active', + verbose => 0, }; -if ($config) { - $opts->{host} = $config->{_}->{NGCP_API_IP}; - $opts->{port} = $config->{_}->{NGCP_API_PORT}; - $opts->{sslverify} = $config->{_}->{NGCP_API_SSLVERIFY} || 'yes'; -} - GetOptions( $opts, - "help|h" => sub { pod2usage(-exitval =>0); }, - "billing_id=i", + "help|h" => \&usage, + "billing_profile_id=i", "contact_id=i", - "host=s", - "port=i", - "auth_user=s", - "auth_pwd=s", - "verbose", "type=s", - "man" => sub { pod2usage(-exitval => 0, -verbose => 2); } -) or pod2usage(2); + "verbose", +) or usage(); -sub main { - my $urlbase = 'https://'.$opts->{host}.':'.$opts->{port}; - my $data = { - billing_profile_id => $opts->{billing_id}, - contact_id => $opts->{contact_id}, - type => $opts->{type}, - status => 'active', - }; - my $ua = LWP::UserAgent->new(); - if($opts->{sslverify} eq 'no') { - $ua->ssl_opts( - verify_hostname => 0, - SSL_verify_mode => IO::Socket::SSL::SSL_VERIFY_NONE, - ); - } - $ua->credentials($opts->{host}.':'.$opts->{port}, 'api_admin_http', - $opts->{auth_user}, $opts->{auth_pwd}); - # debug!! - if($opts->{verbose}) { - $ua->show_progress(1); - $ua->add_handler("request_send", sub { shift->dump; return }); - $ua->add_handler("response_done", sub { shift->dump; return }); - } - my $res = do_request($ua, $urlbase, $data); - if($res->is_success) { - print $res->status_line . ' ' . $res->header('Location'). "\n"; - } else { - die $res->as_string; +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 => 99, + -sections => [ qw(NAME OPTIONS USAGE) ], + -message => $missing ? "Missing parameters: $missing" : '', + ); return; } -sub do_request { - my $ua = shift; - my $urlbase = shift; - my $data = shift; +sub main { + check_params(); - my $req = HTTP::Request->new('POST', $urlbase.'/api/customers/'); - $req->header('Content-Type' => 'application/json'); - $req->header('Prefer' => 'return=representation'); - $req->content(JSON::to_json($data)); - return $ua->request($req); + my $uri = '/api/customers/'; + my %data = map { $_ => $opts->{$_} } + qw(billing_profile_id contact_id type status); + my $client = new NGCP::API::Client; + $client->set_verbose($opts->{verbose}); + my $res = $client->request("POST", $uri, \%data); + print $res->result."\n"; + + return; } main(); +exit 0; + __END__ -=head1 NAME -ngcp-create_customer - create a customer on NGCP +=head1 NAME -=head1 SYNOPSIS - -ngcp-create_customer [options] +ngcp-create_customer - create a customer =head1 OPTIONS @@ -101,31 +72,15 @@ ngcp-create_customer [options] =item B<-help> -Print a brief help message and exits. - -=item B<-auth_user> - -Authentication username . Defaults to 'administrator'. - -=item B<-auth_pwd> - -Authentication password . Defaults to 'administrator'. +Print a brief help message. -=item B<-host> +=item B<-billing_profile_id> -Host where the send queries. Defaults to '127.0.0.1'. - -=item B<-port> - -Port where the send queries. Defaults to 1443. - -=item B<-billing_id> - -The billing profile id. Defaults to 1. +Billing profile id. =item B<-contact_id> -The contact id. Defaults to 1. +Contact id. =item B<-type> @@ -134,36 +89,46 @@ Customer can be one of the "sipaccount" or "pbxaccount" type. Defaults to =item B<-verbose> -See debug information. Default false. +Show additional debug information. Default false. =back -=head1 DESCRIPTION +=head1 USAGE -B<This program> will create a subscriber at NGCP. +ngcp-create_customer [options] -=head1 USAGE +ngcp-create_customer --billing_profile_id 1 --contact_id 4 --type sipaccount -ngcp-create_customer -host 1.2.3.4 -billing_id 1 -profile_id 4 -type sipaccount +=head1 DESCRIPTION + +B<This program> creates a customer on the NGCP platform. =head1 REQUIRED ARGUMENTS -TODO +=over 8 + +=item B<-billing_profile_id> + +=item B<-contact_id> + +=back =head1 EXIT STATUS -Exit code 0 means that everything should have went fine otherwise error. +Exit code 0 means everything is ok otherwise 1. + +=head1 CONFIGURATION =head1 DIAGNOSTICS -=head1 CONFIGURATION +=head1 SEE ALSO -/etc/default/ngcp-api for default values +NGCP::API::Client =head1 DEPENDENCIES ngcp-create_customer relies on a bunch of Perl modules, all of them specified as -dependencies through the ngcp-ossbss-clients-perl Debian package. +dependencies through the Debian package. =head1 INCOMPATIBILITIES @@ -178,17 +143,21 @@ Development Team <support@sipwise.com>. Victor Seva <vseva@sipwise.com> -=head1 LICENSE +=head1 LICENSE AND COPYRIGHT -Copyright (c) 2015 Sipwise GmbH, Austria. -All rights reserved. You may not copy, distribute -or modify without prior written permission from -Sipwise GmbH, Austria. +Copyright (C) 2016 Sipwise GmbH, Austria -=head1 LICENSE AND COPYRIGHT +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. -Copyright (c) 2015 Sipwise GmbH, Austria. -You should have received a copy of the licence terms together with the -software. +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. =cut diff --git a/bin/ngcp-create_domain b/bin/ngcp-create_domain index cf0859c..3318eb3 100755 --- a/bin/ngcp-create_domain +++ b/bin/ngcp-create_domain @@ -1,104 +1,72 @@ #!/usr/bin/perl use strict; use warnings; -use Config::Tiny; use English; use Getopt::Long; -use JSON qw(); -use LWP::UserAgent; use Pod::Usage; -use IO::Socket::SSL; +use NGCP::API::Client; +use Readonly; + +Readonly my @required => qw(domain); -my $config = Config::Tiny->read('/etc/default/ngcp-api'); my $opts = { + domain => $ARGV[0], reseller_id => 1, - host => '127.0.0.1', - port => 1443, - auth_user => 'administrator', - auth_pwd => 'administrator', - verbose => 0, skip_xmpp => 0, skip_sip => 0, + verbose => 0, }; -if ($config) { - $opts->{host} = $config->{_}->{NGCP_API_IP}; - $opts->{port} = $config->{_}->{NGCP_API_PORT}; - $opts->{sslverify} = $config->{_}->{NGCP_API_SSLVERIFY} || 'yes'; -} - GetOptions( $opts, - "help|h" => sub { pod2usage(-exitval =>0); }, + "help|h" => \&usage, + "domain=s", "reseller_id=i", - "host=s", - "port=i", - "auth_user=s", - "auth_pwd=s", "skip_xmpp", "skip_sip", "verbose", - "man" => sub { pod2usage(-exitval => 0, -verbose => 2); }, -) or pod2usage(2); - -die pod2usage(-exitval => 1, -message => "No domain") unless ($#ARGV == 0); +) or usage(); -sub main { - my $domain = shift; - my $urlbase = 'https://'.$opts->{host}.':'.$opts->{port}; - my $data = { - domain => $domain, - reseller_id => $opts->{reseller_id}, - ($opts->{skip_xmpp} ? (_skip_xmpp_reload => 1) : ()), - ($opts->{skip_sip} ? (_skip_sip_reload => 1) : ()), - }; - my $ua = LWP::UserAgent->new(); - if($opts->{sslverify} eq 'no') { - $ua->ssl_opts( - verify_hostname => 0, - SSL_verify_mode => IO::Socket::SSL::SSL_VERIFY_NONE, - ); - } - $ua->credentials($opts->{host}.':'.$opts->{port}, 'api_admin_http', - $opts->{auth_user}, $opts->{auth_pwd}); - # debug!! - if($opts->{verbose}) { - $ua->show_progress(1); - $ua->add_handler("request_send", sub { shift->dump; return }); - $ua->add_handler("response_done", sub { shift->dump; return }); - } - - my $res = do_request($ua, $urlbase, $data); - if($res->is_success) { - print $res->status_line . ' ' . $res->header('Location') . "\n"; - } else { - die $res->as_string; +sub check_params { + my @missing; + foreach my $param (@required) { + push @missing, $param unless $opts->{$param}; } + usage(join(' ', @missing)) if scalar @missing; return; } -sub do_request { - my $ua = shift; - my $urlbase = shift; - my $data = shift; +sub usage { + my $missing = shift; + pod2usage(-exitval => $missing ? 1 : 0, + -verbose => 99, + -sections => [ qw(NAME OPTIONS USAGE) ], + -message => $missing ? "Missing parameters: $missing" : '', + ); + return; +} - my $req = HTTP::Request->new('POST', $urlbase."/api/domains/"); - $req->header('Content-Type' => 'application/json'); - $req->header('Prefer' => 'return=representation'); - $req->content(JSON::to_json($data)); +sub main { + check_params(); + my $uri = '/api/domains/'; + my %data = map { $_ => $opts->{$_} } qw(reseller_id domain); + map { $data{"_".$_."_reload"} = $opts->{$_} } qw(skip_xmpp skip_sip); + my $client = new NGCP::API::Client; + $client->set_verbose($opts->{verbose}); + my $res = $client->request("POST", $uri, \%data); + print $res->result."\n"; - return $ua->request($req); + return; } -main($ARGV[0]); +main(); -__END__ -=head1 NAME +exit 0; -ngcp-create_domain - create a domain on NGCP +__END__ -=head1 SYNOPSIS +=head1 NAME -ngcp-create_domain [options] domain +ngcp-create_domain - create an NGCP domain =head1 OPTIONS @@ -106,31 +74,11 @@ ngcp-create_domain [options] domain =item B<-help> -Print a brief help message and exits. +Print a brief help message. =item B<-reseller_id> -The reseller id to assign this domain to. Defaults to 1. - -=item B<-auth_user> - -Authentication username . Defaults to 'administrator'. - -=item B<-auth_pwd> - -Authentication password . Defaults to 'administrator'. - -=item B<-host> - -Host where the send queries. Defaults to '127.0.0.1'. - -=item B<-port> - -Port where the send queries. Defaults to 1443. - -=item B<-verbose> - -See debug information. Default false. +Reseller id. Default 1. =item B<-skip_sip> @@ -142,34 +90,46 @@ until the respective service is restarted or properly notified. Default false. Skip reloading XMPP services. If true, changes will not be effective immedeately until the respective service is restarted or properly notified. Default false. -=back +=item B<-verbose> -=head1 DESCRIPTION +Show additional debug information. Default false. -B<This program> will create a domain at NGCP. +=back =head1 USAGE -ngcp-create_domain -host 1.2.3.4 -reseller_id 4 test.example.org +ngcp-create_domain [options] + +ngcp-create_domain --domain example.org + +=head1 DESCRIPTION + +B<This program> creates a domain on the NGCP platform. =head1 REQUIRED ARGUMENTS -B<domain> to be created +=over 8 + +=item B<-domain> + +=back =head1 EXIT STATUS -Exit code 0 means that everything should have went fine otherwise error. +Exit code 0 means everything is ok otherwise 1. + +=head1 CONFIGURATION =head1 DIAGNOSTICS -=head1 CONFIGURATION +=head1 SEE ALSO -/etc/default/ngcp-api for default values +NGCP::API::Client =head1 DEPENDENCIES ngcp-create_domain relies on a bunch of Perl modules, all of them specified as -dependencies through the ngcp-ossbss-clients-perl Debian package. +dependencies through the Debian package. =head1 INCOMPATIBILITIES @@ -184,17 +144,21 @@ Development Team <support@sipwise.com>. Victor Seva <vseva@sipwise.com> -=head1 LICENSE +=head1 LICENSE AND COPYRIGHT -Copyright (c) 2015 Sipwise GmbH, Austria. -All rights reserved. You may not copy, distribute -or modify without prior written permission from -Sipwise GmbH, Austria. +Copyright (C) 2016 Sipwise GmbH, Austria -=head1 LICENSE AND COPYRIGHT +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. -Copyright (c) 2015 Sipwise GmbH, Austria. -You should have received a copy of the licence terms together with the -software. +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. =cut diff --git a/bin/ngcp-create_subscriber b/bin/ngcp-create_subscriber index 54e149d..8b630d8 100755 --- a/bin/ngcp-create_subscriber +++ b/bin/ngcp-create_subscriber @@ -1,152 +1,87 @@ #!/usr/bin/perl use strict; use warnings; -use Config::Tiny; use English; use Getopt::Long; -use JSON qw(); -use LWP::UserAgent; use Pod::Usage; -use IO::Socket::SSL; +use NGCP::API::Client; +use Readonly; + +Readonly my @required => qw(customer_id username domain password cc ac sn); -my $config = Config::Tiny->read('/etc/default/ngcp-api'); my $opts = { - host => '127.0.0.1', - port => 1443, - auth_user => 'administrator', - auth_pwd => 'administrator', + admin => 0, verbose => 0, - admin => 0 }; -if ($config) { - $opts->{host} = $config->{_}->{NGCP_API_IP}; - $opts->{port} = $config->{_}->{NGCP_API_PORT}; - $opts->{sslverify} = $config->{_}->{NGCP_API_SSLVERIFY} || 'yes'; -} - GetOptions( $opts, - "help|h" => sub { pod2usage(-exitval =>0); }, + "help|h" => \&usage, "customer_id=i", - "host=s", - "port=i", - "auth_user=s", - "auth_pwd=s", - "verbose", - "man" => sub { pod2usage(-exitval => 0, -verbose => 2); }, "username|u=s", - "domain|d=s", "password|p=s", + "domain|d=s", "admin|s=i", "cc|c=i", "ac|a=i", "sn|n=i", - "account_id|v=i", - "webpassword|w=s" -) or pod2usage(2); - -die pod2usage(-exitval => 1, -message => "Missing parameters: customer_id") - unless defined $opts->{customer_id}; -die pod2usage(-exitval => 1, -message => "Missing parameters") unless - defined $opts->{username} and defined $opts->{domain} - and defined $opts->{password}; -die pod2usage(-exitval => 1, -message => "Missing parameters") unless - (defined $opts->{cc} and defined $opts->{ac} and defined $opts->{sn}) - or ( not defined $opts->{cc} and not defined $opts->{ac} - and not defined $opts->{sn}); + "webpassword|w=s", + "verbose", +) or usage(); -sub main { - my $urlbase = 'https://'.$opts->{host}.':'.$opts->{port}; - - my $ua = LWP::UserAgent->new(); - if($opts->{sslverify} eq 'no') { - $ua->ssl_opts( - verify_hostname => 0, - SSL_verify_mode => IO::Socket::SSL::SSL_VERIFY_NONE, - ); - } - $ua->credentials($opts->{host}.':'.$opts->{port}, 'api_admin_http', - $opts->{auth_user}, $opts->{auth_pwd}); - # debug!! - if($opts->{verbose}) { - $ua->show_progress(1); - $ua->add_handler("request_send", sub { shift->dump; return }); - $ua->add_handler("response_done", sub { shift->dump; return }); - } - my $domain_id = get_domain_id($ua, $urlbase, $opts->{domain}); - my $res = do_request($ua, $urlbase, get_data($domain_id)); - if($res->is_success) { - print $res->status_line . ' ' . $res->header('Location') . "\n"; - } else { - die $res->as_string; +sub check_params { + my @missing; + foreach my $param (@required) { + push @missing, $param unless $opts->{$param}; } + usage(join(' ', @missing)) if scalar @missing; return; } -sub get_data { - my $domain_id = shift; - my $data = { - administrative => $opts->{admin} || 0, - domain_id => $domain_id, - customer_id => $opts->{customer_id}, - username => $opts->{username}, - password => $opts->{password}, - webpassword => $opts->{webpassword}, - primary_number => { - cc => $opts->{cc}, - ac => $opts->{ac}, - sn => $opts->{sn} - }, - }; - return $data; +sub usage { + my $msg = shift; + pod2usage(-exitval => $msg ? 1 : 0, + -verbose => 99, + -sections => [ qw(NAME OPTIONS USAGE) ], + -message => $msg + ? $msg =~ /not found/i + ? $msg + : "Missing parameters: $msg" + : '', + ); + return; } -sub get_domain_id { - my $ua = shift; - my $urlbase = shift; - my $domain = shift; - my $url = $urlbase."/api/domains/?domain=".$domain; - my $req = HTTP::Request->new('GET', $url); - my $domain_id; - - my $res = $ua->request($req); - if($res->is_success) { - my $collection = JSON::from_json($res->decoded_content); - if ($collection->{total_count} == 1) { - $domain_id = $collection->{_embedded}->{'ngcp:domains'}->{id}; - } - else { - pod2usage(-exitval => 3, -message => "Domain not found"); - } - } - else { - die $res->status_line, "\n"; +sub main { + check_params(); + my $uri = '/api/subscribers/'; + my %data = map { $_ => $opts->{$_} } + qw(customer_id username password webpassword); + $data{primary_number} = join '', @{$opts}{qw(cc ac sn)}; + $data{administrative} = $opts->{admin}; + my $client = new NGCP::API::Client; + $client->set_verbose($opts->{verbose}); + # domain_id + my $dom = $client->request("GET", "/api/domains/?domain=".$opts->{domain}); + if ($dom->as_hash->{total_count} == 1) { + $data{domain_id} = $dom->as_hash->{_embedded}->{'ngcp:domains'}->{id}; + } else { + usage("Domain not found"); } - return $domain_id; -} + my $res = $client->request("POST", $uri, \%data); + print $res->result."\n"; -sub do_request { - my $ua = shift; - my $urlbase = shift; - my $data = shift; - - my $req = HTTP::Request->new('POST', $urlbase.'/api/subscribers/'); - $req->header('Content-Type' => 'application/json'); - $req->header('Prefer' => 'return=representation'); - $req->content(JSON::to_json($data)); - return $ua->request($req); + return; } main(); -__END__ -=head1 NAME +exit 0; -ngcp-create_subscriber - create a subscriber on NGCP +__END__ -=head1 SYNOPSIS +=head1 NAME -ngcp-create_subscriber [options] +ngcp-create_subscriber - create a subscriber =head1 OPTIONS @@ -154,99 +89,97 @@ ngcp-create_subscriber [options] =item B<-help> -Print a brief help message and exits. +Print a brief help message. =item B<-customer_id> -The customer id to assign this subscriber to. - -=item B<-auth_user> - -Authentication username . Defaults to 'administrator'. - -=item B<-auth_pwd> - -Authentication password . Defaults to 'administrator'. - -=item B<-host> - -Host where the send queries. Defaults to '127.0.0.1'. - -=item B<-port> - -Port where the send queries. Defaults to 1443. - -=item B<-account_id|v> - -the unique ID of an existing account, the script will create a new one -if unspecified. +An existing customer id to assign this subscriber to. =item B<-username|u> -new SIP username. +A SIP username. =item B<-domain|d> -existing domain for subscriber. +An existing domain for the new subscriber. =item B<-password|p> -unencrypted SIP password for subscriber. +An unencrypted SIP password for the new subscriber. =item B<-webpassword|w> -unencrypted web password for subscriber. +An unencrypted web password for the new subscriber. =item B<-cc|c> -country code of subscriber number. +A country code part of the subscriber's number. =item B<-ac|a> -area code of subscriber number. +An area code part of the subscriber's number. =item B<-number|n> -local part of subscriber number. +A local number part of the subscriber's number. =item B<-admin|s> -whether or not to set the administrative flag for the subscriber. -defaults to 0 (no). +Set the administrative flag for the new subscriber. +Defaults to 0 (no). =item B<-verbose> -See debug information. Default false. +Show additional debug information. Default false. =back -=head1 DESCRIPTION +=head1 USAGE -B<This program> will create a subscriber at NGCP. +ngcp-create_subscriber [options] -=head1 USAGE +ngcp-create_subscriber --customer_id 1 --username 4311101 --domain sipwise.com --password SecurePassword1 --cc 43 --ac 111 --sn 01 + +=head1 DESCRIPTION -ngcp-create_subscriber -host 1.2.3.4 -customer_id 4 -d test.example.org -u test - -p passw12_ -c 34 -a 11 -n 12345 -s 0 +B<This program> creates a subscriber on the NGCP platform. =head1 REQUIRED ARGUMENTS -TODO +=over 8 + +=item B<-customer_id> + +=item B<-username> + +=item B<-domain> + +=item B<-password> + +=item B<-cc> + +=item B<-ac> + +=item B<-sn> + +=back =head1 EXIT STATUS -Exit code 0 means that everything should have went fine otherwise error. +Exit code 0 means everything is ok otherwise 1. + +=head1 CONFIGURATION =head1 DIAGNOSTICS -=head1 CONFIGURATION +=head1 SEE ALSO -/etc/default/ngcp-api for default values +NGCP::API::Client =head1 DEPENDENCIES -ngcp-create_subscriber relies on a bunch of Perl modules, all of them specified as -dependencies through the ngcp-ossbss-clients-perl Debian package. +ngcp-create_customer relies on a bunch of Perl modules, all of them specified as +dependencies through the Debian package. =head1 INCOMPATIBILITIES @@ -261,17 +194,21 @@ Development Team <support@sipwise.com>. Victor Seva <vseva@sipwise.com> -=head1 LICENSE +=head1 LICENSE AND COPYRIGHT -Copyright (c) 2015 Sipwise GmbH, Austria. -All rights reserved. You may not copy, distribute -or modify without prior written permission from -Sipwise GmbH, Austria. +Copyright (C) 2016 Sipwise GmbH, Austria -=head1 LICENSE AND COPYRIGHT +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. -Copyright (c) 2015 Sipwise GmbH, Austria. -You should have received a copy of the licence terms together with the -software. +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. =cut diff --git a/bin/ngcp-credit-warning b/bin/ngcp-credit-warning index cc9758f..3c74e7a 100755 --- a/bin/ngcp-credit-warning +++ b/bin/ngcp-credit-warning @@ -1,61 +1,232 @@ -#!/usr/bin/perl -w - +#!/usr/bin/perl use strict; use warnings; - -use Email::Sender::Simple qw(sendmail); +use English; +use Getopt::Long; +use Pod::Usage; +use NGCP::API::Client; +use Readonly; use XML::Simple; -use Sipwise::DB; -use Sipwise::Provisioning::Config; +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 $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, + -sections => [ qw(NAME OPTIONS USAGE) ], + -message => $msg + ? $msg =~ /not found/i + ? $msg + : "Missing parameters: $msg" + : '', + ); + return; +} + +sub load_config { + $config = XML::Simple->new()->XMLin($config_file, ForceArray => 0) + or die "Cannot load config: $config_file: $ERRNO"; + return; +} + +sub send_email { + my ($cwarning, $contracts) = @_; -my $MTA = '/usr/sbin/sendmail -oi -t'; + my $template = get_email_template() || return; -sub main; + my $vars = { domain => $cwarning->{domain}, + threshold => $cwarning->{threshold}, + adminmail => $config->{adminmail} }; + + foreach my $data (@{$contracts}) { + $vars->{contracts} .= sprintf <<EOF, @{$data}{qw(id cash_balance)}; +contract_id: %s cash_balance: %s +EOF + } -main; + 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) = @_; + my $client = new NGCP::API::Client; + $client->set_verbose($opts->{verbose}); + my $res = $client->request("GET", $uri); + die $res->result unless $res->is_success; + my $res_hash = $res->as_hash; + return [] unless $res_hash->{total_count} && $res_hash->{total_count} > 0; + my $data = $res_hash->{_embedded}{'ngcp:'.$link}; + return ref $data eq 'ARRAY' ? $data : [ $data ]; +} + +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 { - my $xs = new XML::Simple; - my $conf = Sipwise::Provisioning::Config->new()->get_config(); - my $db = new Sipwise::DB ( $$conf{billingdb} ); - - $$conf{credit_warnings} = [ $$conf{credit_warnings} ] - if defined eval { %{$$conf{credit_warnings}} }; - - foreach my $domcfg (@{$$conf{credit_warnings}}) { - - my $contracts = $db->sql_get_all_arrayref(" - SELECT a.contract_id,a.cash_balance,a.cash_balance_interval,GROUP_CONCAT(c.username,'\@',d.domain) AS subscribers - FROM contract_balances a, contracts b,voip_subscribers c, domains d - WHERE a.start = DATE_FORMAT(now(), '%Y-%m-01 00:00:00') - AND a.contract_id = b.id - AND b.status != 'terminated' - AND a.contract_id = c.contract_id - AND c.domain_id = d.id - AND d.domain = ? - AND c.status != 'terminated' - AND a.cash_balance < ? - GROUP BY contract_id - ", $$domcfg{domain}, $$domcfg{threshold}); - if(@$contracts) { - $$domcfg{recipients} = [ $$domcfg{recipients} ] - unless defined eval { @{$$domcfg{recipients}} }; - - my $mailtxt; - $mailtxt .= "Credit threshold warning for: $$domcfg{domain}\nThe following contracts are below the configured threshold of $$domcfg{threshold} cent:\n\n"; - $mailtxt .= "account_id\tcash_balance\tcash_balance_interval\tsubscribers\n"; - for(@$contracts) { - $mailtxt .= "$$_{contract_id}\t$$_{cash_balance}\t$$_{cash_balance_interval}\t$$_{subscribers}\n"; - } - - sendmail ( Email::Simple->create( - header => [ - To => join(', ', @{$$domcfg{recipients}}), - From => $$conf{adminmail}, - Subject => 'Sipwise NGCP credit threshold notification', - ], - body => $mailtxt, - )); + 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; + my $balances = + get_data(sprintf('/api/customerbalances/?domain=%s', + $cwarning->{domain}), + 'customerbalances'); + foreach my $balance (@{$balances}) { + next if $balance->{cash_balance} >= $cwarning->{threshold}; + push @contracts, + { map { $_ => $balance->{$_} } qw(id cash_balance) }; + } + if (@contracts) { + send_email($cwarning, \@contracts); + } } - } + return; } + +main(); + +exit 0; + +__END__ + +=head1 NAME + +ngcp-credit-warning - checks for contract balances above credit warning thresholds + +=head1 OPTIONS + +=over 8 + +=item B<-help> + +Print a brief help message. + +=item B<-verbose> + +Show additional debug information. Default false. + +=back + +=head1 USAGE + +ngcp-credit-warning [options] + +=head1 DESCRIPTION + +B<This program> checks for contract balances above credit warning thresholds and sends email notifications about the incidents + +=head1 REQUIRED ARGUMENTS + +None + +=head1 EXIT STATUS + +Exit code 0 means everything is ok otherwise 1. + +=head1 CONFIGURATION + +=head1 DIAGNOSTICS + +=head1 SEE ALSO + +NGCP::API::Client + +=head1 DEPENDENCIES + +ngcp-credit-warning relies on a bunch of Perl modules, all of them specified as +dependencies through the Debian package. + +=head1 INCOMPATIBILITIES + +No known at this time. + +=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 AND COPYRIGHT + +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/>. + +=cut diff --git a/bin/ngcp-delete_domain b/bin/ngcp-delete_domain index f5f0938..547bab0 100755 --- a/bin/ngcp-delete_domain +++ b/bin/ngcp-delete_domain @@ -1,126 +1,82 @@ #!/usr/bin/perl use strict; use warnings; -use Config::Tiny; use English; use Getopt::Long; -use JSON qw(); -use LWP::UserAgent; use Pod::Usage; -use URI; -use IO::Socket::SSL; +use NGCP::API::Client; +use Readonly; + +Readonly my @required => qw(domain); -my $config = Config::Tiny->read('/etc/default/ngcp-api'); my $opts = { - reseller_id => 1, - host => '127.0.0.1', - port => 1443, - auth_user => 'administrator', - auth_pwd => 'administrator', + domain => $ARGV[0], skip_xmpp => 0, skip_sip => 0, verbose => 0, }; -if ($config) { - $opts->{host} = $config->{_}->{NGCP_API_IP}; - $opts->{port} = $config->{_}->{NGCP_API_PORT}; - $opts->{sslverify} = $config->{_}->{NGCP_API_SSLVERIFY} || 'yes'; -} - GetOptions( $opts, - "help|h", - "reseller_id=i", - "host=s", - "port=i", - "auth_user=s", - "auth_pwd=s", - "skip_sip", + "help|h" => \&usage, + "domain=s", "skip_xmpp", + "skip_sip", "verbose", - "man" => sub { pod2usage(-exitval => 0, -verbose => 2); }, -) or pod2usage(2); - -die pod2usage(-exitval => 1, -message => "No domain") unless ($#ARGV == 0); +) or usage(); -sub main { - my $domain = shift; - my $urlbase = 'https://'.$opts->{host}.':'.$opts->{port}; - - my $ua = LWP::UserAgent->new(); - if($opts->{sslverify} eq 'no') { - $ua->ssl_opts( - verify_hostname => 0, - SSL_verify_mode => IO::Socket::SSL::SSL_VERIFY_NONE, - ); - } - $ua->credentials($opts->{host}.':'.$opts->{port}, 'api_admin_http', - $opts->{auth_user}, $opts->{auth_pwd}); - # debug!! - if($opts->{verbose}) { - $ua->show_progress(1); - $ua->add_handler("request_send", sub { shift->dump; return }); - $ua->add_handler("response_done", sub { shift->dump; return }); - } - my $domain_url = get_domain_url($ua, $urlbase, $domain); - my $res = do_request($ua, $domain_url); - if($res->is_success) { - print $res->status_line . "\n"; - } else { - die $res->as_string; +sub check_params { + my @missing; + foreach my $param (@required) { + push @missing, $param unless $opts->{$param}; } + usage(join(' ', @missing)) if scalar @missing; return; } -sub get_domain_url { - my $ua = shift; - my $urlbase = shift; - my $domain = shift; - my $url = $urlbase."/api/domains/?domain=".$domain; - my $req = HTTP::Request->new('GET', $url); - my $domain_url; - - my $res = $ua->request($req); - if($res->is_success) { - my $collection = JSON::from_json($res->decoded_content); - if ($collection->{total_count} == 1) { - $domain_url = $urlbase . - $collection->{_links}->{'ngcp:domains'}->{href}; - } - else { - pod2usage(-exitval => 3, -message => "Domain not found"); - } - } - else { - die $res->as_string; - } - return $domain_url; +sub usage { + my $msg = shift; + pod2usage(-exitval => $msg ? 1 : 0, + -verbose => 99, + -sections => [ qw(NAME OPTIONS USAGE) ], + -message => $msg + ? $msg =~ /not found/i + ? $msg + : "Missing parameters: $msg" + : '', + ); + return; } -sub do_request { - my $ua = shift; - my $url = shift; - - my $full_url = URI->new($url); - $full_url->query_form( - $full_url->query_form, - ($opts->{skip_xmpp} ? (_skip_xmpp_reload => 1) : ()), - ($opts->{skip_sip} ? (_skip_sip_reload => 1) : ()), - ); - my $req = HTTP::Request->new('DELETE', $full_url); - return $ua->request($req); +sub main { + check_params(); + my $uri = '/api/domains/'; + my %data = map { "_".$_."_reload" => $opts->{$_} } qw(skip_xmpp skip_sip); + my $client = new NGCP::API::Client; + $client->set_verbose($opts->{verbose}); + # domain_id + my $dom = $client->request("GET", "/api/domains/?domain=".$opts->{domain}); + if ($dom->as_hash->{total_count} == 1) { + my $dom_id = $dom->as_hash->{_embedded}->{'ngcp:domains'}->{id}; + usage("Domain not found") unless $dom_id; + $uri .= $dom_id; + } else { + usage("Domain not found"); + } + my $res = $client->request("DELETE", $uri, \%data); + print $res->result."\n"; + + return; } -main($ARGV[0]); +main(); -__END__ -=head1 NAME +exit 0; -ngcp-delete_domain - delete a domain on NGCP +__END__ -=head1 SYNOPSIS +=head1 NAME -ngcp-delete_domain [options] domain +ngcp-delete_domain - delete an NGCP domain =head1 OPTIONS @@ -128,31 +84,7 @@ ngcp-delete_domain [options] domain =item B<-help> -Print a brief help message and exits. - -=item B<-reseller_id> - -The reseller id to assign this domain to. Defaults to 1. - -=item B<-auth_user> - -Authentication username . Defaults to 'administrator'. - -=item B<-auth_pwd> - -Authentication password . Defaults to 'administrator'. - -=item B<-host> - -Host where the send queries. Defaults to '127.0.0.1'. - -=item B<-port> - -Port where the send queries. Defaults to 1443. - -=item B<-verbose> - -See debug information. Default false. +Print a brief help message. =item B<-skip_sip> @@ -164,34 +96,46 @@ until the respective service is restarted or properly notified. Default false. Skip reloading XMPP services. If true, changes will not be effective immedeately until the respective service is restarted or properly notified. Default false. -=back +=item B<-verbose> -=head1 DESCRIPTION +Show additional debug information. Default false. -B<This program> will delete a domain at NGCP. +=back =head1 USAGE -ngcp-delete_domain -host 1.2.3.4 -reseller_id 4 test.example.org +ngcp-delete_domain [options] + +ngcp-delete_domain --domain example.org + +=head1 DESCRIPTION + +B<This program> deletes a domain on the NGCP platform. =head1 REQUIRED ARGUMENTS -B<domain> to be deleted +=over 8 + +=item B<-domain> + +=back =head1 EXIT STATUS -Exit code 0 means that everything should have went fine otherwise error. +Exit code 0 means everything is ok otherwise 1. + +=head1 CONFIGURATION =head1 DIAGNOSTICS -=head1 CONFIGURATION +=head1 SEE ALSO -/etc/default/ngcp-api for default values +NGCP::API::Client =head1 DEPENDENCIES ngcp-delete_domain relies on a bunch of Perl modules, all of them specified as -dependencies through the ngcp-ossbss-clients-perl Debian package. +dependencies through the Debian package. =head1 INCOMPATIBILITIES @@ -206,17 +150,21 @@ Development Team <support@sipwise.com>. Victor Seva <vseva@sipwise.com> -=head1 LICENSE +=head1 LICENSE AND COPYRIGHT -Copyright (c) 2015 Sipwise GmbH, Austria. -All rights reserved. You may not copy, distribute -or modify without prior written permission from -Sipwise GmbH, Austria. +Copyright (C) 2016 Sipwise GmbH, Austria -=head1 LICENSE AND COPYRIGHT +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. -Copyright (c) 2015 Sipwise GmbH, Austria. -You should have received a copy of the licence terms together with the -software. +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. =cut diff --git a/bin/ngcp-fraud-auto-lock b/bin/ngcp-fraud-auto-lock index e3012ec..d18be6d 100755 --- a/bin/ngcp-fraud-auto-lock +++ b/bin/ngcp-fraud-auto-lock @@ -1,154 +1,259 @@ #!/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(); -use Email::Sender::Simple qw(sendmail); -use Sipwise::Provisioning::Billing; - -my %LOCK = ( - none => undef, - foreign => 1, - outgoing => 2, - incoming => 3, - global => 4, - 0 => 'none', - 1 => 'foreign', - 2 => 'outgoing', - 3 => 'incoming', - 4 => 'global', -); - -my $conf = Sipwise::Provisioning::Config->new()->get_config(); - -my $o = Sipwise::Provisioning::Billing->new(); -my $db = $o->{database}; - -# We select only those billing profile hits which exceed the fraud limit and -# have an action attached to keep the number of result rows small. -# However, we select all account hits and manually check them later, as they -# can potentially override billing profile hits. -my $a = $db->sql_get_all_arrayref(<<"!"); -SELECT bpinfo.type, bpinfo.id, - IF (bpinfo.fraud_use_reseller_rates > 0, SUM(cdr.source_reseller_cost), - SUM(cdr.source_customer_cost)) as interval_cost, - bpinfo.fraud_interval_limit, bpinfo.fraud_interval_lock, bpinfo.fraud_interval_notify -FROM ( - SELECT contracts.id, bp.fraud_use_reseller_rates, - CASE WHEN cfp.fraud_interval_limit > 0 THEN 'account_limit' - ELSE 'profile_limit' END as type, - IF (cfp.fraud_interval_limit > 0, cfp.fraud_interval_limit, bp.fraud_interval_limit) as fraud_interval_limit, - IF (cfp.fraud_interval_limit > 0, cfp.fraud_interval_lock, bp.fraud_interval_lock) as fraud_interval_lock, - IF (cfp.fraud_interval_limit > 0, cfp.fraud_interval_notify, bp.fraud_interval_notify) as fraud_interval_notify - FROM billing.contracts - JOIN billing.billing_profiles bp - ON (bp.id = - (SELECT m.billing_profile_id - FROM billing.billing_mappings m - USE INDEX (contractid_idx) - JOIN products pr ON pr.id = m.product_id - WHERE ((m.start_date IS NULL) OR (m.start_date <= NOW())) - AND ((m.end_date IS NULL) OR (m.end_date >= NOW())) - AND (m.contract_id = contracts.id) - AND (pr.class IN ('sipaccount', 'pbxaccount') OR pr.class IS NULL) - ORDER BY m.start_date DESC LIMIT 1 - ) - ) - LEFT JOIN billing.contract_fraud_preferences cfp ON cfp.contract_id = contracts.id - WHERE (contracts.status = 'active') - AND (cfp.fraud_interval_limit > 0 OR bp.fraud_interval_limit > 0) -) as bpinfo -JOIN accounting.cdr ON cdr.source_account_id = bpinfo.id -WHERE cdr.start_time BETWEEN UNIX_TIMESTAMP(DATE_FORMAT(NOW(), '%Y-%m-01 00:00:00')) - AND UNIX_TIMESTAMP(DATE_FORMAT(NOW() + INTERVAL 1 MONTH, '%Y-%m-01 00:00:00'))-1 -GROUP BY bpinfo.id -HAVING interval_cost >= fraud_interval_limit - AND (fraud_interval_lock > 0 OR fraud_interval_notify <> '') -! - -my $x = {}; -for my $e (@{ $a }) { - if(exists $x->{$e->{id}}) { - if($x->{$e->{id}}->{type} eq 'profile_limit' && $e->{type} eq 'account_limit') { - - # if account limit hits and it has lock and/or notify, mark for action - if(defined $e->{fraud_interval_limit} and - int($e->{interval_cost}) >= int($e->{fraud_interval_limit}) and - ($e->{fraud_interval_lock} || $e->{fraud_interval_notify})) { - - $x->{$e->{id}} = $e; - } else { - # we have account fraud prefs set, but either the limit is not reached - # or no actions are necessary, let it slip through, overriding - # billing profile fraud settings - delete $x->{$e->{id}}; - } - } - } else { - # if account or billing profile limit hits and it has lock and/or notify, - # mark for action - if(defined $e->{fraud_interval_limit} and - int($e->{interval_cost}) >= int($e->{fraud_interval_limit}) and - ($e->{fraud_interval_lock} || $e->{fraud_interval_notify})) { - - $x->{$e->{id}} = $e; +Readonly my @required => qw(); +Readonly my $config_file => '/etc/ngcp-panel/provisioning.conf'; +Readonly my $interval => 'month'; + +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, + -sections => [ qw(NAME OPTIONS USAGE) ], + -message => $msg + ? $msg =~ /not found/i + ? $msg + : "Missing parameters: $msg" + : '', + ); + return; } -for my $e (values %{ $x }) { +sub load_config { + $config = XML::Simple->new()->XMLin($config_file, ForceArray => 0) + or die "Cannot load config: $config_file: $ERRNO"; + return; +} + +sub get_data { + my ($uri, $link) = @_; + my $client = new NGCP::API::Client; + $client->set_verbose($opts->{verbose}); + my $res = $client->request("GET", $uri); + die $res->result unless $res->is_success; + my $res_hash = $res->as_hash; + return [] unless $res_hash->{total_count} && $res_hash->{total_count} > 0; + my $data = $res_hash->{_embedded}{'ngcp:'.$link}; + return ref $data eq 'ARRAY' ? $data : [ $data ]; +} - $e->{fraud_interval_lock} and - $o->lock_voip_account({id => $e->{id}, lock => $LOCK{$e->{fraud_interval_lock}}}); +sub get_email_template { + my $event = shift; + my $lock_type = $event->{interval_lock} ? 'lock' : 'warning'; + my $reseller_id = $event->{reseller_id}; + my $templates_data = get_data('/api/emailtemplates/', 'emailtemplates'); + my $selected_template; + foreach my $template (@{$templates_data}) { + next if $template->{name} ne 'customer_fraud_'.$lock_type.'_default_email' + && $template->{name} ne 'customer_fraud_'.$lock_type.'_email'; + next if $template->{reseller_id} && $template->{reseller_id} != $reseller_id; + $selected_template = $template; + last if $template->{reseller_id}; + } + return $selected_template; +} - $e->{fraud_interval_notify} or next; +sub send_email { + my ($event, $subscribers) = @_; - my $subs = $db->sql_get_all_arrayref(<<"!", $e->{id}); - SELECT s.username, d.domain, s.external_id - FROM voip_subscribers s - LEFT JOIN domains d ON d.id = s.domain_id - WHERE s.contract_id = ? - AND s.status != 'terminated' -! + my $template = get_email_template($event); - my $cur = sprintf('%.2f', $e->{interval_cost} / 100); - my $max = sprintf('%.2f', $e->{fraud_interval_limit} / 100); + my $vars = { adminmail => $config->{adminmail}, + customer_id => $event->{id}, + interval_cost => sprintf('%.2f', $event->{interval_cost}/100), + interval_limit => sprintf('%.2f', $event->{interval_limit}/100), + type => $event->{type} eq 'profile_limit' + ? 'billing profile' : 'customer', + }; - my ($subject, $body); - if ($e->{fraud_interval_lock}) { - $body = "Account ID " . $e->{id} . " has been locked due to exceeding the configured" . "\n" - . "credit balance threshold ($cur >= $max ) in the " - . ($e->{type} eq 'profile_limit' ? 'billing profile' : 'account settings') . "\n\n"; - $subject = 'Account ID ' . $e->{id} . ' locked by fraud detection'; - } - else { - $body = "Account ID " . $e->{id} . " is currently exceeding the configured credit balance" . "\n" - . "threshold ($cur >= $max) in the " - . ($e->{type} eq 'profile_limit' ? 'billing profile' : 'account settings') . ",\n" - . "but has not been locked due to configuration.\n\n"; - $subject = 'Account ID ' . $e->{id} . ' exceeding fraud detection limit'; + foreach my $subscriber (@{$subscribers}) { + $vars->{subscribers} .= sprintf "%s\@%s %s\n", + @{$subscriber}{qw(username domain)}, + $subscriber->{external_id} + ? '('.$subscriber->{external_id}.')' : ''; } - if (!$subs || !@$subs) { - $body .= "There are no affected subscribers.\n"; - } - else { - $body .= "Affected subscribers:\n"; - for my $s (@$subs) { - $body .= "\t$s->{username}\@$s->{domain}". - ($s->{external_id} ? " (external ID '$s->{external_id}')" - : '') . "\n"; - } - } - - sendmail ( Email::Simple->create( + 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 => $e->{fraud_interval_notify}, - From => $$conf{adminmail}, - Subject => $subject, + To => $event->{interval_notify}, + From => $template->{from_email}, + Subject => $template->{subject}, ], - body => $body, - )); + body => $template->{body}, + ); + + Email::Sender::Simple->send($email, { transport => $transport }) + or die sprintf "Cannot send fraud auto lock notification to %s: $ERRNO", + $email->header('To'); + + return; +} + + +sub lock_customer { + my ($event, $subscribers) = @_; + + my $client = new NGCP::API::Client; + $client->set_verbose($opts->{verbose}); + my $uri = '/api/customers/'.$event->{id}; + my $data = [ { op => 'replace', + path => '/status', + value => 'locked' } ]; + my $res = $client->request("PATCH", $uri, $data); + if ($res->status_line =~ /200 OK/) { + foreach my $subscriber (@{$subscribers}) { + $uri = '/api/subscribers/'.$subscriber->{id}; + $data = [ { op => 'replace', + path => '/status', + value => 'locked' }, + { op => 'replace', + path => '/lock', + value => $event->{interval_lock} } ]; + $res = $client->request("PATCH", $uri, $data); + } + } + + return; +} + +sub main { + check_params(); + load_config(); + my $events = get_data(sprintf('/api/customerfraudevents/?interval=%s', + $interval), + 'customerfraudevents'); + foreach my $event (@{$events}) { + my $subscribers = get_data(sprintf('/api/subscribers/?customer_id=%d', + $event->{id}), + 'subscribers'); + if ($event->{interval_lock} > 0) { + lock_customer($event, $subscribers); + } + send_email($event, $subscribers); + } + return; } -1; +main(); + +exit 0; + +__END__ + +=head1 NAME + +ngcp-fraud-auto-lock - checks for contract balances above fraud limit thresholds + +=head1 OPTIONS + +=over 8 + +=item B<-help> + +Print a brief help message. + +=item B<-verbose> + +Show additional debug information. Default false. + +=back + +=head1 USAGE + +ngcp-fraud-auto-lock [options] + +=head1 DESCRIPTION + +B<This program> checks for contract balances above fraud limit warning thresholds and sends email notifications about the incidents as applying actions on such contracts (e.g. lock). Interval: 'month' + +=head1 REQUIRED ARGUMENTS + +None + +=head1 EXIT STATUS + +Exit code 0 means everything is ok otherwise 1. + +=head1 CONFIGURATION + +=head1 DIAGNOSTICS + +=head1 SEE ALSO + +NGCP::API::Client + +=head1 DEPENDENCIES + +ngcp-fraud-auto-lock relies on a bunch of Perl modules, all of them specified as +dependencies through the Debian package. + +=head1 INCOMPATIBILITIES + +No known at this time. + +=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 AND COPYRIGHT + +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/>. + +=cut diff --git a/bin/ngcp-fraud-daily-lock b/bin/ngcp-fraud-daily-lock index 60b27ec..7fec927 100755 --- a/bin/ngcp-fraud-daily-lock +++ b/bin/ngcp-fraud-daily-lock @@ -1,146 +1,259 @@ #!/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(); -use Email::Sender::Simple qw(sendmail); -use Sipwise::Provisioning::Billing; - -my %LOCK = ( - none => undef, - foreign => 1, - outgoing => 2, - incoming => 3, - global => 4, - 0 => 'none', - 1 => 'foreign', - 2 => 'outgoing', - 3 => 'incoming', - 4 => 'global', -); - -my $conf = Sipwise::Provisioning::Config->new()->get_config(); - -my $o = Sipwise::Provisioning::Billing->new(); -my $db = $o->{database}; - -my $a = $db->sql_get_all_arrayref(<<"!"); -SELECT bpinfo.type, bpinfo.id, - IF (bpinfo.fraud_use_reseller_rates > 0, SUM(cdr.source_reseller_cost), - SUM(cdr.source_customer_cost)) as daily_cost, - bpinfo.fraud_daily_limit, bpinfo.fraud_daily_lock, bpinfo.fraud_daily_notify -FROM ( - SELECT contracts.id, bp.fraud_use_reseller_rates, - CASE WHEN cfp.fraud_daily_limit > 0 THEN 'account_limit' - ELSE 'profile_limit' END as type, - IF (cfp.fraud_daily_limit > 0, cfp.fraud_daily_limit, bp.fraud_daily_limit) as fraud_daily_limit, - IF (cfp.fraud_daily_limit > 0, cfp.fraud_daily_lock, bp.fraud_daily_lock) as fraud_daily_lock, - IF (cfp.fraud_daily_limit > 0, cfp.fraud_daily_notify, bp.fraud_daily_notify) as fraud_daily_notify - FROM billing.contracts - JOIN billing.billing_profiles bp - ON (bp.id = - (SELECT m.billing_profile_id - FROM billing.billing_mappings m - USE INDEX (contractid_idx) - WHERE ((m.start_date IS NULL) OR (m.start_date <= NOW())) - AND ((m.end_date IS NULL) OR (m.end_date >= NOW())) - AND (m.contract_id = contracts.id) - ORDER BY m.start_date DESC LIMIT 1 - ) - ) - LEFT JOIN billing.contract_fraud_preferences cfp ON cfp.contract_id = contracts.id - WHERE (contracts.status = 'active') - AND (cfp.fraud_daily_limit > 0 OR bp.fraud_daily_limit > 0) -) as bpinfo -JOIN accounting.cdr ON cdr.source_account_id = bpinfo.id -WHERE cdr.start_time BETWEEN UNIX_TIMESTAMP(DATE_FORMAT(NOW(), '%Y-%m-%d 00:00:00')) - AND UNIX_TIMESTAMP(DATE_FORMAT(NOW(), '%Y-%m-%d 23:59:59')) -GROUP BY bpinfo.id -HAVING daily_cost >= fraud_daily_limit -! - -my $x = {}; -for my $e (@{ $a }) { - if(exists $x->{$e->{id}}) { - if($x->{$e->{id}}->{type} eq 'profile_limit' && $e->{type} eq 'account_limit') { - - # if account limit hits and it has lock and/or notify, mark for action - if(defined $e->{fraud_daily_limit} and - int($e->{daily_cost}) >= int($e->{fraud_daily_limit}) and - ($e->{fraud_daily_lock} || $e->{fraud_daily_notify})) { - - $x->{$e->{id}} = $e; - } else { - # we have account fraud prefs set, but either the limit is not reached - # or no actions are necessary, let it slip through, overriding - # billing profile fraud settings - delete $x->{$e->{id}}; - } - } - } else { - # if account or billing profile limit hits and it has lock and/or notify, - # mark for action - if(defined $e->{fraud_daily_limit} and - int($e->{daily_cost}) >= int($e->{fraud_daily_limit}) and - ($e->{fraud_daily_lock} || $e->{fraud_daily_notify})) { - - $x->{$e->{id}} = $e; +Readonly my @required => qw(); +Readonly my $config_file => '/etc/ngcp-panel/provisioning.conf'; +Readonly my $interval => 'day'; + +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, + -sections => [ qw(NAME OPTIONS USAGE) ], + -message => $msg + ? $msg =~ /not found/i + ? $msg + : "Missing parameters: $msg" + : '', + ); + return; } -for my $e (values %{ $x }) { - $e->{fraud_daily_lock} and - $o->lock_voip_account({id => $e->{id}, lock => $LOCK{$e->{fraud_daily_lock}}}); - - $e->{fraud_daily_notify} or next; - - my $subs = $db->sql_get_all_arrayref(<<"!", $e->{id}); - SELECT s.username, d.domain, s.external_id - FROM voip_subscribers s - LEFT JOIN domains d ON d.id = s.domain_id - WHERE s.contract_id = ? - AND s.status != 'terminated' -! - - my $cur = sprintf('%.2f', $e->{daily_cost} / 100); - my $max = sprintf('%.2f', $e->{fraud_daily_limit} / 100); - - my ($subject, $body); - if ($e->{fraud_daily_lock}) { - $body = "Account ID " . $e->{id} . " has been locked due to exceeding the configured" . "\n" - . "daily credit balance threshold ($cur >= $max ) in the " - . ($e->{type} eq 'profile_limit' ? 'billing profile' : 'account settings') . "\n\n"; - $subject = 'Account ID ' . $e->{id} . ' locked by daily fraud detection'; +sub load_config { + $config = XML::Simple->new()->XMLin($config_file, ForceArray => 0) + or die "Cannot load config: $config_file: $ERRNO"; + return; +} + +sub get_data { + my ($uri, $link) = @_; + my $client = new NGCP::API::Client; + $client->set_verbose($opts->{verbose}); + my $res = $client->request("GET", $uri); + die $res->result unless $res->is_success; + my $res_hash = $res->as_hash; + return [] unless $res_hash->{total_count} && $res_hash->{total_count} > 0; + my $data = $res_hash->{_embedded}{'ngcp:'.$link}; + return ref $data eq 'ARRAY' ? $data : [ $data ]; +} + +sub get_email_template { + my $event = shift; + my $lock_type = $event->{interval_lock} ? 'lock' : 'warning'; + my $reseller_id = $event->{reseller_id}; + my $templates_data = get_data('/api/emailtemplates/', 'emailtemplates'); + my $selected_template; + foreach my $template (@{$templates_data}) { + next if $template->{name} ne 'customer_fraud_'.$lock_type.'_default_email' + && $template->{name} ne 'customer_fraud_'.$lock_type.'_email'; + next if $template->{reseller_id} && $template->{reseller_id} != $reseller_id; + $selected_template = $template; + last if $template->{reseller_id}; } - else { - $body = "Account ID " . $e->{id} . " is currently exceeding the configured daily credit balance" . "\n" - . "threshold ($cur >= $max) in the " - . ($e->{type} eq 'profile_limit' ? 'billing profile' : 'account settings') . ",\n" - . "but has not been locked due to configuration.\n\n"; - $subject = 'Account ID ' . $e->{id} . ' exceeding daily fraud detection limit'; + return $selected_template; +} + +sub send_email { + my ($event, $subscribers) = @_; + + my $template = get_email_template($event); + + my $vars = { adminmail => $config->{adminmail}, + customer_id => $event->{id}, + interval_cost => sprintf('%.2f', $event->{interval_cost}/100), + interval_limit => sprintf('%.2f', $event->{interval_limit}/100), + type => $event->{type} eq 'profile_limit' + ? 'billing profile' : 'customer', + }; + + foreach my $subscriber (@{$subscribers}) { + $vars->{subscribers} .= sprintf "%s\@%s %s\n", + @{$subscriber}{qw(username domain)}, + $subscriber->{external_id} + ? '('.$subscriber->{external_id}.')' : ''; } - if (!$subs || !@$subs) { - $body .= "There are no affected subscribers.\n"; - } - else { - $body .= "Affected subscribers:\n"; - for my $s (@$subs) { - $body .= "\t$s->{username}\@$s->{domain}". - ($s->{external_id} ? " (external ID '$s->{external_id}')" - : '') . "\n"; - } - } - - sendmail ( Email::Simple->create( + 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 => $e->{fraud_daily_notify}, - From => $$conf{adminmail}, - Subject => $subject, + To => $event->{interval_notify}, + From => $template->{from_email}, + Subject => $template->{subject}, ], - body => $body, - )); + body => $template->{body}, + ); + + Email::Sender::Simple->send($email, { transport => $transport }) + or die sprintf "Cannot send fraud daily lock notification to %s: $ERRNO", + $email->header('To'); + + return; +} + + +sub lock_customer { + my ($event, $subscribers) = @_; + + my $client = new NGCP::API::Client; + $client->set_verbose($opts->{verbose}); + my $uri = '/api/customers/'.$event->{id}; + my $data = [ { op => 'replace', + path => '/status', + value => 'locked' } ]; + my $res = $client->request("PATCH", $uri, $data); + if ($res->status_line =~ /200 OK/) { + foreach my $subscriber (@{$subscribers}) { + $uri = '/api/subscribers/'.$subscriber->{id}; + $data = [ { op => 'replace', + path => '/status', + value => 'locked' }, + { op => 'replace', + path => '/lock', + value => $event->{interval_lock} } ]; + $res = $client->request("PATCH", $uri, $data); + } + } + + return; +} + +sub main { + check_params(); + load_config(); + my $events = get_data(sprintf('/api/customerfraudevents/?interval=%s', + $interval), + 'customerfraudevents'); + foreach my $event (@{$events}) { + my $subscribers = get_data(sprintf('/api/subscribers/?customer_id=%d', + $event->{id}), + 'subscribers'); + if ($event->{interval_lock} > 0) { + lock_customer($event, $subscribers); + } + send_email($event, $subscribers); + } + return; } -1; +main(); + +exit 0; + +__END__ + +=head1 NAME + +ngcp-fraud-daily-lock - checks for contract balances above fraud limit thresholds + +=head1 OPTIONS + +=over 8 + +=item B<-help> + +Print a brief help message. + +=item B<-verbose> + +Show additional debug information. Default false. + +=back + +=head1 USAGE + +ngcp-fraud-daily-lock [options] + +=head1 DESCRIPTION + +B<This program> checks for contract balances above fraud limit warning thresholds and sends email notifications about the incidents as applying actions on such contracts (e.g. lock). Interval: 'day' + +=head1 REQUIRED ARGUMENTS + +None + +=head1 EXIT STATUS + +Exit code 0 means everything is ok otherwise 1. + +=head1 CONFIGURATION + +=head1 DIAGNOSTICS + +=head1 SEE ALSO + +NGCP::API::Client + +=head1 DEPENDENCIES + +ngcp-fraud-daily-lock relies on a bunch of Perl modules, all of them specified as +dependencies through the Debian package. + +=head1 INCOMPATIBILITIES + +No known at this time. + +=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 AND COPYRIGHT + +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/>. + +=cut diff --git a/bin/ngcp-get_customer b/bin/ngcp-get_customer index 7cecd3b..5842fd1 100755 --- a/bin/ngcp-get_customer +++ b/bin/ngcp-get_customer @@ -1,135 +1,65 @@ #!/usr/bin/perl use strict; use warnings; -use Config::Tiny; use English; use Getopt::Long; -use JSON qw(); -use LWP::UserAgent; use Pod::Usage; -use Data::Dumper; -use IO::Socket::SSL; +use NGCP::API::Client; +use Readonly; + +Readonly my @required => qw(customer_id); -my $config = Config::Tiny->read('/etc/default/ngcp-api'); my $opts = { - host => '127.0.0.1', - port => 1443, - auth_user => 'administrator', - auth_pwd => 'administrator', verbose => 0, - admin => 0 }; -if ($config) { - $opts->{host} = $config->{_}->{NGCP_API_IP}; - $opts->{port} = $config->{_}->{NGCP_API_PORT}; - $opts->{sslverify} = $config->{_}->{NGCP_API_SSLVERIFY} || 'yes'; -} - GetOptions( $opts, - "help|h" => sub { pod2usage(-exitval =>0); }, - "host=s", - "port=i", - "auth_user=s", - "auth_pwd=s", + "help|h" => \&usage, + "customer_id=i", "verbose", - "man" => sub { pod2usage(-exitval => 0, -verbose => 2); }, - "username|u=s", - "domain|d=s", - "account_id|i=i" -) or pod2usage(2); - -die pod2usage(-exitval => 1, -message => "Missing parameters") unless - (defined $opts->{account_id} and not defined $opts->{username} and - not defined $opts->{domain}) or - (defined $opts->{username} and defined $opts->{domain} and - not defined $opts->{account_id}); +) or usage(); -sub main { - my $urlbase = 'https://'.$opts->{host}.':'.$opts->{port}; - my $ua = LWP::UserAgent->new(); - if($opts->{sslverify} eq 'no') { - $ua->ssl_opts( - verify_hostname => 0, - SSL_verify_mode => IO::Socket::SSL::SSL_VERIFY_NONE, - ); - } - $ua->credentials($opts->{host}.':'.$opts->{port}, 'api_admin_http', - $opts->{auth_user}, $opts->{auth_pwd}); - # debug!! - if($opts->{verbose}) { - $ua->show_progress(1); - $ua->add_handler("request_send", sub { shift->dump; return }); - $ua->add_handler("response_done", sub { shift->dump; return }); - } - my $customer_url; - if ($opts->{account_id}) { - $customer_url = $urlbase . '/api/customers/'.$opts->{account_id}; - } - else { - $customer_url= get_customer_url($ua, $urlbase); - } - my $res = do_request($ua, $customer_url); - if($res->is_success) { - # use no indentation/linebreaks, for syslog logging - $Data::Dumper::Indent = 1; - # don't print useless variable names - $Data::Dumper::Terse = 1; - # sort hash keys, so parameters always have the same order - $Data::Dumper::Sortkeys = 1; - my $collection = JSON::from_json($res->decoded_content); - print "VoIP account information:\n", Dumper $collection; - } else { - die $res->as_string; +sub check_params { + my @missing; + foreach my $param (@required) { + push @missing, $param unless $opts->{$param}; } + usage(join(' ', @missing)) if scalar @missing; return; } -sub get_customer_url { - my $ua = shift; - my $urlbase = shift; - my $url = $urlbase."/api/subscribers/?domain=".$opts->{domain}. - '&username='.$opts->{username}; - my $req = HTTP::Request->new('GET', $url); - my $customer_url; - - my $res = $ua->request($req); - if($res->is_success) { - my $collection = JSON::from_json($res->decoded_content); - if ($collection->{total_count} == 1) { - my $lnks = $collection->{_embedded}->{'ngcp:subscribers'}->{_links}; - $customer_url = $urlbase . $lnks->{'ngcp:customers'}->{href}; - } - else { - pod2usage(-exitval => 3, -message => "customer not found"); - } - } - else { - die $res->as_string; - } - return $customer_url; +sub usage { + my $missing = shift; + pod2usage(-exitval => $missing ? 1 : 0, + -verbose => 99, + -sections => [ qw(NAME OPTIONS USAGE) ], + -message => $missing ? "Missing parameters: $missing" : '', + ); + return; } -sub do_request { - my $ua = shift; - my $url = shift; - my $req = HTTP::Request->new('GET', $url); - $req->header('Content-Type' => 'application/json'); - $req->header('Prefer' => 'return=representation'); +sub main { + check_params(); + my $uri = '/api/customers/'; + $uri .= $opts->{customer_id} ? $opts->{customer_id} : ''; + my $client = new NGCP::API::Client; + $client->set_verbose($opts->{verbose}); + my $res = $client->request("GET", $uri); + $res->is_success ? print $res->decoded_content."\n" + : print $res->result."\n"; - return $ua->request($req); + return; } main(); -__END__ -=head1 NAME +exit 0; -ngcp-get_customer - show info of a customer on NGCP +__END__ -=head1 SYNOPSIS +=head1 NAME -ngcp-get_customer [options] +ngcp-get_customer - retreives an NGCP Customer =head1 OPTIONS @@ -137,70 +67,52 @@ ngcp-get_customer [options] =item B<-help> -Print a brief help message and exits. - -=item B<-auth_user> - -Authentication username . Defaults to 'administrator'. - -=item B<-auth_pwd> - -Authentication password . Defaults to 'administrator'. - -=item B<-host> +Print a brief help message. -Host where the send queries. Defaults to '127.0.0.1'. +=item B<-customer_id> -=item B<-port> - -Port where the send queries. Defaults to 1443. - -=item B<-account_id|i> - -the unique ID of an existing account. - -=item B<-username|u> - -SIP username. - -=item B<-domain|d> - -existing domain for subscriber. +Customer id =item B<-verbose> -See debug information. Default false. +Show additional debug information. Default false. =back -=head1 DESCRIPTION +=head1 USAGE -B<This program> will show info of a customer at NGCP. +ngcp-get_customer [options] -=head1 USAGE +ngcp-get_customer --customer_id 11 -ngcp-get_customer -host 1.2.3.4 -d test.example.org -u test +=head1 DESCRIPTION -ngcp-get_customer -host 1.2.3.4 -i 45 +B<This program> retreives a customer from the NGCP platform. =head1 REQUIRED ARGUMENTS -B<domain> and B<username> or B<account_id> +=over 8 + +=item B<-customer_id> + +=back =head1 EXIT STATUS -Exit code 0 means that everything should have went fine otherwise error. +Exit code 0 means everything is ok otherwise 1. + +=head1 CONFIGURATION =head1 DIAGNOSTICS -=head1 CONFIGURATION +=head1 SEE ALSO -/etc/default/ngcp-api for default values +NGCP::API::Client =head1 DEPENDENCIES ngcp-get_customer relies on a bunch of Perl modules, all of them specified as -dependencies through the ngcp-ossbss-clients-perl Debian package. +dependencies through the Debian package. =head1 INCOMPATIBILITIES @@ -215,17 +127,21 @@ Development Team <support@sipwise.com>. Victor Seva <vseva@sipwise.com> -=head1 LICENSE +=head1 LICENSE AND COPYRIGHT -Copyright (c) 2015 Sipwise GmbH, Austria. -All rights reserved. You may not copy, distribute -or modify without prior written permission from -Sipwise GmbH, Austria. +Copyright (C) 2016 Sipwise GmbH, Austria -=head1 LICENSE AND COPYRIGHT +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. -Copyright (c) 2015 Sipwise GmbH, Austria. -You should have received a copy of the licence terms together with the -software. +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. =cut diff --git a/bin/ngcp-sound_set b/bin/ngcp-sound_set index 76420ca..c207c5d 100755 --- a/bin/ngcp-sound_set +++ b/bin/ngcp-sound_set @@ -1,99 +1,147 @@ #!/usr/bin/perl use strict; +use warnings; +use English; +use Getopt::Long; +use Pod::Usage; +use NGCP::API::Client; +use Readonly; + +Readonly my @required => qw(id); + +my $opts = { + verbose => 0, +}; + +GetOptions( $opts, + "help|h" => \&usage, + "id=i", + "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; +} -use Data::Dumper; -use Sipwise::Provisioning::Voip; -use Sipwise::Provisioning::Config; +sub usage { + my $missing = shift; + pod2usage(-exitval => $missing ? 1 : 0, + -verbose => 99, + -sections => [ qw(NAME OPTIONS USAGE) ], + -message => $missing ? "Missing parameters: $missing" : '', + ); + return; +} -my %CONFIG = (admin => 'cmd'); +sub main { + check_params(); + my $uri = '/api/soundsets/'; + $uri .= $opts->{id} ? $opts->{id} : ''; + my $client = new NGCP::API::Client; + $client->set_verbose($opts->{verbose}); + my $res = $client->request("GET", $uri); + $res->is_success ? print $res->content."\n" + : print $res->result."\n"; + + return; +} -my $config = Sipwise::Provisioning::Config->new()->get_config(); +main(); -unless ($CONFIG{password} = $config->{acl}->{$CONFIG{admin}}->{password}) { - die "Error: No provisioning password found for user $CONFIG{admin}\n"; -} +exit 0; -sub main; -sub usage; -sub call_prov; +__END__ -my $prov = Sipwise::Provisioning::Voip->new(); +=head1 NAME -main; +ngcp-sound_set - retreives an NGCP Sound Set -sub main { - # use no indentation/linebreaks, for syslog logging - $Data::Dumper::Indent = 1; - # don't print useless variable names - $Data::Dumper::Terse = 1; - # sort hash keys, so parameters always have the same order - $Data::Dumper::Sortkeys = 1; - - my $return; - - print "Fetching all sound sets\n"; - $return = call_prov('get_sound_sets'); - print "Sound Sets:\n", Dumper $return; - - print "Creating global sound set\n"; - $return = call_prov('create_sound_set', { - reseller_id => 1, - name => 'api sound set', - description => 'sound set created via api', - }); - print "Created Sound Set:\n", Dumper $return; - my $set_id = $return; - - print "Fetching new sound set\n"; - $return = call_prov('get_sound_set', { id => $set_id }); - print "Sound Set:\n", Dumper $return; - - print "Updating global sound set\n"; - $return = call_prov('update_sound_set', { - id => $set_id, - name => 'updated sound set', - description => 'updated sound set created via api', - account_id => 23, - }); - print "Updated Sound Set:\n", Dumper $return; - - print "Fetching new sound set\n"; - $return = call_prov('get_sound_set', { id => $set_id }); - print "Sound Set:\n", Dumper $return; - - print "Delete new sound set\n"; - $return = call_prov('delete_sound_set', { id => $set_id }); - print "Sound Set Deleted:\n", Dumper $return; - - exit; -} +=head1 OPTIONS +=over 8 -sub call_prov { - # scalar, scalar, hash-ref - my ($function, $parameter) = @_; - my $result; - - eval { - $result = $prov->handle_request( $function, - { - authentication => { - type => 'system', - username => $CONFIG{admin}, - password => $CONFIG{password}, - }, - parameters => $parameter, - }); - }; - - if($@) { - if(ref $@ eq 'SOAP::Fault') { - die "Voip\::$function failed: ". $@->faultstring; - } else { - die "Voip\::$function failed: $@"; - } - } +=item B<-help> - return $result; -} +Print a brief help message. + +=item B<-id> + +Sound set id + +=item B<-verbose> + +Show additional debug information. Default false. + +=back + +=head1 USAGE + +ngcp-sound_set [options] + +ngcp-sound_set --id 11 + +=head1 DESCRIPTION + +B<This program> retreives a sound set from the NGCP platform. + +=head1 REQUIRED ARGUMENTS + +=over 8 + +=item B<-id> + +=back + +=head1 EXIT STATUS + +Exit code 0 means everything is ok otherwise 1. + +=head1 CONFIGURATION + +=head1 DIAGNOSTICS + +=head1 SEE ALSO + +NGCP::API::Client + +=head1 DEPENDENCIES + +ngcp-sound_set relies on a bunch of Perl modules, all of them specified as +dependencies through the Debian package. + +=head1 INCOMPATIBILITIES + +No known at this time. + +=head1 BUGS AND LIMITATIONS + +Please report problems you notice to the Sipwise +Development Team <support@sipwise.com>. + +=head1 AUTHOR + +Victor Seva <vseva@sipwise.com> + +=head1 LICENSE AND COPYRIGHT + +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/>. +=cut diff --git a/bin/ngcp-terminate_customer b/bin/ngcp-terminate_customer index 4a55a13..cf58aa0 100755 --- a/bin/ngcp-terminate_customer +++ b/bin/ngcp-terminate_customer @@ -1,143 +1,66 @@ #!/usr/bin/perl use strict; use warnings; -use Config::Tiny; use English; use Getopt::Long; -use JSON qw(); -use LWP::UserAgent; use Pod::Usage; -use IO::Socket::SSL; +use NGCP::API::Client; +use Readonly; + +Readonly my @required => qw(customer_id); -my $config = Config::Tiny->read('/etc/default/ngcp-api'); my $opts = { - host => '127.0.0.1', - port => 1443, - auth_user => 'administrator', - auth_pwd => 'administrator', verbose => 0, - admin => 0 }; -if ($config) { - $opts->{host} = $config->{_}->{NGCP_API_IP}; - $opts->{port} = $config->{_}->{NGCP_API_PORT}; - $opts->{sslverify} = $config->{_}->{NGCP_API_SSLVERIFY} || 'yes'; -} - GetOptions( $opts, - "help|h" => sub { pod2usage(-exitval =>0); }, - "host=s", - "port=i", - "auth_user=s", - "auth_pwd=s", + "help|h" => \&usage, + "customer_id=i", "verbose", - "man" => sub { pod2usage(-exitval => 0, -verbose => 2); }, - "username|u=s", - "domain|d=s", - "account_id|i=i" -) or pod2usage(2); - -die pod2usage(-exitval => 1, -message => "Missing parameters") unless - (defined $opts->{account_id} and not defined $opts->{username} and - not defined $opts->{domain}) or - (defined $opts->{username} and defined $opts->{domain} and - not defined $opts->{account_id}); +) or usage(); -sub main { - my $urlbase = 'https://'.$opts->{host}.':'.$opts->{port}; - my $ua = LWP::UserAgent->new(); - if($opts->{sslverify} eq 'no') { - $ua->ssl_opts( - verify_hostname => 0, - SSL_verify_mode => IO::Socket::SSL::SSL_VERIFY_NONE, - ); - } - $ua->credentials($opts->{host}.':'.$opts->{port}, 'api_admin_http', - $opts->{auth_user}, $opts->{auth_pwd}); - # debug!! - if($opts->{verbose}) { - $ua->show_progress(1); - $ua->add_handler("request_send", sub { shift->dump; return }); - $ua->add_handler("response_done", sub { shift->dump; return }); - } - my $customer_url; - if ($opts->{account_id}) { - $customer_url = $urlbase . '/api/customers/'.$opts->{account_id}; - } - else { - $customer_url= get_customer_url($ua, $urlbase); - } - my $res = do_request($ua, $customer_url); - if($res->is_success) { - print $res->status_line . "\n"; - } else { - die $res->as_string; +sub check_params { + my @missing; + foreach my $param (@required) { + push @missing, $param unless $opts->{$param}; } + usage(join(' ', @missing)) if scalar @missing; return; } -sub get_customer_url { - my $ua = shift; - my $urlbase = shift; - my $url = $urlbase."/api/subscribers/?domain=".$opts->{domain}. - '&username='.$opts->{username}; - my $req = HTTP::Request->new('GET', $url); - my $customer_url; - - my $res = $ua->request($req); - if($res->is_success) { - my $collection = JSON::from_json($res->decoded_content); - if ($collection->{total_count} == 1) { - $customer_url = $urlbase . - $collection->{_links}->{'ngcp:customers'}->{href}; - } - else { - pod2usage(-exitval => 3, -message => "customer not found"); - } - } - else { - die $res->as_string; - } - return $customer_url; +sub usage { + my $missing = shift; + pod2usage(-exitval => $missing ? 1 : 0, + -verbose => 99, + -sections => [ qw(NAME OPTIONS USAGE) ], + -message => $missing ? "Missing parameters: $missing" : '', + ); + return; } -sub do_request { - my $ua = shift; - my $url = shift; - my $data = { - status => 'terminated', - contact_id => 0, - billing_profile_id => 0 - }; - my $req = HTTP::Request->new('GET', $url); - my $res = $ua->request($req); - if($res->is_success) { - my $collection = JSON::from_json($res->decoded_content); - $data->{contact_id} = $collection->{contact_id}; - $data->{billing_profile_id} = $collection->{billing_profile_id}; - } - else { - die $res->as_string; - } - $req = HTTP::Request->new('PUT', $url); - $req->header('Content-Type' => 'application/json'); - $req->header('Prefer' => 'return=minimal'); - $req->content(JSON::to_json($data)); +sub main { + check_params(); + my $uri = '/api/customers/'.$opts->{customer_id}; + my $client = new NGCP::API::Client; + $client->set_verbose($opts->{verbose}); + my $data = [ { op => 'replace', + path => '/status', + value => 'terminated' } ]; + my $res = $client->request("PATCH", $uri, $data); + print $res->result."\n"; - return $ua->request($req); + return; } main(); -__END__ -=head1 NAME +exit 0; -ngcp-terminate_customer - terminates a customer on NGCP +__END__ -=head1 SYNOPSIS +=head1 NAME -ngcp-terminate_customer [options] +ngcp-terminate_customer - terminate an NGCP Customer =head1 OPTIONS @@ -145,70 +68,52 @@ ngcp-terminate_customer [options] =item B<-help> -Print a brief help message and exits. - -=item B<-auth_user> - -Authentication username . Defaults to 'administrator'. - -=item B<-auth_pwd> - -Authentication password . Defaults to 'administrator'. +Print a brief help message. -=item B<-host> +=item B<-customer_id> -Host where the send queries. Defaults to '127.0.0.1'. - -=item B<-port> - -Port where the send queries. Defaults to 1443. - -=item B<-account_id|i> - -the unique ID of an existing account. - -=item B<-username|u> - -SIP username. - -=item B<-domain|d> - -existing domain for subscriber. +Customer id =item B<-verbose> -See debug information. Default false. +Show additional debug information. Default false. =back -=head1 DESCRIPTION +=head1 USAGE -B<This program> will terminate a customer at NGCP. +ngcp-terminate_customer [options] -=head1 USAGE +ngcp-terminate_customer --customer_id 11 -ngcp-terminate_customer -host 1.2.3.4 -d test.example.org -u test +=head1 DESCRIPTION -ngcp-terminate_customer -host 1.2.3.4 -i 45 +B<This program> terminates a customer on the NGCP platform. =head1 REQUIRED ARGUMENTS -B<domain> and B<username> or B<account_id> +=over 8 + +=item B<-customer_id> + +=back =head1 EXIT STATUS -Exit code 0 means that everything should have went fine otherwise error. +Exit code 0 means everything is ok otherwise 1. + +=head1 CONFIGURATION =head1 DIAGNOSTICS -=head1 CONFIGURATION +=head1 SEE ALSO -/etc/default/ngcp-api for default values +NGCP::API::Client =head1 DEPENDENCIES ngcp-terminate_customer relies on a bunch of Perl modules, all of them specified as -dependencies through the ngcp-ossbss-clients-perl Debian package. +dependencies through the Debian package. =head1 INCOMPATIBILITIES @@ -223,17 +128,21 @@ Development Team <support@sipwise.com>. Victor Seva <vseva@sipwise.com> -=head1 LICENSE +=head1 LICENSE AND COPYRIGHT -Copyright (c) 2015 Sipwise GmbH, Austria. -All rights reserved. You may not copy, distribute -or modify without prior written permission from -Sipwise GmbH, Austria. +Copyright (C) 2016 Sipwise GmbH, Austria -=head1 LICENSE AND COPYRIGHT +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. -Copyright (c) 2015 Sipwise GmbH, Austria. -You should have received a copy of the licence terms together with the -software. +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. =cut diff --git a/bin/ngcp-terminate_subscriber b/bin/ngcp-terminate_subscriber index 2b92882..f8cd0f4 100755 --- a/bin/ngcp-terminate_subscriber +++ b/bin/ngcp-terminate_subscriber @@ -1,147 +1,81 @@ #!/usr/bin/perl use strict; use warnings; -use Config::Tiny; use English; use Getopt::Long; -use JSON qw(); -use LWP::UserAgent; use Pod::Usage; -use IO::Socket::SSL; +use NGCP::API::Client; +use Readonly; + +Readonly my @required => qw(username domain); -my $config = Config::Tiny->read('/etc/default/ngcp-api'); my $opts = { - host => '127.0.0.1', - port => 1443, - auth_user => 'administrator', - auth_pwd => 'administrator', verbose => 0, - admin => 0 }; -if ($config) { - $opts->{host} = $config->{_}->{NGCP_API_IP}; - $opts->{port} = $config->{_}->{NGCP_API_PORT}; - $opts->{sslverify} = $config->{_}->{NGCP_API_SSLVERIFY} || 'yes'; -} - GetOptions( $opts, - "help|h", - "host=s", - "port=i", - "auth_user=s", - "auth_pwd=s", + "help|h" => \&usage, + "username=s", + "domain=s", "verbose", - "man" => sub { pod2usage(-exitval => 0, -verbose => 2); }, - "username|u=s", - "domain|d=s", - "account_id|i=i" -) or pod2usage(2); - -die pod2usage(-exitval => 1, -message => "Missing parameters") unless - (defined $opts->{account_id} and not defined $opts->{username} and - not defined $opts->{domain}) or - (defined $opts->{username} and defined $opts->{domain} and - not defined $opts->{account_id}); +) or usage(); -sub main { - my $urlbase = 'https://'.$opts->{host}.':'.$opts->{port}; - my $ua = LWP::UserAgent->new(); - if($opts->{sslverify} eq 'no') { - $ua->ssl_opts( - verify_hostname => 0, - SSL_verify_mode => IO::Socket::SSL::SSL_VERIFY_NONE, - ); - } - $ua->credentials($opts->{host}.':'.$opts->{port}, 'api_admin_http', - $opts->{auth_user}, $opts->{auth_pwd}); - # debug!! - if($opts->{verbose}) { - $ua->show_progress(1); - $ua->add_handler("request_send", sub { shift->dump; return }); - $ua->add_handler("response_done", sub { shift->dump; return }); - } - my $subscriber_url; - if ($opts->{account_id}) { - $subscriber_url = $urlbase . '/api/customers/'.$opts->{account_id}; - } - else { - $subscriber_url= get_subscriber_url($ua, $urlbase); - } - my $res = do_request($ua, $subscriber_url); - if($res->is_success) { - print $res->status_line . "\n"; - } else { - die $res->as_string; +sub check_params { + my @missing; + foreach my $param (@required) { + push @missing, $param unless $opts->{$param}; } + usage(join(' ', @missing)) if scalar @missing; return; } -sub get_subscriber_url { - my $ua = shift; - my $urlbase = shift; - my $url = $urlbase."/api/subscribers/?domain=".$opts->{domain}. - '&username='.$opts->{username}; - my $req = HTTP::Request->new('GET', $url); - my $subscriber_url; - - my $res = $ua->request($req); - if($res->is_success) { - my $collection = JSON::from_json($res->decoded_content); - if ($collection->{total_count} == 1) { - $subscriber_url = $urlbase . - $collection->{_links}->{'ngcp:subscribers'}->{href}; - } - else { - pod2usage(-exitval => 3, -message => "subscriber not found"); - } - } - else { - die $res->as_string; - } - return $subscriber_url; +sub usage { + my $msg = shift; + pod2usage(-exitval => $msg ? 1 : 0, + -verbose => 99, + -sections => [ qw(NAME OPTIONS USAGE) ], + -message => $msg + ? $msg =~ /not found/i + ? $msg + : "Missing parameters: $msg" + : '', + ); + return; } -sub do_request { - my $ua = shift; - my $url = shift; - my $data = { - status => 'terminated', - domain_id => 0, - customer_id => 0, - username => '', - password => '' - }; - my $req = HTTP::Request->new('GET', $url); - my $res = $ua->request($req); - if($res->is_success) { - my $collection = JSON::from_json($res->decoded_content); - $data->{domain_id} = $collection->{domain_id}; - $data->{customer_id} = $collection->{customer_id}; - $data->{username} = $collection->{username}; - $data->{password} = $collection->{password}; - } - else { - die $res->as_string; +sub main { + check_params(); + my $uri = sprintf '/api/subscribers/?username=%s&domain=%s', + @{$opts}{qw(username domain)}; + my $client = new NGCP::API::Client; + $client->set_verbose($opts->{verbose}); + my $sub = $client->request("GET", $uri); + my $sub_id; + if ($sub->as_hash->{total_count} == 1) { + $sub_id = $sub->as_hash->{_embedded}->{'ngcp:subscribers'}->{id}; + usage("Wrong subscriber id found") unless $sub_id =~ /^\d$/; + } else { + usage("Subscriber not found"); } - $req = HTTP::Request->new('PUT', $url); - $req->header('Content-Type' => 'application/json'); - $req->header('Prefer' => 'return=minimal'); - $req->content(JSON::to_json($data)); + $uri = '/api/subscribers/'.$sub_id; + my $data = [ { op => 'replace', + path => '/status', + value => 'terminated' } ]; + my $res = $client->request("PATCH", $uri, $data); + print $res->result."\n"; - return $ua->request($req); + return; } main(); -__END__ -=head1 NAME +exit 0; -ngcp-terminate_subscriber - terminates a subscriber on NGCP +__END__ -=head1 SYNOPSIS +=head1 NAME -ngcp-terminate_subscriber [options] +ngcp-terminate_subscriber - terminate an NGCP Subscriber =head1 OPTIONS @@ -149,70 +83,58 @@ ngcp-terminate_subscriber [options] =item B<-help> -Print a brief help message and exits. - -=item B<-auth_user> - -Authentication username . Defaults to 'administrator'. +Print a brief help message -=item B<-auth_pwd> +=item B<-username> -Authentication password . Defaults to 'administrator'. +Subscriber username -=item B<-host> +=item B<-domain> -Host where the send queries. Defaults to '127.0.0.1'. +Subscriber domain -=item B<-port> - -Port where the send queries. Defaults to 1443. - -=item B<-account_id|i> - -the unique ID of an existing account. - -=item B<-username|u> - -SIP username. +=item B<-verbose> -=item B<-domain|d> +Show additional debug information. Default false. -existing domain for subscriber. +=back -=item B<-verbose> +=head1 USAGE -See debug information. Default false. +ngcp-terminate_subscriber [options] -=back +ngcp-terminate_subscriber --username 431110001 --domain example.org =head1 DESCRIPTION -B<This program> will terminate a subscriber at NGCP. +B<This program> terminates a subscriber on the NGCP platform. -=head1 USAGE +=head1 REQUIRED ARGUMENTS -ngcp-terminate_subscriber -host 1.2.3.4 -d test.example.org -u test +=over 8 -ngcp-terminate_subscriber -host 1.2.3.4 -i 45 +=item B<-username> -=head1 REQUIRED ARGUMENTS +=item B<-domain> -B<domain> and B<username> or B<account_id> +=back =head1 EXIT STATUS -Exit code 0 means that everything should have went fine otherwise error. +Exit code 0 means everything is ok otherwise 1. + +=head1 CONFIGURATION =head1 DIAGNOSTICS -=head1 CONFIGURATION +=head1 SEE ALSO -/etc/default/ngcp-api for default values +NGCP::API::Client =head1 DEPENDENCIES ngcp-terminate_subscriber relies on a bunch of Perl modules, all of them specified as -dependencies through the ngcp-ossbss-clients-perl Debian package. +dependencies through the Debian package. =head1 INCOMPATIBILITIES @@ -227,17 +149,21 @@ Development Team <support@sipwise.com>. Victor Seva <vseva@sipwise.com> -=head1 LICENSE +=head1 LICENSE AND COPYRIGHT -Copyright (c) 2015 Sipwise GmbH, Austria. -All rights reserved. You may not copy, distribute -or modify without prior written permission from -Sipwise GmbH, Austria. +Copyright (C) 2016 Sipwise GmbH, Austria -=head1 LICENSE AND COPYRIGHT +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. -Copyright (c) 2015 Sipwise GmbH, Austria. -You should have received a copy of the licence terms together with the -software. +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. =cut