xlogin 0.8.3 → 0.8.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1d9127e12b562fc160b59f27eb380c61c80d91cf
4
- data.tar.gz: bddfb491a1dc4d53b5b61464aa550cfaa45024a9
3
+ metadata.gz: d0c4789d65178ce5f60077b6d9f1f066872a7e8f
4
+ data.tar.gz: d41b0cdf51f5a566c84757104cb5094e1504ba1b
5
5
  SHA512:
6
- metadata.gz: 016bbc7159b7f0afae1c0f162d55111723290f7700a8cbf179a0176b6f1a321e220bf7a0ccb020e85fa65a7c666444792c51c414e1e850ef2d9528a9ff1c1e63
7
- data.tar.gz: d2446df25335c0a95188efdf5ecd6a441ed3d00979af7a5d0aed1b6c587ce4318e39de92b2dd86b0f2445abef5eec2b4334f84b0c1680d4af397849fb8bb36a7
6
+ metadata.gz: b9b3b1cf81d0f967cfaa2cfb3d630f1e1e1ede4abd3c5671b3b85eec429a5f5f6b088cf0fe763a61f6e8b1c6c977baa0b227f522465d38028347099fb47f3ca5
7
+ data.tar.gz: 3005ee45108fc3c5f61b0c2abf0c77916db5a0561508274a9e9c4498d4c3dc7cc529136d3cf35f95a82ab6152f3c9c131772e952dc04ed85d5c74dfb5e6f355e
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- xlogin (0.8.1)
4
+ xlogin (0.8.4)
5
5
  net-ssh
6
6
  net-ssh-gateway
7
7
  net-ssh-telnet
data/lib/xlogin/cli.rb CHANGED
@@ -4,6 +4,7 @@ require 'optparse'
4
4
  require 'ostruct'
5
5
  require 'parallel'
6
6
  require 'readline'
7
+ require 'socket'
7
8
  require 'stringio'
8
9
 
9
10
  module Xlogin
@@ -20,13 +21,15 @@ module Xlogin
20
21
 
21
22
  def self.getopts(args)
22
23
  config = OpenStruct.new(
23
- parallel: 1,
24
+ jobs: 1,
25
+ port: 8080,
26
+ taskname: :tty,
24
27
  inventory: nil,
25
28
  templates: [],
26
29
  )
27
30
 
28
31
  parser = OptionParser.new
29
- parser.banner = "#{File.basename($0)} HOST [TASK ARGUMENTS] [Options]"
32
+ parser.banner = "#{File.basename($0)} HOST_PATTERN [Options]"
30
33
  parser.version = Xlogin::VERSION
31
34
 
32
35
  parser.on('-i PATH', '--inventory', String, 'The PATH to the inventory file(default: $HOME/.xloginrc).') { |v| config.inventory = v }
@@ -34,14 +37,20 @@ module Xlogin
34
37
  parser.on('-T DIRECTORY', '--template-dir', String, 'The DIRECTORY of the template files.') { |v| config.templates += Dir.glob(File.join(v, '*.rb')) }
35
38
  parser.on('-L [DIRECTORY]', '--log-dir', String, 'The DIRECTORY of the log files(default: $PWD).') { |v| config.logdir = v || '.' }
36
39
 
37
- parser.on('-j NUM', '--jobs', Integer, 'The NUM of jobs to execute in parallel(default: 1).') { |v| config.parallel = v }
38
- parser.on('-e', '--enable', TrueClass, 'Try to gain enable priviledge.') { |v| config.enable = v }
40
+ parser.on('-l', '--list', TrueClass, 'List all available devices.') { |v| config.taskname = :list }
41
+ parser.on('-e', '--exec', TrueClass, 'Execute commands and quit.') { |v| config.taskname = :exec }
42
+ parser.on('-t', '--tty', TrueClass, 'Allocate a pseudo-tty.') { |v| config.taskname = :tty }
43
+
44
+ parser.on('-p NUM', '--port', Integer, 'Run as server on specified port(default: 8080).') { |v| config.taskname = :listen; config.port = v }
45
+ parser.on('-j NUM', '--jobs', Integer, 'The NUM of jobs to execute in parallel(default: 1).') { |v| config.jobs = v }
46
+
47
+ parser.on('-E', '--enable', TrueClass, 'Try to gain enable priviledge.') { |v| config.enable = v }
39
48
  parser.on('-y', '--assume-yes', TrueClass, 'Automatically answer yes to prompts.') { |v| config.authorize = v }
40
49
 
41
50
  begin
42
51
  args = parser.parse!(args)
43
- hostlist = args.shift
44
- taskname = args.shift || 'tty'
52
+ host = args.shift
53
+ config.args = args
45
54
 
46
55
  Xlogin.configure do
47
56
  config.inventory ||= DEFAULT_INVENTORY_FILE
@@ -55,13 +64,8 @@ module Xlogin
55
64
  load_templates(*config.templates.map { |file| File.expand_path(file, ENV['PWD']) })
56
65
  end
57
66
 
58
- config.hostlist = hostlist.to_s.split(',').flat_map { |pattern| Xlogin.factory.list(pattern) }
59
- config.taskname = taskname.to_s.downcase.tr('-', '_')
60
- config.arguments = args
61
-
62
- methods = Xlogin::CLI.instance_methods(false)
63
- raise "No host found: `#{hostlist}`" if config.hostlist.empty?
64
- raise "No task defined: `#{taskname}`" if config.taskname.empty? || methods.find_index(config.taskname.to_sym).nil?
67
+ config.hostlist = host.to_s.split(',').flat_map { |pattern| Xlogin.factory.list(pattern) }
68
+ raise "No host found: `#{host}`" if config.hostlist.empty?
65
69
  rescue => e
66
70
  $stderr.puts e, '', parser
67
71
  exit 1
@@ -71,55 +75,98 @@ module Xlogin
71
75
  end
72
76
 
73
77
  def list(config)
74
- width = config.hostlist.map { |e| e[:name].length }.max
75
- $stdout.puts config.hostlist.map { |e| "#{e[:name].to_s.ljust(width)} #{e[:type]}" }.sort
78
+ wid1 = config.hostlist.map { |e| e[:name].length }.max
79
+ wid2 = config.hostlist.map { |e| e[:type].length }.max
80
+ list = config.hostlist.map { |e| "#{e[:name].to_s.ljust(wid1)} #{e[:type].to_s.ljust(wid2)} #{e[:uri]}" }.sort
81
+ $stdout.puts list
76
82
  end
77
83
 
78
84
  def tty(config)
79
85
  Signal.trap(:INT) { exit 0 }
86
+
80
87
  list = config.hostlist.sort_by { |e| e[:name] }
81
88
  list.each do |target|
82
- Readline.readline(">> #{target[:name]} ", false) unless list.size == 1
83
- $stdout.puts "Trying #{target[:name]}...", "Escape character is '^]'."
89
+ unless list.size == 1
90
+ case resp = Readline.readline(">> #{target[:name]}(Y/n)? ", false).strip
91
+ when /^y(es)?$/i, ''
92
+ when /^n(o)?$/i then next
93
+ else redo
94
+ end
95
+ end
96
+
97
+ config.jobs = 1
84
98
  config.hostlist = [target]
85
- login(config) { |session| session.interact! }
99
+
100
+ $stdout.puts "Trying #{target[:name]}...", "Escape character is '^]'."
101
+ session, _ = exec(config)
102
+ session.interact!
86
103
  end
87
104
  end
88
105
 
89
- def exec(config)
90
- command_lines = ['', *config.arguments.flat_map { |e| e.split(';') }].map(&:strip)
91
- login(config) { |session| command_lines.each { |command| session.cmd(command) } }
106
+ def listen(config)
107
+ Signal.trap(:INT) { exit 0 }
108
+ config.jobs = config.hostlist.size
109
+
110
+ width = config.hostlist.map { |e| e[:name].length }.max
111
+ sessions = exec(config).compact
112
+
113
+ $stdout.puts "", ""
114
+ $stdout.puts "=> Start xlogin server on port=#{config.port}"
115
+ $stdout.puts "=> Ctrl-C to shutdown"
116
+
117
+ server = TCPServer.open(config.port)
118
+ socket = server.accept
119
+ while line = socket.gets
120
+ Parallel.each(sessions, in_threads: sessions.size) do |session|
121
+ resp = session.cmd(line.chomp)
122
+ prefix = "#{session.name.to_s.ljust(width)} |"
123
+ output = resp.to_s.lines.map { |line| prefix + line.chomp.gsub("\r", '') + "\n" }.join
124
+ socket.print output
125
+ $stdout.print output if config.jobs > 1
126
+ end
127
+ end
128
+ ensure
129
+ socket.close if socket
130
+ server.close if server
92
131
  end
93
132
 
94
- def load(config)
95
- command_lines = ['', *config.arguments.flat_map { |e| IO.readlines(e) }].map(&:strip)
96
- login(config) { |session| command_lines.each { |command| session.cmd(command) } }
97
- end
133
+ def exec(config, &block)
134
+ width = config.hostlist.map { |e| e[:name].length }.max
135
+
136
+ Parallel.map(config.hostlist, in_threads: config.jobs) do |hostinfo|
137
+ session = nil
138
+ error = nil
98
139
 
99
- private
100
- def login(config, &block)
101
- Parallel.map(config.hostlist, in_threads: config.parallel) do |hostinfo|
102
140
  begin
103
141
  buffer = StringIO.new
104
142
  hostname = hostinfo[:name]
105
143
 
106
144
  loggers = []
107
- loggers << ((config.parallel > 1)? buffer : $stdout)
145
+ loggers << ((config.jobs > 1)? buffer : $stdout)
108
146
  loggers << File.expand_path(File.join(config.logdir, "#{hostname}.log"), ENV['PWD']) if config.logdir
109
147
 
110
148
  session = Xlogin.get(hostinfo.merge(log: loggers))
111
149
  session.enable if config.enable && hostinfo[:enable]
112
150
 
113
- block.call(session)
151
+ command_lines = ['', *config.args.flat_map { |e| e.split(';') }].map(&:strip)
152
+ command_lines.each { |line| session.cmd(line) }
153
+
154
+ block.call(session) if block
114
155
  rescue => e
115
- lines = (config.parallel > 1)? ["\n#{hostname}\t| [Error] #{e}"] : ["\n[Error] #{e}"]
116
- lines.each { |line| $stderr.print "#{line.chomp}\n" }
117
- end
156
+ error = e
157
+ ensure
158
+ if config.jobs > 1
159
+ prefix = "#{hostname.to_s.ljust(width)} |"
160
+ output = buffer.string.lines.map { |line| prefix + line.chomp.gsub("\r", '') + "\n" }.join
161
+ $stdout.print output
162
+ $stderr.print prefix + "[Error] #{error}\n" if error
163
+ else
164
+ $stderr.print "[Error] #{error}\n" if error
165
+ end
118
166
 
119
- if config.parallel > 1
120
- lines = buffer.string.lines.map { |line| "#{hostname}\t| " + line.gsub("\r", '') }
121
- lines.each { |line| $stdout.print "#{line.chomp}\n" }
122
167
  end
168
+
169
+ session
123
170
  end
124
171
  end
125
172
 
@@ -1,3 +1,3 @@
1
1
  module Xlogin
2
- VERSION = "0.8.3"
2
+ VERSION = "0.8.4"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xlogin
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.3
4
+ version: 0.8.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - haccht
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-05-10 00:00:00.000000000 Z
11
+ date: 2018-05-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: net-telnet