train 0.18.0 → 0.19.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 +4 -4
- data/CHANGELOG.md +14 -2
- data/Gemfile +1 -1
- data/README.md +6 -0
- data/lib/train/extras/command_wrapper.rb +9 -3
- data/lib/train/extras/stat.rb +1 -2
- data/lib/train/transports/winrm.rb +3 -3
- data/lib/train/transports/winrm_connection.rb +8 -11
- data/lib/train/version.rb +1 -1
- data/test/unit/extras/command_wrapper_test.rb +0 -16
- data/test/unit/extras/stat_test.rb +51 -30
- data/train.gemspec +2 -2
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c99003b292f41d03c790974f1aabd9b0ad7792cf
|
4
|
+
data.tar.gz: 7b2ffa667c8eba8fe0440a8a63483f88f19a4aa5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: df622e11873f9e6583ced3fed9c953a513aa3dd0acdf4bc2c2ec5f60f81f64220691e08a45e729937257e62ab19f38aed9e548614a004cbe471655393e671b06
|
7
|
+
data.tar.gz: 709616bea4c244942aa2d0d8929a27a140090b93b55b37e4edcd9cb68033b925d981810328ed69b904cfb323b89ebfecacd75a8bcdf2baf14e205357f05e45a7
|
data/CHANGELOG.md
CHANGED
@@ -1,7 +1,19 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
-
## [0.
|
4
|
-
[Full Changelog](https://github.com/chef/train/compare/v0.
|
3
|
+
## [0.19.0](https://github.com/chef/train/tree/0.19.0) (2016-09-05)
|
4
|
+
[Full Changelog](https://github.com/chef/train/compare/v0.18.0...0.19.0)
|
5
|
+
|
6
|
+
**Fixed bugs:**
|
7
|
+
|
8
|
+
- use stat -c for alpine linux [\#146](https://github.com/chef/train/pull/146) ([chris-rock](https://github.com/chris-rock))
|
9
|
+
|
10
|
+
**Merged pull requests:**
|
11
|
+
|
12
|
+
- support ruby 2.2.1 [\#145](https://github.com/chef/train/pull/145) ([chris-rock](https://github.com/chris-rock))
|
13
|
+
- Use winrm v2 implementation [\#122](https://github.com/chef/train/pull/122) ([mwrock](https://github.com/mwrock))
|
14
|
+
|
15
|
+
## [v0.18.0](https://github.com/chef/train/tree/v0.18.0) (2016-08-26)
|
16
|
+
[Full Changelog](https://github.com/chef/train/compare/v0.17.0...v0.18.0)
|
5
17
|
|
6
18
|
**Merged pull requests:**
|
7
19
|
|
data/Gemfile
CHANGED
@@ -8,7 +8,7 @@ if Gem::Version.new(RUBY_VERSION) <= Gem::Version.new('1.9.3')
|
|
8
8
|
gem 'net-ssh', '~> 2.9'
|
9
9
|
end
|
10
10
|
|
11
|
-
if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.2')
|
11
|
+
if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.2.2')
|
12
12
|
gem 'json', '< 2.0'
|
13
13
|
gem 'rack', '< 2.0'
|
14
14
|
end
|
data/README.md
CHANGED
@@ -101,6 +101,12 @@ We perform `unit`, `integration` and `windows` tests.
|
|
101
101
|
* `integration` tests run against VMs and docker containers
|
102
102
|
* `windows` tests that run on appveyor for windows integration tests
|
103
103
|
|
104
|
+
## Mac/Linux
|
105
|
+
|
106
|
+
```
|
107
|
+
bundle exec ruby -W -Ilib:test/unit test/unit/extras/stat_test.rb
|
108
|
+
```
|
109
|
+
|
104
110
|
## Windows
|
105
111
|
|
106
112
|
```
|
@@ -3,7 +3,6 @@
|
|
3
3
|
# author: Christoph Hartmann
|
4
4
|
|
5
5
|
require 'base64'
|
6
|
-
require 'winrm'
|
7
6
|
require 'train/errors'
|
8
7
|
|
9
8
|
module Train::Extras
|
@@ -114,15 +113,22 @@ module Train::Extras
|
|
114
113
|
# especially in local mode, we cannot be sure that we get a Powershell
|
115
114
|
# we may just get a `cmd`.
|
116
115
|
# TODO: we may want to opt for powershell.exe -command instead of `encodeCommand`
|
117
|
-
"powershell -encodedCommand #{
|
116
|
+
"powershell -encodedCommand #{encoded(safe_script(script))}"
|
118
117
|
end
|
119
118
|
|
120
|
-
# reused from https://github.com/WinRb/WinRM/blob/master/lib/winrm/command_executor.rb
|
121
119
|
# suppress the progress stream from leaking to stderr
|
122
120
|
def safe_script(script)
|
123
121
|
"$ProgressPreference='SilentlyContinue';" + script
|
124
122
|
end
|
125
123
|
|
124
|
+
# Encodes the script so that it can be passed to the PowerShell
|
125
|
+
# --EncodedCommand argument.
|
126
|
+
# @return [String] The UTF-16LE base64 encoded script
|
127
|
+
def encoded(script)
|
128
|
+
encoded_script = safe_script(script).encode('UTF-16LE', 'UTF-8')
|
129
|
+
Base64.strict_encode64(encoded_script)
|
130
|
+
end
|
131
|
+
|
126
132
|
def to_s
|
127
133
|
'PowerShell CommandWrapper'
|
128
134
|
end
|
data/lib/train/extras/stat.rb
CHANGED
@@ -34,9 +34,8 @@ module Train::Extras
|
|
34
34
|
|
35
35
|
def self.linux_stat(shell_escaped_path, backend, follow_symlink)
|
36
36
|
lstat = follow_symlink ? ' -L' : ''
|
37
|
-
format = backend.os.esx? ? '-c' : '--printf'
|
37
|
+
format = (backend.os.esx? || backend.os[:name] == 'alpine') ? '-c' : '--printf'
|
38
38
|
res = backend.run_command("stat#{lstat} #{shell_escaped_path} 2>/dev/null #{format} '%s\n%f\n%U\n%u\n%G\n%g\n%X\n%Y\n%C'")
|
39
|
-
|
40
39
|
# ignore the exit_code: it is != 0 if selinux labels are not supported
|
41
40
|
# on the system.
|
42
41
|
|
@@ -89,7 +89,7 @@ module Train::Transports
|
|
89
89
|
opts[:endpoint] = "#{scheme}://#{opts[:host]}:#{port}/#{path}"
|
90
90
|
end
|
91
91
|
|
92
|
-
WINRM_FS_SPEC_VERSION = '~> 0
|
92
|
+
WINRM_FS_SPEC_VERSION = '~> 1.0'.freeze
|
93
93
|
|
94
94
|
# Builds the hash of options needed by the Connection object on
|
95
95
|
# construction.
|
@@ -100,12 +100,12 @@ module Train::Transports
|
|
100
100
|
def connection_options(opts)
|
101
101
|
{
|
102
102
|
logger: logger,
|
103
|
-
|
103
|
+
transport: :negotiate,
|
104
104
|
disable_sspi: false,
|
105
105
|
basic_auth_only: false,
|
106
106
|
endpoint: opts[:endpoint],
|
107
107
|
user: opts[:user],
|
108
|
-
|
108
|
+
password: opts[:password],
|
109
109
|
rdp_port: opts[:rdp_port],
|
110
110
|
connection_retries: opts[:connection_retries],
|
111
111
|
connection_retry_sleep: opts[:connection_retry_sleep],
|
@@ -30,9 +30,7 @@ class Train::Transports::WinRM
|
|
30
30
|
class Connection < BaseConnection
|
31
31
|
def initialize(options)
|
32
32
|
super(options)
|
33
|
-
@endpoint = @options.delete(:endpoint)
|
34
33
|
@rdp_port = @options.delete(:rdp_port)
|
35
|
-
@winrm_transport = @options.delete(:winrm_transport)
|
36
34
|
@connection_retries = @options.delete(:connection_retries)
|
37
35
|
@connection_retry_sleep = @options.delete(:connection_retry_sleep)
|
38
36
|
@max_wait_until_ready = @options.delete(:max_wait_until_ready)
|
@@ -59,11 +57,11 @@ class Train::Transports::WinRM
|
|
59
57
|
logger.debug("[WinRM] #{self} (#{command})")
|
60
58
|
out = ''
|
61
59
|
|
62
|
-
response = session.
|
60
|
+
response = session.run(command) do |stdout, _|
|
63
61
|
out << stdout if stdout
|
64
62
|
end
|
65
63
|
|
66
|
-
CommandResult.new(out, response.stderr, response
|
64
|
+
CommandResult.new(out, response.stderr, response.exitcode)
|
67
65
|
end
|
68
66
|
|
69
67
|
# (see Base::Connection#login_command)
|
@@ -98,7 +96,7 @@ class Train::Transports::WinRM
|
|
98
96
|
end
|
99
97
|
|
100
98
|
def uri
|
101
|
-
"winrm://#{options[:user]}@#{
|
99
|
+
"winrm://#{options[:user]}@#{options[:endpoint]}:#{@rdp_port}"
|
102
100
|
end
|
103
101
|
|
104
102
|
private
|
@@ -112,7 +110,7 @@ class Train::Transports::WinRM
|
|
112
110
|
# Mac system
|
113
111
|
# @api private
|
114
112
|
def rdp_doc(opts = {})
|
115
|
-
host = URI.parse(
|
113
|
+
host = URI.parse(options[:endpoint]).host
|
116
114
|
content = [
|
117
115
|
"full address:s:#{host}:#{@rdp_port}",
|
118
116
|
'prompt for credentials:i:1',
|
@@ -139,7 +137,7 @@ class Train::Transports::WinRM
|
|
139
137
|
def login_command_for_linux
|
140
138
|
args = %W( -u #{options[:user]} )
|
141
139
|
args += %W( -p #{options[:pass]} ) if options.key?(:pass)
|
142
|
-
args += %W( #{URI.parse(
|
140
|
+
args += %W( #{URI.parse(options[:endpoint]).host}:#{@rdp_port} )
|
143
141
|
LoginCommand.new('rdesktop', args)
|
144
142
|
end
|
145
143
|
|
@@ -172,10 +170,9 @@ class Train::Transports::WinRM
|
|
172
170
|
retry_delay: @connection_retry_sleep.to_i,
|
173
171
|
}.merge(retry_options)
|
174
172
|
|
175
|
-
|
176
|
-
@service = ::WinRM::WinRMWebService.new(*service_args)
|
173
|
+
@service = ::WinRM::Connection.new(options.merge(opts))
|
177
174
|
@service.logger = logger
|
178
|
-
@service.
|
175
|
+
@service.shell(:powershell)
|
179
176
|
end
|
180
177
|
end
|
181
178
|
|
@@ -184,7 +181,7 @@ class Train::Transports::WinRM
|
|
184
181
|
#
|
185
182
|
# @api private
|
186
183
|
def to_s
|
187
|
-
"
|
184
|
+
"<#{options.inspect}>"
|
188
185
|
end
|
189
186
|
|
190
187
|
class OS < OSCommon
|
data/lib/train/version.rb
CHANGED
@@ -60,19 +60,3 @@ describe 'linux command' do
|
|
60
60
|
lc.run(cmd).must_equal "echo #{bpw} | base64 --decode | #{sudo_command} -S #{cmd}"
|
61
61
|
end
|
62
62
|
end
|
63
|
-
|
64
|
-
describe 'powershell command' do
|
65
|
-
let(:cls) { Train::Extras::PowerShellCommand }
|
66
|
-
let(:cmd) { rand.to_s }
|
67
|
-
let(:backend) {
|
68
|
-
backend = Train::Transports::Mock.new.connection
|
69
|
-
backend.mock_os({ family: 'windows' })
|
70
|
-
backend
|
71
|
-
}
|
72
|
-
|
73
|
-
it 'wraps commands in powershell' do
|
74
|
-
lc = cls.new(backend, {})
|
75
|
-
tmp =
|
76
|
-
lc.run(cmd).must_equal "powershell -encodedCommand #{WinRM::PowershellScript.new('$ProgressPreference=\'SilentlyContinue\';' + cmd).encoded}"
|
77
|
-
end
|
78
|
-
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
require 'helper'
|
3
3
|
require 'train/extras'
|
4
|
+
require 'train/transports/mock'
|
4
5
|
|
5
6
|
describe 'stat' do
|
6
7
|
let(:cls) { Train::Extras::Stat }
|
@@ -42,27 +43,22 @@ describe 'stat' do
|
|
42
43
|
end
|
43
44
|
|
44
45
|
describe 'linux stat' do
|
45
|
-
let(:backend) {
|
46
|
+
let(:backend) {
|
47
|
+
mock = Train::Transports::Mock.new(verbose: true).connection
|
48
|
+
mock.mock_os({ name: 'ubuntu', family: 'debian', release: '15.04', arch: 'x86_64' })
|
49
|
+
mock.commands = {
|
50
|
+
"stat /path 2>/dev/null --printf '%s\n%f\n%U\n%u\n%G\n%g\n%X\n%Y\n%C'" => mock.mock_command('', '', '', 0),
|
51
|
+
"stat /path-stat 2>/dev/null --printf '%s\n%f\n%U\n%u\n%G\n%g\n%X\n%Y\n%C'" => mock.mock_command('', "360\n43ff\nroot\n0\nrootz\n1\n1444520846\n1444522445\n?", '', 0),
|
52
|
+
}
|
53
|
+
mock
|
54
|
+
}
|
46
55
|
|
47
56
|
it 'ignores wrong stat results' do
|
48
|
-
res = Minitest::Mock.new
|
49
|
-
os = Minitest::Mock.new
|
50
|
-
res.expect :stdout, ''
|
51
|
-
os.expect :esx?, false
|
52
|
-
backend.expect :os, os
|
53
|
-
backend.expect :run_command, res, [String]
|
54
57
|
cls.linux_stat('/path', backend, false).must_equal({})
|
55
58
|
end
|
56
59
|
|
57
60
|
it 'reads correct stat results' do
|
58
|
-
|
59
|
-
os = Minitest::Mock.new
|
60
|
-
# 43ff is 41777; linux_stat strips the 4
|
61
|
-
res.expect :stdout, "360\n43ff\nroot\n0\nrootz\n1\n1444520846\n1444522445\n?"
|
62
|
-
os.expect :esx?, false
|
63
|
-
backend.expect :os, os
|
64
|
-
backend.expect :run_command, res, [String]
|
65
|
-
cls.linux_stat('/path', backend, false).must_equal({
|
61
|
+
cls.linux_stat('/path-stat', backend, false).must_equal({
|
66
62
|
type: :directory,
|
67
63
|
mode: 01777,
|
68
64
|
owner: 'root',
|
@@ -77,27 +73,52 @@ describe 'stat' do
|
|
77
73
|
end
|
78
74
|
|
79
75
|
describe 'esx stat' do
|
80
|
-
let(:backend) {
|
76
|
+
let(:backend) {
|
77
|
+
mock = Train::Transports::Mock.new(verbose: true).connection
|
78
|
+
mock.mock_os({ name: 'vmkernel', family: 'esx', release: '5' })
|
79
|
+
mock.commands = {
|
80
|
+
"stat /path 2>/dev/null -c '%s\n%f\n%U\n%u\n%G\n%g\n%X\n%Y\n%C'" => mock.mock_command('', '', '', 0),
|
81
|
+
"stat /path-stat 2>/dev/null -c '%s\n%f\n%U\n%u\n%G\n%g\n%X\n%Y\n%C'" => mock.mock_command('', "360\n43ff\nroot\n0\nrootz\n1\n1444520846\n1444522445\n?", '', 0),
|
82
|
+
}
|
83
|
+
mock
|
84
|
+
}
|
81
85
|
|
82
86
|
it 'ignores wrong stat results' do
|
83
|
-
res = Minitest::Mock.new
|
84
|
-
os = Minitest::Mock.new
|
85
|
-
res.expect :stdout, ''
|
86
|
-
os.expect :esx?, true
|
87
|
-
backend.expect :os, os
|
88
|
-
backend.expect :run_command, res, [String]
|
89
87
|
cls.linux_stat('/path', backend, false).must_equal({})
|
90
88
|
end
|
91
89
|
|
92
90
|
it 'reads correct stat results' do
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
91
|
+
cls.linux_stat('/path-stat', backend, false).must_equal({
|
92
|
+
type: :directory,
|
93
|
+
mode: 01777,
|
94
|
+
owner: 'root',
|
95
|
+
uid: 0,
|
96
|
+
group: 'rootz',
|
97
|
+
gid: 1,
|
98
|
+
mtime: 1444522445,
|
99
|
+
size: 360,
|
100
|
+
selinux_label: nil,
|
101
|
+
})
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe 'alpine stat' do
|
106
|
+
let(:backend) {
|
107
|
+
mock = Train::Transports::Mock.new(verbose: true).connection
|
108
|
+
mock.mock_os({ name: 'alpine', family: 'alpine', release: nil })
|
109
|
+
mock.commands = {
|
110
|
+
"stat /path 2>/dev/null -c '%s\n%f\n%U\n%u\n%G\n%g\n%X\n%Y\n%C'" => mock.mock_command('', '', '', 0),
|
111
|
+
"stat /path-stat 2>/dev/null -c '%s\n%f\n%U\n%u\n%G\n%g\n%X\n%Y\n%C'" => mock.mock_command('', "360\n43ff\nroot\n0\nrootz\n1\n1444520846\n1444522445\n?", '', 0),
|
112
|
+
}
|
113
|
+
mock
|
114
|
+
}
|
115
|
+
|
116
|
+
it 'ignores wrong stat results' do
|
117
|
+
cls.linux_stat('/path', backend, false).must_equal({})
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'reads correct stat results' do
|
121
|
+
cls.linux_stat('/path-stat', backend, false).must_equal({
|
101
122
|
type: :directory,
|
102
123
|
mode: 01777,
|
103
124
|
owner: 'root',
|
data/train.gemspec
CHANGED
@@ -30,8 +30,8 @@ Gem::Specification.new do |spec|
|
|
30
30
|
# 1.9 support is no longer needed here or for Inspec
|
31
31
|
spec.add_dependency 'net-ssh', '>= 2.9', '< 4.0'
|
32
32
|
spec.add_dependency 'net-scp', '~> 1.2'
|
33
|
-
spec.add_dependency 'winrm', '~>
|
34
|
-
spec.add_dependency 'winrm-fs', '~> 0
|
33
|
+
spec.add_dependency 'winrm', '~> 2.0'
|
34
|
+
spec.add_dependency 'winrm-fs', '~> 1.0'
|
35
35
|
spec.add_dependency 'docker-api', '~> 1.26'
|
36
36
|
|
37
37
|
spec.add_development_dependency 'mocha', '~> 1.1'
|
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: 0.
|
4
|
+
version: 0.19.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: 2016-
|
11
|
+
date: 2016-09-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: json
|
@@ -84,28 +84,28 @@ dependencies:
|
|
84
84
|
requirements:
|
85
85
|
- - "~>"
|
86
86
|
- !ruby/object:Gem::Version
|
87
|
-
version: '
|
87
|
+
version: '2.0'
|
88
88
|
type: :runtime
|
89
89
|
prerelease: false
|
90
90
|
version_requirements: !ruby/object:Gem::Requirement
|
91
91
|
requirements:
|
92
92
|
- - "~>"
|
93
93
|
- !ruby/object:Gem::Version
|
94
|
-
version: '
|
94
|
+
version: '2.0'
|
95
95
|
- !ruby/object:Gem::Dependency
|
96
96
|
name: winrm-fs
|
97
97
|
requirement: !ruby/object:Gem::Requirement
|
98
98
|
requirements:
|
99
99
|
- - "~>"
|
100
100
|
- !ruby/object:Gem::Version
|
101
|
-
version: '0
|
101
|
+
version: '1.0'
|
102
102
|
type: :runtime
|
103
103
|
prerelease: false
|
104
104
|
version_requirements: !ruby/object:Gem::Requirement
|
105
105
|
requirements:
|
106
106
|
- - "~>"
|
107
107
|
- !ruby/object:Gem::Version
|
108
|
-
version: '0
|
108
|
+
version: '1.0'
|
109
109
|
- !ruby/object:Gem::Dependency
|
110
110
|
name: docker-api
|
111
111
|
requirement: !ruby/object:Gem::Requirement
|