teuton 2.9.6 → 2.10.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b77d496bd14e955446cbb709c63c7df74059c708949159326e3d2e0edc09b81a
4
- data.tar.gz: f721aa3a9fd30021bdf15ca26c19b308d7f38e00ea016a43d6b847f7b673f7b8
3
+ metadata.gz: 7936417ce11de28acf3bddee94dcf41b4848742eae8266cce8bf70792ff4e592
4
+ data.tar.gz: bf8175c24a48e80c6257ab90898b52421157a471010ac1e730b3926962394ef9
5
5
  SHA512:
6
- metadata.gz: 7cdc0745e4b04b7c81893a3aaef4fa1478f55d2c8390edaf1153ad82005238cce3d6a4ff668566528e2eca1a127c941adc1683f2164e4afd75c4125380c2bb77
7
- data.tar.gz: 88b54291a14bb76f074dd9ec27657ede78142e2388b7e40af5ed058b8cad0e43d1257a6c48b9e60106268aa4b932a532b8953a96a0b600bdfe9787ff4d623cc4
6
+ metadata.gz: 5a042452b9f025520bce19c4254e799ae9c51e5195804bc8a7d132c63d9271e7de3f03a9c14cb85b799635174a20cddc8a002bd43c565e91395d474059f82d1e
7
+ data.tar.gz: dd3051109b8b756709e34343bed5301140b33368f4fc3efed751f805960db29495ca9b84bfcaf36251715215a649e53be350cb4cee88e294d74285676a77e837
@@ -14,20 +14,9 @@ Available command functions:
14
14
 
15
15
  Show help about command functions.
16
16
 
17
- Example:
18
- ```bash
19
- $ teuton help
20
- Commands:
21
- teuton [run] [OPTIONS] DIRECTORY # Run test from directory
22
- teuton check [OPTIONS] DIRECTORY # Check test and config file content
23
- teuton config DIRECTORY # Suggest configuration
24
- teuton help [COMMAND] # Describe available commands or one specific command
25
- teuton new DIRECTORY # Create skeleton for a new project
26
- teuton readme DIRECTORY # Show README extracted from test contents
27
- teuton version # Show the program version
28
- ```
29
-
30
- Execute `teuton help FUNCTION_NAME` for more information.
17
+ Usage:
18
+ * `teuton help`
19
+ * `teuton help FUNCTION_NAME`
31
20
 
32
21
  Alias: `teuton h`,`teuton -h`, `teuton --help`
33
22
 
@@ -37,13 +26,6 @@ Show current version.
37
26
 
38
27
  Usage: `teuton version`
39
28
 
40
- Example:
41
-
42
- ```bash
43
- $ teuton version
44
- teuton (version 2.9.5)
45
- ```
46
-
47
29
  Alias: `teuton v`, `teuton -v`, `teuton --version`
48
30
 
49
31
  # 3. Create new test
@@ -75,7 +57,7 @@ Alias: `teuton n foo`, `teuton -n foo`, `teuton --new foo`
75
57
 
76
58
  # 4. Check test
77
59
 
78
- Check test and config files located into DIRPATH folder.
60
+ Check test and config files from DIRPATH folder.
79
61
 
80
62
  Usage: `teuton check DIRPATH`
81
63
 
@@ -100,11 +82,6 @@ Create a readme file for the exercise.
100
82
 
101
83
  Usage: `teuton readme DIRPATH > README.md`
102
84
 
103
- This function reads test and config files, and generate Markdown output with guidelines and target descriptions.
104
-
105
- Students will need this information to resolv the proposed problem/exercise into their machines.
85
+ This function reads test and config files, and generate Markdown output with guidelines and target descriptions about the exercise.
106
86
 
107
- Alias:
108
- * `teuton r DIRPATH`
109
- * `teuton -r DIRPATH`
110
- * `teuton --readme DIRPATH`
87
+ Alias: `teuton r DIRPATH`, `teuton -r DIRPATH`, `teuton --readme DIRPATH`
@@ -37,12 +37,13 @@ Executing `teuton run examples/13-feedback`, we get this output:
37
37
 
38
38
  ```
39
39
  GROUPS
40
- - Preserve output reports
40
+ - Hide feedback messages from output
41
41
  01 (1.0/1.0)
42
- Description : Exits user Obiwan
43
- Command : ********
44
- Duration : 0.002 (local)
45
- Alterations : *******************
46
- Expected : ************** (String)
47
- Result : ******** (String)
42
+ Description : Service SSH disabled
43
+ Command : *********************
44
+ Output : *********
45
+ Duration : 0.011 (local)
46
+ Alterations : **********************
47
+ Expected : **************
48
+ Result : ********
48
49
  ```
@@ -15,15 +15,11 @@ class Case
15
15
  include DSL
16
16
  include Verbose
17
17
 
18
- attr_accessor :action # Updated by ExecuteManager
19
- attr_accessor :result # Updated by ExecuteManager
20
- attr_accessor :sessions # Updated by ExecuteManager
21
- attr_accessor :conn_status # Updated by ExecuteManager
22
-
23
- attr_reader :id
24
- attr_reader :config # Readed by ExecuteManager
25
- attr_reader :uniques
26
- attr_reader :skip
18
+ # Updated by ExecuteManager
19
+ attr_accessor :action, :result, :sessions, :conn_status
20
+ # Readed by ExecuteManager
21
+ attr_reader :id, :config, :uniques, :skip
22
+
27
23
  @@id = "01" # First case ID value
28
24
 
29
25
  def initialize(config)
@@ -2,7 +2,7 @@
2
2
 
3
3
  module DSL
4
4
  # * send, tempfile, tempdir, remote_tempdir, remote_tempfile
5
- def send(args = {})
5
+ def send(logfile, args = {})
6
6
  return if skip?
7
7
 
8
8
  return unless args[:copy_to]
@@ -10,10 +10,10 @@ module DSL
10
10
  host = args[:copy_to].to_s
11
11
  return unless @conn_status[host].nil?
12
12
 
13
- ip = get((host + "_ip").to_sym)
14
- username = get((host + "_username").to_sym).to_s
15
- password = get((host + "_password").to_sym).to_s
16
- port = get((host + "_port").to_sym).to_i
13
+ ip = get(:"#{host}_ip")
14
+ username = get(:"#{host}_username").to_s
15
+ password = get(:"#{host}_password").to_s
16
+ port = get(:"#{host}_port").to_i
17
17
  port = 22 if port.zero?
18
18
 
19
19
  filename = "#{@report.filename}.#{@report.format}"
@@ -32,11 +32,16 @@ module DSL
32
32
  Net::SFTP.start(ip, username, password: password, port: port) do |sftp|
33
33
  sftp.upload!(localfilepath, remotefilepath)
34
34
  end
35
- msg = Rainbow("==> Case #{get(:tt_members)}: report (#{remotefilepath}) copy to (#{ip})").green
35
+ msg = Rainbow("==> [ OK ] Case #{get(:tt_members)}: report (#{remotefilepath}) copy to (#{ip})").green
36
36
  verboseln(msg)
37
- rescue
38
- msg = Rainbow("==> [FAIL] #{get(:tt_members)}: 'scp #{localfilepath}' to #{remotefilepath}").red
37
+ logfile.write "#{msg}\n"
38
+ logfile.flush
39
+ rescue => e
40
+ msg = Rainbow("==> [FAIL] Case #{get(:tt_members)}: 'scp #{localfilepath}' to #{remotefilepath}").red
41
+ msg += "\n--> [ERROR] #{e}"
39
42
  verboseln(msg)
43
+ logfile.write "#{msg}\n"
44
+ logfile.flush
40
45
  end
41
46
  end
42
47
 
@@ -1,24 +1,15 @@
1
1
  require_relative "../utils/project"
2
2
  require_relative "case_manager"
3
3
 
4
- def use(filename)
5
- filename += ".rb"
6
- rbfiles = File.join(Project.value[:project_path], "**", filename)
7
- files = Dir.glob(rbfiles)
8
- findfiles = []
9
- files.sort.each { |f| findfiles << f if f.include?(filename) }
10
- begin
11
- require_relative findfiles.first
12
- Project.value[:uses] << File.basename(findfiles.first)
13
- rescue
14
- puts "[ERROR] Unknown file : #{filename}"
15
- puts " Check line : use '#{filename}'"
16
- exit 1
17
- end
18
- end
4
+ # DSL instructions that apply equally to all cases.
5
+ # Therefore, they are stored globally in the case manager.
6
+ # * define_macro
7
+ # * group
8
+ # * play
9
+ # * use
19
10
 
20
11
  def define_macro(name, *args, &block)
21
- Project.value[:macros][name] = {args: args, block: block}
12
+ Project.value[:macros][name] = { args: args, block: block }
22
13
  end
23
14
  alias def_macro define_macro
24
15
  alias defmacro define_macro
@@ -27,7 +18,7 @@ alias defmacro define_macro
27
18
  # @param name (String) Group name
28
19
  # @param block (Block) Tests code
29
20
  def group(name, &block)
30
- Project.value[:groups] << {name: name, block: block}
21
+ Project.value[:groups] << { name: name, block: block }
31
22
  end
32
23
  alias task group
33
24
 
@@ -36,3 +27,19 @@ def play(&block)
36
27
  CaseManager.new.play(&block)
37
28
  end
38
29
  alias start play
30
+
31
+ def use(filename)
32
+ filename += ".rb"
33
+ rbfiles = File.join(Project.value[:project_path], "**", filename)
34
+ files = Dir.glob(rbfiles)
35
+ findfiles = []
36
+ files.sort.each { |f| findfiles << f if f.include?(filename) }
37
+ begin
38
+ require_relative findfiles.first
39
+ Project.value[:uses] << File.basename(findfiles.first)
40
+ rescue StandardError
41
+ puts "[ERROR] Unknown file : #{filename}"
42
+ puts " Check line : use '#{filename}'"
43
+ exit 1
44
+ end
45
+ end
@@ -22,9 +22,7 @@ class ExportManager
22
22
  end
23
23
 
24
24
  options = strings2symbols(args)
25
- if options[:format].nil?
26
- options[:format] = default_format
27
- end
25
+ options[:format] = default_format if options[:format].nil?
28
26
 
29
27
  # Step 1: Export case reports
30
28
  threads = []
@@ -1,17 +1,33 @@
1
1
  require "rainbow"
2
2
 
3
3
  class SendManager
4
+ def initialize
5
+ logpath = File.join(Project.value[:output_basedir], Project.value[:test_name], "send.log")
6
+ @logfile = File.open(logpath, "a")
7
+ end
8
+
4
9
  ##
5
- # Execute "send" order: Send every case report
10
+ # Execute "send" order: Copy every case report to remote hosts
6
11
  # @param args (Hash) Send options
7
12
  def call(cases, args)
8
13
  threads = []
9
14
  puts ""
10
- puts Rainbow("-" * 50).green
11
- puts Rainbow("Sending files...#{args}").color(:green)
12
- cases.each { |c| threads << Thread.new { c.send(args) } }
15
+ write("-" * 70, :green)
16
+ write("Started at #{Time.new}", :green)
17
+ write("Sending reports to reachable hosts. Options=#{args}", :green)
18
+
19
+ cases.each { |c| threads << Thread.new { c.send(@logfile, args) } }
13
20
  threads.each(&:join)
14
- puts Rainbow("Sending finished!").color(:green)
15
- puts Rainbow("-" * 50).green
21
+
22
+ write("Finished!", :green)
23
+ puts Rainbow("-" * 70).green
24
+ end
25
+
26
+ private
27
+
28
+ def write(msg, color)
29
+ puts Rainbow(msg).color(color)
30
+ @logfile.write "#{msg}\n"
31
+ @logfile.flush
16
32
  end
17
33
  end
@@ -35,6 +35,7 @@ module Formatter
35
35
  xml: XMLFormatter,
36
36
  yaml: YAMLFormatter,
37
37
  moodle_csv: MoodleCSVFormatter,
38
+ resume_colored_text: ResumeColoredTextFormatter,
38
39
  resume_html: ResumeHTMLFormatter,
39
40
  resume_json: ResumeJSONFormatter,
40
41
  resume_txt: ResumeTXTFormatter,
@@ -3,11 +3,7 @@ require_relative "../utils/settings"
3
3
  require_relative "formatter/formatter"
4
4
 
5
5
  class Report
6
- attr_accessor :id, :filename, :output_dir
7
- attr_accessor :head
8
- attr_accessor :lines
9
- attr_accessor :tail
10
- attr_accessor :format
6
+ attr_accessor :id, :filename, :output_dir, :head, :lines, :tail, :format
11
7
  attr_reader :history
12
8
 
13
9
  def initialize(id = "00")
@@ -63,9 +63,9 @@ class Project
63
63
  value[:config_path] = finder.config_path
64
64
  value[:test_name] = finder.test_name
65
65
 
66
- unless value[:options]["case"].nil?
67
- numbers = value[:options]["case"].split(",")
68
- value[:options]["case"] = numbers.collect!(&:to_i)
69
- end
66
+ return if value[:options]["case"].nil?
67
+
68
+ numbers = value[:options]["case"].split(",")
69
+ value[:options]["case"] = numbers.collect!(&:to_i)
70
70
  end
71
71
  end
@@ -1,5 +1,5 @@
1
1
  module Teuton
2
- VERSION = "2.9.6"
2
+ VERSION = "2.10.0"
3
3
  APPNAME = "teuton"
4
4
  GEMNAME = "teuton"
5
5
  DOCKERNAME = "dvarrui/#{GEMNAME}"
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: teuton
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.9.6
4
+ version: 2.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Vargas Ruiz
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-11-06 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: rainbow
@@ -107,6 +107,34 @@ dependencies:
107
107
  - - "~>"
108
108
  - !ruby/object:Gem::Version
109
109
  version: '4.0'
110
+ - !ruby/object:Gem::Dependency
111
+ name: ed25519
112
+ requirement: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - "~>"
115
+ - !ruby/object:Gem::Version
116
+ version: '1.2'
117
+ type: :runtime
118
+ prerelease: false
119
+ version_requirements: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - "~>"
122
+ - !ruby/object:Gem::Version
123
+ version: '1.2'
124
+ - !ruby/object:Gem::Dependency
125
+ name: bcrypt_pbkdf
126
+ requirement: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - "~>"
129
+ - !ruby/object:Gem::Version
130
+ version: '1.0'
131
+ type: :runtime
132
+ prerelease: false
133
+ version_requirements: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - "~>"
136
+ - !ruby/object:Gem::Version
137
+ version: '1.0'
110
138
  description: |2
111
139
  Intrastructure test, useful for:
112
140
  (1) Sysadmin teachers to evaluate students remote machines.
@@ -121,11 +149,8 @@ executables:
121
149
  - teuton
122
150
  extensions: []
123
151
  extra_rdoc_files:
124
- - README.md
125
152
  - LICENSE
126
- - docs/changelog/changelog.1.md
127
- - docs/changelog/changelog.2.md
128
- - docs/changelog/todo.md
153
+ - README.md
129
154
  - docs/commands/README.md
130
155
  - docs/commands/check-example.md
131
156
  - docs/commands/howto-run-tests.md
@@ -190,9 +215,6 @@ files:
190
215
  - LICENSE
191
216
  - README.md
192
217
  - bin/teuton
193
- - docs/changelog/changelog.1.md
194
- - docs/changelog/changelog.2.md
195
- - docs/changelog/todo.md
196
218
  - docs/commands/README.md
197
219
  - docs/commands/check-example.md
198
220
  - docs/commands/howto-run-tests.md
@@ -308,10 +330,6 @@ files:
308
330
  - lib/teuton/check/main.rb
309
331
  - lib/teuton/check/show.rb
310
332
  - lib/teuton/cli.rb
311
- - lib/teuton/deprecated/application.rb
312
- - lib/teuton/deprecated/application_test.rb
313
- - lib/teuton/deprecated/runner.rb
314
- - lib/teuton/deprecated/utils.rb
315
333
  - lib/teuton/files/README.md
316
334
  - lib/teuton/files/config.yaml
317
335
  - lib/teuton/files/start.rb
@@ -368,7 +386,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
368
386
  - !ruby/object:Gem::Version
369
387
  version: '0'
370
388
  requirements: []
371
- rubygems_version: 3.6.2
389
+ rubygems_version: 3.7.2
372
390
  specification_version: 4
373
391
  summary: Teuton (Infrastructure test)
374
392
  test_files: []
@@ -1,119 +0,0 @@
1
- [<< back](../CHANGELOG.md)
2
-
3
- # CHANGELOG
4
-
5
- ## [0.22.1] June 2017
6
-
7
- * Now it's posible to use config files with YAML and JSON format
8
- * Preparing migration of CLI command to use Thor gem
9
-
10
- ## [1.0.0] July 2017
11
-
12
- * New stable version
13
-
14
- ## 2019
15
-
16
- ## [1.10.0] Janyary 2019
17
-
18
- * SysadminGame change his name by TEUTON. "project" command replaced by "teuton".
19
- * Challenges (Teuton scripts) moved to "teuton-challenges" github repository.
20
- * Execute "rake get_challenges" to get sample teuton challenges
21
-
22
- ## [2.0.4] August 2019
23
-
24
- * TEUTON project grew up and was divided into the folowing repositories: teuton, challenges, panel, resources and vagrant.
25
- * Documentation has been moved into respository teuton wiki. Only maintain English docs.
26
-
27
- ## [2.1.0]
28
-
29
- **Export grades on csv file using Moodle format**
30
-
31
- * Automaticaly exports `moodle.csv` file with all cases grades, using adecuate format so it could be imported directly into Moodle platform.
32
- * We need to configure some params like this:
33
-
34
- ```
35
- ---
36
- :global:
37
- :cases:
38
- - :tt_members: ...
39
- :tt_moodle_id: User Moodle Identity
40
- ```
41
-
42
- **readme keyword**
43
-
44
- We currently use the "teuton readme pry-folder" command to export README file from the challenge.
45
-
46
- * This example shows how to use readme keyword to add group description or target description:
47
-
48
- ```
49
- group "GROUPNAME" do
50
- readme "Description for this group"
51
-
52
- target "target1"
53
- readme "Description for this target"
54
- goto :host, :exec => 'id root'
55
- expec_one 'root'
56
- ```
57
-
58
- **Installation process**
59
-
60
- * Use Bundler to install gems instead of rake.
61
- * It will be usefull use sysadming-game as gem? And install it with `gem install teuton`.
62
- * Vagrant: test how to use vagrant machines as case hosts.
63
-
64
- **Info sobre novedades de la versión 2.1**
65
-
66
- 1. Teuton readme y dsl readme
67
- 2. Macros de define macro
68
- 3. Export yaml y html
69
- 4. Teuton --no-color
70
- 5. teuton run --case
71
- 6. teuton run --cname
72
- 7. teuton run --cpath
73
- 8. actualizar formatos de salida
74
- 9. instalación mediante gemas
75
- 10. teuton panel
76
- 11. teuton client y server
77
- 12. nuevos nombres de comandos...
78
- 13. cambio de goto a run
79
-
80
- ## [2.2.0]
81
-
82
- **New features**
83
-
84
- * Let's see new features examples:
85
- * 10 result and moodle_id
86
- * 11 get_vars
87
- * 12 alias
88
- * 13 include (tt_include config param)
89
- * 14 macros
90
-
91
- **Configuration file**
92
-
93
- * Por defecto los valores de clave de los ficheros de configuración serán Strings en lugar de símbolos, aunque lo símbolos seguirán funcionando.
94
-
95
- **get_vars: To think - We are not sure about this***
96
-
97
- * "get" keyword simplification: Simplify getting and setting params process. For example: `_username_`, may be alias for `get(:username)`. Then
98
-
99
- ```
100
- target "Create user #{_username_}"
101
- run "id #{_username_}"
102
- expect_one _username_
103
- ```
104
- Same as
105
-
106
- ```
107
- target "Create user "+get(:username)
108
- run "id " + get(:username)
109
- expect_one get(:username)
110
- ```
111
-
112
- * Promocinar el proyecto:
113
- * Documentar y hacer videos.
114
- * Charlas y talleres
115
-
116
- **Fixed**
117
-
118
- * Solucionar fallo en --cname
119
- * Revisar doc options como cpanel
@@ -1,136 +0,0 @@
1
-
2
- ## [2.3.9]
3
-
4
- - FIX: Remove warnings from linter
5
- - FIX: Remove warning about thor gem version. Upgrade gem to 1.2
6
-
7
- ## [2.3.11]
8
-
9
- - Issue #18
10
-
11
- ## [2.4.0]
12
-
13
- New features:
14
- - Hide feedback from reports: `export feedback: false`
15
- - Add new DSL keyword: expect_last, expect_fisrt
16
- - Remove os gem.
17
- - Change test output colors to green as use others test tools.
18
- - Change show DSL params. Accepts one param "verbose: NUMBER" to adjust verbosity output level on screen.
19
-
20
- New doc and example:
21
- - 14-alias
22
- - 16-exit_codes
23
-
24
- Bug fixed:
25
- - All "expect*" keywords must require 2 arguments. The second is optional.
26
-
27
- Revise
28
- - Remove colors to log text
29
- - teuton readme: macros, getvars, expect_last, expect_first
30
-
31
- ## [2.4.2]
32
-
33
- - Fix bug with result.grep_v(Array)
34
-
35
- ## [2.4.3]
36
-
37
- - Fix: "expect_none" without params works as "expect result.count.eq 0"
38
- - Add: "expect_nothing" that works as "expect result.count.eq 0".
39
-
40
- ## [2.4.4]
41
-
42
- -- Modify: teuton check output colors and exit codes.
43
- exit code 0 = check OK
44
- exit code 1 = check error
45
- -- Fix teuton check docs.
46
-
47
- ## [2.4.5]
48
-
49
- -- FIX: "expect_nothing" was always TRUE when SSH/Telnet connections fails!
50
- Now when SSH/Telnet connections fails result contains "SSH: NO CONNECTION!"
51
- So "expect_nothing" will fail.
52
-
53
- ## [2.5.0]
54
-
55
- - ADD: "tt_moodle_max_score" global configuration param. Teuton grades (0-100) are divided by this value when exporting data into "moodle.csv" output file.
56
- - UPDATE: Revise documentation. Doc learn 10,11, 12,13 y 14. 10 result and moodle_id, 12 alias, 13 include, 14 macro, Doc tt_include
57
- - UPDATE: Internal changes. Remove Colorize gem and replace with Rainbow.
58
-
59
- ## [2.6.0]
60
-
61
- - [ADD] When running local or SSH commands, stdout and stderr are captured and readed by "expect" sentence.
62
-
63
- ## [2.7.0]
64
-
65
- New features:
66
- - [ADD] "teuton config PROJECTPATH" will suggest suitable configuration for the project.
67
- - [ADD] Every one line command output is registered into reports.
68
- - [ADD] "expect_exit 1", check last command exit code is equal to 1.
69
-
70
- Internal changes:
71
- * Application class splited into Settings and Project classes
72
- * Create SendManager similar to ExportManager
73
-
74
- ## [2.7.1]
75
-
76
- - [FIX] Fixed an issue that appeared when executing test and fail connection to remote computer.
77
-
78
- ## [2.7.2] 20230607
79
-
80
- - [FIX] Fixed an issue that appeared when exporting reports without feedback after failing to connect to remote computer.
81
-
82
- ## [2.7.3] 20230607
83
-
84
- - [FIX] Hall of fame now use Project class instead of Application.
85
-
86
- ## [2.8.0] 20230630
87
-
88
- DSL expect:
89
- - [ADD] "expect_ok" as "expect_exit 0 ".
90
- - [ADD] "expect_fail" as "expect_exit NUMBER" where NUMBER > 0.
91
- - [FIX] expect evaluation fail when there is no remote connection.
92
-
93
- DSL send:
94
- - [UPDATE] Rename "remote_dir" send param to "dir".
95
- - [UPDATE] send output messages
96
-
97
- ## [2.9.0] 20230726
98
-
99
- - [ADD] "expect_sequence" that check if sequence is present
100
- - [ADD] New DSL "run_script". Example: `run_script script, on: :host1`, upload script to host1 and then execute it on remote.
101
- - [ADD] New DSL "upload". Upload local file to remote host. Example `upload "localfile", to: :host1`
102
- - [ADD] `teuton check` works with `expect_sequence`, `run_script` and `upload`.
103
- - [FIX] `teuton check` works fine with `macros`.
104
- - [ADD] `teuton readme` works with `expect_sequence`, `run_script` and `upload`.
105
- - [FIX] `teuton readme` works fine with `macros`.
106
-
107
- ## [2.9.1] 20231117
108
-
109
- - [FIX] Config option `tt_include` doubled readed data on Windows platforms.
110
-
111
- ## [2.9.2] 20231201
112
-
113
- - [FIX] Change error message when running a non-existent challenge
114
- ```
115
- ❯ teuton run example/foo
116
- [ERROR] Cannot find main file!
117
- /home/username/example/foo/start.rb
118
- or /home/username/example/foo.rb
119
- ```
120
-
121
- ## [2.9.3] 20250402
122
-
123
- - [FIX] Error with telnet connections.
124
-
125
- ## [2.9.4] 20250410
126
-
127
- - [FIX] Improve the markdown output of the readme.
128
- - [FIX] Telnet exitcode
129
-
130
- ## [2.9.5] 20250514
131
-
132
- - [FIX] `require "json_pure"`is deprecated. Use `json` gem instead of `json_pure`.
133
-
134
- ## [2.9.6] 20251106
135
-
136
- - [FIX] Problem with `export preserve: true`. It was using old class Application. Now use Project class.
@@ -1,16 +0,0 @@
1
-
2
- ## TO-DO
3
-
4
- New features:
5
- - Teuton readme --lang=es and export files with other langs
6
- - Snode Dockerfile with SSH server
7
- - Auto Parse new input format, and detect parse errors
8
-
9
- Revise:
10
- * verify get(:key) and get('key') works fine!
11
- * Formatter: xml
12
-
13
- Internal changes:
14
- * Laboratory to Checker
15
- * Unify messages ERROR, INFO, WARN. etc
16
- * Add tt_label as alias of tt_members
@@ -1,80 +0,0 @@
1
- require "singleton"
2
- require_relative "name_file_finder"
3
-
4
- class Application
5
- include Singleton
6
-
7
- attr_reader :letter
8
- attr_reader :running_basedir, :output_basedir
9
- attr_reader :default
10
- attr_accessor :options
11
- attr_accessor :verbose
12
- attr_accessor :global # Global configuration params
13
- attr_accessor :ialias # Internal alias
14
- attr_accessor :uses # Array of uses
15
- attr_accessor :project_path, :script_path, :config_path, :test_name
16
-
17
- def initialize
18
- reset
19
- end
20
-
21
- def reset
22
- @letter = {
23
- good: ".",
24
- bad: "F",
25
- error: "?",
26
- none: " ",
27
- ok: "\u{2714}",
28
- cross: "\u{2716}"
29
- }
30
- @running_basedir = Dir.getwd
31
- @output_basedir = "var"
32
- @default = {name: "teuton", format: :txt, debug: false}
33
- @options = {
34
- "lang" => "en",
35
- "color" => true,
36
- "panel" => false
37
- }
38
- @verbose = true
39
-
40
- @global = {}
41
- @ialias = {}
42
- @uses = [] # TODO
43
- end
44
-
45
- def debug
46
- @default[:debug]
47
- end
48
-
49
- def name
50
- @default[:name]
51
- end
52
-
53
- def quiet?
54
- return true if Application.instance.options["quiet"]
55
- return true unless Application.instance.verbose
56
-
57
- false
58
- end
59
-
60
- ##
61
- # Preprocess input options:
62
- # * Convert input case options String to an Array of integers
63
- # * Read color input option
64
- def add_input_params(projectpath, options)
65
- @options.merge! options
66
- Rainbow.enabled = @options["color"]
67
-
68
- finder = NameFileFinder.new(@options)
69
- finder.find_filenames_for(projectpath)
70
- @project_path = finder.project_path
71
- @script_path = finder.script_path
72
- @config_path = finder.config_path
73
- @test_name = finder.test_name
74
-
75
- unless @options["case"].nil?
76
- numbers = @options["case"].split(",")
77
- @options["case"] = numbers.collect!(&:to_i)
78
- end
79
- end
80
- end
@@ -1,32 +0,0 @@
1
- require "test/unit"
2
- require_relative "../../lib/teuton/utils/application"
3
-
4
- class ApplicationTest < Test::Unit::TestCase
5
- def setup
6
- @app = Application.instance
7
- @app.reset
8
- end
9
-
10
- def test_init_params
11
- assert_equal ".", @app.letter[:good]
12
- assert_equal "F", @app.letter[:bad]
13
- assert_equal "?", @app.letter[:error]
14
- assert_equal " ", @app.letter[:none]
15
- assert_equal "var", @app.output_basedir
16
- assert_equal false, @app.debug
17
- assert_equal true, @app.verbose
18
-
19
- assert_equal true, @app.global == {}
20
- end
21
-
22
- def test_quiet?
23
- @app.verbose = false
24
- assert_equal false, @app.verbose
25
- assert_equal true, Application.instance.quiet?
26
- @app.verbose = true
27
- assert_equal true, @app.verbose
28
- assert_equal false, Application.instance.quiet?
29
- @app.options["quiet"] = true
30
- assert_equal true, Application.instance.quiet?
31
- end
32
- end
@@ -1,190 +0,0 @@
1
- require "net/ssh"
2
- require "net/sftp"
3
- require "net/telnet"
4
- require_relative "dsl/log"
5
-
6
- class Case
7
- private
8
-
9
- # READ: @config
10
- # WRITE: @action, @result, @session
11
- def run_cmd_on(host)
12
- protocol = @config.get(:"#{host}_protocol")
13
- ip = @config.get(:"#{host}_ip")
14
-
15
- if protocol.to_s.downcase == "local" || host.to_s == "localhost"
16
- # Protocol force => local
17
- run_cmd_localhost
18
- elsif protocol.to_s.downcase == "ssh"
19
- # Protocol force => ssh
20
- run_cmd_remote_ssh(host)
21
- elsif protocol.to_s.downcase == "telnet"
22
- # Protocol force => telnet
23
- run_cmd_remote_telnet(host)
24
- elsif ip.to_s.downcase == "localhost" || ip.to_s.include?("127.0.0.")
25
- run_cmd_localhost
26
- elsif ip == "NODATA"
27
- log("#{host} IP not found!", :error)
28
- else
29
- run_cmd_remote_ssh host
30
- end
31
- end
32
-
33
- def run_cmd_localhost
34
- @action[:conn_type] = :local
35
- resp = my_execute(@action[:command], @action[:encoding])
36
- @result.exitcode = resp[:exitcode]
37
- @result.content = resp[:content]
38
- end
39
-
40
- def run_cmd_remote(input_hostname)
41
- # @param input_hostname (Symbol or String)
42
- hostname = input_hostname.to_s
43
- i = (hostname + "_protocol").to_sym
44
- protocol = @config.get(i) if @config.get(i)
45
- protocol = :ssh if protocol.nil? || protocol == "NODATA"
46
- protocol = protocol.to_sym
47
- case protocol
48
- when :ssh
49
- run_cmd_remote_ssh(input_hostname)
50
- when :telnet
51
- run_cmd_remote_telnet(input_hostname)
52
- when :local
53
- run_cmd_localhost
54
- else
55
- log("Protocol #{protocol} unknown! Use ssh or telnet.", :error)
56
- end
57
- end
58
-
59
- def run_cmd_remote_ssh(input_hostname)
60
- @action[:conn_type] = :ssh
61
- hostname = input_hostname.to_s
62
- ip = @config.get(:"#{hostname}_ip").to_s
63
- username = @config.get(:"#{hostname}_username").to_s
64
- password = @config.get(:"#{hostname}_password").to_s
65
- port = @config.get(:"#{hostname}_port").to_i
66
- port = 22 if port.zero?
67
-
68
- unless @config.get(:"#{hostname}_route") == "NODATA"
69
- # Reconfigure command with gateway. Example host1_route: IP.
70
- # hostname2 = hostname ¿not used?
71
- ip2 = ip
72
- username2 = username
73
- password2 = password
74
- command2 = @action[:command]
75
- hostname = @config.get(:"#{hostname}_route")
76
- ip = @config.get(:"#{hostname}_ip").to_s
77
- username = @config.get(:"#{hostname}_username").to_s
78
- password = @config.get(:"#{hostname}_password").to_s
79
- ostype = @config.get(:"#{hostname}_ostype").to_s
80
-
81
- @action[:command] = if ostype.downcase.start_with? "win"
82
- "echo y | plink #{username2}@#{ip2} -ssh -pw #{password2} \"#{command2}\""
83
- else
84
- "sshpass -p #{password2} #{username2}@#{ip2} #{command2}"
85
- end
86
- end
87
-
88
- text = ""
89
- exitcode = 0
90
- begin
91
- if @sessions[hostname].nil?
92
- @sessions[hostname] = Net::SSH.start(
93
- ip,
94
- username,
95
- port: port,
96
- password: password,
97
- keepalive: true,
98
- timeout: 30,
99
- non_interactive: true
100
- )
101
- end
102
- text = if @sessions[hostname].instance_of? Net::SSH::Connection::Session
103
- @sessions[hostname].exec!(@action[:command])
104
- else
105
- "SSH: NO CONNECTION!"
106
- end
107
- exitcode = text.exitstatus
108
- rescue Errno::EHOSTUNREACH
109
- @sessions[hostname] = :nosession
110
- @conn_status[hostname] = :host_unreachable
111
- exitcode = -1
112
- log("Host #{ip} unreachable!", :error)
113
- rescue Net::SSH::AuthenticationFailed
114
- @sessions[hostname] = :nosession
115
- @conn_status[hostname] = :error_authentication_failed
116
- exitcode = -1
117
- log("SSH::AuthenticationFailed!", :error)
118
- rescue Net::SSH::HostKeyMismatch
119
- @sessions[hostname] = :nosession
120
- @conn_status[hostname] = :host_key_mismatch
121
- exitcode = -1
122
- log("SSH::HostKeyMismatch!", :error)
123
- log("* The destination server's fingerprint is not matching " \
124
- "what is in your local known_hosts file.", :error)
125
- log("* Remove the existing entry in your local known_hosts file", :error)
126
- log("* Try this => ssh-keygen -f '/home/USERNAME/.ssh/known_hosts' " \
127
- "-R #{ip}", :error)
128
- rescue => e
129
- @sessions[hostname] = :nosession
130
- @conn_status[hostname] = :error
131
- exitcode = -1
132
- log("[#{e.class}] SSH on <#{username}@#{ip}>" \
133
- " exec: #{@action[:command]}", :error)
134
- end
135
- output = encode_and_split(@action[:encoding], text)
136
- @result.exitcode = exitcode
137
- @result.content = output
138
- @result.content.compact!
139
- end
140
-
141
- def run_cmd_remote_telnet(input_hostname)
142
- @action[:conn_type] = :telnet
143
- # app = Application.instance ¿not used?
144
- hostname = input_hostname.to_s
145
- ip = @config.get((hostname + "_ip").to_sym)
146
- username = @config.get((hostname + "_username").to_sym).to_s
147
- password = @config.get((hostname + "_password").to_sym).to_s
148
- text = ""
149
- begin
150
- if @sessions[hostname].nil? || @sessions[hostname] == :ok
151
- h = Net::Telnet.new(
152
- "Host" => ip,
153
- "Timeout" => 30,
154
- "Prompt" => /login|teuton|[$%#>]/
155
- )
156
- # "Prompt" => Regexp.new(username[1, 40]))
157
- # "Prompt" => /[$%#>] \z/n)
158
- h.login(username, password)
159
- h.cmd(@action[:command]) { |i| text << i }
160
- h.close
161
- @sessions[hostname] = :ok
162
- else
163
- text = "TELNET: NO CONNECTION!"
164
- end
165
- rescue Net::OpenTimeout
166
- @sessions[hostname] = :nosession
167
- @conn_status[hostname] = :open_timeout
168
- verbose Rainbow(Application.instance.letter[:error]).red.bright
169
- log(" ExceptionType=<Net::OpenTimeout> doing <telnet #{ip}>", :error)
170
- log(" └── Revise host IP!", :warn)
171
- rescue Net::ReadTimeout
172
- @sessions[hostname] = :nosession
173
- @conn_status[hostname] = :read_timeout
174
- verbose Rainbow(Application.instance.letter[:error]).red.bright
175
- log(" ExceptionType=<Net::ReadTimeout> doing <telnet #{ip}>", :error)
176
- rescue => e
177
- @sessions[hostname] = :nosession
178
- @conn_status[hostname] = :error
179
- verbose Rainbow(Application.instance.letter[:error]).red.bright
180
- log(" ExceptionType=<#{e.class}> doing telnet on <#{username}@#{ip}>" \
181
- " exec: #{@action[:command]}", :error)
182
- log(" └── username=<#{username}>, password=<#{password}>," \
183
- " ip=<#{ip}>, HOSTID=<#{hostname}>", :warn)
184
- end
185
- output = encode_and_split(@action[:encoding], text)
186
- @result.exitcode = -1
187
- @result.content = output
188
- @result.content.compact!
189
- end
190
- end
@@ -1,40 +0,0 @@
1
- require "open3"
2
- require "rainbow"
3
- require_relative "../utils/project"
4
-
5
- module Utils
6
- def encode_and_split(encoding, text)
7
- # Convert text to UTF-8 deleting unknown chars
8
- text ||= "" # Ensure text is not nil
9
- flag = [:default, "UTF-8"].include? encoding
10
- return text.encode("UTF-8", invalid: :replace).split("\n") if flag
11
-
12
- # Convert text from input ENCODING to UTF-8
13
- ec = Encoding::Converter.new(encoding.to_s, "UTF-8")
14
- begin
15
- text = ec.convert(text)
16
- rescue => e
17
- warn "[ERROR] #{e}"
18
- warn " Suggest declare text encoding, for example:"
19
- warn " run 'command', on: :host, :encoding => 'ISO-8859-1'"
20
- end
21
-
22
- text.split("\n")
23
- end
24
-
25
- def my_execute(cmd, encoding = "UTF-8")
26
- # TODO: mover a la clase ExecuteManager
27
- return {exitstatus: 0, content: ""} if Project.debug?
28
-
29
- begin
30
- text, status = Open3.capture2e(cmd)
31
- exitstatus = status.exitstatus
32
- rescue => e
33
- verbose Rainbow("!").green
34
- text = e.to_s
35
- exitstatus = 1
36
- end
37
- content = encode_and_split(encoding, text)
38
- {exitstatus: exitstatus, content: content}
39
- end
40
- end