train 1.3.0 → 1.4.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
  SHA1:
3
- metadata.gz: '095b1ae4856669cbe224dffbfa09f555ce7c0d05'
4
- data.tar.gz: ee6cc55a500e4466e497e853e49963a05b1f85d2
3
+ metadata.gz: f666a5aa2bb040f3bc662ef2881d2a3778764cc9
4
+ data.tar.gz: 6e84e3102772ea858d8f4827f959e74f0d7a396f
5
5
  SHA512:
6
- metadata.gz: ea321b3f07afc791e16628f7d4f26277dc7caed537e29f8351dd8934741af77b8ee137ce35184d820c2aca2e02b335d6fdb538784577f11a06e9c7be1924ef07
7
- data.tar.gz: d3a80455ea2819ccdb0ba1e92fdd94c7525604d6dfe49345902531e44eef9c06fd08d39b7911ac9464d44da4f762cd46fe10ab377804327237e4ba7e6405f987
6
+ metadata.gz: 376156ec17342f41fb82f5a1e8888e1c19b31f8760fd0ceaed4b664f68acf54c759129d3a458c0343c19d0925c70a09f715d1c8f18171d82b506c6ab331267f9
7
+ data.tar.gz: 5bce1e60af8264a419c68898e8efca072e0f5004313a9aabb1b83a978956618e21d6d3bc9de9ee848a93b482bfe6ec751d713bda18035074814b15294d5502da
data/CHANGELOG.md CHANGED
@@ -1,7 +1,21 @@
1
1
  # Change Log
2
2
 
3
- ## [1.3.0](https://github.com/chef/train/tree/1.3.0) (2018-03-29)
4
- [Full Changelog](https://github.com/chef/train/compare/v1.2.0...1.3.0)
3
+ ## [1.4.0](https://github.com/chef/train/tree/1.4.0) (2018-04-12)
4
+ [Full Changelog](https://github.com/chef/train/compare/v1.3.0...1.4.0)
5
+
6
+ **Closed issues:**
7
+
8
+ - Train reports directories with the archive bit set as files on the windows platform [\#274](https://github.com/chef/train/issues/274)
9
+
10
+ **Merged pull requests:**
11
+
12
+ - Add CloudLinux as a detected platform [\#281](https://github.com/chef/train/pull/281) ([tarcinil](https://github.com/tarcinil))
13
+ - Move Cisco IOS connection under SSH transport [\#279](https://github.com/chef/train/pull/279) ([jerryaldrichiii](https://github.com/jerryaldrichiii))
14
+ - Initialize FileManager using '@service' [\#278](https://github.com/chef/train/pull/278) ([marcparadise](https://github.com/marcparadise))
15
+ - small fix to make sure windows directories with the archive bit set a… [\#275](https://github.com/chef/train/pull/275) ([devoptimist](https://github.com/devoptimist))
16
+
17
+ ## [v1.3.0](https://github.com/chef/train/tree/v1.3.0) (2018-03-29)
18
+ [Full Changelog](https://github.com/chef/train/compare/v1.2.0...v1.3.0)
5
19
 
6
20
  **Implemented enhancements:**
7
21
 
@@ -13,6 +27,7 @@
13
27
 
14
28
  **Merged pull requests:**
15
29
 
30
+ - Release Train 1.3.0 [\#276](https://github.com/chef/train/pull/276) ([jquick](https://github.com/jquick))
16
31
  - Add MSI connection option for azure. [\#272](https://github.com/chef/train/pull/272) ([jquick](https://github.com/jquick))
17
32
  - Add transport for Cisco IOS [\#271](https://github.com/chef/train/pull/271) ([jerryaldrichiii](https://github.com/jerryaldrichiii))
18
33
  - Add platform uuid information. [\#270](https://github.com/chef/train/pull/270) ([jquick](https://github.com/jquick))
@@ -39,7 +39,7 @@ module Train
39
39
  end
40
40
 
41
41
  def type
42
- if attributes.include?('Archive')
42
+ if attributes.include?('Archive') && !attributes.include?('Directory')
43
43
  return :file
44
44
  elsif attributes.include?('ReparsePoint')
45
45
  return :symlink
@@ -195,6 +195,18 @@ module Train::Platforms::Detect::Specifications
195
195
  true
196
196
  end
197
197
  }
198
+ plat.name('cloudlinux').title('CloudLinux').in_family('redhat')
199
+ .detect {
200
+ lsb = read_linux_lsb
201
+ if lsb && lsb[:id] =~ /cloudlinux/i
202
+ @platform[:release] = lsb[:release]
203
+ true
204
+ elsif (raw = unix_file_contents('/etc/redhat-release')) =~ /cloudlinux/i
205
+ @platform[:name] = redhatish_platform(raw)
206
+ @platform[:release] = redhatish_version(raw)
207
+ true
208
+ end
209
+ }
198
210
  # keep redhat at the end as a fallback for anything with a redhat-release
199
211
  plat.name('redhat').title('Red Hat Linux').in_family('redhat')
200
212
  .detect {
@@ -0,0 +1,119 @@
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
+ private
27
+
28
+ def establish_connection
29
+ logger.debug("[SSH] opening connection to #{self}")
30
+
31
+ Net::SSH.start(@host, @user, @ssh_options)
32
+ end
33
+
34
+ def session
35
+ return @session unless @session.nil?
36
+
37
+ @session = open_channel(establish_connection)
38
+
39
+ # Escalate privilege to enable mode if password is given
40
+ if @enable_password
41
+ run_command_via_connection("enable\r\n#{@enable_password}")
42
+ end
43
+
44
+ # Prevent `--MORE--` by removing terminal length limit
45
+ run_command_via_connection('terminal length 0')
46
+
47
+ @session
48
+ end
49
+
50
+ def run_command_via_connection(cmd)
51
+ # Ensure buffer is empty before sending data
52
+ @buf = ''
53
+
54
+ logger.debug("[SSH] Running `#{cmd}` on #{self}")
55
+ session.send_data(cmd + "\r\n")
56
+
57
+ logger.debug('[SSH] waiting for prompt')
58
+ until @buf =~ @prompt
59
+ raise BadEnablePassword if @buf =~ /Bad secrets/
60
+ session.connection.process(0)
61
+ end
62
+
63
+ # Save the buffer and clear it for the next command
64
+ output = @buf.dup
65
+ @buf = ''
66
+
67
+ format_result(format_output(output, cmd))
68
+ end
69
+
70
+ ERROR_MATCHERS = [
71
+ 'Bad IP address',
72
+ 'Incomplete command',
73
+ 'Invalid input detected',
74
+ 'Unrecognized host',
75
+ ].freeze
76
+
77
+ # IOS commands do not have an exit code so we must compare the command
78
+ # output with partial segments of known errors. Then, we return a
79
+ # `CommandResult` with arguments in the correct position based on the
80
+ # result.
81
+ def format_result(result)
82
+ if ERROR_MATCHERS.none? { |e| result.include?(e) }
83
+ CommandResult.new(result, '', 0)
84
+ else
85
+ CommandResult.new('', result, 1)
86
+ end
87
+ end
88
+
89
+ # The buffer (@buf) contains all data sent/received on the SSH channel so
90
+ # we need to format the data to match what we would expect from Train
91
+ def format_output(output, cmd)
92
+ leading_prompt = /(\r\n|^)\S+[>#]/
93
+ command_string = /#{Regexp.quote(cmd)}\r\n/
94
+ trailing_prompt = /\S+[>#](\r\n|$)/
95
+ trailing_line_endings = /(\r\n)+$/
96
+
97
+ output
98
+ .sub(leading_prompt, '')
99
+ .sub(command_string, '')
100
+ .gsub(trailing_prompt, '')
101
+ .gsub(trailing_line_endings, '')
102
+ end
103
+
104
+ # Create an SSH channel that writes to @buf when data is received
105
+ def open_channel(ssh)
106
+ logger.debug("[SSH] opening SSH channel to #{self}")
107
+ ssh.open_channel do |ch|
108
+ ch.on_data do |_, data|
109
+ @buf += data
110
+ end
111
+
112
+ ch.send_channel_request('shell') do |_, success|
113
+ raise 'Failed to open SSH shell' unless success
114
+ logger.debug('[SSH] shell opened')
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
@@ -37,6 +37,7 @@ module Train::Transports
37
37
  name 'ssh'
38
38
 
39
39
  require 'train/transports/ssh_connection'
40
+ require 'train/transports/cisco_ios_connection'
40
41
 
41
42
  # add options for submodules
42
43
  include_options Train::Extras::CommandWrapper
@@ -193,6 +194,19 @@ module Train::Transports
193
194
 
194
195
  @connection_options = options
195
196
  conn = Connection.new(options, &block)
197
+
198
+ # Cisco IOS requires a special implementation of `Net:SSH`. This uses the
199
+ # SSH transport to identify the platform, but then replaces SSHConnection
200
+ # with a CiscoIOSConnection in order to behave as expected for the user.
201
+ if defined?(conn.platform.cisco_ios?) && conn.platform.cisco_ios?
202
+ ios_options = {}
203
+ ios_options[:host] = @options[:host]
204
+ ios_options[:user] = @options[:user]
205
+ ios_options[:enable_password] = @options[:enable_password]
206
+ ios_options.merge!(@connection_options)
207
+ conn = CiscoIOSConnection.new(ios_options)
208
+ end
209
+
196
210
  @connection = conn unless conn.nil?
197
211
  end
198
212
 
@@ -80,7 +80,7 @@ class Train::Transports::WinRM
80
80
  retry_limit: @max_wait_until_ready / delay,
81
81
  retry_delay: delay,
82
82
  )
83
- run_command(PING_COMMAND.dup)
83
+ run_command_via_connection(PING_COMMAND.dup)
84
84
  end
85
85
 
86
86
  def uri
@@ -129,7 +129,11 @@ class Train::Transports::WinRM
129
129
  # @return [Winrm::FileManager] a file transporter
130
130
  # @api private
131
131
  def file_manager
132
- @file_manager ||= WinRM::FS::FileManager.new(session)
132
+ @file_manager ||= begin
133
+ # Ensure @service is available:
134
+ wait_until_ready
135
+ WinRM::FS::FileManager.new(@service)
136
+ end
133
137
  end
134
138
 
135
139
  # Builds a `LoginCommand` for use by Linux-based platforms.
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 = '1.3.0'.freeze
6
+ VERSION = '1.4.0'.freeze
7
7
  end
@@ -54,6 +54,16 @@ describe 'os_detect' do
54
54
  platform[:family].must_equal('redhat')
55
55
  platform[:release].must_equal('7.4')
56
56
  end
57
+ it 'sets the correct family, name, and release on CloudLinux' do
58
+ files = {
59
+ '/etc/redhat-release' => "CloudLinux release 7.4 (Georgy Grechko)\n",
60
+ '/etc/os-release' => "NAME=\"CloudLinux\"\nVERSION=\"7.4 (Georgy Grechko)\"\nID=\"cloudlinux\"\nID_LIKE=\"rhel fedora centos\"\nVERSION_ID=\"7.4\"\nPRETTY_NAME=\"CloudLinux 7.4 (Georgy Grechko)\"\nANSI_COLOR=\"0;31\"\nCPE_NAME=\"cpe:/o:cloudlinux:cloudlinux:7.4:GA:server\"\nHOME_URL=\"https://www.cloudlinux.com//\"\nBUG_REPORT_URL=\"https://www.cloudlinux.com/support\"\n",
61
+ }
62
+ platform = scan_with_files('linux', files)
63
+ platform[:name].must_equal('cloudlinux')
64
+ platform[:family].must_equal('redhat')
65
+ platform[:release].must_equal('7.4')
66
+ end
57
67
  end
58
68
  end
59
69
 
@@ -133,6 +133,15 @@ describe 'platform' do
133
133
  it { os.unix?.must_equal(true) }
134
134
  end
135
135
 
136
+ describe 'with platform set to cloudlinux' do
137
+ let(:os) { mock_platform('cloudlinux') }
138
+ it { os.redhat?.must_equal(true) }
139
+ it { os.debian?.must_equal(false) }
140
+ it { os.suse?.must_equal(false) }
141
+ it { os.linux?.must_equal(true) }
142
+ it { os.unix?.must_equal(true) }
143
+ end
144
+
136
145
  describe 'with platform set to fedora' do
137
146
  let(:os) { mock_platform('fedora') }
138
147
  it { os.fedora?.must_equal(true) }
@@ -0,0 +1,81 @@
1
+ # encoding: utf-8
2
+
3
+ require 'helper'
4
+ require 'train/transports/ssh'
5
+
6
+ describe 'CiscoIOSConnection' do
7
+ let(:cls) do
8
+ Train::Platforms::Detect::Specifications::OS.load
9
+ plat = Train::Platforms.name('mock').in_family('cisco_ios')
10
+ plat.add_platform_methods
11
+ plat.stubs(:cisco_ios?).returns(true)
12
+ Train::Platforms::Detect.stubs(:scan).returns(plat)
13
+ Train::Transports::SSH
14
+ end
15
+
16
+ let(:opts) do
17
+ {
18
+ host: 'fakehost',
19
+ user: 'fakeuser',
20
+ password: 'fakepassword',
21
+ }
22
+ end
23
+
24
+ let(:connection) do
25
+ cls.new(opts).connection
26
+ end
27
+
28
+ describe '#initialize' do
29
+ it 'provides a uri' do
30
+ connection.uri.must_equal 'ssh://fakeuser@fakehost:22'
31
+ end
32
+ end
33
+
34
+ describe '#format_result' do
35
+ it 'returns correctly when result is `good`' do
36
+ output = 'good'
37
+ Train::Extras::CommandResult.expects(:new).with(output, '', 0)
38
+ connection.send(:format_result, 'good')
39
+ end
40
+
41
+ it 'returns correctly when result matches /Bad IP address/' do
42
+ output = "Translating \"nope\"\r\n\r\nTranslating \"nope\"\r\n\r\n% Bad IP address or host name\r\n% Unknown command or computer name, or unable to find computer address\r\n"
43
+ Train::Extras::CommandResult.expects(:new).with('', output, 1)
44
+ connection.send(:format_result, output)
45
+ end
46
+
47
+ it 'returns correctly when result matches /Incomplete command/' do
48
+ output = "% Incomplete command.\r\n\r\n"
49
+ Train::Extras::CommandResult.expects(:new).with('', output, 1)
50
+ connection.send(:format_result, output)
51
+ end
52
+
53
+ it 'returns correctly when result matches /Invalid input detected/' do
54
+ output = " ^\r\n% Invalid input detected at '^' marker.\r\n\r\n"
55
+ Train::Extras::CommandResult.expects(:new).with('', output, 1)
56
+ connection.send(:format_result, output)
57
+ end
58
+
59
+ it 'returns correctly when result matches /Unrecognized host/' do
60
+ output = "Translating \"nope\"\r\n% Unrecognized host or address, or protocol not running.\r\n\r\n"
61
+ Train::Extras::CommandResult.expects(:new).with('', output, 1)
62
+ connection.send(:format_result, output)
63
+ end
64
+ end
65
+
66
+ describe '#format_output' do
67
+ it 'returns the correct output' do
68
+ cmd = 'show calendar'
69
+ output = "show calendar\r\n10:35:50 UTC Fri Mar 23 2018\r\n7200_ios_12#\r\n7200_ios_12#"
70
+ result = connection.send(:format_output, output, cmd)
71
+ result.must_equal '10:35:50 UTC Fri Mar 23 2018'
72
+ end
73
+
74
+ it 'returns the correct output when a pipe is used' do
75
+ cmd = 'show running-config | section line con 0'
76
+ output = "show running-config | section line con 0\r\nline con 0\r\n exec-timeout 0 0\r\n privilege level 15\r\n logging synchronous\r\n stopbits 1\r\n7200_ios_12#\r\n7200_ios_12#"
77
+ result = connection.send(:format_output, output, cmd)
78
+ result.must_equal "line con 0\r\n exec-timeout 0 0\r\n privilege level 15\r\n logging synchronous\r\n stopbits 1"
79
+ end
80
+ end
81
+ end
@@ -5,10 +5,10 @@ require 'train/transports/ssh'
5
5
 
6
6
  describe 'ssh transport' do
7
7
  let(:cls) do
8
- plat = Train::Platforms.name('mock').in_family('linux')
9
- plat.add_platform_methods
10
- Train::Platforms::Detect.stubs(:scan).returns(plat)
11
- Train::Transports::SSH
8
+ plat = Train::Platforms.name('mock').in_family('linux')
9
+ plat.add_platform_methods
10
+ Train::Platforms::Detect.stubs(:scan).returns(plat)
11
+ Train::Transports::SSH
12
12
  end
13
13
  let(:conf) {{
14
14
  host: rand.to_s,
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: train
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dominik Richter
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-03-29 00:00:00.000000000 Z
11
+ date: 2018-04-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json
@@ -225,7 +225,7 @@ files:
225
225
  - lib/train/plugins/transport.rb
226
226
  - lib/train/transports/aws.rb
227
227
  - lib/train/transports/azure.rb
228
- - lib/train/transports/cisco_ios.rb
228
+ - lib/train/transports/cisco_ios_connection.rb
229
229
  - lib/train/transports/docker.rb
230
230
  - lib/train/transports/local.rb
231
231
  - lib/train/transports/mock.rb
@@ -292,7 +292,7 @@ files:
292
292
  - test/unit/train_test.rb
293
293
  - test/unit/transports/aws_test.rb
294
294
  - test/unit/transports/azure_test.rb
295
- - test/unit/transports/cisco_ios.rb
295
+ - test/unit/transports/cisco_ios_connection.rb
296
296
  - test/unit/transports/local_test.rb
297
297
  - test/unit/transports/mock_test.rb
298
298
  - test/unit/transports/ssh_test.rb
@@ -383,7 +383,7 @@ test_files:
383
383
  - test/unit/train_test.rb
384
384
  - test/unit/transports/aws_test.rb
385
385
  - test/unit/transports/azure_test.rb
386
- - test/unit/transports/cisco_ios.rb
386
+ - test/unit/transports/cisco_ios_connection.rb
387
387
  - test/unit/transports/local_test.rb
388
388
  - test/unit/transports/mock_test.rb
389
389
  - test/unit/transports/ssh_test.rb
@@ -1,140 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'train/plugins'
4
- require 'train/transports/ssh'
5
-
6
- module Train::Transports
7
- class BadEnablePassword < Train::TransportError; end
8
-
9
- class CiscoIOS < SSH
10
- name 'cisco_ios'
11
-
12
- option :host, required: true
13
- option :user, required: true
14
- option :port, default: 22, required: true
15
-
16
- option :password, required: true
17
-
18
- # Used to elevate to enable mode (similar to `sudo su` in Linux)
19
- option :enable_password
20
-
21
- def connection
22
- @connection ||= Connection.new(validate_options(@options).options)
23
- end
24
-
25
- class Connection < BaseConnection
26
- def initialize(options)
27
- super(options)
28
-
29
- # Delete options to avoid passing them in to `Net::SSH.start` later
30
- @host = @options.delete(:host)
31
- @user = @options.delete(:user)
32
- @port = @options.delete(:port)
33
- @enable_password = @options.delete(:enable_password)
34
-
35
- @prompt = /^\S+[>#]\r\n.*$/
36
- end
37
-
38
- def uri
39
- "ssh://#{@user}@#{@host}:#{@port}"
40
- end
41
-
42
- private
43
-
44
- def establish_connection
45
- logger.debug("[SSH] opening connection to #{self}")
46
-
47
- Net::SSH.start(
48
- @host,
49
- @user,
50
- @options.reject { |_key, value| value.nil? },
51
- )
52
- end
53
-
54
- def session
55
- return @session unless @session.nil?
56
-
57
- @session = open_channel(establish_connection)
58
-
59
- # Escalate privilege to enable mode if password is given
60
- if @enable_password
61
- run_command_via_connection("enable\r\n#{@enable_password}")
62
- end
63
-
64
- # Prevent `--MORE--` by removing terminal length limit
65
- run_command_via_connection('terminal length 0')
66
-
67
- @session
68
- end
69
-
70
- def run_command_via_connection(cmd)
71
- # Ensure buffer is empty before sending data
72
- @buf = ''
73
-
74
- logger.debug("[SSH] Running `#{cmd}` on #{self}")
75
- session.send_data(cmd + "\r\n")
76
-
77
- logger.debug('[SSH] waiting for prompt')
78
- until @buf =~ @prompt
79
- raise BadEnablePassword if @buf =~ /Bad secrets/
80
- session.connection.process(0)
81
- end
82
-
83
- # Save the buffer and clear it for the next command
84
- output = @buf.dup
85
- @buf = ''
86
-
87
- format_result(format_output(output, cmd))
88
- end
89
-
90
- ERROR_MATCHERS = [
91
- 'Bad IP address',
92
- 'Incomplete command',
93
- 'Invalid input detected',
94
- 'Unrecognized host',
95
- ].freeze
96
-
97
- # IOS commands do not have an exit code so we must compare the command
98
- # output with partial segments of known errors. Then, we return a
99
- # `CommandResult` with arguments in the correct position based on the
100
- # result.
101
- def format_result(result)
102
- if ERROR_MATCHERS.none? { |e| result.include?(e) }
103
- CommandResult.new(result, '', 0)
104
- else
105
- CommandResult.new('', result, 1)
106
- end
107
- end
108
-
109
- # The buffer (@buf) contains all data sent/received on the SSH channel so
110
- # we need to format the data to match what we would expect from Train
111
- def format_output(output, cmd)
112
- leading_prompt = /(\r\n|^)\S+[>#]/
113
- command_string = /#{cmd}\r\n/
114
- trailing_prompt = /\S+[>#](\r\n|$)/
115
- trailing_line_endings = /(\r\n)+$/
116
-
117
- output
118
- .sub(leading_prompt, '')
119
- .sub(command_string, '')
120
- .gsub(trailing_prompt, '')
121
- .gsub(trailing_line_endings, '')
122
- end
123
-
124
- # Create an SSH channel that writes to @buf when data is received
125
- def open_channel(ssh)
126
- logger.debug("[SSH] opening SSH channel to #{self}")
127
- ssh.open_channel do |ch|
128
- ch.on_data do |_, data|
129
- @buf += data
130
- end
131
-
132
- ch.send_channel_request('shell') do |_, success|
133
- raise 'Failed to open SSH shell' unless success
134
- logger.debug('[SSH] shell opened')
135
- end
136
- end
137
- end
138
- end
139
- end
140
- end
@@ -1,94 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'helper'
4
- require 'train/transports/cisco_ios'
5
-
6
- describe 'Train::Transports::CiscoIOS' do
7
- let(:cls) do
8
- plat = Train::Platforms.name('mock').in_family('cisco_ios')
9
- plat.add_platform_methods
10
- Train::Platforms::Detect.stubs(:scan).returns(plat)
11
- Train::Transports::CiscoIOS
12
- end
13
-
14
- let(:opts) do
15
- {
16
- host: 'fakehost',
17
- user: 'fakeuser',
18
- password: 'fakepassword',
19
- }
20
- end
21
-
22
- let(:cisco_ios) do
23
- cls.new(opts)
24
- end
25
-
26
- describe 'CiscoIOS::Connection' do
27
- let(:connection) { cls.new(opts).connection }
28
-
29
- describe '#initialize' do
30
- it 'raises an error when user is missing' do
31
- opts.delete(:user)
32
- err = proc { cls.new(opts).connection }.must_raise(Train::ClientError)
33
- err.message.must_match(/must provide.*user/)
34
- end
35
-
36
- it 'raises an error when host is missing' do
37
- opts.delete(:host)
38
- err = proc { cls.new(opts).connection }.must_raise(Train::ClientError)
39
- err.message.must_match(/must provide.*host/)
40
- end
41
-
42
- it 'raises an error when password is missing' do
43
- opts.delete(:password)
44
- err = proc { cls.new(opts).connection }.must_raise(Train::ClientError)
45
- err.message.must_match(/must provide.*password/)
46
- end
47
-
48
- it 'provides a uri' do
49
- connection.uri.must_equal 'ssh://fakeuser@fakehost:22'
50
- end
51
- end
52
-
53
- describe '#format_result' do
54
- it 'returns correctly when result is `good`' do
55
- output = 'good'
56
- Train::Extras::CommandResult.expects(:new).with(output, '', 0)
57
- connection.send(:format_result, 'good')
58
- end
59
-
60
- it 'returns correctly when result matches /Bad IP address/' do
61
- output = "Translating \"nope\"\r\n\r\nTranslating \"nope\"\r\n\r\n% Bad IP address or host name\r\n% Unknown command or computer name, or unable to find computer address\r\n"
62
- Train::Extras::CommandResult.expects(:new).with('', output, 1)
63
- connection.send(:format_result, output)
64
- end
65
-
66
- it 'returns correctly when result matches /Incomplete command/' do
67
- output = "% Incomplete command.\r\n\r\n"
68
- Train::Extras::CommandResult.expects(:new).with('', output, 1)
69
- connection.send(:format_result, output)
70
- end
71
-
72
- it 'returns correctly when result matches /Invalid input detected/' do
73
- output = " ^\r\n% Invalid input detected at '^' marker.\r\n\r\n"
74
- Train::Extras::CommandResult.expects(:new).with('', output, 1)
75
- connection.send(:format_result, output)
76
- end
77
-
78
- it 'returns correctly when result matches /Unrecognized host/' do
79
- output = "Translating \"nope\"\r\n% Unrecognized host or address, or protocol not running.\r\n\r\n"
80
- Train::Extras::CommandResult.expects(:new).with('', output, 1)
81
- connection.send(:format_result, output)
82
- end
83
- end
84
-
85
- describe '#format_output' do
86
- it 'returns output containing only the output of the command executed' do
87
- cmd = 'show calendar'
88
- output = "show calendar\r\n10:35:50 UTC Fri Mar 23 2018\r\n7200_ios_12#\r\n7200_ios_12#"
89
- result = connection.send(:format_output, output, cmd)
90
- result.must_equal '10:35:50 UTC Fri Mar 23 2018'
91
- end
92
- end
93
- end
94
- end