summaryrefslogtreecommitdiff
path: root/FS/FS/part_export/router.pm
diff options
context:
space:
mode:
Diffstat (limited to 'FS/FS/part_export/router.pm')
-rw-r--r--FS/FS/part_export/router.pm375
1 files changed, 0 insertions, 375 deletions
diff --git a/FS/FS/part_export/router.pm b/FS/FS/part_export/router.pm
deleted file mode 100644
index 42aa51c..0000000
--- a/FS/FS/part_export/router.pm
+++ /dev/null
@@ -1,375 +0,0 @@
-package FS::part_export::router;
-
-=head1 FS::part_export::router
-
-This export connects to a router and transmits commands via telnet or SSH.
-It requires the following custom router fields:
-
-=head1 Required custom fields
-
-=over 4
-
-=item admin_address - IP address (or hostname) to connect.
-
-=item admin_user - Username for the router.
-
-=item admin_password - Password for the router.
-
-=item admin_protocol - Protocol to use for the router. 'telnet' or 'ssh'. The ssh protocol only support password-less (ie. RSA key) authentication. As such, the admin_password field isn't used if ssh is specified.
-
-=item admin_timeout - Time in seconds to wait for a connection.
-
-=item admin_prompt - A regular expression matching the router's prompt. See Net::Telnet for details. Only applies to the 'telnet' protocol.
-
-=item admin_cmd_insert - Insert export command.
-
-=item admin_cmd_insert_error - Insert export command error pattern.
-
-=item admin_cmd_delete - Delete export command.
-
-=item admin_cmd_delete_error - Delete export command error pattern.
-
-=item admin_cmd_replace - Replace export command.
-
-=item admin_cmd_replace_error - Replace export command error pattern.
-
-=item admin_cmd_suspend - Suspend export command.
-
-=item admin_cmd_suspend_error - Support export command error pattern.
-
-=item admin_cmd_unsuspend - Unsuspend export command.
-
-=item admin_cmd_unsuspend_error - Unsuspend export command error pattern.
-
-The admin_cmd_* virtual fields, if set, will be processed in one of two ways. After being expanded, they will be run on the router specified by admin_address using the protocol specified by admin_protocol.
-
-=over 4
-
-=item Text::Template
-
-If the export command contains the string [@--, then it will be processed with Text::Template using [@-- and --@] as delimeters.
-
-=item eval
-
-If the export command does not contain [@--, it will be double quoted and eval'd.
-
-=back
-
-The admin_cmd_*_error virtual fields, if set, define a regular expression that will be matched against the output of the command being run. If the pattern matches, an error will be raised using the output as the error.
-
-If any of the required router virtual fields are not defined, then the export silently declines.
-
-=back
-
-The export itself takes no options.
-
-=cut
-
-use strict;
-use vars qw(@ISA %info $me $DEBUG);
-use Tie::IxHash;
-use Text::Template;
-
-use FS::Record qw(qsearchs);
-use FS::part_export;
-
-@ISA = qw(FS::part_export);
-
-tie my %options, 'Tie::IxHash',
- 'protocol' => {
- label=>'Protocol',
- type =>'select',
- options => [qw(telnet ssh)],
- default => 'telnet'},
-;
-
-%info = (
- 'svc' => 'svc_broadband',
- 'desc' => 'Send a command to a router.',
- 'options' => \%options,
- 'notes' => 'Installation of Net::Telnet from CPAN is required for telnet connections. This export will execute if the following virtual fields are set on the router: admin_user, admin_password, admin_address, admin_timeout, admin_prompt. Option virtual fields are: admin_cmd_insert, admin_cmd_replace, admin_cmd_delete, admin_cmd_suspend, admin_cmd_unsuspend. See the module documentation for a full list of required/supported router virtual fields.',
-);
-
-$me = '[' . __PACKAGE__ . ']';
-$DEBUG = 1;
-
-
-sub rebless { shift; }
-
-sub _field_prefix { 'admin'; }
-
-sub _req_router_fields {
- map {
- $_[0]->_field_prefix . '_' . $_
- } (qw(address prompt user));
-}
-
-sub _export_insert {
- my($self) = shift;
- warn "Running insert for " . ref($self);
- $self->_export_command('insert', @_);
-}
-
-sub _export_delete {
- my($self) = shift;
- $self->_export_command('delete', @_);
-}
-
-sub _export_suspend {
- my($self) = shift;
- $self->_export_command('suspend', @_);
-}
-
-sub _export_unsuspend {
- my($self) = shift;
- $self->_export_command('unsuspend', @_);
-}
-
-sub _export_replace {
- my($self) = shift;
- $self->_export_command('replace', @_);
-}
-
-sub _export_command {
- my ($self, $action, $svc_broadband) = (shift, shift, shift);
- my ($error, $old);
-
- if ($action eq 'replace') {
- $old = shift;
- }
-
- warn "[debug]$me Processing action '$action'" if $DEBUG;
-
- # fetch router info
- my $router = $self->_get_router($svc_broadband, @_);
- unless ($router) {
- return "Unable to lookup router for $action export";
- }
-
- unless ($self->_check_router_fields($router)) {
- # Virtual fields aren't defined. Exit silently.
- warn "[debug]$me Required router virtual fields not defined. Returning..."
- if $DEBUG;
- return '';
- }
-
- my $args;
- ($error, $args) = $self->_prepare_args(
- $action,
- $router,
- $svc_broadband,
- ($old ? $old : ()),
- @_
- );
-
- if ($error) {
- # Error occured while preparing args.
- return $error;
- } elsif (not defined $args) {
- # Silently decline.
- warn "[debug]$me Declining '$action' export" if $DEBUG;
- return '';
- } # else ... queue the export.
-
- warn "[debug]$me Queueing with args: " . join(', ', @$args) if $DEBUG;
-
- return(
- $self->_queue(
- $svc_broadband->svcnum,
- $self->_get_cmd_sub($svc_broadband, $router),
- @$args
- )
- );
-
-}
-
-sub _prepare_args {
-
- my ($self, $action, $router, $svc_broadband) = (shift, shift, shift, shift);
- my $old = shift if ($action eq 'replace');
- my $error = '';
-
- my $field_prefix = $self->_field_prefix;
- my $command = $router->getfield("${field_prefix}_cmd_${action}");
- unless ($command) {
- warn "[debug]$me router custom field '${field_prefix}_cmd_$action' "
- . "is not defined." if $DEBUG;
- return '';
- }
-
- if ($command =~ /\[\@--/) { # Use Text::Template
-
- my $template_data = {};
-
- if ($action eq 'replace') {
- $template_data->{"old_$_"} = $old->getfield($_) foreach $old->fields;
- $template_data->{"new_$_"} = $svc_broadband->getfield($_)
- foreach $svc_broadband->fields;
- } else {
- $template_data->{$_} = $svc_broadband->getfield($_)
- foreach $svc_broadband->fields;
- }
-
- my $template = new Text::Template (
- TYPE => 'STRING',
- SOURCE => $command,
- DELIMITERS => [ '[@--', '--@]' ],
- ) or return "Unable to construct template for router command: "
- . $Text::Template::ERROR;
-
- $command = $template->fill_in(
- HASH => $template_data,
- BROKEN_ARG => \$error,
- BROKEN => sub {
- my %bargs = @_;
- my $err = $bargs{'arg'};
- $$err = $bargs{'error'};
- return undef;
- },
- );
-
- if (not defined $command or $error) {
- $error ||= $Text::Template::ERROR;
- return "Unable to fill-in template for router command: $error";
- }
-
- } else { # Use eval
- no strict 'vars';
- no strict 'refs';
-
- if ($action eq 'replace') {
- ${"old_$_"} = $old->getfield($_) foreach $old->fields;
- ${"new_$_"} = $svc_broadband->getfield($_) foreach $svc_broadband->fields;
- $command = eval(qq("$command"));
- } else {
- ${$_} = $svc_broadband->getfield($_) foreach $svc_broadband->fields;
- $command = eval(qq("$command"));
- }
- return $@ if $@;
- }
-
- my $args = [
- 'user' => $router->getfield($field_prefix . '_user'),
- 'password' => $router->getfield($field_prefix . '_password'),
- 'host' => $router->getfield($field_prefix . '_address'),
- 'Timeout' => $router->getfield($field_prefix . '_timeout'),
- 'Prompt' => $router->getfield($field_prefix . '_prompt'),
- 'command' => $command,
- ];
-
- my $error_check = $router->getfield("${field_prefix}_cmd_${action}_error");
- push(@$args, ('error_check' => $error_check)) if ($error_check);
-
- return('', $args);
-
-}
-
-sub _get_cmd_sub {
-
- my ($self, $svc_broadband, $router) = (shift, shift, shift);
-
- my $protocol = (
- $router->getfield($self->_field_prefix . '_protocol') =~ /^(telnet|ssh)$/
- ) ? $1 : 'telnet';
-
- return(ref($self)."::".$protocol."_cmd");
-
-}
-
-sub _check_router_fields {
-
- my ($self, $router, $action) = (shift, shift, shift);
- my @check_fields = $self->_req_router_fields;
-
- foreach (@check_fields) {
- if ($router->getfield($_) eq '') {
- warn "[debug]$me Required field '$_' is unset" if $DEBUG;
- return 0;
- } else {
- return 1;
- }
- }
-
-}
-
-sub _queue {
- my( $self, $svcnum, $cmd_sub ) = (shift, shift, shift);
- my $queue = new FS::queue {
- 'svcnum' => $svcnum,
- };
- $queue->job($cmd_sub);
- $queue->insert(@_);
-}
-
-sub _get_router {
- my ($self, $svc_broadband, %args) = (shift, shift, shift, @_);
-
- my $router;
- if ($args{'routernum'}) {
- $router = qsearchs('router', { routernum => $args{'routernum'}});
- } else {
- $router = $svc_broadband->addr_block->router;
- }
-
- return($router);
-
-}
-
-
-# Subroutines
-sub ssh_cmd {
- my %arg = @_;
-
- eval 'use Net::SSH \'0.08\'';
- die $@ if $@;
-
- my @out = &Net::SSH::ssh_cmd( { @_ } );
- my $error = &_cmd_error_check(\%arg, \@out);
-
- die ("Error while processing ssh command: $error") if $error;
-
- return '';
-
-}
-
-sub telnet_cmd {
- my %arg = @_;
-
- eval 'use Net::Telnet';
- die $@ if $@;
-
- my $t = new Net::Telnet (Timeout => $arg{'Timeout'},
- Prompt => $arg{'Prompt'});
- $t->open($arg{'host'});
- $t->login($arg{'user'}, $arg{'password'});
- my @out = $t->cmd($arg{'command'});
- my $error = &_cmd_error_check(\%arg, \@out);
-
- die ("Error while processing telnet command: $error") if $error;
-
- return '';
-
-}
-
-sub _cmd_error_check {
- my ($arg, $out) = (shift, shift);
-
- die "_cmd_error_check called without proper arguments"
- unless (ref($arg) eq 'HASH' and ref($out) eq 'ARRAY');
-
- unless (exists($arg->{'error_check'}) and $arg->{'error_check'} ne '') {
- #Preserve default behaviour and return output if a check isn't defined.
- warn "Output from router command: " . join('', @$out) if $DEBUG;
- return '';
- }
-
- my $error_check = $arg->{'error_check'};
- foreach (@$out) {
- return $_ if /$error_check/;
- }
-
- return '';
-
-}
-
-1;