train-core 2.0.8 → 2.0.12

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: 6296676d2fb3138e2e4e3f660e6bc9d871f10419318ba3344ca472c1eca7f0d2
4
- data.tar.gz: 8c5d1f00ee0c1e4dffa9520c8c622cd5333716a90576d52dfc5856f2ce7bf6de
3
+ metadata.gz: 6428f10f1fcb461fff9d6a262ed8a8c643ca0aaf21cc60a0ddeff1573f4e3c0e
4
+ data.tar.gz: a1d8450b00960078fb2116ec40dd3f1e61a5976a4aa6aa14e4c0a3e73596f27b
5
5
  SHA512:
6
- metadata.gz: 97150adffc1f18041eb3c1f7c77c439920674a2f1d40ef90b7720eeb808bc98709d4cd646af0fae949a47229703dc19988ac2ca54b21e1de5aeb2b71a873a4d1
7
- data.tar.gz: '028b9286800362e7e945c6fa5d3efde308e5b917233e7e9367b00ba289e87902ac4a8ccfcb55bf6879d7548340a40156e0cf2a05035c139d86d216dd27bda036'
6
+ metadata.gz: 338cd5ee7abda4182c71c3132336b647ab5353d90934673fdf156577506167e109e557b6c139288b5dcc89476742a34eb692b95bfd99ad7159775f531f90c3ee
7
+ data.tar.gz: d15361a0bc4362272ea783c5198dea4ef6dbb5beb1a3878e04eb4484126f0b5daa2fdb0dbe725b5828da9cf48519f3d43730860a5a4e7de3ceaac7284b13f765
@@ -0,0 +1,128 @@
1
+ # encoding: utf-8
2
+
3
+ class Train::Transports::SSH
4
+ class CiscoIOSConnection < BaseConnection
5
+ class BadEnablePassword < Train::TransportError; end
6
+
7
+ def initialize(options)
8
+ super(options)
9
+
10
+ # Extract options to avoid passing them in to `Net::SSH.start` later
11
+ @host = options.delete(:host)
12
+ @user = options.delete(:user)
13
+ @port = options.delete(:port)
14
+ @enable_password = options.delete(:enable_password)
15
+
16
+ # Use all options left that are not `nil` for `Net::SSH.start` later
17
+ @ssh_options = options.reject { |_key, value| value.nil? }
18
+
19
+ @prompt = /^\S+[>#]\r\n.*$/
20
+ end
21
+
22
+ def uri
23
+ "ssh://#{@user}@#{@host}:#{@port}"
24
+ end
25
+
26
+ def unique_identifier
27
+ result = run_command_via_connection('show version | include Processor')
28
+ result.stdout.split(' ')[-1]
29
+ end
30
+
31
+ private
32
+
33
+ def establish_connection
34
+ logger.debug("[SSH] opening connection to #{self}")
35
+
36
+ Net::SSH.start(@host, @user, @ssh_options)
37
+ end
38
+
39
+ def session
40
+ return @session unless @session.nil?
41
+
42
+ @session = open_channel(establish_connection)
43
+
44
+ # Escalate privilege to enable mode if password is given
45
+ if @enable_password
46
+ # This verifies we are not in privileged exec mode before running the
47
+ # enable command. Otherwise, the password will be in history.
48
+ if run_command_via_connection('show privilege').stdout.split[-1] != '15'
49
+ run_command_via_connection("enable\r\n#{@enable_password}")
50
+ end
51
+ end
52
+
53
+ # Prevent `--MORE--` by removing terminal length limit
54
+ run_command_via_connection('terminal length 0')
55
+
56
+ @session
57
+ end
58
+
59
+ def run_command_via_connection(cmd, &_data_handler)
60
+ # Ensure buffer is empty before sending data
61
+ @buf = ''
62
+
63
+ logger.debug("[SSH] Running `#{cmd}` on #{self}")
64
+ session.send_data(cmd + "\r\n")
65
+
66
+ logger.debug('[SSH] waiting for prompt')
67
+ until @buf =~ @prompt
68
+ raise BadEnablePassword if @buf =~ /Bad secrets/
69
+ session.connection.process(0)
70
+ end
71
+
72
+ # Save the buffer and clear it for the next command
73
+ output = @buf.dup
74
+ @buf = ''
75
+
76
+ format_result(format_output(output, cmd))
77
+ end
78
+
79
+ ERROR_MATCHERS = [
80
+ 'Bad IP address',
81
+ 'Incomplete command',
82
+ 'Invalid input detected',
83
+ 'Unrecognized host',
84
+ ].freeze
85
+
86
+ # IOS commands do not have an exit code so we must compare the command
87
+ # output with partial segments of known errors. Then, we return a
88
+ # `CommandResult` with arguments in the correct position based on the
89
+ # result.
90
+ def format_result(result)
91
+ if ERROR_MATCHERS.none? { |e| result.include?(e) }
92
+ CommandResult.new(result, '', 0)
93
+ else
94
+ CommandResult.new('', result, 1)
95
+ end
96
+ end
97
+
98
+ # The buffer (@buf) contains all data sent/received on the SSH channel so
99
+ # we need to format the data to match what we would expect from Train
100
+ def format_output(output, cmd)
101
+ leading_prompt = /(\r\n|^)\S+[>#]/
102
+ command_string = /#{Regexp.quote(cmd)}\r\n/
103
+ trailing_prompt = /\S+[>#](\r\n|$)/
104
+ trailing_line_endings = /(\r\n)+$/
105
+
106
+ output
107
+ .sub(leading_prompt, '')
108
+ .sub(command_string, '')
109
+ .gsub(trailing_prompt, '')
110
+ .gsub(trailing_line_endings, '')
111
+ end
112
+
113
+ # Create an SSH channel that writes to @buf when data is received
114
+ def open_channel(ssh)
115
+ logger.debug("[SSH] opening SSH channel to #{self}")
116
+ ssh.open_channel do |ch|
117
+ ch.on_data do |_, data|
118
+ @buf += data
119
+ end
120
+
121
+ ch.send_channel_request('shell') do |_, success|
122
+ raise 'Failed to open SSH shell' unless success
123
+ logger.debug('[SSH] shell opened')
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end
data/lib/train/version.rb CHANGED
@@ -3,5 +3,5 @@
3
3
  # Author:: Dominik Richter (<dominik.richter@gmail.com>)
4
4
 
5
5
  module Train
6
- VERSION = '2.0.8'.freeze
6
+ VERSION = '2.0.12'.freeze
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: train-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.8
4
+ version: 2.0.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dominik Richter
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-04-19 00:00:00.000000000 Z
11
+ date: 2019-04-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json
@@ -90,34 +90,6 @@ dependencies:
90
90
  - - "<"
91
91
  - !ruby/object:Gem::Version
92
92
  version: '3.0'
93
- - !ruby/object:Gem::Dependency
94
- name: ed25519
95
- requirement: !ruby/object:Gem::Requirement
96
- requirements:
97
- - - "~>"
98
- - !ruby/object:Gem::Version
99
- version: '1.2'
100
- type: :runtime
101
- prerelease: false
102
- version_requirements: !ruby/object:Gem::Requirement
103
- requirements:
104
- - - "~>"
105
- - !ruby/object:Gem::Version
106
- version: '1.2'
107
- - !ruby/object:Gem::Dependency
108
- name: bcrypt_pbkdf
109
- requirement: !ruby/object:Gem::Requirement
110
- requirements:
111
- - - "~>"
112
- - !ruby/object:Gem::Version
113
- version: '1.0'
114
- type: :runtime
115
- prerelease: false
116
- version_requirements: !ruby/object:Gem::Requirement
117
- requirements:
118
- - - "~>"
119
- - !ruby/object:Gem::Version
120
- version: '1.0'
121
93
  - !ruby/object:Gem::Dependency
122
94
  name: winrm
123
95
  requirement: !ruby/object:Gem::Requirement
@@ -187,6 +159,7 @@ files:
187
159
  - lib/train/plugins.rb
188
160
  - lib/train/plugins/base_connection.rb
189
161
  - lib/train/plugins/transport.rb
162
+ - lib/train/transports/cisco_ios_connection.rb
190
163
  - lib/train/transports/local.rb
191
164
  - lib/train/transports/mock.rb
192
165
  - lib/train/transports/ssh.rb
@@ -206,7 +179,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
206
179
  requirements:
207
180
  - - ">="
208
181
  - !ruby/object:Gem::Version
209
- version: '0'
182
+ version: '2.4'
210
183
  required_rubygems_version: !ruby/object:Gem::Requirement
211
184
  requirements:
212
185
  - - ">="