| 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__ |