1 package FS::part_export::broadband_snmp;
4 use vars qw(%info $DEBUG);
5 use base 'FS::part_export';
6 use Net::SNMP qw(:asn1 :snmp);
11 my $me = '['.__PACKAGE__.']';
13 tie my %snmp_version, 'Tie::IxHash',
16 # 3 => 'v3' not implemented
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' },
38 { label => ucfirst($_) . ' commands',
42 } qw( insert delete replace suspend unsuspend )
44 'ip_addr_change_to_new' => {
45 label=>'Send IP address changes to new address',
48 'timeout' => { label=>'Timeout (seconds)' },
52 'svc' => 'svc_broadband',
53 'desc' => 'Send SNMP requests to the service IP address',
54 'options' => \%options,
58 Send one or more SNMP SET requests to the IP address registered to the service.
59 Enter one command per line. Each command is a target OID, data type flag,
60 and value, separated by spaces.
61 The data type flag is one of the following:
63 <li><i>i</i> = INTEGER</li>
64 <li><i>u</i> = UNSIGNED32</li>
65 <li><i>s</i> = OCTET-STRING (as ASCII)</li>
66 <li><i>a</i> = IPADDRESS</li>
67 <li><i>n</i> = NULL</li></ul>
68 The value may interpolate fields from svc_broadband by prefixing the field
69 name with <b>$</b>, or <b>$new_</b> and <b>$old_</b> for replace operations.
70 The value may contain whitespace; quotes are not necessary.<br>
72 For example, to set the SNMPv2-MIB "sysName.0" object to the string
73 "svc_broadband" followed by the service number, use the following
75 <pre>1.3.6.1.2.1.1.5.0 s svc_broadband$svcnum</pre><br>
81 $self->export_command('insert', @_);
86 $self->export_command('delete', @_);
91 $self->export_command('replace', @_);
96 $self->export_command('suspend', @_);
99 sub export_unsuspend {
101 $self->export_command('unsuspend', @_);
106 my ($action, $svc_new, $svc_old) = @_;
108 my $command_text = $self->option($action.'_command');
109 return if !length($command_text);
111 warn "$me parsing ${action}_command:\n" if $DEBUG;
113 foreach (split /\n/, $command_text) {
114 my ($oid, $type, $value) = split /\s/, $_, 3;
115 $oid =~ /^(\d+\.)*\d+$/ or die "invalid OID '$oid'\n";
116 my $typenum = $snmp_type{$type} or die "unknown data type '$type'\n";
117 $value = '' if !defined($value); # allow sending an empty string
118 $value = $self->substitute($value, $svc_new, $svc_old);
119 warn "$me $oid $type $value\n" if $DEBUG;
120 push @commands, $oid, $typenum, $value;
123 my $ip_addr = $svc_new->ip_addr;
124 # ip address change: send to old address unless told otherwise
125 if ( defined $svc_old and ! $self->option('ip_addr_change_to_new') ) {
126 $ip_addr = $svc_old->ip_addr;
128 warn "$me opening session to $ip_addr\n" if $DEBUG;
131 -hostname => $ip_addr,
132 -community => $self->option('community'),
133 -timeout => $self->option('timeout') || 20,
135 my $version = $self->option('version');
136 $opt{-version} = $snmp_version{$version} or die 'invalid version';
137 $opt{-varbindlist} = \@commands; # just for now
139 $self->snmp_queue( $svc_new->svcnum, %opt );
145 my $queue = new FS::queue {
147 'job' => 'FS::part_export::broadband_snmp::snmp_request',
154 my $varbindlist = delete $opt{-varbindlist};
155 my ($session, $error) = Net::SNMP->session(%opt);
156 die "Couldn't create SNMP session: $error" if !$session;
158 warn "$me sending SET request\n" if $DEBUG;
159 my $result = $session->set_request( -varbindlist => $varbindlist );
160 $error = $session->error();
163 if (!defined $result) {
164 die "SNMP request failed: $error\n";
169 # double-quote-ish interpolation of service fields
170 # accepts old_ and new_ for replace actions, like shellcommands
172 my ($value, $svc_new, $svc_old) = @_;
173 foreach my $field ( $svc_new->fields ) {
174 my $new_val = $svc_new->$field;
175 $value =~ s/\$(new_)?$field/$new_val/g;
176 if ( $svc_old ) { # replace only
177 my $old_val = $svc_old->$field;
178 $value =~ s/\$old_$field/$old_val/g;