MT#18411 provisioning scripts rework

- reworked /bin/* provisioning scripts to use NGCP::API::Client
    - completely reworked ngcp-fraud-* ngcp-credit-warning scripts

Change-Id: I416847c5c1d3e7dda5695d700a03182fa47f5b24
(cherry picked from commit 3d65648d9f)
changes/55/5555/1
Kirill Solomko 9 years ago
parent 7b68db7c31
commit 9f394cac51

@ -1,125 +1,92 @@
#!/usr/bin/perl #!/usr/bin/perl
use strict; use strict;
use warnings; use warnings;
use Config::Tiny;
use English; use English;
use Getopt::Long; use Getopt::Long;
use JSON qw(); use NGCP::API::Client;
use LWP::UserAgent;
use Pod::Usage; use Pod::Usage;
use IO::Socket::SSL; use Readonly;
Readonly my @required => qw();
my $config = Config::Tiny->read('/etc/default/ngcp-api');
my $opts = { my $opts = {
host => '127.0.0.1',
port => 1443,
auth_user => 'administrator',
auth_pwd => 'administrator',
verbose => 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, GetOptions( $opts,
"help|h" => sub { pod2usage(-exitval =>0); }, "help|h" => \&usage,
"host=s",
"port=i",
"auth_user=s",
"auth_pwd=s",
"verbose", "verbose",
"man" => sub { pod2usage(-exitval => 0, -verbose => 2); }, ) or usage();
) or pod2usage(2);
sub main { sub check_params {
my $urlbase = 'https://'.$opts->{host}.':'.$opts->{port}; my @missing;
my $ua = LWP::UserAgent->new(); foreach my $param (@required) {
if($opts->{sslverify} eq 'no') { push @missing, $param unless $opts->{$param};
$ua->ssl_opts(
verify_hostname => 0,
SSL_verify_mode => IO::Socket::SSL::SSL_VERIFY_NONE,
);
} }
$ua->credentials($opts->{host}.':'.$opts->{port}, 'api_admin_http', usage(join(' ', @missing)) if scalar @missing;
$opts->{auth_user}, $opts->{auth_pwd}); return;
# 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 usage {
my $missing = shift;
pod2usage(-exitval => $missing ? 1 : 0,
-verbose => 99,
-sections => [ qw(NAME OPTIONS USAGE) ],
-message => $missing ? "Missing parameters: $missing" : '',
);
return; return;
} }
sub do_request { sub main {
my $ua = shift; check_params();
my $url = shift; my $client = new NGCP::API::Client;
my $req = HTTP::Request->new('GET', $url); my $uri = '/api/domains/';
$req->header('Content-Type' => 'application/json'); $client->set_verbose($opts->{verbose});
$req->header('Prefer' => 'return=representation'); 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(); main();
exit 0;
__END__ __END__
=head1 NAME =head1 NAME
ngcp-api_ping - check NGCP API status ngcp-api_ping - check NGCP API status
=head1 SYNOPSIS
ngcp-api_ping [options]
=head1 OPTIONS =head1 OPTIONS
=over 8 =over 8
=item B<-help> =item B<-help>
Print a brief help message and exits. Print a brief help message.
=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> =item B<-verbose>
See debug information. Default false. Show additional debug information. Default false.
=back =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 =head1 REQUIRED ARGUMENTS
@ -127,18 +94,20 @@ None
=head1 EXIT STATUS =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 DIAGNOSTICS
=head1 CONFIGURATION =head1 SEE ALSO
/etc/default/ngcp-api for default values NGCP::API::Client
=head1 DEPENDENCIES =head1 DEPENDENCIES
ngcp-api_ping relies on a bunch of Perl modules, all of them specified as 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 =head1 INCOMPATIBILITIES
@ -153,17 +122,21 @@ Development Team <support@sipwise.com>.
Victor Seva <vseva@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. This program is free software: you can redistribute it and/or modify
All rights reserved. You may not copy, distribute it under the terms of the GNU General Public License as published by
or modify without prior written permission from the Free Software Foundation, either version 3 of the License, or
Sipwise GmbH, Austria. (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 GNU General Public License
You should have received a copy of the licence terms together with the along with this program. If not, see <http://www.gnu.org/licenses/>.
software.
=cut =cut

@ -1,99 +1,70 @@
#!/usr/bin/perl #!/usr/bin/perl
use strict; use strict;
use warnings; use warnings;
use Config::Tiny;
use English; use English;
use Getopt::Long; use Getopt::Long;
use JSON qw();
use LWP::UserAgent;
use Pod::Usage; 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 = { my $opts = {
billing_id => 1,
contact_id => 1,
type => 'sipaccount', type => 'sipaccount',
host => '127.0.0.1', status => 'active',
port => 1443, verbose => 0,
auth_user => 'administrator',
auth_pwd => 'administrator',
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, GetOptions( $opts,
"help|h" => sub { pod2usage(-exitval =>0); }, "help|h" => \&usage,
"billing_id=i", "billing_profile_id=i",
"contact_id=i", "contact_id=i",
"host=s",
"port=i",
"auth_user=s",
"auth_pwd=s",
"verbose",
"type=s", "type=s",
"man" => sub { pod2usage(-exitval => 0, -verbose => 2); } "verbose",
) or pod2usage(2); ) or usage();
sub main { sub check_params {
my $urlbase = 'https://'.$opts->{host}.':'.$opts->{port}; my @missing;
my $data = { foreach my $param (@required) {
billing_profile_id => $opts->{billing_id}, push @missing, $param unless $opts->{$param};
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); usage(join(' ', @missing)) if scalar @missing;
if($res->is_success) { return;
print $res->status_line . ' ' . $res->header('Location'). "\n";
} else {
die $res->as_string;
} }
sub usage {
my $missing = shift;
pod2usage(-exitval => $missing ? 1 : 0,
-verbose => 99,
-sections => [ qw(NAME OPTIONS USAGE) ],
-message => $missing ? "Missing parameters: $missing" : '',
);
return; return;
} }
sub do_request { sub main {
my $ua = shift; check_params();
my $urlbase = shift;
my $data = shift; 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";
my $req = HTTP::Request->new('POST', $urlbase.'/api/customers/'); return;
$req->header('Content-Type' => 'application/json');
$req->header('Prefer' => 'return=representation');
$req->content(JSON::to_json($data));
return $ua->request($req);
} }
main(); main();
__END__ exit 0;
=head1 NAME
ngcp-create_customer - create a customer on NGCP __END__
=head1 SYNOPSIS =head1 NAME
ngcp-create_customer [options] ngcp-create_customer - create a customer
=head1 OPTIONS =head1 OPTIONS
@ -101,31 +72,15 @@ ngcp-create_customer [options]
=item B<-help> =item B<-help>
Print a brief help message and exits. Print a brief help message.
=item B<-auth_user>
Authentication username . Defaults to 'administrator'.
=item B<-auth_pwd> =item B<-billing_profile_id>
Authentication password . Defaults to 'administrator'. Billing profile id.
=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<-billing_id>
The billing profile id. Defaults to 1.
=item B<-contact_id> =item B<-contact_id>
The contact id. Defaults to 1. Contact id.
=item B<-type> =item B<-type>
@ -134,36 +89,46 @@ Customer can be one of the "sipaccount" or "pbxaccount" type. Defaults to
=item B<-verbose> =item B<-verbose>
See debug information. Default false. Show additional debug information. Default false.
=back =back
=head1 DESCRIPTION =head1 USAGE
ngcp-create_customer [options]
B<This program> will create a subscriber at NGCP. ngcp-create_customer --billing_profile_id 1 --contact_id 4 --type sipaccount
=head1 USAGE =head1 DESCRIPTION
ngcp-create_customer -host 1.2.3.4 -billing_id 1 -profile_id 4 -type sipaccount B<This program> creates a customer on the NGCP platform.
=head1 REQUIRED ARGUMENTS =head1 REQUIRED ARGUMENTS
TODO =over 8
=item B<-billing_profile_id>
=item B<-contact_id>
=back
=head1 EXIT STATUS =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 DIAGNOSTICS
=head1 CONFIGURATION =head1 SEE ALSO
/etc/default/ngcp-api for default values NGCP::API::Client
=head1 DEPENDENCIES =head1 DEPENDENCIES
ngcp-create_customer relies on a bunch of Perl modules, all of them specified as 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 =head1 INCOMPATIBILITIES
@ -178,17 +143,21 @@ Development Team <support@sipwise.com>.
Victor Seva <vseva@sipwise.com> Victor Seva <vseva@sipwise.com>
=head1 LICENSE =head1 LICENSE AND COPYRIGHT
Copyright (c) 2015 Sipwise GmbH, Austria. Copyright (C) 2016 Sipwise GmbH, Austria
All rights reserved. You may not copy, distribute
or modify without prior written permission from
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 GNU General Public License
You should have received a copy of the licence terms together with the along with this program. If not, see <http://www.gnu.org/licenses/>.
software.
=cut =cut

@ -1,104 +1,72 @@
#!/usr/bin/perl #!/usr/bin/perl
use strict; use strict;
use warnings; use warnings;
use Config::Tiny;
use English; use English;
use Getopt::Long; use Getopt::Long;
use JSON qw();
use LWP::UserAgent;
use Pod::Usage; 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 = { my $opts = {
domain => $ARGV[0],
reseller_id => 1, reseller_id => 1,
host => '127.0.0.1',
port => 1443,
auth_user => 'administrator',
auth_pwd => 'administrator',
verbose => 0,
skip_xmpp => 0, skip_xmpp => 0,
skip_sip => 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, GetOptions( $opts,
"help|h" => sub { pod2usage(-exitval =>0); }, "help|h" => \&usage,
"domain=s",
"reseller_id=i", "reseller_id=i",
"host=s",
"port=i",
"auth_user=s",
"auth_pwd=s",
"skip_xmpp", "skip_xmpp",
"skip_sip", "skip_sip",
"verbose", "verbose",
"man" => sub { pod2usage(-exitval => 0, -verbose => 2); }, ) or usage();
) or pod2usage(2);
die pod2usage(-exitval => 1, -message => "No domain") unless ($#ARGV == 0);
sub main { sub check_params {
my $domain = shift; my @missing;
my $urlbase = 'https://'.$opts->{host}.':'.$opts->{port}; foreach my $param (@required) {
my $data = { push @missing, $param unless $opts->{$param};
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', usage(join(' ', @missing)) if scalar @missing;
$opts->{auth_user}, $opts->{auth_pwd}); return;
# 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); sub usage {
if($res->is_success) { my $missing = shift;
print $res->status_line . ' ' . $res->header('Location') . "\n"; pod2usage(-exitval => $missing ? 1 : 0,
} else { -verbose => 99,
die $res->as_string; -sections => [ qw(NAME OPTIONS USAGE) ],
} -message => $missing ? "Missing parameters: $missing" : '',
);
return; return;
} }
sub do_request { sub main {
my $ua = shift; check_params();
my $urlbase = shift; my $uri = '/api/domains/';
my $data = shift; my %data = map { $_ => $opts->{$_} } qw(reseller_id domain);
map { $data{"_".$_."_reload"} = $opts->{$_} } qw(skip_xmpp skip_sip);
my $req = HTTP::Request->new('POST', $urlbase."/api/domains/"); my $client = new NGCP::API::Client;
$req->header('Content-Type' => 'application/json'); $client->set_verbose($opts->{verbose});
$req->header('Prefer' => 'return=representation'); my $res = $client->request("POST", $uri, \%data);
$req->content(JSON::to_json($data)); print $res->result."\n";
return $ua->request($req); return;
} }
main($ARGV[0]); main();
__END__ exit 0;
=head1 NAME
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 =head1 OPTIONS
@ -106,31 +74,11 @@ ngcp-create_domain [options] domain
=item B<-help> =item B<-help>
Print a brief help message and exits. Print a brief help message.
=item B<-reseller_id> =item B<-reseller_id>
The reseller id to assign this domain to. Defaults to 1. Reseller id. Default 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.
=item B<-skip_sip> =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 Skip reloading XMPP services. If true, changes will not be effective immedeately
until the respective service is restarted or properly notified. Default false. 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 =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 =head1 REQUIRED ARGUMENTS
B<domain> to be created =over 8
=item B<-domain>
=back
=head1 EXIT STATUS =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 DIAGNOSTICS
=head1 CONFIGURATION =head1 SEE ALSO
/etc/default/ngcp-api for default values NGCP::API::Client
=head1 DEPENDENCIES =head1 DEPENDENCIES
ngcp-create_domain relies on a bunch of Perl modules, all of them specified as 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 =head1 INCOMPATIBILITIES
@ -184,17 +144,21 @@ Development Team <support@sipwise.com>.
Victor Seva <vseva@sipwise.com> Victor Seva <vseva@sipwise.com>
=head1 LICENSE =head1 LICENSE AND COPYRIGHT
Copyright (c) 2015 Sipwise GmbH, Austria. Copyright (C) 2016 Sipwise GmbH, Austria
All rights reserved. You may not copy, distribute
or modify without prior written permission from
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 GNU General Public License
You should have received a copy of the licence terms together with the along with this program. If not, see <http://www.gnu.org/licenses/>.
software.
=cut =cut

@ -1,152 +1,87 @@
#!/usr/bin/perl #!/usr/bin/perl
use strict; use strict;
use warnings; use warnings;
use Config::Tiny;
use English; use English;
use Getopt::Long; use Getopt::Long;
use JSON qw();
use LWP::UserAgent;
use Pod::Usage; 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 = { my $opts = {
host => '127.0.0.1', admin => 0,
port => 1443,
auth_user => 'administrator',
auth_pwd => 'administrator',
verbose => 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, GetOptions( $opts,
"help|h" => sub { pod2usage(-exitval =>0); }, "help|h" => \&usage,
"customer_id=i", "customer_id=i",
"host=s",
"port=i",
"auth_user=s",
"auth_pwd=s",
"verbose",
"man" => sub { pod2usage(-exitval => 0, -verbose => 2); },
"username|u=s", "username|u=s",
"domain|d=s",
"password|p=s", "password|p=s",
"domain|d=s",
"admin|s=i", "admin|s=i",
"cc|c=i", "cc|c=i",
"ac|a=i", "ac|a=i",
"sn|n=i", "sn|n=i",
"account_id|v=i", "webpassword|w=s",
"webpassword|w=s" "verbose",
) or pod2usage(2); ) or usage();
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});
sub main {
my $urlbase = 'https://'.$opts->{host}.':'.$opts->{port};
my $ua = LWP::UserAgent->new(); sub check_params {
if($opts->{sslverify} eq 'no') { my @missing;
$ua->ssl_opts( foreach my $param (@required) {
verify_hostname => 0, push @missing, $param unless $opts->{$param};
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;
} }
usage(join(' ', @missing)) if scalar @missing;
return; return;
} }
sub get_data { sub usage {
my $domain_id = shift; my $msg = shift;
my $data = { pod2usage(-exitval => $msg ? 1 : 0,
administrative => $opts->{admin} || 0, -verbose => 99,
domain_id => $domain_id, -sections => [ qw(NAME OPTIONS USAGE) ],
customer_id => $opts->{customer_id}, -message => $msg
username => $opts->{username}, ? $msg =~ /not found/i
password => $opts->{password}, ? $msg
webpassword => $opts->{webpassword}, : "Missing parameters: $msg"
primary_number => { : '',
cc => $opts->{cc}, );
ac => $opts->{ac}, return;
sn => $opts->{sn}
},
};
return $data;
} }
sub get_domain_id { sub main {
my $ua = shift; check_params();
my $urlbase = shift; my $uri = '/api/subscribers/';
my $domain = shift; my %data = map { $_ => $opts->{$_} }
my $url = $urlbase."/api/domains/?domain=".$domain; qw(customer_id username password webpassword);
my $req = HTTP::Request->new('GET', $url); $data{primary_number} = join '', @{$opts}{qw(cc ac sn)};
my $domain_id; $data{administrative} = $opts->{admin};
my $client = new NGCP::API::Client;
my $res = $ua->request($req); $client->set_verbose($opts->{verbose});
if($res->is_success) { # domain_id
my $collection = JSON::from_json($res->decoded_content); my $dom = $client->request("GET", "/api/domains/?domain=".$opts->{domain});
if ($collection->{total_count} == 1) { if ($dom->as_hash->{total_count} == 1) {
$domain_id = $collection->{_embedded}->{'ngcp:domains'}->{id}; $data{domain_id} = $dom->as_hash->{_embedded}->{'ngcp:domains'}->{id};
} } else {
else { usage("Domain not found");
pod2usage(-exitval => 3, -message => "Domain not found");
}
}
else {
die $res->status_line, "\n";
}
return $domain_id;
} }
my $res = $client->request("POST", $uri, \%data);
print $res->result."\n";
sub do_request { return;
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);
} }
main(); main();
exit 0;
__END__ __END__
=head1 NAME
ngcp-create_subscriber - create a subscriber on NGCP =head1 NAME
=head1 SYNOPSIS ngcp-create_subscriber - create a subscriber
ngcp-create_subscriber [options]
=head1 OPTIONS =head1 OPTIONS
@ -154,99 +89,97 @@ ngcp-create_subscriber [options]
=item B<-help> =item B<-help>
Print a brief help message and exits. Print a brief help message.
=item B<-customer_id> =item B<-customer_id>
The customer id to assign this subscriber to. An existing 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.
=item B<-username|u> =item B<-username|u>
new SIP username. A SIP username.
=item B<-domain|d> =item B<-domain|d>
existing domain for subscriber. An existing domain for the new subscriber.
=item B<-password|p> =item B<-password|p>
unencrypted SIP password for subscriber. An unencrypted SIP password for the new subscriber.
=item B<-webpassword|w> =item B<-webpassword|w>
unencrypted web password for subscriber. An unencrypted web password for the new subscriber.
=item B<-cc|c> =item B<-cc|c>
country code of subscriber number. A country code part of the subscriber's number.
=item B<-ac|a> =item B<-ac|a>
area code of subscriber number. An area code part of the subscriber's number.
=item B<-number|n> =item B<-number|n>
local part of subscriber number. A local number part of the subscriber's number.
=item B<-admin|s> =item B<-admin|s>
whether or not to set the administrative flag for the subscriber. Set the administrative flag for the new subscriber.
defaults to 0 (no). Defaults to 0 (no).
=item B<-verbose> =item B<-verbose>
See debug information. Default false. Show additional debug information. Default false.
=back =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
ngcp-create_subscriber -host 1.2.3.4 -customer_id 4 -d test.example.org -u test =head1 DESCRIPTION
-p passw12_ -c 34 -a 11 -n 12345 -s 0
B<This program> creates a subscriber on the NGCP platform.
=head1 REQUIRED ARGUMENTS =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 =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 DIAGNOSTICS
=head1 CONFIGURATION =head1 SEE ALSO
/etc/default/ngcp-api for default values NGCP::API::Client
=head1 DEPENDENCIES =head1 DEPENDENCIES
ngcp-create_subscriber relies on a bunch of Perl modules, all of them specified as 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 =head1 INCOMPATIBILITIES
@ -261,17 +194,21 @@ Development Team <support@sipwise.com>.
Victor Seva <vseva@sipwise.com> Victor Seva <vseva@sipwise.com>
=head1 LICENSE =head1 LICENSE AND COPYRIGHT
Copyright (c) 2015 Sipwise GmbH, Austria. Copyright (C) 2016 Sipwise GmbH, Austria
All rights reserved. You may not copy, distribute
or modify without prior written permission from
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 GNU General Public License
You should have received a copy of the licence terms together with the along with this program. If not, see <http://www.gnu.org/licenses/>.
software.
=cut =cut

@ -1,61 +1,232 @@
#!/usr/bin/perl -w #!/usr/bin/perl
use strict; use strict;
use warnings; use warnings;
use English;
use Email::Sender::Simple qw(sendmail); use Getopt::Long;
use Pod::Usage;
use NGCP::API::Client;
use Readonly;
use XML::Simple; use XML::Simple;
use Sipwise::DB; use Template;
use Sipwise::Provisioning::Config; use Email::Sender::Simple qw();
use Email::Simple;
use Email::Simple::Creator;
use Email::Sender::Transport::Sendmail qw();
my $MTA = '/usr/sbin/sendmail -oi -t'; Readonly my @required => qw();
Readonly my $config_file => '/etc/ngcp-panel/provisioning.conf';
sub main; my $opts = {
verbose => 0,
};
main; my $config;
sub main { GetOptions( $opts,
my $xs = new XML::Simple; "help|h" => \&usage,
my $conf = Sipwise::Provisioning::Config->new()->get_config(); "verbose",
my $db = new Sipwise::DB ( $$conf{billingdb} ); ) or usage();
$$conf{credit_warnings} = [ $$conf{credit_warnings} ] sub check_params {
if defined eval { %{$$conf{credit_warnings}} }; my @missing;
foreach my $param (@required) {
foreach my $domcfg (@{$$conf{credit_warnings}}) { push @missing, $param unless $opts->{$param};
}
my $contracts = $db->sql_get_all_arrayref(" usage(join(' ', @missing)) if scalar @missing;
SELECT a.contract_id,a.cash_balance,a.cash_balance_interval,GROUP_CONCAT(c.username,'\@',d.domain) AS subscribers return;
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 sub usage {
AND b.status != 'terminated' my $msg = shift;
AND a.contract_id = c.contract_id pod2usage(-exitval => $msg ? 1 : 0,
AND c.domain_id = d.id -verbose => 99,
AND d.domain = ? -sections => [ qw(NAME OPTIONS USAGE) ],
AND c.status != 'terminated' -message => $msg
AND a.cash_balance < ? ? $msg =~ /not found/i
GROUP BY contract_id ? $msg
", $$domcfg{domain}, $$domcfg{threshold}); : "Missing parameters: $msg"
if(@$contracts) { : '',
$$domcfg{recipients} = [ $$domcfg{recipients} ] );
unless defined eval { @{$$domcfg{recipients}} }; return;
}
my $mailtxt;
$mailtxt .= "Credit threshold warning for: $$domcfg{domain}\nThe following contracts are below the configured threshold of $$domcfg{threshold} cent:\n\n"; sub load_config {
$mailtxt .= "account_id\tcash_balance\tcash_balance_interval\tsubscribers\n"; $config = XML::Simple->new()->XMLin($config_file, ForceArray => 0)
for(@$contracts) { or die "Cannot load config: $config_file: $ERRNO";
$mailtxt .= "$$_{contract_id}\t$$_{cash_balance}\t$$_{cash_balance_interval}\t$$_{subscribers}\n"; return;
} }
sendmail ( Email::Simple->create( sub send_email {
my ($cwarning, $contracts) = @_;
my $template = get_email_template() || return;
my $vars = { domain => $cwarning->{domain},
threshold => $cwarning->{threshold},
adminmail => $config->{adminmail} };
foreach my $data (@{$contracts}) {
$vars->{contracts} .= sprintf <<EOF, @{$data}{qw(id cash_balance)};
contract_id: %s cash_balance: %s
EOF
}
my $tt = Template->new();
map { my $out;
$tt->process(\$template->{$_}, $vars, \$out);
$out and $template->{$_} = $out;
} keys %{$template};
my $transport = Email::Sender::Transport::Sendmail->new;
my $email = Email::Simple->create(
header => [ header => [
To => join(', ', @{$$domcfg{recipients}}), To => ref $cwarning->{recipients} eq 'ARRAY'
From => $$conf{adminmail}, ? join(', ', @{$cwarning->{recipients}})
Subject => 'Sipwise NGCP credit threshold notification', : $cwarning->{recipients},
From => $template->{from_email},
Subject => $template->{subject},
], ],
body => $mailtxt, 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 {
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

@ -1,126 +1,82 @@
#!/usr/bin/perl #!/usr/bin/perl
use strict; use strict;
use warnings; use warnings;
use Config::Tiny;
use English; use English;
use Getopt::Long; use Getopt::Long;
use JSON qw();
use LWP::UserAgent;
use Pod::Usage; use Pod::Usage;
use URI; use NGCP::API::Client;
use IO::Socket::SSL; use Readonly;
Readonly my @required => qw(domain);
my $config = Config::Tiny->read('/etc/default/ngcp-api');
my $opts = { my $opts = {
reseller_id => 1, domain => $ARGV[0],
host => '127.0.0.1',
port => 1443,
auth_user => 'administrator',
auth_pwd => 'administrator',
skip_xmpp => 0, skip_xmpp => 0,
skip_sip => 0, skip_sip => 0,
verbose => 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, GetOptions( $opts,
"help|h", "help|h" => \&usage,
"reseller_id=i", "domain=s",
"host=s",
"port=i",
"auth_user=s",
"auth_pwd=s",
"skip_sip",
"skip_xmpp", "skip_xmpp",
"skip_sip",
"verbose", "verbose",
"man" => sub { pod2usage(-exitval => 0, -verbose => 2); }, ) or usage();
) or pod2usage(2);
die pod2usage(-exitval => 1, -message => "No domain") unless ($#ARGV == 0);
sub main { sub check_params {
my $domain = shift; my @missing;
my $urlbase = 'https://'.$opts->{host}.':'.$opts->{port}; foreach my $param (@required) {
push @missing, $param unless $opts->{$param};
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;
} }
usage(join(' ', @missing)) if scalar @missing;
return; return;
} }
sub get_domain_url { sub usage {
my $ua = shift; my $msg = shift;
my $urlbase = shift; pod2usage(-exitval => $msg ? 1 : 0,
my $domain = shift; -verbose => 99,
my $url = $urlbase."/api/domains/?domain=".$domain; -sections => [ qw(NAME OPTIONS USAGE) ],
my $req = HTTP::Request->new('GET', $url); -message => $msg
my $domain_url; ? $msg =~ /not found/i
? $msg
my $res = $ua->request($req); : "Missing parameters: $msg"
if($res->is_success) { : '',
my $collection = JSON::from_json($res->decoded_content); );
if ($collection->{total_count} == 1) { return;
$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 do_request { sub main {
my $ua = shift; check_params();
my $url = shift; 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";
my $full_url = URI->new($url); return;
$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);
} }
main($ARGV[0]); main();
__END__ exit 0;
=head1 NAME
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 =head1 OPTIONS
@ -128,31 +84,7 @@ ngcp-delete_domain [options] domain
=item B<-help> =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.
=item B<-skip_sip> =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 Skip reloading XMPP services. If true, changes will not be effective immedeately
until the respective service is restarted or properly notified. Default false. 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 =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 =head1 REQUIRED ARGUMENTS
B<domain> to be deleted =over 8
=item B<-domain>
=back
=head1 EXIT STATUS =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 DIAGNOSTICS
=head1 CONFIGURATION =head1 SEE ALSO
/etc/default/ngcp-api for default values NGCP::API::Client
=head1 DEPENDENCIES =head1 DEPENDENCIES
ngcp-delete_domain relies on a bunch of Perl modules, all of them specified as 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 =head1 INCOMPATIBILITIES
@ -206,17 +150,21 @@ Development Team <support@sipwise.com>.
Victor Seva <vseva@sipwise.com> Victor Seva <vseva@sipwise.com>
=head1 LICENSE =head1 LICENSE AND COPYRIGHT
Copyright (c) 2015 Sipwise GmbH, Austria. Copyright (C) 2016 Sipwise GmbH, Austria
All rights reserved. You may not copy, distribute
or modify without prior written permission from
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 GNU General Public License
You should have received a copy of the licence terms together with the along with this program. If not, see <http://www.gnu.org/licenses/>.
software.
=cut =cut

@ -1,154 +1,259 @@
#!/usr/bin/perl #!/usr/bin/perl
use strict; use strict;
use warnings; use warnings;
use English;
use Getopt::Long;
use Pod::Usage;
use NGCP::API::Client;
use Readonly;
use XML::Simple;
use Template;
use Email::Sender::Simple qw();
use Email::Simple;
use Email::Simple::Creator;
use Email::Sender::Transport::Sendmail qw();
Readonly my @required => qw();
Readonly my $config_file => '/etc/ngcp-panel/provisioning.conf';
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;
}
use Email::Sender::Simple qw(sendmail); sub usage {
use Sipwise::Provisioning::Billing; my $msg = shift;
pod2usage(-exitval => $msg ? 1 : 0,
my %LOCK = ( -verbose => 99,
none => undef, -sections => [ qw(NAME OPTIONS USAGE) ],
foreign => 1, -message => $msg
outgoing => 2, ? $msg =~ /not found/i
incoming => 3, ? $msg
global => 4, : "Missing parameters: $msg"
0 => 'none', : '',
1 => 'foreign',
2 => 'outgoing',
3 => 'incoming',
4 => 'global',
); );
return;
}
my $conf = Sipwise::Provisioning::Config->new()->get_config(); sub load_config {
$config = XML::Simple->new()->XMLin($config_file, ForceArray => 0)
my $o = Sipwise::Provisioning::Billing->new(); or die "Cannot load config: $config_file: $ERRNO";
my $db = $o->{database}; return;
# 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}};
} }
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 ];
} }
} else {
# if account or billing profile limit hits and it has lock and/or notify, sub get_email_template {
# mark for action my $event = shift;
if(defined $e->{fraud_interval_limit} and my $lock_type = $event->{interval_lock} ? 'lock' : 'warning';
int($e->{interval_cost}) >= int($e->{fraud_interval_limit}) and my $reseller_id = $event->{reseller_id};
($e->{fraud_interval_lock} || $e->{fraud_interval_notify})) { my $templates_data = get_data('/api/emailtemplates/', 'emailtemplates');
my $selected_template;
$x->{$e->{id}} = $e; 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;
} }
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}.')' : '';
} }
for my $e (values %{ $x }) { my $tt = Template->new();
map { my $out;
$tt->process(\$template->{$_}, $vars, \$out);
$out and $template->{$_} = $out;
} keys %{$template};
$e->{fraud_interval_lock} and my $transport = Email::Sender::Transport::Sendmail->new;
$o->lock_voip_account({id => $e->{id}, lock => $LOCK{$e->{fraud_interval_lock}}}); my $email = Email::Simple->create(
header => [
To => $event->{interval_notify},
From => $template->{from_email},
Subject => $template->{subject},
],
body => $template->{body},
);
$e->{fraud_interval_notify} or next; Email::Sender::Simple->send($email, { transport => $transport })
or die sprintf "Cannot send fraud auto lock notification to %s: $ERRNO",
$email->header('To');
return;
}
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->{interval_cost} / 100); sub lock_customer {
my $max = sprintf('%.2f', $e->{fraud_interval_limit} / 100); my ($event, $subscribers) = @_;
my ($subject, $body); my $client = new NGCP::API::Client;
if ($e->{fraud_interval_lock}) { $client->set_verbose($opts->{verbose});
$body = "Account ID " . $e->{id} . " has been locked due to exceeding the configured" . "\n" my $uri = '/api/customers/'.$event->{id};
. "credit balance threshold ($cur >= $max ) in the " my $data = [ { op => 'replace',
. ($e->{type} eq 'profile_limit' ? 'billing profile' : 'account settings') . "\n\n"; path => '/status',
$subject = 'Account ID ' . $e->{id} . ' locked by fraud detection'; 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);
} }
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';
} }
if (!$subs || !@$subs) { return;
$body .= "There are no affected subscribers.\n";
} }
else {
$body .= "Affected subscribers:\n"; sub main {
for my $s (@$subs) { check_params();
$body .= "\t$s->{username}\@$s->{domain}". load_config();
($s->{external_id} ? " (external ID '$s->{external_id}')" my $events = get_data(sprintf('/api/customerfraudevents/?interval=%s',
: '') . "\n"; $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;
sendmail ( Email::Simple->create(
header => [
To => $e->{fraud_interval_notify},
From => $$conf{adminmail},
Subject => $subject,
],
body => $body,
));
} }
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

@ -1,146 +1,259 @@
#!/usr/bin/perl #!/usr/bin/perl
use strict; use strict;
use warnings; 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); Readonly my @required => qw();
use Sipwise::Provisioning::Billing; Readonly my $config_file => '/etc/ngcp-panel/provisioning.conf';
Readonly my $interval => 'day';
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 $opts = {
verbose => 0,
my $o = Sipwise::Provisioning::Billing->new(); };
my $db = $o->{database};
my $config;
my $a = $db->sql_get_all_arrayref(<<"!");
SELECT bpinfo.type, bpinfo.id, GetOptions( $opts,
IF (bpinfo.fraud_use_reseller_rates > 0, SUM(cdr.source_reseller_cost), "help|h" => \&usage,
SUM(cdr.source_customer_cost)) as daily_cost, "verbose",
bpinfo.fraud_daily_limit, bpinfo.fraud_daily_lock, bpinfo.fraud_daily_notify ) or usage();
FROM (
SELECT contracts.id, bp.fraud_use_reseller_rates, sub check_params {
CASE WHEN cfp.fraud_daily_limit > 0 THEN 'account_limit' my @missing;
ELSE 'profile_limit' END as type, foreach my $param (@required) {
IF (cfp.fraud_daily_limit > 0, cfp.fraud_daily_limit, bp.fraud_daily_limit) as fraud_daily_limit, push @missing, $param unless $opts->{$param};
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;
} }
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 {
$e->{fraud_daily_lock} and $config = XML::Simple->new()->XMLin($config_file, ForceArray => 0)
$o->lock_voip_account({id => $e->{id}, lock => $LOCK{$e->{fraud_daily_lock}}}); or die "Cannot load config: $config_file: $ERRNO";
return;
$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';
} }
else {
$body = "Account ID " . $e->{id} . " is currently exceeding the configured daily credit balance" . "\n" sub get_data {
. "threshold ($cur >= $max) in the " my ($uri, $link) = @_;
. ($e->{type} eq 'profile_limit' ? 'billing profile' : 'account settings') . ",\n" my $client = new NGCP::API::Client;
. "but has not been locked due to configuration.\n\n"; $client->set_verbose($opts->{verbose});
$subject = 'Account ID ' . $e->{id} . ' exceeding daily fraud detection limit'; 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 ];
} }
if (!$subs || !@$subs) { sub get_email_template {
$body .= "There are no affected subscribers.\n"; 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 { return $selected_template;
$body .= "Affected subscribers:\n";
for my $s (@$subs) {
$body .= "\t$s->{username}\@$s->{domain}".
($s->{external_id} ? " (external ID '$s->{external_id}')"
: '') . "\n";
} }
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}.')' : '';
} }
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 => [ header => [
To => $e->{fraud_daily_notify}, To => $event->{interval_notify},
From => $$conf{adminmail}, From => $template->{from_email},
Subject => $subject, 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;
} }
1; 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;
}
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

@ -1,135 +1,65 @@
#!/usr/bin/perl #!/usr/bin/perl
use strict; use strict;
use warnings; use warnings;
use Config::Tiny;
use English; use English;
use Getopt::Long; use Getopt::Long;
use JSON qw();
use LWP::UserAgent;
use Pod::Usage; use Pod::Usage;
use Data::Dumper; use NGCP::API::Client;
use IO::Socket::SSL; use Readonly;
Readonly my @required => qw(customer_id);
my $config = Config::Tiny->read('/etc/default/ngcp-api');
my $opts = { my $opts = {
host => '127.0.0.1',
port => 1443,
auth_user => 'administrator',
auth_pwd => 'administrator',
verbose => 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, GetOptions( $opts,
"help|h" => sub { pod2usage(-exitval =>0); }, "help|h" => \&usage,
"host=s", "customer_id=i",
"port=i",
"auth_user=s",
"auth_pwd=s",
"verbose", "verbose",
"man" => sub { pod2usage(-exitval => 0, -verbose => 2); }, ) or usage();
"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});
sub main { sub check_params {
my $urlbase = 'https://'.$opts->{host}.':'.$opts->{port}; my @missing;
my $ua = LWP::UserAgent->new(); foreach my $param (@required) {
if($opts->{sslverify} eq 'no') { push @missing, $param unless $opts->{$param};
$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;
} }
usage(join(' ', @missing)) if scalar @missing;
return; return;
} }
sub get_customer_url { sub usage {
my $ua = shift; my $missing = shift;
my $urlbase = shift; pod2usage(-exitval => $missing ? 1 : 0,
my $url = $urlbase."/api/subscribers/?domain=".$opts->{domain}. -verbose => 99,
'&username='.$opts->{username}; -sections => [ qw(NAME OPTIONS USAGE) ],
my $req = HTTP::Request->new('GET', $url); -message => $missing ? "Missing parameters: $missing" : '',
my $customer_url; );
return;
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 do_request { sub main {
my $ua = shift; check_params();
my $url = shift; my $uri = '/api/customers/';
my $req = HTTP::Request->new('GET', $url); $uri .= $opts->{customer_id} ? $opts->{customer_id} : '';
$req->header('Content-Type' => 'application/json'); my $client = new NGCP::API::Client;
$req->header('Prefer' => 'return=representation'); $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(); main();
__END__ exit 0;
=head1 NAME
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 =head1 OPTIONS
@ -137,70 +67,52 @@ ngcp-get_customer [options]
=item B<-help> =item B<-help>
Print a brief help message and exits. Print a brief help message.
=item B<-auth_user>
Authentication username . Defaults to 'administrator'.
=item B<-auth_pwd>
Authentication password . Defaults to 'administrator'. =item B<-customer_id>
=item B<-host> 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.
=item B<-verbose> =item B<-verbose>
See debug information. Default false. Show additional debug information. Default false.
=back =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 =head1 REQUIRED ARGUMENTS
B<domain> and B<username> or B<account_id> =over 8
=item B<-customer_id>
=back
=head1 EXIT STATUS =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 DIAGNOSTICS
=head1 CONFIGURATION =head1 SEE ALSO
/etc/default/ngcp-api for default values NGCP::API::Client
=head1 DEPENDENCIES =head1 DEPENDENCIES
ngcp-get_customer relies on a bunch of Perl modules, all of them specified as 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 =head1 INCOMPATIBILITIES
@ -215,17 +127,21 @@ Development Team <support@sipwise.com>.
Victor Seva <vseva@sipwise.com> Victor Seva <vseva@sipwise.com>
=head1 LICENSE =head1 LICENSE AND COPYRIGHT
Copyright (c) 2015 Sipwise GmbH, Austria. Copyright (C) 2016 Sipwise GmbH, Austria
All rights reserved. You may not copy, distribute
or modify without prior written permission from
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 GNU General Public License
You should have received a copy of the licence terms together with the along with this program. If not, see <http://www.gnu.org/licenses/>.
software.
=cut =cut

@ -1,99 +1,147 @@
#!/usr/bin/perl #!/usr/bin/perl
use strict; use strict;
use warnings;
use English;
use Getopt::Long;
use Pod::Usage;
use NGCP::API::Client;
use Readonly;
use Data::Dumper; Readonly my @required => qw(id);
use Sipwise::Provisioning::Voip;
use Sipwise::Provisioning::Config;
my %CONFIG = (admin => 'cmd'); my $opts = {
verbose => 0,
};
my $config = Sipwise::Provisioning::Config->new()->get_config(); GetOptions( $opts,
"help|h" => \&usage,
"id=i",
"verbose",
) or usage();
unless ($CONFIG{password} = $config->{acl}->{$CONFIG{admin}}->{password}) { sub check_params {
die "Error: No provisioning password found for user $CONFIG{admin}\n"; my @missing;
foreach my $param (@required) {
push @missing, $param unless $opts->{$param};
}
usage(join(' ', @missing)) if scalar @missing;
return;
} }
sub main; sub usage {
sub usage; my $missing = shift;
sub call_prov; pod2usage(-exitval => $missing ? 1 : 0,
-verbose => 99,
my $prov = Sipwise::Provisioning::Voip->new(); -sections => [ qw(NAME OPTIONS USAGE) ],
-message => $missing ? "Missing parameters: $missing" : '',
main; );
return;
}
sub main { sub main {
# use no indentation/linebreaks, for syslog logging check_params();
$Data::Dumper::Indent = 1; my $uri = '/api/soundsets/';
# don't print useless variable names $uri .= $opts->{id} ? $opts->{id} : '';
$Data::Dumper::Terse = 1; my $client = new NGCP::API::Client;
# sort hash keys, so parameters always have the same order $client->set_verbose($opts->{verbose});
$Data::Dumper::Sortkeys = 1; my $res = $client->request("GET", $uri);
$res->is_success ? print $res->content."\n"
my $return; : print $res->result."\n";
print "Fetching all sound sets\n"; return;
$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;
} }
main();
sub call_prov { exit 0;
# 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($@) { __END__
if(ref $@ eq 'SOAP::Fault') {
die "Voip\::$function failed: ". $@->faultstring;
} else {
die "Voip\::$function failed: $@";
}
}
return $result; =head1 NAME
}
ngcp-sound_set - retreives an NGCP Sound Set
=head1 OPTIONS
=over 8
=item B<-help>
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

@ -1,143 +1,66 @@
#!/usr/bin/perl #!/usr/bin/perl
use strict; use strict;
use warnings; use warnings;
use Config::Tiny;
use English; use English;
use Getopt::Long; use Getopt::Long;
use JSON qw();
use LWP::UserAgent;
use Pod::Usage; 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 = { my $opts = {
host => '127.0.0.1',
port => 1443,
auth_user => 'administrator',
auth_pwd => 'administrator',
verbose => 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, GetOptions( $opts,
"help|h" => sub { pod2usage(-exitval =>0); }, "help|h" => \&usage,
"host=s", "customer_id=i",
"port=i",
"auth_user=s",
"auth_pwd=s",
"verbose", "verbose",
"man" => sub { pod2usage(-exitval => 0, -verbose => 2); }, ) or usage();
"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});
sub main { sub check_params {
my $urlbase = 'https://'.$opts->{host}.':'.$opts->{port}; my @missing;
my $ua = LWP::UserAgent->new(); foreach my $param (@required) {
if($opts->{sslverify} eq 'no') { push @missing, $param unless $opts->{$param};
$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;
} }
usage(join(' ', @missing)) if scalar @missing;
return; return;
} }
sub get_customer_url { sub usage {
my $ua = shift; my $missing = shift;
my $urlbase = shift; pod2usage(-exitval => $missing ? 1 : 0,
my $url = $urlbase."/api/subscribers/?domain=".$opts->{domain}. -verbose => 99,
'&username='.$opts->{username}; -sections => [ qw(NAME OPTIONS USAGE) ],
my $req = HTTP::Request->new('GET', $url); -message => $missing ? "Missing parameters: $missing" : '',
my $customer_url; );
return;
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 do_request { sub main {
my $ua = shift; check_params();
my $url = shift; my $uri = '/api/customers/'.$opts->{customer_id};
my $data = { my $client = new NGCP::API::Client;
status => 'terminated', $client->set_verbose($opts->{verbose});
contact_id => 0, my $data = [ { op => 'replace',
billing_profile_id => 0 path => '/status',
}; value => 'terminated' } ];
my $req = HTTP::Request->new('GET', $url); my $res = $client->request("PATCH", $uri, $data);
my $res = $ua->request($req); print $res->result."\n";
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));
return $ua->request($req); return;
} }
main(); main();
__END__ exit 0;
=head1 NAME
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 =head1 OPTIONS
@ -145,70 +68,52 @@ ngcp-terminate_customer [options]
=item B<-help> =item B<-help>
Print a brief help message and exits. Print a brief help message.
=item B<-auth_user>
Authentication username . Defaults to 'administrator'. =item B<-customer_id>
=item B<-auth_pwd> Customer id
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|i>
the unique ID of an existing account.
=item B<-username|u>
SIP username.
=item B<-domain|d>
existing domain for subscriber.
=item B<-verbose> =item B<-verbose>
See debug information. Default false. Show additional debug information. Default false.
=back =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 =head1 REQUIRED ARGUMENTS
B<domain> and B<username> or B<account_id> =over 8
=item B<-customer_id>
=back
=head1 EXIT STATUS =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 DIAGNOSTICS
=head1 CONFIGURATION =head1 SEE ALSO
/etc/default/ngcp-api for default values NGCP::API::Client
=head1 DEPENDENCIES =head1 DEPENDENCIES
ngcp-terminate_customer relies on a bunch of Perl modules, all of them specified as 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 =head1 INCOMPATIBILITIES
@ -223,17 +128,21 @@ Development Team <support@sipwise.com>.
Victor Seva <vseva@sipwise.com> Victor Seva <vseva@sipwise.com>
=head1 LICENSE =head1 LICENSE AND COPYRIGHT
Copyright (c) 2015 Sipwise GmbH, Austria. Copyright (C) 2016 Sipwise GmbH, Austria
All rights reserved. You may not copy, distribute
or modify without prior written permission from
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 GNU General Public License
You should have received a copy of the licence terms together with the along with this program. If not, see <http://www.gnu.org/licenses/>.
software.
=cut =cut

@ -1,147 +1,81 @@
#!/usr/bin/perl #!/usr/bin/perl
use strict; use strict;
use warnings; use warnings;
use Config::Tiny;
use English; use English;
use Getopt::Long; use Getopt::Long;
use JSON qw();
use LWP::UserAgent;
use Pod::Usage; 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 = { my $opts = {
host => '127.0.0.1',
port => 1443,
auth_user => 'administrator',
auth_pwd => 'administrator',
verbose => 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, GetOptions( $opts,
"help|h", "help|h" => \&usage,
"host=s", "username=s",
"port=i", "domain=s",
"auth_user=s",
"auth_pwd=s",
"verbose", "verbose",
"man" => sub { pod2usage(-exitval => 0, -verbose => 2); }, ) or usage();
"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});
sub main { sub check_params {
my $urlbase = 'https://'.$opts->{host}.':'.$opts->{port}; my @missing;
my $ua = LWP::UserAgent->new(); foreach my $param (@required) {
if($opts->{sslverify} eq 'no') { push @missing, $param unless $opts->{$param};
$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;
} }
usage(join(' ', @missing)) if scalar @missing;
return; return;
} }
sub get_subscriber_url { sub usage {
my $ua = shift; my $msg = shift;
my $urlbase = shift; pod2usage(-exitval => $msg ? 1 : 0,
my $url = $urlbase."/api/subscribers/?domain=".$opts->{domain}. -verbose => 99,
'&username='.$opts->{username}; -sections => [ qw(NAME OPTIONS USAGE) ],
my $req = HTTP::Request->new('GET', $url); -message => $msg
my $subscriber_url; ? $msg =~ /not found/i
? $msg
my $res = $ua->request($req); : "Missing parameters: $msg"
if($res->is_success) { : '',
my $collection = JSON::from_json($res->decoded_content); );
if ($collection->{total_count} == 1) { return;
$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 do_request { sub main {
my $ua = shift; check_params();
my $url = shift; my $uri = sprintf '/api/subscribers/?username=%s&domain=%s',
my $data = { @{$opts}{qw(username domain)};
status => 'terminated', my $client = new NGCP::API::Client;
domain_id => 0, $client->set_verbose($opts->{verbose});
customer_id => 0, my $sub = $client->request("GET", $uri);
username => '', my $sub_id;
password => '' if ($sub->as_hash->{total_count} == 1) {
}; $sub_id = $sub->as_hash->{_embedded}->{'ngcp:subscribers'}->{id};
my $req = HTTP::Request->new('GET', $url); usage("Wrong subscriber id found") unless $sub_id =~ /^\d$/;
my $res = $ua->request($req); } else {
if($res->is_success) { usage("Subscriber not found");
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;
} }
$req = HTTP::Request->new('PUT', $url); $uri = '/api/subscribers/'.$sub_id;
$req->header('Content-Type' => 'application/json'); my $data = [ { op => 'replace',
$req->header('Prefer' => 'return=minimal'); path => '/status',
$req->content(JSON::to_json($data)); value => 'terminated' } ];
my $res = $client->request("PATCH", $uri, $data);
print $res->result."\n";
return $ua->request($req); return;
} }
main(); main();
__END__ exit 0;
=head1 NAME
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 =head1 OPTIONS
@ -149,70 +83,58 @@ ngcp-terminate_subscriber [options]
=item B<-help> =item B<-help>
Print a brief help message and exits. Print a brief help message
=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> =item B<-username>
Port where the send queries. Defaults to 1443. Subscriber username
=item B<-account_id|i> =item B<-domain>
the unique ID of an existing account. Subscriber domain
=item B<-username|u> =item B<-verbose>
SIP username. Show additional debug information. Default false.
=item B<-domain|d> =back
existing domain for subscriber. =head1 USAGE
=item B<-verbose> ngcp-terminate_subscriber [options]
See debug information. Default false. ngcp-terminate_subscriber --username 431110001 --domain example.org
=back
=head1 DESCRIPTION =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 =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 DIAGNOSTICS
=head1 CONFIGURATION =head1 SEE ALSO
/etc/default/ngcp-api for default values NGCP::API::Client
=head1 DEPENDENCIES =head1 DEPENDENCIES
ngcp-terminate_subscriber relies on a bunch of Perl modules, all of them specified as 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 =head1 INCOMPATIBILITIES
@ -227,17 +149,21 @@ Development Team <support@sipwise.com>.
Victor Seva <vseva@sipwise.com> Victor Seva <vseva@sipwise.com>
=head1 LICENSE =head1 LICENSE AND COPYRIGHT
Copyright (c) 2015 Sipwise GmbH, Austria. Copyright (C) 2016 Sipwise GmbH, Austria
All rights reserved. You may not copy, distribute
or modify without prior written permission from
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 GNU General Public License
You should have received a copy of the licence terms together with the along with this program. If not, see <http://www.gnu.org/licenses/>.
software.
=cut =cut

Loading…
Cancel
Save