line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Net::Autoconfig; |
2
|
|
|
|
|
|
|
|
3
|
6
|
|
|
6
|
|
93610
|
use 5.008008; |
|
6
|
|
|
|
|
20
|
|
|
6
|
|
|
|
|
249
|
|
4
|
6
|
|
|
6
|
|
49
|
use strict; |
|
6
|
|
|
|
|
11
|
|
|
6
|
|
|
|
|
256
|
|
5
|
6
|
|
|
6
|
|
28
|
use warnings; |
|
6
|
|
|
|
|
10
|
|
|
6
|
|
|
|
|
214
|
|
6
|
|
|
|
|
|
|
|
7
|
6
|
|
|
6
|
|
13477
|
use Log::Log4perl qw(:levels :easy); |
|
6
|
|
|
|
|
581942
|
|
|
6
|
|
|
|
|
49
|
|
8
|
6
|
|
|
6
|
|
6531
|
use Net::Autoconfig::Device; |
|
6
|
|
|
|
|
18
|
|
|
6
|
|
|
|
|
188
|
|
9
|
6
|
|
|
6
|
|
7907
|
use Net::Autoconfig::Template; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
25
|
|
10
|
1
|
|
|
1
|
|
7
|
use Data::Dumper; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
90
|
|
11
|
1
|
|
|
1
|
|
7
|
use POSIX ":sys_wait_h"; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
11
|
|
12
|
1
|
|
|
1
|
|
237
|
use Cwd; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
69
|
|
13
|
1
|
|
|
1
|
|
5
|
use version; our $VERSION = version->new("v1.13.2"); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
6
|
|
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
################################################################################ |
16
|
|
|
|
|
|
|
# Constants and Global Variables |
17
|
|
|
|
|
|
|
################################################################################ |
18
|
|
|
|
|
|
|
|
19
|
1
|
|
|
1
|
|
126
|
use constant TRUE => 1; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
79
|
|
20
|
1
|
|
|
1
|
|
5
|
use constant FALSE => 0; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
42
|
|
21
|
|
|
|
|
|
|
|
22
|
1
|
|
|
1
|
|
7
|
use constant MAXIMUM_MAX_CHILDREN => 256; # Absolute Maximum # of child processes (if using bulk mode) |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
45
|
|
23
|
1
|
|
|
1
|
|
5
|
use constant DEFAULT_MAX_CHILDREN => 64; # Default max # of child processes (if using bulk mode) |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
46
|
|
24
|
1
|
|
|
1
|
|
5
|
use constant MINIMUM_MAX_CHILDREN => 1; # Absolute Minimum # of child processes (if using bulk mode) |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
40
|
|
25
|
|
|
|
|
|
|
|
26
|
1
|
|
|
1
|
|
6
|
use constant DEFAULT_DIR => '/usr/local/etc/autoconfig'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
62
|
|
27
|
1
|
|
|
1
|
|
5
|
use constant DEFAULT_LOGFILE => DEFAULT_DIR . '/logging.conf'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
43
|
|
28
|
|
|
|
|
|
|
|
29
|
1
|
|
|
1
|
|
6
|
use constant MAXIMUM_LOG_LEVEL => 5; # Absolute Maximum log level |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
54
|
|
30
|
1
|
|
|
1
|
|
5
|
use constant DEFAULT_LOG_LEVEL => 3; # Set the default log level to info |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
50
|
|
31
|
1
|
|
|
1
|
|
6
|
use constant MINIMUM_LOG_LEVEL => 0; # Absolute Minimum log level |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
64
|
|
32
|
|
|
|
|
|
|
|
33
|
1
|
|
|
1
|
|
12
|
use constant DEFAULT_BULK_MODE => TRUE; # Enable parallel processing by default |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
256
|
|
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
#################### |
36
|
|
|
|
|
|
|
# Friendly User Prompt Messages |
37
|
|
|
|
|
|
|
#################### |
38
|
1
|
|
|
|
|
4145
|
use constant USER_PROMPTS => { |
39
|
|
|
|
|
|
|
'password' => "Device Access Password", |
40
|
|
|
|
|
|
|
'enable_password' => "Device Admin Password", |
41
|
|
|
|
|
|
|
'console_password' => "Console Server Access Password", |
42
|
1
|
|
|
1
|
|
13
|
}; |
|
1
|
|
|
|
|
2
|
|
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
# A hash ref to store child processes. |
46
|
|
|
|
|
|
|
# Contains active processes, and return values |
47
|
|
|
|
|
|
|
our $CHILD_PROCESSES = {}; |
48
|
|
|
|
|
|
|
$CHILD_PROCESSES->{'active'} = {}; |
49
|
|
|
|
|
|
|
$CHILD_PROCESSES->{'finished'} = {}; |
50
|
|
|
|
|
|
|
$CHILD_PROCESSES->{'info'} = {}; |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
# Zombies are dead child processes that need to |
53
|
|
|
|
|
|
|
# be reaped. |
54
|
|
|
|
|
|
|
our $ZOMBIES; |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
# Setup signal handling for reaping our own zombies. |
57
|
|
|
|
|
|
|
# Zombie handling is done by _reaper, which is in the |
58
|
|
|
|
|
|
|
# private methods section. |
59
|
|
|
|
|
|
|
$SIG{'CHLD'} = sub { $ZOMBIES++ }; |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
################################################################################ |
62
|
|
|
|
|
|
|
# Methods |
63
|
|
|
|
|
|
|
################################################################################ |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
############################################################ |
66
|
|
|
|
|
|
|
# Public Methods |
67
|
|
|
|
|
|
|
############################################################ |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
######################################## |
70
|
|
|
|
|
|
|
# new |
71
|
|
|
|
|
|
|
# public method |
72
|
|
|
|
|
|
|
# |
73
|
|
|
|
|
|
|
# Create a new Net::Autoconfig object. |
74
|
|
|
|
|
|
|
# |
75
|
|
|
|
|
|
|
# Log levels (not implemented yet): |
76
|
|
|
|
|
|
|
# 0 = Fatal => Least verbose |
77
|
|
|
|
|
|
|
# 1 = Error |
78
|
|
|
|
|
|
|
# 2 = Warn |
79
|
|
|
|
|
|
|
# 3 = Info |
80
|
|
|
|
|
|
|
# 4 = Debug |
81
|
|
|
|
|
|
|
# 5 = Trace => Most verbose |
82
|
|
|
|
|
|
|
# |
83
|
|
|
|
|
|
|
######################################## |
84
|
|
|
|
|
|
|
sub new { |
85
|
0
|
|
|
0
|
1
|
|
my $invocant = shift; # calling class |
86
|
0
|
|
0
|
|
|
|
my $class = ref($invocant) || $invocant; |
87
|
0
|
|
|
|
|
|
my $log = Log::Log4perl->get_logger($class); |
88
|
0
|
|
|
|
|
|
my %user_data = @_; |
89
|
|
|
|
|
|
|
|
90
|
0
|
|
|
|
|
|
my $self = { |
91
|
|
|
|
|
|
|
bulk_mode => DEFAULT_BULK_MODE, |
92
|
|
|
|
|
|
|
log_level => DEFAULT_LOG_LEVEL, |
93
|
|
|
|
|
|
|
max_children => DEFAULT_MAX_CHILDREN, |
94
|
|
|
|
|
|
|
logfile => DEFAULT_LOGFILE, |
95
|
|
|
|
|
|
|
}; |
96
|
|
|
|
|
|
|
|
97
|
0
|
|
|
|
|
|
$self = bless $self, $class; |
98
|
|
|
|
|
|
|
|
99
|
0
|
|
|
|
|
|
$self->logfile( $user_data{'logfile'} ); |
100
|
0
|
|
|
|
|
|
$self->init_logging(); |
101
|
|
|
|
|
|
|
|
102
|
0
|
|
|
|
|
|
$self->bulk_mode( $user_data{'bulk_mode'} ); |
103
|
0
|
|
|
|
|
|
$self->log_level( $user_data{'log_level'} ); |
104
|
0
|
|
|
|
|
|
$self->max_children( $user_data{'max_children'} ); |
105
|
|
|
|
|
|
|
|
106
|
0
|
|
|
|
|
|
$log->info("########################################"); |
107
|
0
|
|
|
|
|
|
$log->info("# Net::Autoconfig Started #"); |
108
|
0
|
|
|
|
|
|
$log->info("########################################"); |
109
|
0
|
|
|
|
|
|
return $self; |
110
|
|
|
|
|
|
|
} |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
######################################## |
113
|
|
|
|
|
|
|
# init_logging |
114
|
|
|
|
|
|
|
# public method |
115
|
|
|
|
|
|
|
# |
116
|
|
|
|
|
|
|
# Initialize logging for Net::Autoconfig. |
117
|
|
|
|
|
|
|
# If multiple Net::Autoconfig objects |
118
|
|
|
|
|
|
|
# are created, calling this will affect |
119
|
|
|
|
|
|
|
# all of them; it changes their logging |
120
|
|
|
|
|
|
|
# definitions. |
121
|
|
|
|
|
|
|
# |
122
|
|
|
|
|
|
|
# Returns undef |
123
|
|
|
|
|
|
|
######################################## |
124
|
|
|
|
|
|
|
sub init_logging { |
125
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
# XXX - Setup a saner, \$log_string |
128
|
|
|
|
|
|
|
# config so it's not just to stdout/stderr |
129
|
|
|
|
|
|
|
|
130
|
0
|
0
|
|
|
|
|
if ( -e $self->logfile ) |
131
|
|
|
|
|
|
|
{ |
132
|
0
|
|
|
|
|
|
eval { |
133
|
0
|
|
|
|
|
|
Log::Log4perl::init( $self->logfile ); |
134
|
|
|
|
|
|
|
}; |
135
|
0
|
0
|
|
|
|
|
if ($@) { |
136
|
0
|
|
|
|
|
|
print STDERR "Failed to initialize '" . $self->logfile |
137
|
|
|
|
|
|
|
. "' even though it exists.\n"; |
138
|
0
|
|
|
|
|
|
print STDERR "Logging to STDERR."; |
139
|
0
|
|
|
|
|
|
Log::Log4perl->easy_init($WARN); |
140
|
|
|
|
|
|
|
} |
141
|
|
|
|
|
|
|
} |
142
|
|
|
|
|
|
|
else |
143
|
|
|
|
|
|
|
{ |
144
|
0
|
|
|
|
|
|
print STDERR "logging.conf does not exist!"; |
145
|
0
|
|
|
|
|
|
print STDERR "Logging to STDERR."; |
146
|
0
|
|
|
|
|
|
Log::Log4perl->easy_init($INFO); |
147
|
|
|
|
|
|
|
} |
148
|
0
|
|
|
|
|
|
return; |
149
|
|
|
|
|
|
|
} |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
######################################## |
152
|
|
|
|
|
|
|
# bulk_mode |
153
|
|
|
|
|
|
|
# public method |
154
|
|
|
|
|
|
|
# |
155
|
|
|
|
|
|
|
# Accessor/Mutator method |
156
|
|
|
|
|
|
|
# If passed a parameter, set the |
157
|
|
|
|
|
|
|
# bulk_mode value to TRUE or FAlSE |
158
|
|
|
|
|
|
|
# |
159
|
|
|
|
|
|
|
# If passed undef, return the |
160
|
|
|
|
|
|
|
# bulk_mode value (TRUE or FALSE); |
161
|
|
|
|
|
|
|
######################################## |
162
|
|
|
|
|
|
|
sub bulk_mode { |
163
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
164
|
0
|
|
|
|
|
|
my $mode = shift; |
165
|
0
|
|
|
|
|
|
my $log = Log::Log4perl->get_logger( ref($self) ); |
166
|
|
|
|
|
|
|
|
167
|
0
|
0
|
|
|
|
|
if (defined $mode) |
168
|
|
|
|
|
|
|
{ |
169
|
0
|
0
|
|
|
|
|
$log->debug("Setting bulk_mode to " . ($mode ? TRUE : FALSE)); |
170
|
0
|
0
|
|
|
|
|
$self->{'bulk_mode'} = $mode ? TRUE : FALSE; |
171
|
|
|
|
|
|
|
} |
172
|
0
|
0
|
|
|
|
|
return defined $mode ? undef : $self->{'bulk_mode'}; |
173
|
|
|
|
|
|
|
} |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
######################################## |
176
|
|
|
|
|
|
|
# log_level |
177
|
|
|
|
|
|
|
# public method |
178
|
|
|
|
|
|
|
# |
179
|
|
|
|
|
|
|
# Accessor/Mutator method |
180
|
|
|
|
|
|
|
# If passed a parameter, set the |
181
|
|
|
|
|
|
|
# log_level to the passed value (or within 0-5) |
182
|
|
|
|
|
|
|
# |
183
|
|
|
|
|
|
|
# If passed undef, return the |
184
|
|
|
|
|
|
|
# log_level value. |
185
|
|
|
|
|
|
|
######################################## |
186
|
|
|
|
|
|
|
sub log_level { |
187
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
188
|
0
|
|
|
|
|
|
my $level = shift; |
189
|
0
|
|
|
|
|
|
my $log = Log::Log4perl->get_logger( ref($self) ); |
190
|
|
|
|
|
|
|
|
191
|
0
|
0
|
|
|
|
|
if (defined $level) |
192
|
|
|
|
|
|
|
{ |
193
|
0
|
|
|
|
|
|
$level = int($level); |
194
|
0
|
0
|
|
|
|
|
if ($level > MAXIMUM_LOG_LEVEL) |
|
|
0
|
|
|
|
|
|
195
|
|
|
|
|
|
|
{ |
196
|
0
|
|
|
|
|
|
$level = MAXIMUM_LOG_LEVEL; |
197
|
0
|
|
|
|
|
|
$log->warn("Log level set too high. Setting to " . MAXIMUM_LOG_LEVEL); |
198
|
|
|
|
|
|
|
} |
199
|
|
|
|
|
|
|
elsif ($level < MINIMUM_LOG_LEVEL) |
200
|
|
|
|
|
|
|
{ |
201
|
0
|
|
|
|
|
|
$level = MINIMUM_LOG_LEVEL; |
202
|
0
|
|
|
|
|
|
$log->warn("Log level set too low. Setting to " . MINIMUM_LOG_LEVEL); |
203
|
|
|
|
|
|
|
} |
204
|
0
|
|
|
|
|
|
$log->debug("Setting log_level to $level"); |
205
|
0
|
|
|
|
|
|
$self->{'log_level'} = $level; |
206
|
|
|
|
|
|
|
} |
207
|
0
|
0
|
|
|
|
|
return defined $level ? undef : $self->{'log_level'}; |
208
|
|
|
|
|
|
|
} |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
######################################## |
211
|
|
|
|
|
|
|
# max_children |
212
|
|
|
|
|
|
|
# public method |
213
|
|
|
|
|
|
|
# |
214
|
|
|
|
|
|
|
# Accessor/Mutator method |
215
|
|
|
|
|
|
|
# If passed a parameter, set the |
216
|
|
|
|
|
|
|
# maximum number of child processes. |
217
|
|
|
|
|
|
|
# Only used when "bulk_mode" is enabled. |
218
|
|
|
|
|
|
|
# |
219
|
|
|
|
|
|
|
# If passed undef, return the |
220
|
|
|
|
|
|
|
# max number of children. |
221
|
|
|
|
|
|
|
######################################## |
222
|
|
|
|
|
|
|
sub max_children { |
223
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
224
|
0
|
|
|
|
|
|
my $max_children = shift; |
225
|
0
|
|
|
|
|
|
my $log = Log::Log4perl->get_logger( ref($self) ); |
226
|
|
|
|
|
|
|
|
227
|
0
|
0
|
|
|
|
|
if (defined $max_children) |
228
|
|
|
|
|
|
|
{ |
229
|
0
|
0
|
|
|
|
|
if ($max_children > MAXIMUM_MAX_CHILDREN) |
|
|
0
|
|
|
|
|
|
230
|
|
|
|
|
|
|
{ |
231
|
0
|
|
|
|
|
|
$max_children = MAXIMUM_MAX_CHILDREN; |
232
|
0
|
|
|
|
|
|
$log->warn("Log max_children set too high. Setting to '256'."); |
233
|
|
|
|
|
|
|
} |
234
|
|
|
|
|
|
|
elsif ($max_children < MINIMUM_MAX_CHILDREN) |
235
|
|
|
|
|
|
|
{ |
236
|
0
|
|
|
|
|
|
$max_children = MINIMUM_MAX_CHILDREN; |
237
|
0
|
|
|
|
|
|
$log->warn("Log max_children set too low. Setting to '1'."); |
238
|
|
|
|
|
|
|
} |
239
|
0
|
|
|
|
|
|
$log->debug("Setting max_children to $max_children"); |
240
|
0
|
|
|
|
|
|
$self->{'max_children'} = $max_children; |
241
|
|
|
|
|
|
|
} |
242
|
0
|
0
|
|
|
|
|
return defined $max_children ? undef : $self->{'max_children'}; |
243
|
|
|
|
|
|
|
} |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
######################################## |
246
|
|
|
|
|
|
|
# get_report |
247
|
|
|
|
|
|
|
# public method |
248
|
|
|
|
|
|
|
# |
249
|
|
|
|
|
|
|
# Return info about the finished processes. |
250
|
|
|
|
|
|
|
# Returns a hash ref with: |
251
|
|
|
|
|
|
|
# 'succeded'=> { list of hostnames } |
252
|
|
|
|
|
|
|
# 'failed' => {list of hostnames } |
253
|
|
|
|
|
|
|
######################################## |
254
|
|
|
|
|
|
|
sub get_report { |
255
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
256
|
0
|
|
|
|
|
|
my $report = {}; |
257
|
0
|
|
|
|
|
|
my @succeded; # devices that exited successfully |
258
|
|
|
|
|
|
|
my @failed; # devices that exited unsuccessfully |
259
|
|
|
|
|
|
|
|
260
|
0
|
|
|
|
|
|
foreach my $device_pid (keys %{ $CHILD_PROCESSES->{'info'} }) |
|
0
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
{ |
262
|
0
|
0
|
|
|
|
|
if ($CHILD_PROCESSES->{'finished'}->{$device_pid}) |
263
|
|
|
|
|
|
|
{ |
264
|
|
|
|
|
|
|
# it failed |
265
|
0
|
|
|
|
|
|
push(@failed, $CHILD_PROCESSES->{'info'}->{$device_pid}); |
266
|
|
|
|
|
|
|
} |
267
|
|
|
|
|
|
|
else |
268
|
|
|
|
|
|
|
{ |
269
|
|
|
|
|
|
|
# it succeded |
270
|
0
|
|
|
|
|
|
push(@succeded, $CHILD_PROCESSES->{'info'}->{$device_pid}); |
271
|
|
|
|
|
|
|
} |
272
|
|
|
|
|
|
|
} |
273
|
0
|
|
|
|
|
|
$report->{'succeded'} = \@succeded; |
274
|
0
|
|
|
|
|
|
$report->{'failed'} = \@failed; |
275
|
0
|
0
|
|
|
|
|
return wantarray ? %$report : $report; |
276
|
|
|
|
|
|
|
} |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
######################################## |
279
|
|
|
|
|
|
|
# logfile |
280
|
|
|
|
|
|
|
# public method |
281
|
|
|
|
|
|
|
# |
282
|
|
|
|
|
|
|
# Accessor/Mutator |
283
|
|
|
|
|
|
|
# |
284
|
|
|
|
|
|
|
#################### |
285
|
|
|
|
|
|
|
# Mutator |
286
|
|
|
|
|
|
|
# |
287
|
|
|
|
|
|
|
# Sets the logfile if it exists |
288
|
|
|
|
|
|
|
# (assumes current working directory if |
289
|
|
|
|
|
|
|
# the filename is not specified absolutely.) |
290
|
|
|
|
|
|
|
# |
291
|
|
|
|
|
|
|
# Else, it sets the logfile to the default. |
292
|
|
|
|
|
|
|
# |
293
|
|
|
|
|
|
|
# Returns: |
294
|
|
|
|
|
|
|
# Success => undef |
295
|
|
|
|
|
|
|
# Failure => error message |
296
|
|
|
|
|
|
|
#################### |
297
|
|
|
|
|
|
|
# Accessor |
298
|
|
|
|
|
|
|
# |
299
|
|
|
|
|
|
|
# Returns |
300
|
|
|
|
|
|
|
# the logfile's absolute path |
301
|
|
|
|
|
|
|
######################################## |
302
|
|
|
|
|
|
|
sub logfile { |
303
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
304
|
0
|
|
|
|
|
|
my $logfile = shift; |
305
|
0
|
|
|
|
|
|
my $return_value; |
306
|
|
|
|
|
|
|
|
307
|
0
|
0
|
|
|
|
|
if ( defined $logfile ) |
308
|
|
|
|
|
|
|
{ |
309
|
|
|
|
|
|
|
# Check for abs path |
310
|
0
|
0
|
|
|
|
|
if ( $logfile !~ /^\// ) |
311
|
|
|
|
|
|
|
{ |
312
|
0
|
|
|
|
|
|
$logfile = join('/', getcwd(), $logfile); |
313
|
|
|
|
|
|
|
} |
314
|
|
|
|
|
|
|
|
315
|
0
|
0
|
|
|
|
|
if (-e $logfile) |
316
|
|
|
|
|
|
|
{ |
317
|
0
|
|
|
|
|
|
$self->{'logfile'} = $logfile; |
318
|
|
|
|
|
|
|
} |
319
|
|
|
|
|
|
|
else |
320
|
|
|
|
|
|
|
{ |
321
|
0
|
|
|
|
|
|
$self->{'logfile'} = DEFAULT_LOGFILE; |
322
|
0
|
|
|
|
|
|
print STDERR "\n'$logfile' either does not exist or is unreadable\n"; |
323
|
0
|
|
|
|
|
|
print STDERR "\nUsing default logfile " . DEFAULT_LOGFILE . "\n"; |
324
|
|
|
|
|
|
|
} |
325
|
0
|
|
|
|
|
|
undef $return_value; |
326
|
|
|
|
|
|
|
} |
327
|
|
|
|
|
|
|
else |
328
|
|
|
|
|
|
|
{ |
329
|
0
|
|
|
|
|
|
$return_value = $self->{'logfile'}; |
330
|
|
|
|
|
|
|
} |
331
|
0
|
|
|
|
|
|
return $return_value; |
332
|
|
|
|
|
|
|
} |
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
######################################## |
335
|
|
|
|
|
|
|
# load_devices |
336
|
|
|
|
|
|
|
# public method |
337
|
|
|
|
|
|
|
# |
338
|
|
|
|
|
|
|
# This method looks at a device config |
339
|
|
|
|
|
|
|
# file and returns |
340
|
|
|
|
|
|
|
# an array ref of Net::Autoconfig::Device's. |
341
|
|
|
|
|
|
|
# Devices are returned in the same order as |
342
|
|
|
|
|
|
|
# in the device file. |
343
|
|
|
|
|
|
|
# |
344
|
|
|
|
|
|
|
# Returns: |
345
|
|
|
|
|
|
|
# array context => an array of Devices |
346
|
|
|
|
|
|
|
# scalar context => an array ref of Devices |
347
|
|
|
|
|
|
|
# undef => failure |
348
|
|
|
|
|
|
|
######################################## |
349
|
|
|
|
|
|
|
sub load_devices { |
350
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
351
|
0
|
|
|
|
|
|
my $filename = shift; |
352
|
0
|
|
|
|
|
|
my $log = Log::Log4perl->get_logger( ref($self) ); |
353
|
0
|
|
|
|
|
|
my $devices = []; # an array ref of Net::Autoconfig::Devices, key = hostname |
354
|
0
|
|
|
|
|
|
my $file_format; # indicates if the file is a hash of arrays, or as hash of hashes of arrays |
355
|
|
|
|
|
|
|
my $file_hash_depth; # an integer of the number of levels of hashes in the device file |
356
|
0
|
|
|
|
|
|
my $current_device; # the name of the current device to add parameters too |
357
|
0
|
|
|
|
|
|
my $line_counter; # The current line we're on in the device config file (used for logging) |
358
|
0
|
|
|
|
|
|
my $default_device; # The default device, helps populate new devices |
359
|
0
|
0
|
|
|
|
|
$filename or $filename = ""; |
360
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
# Check for abs path |
362
|
0
|
0
|
|
|
|
|
if ( $filename !~ /\// ) |
363
|
|
|
|
|
|
|
{ |
364
|
0
|
|
|
|
|
|
$filename = join("/", getcwd(), $filename); |
365
|
|
|
|
|
|
|
} |
366
|
|
|
|
|
|
|
|
367
|
0
|
0
|
|
|
|
|
(&_file_not_usable($filename, "device config")) and return; |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
eval |
370
|
0
|
|
|
|
|
|
{ |
371
|
0
|
0
|
|
|
|
|
open(DEVICES, $filename) || die print "Could not open '$filename' for reading: $!"; |
372
|
|
|
|
|
|
|
}; |
373
|
0
|
0
|
|
|
|
|
if ($@) |
374
|
|
|
|
|
|
|
{ |
375
|
0
|
|
|
|
|
|
$log->warn("Unable to open '$filename': $@"); |
376
|
0
|
|
|
|
|
|
return; |
377
|
|
|
|
|
|
|
} |
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
# Create this here in case someone decides not to use the default |
380
|
|
|
|
|
|
|
# device. Re-set the auto-disover bit |
381
|
0
|
|
|
|
|
|
$default_device = Net::Autoconfig::Device->new( 'auto_discover' => FALSE ); |
382
|
0
|
|
|
|
|
|
$default_device->hostname('autoconfig-default'); |
383
|
|
|
|
|
|
|
|
384
|
0
|
|
|
|
|
|
while (my $line = ) |
385
|
|
|
|
|
|
|
{ |
386
|
0
|
|
|
|
|
|
chomp $line; |
387
|
0
|
0
|
|
|
|
|
next if $line =~ /^#/; |
388
|
0
|
0
|
|
|
|
|
next if $line =~ /^\s*$/; |
389
|
|
|
|
|
|
|
|
390
|
0
|
|
|
|
|
|
$line_counter++; |
391
|
|
|
|
|
|
|
|
392
|
0
|
0
|
|
|
|
|
if ($line =~ /^:/) |
|
|
0
|
|
|
|
|
|
393
|
|
|
|
|
|
|
{ |
394
|
|
|
|
|
|
|
# some type of host declaration (host or default) |
395
|
0
|
|
|
|
|
|
$line =~ s/^://; |
396
|
0
|
|
|
|
|
|
$line =~ s/:$//; |
397
|
0
|
|
|
|
|
|
$line =~ s/\s*(.*?)\s*/$1/; #remove preceding and trailing whitespace |
398
|
|
|
|
|
|
|
|
399
|
0
|
0
|
|
|
|
|
if (not $line) |
400
|
|
|
|
|
|
|
{ |
401
|
0
|
|
|
|
|
|
$log->warn("In device file, undef device '::' line at $line_counter."); |
402
|
0
|
|
|
|
|
|
next; |
403
|
|
|
|
|
|
|
} |
404
|
|
|
|
|
|
|
|
405
|
0
|
0
|
|
|
|
|
if ($line =~ /default/i) |
|
|
0
|
|
|
|
|
|
406
|
|
|
|
|
|
|
{ |
407
|
0
|
|
|
|
|
|
$current_device = $default_device; |
408
|
|
|
|
|
|
|
} |
409
|
|
|
|
|
|
|
elsif ($line =~ /^end$/) |
410
|
|
|
|
|
|
|
{ |
411
|
0
|
0
|
|
|
|
|
if ($current_device->hostname !~ /autoconfig-default/i) |
412
|
|
|
|
|
|
|
{ |
413
|
0
|
|
|
|
|
|
$log->trace("Adding " . $current_device->hostname |
414
|
|
|
|
|
|
|
. " to the list of devices."); |
415
|
0
|
|
|
|
|
|
$current_device = $current_device->auto_discover; |
416
|
0
|
|
|
|
|
|
push(@$devices, $current_device); |
417
|
|
|
|
|
|
|
} |
418
|
0
|
|
|
|
|
|
undef $current_device; |
419
|
|
|
|
|
|
|
} |
420
|
|
|
|
|
|
|
else |
421
|
|
|
|
|
|
|
{ |
422
|
0
|
|
|
|
|
|
$current_device = Net::Autoconfig::Device->new( |
423
|
|
|
|
|
|
|
$default_device->get(), |
424
|
|
|
|
|
|
|
'hostname' => $line, |
425
|
|
|
|
|
|
|
); |
426
|
|
|
|
|
|
|
} |
427
|
|
|
|
|
|
|
} |
428
|
|
|
|
|
|
|
elsif ($line =~ /\s*(.*?)\s*=\s*(.*?)\s*$/) |
429
|
|
|
|
|
|
|
{ |
430
|
0
|
|
|
|
|
|
my $key = $1; |
431
|
0
|
|
|
|
|
|
my $value = $2; |
432
|
0
|
0
|
|
|
|
|
if (not $current_device) |
433
|
|
|
|
|
|
|
{ |
434
|
0
|
|
|
|
|
|
$log->warn("No device is currently configured at line $line_counter."); |
435
|
0
|
|
|
|
|
|
next; |
436
|
|
|
|
|
|
|
} |
437
|
0
|
0
|
|
|
|
|
if ($log->is_trace()) |
438
|
|
|
|
|
|
|
{ |
439
|
0
|
|
|
|
|
|
$log->trace("line # = $line_counter"); |
440
|
0
|
|
|
|
|
|
$log->trace("line = '$line'"); |
441
|
0
|
|
|
|
|
|
$log->trace("key = '$key'"); |
442
|
0
|
|
|
|
|
|
$log->trace("value = '$value'"); |
443
|
|
|
|
|
|
|
} |
444
|
|
|
|
|
|
|
|
445
|
0
|
0
|
|
|
|
|
if ($value =~ /\/i) |
446
|
|
|
|
|
|
|
{ |
447
|
0
|
|
|
|
|
|
my $user_prompts = USER_PROMPTS; |
448
|
0
|
|
|
|
|
|
my $hostname = $current_device->hostname; |
449
|
0
|
|
|
|
|
|
my $message = $user_prompts->{$key}; |
450
|
0
|
0
|
|
|
|
|
if (not $message) |
451
|
|
|
|
|
|
|
{ |
452
|
0
|
|
|
|
|
|
$message = $key; |
453
|
|
|
|
|
|
|
} |
454
|
0
|
0
|
|
|
|
|
if ($hostname eq $default_device->hostname) |
455
|
|
|
|
|
|
|
{ |
456
|
0
|
|
|
|
|
|
$hostname = "Default"; |
457
|
|
|
|
|
|
|
} |
458
|
0
|
|
|
|
|
|
$message = "[$hostname] - $message"; |
459
|
0
|
|
|
|
|
|
$value = &_get_password($message); |
460
|
|
|
|
|
|
|
} |
461
|
|
|
|
|
|
|
|
462
|
0
|
|
|
|
|
|
$current_device->set($key => $value); |
463
|
|
|
|
|
|
|
} |
464
|
|
|
|
|
|
|
else |
465
|
|
|
|
|
|
|
{ |
466
|
0
|
|
|
|
|
|
$log->warn("Invalid key = value line. Line = '$line'."); |
467
|
|
|
|
|
|
|
} |
468
|
|
|
|
|
|
|
} |
469
|
|
|
|
|
|
|
|
470
|
0
|
|
|
|
|
|
close(DEVICES); |
471
|
0
|
0
|
|
|
|
|
return wantarray ? @$devices : $devices; |
472
|
|
|
|
|
|
|
} |
473
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
######################################## |
475
|
|
|
|
|
|
|
# load_template |
476
|
|
|
|
|
|
|
# public method |
477
|
|
|
|
|
|
|
# |
478
|
|
|
|
|
|
|
# Load a configuration template from disk. |
479
|
|
|
|
|
|
|
# These files use the colon file format. |
480
|
|
|
|
|
|
|
# See documentation for more details. |
481
|
|
|
|
|
|
|
# |
482
|
|
|
|
|
|
|
# Returns |
483
|
|
|
|
|
|
|
# success => a hash ref of the different hosts/devices types |
484
|
|
|
|
|
|
|
# failure => undef |
485
|
|
|
|
|
|
|
######################################## |
486
|
|
|
|
|
|
|
sub load_template { |
487
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
488
|
0
|
|
|
|
|
|
my $filename = shift; |
489
|
0
|
|
|
|
|
|
my $log = Log::Log4perl->get_logger( ref($self) ); |
490
|
0
|
|
|
|
|
|
my $template; |
491
|
0
|
0
|
|
|
|
|
$filename or $filename = ""; |
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
# Check for abs path |
494
|
0
|
0
|
|
|
|
|
if ( $filename !~ /^\// ) |
495
|
|
|
|
|
|
|
{ |
496
|
0
|
|
|
|
|
|
$filename = join("/", getcwd(), $filename); |
497
|
|
|
|
|
|
|
} |
498
|
|
|
|
|
|
|
|
499
|
0
|
0
|
|
|
|
|
(&_file_not_usable($filename, "template file")) and return; |
500
|
|
|
|
|
|
|
|
501
|
0
|
|
|
|
|
|
$template = Net::Autoconfig::Template->new($filename); |
502
|
|
|
|
|
|
|
|
503
|
0
|
|
|
|
|
|
return $template; |
504
|
|
|
|
|
|
|
} |
505
|
|
|
|
|
|
|
|
506
|
|
|
|
|
|
|
######################################## |
507
|
|
|
|
|
|
|
# autoconfig |
508
|
|
|
|
|
|
|
# public method |
509
|
|
|
|
|
|
|
# |
510
|
|
|
|
|
|
|
# Takes a hash ref of device files and |
511
|
|
|
|
|
|
|
# a template file, and executes the commands on all of the devices. |
512
|
|
|
|
|
|
|
# |
513
|
|
|
|
|
|
|
# There are two ways a template can be applied to a device. |
514
|
|
|
|
|
|
|
# If the device model matches a template entry, then that is |
515
|
|
|
|
|
|
|
# applied first. If the device name matches a template entry, |
516
|
|
|
|
|
|
|
# then that is applied to the device second. |
517
|
|
|
|
|
|
|
# |
518
|
|
|
|
|
|
|
# This allows for a device to receive a "generic" configuration |
519
|
|
|
|
|
|
|
# destined for all devices first, and a more "specific" configuration |
520
|
|
|
|
|
|
|
# later. |
521
|
|
|
|
|
|
|
# |
522
|
|
|
|
|
|
|
# Takes: |
523
|
|
|
|
|
|
|
# $devices_hash_ref, Net::Autoconfig::Template |
524
|
|
|
|
|
|
|
# |
525
|
|
|
|
|
|
|
# Returns: |
526
|
|
|
|
|
|
|
# success = undef |
527
|
|
|
|
|
|
|
# failure = An array or array ref (contextual) of the failed devices |
528
|
|
|
|
|
|
|
######################################## |
529
|
|
|
|
|
|
|
sub autoconfig { |
530
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
531
|
0
|
|
|
|
|
|
my $devices = shift; |
532
|
0
|
|
|
|
|
|
my $template = shift; |
533
|
0
|
|
|
|
|
|
my $failed_ping_test; # results from doing the ping test on the device |
534
|
0
|
|
|
|
|
|
my $log = Log::Log4perl->get_logger( ref($self) ); |
535
|
|
|
|
|
|
|
|
536
|
0
|
0
|
|
|
|
|
if (ref($self) !~ /Net::Autoconfig/) |
537
|
|
|
|
|
|
|
{ |
538
|
0
|
|
|
|
|
|
$log->warn("Autoconfig not called as a method."); |
539
|
0
|
|
|
|
|
|
return "Autoconfig not called as a method."; |
540
|
|
|
|
|
|
|
} |
541
|
|
|
|
|
|
|
|
542
|
0
|
0
|
|
|
|
|
if (not $devices) |
543
|
|
|
|
|
|
|
{ |
544
|
0
|
|
|
|
|
|
$log->warn("No devices passed to autoconfig."); |
545
|
0
|
|
|
|
|
|
return "No devices passed to autoconfig."; |
546
|
|
|
|
|
|
|
} |
547
|
|
|
|
|
|
|
|
548
|
0
|
0
|
|
|
|
|
if (not ref ($devices) eq "ARRAY") |
549
|
|
|
|
|
|
|
{ |
550
|
0
|
|
|
|
|
|
$log->warn("Devices were not passed as an array ref."); |
551
|
0
|
|
|
|
|
|
return "Devices were not passed as an array ref."; |
552
|
|
|
|
|
|
|
} |
553
|
|
|
|
|
|
|
|
554
|
0
|
0
|
|
|
|
|
if (not $template) |
555
|
|
|
|
|
|
|
{ |
556
|
0
|
|
|
|
|
|
$log->warn("No template passed to autoconfig."); |
557
|
0
|
|
|
|
|
|
return "No template passed to autoconfig."; |
558
|
|
|
|
|
|
|
} |
559
|
|
|
|
|
|
|
|
560
|
0
|
|
|
|
|
|
foreach my $device ( @$devices ) |
561
|
|
|
|
|
|
|
{ |
562
|
0
|
|
|
|
|
|
my $child_pid; # PID of the child process (if used) |
563
|
|
|
|
|
|
|
|
564
|
0
|
0
|
|
|
|
|
if ($log->is_trace) |
565
|
|
|
|
|
|
|
{ |
566
|
0
|
|
|
|
|
|
$log->trace("Device about to be configured: " . Dumper($device)); |
567
|
|
|
|
|
|
|
} |
568
|
|
|
|
|
|
|
|
569
|
0
|
|
|
|
|
|
while (keys %{ $CHILD_PROCESSES->{'active'} } > $self->max_children) |
|
0
|
|
|
|
|
|
|
570
|
|
|
|
|
|
|
{ |
571
|
0
|
|
|
|
|
|
$log->debug("Reached max # of child processes (" . $self->max_children |
572
|
|
|
|
|
|
|
. ") Waiting for some processes to clear up..."); |
573
|
0
|
0
|
|
|
|
|
&_reaper() if $ZOMBIES; |
574
|
0
|
|
|
|
|
|
sleep(1); |
575
|
|
|
|
|
|
|
} |
576
|
|
|
|
|
|
|
|
577
|
0
|
0
|
|
|
|
|
if ($self->bulk_mode) |
578
|
|
|
|
|
|
|
{ |
579
|
0
|
|
|
|
|
|
$log->trace("Forking process"); |
580
|
0
|
|
|
|
|
|
$child_pid = fork(); |
581
|
|
|
|
|
|
|
#$log->trace("Fork created for Parent $$ - Child $child_pid. Device " . $device->hostname); |
582
|
0
|
0
|
|
|
|
|
if ($child_pid == -1) |
|
|
0
|
|
|
|
|
|
583
|
|
|
|
|
|
|
{ |
584
|
|
|
|
|
|
|
# Failed to fork! |
585
|
0
|
|
|
|
|
|
$log->warn("Failed to create child process for device " . $device->hostname); |
586
|
0
|
|
|
|
|
|
next; |
587
|
|
|
|
|
|
|
} |
588
|
|
|
|
|
|
|
elsif ($child_pid) |
589
|
|
|
|
|
|
|
{ |
590
|
|
|
|
|
|
|
# I'm the parent |
591
|
0
|
|
|
|
|
|
$log->debug("Parent $$ - Child $child_pid - Current Device : " . $device->hostname); |
592
|
0
|
|
|
|
|
|
$log->debug("Child $child_pid bulk_mode = " . $self->bulk_mode()); |
593
|
0
|
|
|
|
|
|
$CHILD_PROCESSES->{'active'}->{$child_pid} = $device->hostname; |
594
|
0
|
|
|
|
|
|
$CHILD_PROCESSES->{'info'}->{$child_pid} = $device->hostname; |
595
|
0
|
|
|
|
|
|
next; |
596
|
|
|
|
|
|
|
} |
597
|
|
|
|
|
|
|
else |
598
|
|
|
|
|
|
|
{ |
599
|
|
|
|
|
|
|
# This is the child |
600
|
0
|
|
|
|
|
|
$log->debug("Child process started for " . $device->hostname); |
601
|
|
|
|
|
|
|
} |
602
|
|
|
|
|
|
|
} |
603
|
|
|
|
|
|
|
|
604
|
0
|
0
|
|
|
|
|
if ($device->provision) |
605
|
|
|
|
|
|
|
{ |
606
|
0
|
|
|
|
|
|
$device->hostname =~ /\A(.*)\@(.*)$/; |
607
|
0
|
0
|
0
|
|
|
|
if ($1 and $2) |
608
|
|
|
|
|
|
|
{ |
609
|
|
|
|
|
|
|
# Well formed provisioning hostname |
610
|
0
|
|
|
|
|
|
$failed_ping_test = &_failed_ping_test($2); |
611
|
|
|
|
|
|
|
} |
612
|
|
|
|
|
|
|
else |
613
|
|
|
|
|
|
|
{ |
614
|
|
|
|
|
|
|
# Poorly formed or normal hostname |
615
|
0
|
|
|
|
|
|
$log->warn("Provisioning hostname " . $device->hostname . " poorly formed."); |
616
|
0
|
|
|
|
|
|
$failed_ping_test = TRUE; |
617
|
|
|
|
|
|
|
} |
618
|
|
|
|
|
|
|
} |
619
|
|
|
|
|
|
|
else |
620
|
|
|
|
|
|
|
{ |
621
|
0
|
|
|
|
|
|
$failed_ping_test = &_failed_ping_test($device->hostname); |
622
|
|
|
|
|
|
|
} |
623
|
|
|
|
|
|
|
|
624
|
0
|
0
|
|
|
|
|
if ($failed_ping_test) |
625
|
|
|
|
|
|
|
{ |
626
|
0
|
|
0
|
|
|
|
my $hostname = $device->hostname || ""; |
627
|
0
|
|
|
|
|
|
$log->warn("$hostname was not reachable via ping. Aborting configuration attempt."); |
628
|
0
|
0
|
|
|
|
|
if ($self->bulk_mode) |
629
|
|
|
|
|
|
|
{ |
630
|
0
|
|
|
|
|
|
exit; |
631
|
|
|
|
|
|
|
} |
632
|
|
|
|
|
|
|
else |
633
|
|
|
|
|
|
|
{ |
634
|
0
|
|
|
|
|
|
next; |
635
|
|
|
|
|
|
|
} |
636
|
|
|
|
|
|
|
} |
637
|
|
|
|
|
|
|
|
638
|
|
|
|
|
|
|
# Establish a connection to the device first |
639
|
0
|
0
|
|
|
|
|
$device->provision and $device->console_connect(); |
640
|
0
|
|
|
|
|
|
$device->connect(); |
641
|
0
|
|
|
|
|
|
$device->get_admin_rights(); |
642
|
0
|
|
|
|
|
|
$device->disable_paging(); |
643
|
|
|
|
|
|
|
|
644
|
0
|
0
|
|
|
|
|
$device->provision and $device->lookup_model; |
645
|
|
|
|
|
|
|
|
646
|
|
|
|
|
|
|
# Do the generic, device model/type template first |
647
|
|
|
|
|
|
|
# device->model returns an array ref, a device can match more |
648
|
|
|
|
|
|
|
# than one device type. Take the first one that exists in the template. |
649
|
0
|
|
|
|
|
|
MODEL_CONFIG: |
650
|
0
|
|
|
|
|
|
foreach my $model ( @{ $device->model } ) |
651
|
|
|
|
|
|
|
{ |
652
|
0
|
0
|
|
|
|
|
if ($template->{ $model } ) |
653
|
|
|
|
|
|
|
{ |
654
|
0
|
|
|
|
|
|
$log->info("Starting generic, model based using template" |
655
|
|
|
|
|
|
|
. " '$model' to configure " . $device->hostname); |
656
|
0
|
|
|
|
|
|
$device->configure($template->{ $model }); |
657
|
0
|
|
|
|
|
|
last MODEL_CONFIG; |
658
|
|
|
|
|
|
|
} |
659
|
|
|
|
|
|
|
else |
660
|
|
|
|
|
|
|
{ |
661
|
0
|
|
|
|
|
|
$log->info("No generic, model based template called '$model'" . |
662
|
|
|
|
|
|
|
" for host " . $device->hostname); |
663
|
0
|
|
|
|
|
|
next MODEL_CONFIG; |
664
|
|
|
|
|
|
|
} |
665
|
|
|
|
|
|
|
} |
666
|
|
|
|
|
|
|
|
667
|
0
|
0
|
|
|
|
|
if ($template->{$device->hostname}) |
668
|
|
|
|
|
|
|
{ |
669
|
|
|
|
|
|
|
# Do the host specific template second. |
670
|
0
|
|
|
|
|
|
$log->info("Starting specific, hostname based configuration"); |
671
|
0
|
|
|
|
|
|
$device->configure($template->{ $device->hostname }); |
672
|
|
|
|
|
|
|
} |
673
|
|
|
|
|
|
|
else |
674
|
|
|
|
|
|
|
{ |
675
|
0
|
|
|
|
|
|
$log->info("No specific, hostnamed based template defined for host " . $device->hostname); |
676
|
|
|
|
|
|
|
} |
677
|
0
|
|
|
|
|
|
$device->end_session(); |
678
|
|
|
|
|
|
|
|
679
|
0
|
0
|
|
|
|
|
if ($self->bulk_mode) |
680
|
|
|
|
|
|
|
{ |
681
|
0
|
0
|
|
|
|
|
if ($child_pid == 0) |
682
|
|
|
|
|
|
|
{ |
683
|
0
|
|
|
|
|
|
$log->trace("Terminating child process $$ for host " . $device->hostname); |
684
|
0
|
|
|
|
|
|
exit; |
685
|
|
|
|
|
|
|
} |
686
|
|
|
|
|
|
|
} |
687
|
|
|
|
|
|
|
} |
688
|
|
|
|
|
|
|
|
689
|
0
|
|
|
|
|
|
while (keys %{ $CHILD_PROCESSES->{'active'}}) |
|
0
|
|
|
|
|
|
|
690
|
|
|
|
|
|
|
{ |
691
|
0
|
|
|
|
|
|
$log->debug("Waiting for child processes to terminate. Sleeping for 5 seconds."); |
692
|
0
|
0
|
|
|
|
|
&_reaper() if $ZOMBIES; |
693
|
0
|
|
|
|
|
|
sleep(5); |
694
|
|
|
|
|
|
|
} |
695
|
|
|
|
|
|
|
|
696
|
0
|
|
|
|
|
|
$log->info("Autoconfig Finished."); |
697
|
|
|
|
|
|
|
|
698
|
0
|
|
|
|
|
|
return; |
699
|
|
|
|
|
|
|
} |
700
|
|
|
|
|
|
|
|
701
|
|
|
|
|
|
|
############################################################ |
702
|
|
|
|
|
|
|
# Private Methods |
703
|
|
|
|
|
|
|
############################################################ |
704
|
|
|
|
|
|
|
# |
705
|
|
|
|
|
|
|
######################################## |
706
|
|
|
|
|
|
|
# _get_password |
707
|
|
|
|
|
|
|
# private function |
708
|
|
|
|
|
|
|
# |
709
|
|
|
|
|
|
|
# Get a password from the user. |
710
|
|
|
|
|
|
|
# I.e. prevent local echoing of their |
711
|
|
|
|
|
|
|
# password. |
712
|
|
|
|
|
|
|
######################################## |
713
|
|
|
|
|
|
|
sub _get_password { |
714
|
0
|
|
|
0
|
|
|
my $prompt = shift; |
715
|
0
|
|
|
|
|
|
my $log = Log::Log4perl->get_logger( __PACKAGE__ ); |
716
|
0
|
|
|
|
|
|
my $message = ""; |
717
|
0
|
|
|
|
|
|
my $user_input = ""; |
718
|
|
|
|
|
|
|
|
719
|
0
|
0
|
|
|
|
|
if (not $prompt) |
720
|
|
|
|
|
|
|
{ |
721
|
0
|
|
|
|
|
|
$log->debug("get_password - Prompt not specified"); |
722
|
0
|
|
|
|
|
|
$prompt = "(Not Specified)"; |
723
|
|
|
|
|
|
|
} |
724
|
|
|
|
|
|
|
|
725
|
0
|
|
|
|
|
|
$message = "[User Input] - $prompt: "; |
726
|
|
|
|
|
|
|
|
727
|
0
|
|
|
|
|
|
$log->trace("get_password - Message = '$message'"); |
728
|
0
|
|
|
|
|
|
print $message; |
729
|
|
|
|
|
|
|
|
730
|
|
|
|
|
|
|
# Hide user input |
731
|
|
|
|
|
|
|
# This only works on linux/unix machines. |
732
|
0
|
|
|
|
|
|
$log->trace("get_password - hiding user text input"); |
733
|
0
|
|
|
|
|
|
system("stty -echo"); |
734
|
|
|
|
|
|
|
|
735
|
0
|
|
|
|
|
|
$user_input = ; |
736
|
0
|
|
|
|
|
|
chomp($user_input); |
737
|
0
|
|
|
|
|
|
$log->trace("get_password - password = '$user_input'"); |
738
|
|
|
|
|
|
|
|
739
|
|
|
|
|
|
|
# Show user input again. |
740
|
0
|
|
|
|
|
|
$log->trace("get_password - showing user text input"); |
741
|
0
|
|
|
|
|
|
system("stty echo"); |
742
|
0
|
|
|
|
|
|
print "\n"; |
743
|
|
|
|
|
|
|
|
744
|
0
|
|
|
|
|
|
return $user_input; |
745
|
|
|
|
|
|
|
} |
746
|
|
|
|
|
|
|
|
747
|
|
|
|
|
|
|
|
748
|
|
|
|
|
|
|
######################################## |
749
|
|
|
|
|
|
|
# _file_not_usable |
750
|
|
|
|
|
|
|
# private method |
751
|
|
|
|
|
|
|
# |
752
|
|
|
|
|
|
|
# Check to see if a file exists, is readable, |
753
|
|
|
|
|
|
|
# etc. |
754
|
|
|
|
|
|
|
# |
755
|
|
|
|
|
|
|
# Takes a filename and a description about the file |
756
|
|
|
|
|
|
|
# E.g. "device configs" or "firmware tempalte" |
757
|
|
|
|
|
|
|
# |
758
|
|
|
|
|
|
|
# Return FALSE if it's okay. |
759
|
|
|
|
|
|
|
# Return TRUE if it's not |
760
|
|
|
|
|
|
|
######################################## |
761
|
|
|
|
|
|
|
sub _file_not_usable { |
762
|
0
|
|
|
0
|
|
|
my $filename = shift; |
763
|
0
|
|
|
|
|
|
my $file_descrip = shift; |
764
|
0
|
|
|
|
|
|
my $working_dir = getcwd(); |
765
|
0
|
|
|
|
|
|
my $log = Log::Log4perl->get_logger( __PACKAGE__ ); |
766
|
0
|
|
0
|
|
|
|
$file_descrip = $file_descrip || ""; |
767
|
|
|
|
|
|
|
|
768
|
0
|
0
|
|
|
|
|
if (! $filename) |
769
|
|
|
|
|
|
|
{ |
770
|
0
|
|
|
|
|
|
$log->warn("$file_descrip: filename not defined."); |
771
|
0
|
|
|
|
|
|
return TRUE; |
772
|
|
|
|
|
|
|
} |
773
|
|
|
|
|
|
|
|
774
|
0
|
0
|
|
|
|
|
if (-d $filename) |
775
|
|
|
|
|
|
|
{ |
776
|
0
|
|
|
|
|
|
$log->warn("$file_descrip: filename, '$filename' is a directory."); |
777
|
0
|
|
|
|
|
|
return TRUE; |
778
|
|
|
|
|
|
|
} |
779
|
|
|
|
|
|
|
|
780
|
0
|
0
|
|
|
|
|
if (not -e $filename) |
781
|
|
|
|
|
|
|
{ |
782
|
0
|
|
|
|
|
|
$log->warn("$file_descrip: '$filename', does not exist."); |
783
|
0
|
|
|
|
|
|
return TRUE; |
784
|
|
|
|
|
|
|
} |
785
|
|
|
|
|
|
|
|
786
|
0
|
0
|
|
|
|
|
if (not -r $filename) |
787
|
|
|
|
|
|
|
{ |
788
|
0
|
|
|
|
|
|
$log->warn("$file_descrip: '$filename', is not readable. Check file permissions."); |
789
|
0
|
|
|
|
|
|
return TRUE; |
790
|
|
|
|
|
|
|
} |
791
|
|
|
|
|
|
|
|
792
|
|
|
|
|
|
|
# Ergo, it must be okay! |
793
|
0
|
|
|
|
|
|
return FALSE; |
794
|
|
|
|
|
|
|
} |
795
|
|
|
|
|
|
|
|
796
|
|
|
|
|
|
|
|
797
|
|
|
|
|
|
|
sub _failed_ping_test { |
798
|
0
|
|
|
0
|
|
|
my $hostname = shift; |
799
|
0
|
|
|
|
|
|
return; |
800
|
|
|
|
|
|
|
} |
801
|
|
|
|
|
|
|
|
802
|
|
|
|
|
|
|
############################## |
803
|
|
|
|
|
|
|
# _reaper |
804
|
|
|
|
|
|
|
# private method |
805
|
|
|
|
|
|
|
# |
806
|
|
|
|
|
|
|
# Takes care of waiting for child processes to finish |
807
|
|
|
|
|
|
|
# so they don't become zombies. Also does some |
808
|
|
|
|
|
|
|
# book keeping so we know which processes succeded |
809
|
|
|
|
|
|
|
# and which ones failed; which ones/how many are active |
810
|
|
|
|
|
|
|
############################## |
811
|
|
|
|
|
|
|
sub _reaper { |
812
|
0
|
|
|
0
|
|
|
my $zombie; |
813
|
0
|
|
|
|
|
|
my $log = Log::Log4perl->get_logger( __PACKAGE__ ); |
814
|
|
|
|
|
|
|
|
815
|
0
|
|
|
|
|
|
$log->trace("Start reaping zombies."); |
816
|
0
|
|
|
|
|
|
$log->trace("Number of zombies : $ZOMBIES"); |
817
|
0
|
|
|
|
|
|
$log->trace("Number of active children: " . int(keys %{ $CHILD_PROCESSES->{active} })); |
|
0
|
|
|
|
|
|
|
818
|
|
|
|
|
|
|
|
819
|
0
|
|
|
|
|
|
$ZOMBIES = 0; |
820
|
|
|
|
|
|
|
|
821
|
|
|
|
|
|
|
# This is a little tricky. |
822
|
|
|
|
|
|
|
# waitpid returns the process id of a zombie that needs to |
823
|
|
|
|
|
|
|
# be reaped. It returns 0 for active procsses. It returns |
824
|
|
|
|
|
|
|
# -1 when there are no child processes left. |
825
|
|
|
|
|
|
|
# You'll see code that has != -1, We want to |
826
|
|
|
|
|
|
|
# keep going when child processes are active and |
827
|
|
|
|
|
|
|
# only reap the dead processes. |
828
|
0
|
|
|
|
|
|
while (($zombie = waitpid(-1, WNOHANG)) > 0) |
829
|
|
|
|
|
|
|
{ |
830
|
0
|
|
|
|
|
|
$CHILD_PROCESSES->{'finished'}->{$zombie} = $? >> 8; |
831
|
0
|
|
|
|
|
|
delete $CHILD_PROCESSES->{'active'}->{$zombie}; |
832
|
|
|
|
|
|
|
} |
833
|
|
|
|
|
|
|
|
834
|
0
|
|
|
|
|
|
$log->trace("Done reaping zombies."); |
835
|
0
|
|
|
|
|
|
return; |
836
|
|
|
|
|
|
|
} |
837
|
|
|
|
|
|
|
|
838
|
|
|
|
|
|
|
# Module must return true. |
839
|
|
|
|
|
|
|
TRUE; |
840
|
|
|
|
|
|
|
|
841
|
|
|
|
|
|
|
__END__ |