teuton 0.0.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 +7 -0
- data/bin/teuton +4 -0
- data/lib/teuton/application.rb +53 -0
- data/lib/teuton/case_manager/case/builtin/main.rb +24 -0
- data/lib/teuton/case_manager/case/builtin/package.rb +20 -0
- data/lib/teuton/case_manager/case/builtin/service.rb +32 -0
- data/lib/teuton/case_manager/case/builtin/user.rb +20 -0
- data/lib/teuton/case_manager/case/case.rb +114 -0
- data/lib/teuton/case_manager/case/close.rb +29 -0
- data/lib/teuton/case_manager/case/config.rb +76 -0
- data/lib/teuton/case_manager/case/dsl/check.rb +24 -0
- data/lib/teuton/case_manager/case/dsl/deprecated.rb +14 -0
- data/lib/teuton/case_manager/case/dsl/expect.rb +78 -0
- data/lib/teuton/case_manager/case/dsl/getset.rb +22 -0
- data/lib/teuton/case_manager/case/dsl/goto.rb +35 -0
- data/lib/teuton/case_manager/case/dsl/log.rb +14 -0
- data/lib/teuton/case_manager/case/dsl/main.rb +11 -0
- data/lib/teuton/case_manager/case/dsl/missing.rb +12 -0
- data/lib/teuton/case_manager/case/dsl/send.rb +69 -0
- data/lib/teuton/case_manager/case/dsl/target.rb +16 -0
- data/lib/teuton/case_manager/case/dsl/unique.rb +11 -0
- data/lib/teuton/case_manager/case/main.rb +7 -0
- data/lib/teuton/case_manager/case/play.rb +59 -0
- data/lib/teuton/case_manager/case/result/ext_array.rb +43 -0
- data/lib/teuton/case_manager/case/result/ext_compare.rb +147 -0
- data/lib/teuton/case_manager/case/result/ext_filter.rb +68 -0
- data/lib/teuton/case_manager/case/result/result.rb +73 -0
- data/lib/teuton/case_manager/case/runner.rb +134 -0
- data/lib/teuton/case_manager/case_manager.rb +76 -0
- data/lib/teuton/case_manager/check_cases.rb +73 -0
- data/lib/teuton/case_manager/dsl.rb +31 -0
- data/lib/teuton/case_manager/export_manager.rb +20 -0
- data/lib/teuton/case_manager/hall_of_fame.rb +28 -0
- data/lib/teuton/case_manager/main.rb +6 -0
- data/lib/teuton/case_manager/report.rb +52 -0
- data/lib/teuton/case_manager/show.rb +19 -0
- data/lib/teuton/case_manager/utils.rb +57 -0
- data/lib/teuton/command/create.rb +20 -0
- data/lib/teuton/command/download.rb +26 -0
- data/lib/teuton/command/main.rb +9 -0
- data/lib/teuton/command/play.rb +34 -0
- data/lib/teuton/command/readme.rb +23 -0
- data/lib/teuton/command/test.rb +35 -0
- data/lib/teuton/command/update.rb +27 -0
- data/lib/teuton/command/version.rb +13 -0
- data/lib/teuton/files/start.rb +13 -0
- data/lib/teuton/project/configfile_reader.rb +49 -0
- data/lib/teuton/project/laboratory/builtin.rb +23 -0
- data/lib/teuton/project/laboratory/dsl.rb +117 -0
- data/lib/teuton/project/laboratory/laboratory.rb +55 -0
- data/lib/teuton/project/laboratory/show.rb +161 -0
- data/lib/teuton/project/name_file_finder.rb +129 -0
- data/lib/teuton/project/project.rb +62 -0
- data/lib/teuton/project/project_creator.rb +79 -0
- data/lib/teuton/project/readme/dsl.rb +109 -0
- data/lib/teuton/project/readme/lang.rb +30 -0
- data/lib/teuton/project/readme/readme.rb +156 -0
- data/lib/teuton/rake_function/check.rb +39 -0
- data/lib/teuton/rake_function/install.rb +36 -0
- data/lib/teuton/report/close.rb +34 -0
- data/lib/teuton/report/formatter/array_formatter.rb +84 -0
- data/lib/teuton/report/formatter/base_formatter.rb +33 -0
- data/lib/teuton/report/formatter/csv_formatter.rb +31 -0
- data/lib/teuton/report/formatter/formatter_factory.rb +73 -0
- data/lib/teuton/report/formatter/html_formatter.rb +81 -0
- data/lib/teuton/report/formatter/json_formatter.rb +17 -0
- data/lib/teuton/report/formatter/list_formatter.rb +71 -0
- data/lib/teuton/report/formatter/moodle_csv_formatter.rb +28 -0
- data/lib/teuton/report/formatter/resume_array_formatter.rb +49 -0
- data/lib/teuton/report/formatter/resume_json_formatter.rb +16 -0
- data/lib/teuton/report/formatter/resume_list_formatter.rb +62 -0
- data/lib/teuton/report/formatter/resume_txt_formatter.rb +102 -0
- data/lib/teuton/report/formatter/resume_yaml_formatter.rb +16 -0
- data/lib/teuton/report/formatter/txt_formatter.rb +102 -0
- data/lib/teuton/report/formatter/xml_formatter.rb +42 -0
- data/lib/teuton/report/formatter/yaml_formatter.rb +18 -0
- data/lib/teuton/report/report.rb +55 -0
- data/lib/teuton/report/show.rb +111 -0
- data/lib/teuton/utils/verbose.rb +15 -0
- data/lib/teuton.rb +17 -0
- metadata +263 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Case class:
|
|
4
|
+
# * play
|
|
5
|
+
# * play_in_parallel
|
|
6
|
+
# * play_in_sequence
|
|
7
|
+
# * fill_report
|
|
8
|
+
# * close_opened_sessions
|
|
9
|
+
class Case
|
|
10
|
+
def play
|
|
11
|
+
if skip?
|
|
12
|
+
verbose "Skipping case <#{@config.get(:tt_members)}>\n"
|
|
13
|
+
return false
|
|
14
|
+
end
|
|
15
|
+
# TODO: Delete old reports???
|
|
16
|
+
start_time = Time.now
|
|
17
|
+
play_in_sequence if get(:tt_sequence) == true # Play in sequence
|
|
18
|
+
play_in_parallel if get(:tt_sequence) != true # Play in parallel
|
|
19
|
+
fill_report(start_time, Time.now)
|
|
20
|
+
close_opened_sessions
|
|
21
|
+
end
|
|
22
|
+
alias start play
|
|
23
|
+
|
|
24
|
+
def close_opened_sessions
|
|
25
|
+
@sessions.each_value do |s|
|
|
26
|
+
s.close if s.class == Net::SSH::Connection::Session
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def play_in_parallel
|
|
33
|
+
@groups.each do |t|
|
|
34
|
+
@action[:groupname] = t[:name]
|
|
35
|
+
instance_eval(&t[:block])
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def play_in_sequence
|
|
40
|
+
verboseln "Starting case <#{@config.get(:tt_members)}>"
|
|
41
|
+
@groups.each do |t|
|
|
42
|
+
verbose "* Processing <#{t[:name]}> "
|
|
43
|
+
@action[:groupname] = t[:name]
|
|
44
|
+
instance_eval(&t[:block])
|
|
45
|
+
verbose "\n"
|
|
46
|
+
end
|
|
47
|
+
verboseln "\n"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def fill_report(start_time, finish_time)
|
|
51
|
+
@report.head.merge! @config.global
|
|
52
|
+
@report.head.merge! @config.local
|
|
53
|
+
@report.head.merge! @config.running
|
|
54
|
+
@report.tail[:case_id] = @id
|
|
55
|
+
@report.tail[:start_time_] = start_time
|
|
56
|
+
@report.tail[:finish_time] = finish_time
|
|
57
|
+
@report.tail[:duration] = finish_time - start_time
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# This is an extension of Result class
|
|
4
|
+
class Result
|
|
5
|
+
def count
|
|
6
|
+
@alterations << 'count'
|
|
7
|
+
if @content.class == Array
|
|
8
|
+
@content = [@content.count]
|
|
9
|
+
self
|
|
10
|
+
elsif @content.nil?
|
|
11
|
+
@content = ['0']
|
|
12
|
+
else
|
|
13
|
+
@content = [@content.to_i.to_s]
|
|
14
|
+
end
|
|
15
|
+
self
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def include?(value)
|
|
19
|
+
@expected = "Include <#{value}> value"
|
|
20
|
+
@content[0].include?(value)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def not_include?(value)
|
|
24
|
+
@expected = "Not include <#{value}> value"
|
|
25
|
+
!@content[0].include?(value)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def contain?(value)
|
|
29
|
+
@expected = "Contain <#{value}> value"
|
|
30
|
+
@content.contain? value
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def empty
|
|
34
|
+
@expected = 'Empty!'
|
|
35
|
+
@content.empty
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
alias count! count
|
|
39
|
+
alias length count
|
|
40
|
+
alias len count
|
|
41
|
+
alias size count
|
|
42
|
+
alias empty? empty
|
|
43
|
+
end
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# This is an extension of Result class
|
|
4
|
+
class Result
|
|
5
|
+
def eq(input)
|
|
6
|
+
@expected = input
|
|
7
|
+
|
|
8
|
+
case input.class.to_s
|
|
9
|
+
when 'Fixnum'
|
|
10
|
+
value = @content[0].to_i
|
|
11
|
+
puts '[WARN] Fixnum class is deprecated!'
|
|
12
|
+
puts ' Upgrade your Ruby version.'
|
|
13
|
+
when 'Float'
|
|
14
|
+
value = @content[0].to_f
|
|
15
|
+
when 'Integer'
|
|
16
|
+
value = @content[0].to_i
|
|
17
|
+
when 'String'
|
|
18
|
+
value = @content[0].to_s
|
|
19
|
+
else
|
|
20
|
+
value = @content[0]
|
|
21
|
+
end
|
|
22
|
+
value == input
|
|
23
|
+
end
|
|
24
|
+
alias eq? eq
|
|
25
|
+
alias equal eq
|
|
26
|
+
alias equal? eq
|
|
27
|
+
alias is_equal? eq
|
|
28
|
+
|
|
29
|
+
def neq(external)
|
|
30
|
+
@expected = "Not equal to #{external}"
|
|
31
|
+
|
|
32
|
+
case external.class.to_s
|
|
33
|
+
when 'Fixnum'
|
|
34
|
+
internal = @content[0].to_i
|
|
35
|
+
puts '[WARN] Fixnum class is deprecated!'
|
|
36
|
+
puts ' Upgrade your Ruby version.'
|
|
37
|
+
when 'Float'
|
|
38
|
+
internal = @content[0].to_f
|
|
39
|
+
when 'Integer'
|
|
40
|
+
internal = @content[0].to_i
|
|
41
|
+
else
|
|
42
|
+
internal = @content[0]
|
|
43
|
+
end
|
|
44
|
+
internal != external
|
|
45
|
+
end
|
|
46
|
+
alias neq? neq
|
|
47
|
+
alias not_equal neq
|
|
48
|
+
alias not_equal? neq
|
|
49
|
+
|
|
50
|
+
def ge(input)
|
|
51
|
+
@expected = "Greater or equal to #{input}"
|
|
52
|
+
return false if @content.nil? || @content[0].nil?
|
|
53
|
+
|
|
54
|
+
value = @content[0]
|
|
55
|
+
case input.class.to_s
|
|
56
|
+
when 'Fixnum'
|
|
57
|
+
value = @content[0].to_i
|
|
58
|
+
puts '[WARN] Fixnum class is deprecated!'
|
|
59
|
+
puts ' Upgrade your Ruby version.'
|
|
60
|
+
when 'Float'
|
|
61
|
+
value = @content[0].to_f
|
|
62
|
+
when 'Integer'
|
|
63
|
+
value = @content[0].to_i
|
|
64
|
+
end
|
|
65
|
+
value >= input
|
|
66
|
+
end
|
|
67
|
+
alias greater_or_equal ge
|
|
68
|
+
alias greater_or_equal? ge
|
|
69
|
+
|
|
70
|
+
def gt(input)
|
|
71
|
+
@expected = "Greater than #{input}"
|
|
72
|
+
return false if @content.nil? || @content[0].nil?
|
|
73
|
+
|
|
74
|
+
value = @content[0]
|
|
75
|
+
case input.class.to_s
|
|
76
|
+
when 'Fixnum'
|
|
77
|
+
value = @content[0].to_i
|
|
78
|
+
puts '[WARN] Fixnum class is deprecated!'
|
|
79
|
+
puts ' Upgrade your Ruby version.'
|
|
80
|
+
when 'Float'
|
|
81
|
+
value = @content[0].to_f
|
|
82
|
+
when 'Integer'
|
|
83
|
+
value = @content[0].to_i
|
|
84
|
+
end
|
|
85
|
+
value > input
|
|
86
|
+
end
|
|
87
|
+
alias greater gt
|
|
88
|
+
alias greater_than gt
|
|
89
|
+
|
|
90
|
+
def le(input)
|
|
91
|
+
@expected = "Lesser or equal to #{input}"
|
|
92
|
+
|
|
93
|
+
return false if @content.nil? || @content[0].nil?
|
|
94
|
+
|
|
95
|
+
value = @content[0]
|
|
96
|
+
case input.class.to_s
|
|
97
|
+
when 'Fixnum'
|
|
98
|
+
value = @content[0].to_i
|
|
99
|
+
puts '[WARN] Fixnum class is deprecated!'
|
|
100
|
+
puts ' Upgrade your Ruby version.'
|
|
101
|
+
when 'Float'
|
|
102
|
+
value = @content[0].to_f
|
|
103
|
+
when 'Integer'
|
|
104
|
+
value = @content[0].to_i
|
|
105
|
+
end
|
|
106
|
+
value <= input
|
|
107
|
+
end
|
|
108
|
+
alias lesser_or_equal le
|
|
109
|
+
alias lesser_or_equal? le
|
|
110
|
+
|
|
111
|
+
def lt(input)
|
|
112
|
+
@expected = "Lesser than #{input}"
|
|
113
|
+
return false if @content.nil? || @content[0].nil?
|
|
114
|
+
|
|
115
|
+
value = @content[0]
|
|
116
|
+
case input.class.to_s
|
|
117
|
+
when 'Fixnum'
|
|
118
|
+
value = @content[0].to_i
|
|
119
|
+
puts '[WARN] Fixnum class is deprecated!'
|
|
120
|
+
puts ' Upgrade your Ruby version.'
|
|
121
|
+
when 'Float'
|
|
122
|
+
value = @content[0].to_f
|
|
123
|
+
when 'Integer'
|
|
124
|
+
value = @content[0].to_i
|
|
125
|
+
end
|
|
126
|
+
value < input
|
|
127
|
+
end
|
|
128
|
+
alias lesser lt
|
|
129
|
+
alias smaller lt
|
|
130
|
+
alias lesser_than lt
|
|
131
|
+
|
|
132
|
+
# Return 'true' if the parameter value is near to the target value.
|
|
133
|
+
# To get this we consider a 10% desviation or less, as an acceptable result.
|
|
134
|
+
def near_to?(input)
|
|
135
|
+
@expected = "Is near to #{input}"
|
|
136
|
+
return false if @content.nil?
|
|
137
|
+
|
|
138
|
+
target = @content[0].to_f
|
|
139
|
+
desv = (target * 10.0) / 100.0
|
|
140
|
+
return true if (target - input.to_f).abs.to_f <= desv
|
|
141
|
+
|
|
142
|
+
false
|
|
143
|
+
end
|
|
144
|
+
alias near_to near_to?
|
|
145
|
+
alias near? near_to?
|
|
146
|
+
alias near near_to?
|
|
147
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# This is an extension of Result class
|
|
4
|
+
class Result
|
|
5
|
+
# TODO: Error line 102 undefined include? method for 0 Fixnum...
|
|
6
|
+
def find(filter)
|
|
7
|
+
@alterations << "find(#{filter})"
|
|
8
|
+
case filter.class.to_s
|
|
9
|
+
when 'Array'
|
|
10
|
+
find_when_array(filter)
|
|
11
|
+
when 'String' || 'Integer'
|
|
12
|
+
@content.select! { |i| i.include?(filter.to_s) }
|
|
13
|
+
when 'Regexp'
|
|
14
|
+
@content.select! { |i| filter.match(i) }
|
|
15
|
+
end
|
|
16
|
+
self
|
|
17
|
+
end
|
|
18
|
+
alias grep find
|
|
19
|
+
alias grep! find
|
|
20
|
+
alias find! find
|
|
21
|
+
|
|
22
|
+
def not_find(p_filter)
|
|
23
|
+
@alterations << "not_find(#{p_filter})"
|
|
24
|
+
return self if @content.size.zero?
|
|
25
|
+
|
|
26
|
+
@content.reject! { |i| i.include?(p_filter) }
|
|
27
|
+
self
|
|
28
|
+
end
|
|
29
|
+
alias grep_v not_find
|
|
30
|
+
|
|
31
|
+
def since(filter)
|
|
32
|
+
@alterations << "since(#{filter})"
|
|
33
|
+
return self if @content.size.zero?
|
|
34
|
+
|
|
35
|
+
if filter.class == String
|
|
36
|
+
flag = false
|
|
37
|
+
@content.select! do |i|
|
|
38
|
+
flag = true if i.include?(filter.to_s)
|
|
39
|
+
flag
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
self
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def until(filter)
|
|
46
|
+
@alterations << "until(#{filter})"
|
|
47
|
+
return self if @content.size.zero?
|
|
48
|
+
|
|
49
|
+
if filter.class == String
|
|
50
|
+
flag = true
|
|
51
|
+
@content.select! do |i|
|
|
52
|
+
flag = false if i.include?(filter.to_s)
|
|
53
|
+
flag
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
self
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
private
|
|
60
|
+
|
|
61
|
+
def find_when_array(filter)
|
|
62
|
+
@content.select! do |line|
|
|
63
|
+
flag = false
|
|
64
|
+
filter.each { |i| flag ||= line.include?(i) }
|
|
65
|
+
flag
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'ext_array'
|
|
4
|
+
require_relative 'ext_compare'
|
|
5
|
+
require_relative 'ext_filter'
|
|
6
|
+
|
|
7
|
+
# This object contains data returned by remote/local execution
|
|
8
|
+
# * initialize
|
|
9
|
+
# * alterations
|
|
10
|
+
# * content
|
|
11
|
+
# * debug
|
|
12
|
+
# * ok?
|
|
13
|
+
# * reset
|
|
14
|
+
# * restore
|
|
15
|
+
# * value
|
|
16
|
+
class Result
|
|
17
|
+
attr_reader :content
|
|
18
|
+
attr_accessor :exitstatus
|
|
19
|
+
|
|
20
|
+
def initialize
|
|
21
|
+
reset
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def alterations
|
|
25
|
+
@alterations.join(' & ')
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def content=(content)
|
|
29
|
+
@content_backup = content.clone
|
|
30
|
+
@content = content.clone
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def reset
|
|
34
|
+
@content_backup = []
|
|
35
|
+
@content = []
|
|
36
|
+
@exitstatus = nil
|
|
37
|
+
@value = nil
|
|
38
|
+
@expected = nil
|
|
39
|
+
@alterations = []
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def debug
|
|
43
|
+
print "\n" + '*' * 20
|
|
44
|
+
print " [DEBUG] count=#{@content.count} "
|
|
45
|
+
puts '*' * 20
|
|
46
|
+
@content.each_with_index do |item, index|
|
|
47
|
+
puts format('%2d: %s', index, item)
|
|
48
|
+
end
|
|
49
|
+
puts '*' * 57
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def expected
|
|
53
|
+
@expected.to_s
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def ok?
|
|
57
|
+
return false if @exitstatus.nil?
|
|
58
|
+
|
|
59
|
+
@exitstatus.zero?
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def restore
|
|
63
|
+
temp = @content_backup.clone
|
|
64
|
+
reset
|
|
65
|
+
@content_backup = temp
|
|
66
|
+
@content = temp.clone
|
|
67
|
+
end
|
|
68
|
+
alias restore! restore
|
|
69
|
+
|
|
70
|
+
def value
|
|
71
|
+
@content[0]
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
|
|
2
|
+
require 'net/ssh'
|
|
3
|
+
require 'net/sftp'
|
|
4
|
+
require 'net/telnet'
|
|
5
|
+
|
|
6
|
+
# Class Case
|
|
7
|
+
# * run_local_cmd
|
|
8
|
+
# * run_remote_cmd
|
|
9
|
+
# * run_remote_cmd_ssh
|
|
10
|
+
# * run_remote_cmd_telnet
|
|
11
|
+
class Case
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
|
|
15
|
+
def run_local_cmd()
|
|
16
|
+
@action[:conn_type] = :local
|
|
17
|
+
i = my_execute( @action[:command], @action[:encoding] )
|
|
18
|
+
@result.exitstatus = i[:exitstatus]
|
|
19
|
+
@result.content = i[:content]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def run_remote_cmd(input_hostname)
|
|
23
|
+
hostname = input_hostname.to_s
|
|
24
|
+
i = (hostname + '_protocol').to_sym
|
|
25
|
+
protocol = @config.get(i) if @config.get(i)
|
|
26
|
+
protocol = :ssh if protocol.nil? || protocol == 'NODATA'
|
|
27
|
+
protocol = protocol.to_sym
|
|
28
|
+
case protocol
|
|
29
|
+
when :ssh
|
|
30
|
+
run_remote_cmd_ssh(input_hostname)
|
|
31
|
+
when :telnet
|
|
32
|
+
run_remote_cmd_telnet(input_hostname)
|
|
33
|
+
else
|
|
34
|
+
log("Protocol #{protocol} unknown! Use ssh or telnet.", :error)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def run_remote_cmd_ssh(input_hostname)
|
|
39
|
+
@action[:conn_type] = :ssh
|
|
40
|
+
hostname = input_hostname.to_s
|
|
41
|
+
ip = @config.get((hostname + '_ip').to_sym)
|
|
42
|
+
username = @config.get((hostname + '_username').to_sym).to_s
|
|
43
|
+
password = @config.get((hostname + '_password').to_sym).to_s
|
|
44
|
+
text = ''
|
|
45
|
+
begin
|
|
46
|
+
if @sessions[hostname].nil?
|
|
47
|
+
@sessions[hostname] = Net::SSH.start(ip,
|
|
48
|
+
username,
|
|
49
|
+
password: password,
|
|
50
|
+
keepalive: true,
|
|
51
|
+
timeout: 30,
|
|
52
|
+
non_interactive: true)
|
|
53
|
+
end
|
|
54
|
+
if @sessions[hostname].class == Net::SSH::Connection::Session
|
|
55
|
+
text = @sessions[hostname].exec!(@action[:command].to_s)
|
|
56
|
+
end
|
|
57
|
+
rescue Errno::EHOSTUNREACH
|
|
58
|
+
@sessions[hostname] = :nosession
|
|
59
|
+
@conn_status[hostname] = :host_unreachable
|
|
60
|
+
verbose Application.instance.letter[:error]
|
|
61
|
+
log("Host #{ip} unreachable!", :error)
|
|
62
|
+
rescue Net::SSH::AuthenticationFailed
|
|
63
|
+
@sessions[hostname] = :nosession
|
|
64
|
+
@conn_status[hostname] = :error_authentication_failed
|
|
65
|
+
verbose Application.instance.letter[:error]
|
|
66
|
+
log('SSH::AuthenticationFailed!', :error)
|
|
67
|
+
rescue Net::SSH::HostKeyMismatch
|
|
68
|
+
@sessions[hostname] = :nosession
|
|
69
|
+
@conn_status[hostname] = :host_key_mismatch
|
|
70
|
+
verbose Application.instance.letter[:error]
|
|
71
|
+
log('SSH::HostKeyMismatch!', :error)
|
|
72
|
+
log("* The destination server's fingerprint is not matching " \
|
|
73
|
+
'what is in your local known_hosts file.', :error)
|
|
74
|
+
log('* Remove the existing entry in your local known_hosts file', :error)
|
|
75
|
+
log("* Try this => ssh-keygen -f '/home/USERNAME/.ssh/known_hosts' " \
|
|
76
|
+
"-R #{ip}", :error)
|
|
77
|
+
rescue StandardError => e
|
|
78
|
+
@sessions[hostname] = :nosession
|
|
79
|
+
@conn_status[hostname] = :error
|
|
80
|
+
verbose Application.instance.letter[:error]
|
|
81
|
+
log("[#{e.class}] SSH on <#{username}@#{ip}>" \
|
|
82
|
+
" exec: #{@action[:command]}", :error)
|
|
83
|
+
end
|
|
84
|
+
output = encode_and_split(@action[:encoding], text)
|
|
85
|
+
@result.content = output
|
|
86
|
+
@result.content.compact!
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def run_remote_cmd_telnet(input_hostname)
|
|
90
|
+
@action[:conn_type] = :telnet
|
|
91
|
+
app = Application.instance
|
|
92
|
+
hostname = input_hostname.to_s
|
|
93
|
+
ip = @config.get((hostname + '_ip').to_sym)
|
|
94
|
+
username = @config.get((hostname + '_username').to_sym).to_s
|
|
95
|
+
password = @config.get((hostname + '_password').to_sym).to_s
|
|
96
|
+
text = ''
|
|
97
|
+
begin
|
|
98
|
+
if @sessions[hostname].nil? || @sessions[hostname] == :ok
|
|
99
|
+
h = Net::Telnet.new( 'Host' => ip,
|
|
100
|
+
'Timeout' => 30,
|
|
101
|
+
'Prompt' => /login|teuton|[$%#>]/ )
|
|
102
|
+
# 'Prompt' => Regexp.new(username[1, 40]))
|
|
103
|
+
# 'Prompt' => /[$%#>] \z/n)
|
|
104
|
+
h.login(username, password)
|
|
105
|
+
text = ''
|
|
106
|
+
h.cmd(@action[:command]) { |i| text << i }
|
|
107
|
+
h.close
|
|
108
|
+
@sessions[hostname] = :ok
|
|
109
|
+
end
|
|
110
|
+
rescue Net::OpenTimeout
|
|
111
|
+
@sessions[hostname] = :nosession
|
|
112
|
+
@conn_status[hostname] = :open_timeout
|
|
113
|
+
verbose Application.instance.letter[:error]
|
|
114
|
+
log(" ExceptionType=<Net::OpenTimeout> doing <telnet #{ip}>", :error)
|
|
115
|
+
log(' └── Revise host IP!', :warn)
|
|
116
|
+
rescue Net::ReadTimeout
|
|
117
|
+
@sessions[hostname] = :nosession
|
|
118
|
+
@conn_status[hostname] = :read_timeout
|
|
119
|
+
verbose Application.instance.letter[:error]
|
|
120
|
+
log(" ExceptionType=<Net::ReadTimeout> doing <telnet #{ip}>", :error)
|
|
121
|
+
rescue StandardError => e
|
|
122
|
+
@sessions[hostname] = :nosession
|
|
123
|
+
@conn_status[hostname] = :error
|
|
124
|
+
verbose Application.instance.letter[:error]
|
|
125
|
+
log(" ExceptionType=<#{e.class}> doing telnet on <#{username}@#{ip}>" \
|
|
126
|
+
" exec: #{@action[:command]}", :error)
|
|
127
|
+
log(" └── username=<#{username}>, password=<#{password}>," \
|
|
128
|
+
" ip=<#{ip}>, HOSTID=<#{hostname}>", :warn)
|
|
129
|
+
end
|
|
130
|
+
output = encode_and_split(@action[:encoding], text)
|
|
131
|
+
@result.content = output
|
|
132
|
+
@result.content.compact!
|
|
133
|
+
end
|
|
134
|
+
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'singleton'
|
|
4
|
+
require_relative '../application'
|
|
5
|
+
require_relative '../report/report'
|
|
6
|
+
require_relative '../project/configfile_reader'
|
|
7
|
+
require_relative 'case/case'
|
|
8
|
+
require_relative 'export_manager'
|
|
9
|
+
require_relative 'main'
|
|
10
|
+
require_relative 'utils'
|
|
11
|
+
|
|
12
|
+
# This class does all the job
|
|
13
|
+
# Organize the hole job, sending orders to others classes
|
|
14
|
+
# * initialize
|
|
15
|
+
# * play
|
|
16
|
+
# Split into several files:
|
|
17
|
+
# * case_manager/check_cases
|
|
18
|
+
# * case_manager/export
|
|
19
|
+
# * case_manager/hall_of_fame
|
|
20
|
+
# * case_manager/report
|
|
21
|
+
# * case_manager/show
|
|
22
|
+
class CaseManager
|
|
23
|
+
include Singleton
|
|
24
|
+
include Utils
|
|
25
|
+
|
|
26
|
+
def initialize
|
|
27
|
+
@cases = []
|
|
28
|
+
@report = Report.new(0)
|
|
29
|
+
@report.filename = 'resume'
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def play(&block)
|
|
33
|
+
check_cases!
|
|
34
|
+
instance_eval(&block)
|
|
35
|
+
# Run export if user pass option command "--export=json"
|
|
36
|
+
i = Application.instance.options['export']
|
|
37
|
+
export(format: i.to_sym) unless i.nil?
|
|
38
|
+
# Accept "configfile" param REVISE There exists?
|
|
39
|
+
i = Application.instance.options['configfile']
|
|
40
|
+
export(format: i.to_sym) unless i.nil?
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def export(args = {})
|
|
44
|
+
if args.class != Hash
|
|
45
|
+
puts "[ERROR] CaseManager#export: Argument = <#{args}>, " \
|
|
46
|
+
"class = #{args.class}"
|
|
47
|
+
puts ' Usage: export :format => :colored_text'
|
|
48
|
+
raise '[ERROR] CaseManager#export: Argument error!'
|
|
49
|
+
end
|
|
50
|
+
ExportManager.run(@report, @cases, args)
|
|
51
|
+
preserve_files if args[:preserve] == true
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def preserve_files
|
|
55
|
+
app = Application.instance
|
|
56
|
+
t = Time.now
|
|
57
|
+
subdir = "#{t.year}#{format('%02d',t.month)}#{format('%02d',t.day)}-" \
|
|
58
|
+
"#{format('%02d',t.hour)}#{format('%02d',t.min)}" \
|
|
59
|
+
"#{format('%02d',t.sec)}"
|
|
60
|
+
logdir = File.join(app.output_basedir, app.global[:tt_testname], subdir)
|
|
61
|
+
srcdir = File.join(app.output_basedir, app.global[:tt_testname])
|
|
62
|
+
puts "[INFO] Preserving files => #{logdir}"
|
|
63
|
+
FileUtils.mkdir(logdir)
|
|
64
|
+
Dir.glob('var/learn-08-preserve/**.*').each do |file|
|
|
65
|
+
FileUtils.cp(file, logdir)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def send(args = {})
|
|
70
|
+
threads = []
|
|
71
|
+
puts ''
|
|
72
|
+
puts "[INFO] Sending files...#{args.to_s}"
|
|
73
|
+
@cases.each { |c| threads << Thread.new { c.send(args) } }
|
|
74
|
+
threads.each(&:join)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# CaseManager#check_cases!
|
|
4
|
+
class CaseManager
|
|
5
|
+
private
|
|
6
|
+
|
|
7
|
+
def check_cases!
|
|
8
|
+
app = Application.instance
|
|
9
|
+
|
|
10
|
+
# Load configurations from config file
|
|
11
|
+
configdata = ConfigFileReader.read(app.config_path)
|
|
12
|
+
app.ialias = configdata[:alias]
|
|
13
|
+
app.global = configdata[:global]
|
|
14
|
+
app.global[:tt_testname] = app.global[:tt_testname] || app.test_name
|
|
15
|
+
app.global[:tt_sequence] = false if app.global[:tt_sequence].nil?
|
|
16
|
+
|
|
17
|
+
# Create out dir
|
|
18
|
+
outdir = app.global[:tt_outdir] ||
|
|
19
|
+
File.join('var', app.global[:tt_testname])
|
|
20
|
+
ensure_dir outdir
|
|
21
|
+
@report.output_dir = outdir
|
|
22
|
+
|
|
23
|
+
# Fill report head
|
|
24
|
+
open_main_report(app.config_path)
|
|
25
|
+
|
|
26
|
+
# create cases and run
|
|
27
|
+
configdata[:cases].each { |config| @cases << Case.new(config) }
|
|
28
|
+
start_time = run_all_cases # run cases
|
|
29
|
+
|
|
30
|
+
uniques = collect_uniques_for_all_cases
|
|
31
|
+
close_reports_for_all_cases(uniques)
|
|
32
|
+
close_main_report(start_time)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def run_all_cases
|
|
36
|
+
start_time = Time.now
|
|
37
|
+
if Application.instance.global[:tt_sequence]
|
|
38
|
+
verboseln "[INFO] Running in sequence (#{start_time})"
|
|
39
|
+
# Run every case in sequence
|
|
40
|
+
@cases.each(&:play)
|
|
41
|
+
else
|
|
42
|
+
verboseln "[INFO] Running in parallel (#{start_time})"
|
|
43
|
+
threads = []
|
|
44
|
+
# Run all cases in parallel
|
|
45
|
+
@cases.each { |c| threads << Thread.new { c.play } }
|
|
46
|
+
threads.each(&:join)
|
|
47
|
+
end
|
|
48
|
+
start_time
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def collect_uniques_for_all_cases
|
|
52
|
+
uniques = {} # Collect "unique" values from all cases
|
|
53
|
+
@cases.each do |c|
|
|
54
|
+
c.uniques.each do |key|
|
|
55
|
+
if uniques[key].nil?
|
|
56
|
+
uniques[key] = [c.id]
|
|
57
|
+
else
|
|
58
|
+
uniques[key] << c.id
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
uniques
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def close_reports_for_all_cases(uniques)
|
|
66
|
+
threads = []
|
|
67
|
+
@cases.each { |c| threads << Thread.new { c.close uniques } }
|
|
68
|
+
threads.each(&:join)
|
|
69
|
+
|
|
70
|
+
# Build Hall of Fame
|
|
71
|
+
build_hall_of_fame
|
|
72
|
+
end
|
|
73
|
+
end
|