#!/usr/bin/perl use strict; use warnings; use Getopt::Long qw(:config posix_default no_ignorecase); use Pod::Usage qw(pod2usage); use Config::General qw(); use File::Slurp qw(); use XML::Simple qw(); #use lib "/home/rkrenn/sipwise/git/ngcp-schema/lib"; #use lib "/home/rkrenn/sipwise/git/sipwise-base/lib"; #use lib "/usr/local/devel/ngcp-schema/lib"; #use lib "/usr/local/devel/sipwise-base/lib"; use NGCP::Schema qw(); #use lib "/home/rkrenn/sipwise/git/ngcp-panel/lib"; #use lib "/usr/local/devel/ngcp-panel/lib"; use NGCP::Panel::Utils::ProvisioningTemplates qw(); my @panel_configs = qw( /etc/ngcp-panel/ngcp_panel.conf /etc/ngcp_panel.conf /ngcp_panel.conf ); #/home/rkrenn/sipwise/git/vagrant-ngcp/ngcp_panel.conf #/usr/local/devel/vagrant-ngcp/ngcp_panel.conf my @provisioning_configs = qw( /etc/ngcp-panel/provisioning.conf ); #/etc/ngcp-panel/provisioning.conf #/home/rkrenn/sipwise/git/vagrant-ngcp/provisioning.conf #/usr/local/devel/vagrant-ngcp/provisioning.conf my %db = ( host => undef, #'192.168.0.99' port => 3306, user => 'root', password => undef, ); my $template_name = shift @ARGV; #my $template_name = 'My First Provisioning Template'; pod2usage(2) unless $template_name; pod2usage(1) if $template_name =~ /help|\?/; my $help; my $log_level; Getopt::Long::Configure("pass_through"); Getopt::Long::Configure("permute"); GetOptions( ( map { ('db_' . $_ . ':s') => \&parse_old_db_option } keys %db ), ( map { ('db-' . $_ . ':s') => \$db{$_}; } keys %db ), 'log_level:s' => \&parse_old_log_level_option, 'log-level:s' => \$log_level, "help|?" => \$help, ) or pod2usage(2); pod2usage(1) if $help; my %mock_objs = (); my $c = _create_c(); NGCP::Panel::Utils::ProvisioningTemplates::load_template_map($c); if (exists $c->stash->{'provisioning_templates'}->{$template_name}) { $c->stash->{'provisioning_template_name'} = $template_name; my $fields = NGCP::Panel::Utils::ProvisioningTemplates::get_fields($c,0); my $values = { map { $_ => undef; } grep { $_ ne 'purge'; } keys %$fields }; my $csv_file; #my $csv_file = '/home/rkrenn/temp/provisioning_templates/CCS_ICM_Nummern.csv'; my $purge; Getopt::Long::Configure("no_pass_through"); Getopt::Long::Configure("no_permute"); GetOptions( ( map { ($_ . ($fields->{$_}->{required} ? '=' : ':') . 's') => \$values->{$_}; } keys %$values ), "purge" => \$purge, "file:s" => \$csv_file, ) or pod2usage(2); if ($csv_file) { my $csv_data = File::Slurp::read_file($csv_file); my ($linecount,$errors) = NGCP::Panel::Utils::ProvisioningTemplates::process_csv( c => $c, data => \$csv_data, purge => $purge, ); if (scalar @$errors) { die("CSV file ($linecount lines) processed, " . scalar @$errors . " error(s)\n"); } else { print("CSV file ($linecount lines) processed, 0 error(s)\n"); } } else { $values->{purge} = $purge; eval { my $context = NGCP::Panel::Utils::ProvisioningTemplates::provision_begin( c => $c, ); NGCP::Panel::Utils::ProvisioningTemplates::provision_commit_row( c => $c, context => $context, 'values' => $values, #'values' => { # first_name => 'John', # last_name => 'Doe', # cc => "43", # ac => "316", # sn => "1234567", # purge => 1, #} #'values' => { # service_number => '800010144', # switch3_number => '19768988', # company => "test12", # purge => 1, #} ); NGCP::Panel::Utils::ProvisioningTemplates::provision_finish( c => $c, context => $context, ); print ("Provisioning template '$template_name' done: subscriber " . $context->{subscriber}->{username} . '@' . $context->{domain}->{domain} . " created\n"); }; if ($@) { die("Provisioning template '$template_name' failed: " . $@ . "\n"); } } } else { die("Unknown provisioning template '$template_name'\n"); } exit(0); sub parse_old_db_option { my ($name, $value) = @_; my $newname = $name =~ tr/_/-/r; $db{$name} = $value; #warn "$0: option --$name is deprecated; use --$newname instead\n"; } sub parse_old_log_level_option { my ($name, $value) = @_; my $newname = $name =~ tr/_/-/r; $log_level = $value; #warn "$0: option --$name is deprecated; use --$newname instead\n"; } sub _create_c { my $config = _get_panel_config(); { no strict "refs"; ## no critic (ProhibitNoStrict) *{'NGCP::Schema::set_transaction_isolation'} = sub { my ($self,$level) = @_; return $self->storage->dbh_do( sub { my ($storage, $dbh, @args) = @_; $dbh->do("SET TRANSACTION ISOLATION LEVEL " . $args[0]); }, $level, ); }; *{'NGCP::Schema::set_wait_timeout'} = sub { my ($self,$timeout) = @_; return $self->storage->dbh_do( sub { my ($storage, $dbh, @args) = @_; $dbh->do("SET SESSION wait_timeout = " . $args[0]); }, $timeout, ); }; } my $db = _get_schema(); my $req = sub { my $self = shift; return _create_mock('_request', _param => { # '$c->request->params' => undef, }, param => sub { my $self = shift; my $key = shift; return $self->{param}->{$key} if $key; return $self->{param}; }, path => sub { my $self = shift; return 'api/'; }, ); }; $c = _create_mock('c', _stash => { }, stash => sub { my $self = shift; my $key = shift; return $self->{stash}->{$key} if $key; return $self->{stash}; }, _model => { DB => $db, }, model => sub { my $self = shift; my $key = shift; return $self->{model}->{$key} if $key; return $self->{model}; }, log => sub { my $self = shift; return _create_mock('log', debug => sub { my $self = shift; my $str = shift; my @params = @_; print $str . "\n" if ($log_level and grep { $_ eq lc($log_level); } qw(debug)); }, info => sub { my $self = shift; my $str = shift; my @params = @_; print $str . "\n" if ($log_level and grep { $_ eq lc($log_level); } qw(info debug)); }, warn => sub { my $self = shift; my $str = shift; my @params = @_; print $str . "\n" if ($log_level and grep { $_ eq lc($log_level); } qw(warn info debug)); }, error => sub { my $self = shift; my $str = shift; my @params = @_; print $str . "\n" if ($log_level and grep { $_ eq lc($log_level); } qw(error warn info debug)); }, ); }, config => sub { my $self = shift; return $config; }, user => sub { my $self = shift; return _create_mock('user', roles => sub { my $self = shift; return 'admin'; }, #webusername => sub { # my $self = shift; # return '$c->user->webusername'; #}, #domain => sub { # my $self = shift; # return _create_mock('_domain', # domain => sub { # my $self = shift; # return '$c->user->domain->domain'; # }, # ); #}, ); }, request => $req, req => $req, ); } sub _create_mock { my $class = shift; return $mock_objs{$class} if exists $mock_objs{$class}; my %members = @_; my $obj = bless({},$class); foreach my $member (keys %members) { if ('CODE' eq ref $members{$member}) { no strict "refs"; ## no critic (ProhibitNoStrict) *{$class.'::'.$member} = $members{$member}; } else { $obj->{substr($member,1)} = $members{$member}; } } $mock_objs{$class} = $obj; return $obj; } sub _get_schema { my $schema; if ($db{host}) { $schema = NGCP::Schema->connect({ dsn => "DBI:mysql:database=provisioning;host=$db{host};port=$db{port}", user => $db{user}, ( exists $db{password} ? (password => $db{password}) : ()), mysql_enable_utf8 => "1", on_connect_do => "SET NAMES utf8mb4", quote_char => "`", }); $schema->set_wait_timeout(3600); return $schema; } else { foreach my $provisioning_config (@provisioning_configs) { if (-f $provisioning_config) { my $conf = XML::Simple->new->XMLin($provisioning_config, ForceArray => 1); if ($conf && $conf->{ngcp_connect_info}) { my $connectors; if (exists $conf->{ngcp_connect_info}->[0]->{connectors}) { $connectors = $conf->{ngcp_connect_info}->[0]->{connectors}; } else { $connectors = $conf->{ngcp_connect_info}; } $connectors //= []; $schema = NGCP::Schema->connect($connectors->[0]); $schema->set_wait_timeout(3600); return $schema; } } } die("no provisioning.conf found\n") unless $schema; } } sub _get_panel_config { my $config; foreach my $panel_config (@panel_configs) { if( -f $panel_config ){ my $catalyst_config = Config::General->new($panel_config); my %config = $catalyst_config->getall(); $config = \%config; last; } } die("no ngcp_panel.conf found\n") unless $config; return $config; } __END__ =head1 NAME ngcp-provisioning-template - Create subscribers with detailed settings according to provisioning templates =head1 SYNOPSIS For templates defined in config.yml file: E<9>B "I" [I] For templates defined in database: E<9>B "IBI" [I] =head1 DESCRIPTION This program allows to run a 'provisioning template' from database or config.yml. This will produce a subscriber setup including required billing contact, contract, preferences, etc. from an input form defined by that template. The form fields can be passed as command line options. =head1 OPTIONS =over 4 =item B<--help> Print a brief help message and exits. =item B<--db-host=>I The host of the ngcp database to connect to. If omitted, the database connection settings of ngcp-panel will be used. =item B<--db-port=>I The port of the ngcp database to connect to. Only relevant if B<--db-host> is specified. =item B<--db-user=>I The database user for the ngcp database to connect to. Only relevant if B<--db-host> is specified. =item B<--db-password=>I The database user password (if any) for the ngcp database to connect to. Only relevant if B<--db-host> is specified. =item B<--file=>I Specify a .csv file to process. Each row represents form values for one subscriber to create. =item B<--[input-attribute-name]=>I<[attribute-value]> Provide an input attribute name and its value, as defined within the 'fields' tag in the provisioning template (Attribute must not be internal, i.e. 'calculated' type). Only relevant if no --file is specified. =item B<--purge> Terminate an existing subscriber with duplicate number/aliases first. =item B<--log-level> Verbosity of printed messages while processing (debug, info, warn, error). =back =head1 EXAMPLES ngcp-provisioning-template "My First Provisioning Template" --first-name="John" --last-name="Doe" --cc="43" --ac="316" --sn="123456" --purge ... runs "My First Provisioning Template" from config.yml using first_name "John", last_name "Doe" etc. ngcp-provisioning-template "Reseller1/Provisioning Template 1" --file="subscriberdata.csv" --purge ... runs "Provisioning Template 1" of "Reseller1" for each row in "subscriberdata.csv" =head1 AUTHOR Sipwise Development Team C<< >> =head1 LICENSE This software is Copyright © 2020 by 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 package. If not, see . =cut