This commit was generated by cvs2svn to compensate for changes in r4407,
[freeside.git] / FS / FS / part_export / router.pm
1 package FS::part_export::router;
2
3 =head1 FS::part_export::router
4
5 This export connects to a router and transmits commands via telnet or SSH.
6 It requires the following custom router fields:
7
8 =over 4
9
10 =item admin_address - IP address (or hostname) to connect
11
12 =item admin_user - username for admin access
13
14 =item admin_password - password for admin access
15
16 =back
17
18 The export itself needs the following options:
19
20 =over 4
21
22 =item insert, replace, delete - command strings (to be interpolated)
23
24 =item Prompt - prompt string to expect from router after successful login
25
26 =item Timeout - time to wait for prompt string
27
28 =back
29
30 (Prompt and Timeout are required only for telnet connections.)
31
32 =cut
33
34 use vars qw(@ISA %info @saltset);
35 use Tie::IxHash;
36 use String::ShellQuote;
37 use FS::part_export;
38
39 @ISA = qw(FS::part_export);
40
41 tie my %options, 'Tie::IxHash',
42   'protocol' => {
43           label=>'Protocol',
44           type =>'select',
45           options => [qw(telnet ssh)],
46           default => 'telnet'},
47   'insert' => {label=>'Insert command', default=>'' },
48   'delete' => {label=>'Delete command', default=>'' },
49   'replace' => {label=>'Replace command', default=>'' },
50   'Timeout' => {label=>'Time to wait for prompt', default=>'20' },
51   'Prompt' => {label=>'Prompt string', default=>'#' }
52 ;
53
54 %info = (
55   'svc'     => 'svc_broadband',
56   'desc'    => 'Send a command to a router.',
57   'options' => \%options,
58   'notes'   => 'Installation of Net::Telnet from CPAN is required for telnet connections.  ( more detailed description from Kristian / fire2wire? )',
59 );
60
61 @saltset = ( 'a'..'z' , 'A'..'Z' , '0'..'9' , '.' , '/' );
62
63 sub rebless { shift; }
64
65 sub _export_insert {
66   my($self) = shift;
67   $self->_export_command('insert', @_);
68 }
69
70 sub _export_delete {
71   my($self) = shift;
72   $self->_export_command('delete', @_);
73 }
74
75 sub _export_suspend {
76   my($self) = shift;
77   $self->_export_command('suspend', @_);
78 }
79
80 sub _export_unsuspend {
81   my($self) = shift;
82   $self->_export_command('unsuspend', @_);
83 }
84
85 sub _export_command {
86   my ( $self, $action, $svc_broadband) = (shift, shift, shift);
87   my $command = $self->option($action);
88   return '' if $command =~ /^\s*$/;
89
90   no strict 'vars';
91   {
92     no strict 'refs';
93     ${$_} = $svc_broadband->getfield($_) foreach $svc_broadband->fields;
94   }
95   # fetch router info
96   my $router = $svc_broadband->addr_block->router;
97   my %r;
98   $r{$_} = $router->getfield($_) foreach $router->virtual_fields;
99   #warn qq("$command");
100   #warn eval(qq("$command"));
101
102   warn "admin_address: '$r{admin_address}'";
103
104   if ($r{admin_address} ne '') {
105     $self->router_queue( $svc_broadband->svcnum, $self->option('protocol'),
106       user         => $r{admin_user},
107       password     => $r{admin_password},
108       host         => $r{admin_address},
109       Timeout      => $self->option('Timeout'),
110       Prompt       => $self->option('Prompt'),
111       command      => eval(qq("$command")),
112     );
113   } else {
114     return '';
115   }
116 }
117
118 sub _export_replace {
119
120   # We don't handle the case of a svc_broadband moving between routers.
121   # If you want to do that, reprovision the service.
122
123   my($self, $new, $old ) = (shift, shift, shift);
124   my $command = $self->option('replace');
125   no strict 'vars';
126   {
127     no strict 'refs';
128     ${"old_$_"} = $old->getfield($_) foreach $old->fields;
129     ${"new_$_"} = $new->getfield($_) foreach $new->fields;
130   }
131
132   my $router = $new->addr_block->router;
133   my %r;
134   $r{$_} = $router->getfield($_) foreach $router->virtual_fields;
135
136   if ($r{admin_address} ne '') {
137     $self->router_queue( $new->svcnum, $self->option('protocol'),
138       user         => $r{admin_user},
139       password     => $r{admin_password},
140       host         => $r{admin_address},
141       Timeout      => $self->option('Timeout'),
142       Prompt       => $self->option('Prompt'),
143       command      => eval(qq("$command")),
144     );
145   } else {
146     return '';
147   }
148 }
149
150 #a good idea to queue anything that could fail or take any time
151 sub router_queue {
152   #warn join ':', @_;
153   my( $self, $svcnum, $protocol ) = (shift, shift, shift);
154   my $queue = new FS::queue {
155     'svcnum' => $svcnum,
156   };
157   $queue->job ("FS::part_export::router::".$protocol."_cmd");
158   $queue->insert( @_ );
159 }
160
161 sub ssh_cmd { #subroutine, not method
162   use Net::SSH '0.08';
163   &Net::SSH::ssh_cmd( { @_ } );
164 }
165
166 sub telnet_cmd {
167   eval 'use Net::Telnet;';
168   die $@ if $@;
169
170   warn join(', ', @_);
171
172   my %arg = @_;
173
174   my $t = new Net::Telnet (Timeout => $arg{Timeout},
175                            Prompt  => $arg{Prompt});
176   $t->open($arg{host});
177   $t->login($arg{user}, $arg{password});
178   my @error = $t->cmd($arg{command});
179   die @error if (grep /^ERROR/, @error);
180 }
181
182 #sub router_insert { #subroutine, not method
183 #}
184 #sub router_replace { #subroutine, not method
185 #}
186 #sub router_delete { #subroutine, not method
187 #}
188
189 1;
190