xlogin 0.3.7 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +6 -2
- data/bin/cmd_exec +3 -4
- data/bin/xlogin +3 -4
- data/lib/xlogin.rb +13 -25
- data/lib/xlogin/firmware_factory.rb +19 -8
- data/lib/xlogin/rake_task.rb +31 -27
- data/lib/xlogin/session.rb +19 -0
- data/lib/xlogin/templates/ios.rb +36 -0
- data/lib/xlogin/templates/iosxr.rb +22 -0
- data/lib/xlogin/templates/junos.rb +19 -0
- data/lib/xlogin/templates/sros.rb +30 -0
- data/lib/xlogin/{firmware_templates → templates}/vyos.rb +0 -2
- data/lib/xlogin/version.rb +1 -1
- metadata +7 -8
- data/lib/xlogin/rspec.rb +0 -80
- data/lib/xlogin/rspec/context.rb +0 -58
- data/lib/xlogin/rspec/resource.rb +0 -31
- data/lib/xlogin/scanner.rb +0 -88
- data/lib/xlogin/thread_safe.rb +0 -25
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 01f1dcfc4664204170ef0065396788768d5ac676
|
4
|
+
data.tar.gz: a4bf5740a6ca77b67a64497b7cded0942e689f9e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e8bf704c7af2aef3f090951d94088d8ec49c985eff1226333be5d540a0171e1022efdb7cad142c5642d11024418c91d0e695f7c01d0dac4f388454433f550706
|
7
|
+
data.tar.gz: fc21595ec2a4acb907eb9f6dfd77154f3097b8afff7e7e21fd1548e8ca14d617e183a0bd7f56de3238006975f588f2f3a43ca2c4d62216c71c0d513ac233be68
|
data/.gitignore
CHANGED
@@ -56,5 +56,9 @@ build-iPhoneSimulator/
|
|
56
56
|
# End of https://www.gitignore.io/api/ruby
|
57
57
|
/lib/xlogin/.xloginrc
|
58
58
|
/lib/xlogin/_xloginrc
|
59
|
-
/lib/xlogin/
|
60
|
-
!/lib/xlogin/
|
59
|
+
/lib/xlogin/templates/*
|
60
|
+
!/lib/xlogin/templates/vyos.rb
|
61
|
+
!/lib/xlogin/templates/junos.rb
|
62
|
+
!/lib/xlogin/templates/ios.rb
|
63
|
+
!/lib/xlogin/templates/iosxr.rb
|
64
|
+
!/lib/xlogin/templates/sros.rb
|
data/bin/cmd_exec
CHANGED
@@ -46,7 +46,6 @@ module Xlogin
|
|
46
46
|
opt.on('-H', 'Display hostnames for each response.') { |v| options[:H] = v }
|
47
47
|
|
48
48
|
opt.on('-f FILE', 'Read target hostnames from FILE.') { |v| options[:f] = v }
|
49
|
-
opt.on('-r FILE', 'Load extention library.') { |v| options[:r] = v }
|
50
49
|
|
51
50
|
opt.on('-x VALUE', 'Read commands from VALUE.') { |v| options[:x] = v }
|
52
51
|
opt.on('-c VALUE') { |v| options[:c] = v }
|
@@ -74,9 +73,9 @@ module Xlogin
|
|
74
73
|
usage if options[:x].nil? and options[:c].nil?
|
75
74
|
usage if options[:f].nil? && args.empty?
|
76
75
|
|
77
|
-
|
78
|
-
|
79
|
-
|
76
|
+
source_dirs = [ENV['HOME'], Dir.pwd]
|
77
|
+
source_files = source_dirs.flat_map { |dir| [File.join(dir, '_xloginrc'), File.join(dir, '.xloginrc')] }
|
78
|
+
Xlogin.factory.source(*source_files)
|
80
79
|
|
81
80
|
size = (options[:p] || 1).to_i
|
82
81
|
interval = (options[:i] || 0).to_i
|
data/bin/xlogin
CHANGED
@@ -12,7 +12,6 @@ module Xlogin
|
|
12
12
|
opt = OptionParser.new
|
13
13
|
opt.on('-e', '--enable', 'Try to gain enable priviledge.') { |v| options[:e] = v }
|
14
14
|
opt.on('-l', '--log', 'Enable logging.') { |v| options[:l] = v }
|
15
|
-
opt.on('-r FILE', 'Load extention library.') { |v| options[:r] = v }
|
16
15
|
|
17
16
|
opt.on( '--list', 'List all devices.') { |v| options[:list] = v }
|
18
17
|
|
@@ -34,9 +33,9 @@ module Xlogin
|
|
34
33
|
def self.run(args = ARGV)
|
35
34
|
options, args = getopts(args)
|
36
35
|
|
37
|
-
|
38
|
-
|
39
|
-
|
36
|
+
source_dirs = [ENV['HOME'], Dir.pwd]
|
37
|
+
source_files = source_dirs.flat_map { |dir| [File.join(dir, '_xloginrc'), File.join(dir, '.xloginrc')] }
|
38
|
+
Xlogin.factory.source(*source_files)
|
40
39
|
|
41
40
|
if options[:list]
|
42
41
|
puts Xlogin.factory.list.map { |e| "#{e[:name]}\t#{e[:type]}" }
|
data/lib/xlogin.rb
CHANGED
@@ -8,29 +8,24 @@ module Xlogin
|
|
8
8
|
|
9
9
|
class GeneralError < StandardError; end
|
10
10
|
|
11
|
+
# default template directory
|
12
|
+
TEMPLATE_DIR = File.join(File.dirname(__FILE__), 'xlogin', 'templates')
|
13
|
+
|
11
14
|
class << self
|
12
15
|
def factory
|
16
|
+
@factory ||= configure_factory
|
17
|
+
end
|
18
|
+
|
19
|
+
def configure_factory(*template_dirs)
|
13
20
|
unless @factory
|
14
21
|
@factory = Xlogin::FirmwareFactory.instance
|
15
22
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
@factory.load_template_file(File.join(
|
20
|
-
end
|
21
|
-
|
22
|
-
source_dirs = [
|
23
|
-
ENV['HOME'],
|
24
|
-
ENV['XLOGIN_HOME'],
|
25
|
-
Dir.pwd
|
26
|
-
]
|
27
|
-
|
28
|
-
source_dirs.compact.uniq.each do |dir|
|
29
|
-
@factory.source(File.join(dir, '.xloginrc'))
|
30
|
-
@factory.source(File.join(dir, '_xloginrc'))
|
23
|
+
template_dirs = [TEMPLATE_DIR, File.join(Dir.pwd, 'templates'), *template_dirs]
|
24
|
+
template_dirs.compact.uniq.each do |dir|
|
25
|
+
next unless FileTest.directory?(dir)
|
26
|
+
@factory.load_template_file(*Dir.glob(File.join(dir, '*.rb')))
|
31
27
|
end
|
32
28
|
end
|
33
|
-
|
34
29
|
@factory
|
35
30
|
end
|
36
31
|
|
@@ -41,11 +36,8 @@ module Xlogin
|
|
41
36
|
factory.set_template(name, template)
|
42
37
|
end
|
43
38
|
|
44
|
-
def alias(new_name,
|
45
|
-
|
46
|
-
raise Xlogin::GeneralError.new("'#{original_name}' not found") unless template
|
47
|
-
|
48
|
-
factory.set_template(new_name, template)
|
39
|
+
def alias(new_name, name)
|
40
|
+
factory.alias_template(new_name, name)
|
49
41
|
end
|
50
42
|
|
51
43
|
def get(hostname, args = {})
|
@@ -59,8 +51,4 @@ module Xlogin
|
|
59
51
|
end
|
60
52
|
end
|
61
53
|
|
62
|
-
# do not remove this line!
|
63
|
-
# initialize Xlogin systems and load related modules beforehand.
|
64
|
-
Xlogin.factory
|
65
|
-
|
66
54
|
end
|
@@ -11,13 +11,17 @@ module Xlogin
|
|
11
11
|
def initialize
|
12
12
|
@database = Hash.new
|
13
13
|
@templates = Hash.new
|
14
|
+
@aliases = Hash.new
|
14
15
|
end
|
15
16
|
|
16
|
-
def load_template_file(
|
17
|
-
|
17
|
+
def load_template_file(*files)
|
18
|
+
files.each do |file|
|
19
|
+
require file if file =~ /.rb$/
|
20
|
+
end
|
18
21
|
end
|
19
22
|
|
20
23
|
def get_template(name)
|
24
|
+
name = @aliases[name] || name
|
21
25
|
@templates[name.to_s.downcase]
|
22
26
|
end
|
23
27
|
|
@@ -29,11 +33,15 @@ module Xlogin
|
|
29
33
|
@templates.keys
|
30
34
|
end
|
31
35
|
|
32
|
-
def
|
33
|
-
|
36
|
+
def alias_template(new_name, name)
|
37
|
+
@aliases[new_name.to_s.downcase] = name
|
38
|
+
end
|
34
39
|
|
35
|
-
|
36
|
-
|
40
|
+
def source(*files)
|
41
|
+
files.compact.uniq.each do |file|
|
42
|
+
next unless File.exist?(file)
|
43
|
+
instance_eval(IO.read(file))
|
44
|
+
end
|
37
45
|
end
|
38
46
|
|
39
47
|
def get(name)
|
@@ -55,7 +63,10 @@ module Xlogin
|
|
55
63
|
opts = args.reduce({}) { |a, (k, v)| a.merge(k.to_s.downcase.to_sym => v) }
|
56
64
|
raise Xlogin::GeneralError.new("Host not found: #{args}") unless uri && type
|
57
65
|
|
58
|
-
|
66
|
+
template = get_template(type)
|
67
|
+
raise Xlogin::GeneralError.new("Template not defined: #{type}") unless template
|
68
|
+
|
69
|
+
session = template.dup.run(uri, opts)
|
59
70
|
session.name = name if name
|
60
71
|
session
|
61
72
|
end
|
@@ -68,7 +79,7 @@ module Xlogin
|
|
68
79
|
end
|
69
80
|
|
70
81
|
def method_missing(name, *args, &block)
|
71
|
-
super unless caller_locations.first.label
|
82
|
+
super unless caller_locations.first.label =~ /source/ and args.size >= 2
|
72
83
|
|
73
84
|
type = name.to_s.downcase
|
74
85
|
name = args.shift
|
data/lib/xlogin/rake_task.rb
CHANGED
@@ -9,9 +9,18 @@ module Xlogin
|
|
9
9
|
class << self
|
10
10
|
include Rake::DSL
|
11
11
|
|
12
|
-
def
|
13
|
-
|
12
|
+
def mutex
|
13
|
+
@mutex ||= Mutex.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def source(file, &block)
|
17
|
+
Xlogin.factory.source(file)
|
18
|
+
hostnames = Xlogin.factory.list.map { |e| e[:name] }
|
19
|
+
bulk(hostnames, &block)
|
20
|
+
end
|
14
21
|
|
22
|
+
def bulk(names, &block)
|
23
|
+
names = names.map(&:strip).grep(/^\s*[^#]/)
|
15
24
|
namecount = names.uniq.inject({}) { |a, e| a.merge(e => names.count(e)) }
|
16
25
|
duplicate = namecount.keys.select { |name| namecount[name] > 1 }
|
17
26
|
raise Xlogin::GeneralError.new("Duplicate hosts found - #{duplicate.join(', ')}") unless duplicate.empty?
|
@@ -21,15 +30,11 @@ module Xlogin
|
|
21
30
|
|
22
31
|
names.each do |name|
|
23
32
|
desc "#{description} (#{name})"
|
24
|
-
RakeTask.new(name,
|
33
|
+
RakeTask.new(name, &block)
|
25
34
|
end
|
26
35
|
end
|
27
36
|
end
|
28
37
|
|
29
|
-
def mutex
|
30
|
-
@mutex ||= Mutex.new
|
31
|
-
end
|
32
|
-
|
33
38
|
def current_namespace
|
34
39
|
path = Rake.application.current_scope.path
|
35
40
|
|
@@ -46,23 +51,24 @@ module Xlogin
|
|
46
51
|
|
47
52
|
|
48
53
|
attr_reader :name
|
54
|
+
attr_accessor :xlogin_opts
|
49
55
|
attr_accessor :fail_on_error
|
50
56
|
attr_accessor :silent
|
51
57
|
attr_accessor :lockfile
|
52
58
|
attr_accessor :logfile
|
53
59
|
attr_accessor :uncomment
|
54
60
|
|
55
|
-
def initialize(name
|
61
|
+
def initialize(name)
|
56
62
|
@name = name
|
63
|
+
@xlogin_opts = Xlogin.factory.get(name) || {}
|
64
|
+
@session = nil
|
65
|
+
@taskrunner = nil
|
66
|
+
|
57
67
|
@fail_on_error = true
|
58
68
|
@silent = Rake.application.options.silent
|
59
69
|
@lockfile = nil
|
60
70
|
@logfile = nil
|
61
71
|
@uncomment = false
|
62
|
-
@xlogin_opts = xlogin_opts
|
63
|
-
|
64
|
-
@session = nil
|
65
|
-
@taskrunner = nil
|
66
72
|
|
67
73
|
yield(self) if block_given?
|
68
74
|
define
|
@@ -86,9 +92,7 @@ module Xlogin
|
|
86
92
|
private
|
87
93
|
def define
|
88
94
|
RakeTask.current_namespace do
|
89
|
-
|
90
|
-
|
91
|
-
desc description
|
95
|
+
desc Rake.application.last_description || "Run '#{RakeTask.current_namespace}'"
|
92
96
|
Rake.application.last_description = nil if uncomment
|
93
97
|
|
94
98
|
if lockfile
|
@@ -108,24 +112,29 @@ module Xlogin
|
|
108
112
|
end
|
109
113
|
|
110
114
|
def run_task
|
111
|
-
|
115
|
+
raise Xlogin::GeneralError.new("missing xlogin_opts to connect to #{name}") unless @xlogin_opts[:type] && @xlogin_opts[:uri]
|
116
|
+
|
117
|
+
loggers = [@xlogin_opts[:log]].flatten.compact
|
112
118
|
loggers << $stdout unless silent || Rake.application.options.always_multitask
|
113
119
|
|
114
120
|
if logfile
|
115
121
|
mkdir_p(File.dirname(logfile), verbose: Rake.application.options.trace)
|
116
|
-
loggers << logfile
|
122
|
+
loggers << logfile
|
117
123
|
end
|
118
124
|
|
119
125
|
@xlogin_opts[:log] = loggers unless loggers.empty?
|
120
126
|
|
121
127
|
begin
|
122
|
-
@session = Xlogin.
|
123
|
-
@session
|
128
|
+
@session = Xlogin.factory.build(@xlogin_opts)
|
129
|
+
if @session && @taskrunner
|
130
|
+
@session.extend(SessionExt)
|
124
131
|
|
125
|
-
|
126
|
-
|
132
|
+
# pass RakeTask#safe_puts method to the session instance.
|
133
|
+
method_proc = method(:safe_puts)
|
134
|
+
@session.define_singleton_method(:safe_puts) { |*args| method_proc.call(*args) }
|
127
135
|
|
128
|
-
|
136
|
+
@taskrunner.call(@session) if @taskrunner && @session
|
137
|
+
end
|
129
138
|
rescue => e
|
130
139
|
raise e if fail_on_error
|
131
140
|
safe_puts(e, io: $stderr, force: true)
|
@@ -160,14 +169,9 @@ module Xlogin
|
|
160
169
|
cmd(my_command)
|
161
170
|
else
|
162
171
|
cmd(my_command)
|
163
|
-
# retry thid command
|
164
172
|
readline(command)
|
165
173
|
end
|
166
174
|
end
|
167
|
-
|
168
|
-
def sync(&block)
|
169
|
-
RakeTask.mutex.synchronize(&block) if block
|
170
|
-
end
|
171
175
|
end
|
172
176
|
|
173
177
|
end
|
data/lib/xlogin/session.rb
CHANGED
@@ -20,6 +20,25 @@ module Xlogin
|
|
20
20
|
@logger = update_logger
|
21
21
|
end
|
22
22
|
|
23
|
+
def thread_safe(timeout: @timeout, maximum_retry: 1)
|
24
|
+
@safe_session = self
|
25
|
+
@safe_session_mutex ||= Mutex.new
|
26
|
+
|
27
|
+
Timeout.timeout(timeout) do
|
28
|
+
@safe_session_mutex.synchronize do
|
29
|
+
retry_count = 0
|
30
|
+
begin
|
31
|
+
@safe_session ||= Xlogin.get(@host, @opts)
|
32
|
+
yield @safe_session
|
33
|
+
rescue Errno::ECONNRESET => e
|
34
|
+
raise e unless (retry_count += 1) < maximum_retry
|
35
|
+
@safe_session = nil
|
36
|
+
retry
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
23
42
|
def enable_log(out = $stdout)
|
24
43
|
enabled = @loglist.include?(out)
|
25
44
|
unless enabled
|
@@ -0,0 +1,36 @@
|
|
1
|
+
Xlogin.configure :ios do |os|
|
2
|
+
os.timeout(300)
|
3
|
+
os.prompt(/[>$#]/)
|
4
|
+
os.prompt(/yes \/ no: /) do
|
5
|
+
puts opts[:force] ? 'y' : 'n'
|
6
|
+
end
|
7
|
+
|
8
|
+
os.bind(:login) do |password|
|
9
|
+
waitfor(/Password: /) && puts(password)
|
10
|
+
waitfor
|
11
|
+
end
|
12
|
+
|
13
|
+
os.bind(:enable) do |password|
|
14
|
+
puts('enable')
|
15
|
+
waitfor(/Password: /) && puts(password)
|
16
|
+
waitfor
|
17
|
+
end
|
18
|
+
|
19
|
+
os.bind(:config) do
|
20
|
+
begin
|
21
|
+
cmd('terminal length 0')
|
22
|
+
resp = cmd('show run')
|
23
|
+
resp.lines[4..-2].join.to_s
|
24
|
+
ensure
|
25
|
+
cmd('exit')
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
os.bind(:save) do
|
30
|
+
begin
|
31
|
+
cmd('write memory')
|
32
|
+
ensure
|
33
|
+
cmd('exit')
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
Xlogin.configure :iosxr do |os|
|
2
|
+
os.timeout(300)
|
3
|
+
os.prompt(/#\z/)
|
4
|
+
|
5
|
+
os.bind(:login) do |*args|
|
6
|
+
username, password = *args
|
7
|
+
waitfor(/Username: /) && puts(username)
|
8
|
+
waitfor(/Password: /) && puts(password)
|
9
|
+
waitfor
|
10
|
+
end
|
11
|
+
|
12
|
+
os.bind(:config) do
|
13
|
+
begin
|
14
|
+
cmd('terminal width 0')
|
15
|
+
cmd('terminal length 0')
|
16
|
+
resp = cmd('show run')
|
17
|
+
resp.lines[3..-3].join.to_s
|
18
|
+
ensure
|
19
|
+
cmd('exit')
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
Xlogin.configure :junos do |os|
|
2
|
+
os.timeout(300)
|
3
|
+
os.prompt(/[>#] \z/)
|
4
|
+
|
5
|
+
os.bind(:login) do |*args|
|
6
|
+
username, password = *args
|
7
|
+
waitfor(/login:\s/) && puts(username)
|
8
|
+
waitfor(/Password:/) && puts(password)
|
9
|
+
waitfor
|
10
|
+
end
|
11
|
+
|
12
|
+
os.bind(:config) do
|
13
|
+
begin
|
14
|
+
cmd('show configuration | no-more')
|
15
|
+
ensure
|
16
|
+
cmd('exit')
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
Xlogin.configure :sros do |os|
|
2
|
+
os.timeout(300)
|
3
|
+
os.prompt(/[>$#] /)
|
4
|
+
os.prompt(/y\/n:/) do
|
5
|
+
puts opts[:force] ? 'y' : 'n'
|
6
|
+
end
|
7
|
+
|
8
|
+
os.bind(:login) do |*args|
|
9
|
+
username, password = *args
|
10
|
+
waitfor(/Login:\s?/) && puts(username)
|
11
|
+
waitfor(/Password:\s?/) && puts(password)
|
12
|
+
waitfor
|
13
|
+
end
|
14
|
+
|
15
|
+
os.bind(:enable_admin) do |password|
|
16
|
+
puts('enable-admin')
|
17
|
+
waitfor(/Password:\s?/) && puts(password)
|
18
|
+
waitfor
|
19
|
+
end
|
20
|
+
|
21
|
+
os.bind(:config) do
|
22
|
+
begin
|
23
|
+
cmd('environment no more')
|
24
|
+
resp = cmd('admin display-config')
|
25
|
+
resp.lines[2..-2].join.to_s
|
26
|
+
ensure
|
27
|
+
cmd('logout')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/xlogin/version.rb
CHANGED
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.
|
4
|
+
version: 0.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- haccht
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-07-
|
11
|
+
date: 2017-07-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -73,17 +73,16 @@ files:
|
|
73
73
|
- lib/xlogin/delegator.rb
|
74
74
|
- lib/xlogin/firmware.rb
|
75
75
|
- lib/xlogin/firmware_factory.rb
|
76
|
-
- lib/xlogin/firmware_templates/vyos.rb
|
77
76
|
- lib/xlogin/gateway.rb
|
78
77
|
- lib/xlogin/rake_task.rb
|
79
|
-
- lib/xlogin/rspec.rb
|
80
|
-
- lib/xlogin/rspec/context.rb
|
81
|
-
- lib/xlogin/rspec/resource.rb
|
82
|
-
- lib/xlogin/scanner.rb
|
83
78
|
- lib/xlogin/session.rb
|
84
79
|
- lib/xlogin/ssh.rb
|
85
80
|
- lib/xlogin/telnet.rb
|
86
|
-
- lib/xlogin/
|
81
|
+
- lib/xlogin/templates/ios.rb
|
82
|
+
- lib/xlogin/templates/iosxr.rb
|
83
|
+
- lib/xlogin/templates/junos.rb
|
84
|
+
- lib/xlogin/templates/sros.rb
|
85
|
+
- lib/xlogin/templates/vyos.rb
|
87
86
|
- lib/xlogin/version.rb
|
88
87
|
- xlogin.gemspec
|
89
88
|
homepage: https://github.com/haccht/xlogin
|
data/lib/xlogin/rspec.rb
DELETED
@@ -1,80 +0,0 @@
|
|
1
|
-
require 'rspec'
|
2
|
-
require 'stringio'
|
3
|
-
|
4
|
-
require 'xlogin/rspec/context'
|
5
|
-
require 'xlogin/rspec/resource'
|
6
|
-
|
7
|
-
module Xlogin
|
8
|
-
|
9
|
-
module RSpecResourceHelper
|
10
|
-
def node(name)
|
11
|
-
Resources::NodeResource.new(name)
|
12
|
-
end
|
13
|
-
|
14
|
-
def command(str)
|
15
|
-
Resources::CommandResource.new(str)
|
16
|
-
end
|
17
|
-
|
18
|
-
def backend
|
19
|
-
unless @backend
|
20
|
-
context = Xlogin::Contexts.from_example(self)
|
21
|
-
@backend = context.session if context && context.respond_to?(:session)
|
22
|
-
end
|
23
|
-
@backend
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
module RSpecHelper
|
28
|
-
def current_context
|
29
|
-
@context
|
30
|
-
end
|
31
|
-
|
32
|
-
def method_missing(name, *args, &block)
|
33
|
-
if current_context.respond_to?(name)
|
34
|
-
current_context.send(name, *args, &block)
|
35
|
-
else
|
36
|
-
super(name, *args, &block)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
end
|
42
|
-
|
43
|
-
|
44
|
-
include Xlogin::RSpecResourceHelper
|
45
|
-
module RSpec
|
46
|
-
Matchers.define :match do |expected|
|
47
|
-
match do |actual|
|
48
|
-
response = actual.to_s.lines.slice(1..-1).join
|
49
|
-
expected =~ response
|
50
|
-
end
|
51
|
-
|
52
|
-
failure_message do |actual|
|
53
|
-
message = StringIO.new
|
54
|
-
message.puts "Expect response to match #{expected.inspect}"
|
55
|
-
message.puts "Result:"
|
56
|
-
message.puts actual.to_s.lines.slice(1..-2).map { |line| " +#{line}" }
|
57
|
-
message.string
|
58
|
-
end
|
59
|
-
|
60
|
-
failure_message_when_negated do |actual|
|
61
|
-
message = StringIO.new
|
62
|
-
message.puts "Expect response not to match #{expected.inspect}"
|
63
|
-
message.puts "Result:"
|
64
|
-
message.puts actual.to_s.lines.slice(1..-2).map { |line| " +#{line}" }
|
65
|
-
message.string
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
configure do |config|
|
70
|
-
config.include Xlogin::RSpecHelper
|
71
|
-
|
72
|
-
config.before(:all) do
|
73
|
-
@context = Xlogin::Contexts.from_example(self.class)
|
74
|
-
end
|
75
|
-
|
76
|
-
config.before(:each) do
|
77
|
-
@context = Xlogin::Contexts.from_example(RSpec.current_example)
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
data/lib/xlogin/rspec/context.rb
DELETED
@@ -1,58 +0,0 @@
|
|
1
|
-
module Xlogin
|
2
|
-
module Contexts
|
3
|
-
|
4
|
-
class << self
|
5
|
-
def from_example(example)
|
6
|
-
example_group = example.example_group
|
7
|
-
|
8
|
-
node_resource = find_resource(Resources::NodeResource, example_group)
|
9
|
-
command_resource = find_resource(Resources::CommandResource, example_group)
|
10
|
-
|
11
|
-
return nil if node_resource.nil? && command_resource.nil?
|
12
|
-
return NodeContext.new(node_resource.session) if command_resource.nil?
|
13
|
-
|
14
|
-
CommandContext.new(node_resource.session, command_resource.text)
|
15
|
-
end
|
16
|
-
|
17
|
-
def find_resource(klass, example_group)
|
18
|
-
arg = example_group.metadata[:description_args][0]
|
19
|
-
return arg if arg.is_a?(klass)
|
20
|
-
|
21
|
-
parent = example_group.parent_groups[1]
|
22
|
-
find_resource(klass, parent) if parent
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
class NodeContext
|
27
|
-
attr_reader :session
|
28
|
-
|
29
|
-
def initialize(session)
|
30
|
-
@session = session
|
31
|
-
end
|
32
|
-
|
33
|
-
def name
|
34
|
-
@session.name
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
class CommandContext
|
39
|
-
class << self
|
40
|
-
def response_cache
|
41
|
-
@cache ||= {}
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
attr_reader :session, :command
|
46
|
-
|
47
|
-
def initialize(session, command)
|
48
|
-
@session = session
|
49
|
-
@command = command
|
50
|
-
end
|
51
|
-
|
52
|
-
def response
|
53
|
-
self.class.response_cache[[@session.name, @command]] ||= @session.cmd(@command)
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
end
|
58
|
-
end
|
@@ -1,31 +0,0 @@
|
|
1
|
-
module Xlogin
|
2
|
-
module Resources
|
3
|
-
|
4
|
-
class NodeResource
|
5
|
-
def initialize(name)
|
6
|
-
@name = name
|
7
|
-
end
|
8
|
-
|
9
|
-
def session
|
10
|
-
@session ||= Xlogin.get(@name)
|
11
|
-
end
|
12
|
-
|
13
|
-
def to_s
|
14
|
-
"Node '#{session.name}'"
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
class CommandResource
|
19
|
-
attr_reader :text
|
20
|
-
|
21
|
-
def initialize(text)
|
22
|
-
@text = text
|
23
|
-
end
|
24
|
-
|
25
|
-
def to_s
|
26
|
-
"with command '#{text}'"
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
end
|
31
|
-
end
|
data/lib/xlogin/scanner.rb
DELETED
@@ -1,88 +0,0 @@
|
|
1
|
-
require 'xlogin'
|
2
|
-
require 'xlogin/thread_safe'
|
3
|
-
|
4
|
-
module Xlogin
|
5
|
-
|
6
|
-
class Scanner
|
7
|
-
class << self
|
8
|
-
def login_opts(**opts)
|
9
|
-
@login_opts = opts unless opts.empty?
|
10
|
-
@login_opts || {}
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
def initialize
|
15
|
-
@sessions = Hash.new
|
16
|
-
@scan_db = Hash.new
|
17
|
-
@queries = Array.new
|
18
|
-
end
|
19
|
-
|
20
|
-
def ids
|
21
|
-
@scan_db.keys
|
22
|
-
end
|
23
|
-
|
24
|
-
def sessions(&block)
|
25
|
-
hostnames = @queries.map { |_, hostname, _| hostname }.uniq
|
26
|
-
sessions = hostnames.map { |hostname| session(hostname) }
|
27
|
-
sessions.each { |s| block.call(s) } if block
|
28
|
-
sessions
|
29
|
-
end
|
30
|
-
|
31
|
-
def define(id, &block)
|
32
|
-
type = ScanType.new
|
33
|
-
type.instance_eval(&block)
|
34
|
-
|
35
|
-
@scan_db[id] = type
|
36
|
-
end
|
37
|
-
|
38
|
-
def add(id, hostname, *args)
|
39
|
-
@queries << [id, hostname, *args]
|
40
|
-
end
|
41
|
-
|
42
|
-
def scan
|
43
|
-
data = Hash.new
|
44
|
-
cache = Hash.new
|
45
|
-
|
46
|
-
threads = @queries.map do |req_key|
|
47
|
-
Thread.new do
|
48
|
-
id, hostname, *args = *req_key
|
49
|
-
type = @scan_db[id]
|
50
|
-
|
51
|
-
command = type.command.call(*args)
|
52
|
-
content = session(hostname).thread_safe { |s| s.cmd(command) }
|
53
|
-
matched = type.scanner.call(content)
|
54
|
-
|
55
|
-
cache[[hostname, command]] ||= content
|
56
|
-
data[req_key] = matched
|
57
|
-
|
58
|
-
yield(req_key, matched) if block_given?
|
59
|
-
end
|
60
|
-
end
|
61
|
-
threads.each { |th| th.join }
|
62
|
-
|
63
|
-
data
|
64
|
-
end
|
65
|
-
|
66
|
-
def close
|
67
|
-
sessions { |s| s.close }
|
68
|
-
end
|
69
|
-
|
70
|
-
private
|
71
|
-
def session(hostname)
|
72
|
-
@sessions[hostname] ||= Xlogin.get(hostname, **Xlogin::Scanner.login_opts)
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
class ScanType
|
77
|
-
def command(val = nil, &block)
|
78
|
-
return @command unless val || block
|
79
|
-
@command = (val) ? lambda { val } : block
|
80
|
-
end
|
81
|
-
|
82
|
-
def scanner(&block)
|
83
|
-
return @scanner unless block
|
84
|
-
@scanner = block
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
end
|
data/lib/xlogin/thread_safe.rb
DELETED
@@ -1,25 +0,0 @@
|
|
1
|
-
require 'thread'
|
2
|
-
require 'timeout'
|
3
|
-
|
4
|
-
module Xlogin
|
5
|
-
module Session
|
6
|
-
def thread_safe(timeout: @timeout, maximum_retry: 1)
|
7
|
-
@safe_session = self
|
8
|
-
@safe_session_mutex ||= Mutex.new
|
9
|
-
|
10
|
-
Timeout.timeout(timeout) do
|
11
|
-
@safe_session_mutex.synchronize do
|
12
|
-
retry_count = 0
|
13
|
-
begin
|
14
|
-
@safe_session ||= Xlogin.get(@host, @opts)
|
15
|
-
yield @safe_session
|
16
|
-
rescue Errno::ECONNRESET => e
|
17
|
-
raise e unless (retry_count += 1) < maximum_retry
|
18
|
-
@safe_session = nil
|
19
|
-
retry
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|