1 package FS::part_export::broadband_snmp;
4 use vars qw(%info $DEBUG);
5 use base 'FS::part_export';
11 my $me = '['.__PACKAGE__.']';
13 tie my %snmp_version, 'Tie::IxHash',
19 #tie my %snmp_type, 'Tie::IxHash',
24 # o => OBJECT_IDENTIFIER,
27 # # others not implemented yet
30 tie my %options, 'Tie::IxHash',
31 'version' => { label=>'SNMP version',
33 options => [ keys %snmp_version ],
35 'community' => { label=>'Community', default=>'public' },
37 'action' => { multiple=>1 },
38 'oid' => { multiple=>1 },
39 'value' => { multiple=>1 },
40 'datatype'=> { multiple=>1 },
42 'ip_addr_change_to_new' => {
43 label=>'Send IP address changes to new address',
46 'timeout' => { label=>'Timeout (seconds)' },
50 'svc' => 'svc_broadband',
51 'desc' => 'Send SNMP requests to the service IP address',
52 'config_element' => '/edit/elements/part_export/broadband_snmp.html',
53 'options' => \%options,
57 Send one or more SNMP SET requests to the IP address registered to the service.
58 The value may interpolate fields from svc_broadband, cust_location, or
59 cust_main by prefixing the field name with <b>$</b>. For replace operations,
60 svc_broadband fields may be prefixed with <b>$new_</b> and <b>$old_</b>
61 (e.g. "$old_mac_addr").
67 $self->export_command('insert', @_);
72 $self->export_command('delete', @_);
77 $self->export_command('replace', @_);
82 $self->export_command('suspend', @_);
85 sub export_unsuspend {
87 $self->export_command('unsuspend', @_);
92 my ($action, $svc_new, $svc_old) = @_;
94 my @a = split("\n", $self->option('action'));
95 my @o = split("\n", $self->option('oid'));
96 my @v = split("\n", $self->option('value'));
98 warn "$me parsing $action commands:\n" if $DEBUG;
101 my $value = shift @v;
102 next unless shift(@a) eq $action; # ignore commands for other actions
103 $value = $self->substitute($value, $svc_new, $svc_old);
104 warn "$me $oid :=$value\n" if $DEBUG;
105 push @commands, $oid, $value;
108 my $ip_addr = $svc_new->ip_addr;
109 # ip address change: send to old address unless told otherwise
110 if ( defined $svc_old and ! $self->option('ip_addr_change_to_new') ) {
111 $ip_addr = $svc_old->ip_addr;
113 warn "$me opening session to $ip_addr\n" if $DEBUG;
116 DestHost => $ip_addr,
117 Community => $self->option('community'),
118 Timeout => ($self->option('timeout') || 20) * 1000,
120 my $version = $self->option('version');
121 $opt{Version} = $snmp_version{$version} or die 'invalid version';
122 $opt{VarList} = \@commands; # for now
124 $self->snmp_queue( $svc_new->svcnum, %opt );
130 my $queue = new FS::queue {
132 'job' => 'FS::part_export::broadband_snmp::snmp_request',
139 my $flatvarlist = delete $opt{VarList};
140 my $session = SNMP::Session->new(%opt);
142 warn "$me sending SET request\n" if $DEBUG;
145 while (@$flatvarlist) {
146 my @this = splice(@$flatvarlist, 0, 2);
147 push @varlist, [ $this[0], 0, $this[1], undef ];
148 # XXX new option to choose the IID (array index) of the object?
151 $session->set(\@varlist);
152 my $error = $session->{ErrorStr};
154 if ( $session->{ErrorNum} ) {
155 die "SNMP request failed: $error\n";
160 # double-quote-ish interpolation of service fields
161 # accepts old_ and new_ for replace actions, like shellcommands
163 my ($value, $svc_new, $svc_old) = @_;
165 my $location = $svc_new->cust_svc->cust_pkg->cust_location;
166 my $cust_main = $location->cust_main;
168 foreach my $field ( $svc_new->fields ) {
169 my $new_val = $svc_new->$field;
170 $value =~ s/\$(new_)?$field/$new_val/g;
171 if ( $svc_old ) { # replace only
172 my $old_val = $svc_old->$field;
173 $value =~ s/\$old_$field/$old_val/g;
177 # we don't yet have export_relocate hooks in here, so there's no old/new
178 # cust_location. do cust_location before cust_main, since cust_main has
179 # a bunch of empty fields with the same names.
181 foreach my $field ( $location->fields ) {
182 my $curr_val = $location->get($field);
183 $value =~ s/\$$field/$curr_val/g;
186 foreach my $field ( $cust_main->fields ) {
187 my $curr_val = $cust_main->get($field);
188 $value =~ s/\$$field/$curr_val/g;
194 sub _upgrade_exporttype {
195 eval 'use FS::Record qw(qsearch qsearchs)';
196 # change from old style with numeric oid, data type flag, and value
197 # on consecutive lines
198 foreach my $export (qsearch('part_export',
199 { exporttype => 'broadband_snmp' } ))
201 # for the new options
207 foreach my $action (qw(insert replace delete suspend unsuspend)) {
208 my $old_option = qsearchs('part_export_option',
209 { exportnum => $export->exportnum,
210 optionname => $action.'_command' } );
211 next if !$old_option;
212 my $text = $old_option->optionvalue;
213 my @commands = split("\n", $text);
214 foreach (@commands) {
215 my ($oid, $type, $value) = split /\s/, $_, 3;
216 push @{$new_options{action}}, $action;
217 push @{$new_options{oid}}, $oid;
218 push @{$new_options{value}}, $value;
220 my $error = $old_option->delete;
221 warn "error migrating ${action}_command option: $error\n" if $error;
223 foreach (keys(%new_options)) {
224 my $new_option = FS::part_export_option->new({
225 exportnum => $export->exportnum,
227 optionvalue => join("\n", @{ $new_options{$_} })
229 my $error = $new_option->insert;
230 warn "error inserting '$_' option: $error\n" if $error;