teuton 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|