xlogin 0.10.9 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/lib/xlogin/cli.rb +54 -103
  3. data/lib/xlogin/version.rb +1 -1
  4. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a3f7a65ed48d5aa25928be4d31714657faa282f21fe317908c6da68f61ce9ab9
4
- data.tar.gz: 4fc355338732d7df48ef787a152171460c334c3e9494c251e3472c4c892af84a
3
+ metadata.gz: 7597d72f3e0fa7ac0983b0a40841d05e97d4ca089586e941dc4d9fa832d33ffe
4
+ data.tar.gz: 6db438d3ef936a944eeca47856e62f1d0838b80d9b1e5327e37ed2245a5fb7bb
5
5
  SHA512:
6
- metadata.gz: 13df83043b60975e0e17a505b0568aec8c779ff321ba512fbecf1bc654a80d044a5221ca9b69db048c3f1b6412706da05cc013b9ec5ff8c82fcadbb76988202f
7
- data.tar.gz: '063955b5da490638837d0bc04f35c867ba4fe4861d56862854a06939f11d56b94afafec329c0bebc339894e649b34ee509b94b95cb07dfe859c2de9d272f48e6'
6
+ metadata.gz: 4755b483886ba979e6e8fb040923b5b7c53f6e8364eff68184dccb96011d62a39e23570825bcad3e45980318e7b1b6e91797568466f632b16f580ae03decd472
7
+ data.tar.gz: a68ea30752d1f4c0223dedd8a5e4d4b279d5230231b6c45a57d382a5b0009c4c3ff8285a1ea2a88aecd95759087099e854d6cb41346276963675769fa2d9eb1c
data/lib/xlogin/cli.rb CHANGED
@@ -4,7 +4,6 @@ require 'optparse'
4
4
  require 'ostruct'
5
5
  require 'parallel'
6
6
  require 'readline'
7
- require 'socket'
8
7
  require 'stringio'
9
8
 
10
9
  module Xlogin
@@ -16,154 +15,106 @@ module Xlogin
16
15
  def self.run(args = ARGV)
17
16
  config = getopts(args)
18
17
  client = Xlogin::CLI.new
19
- client.method(config.taskname).call(config)
18
+ client.method(config.task.first).call(config)
20
19
  end
21
20
 
22
21
  def self.getopts(args)
23
22
  config = OpenStruct.new(
24
- jobs: 1,
25
- port: 8080,
26
- taskname: :tty,
27
- inventory: nil,
28
- templates: [],
29
- )
23
+ jobs: 1,
24
+ auth: false,
25
+ task: [:tty, nil],
26
+ inventory: DEFAULT_INVENTORY_FILE,
27
+ template_dir: DEFAULT_TEMPLATE_DIR,
28
+ )
30
29
 
31
30
  parser = OptionParser.new
32
31
  parser.banner = "#{File.basename($0)} HOST_PATTERN [Options]"
33
32
  parser.version = Xlogin::VERSION
34
33
 
35
- parser.on('-i PATH', '--inventory', String, 'The PATH to the inventory file(default: $HOME/.xloginrc).') { |v| config.inventory = v }
36
- parser.on('-t PATH', '--template', String, 'The PATH to the template file.') { |v| config.templates << v }
37
- parser.on('-T DIRECTORY', '--template-dir', String, 'The DIRECTORY of the template files.') { |v| config.templates += Dir.glob(File.join(v, '*.rb')) }
38
- parser.on('-L [DIRECTORY]', '--log-dir', String, 'The DIRECTORY of the log files(default: $PWD).') { |v| config.logdir = v || '.' }
34
+ parser.on('-i PATH', '--inventory', String, 'The PATH to the inventory file (default: $HOME/.xloginrc).') { |v| config.inventory = v }
35
+ parser.on('-T PATH', '--template', String, 'The PATH to the template dir (default: $HOME/.xlogin.d).') { |v| config.template_dir = v }
36
+ parser.on('-L [DIRECTORY]', '--log-dir', String, 'The PATH to the log dir (default: $PWD).') { |v| config.logdir = v || '.' }
39
37
 
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 }
38
+ parser.on('-l', '--list', TrueClass, 'List the inventory.') { |v| config.task = [:list, nil] }
39
+ parser.on('-t', '--tty', TrueClass, 'Allocate a pseudo-tty.') { |v| config.task = [:tty, nil] }
40
+ parser.on('-e COMMAND', '--exec', 'Execute commands and quit.') { |v| config.task = [:exec, v] }
43
41
 
44
- parser.on('-p NUM', '--port', Integer, 'Run as server on specified port(default: 8080).') { |v| config.taskname = :listen; config.port = v }
45
42
  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 }
48
- parser.on('-y', '--assume-yes', TrueClass, 'Automatically answer yes to prompts.') { |v| config.authorize = v }
49
-
50
- begin
51
- args = parser.parse!(args)
52
- host = args.shift
53
- config.args = args
54
-
55
- Xlogin.configure do
56
- config.inventory ||= DEFAULT_INVENTORY_FILE
57
- if config.templates.empty?
58
- generate_templates(DEFAULT_TEMPLATE_DIR) unless File.exist?(DEFAULT_TEMPLATE_DIR)
59
- config.templates += Dir.glob(File.join(DEFAULT_TEMPLATE_DIR, '*.rb'))
60
- end
61
-
62
- authorize(config.authorize)
63
- source(File.expand_path(config.inventory, ENV['PWD']))
64
- template_file(*config.templates.map { |file| File.expand_path(file, ENV['PWD']) })
65
- end
66
-
67
- config.hostlist = Xlogin.list(*host.to_s.split(/\s+/))
68
- raise "No host found: `#{host}`" if config.hostlist.empty?
69
- rescue => e
70
- $stderr.puts e, '', parser
71
- exit 1
72
- end
73
-
74
- config
43
+ parser.on('-y', '--assume-yes', TrueClass, 'Automatically answer yes to prompts.') { |v| config.auth = v }
44
+ parser.on('-E', '--enable', TrueClass, 'Try to gain enable priviledge.') { |v| config.enable = v }
45
+
46
+ parser.parse!(args)
47
+ Xlogin.configure do
48
+ authorize(config.auth)
49
+ source(File.expand_path(config.inventory, ENV['PWD']))
50
+ template_dir(File.expand_path(config.template_dir, ENV['PWD']))
51
+ end
52
+
53
+ config.hosts = Xlogin.list(*args)
54
+ raise "No host found: `#{args.join(', ')}`" if config.hosts.empty?
55
+
56
+ return config
57
+ rescue => e
58
+ $stderr.puts e, '', parser
59
+ exit 1
75
60
  end
76
61
 
77
62
  def list(config)
78
- list = config.hostlist.map { |e| e[:name] }.uniq.sort
79
- $stdout.puts list
63
+ $stdout.puts config.hosts.map { |e| e[:name] }.sort.uniq
80
64
  end
81
65
 
82
66
  def tty(config)
83
67
  Signal.trap(:INT) { exit 0 }
84
68
 
85
- list = config.hostlist.sort_by { |e| e[:name] }
86
- list.each do |target|
87
- unless list.size == 1
88
- case resp = Readline.readline(">> #{target[:name]}(Y/n)? ", false).strip
69
+ config.hosts.each do |hostinfo|
70
+ unless config.hosts.size == 1
71
+ case resp = Readline.readline(">> #{hostinfo[:name]}(Y/n)? ", false).strip
89
72
  when /^y(es)?$/i, ''
90
73
  when /^n(o)?$/i then next
91
74
  else redo
92
75
  end
93
76
  end
94
77
 
95
- config.jobs = 1
96
- config.hostlist = [target]
78
+ $stdout.puts "Trying #{hostinfo[:name]}...", "Escape character is '^]'."
79
+ tty_config = OpenStruct.new(config.to_h.merge(jobs: 1, hosts: [hostinfo]))
97
80
 
98
- $stdout.puts "Trying #{target[:name]}...", "Escape character is '^]'."
99
- session, _ = exec(config)
81
+ session, _ = exec(tty_config)
100
82
  session.interact!
101
83
  end
102
84
  end
103
85
 
104
- def listen(config)
105
- Signal.trap(:INT) { exit 0 }
106
- config.jobs = config.hostlist.size
107
-
108
- width = config.hostlist.map { |e| e[:name].length }.max
109
- sessions = exec(config).compact
110
-
111
- $stdout.puts "", ""
112
- $stdout.puts "=> Started xlogin server on port=#{config.port}"
113
- $stdout.puts "=> Ctrl-C to shutdown"
114
-
115
- server = TCPServer.open(config.port)
116
- socket = server.accept
117
- while line = socket.gets
118
- Parallel.each(sessions, in_threads: sessions.size) do |session|
119
- resp = session.cmd(line.chomp)
120
- prefix = "#{session.name.to_s.ljust(width)} |"
121
- output = resp.to_s.lines.map { |line| prefix + line.chomp.gsub("\r", '') + "\n" }.join
122
- socket.print output
123
- $stdout.print output if config.jobs > 1
124
- end
125
- end
126
- ensure
127
- socket.close if socket
128
- server.close if server
129
- end
130
-
131
- def exec(config, &block)
86
+ def exec(config)
132
87
  Signal.trap(:INT) { exit 0 }
133
88
 
134
- width = config.hostlist.map { |e| e[:name].length }.max
135
- Parallel.map(config.hostlist, in_threads: config.jobs) do |hostinfo|
89
+ max_width = config.hosts.map { |e| e[:name].length }.max
90
+ Parallel.map(config.hosts, in_threads: config.jobs) do |hostinfo|
136
91
  session = nil
137
92
  error = nil
138
93
 
139
94
  begin
140
95
  buffer = StringIO.new
141
- hostname = hostinfo[:name]
142
96
 
143
97
  loggers = []
144
98
  loggers << ((config.jobs > 1)? buffer : $stdout)
145
- loggers << File.expand_path(File.join(config.logdir, "#{hostname}.log"), ENV['PWD']) if config.logdir
99
+ loggers << File.expand_path(File.join(config.logdir, "#{hostinfo[:name]}.log"), ENV['PWD']) if config.logdir
146
100
 
147
101
  session = Xlogin.get(hostinfo.merge(log: loggers))
148
102
  session.enable if config.enable && hostinfo[:enable]
149
103
 
150
- command_lines = ['', *config.args.flat_map { |e| e.split(';') }].map(&:strip)
104
+ command_lines = ['', *config.task.last.to_s.split(';').map(&:strip)]
151
105
  command_lines.each { |line| session.cmd(line) }
152
-
153
- block.call(session) if block
154
- rescue => e
155
- error = e
156
- ensure
157
- if config.jobs > 1
158
- prefix = "#{hostname.to_s.ljust(width)} |"
159
- output = buffer.string.lines.map { |line| prefix + line.chomp.gsub("\r", '') + "\n" }.join
160
- $stdout.print output
161
- $stderr.print prefix + "[Error] #{error}\n" if error
162
- else
163
- $stderr.print "[Error] #{error}\n" if error
164
- end
165
-
166
- end
106
+ rescue => err
107
+ error = err
108
+ end
109
+
110
+ if config.jobs > 1
111
+ prefix = "#{hostinfo[:name].to_s.ljust(max_width)} |"
112
+ output = buffer.string.lines.map { |line| prefix + line.chomp.gsub("\r", '') + "\n" }.join
113
+ $stdout.print output
114
+ $stderr.print prefix + "[Error] #{error}\n" if error
115
+ else
116
+ $stderr.print "[Error] #{error}\n" if error
117
+ end
167
118
 
168
119
  session
169
120
  end
@@ -1,3 +1,3 @@
1
1
  module Xlogin
2
- VERSION = "0.10.9"
2
+ VERSION = "0.11.0"
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.10.9
4
+ version: 0.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - haccht
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-01-23 00:00:00.000000000 Z
11
+ date: 2019-01-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: net-telnet