bin/alaxala-deploy in netutils-0.1.1 vs bin/alaxala-deploy in netutils-0.1.2
- old
+ new
@@ -36,12 +36,12 @@
progname = File.basename($0)
STDERR.print "ERROR: #{errmsg}\n\n" if errmsg
STDERR.print "\
Usage:
#{progname} -h
- #{progname} [-c] [-w] [-r] -a
- #{progname} [-c] [-w] [-r] <switch IP address1> <switch IP address2> ...
+ #{progname} [-c] [-d] [-f] [-w] [-r] -a
+ #{progname} [-c] [-d] [-f] [-w] [-r] <switch IP address 1> ...
Description:
deploy files to Alaxala switches, such as certificate files (i.e.,
certificate itself, private key, intermediate CA certificate), HTML
files for Web authentication.
If an option, ``-a,'' is given, deploy to all switches using LLDP or
@@ -52,10 +52,12 @@
Arguments:
switch IP address: an IP address of a switch.
Options:
-h: output this help message.
-c: deploy certificate files.
+ -d: dry run (do not actually reboot).
+ -f: force to consider all switches as requiring reboots.
-w: deploy HTML files.
-r: reload a switch if necessary (only for certificate files).
-a: deploy to all switches.
Example:
output information:
@@ -73,25 +75,96 @@
"
exit 1
end
##
+ROOT_DEPTH = 0
+
+class Vertices
+ class Vertex
+ attr_reader :sw, :depth
+
+ def initialize(sw)
+ @sw = sw
+ depth_compute
+ end
+
+ def depth
+ @sw.note
+ end
+
+ def depth_compute
+ return if ! @sw.note.nil?
+ depth = 0
+ nparent = @sw.parent
+ loop do
+ parent = nparent
+ if parent.nil?
+ break
+ end
+ nparent = parent.parent
+ if ! parent.note.nil?
+ depth += parent.note + 1
+ break
+ end
+ end
+ @sw.note = depth
+ end
+ end
+
+ attr_reader :maxdepth
+
+ def initialize
+ @vertices = [ Queue.new ]
+ @maxdepth = 0
+ @mutex = Thread::Mutex.new
+ end
+
+ def length(depth)
+ @vertices[depth].length
+ end
+
+ def push(sw)
+ v = Vertex.new(sw)
+ @mutex.synchronize do
+ if @vertices[v.depth].nil?
+ @vertices[v.depth] = Queue.new
+ end
+ end
+ @vertices[v.depth].push(v)
+ if v.depth > @maxdepth
+ @maxdepth = v.depth
+ end
+ return v
+ end
+
+ def pop(depth)
+ @vertices[depth].pop(true)
+ end
+end
+
+vertices = Vertices.new
+
+##
# inject() requires Ruby2.4... take a more operational way.
-options0 = ARGV.getopts('hcwra', 'help', 'certificate', 'web', 'reload', 'all')
+options0 = ARGV.getopts(
+ 'hcdfwra', 'help', 'certificate', 'dry', 'force', 'web', 'reload', 'all')
options = {}
options0.map { |k, v| options[k.to_sym] = v }
usage if options[:h]
if options[:a]
if ARGV.length != 0
usage('Extra argument specified')
end
Switch.set_retrieve_all
- SWITCHES.each { |name, ia| Switch.new(name, Switch::Type::ROUTER, ia, ) }
+ SWITCHES.each do |name, ia|
+ Switch.new(name, Switch::Type::ROUTER, ia, ).note = 0
+ end
elsif ARGV.length > 0
ARGV.each do |ia|
- Switch.new(nil, Switch::Type::ROUTER, ia)
+ Switch.new(nil, Switch::Type::ROUTER, ia).note = 0
end
else
usage('No IP address is given.')
end
@@ -101,15 +174,15 @@
if options[:c] || options[:w]
print 'Input FTP user name: '
user = STDIN.gets.strip
print 'Input FTP password: '
password = STDIN.noecho(&:gets).strip
- puts
end
##
-reboots = Queue.new
+retrieve_start_time = Time.now
+
Switch.retrieve do |sw|
if sw.name
print "Connecting: ``#{sw.name}'' (#{sw.ia})\n"
else
print "Connecting: #{sw.ia}\n"
@@ -148,12 +221,12 @@
r = sw.cmd('show system')
if r =~ /^.*Boot Date[^:]+: ([^\n]+).*$/
v = $1.strip
boottime = Time.parse(v)
msg += ", boot: #{v}"
- if boottime < installedtime || options[:c]
- reboots.push(sw)
+ if boottime < installedtime || options[:c] || options[:f]
+ v = vertices.push(sw)
msg += ' (need reboot)'
end
end
puts msg
@@ -237,35 +310,62 @@
print " Done: ``#{sw.name}'' (#{sw.ia}) " +
"(#{sw.maker_to_s} #{sw.product})\n"
end
Switch.warn
+retrieve_end_time = Time.now
+
exit if ! options[:r]
+reboot_times = [ Time.now ]
+reboot_counts = []
+
thread_concurrency = 64
-threads = []
-for i in 1..thread_concurrency do
- threads <<= Thread.new do
- begin
- while sw = reboots.pop(true) do
- sw.configure
- sw.cmd('save')
- sw.unconfigure
- begin
- #
- # note that pager configuration or
- # other configurations barks without
- # an option, ``-f.''
- #
- sw.cmd('reload -f')
- rescue
+for rdepth in 0 .. vertices.maxdepth do
+ depth = vertices.maxdepth - rdepth
+ reboot_counts[depth] = vertices.length(depth)
+ puts "examine: #{depth}-th depth (#{vertices.length(depth)} switches)"
+ threads = []
+ for i in 1..thread_concurrency do
+ threads <<= Thread.new do
+ begin
+ while v = vertices.pop(depth) do
+ sw = v.sw
+ if ! options[:d]
+ sw.configure
+ sw.cmd('save')
+ sw.unconfigure
+ #
+ # note that pager configuration
+ # or other configurations barks
+ # without an option, ``-f.''
+ #
+ begin
+ sw.cmd('reload -f')
+ rescue
+ end
+ end
+ puts " Reboot: ``#{sw.name}'' " +
+ "(#{sw.ia}) done"
end
- puts " Reboot: ``#{sw.name}'' (#{sw.ia}) done"
+ rescue
end
- rescue
end
end
+
+ threads.each do |thread|
+ thread.join
+ end
+
+ reboot_times.push(Time.now)
end
-threads.each do |thread|
- thread.join
+puts "Retrieve time : #{retrieve_start_time.iso8601(3)}" +
+ " (#{retrieve_end_time - retrieve_start_time})"
+puts " Reboot time: #{reboot_times.first.iso8601(3)}" +
+ " (#{reboot_times.last - reboot_times.first})"
+
+for depth in 0 .. vertices.maxdepth do
+ printf "% 10d-th depth: % 4d switches: " +
+ "#{reboot_times[depth + 1] - reboot_times[depth]}\n",
+ depth, reboot_counts[depth]
end