winrm-transport 1.0.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 +7 -0
- data/.cane +2 -0
- data/.gitignore +15 -0
- data/.travis.yml +26 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +13 -0
- data/Guardfile +27 -0
- data/LICENSE.txt +15 -0
- data/README.md +80 -0
- data/Rakefile +49 -0
- data/bin/console +7 -0
- data/bin/setup +7 -0
- data/lib/winrm/transport.rb +28 -0
- data/lib/winrm/transport/command_executor.rb +217 -0
- data/lib/winrm/transport/file_transporter.rb +468 -0
- data/lib/winrm/transport/logging.rb +47 -0
- data/lib/winrm/transport/shell_closer.rb +71 -0
- data/lib/winrm/transport/tmp_zip.rb +184 -0
- data/lib/winrm/transport/version.rb +25 -0
- data/support/check_files.ps1 +46 -0
- data/support/decode_files.ps1 +60 -0
- data/winrm-transport.gemspec +52 -0
- metadata +272 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 8fceb01bb304b3dbde260f959336ea7dc319dd81
|
4
|
+
data.tar.gz: 35dfc04b0d86e4ec094e6646b2e0ffc34224e623
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5ea5f23b2e9bc90cd2fe5c8db87b18fed3b5061e9b4858160cef498583b07c0ca7fc47da1a22f33e244b17a17bef653233070456fc953afa1f27bcfac1b2a0d0
|
7
|
+
data.tar.gz: d2ac24211bd20bc50cfaae3c5c02c430293bf5701975072fb50cb429948db816551aa9a486ee136b69193c475f17665e9455ee30eaf566c22e078a012ff4be4b
|
data/.cane
ADDED
data/.gitignore
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
language: ruby
|
2
|
+
|
3
|
+
rvm:
|
4
|
+
- 2.2
|
5
|
+
- 2.1
|
6
|
+
- 2.0.0
|
7
|
+
- 1.9.3
|
8
|
+
- ruby-head
|
9
|
+
|
10
|
+
before_install:
|
11
|
+
- echo "Updating Bundler to ~> 1.9 until TravisCI has upgraded."
|
12
|
+
- gem install bundler -v "~> 1.9"
|
13
|
+
- bundle --version
|
14
|
+
|
15
|
+
bundler_args: --without guard
|
16
|
+
|
17
|
+
sudo: false
|
18
|
+
|
19
|
+
matrix:
|
20
|
+
allow_failures:
|
21
|
+
- rvm: ruby-head
|
22
|
+
|
23
|
+
addons:
|
24
|
+
code_climate:
|
25
|
+
repo_token:
|
26
|
+
secure: "WSrIaJVtAh88T7cd3DQY38yxiDz44Oms4Z5Dm+mVUv8gpKWixMR3t5ShmDW8+XXWWj3s3WUa2t5yZugrfz0gkrKCxSII6VURakBKy2jEKnEnJWoh8LKYjXHYW2fOU/PpclSFl0Ynxvt8Nn/F9dpbaGAqj2DwycAV4EtByuy06X0="
|
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
ignore %r{^\.gem/}
|
3
|
+
|
4
|
+
def rubocop_opts
|
5
|
+
{ :all_on_start => false, :keep_failed => false, :cli => "-r finstyle" }
|
6
|
+
end
|
7
|
+
|
8
|
+
def yard_opts
|
9
|
+
{ :port => "8808" }
|
10
|
+
end
|
11
|
+
|
12
|
+
group :red_green_refactor, :halt_on_fail => true do
|
13
|
+
guard :minitest do
|
14
|
+
watch(%r{^spec/(.*)_spec\.rb})
|
15
|
+
watch(%r{^lib/(.*)([^/]+)\.rb}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
|
16
|
+
watch(%r{^spec/spec_helper\.rb}) { "spec" }
|
17
|
+
end
|
18
|
+
|
19
|
+
guard :rubocop, rubocop_opts do
|
20
|
+
watch(%r{.+\.rb$})
|
21
|
+
watch(%r{(?:.+/)?\.rubocop\.yml$}) { |m| File.dirname(m[0]) }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
guard :yard, yard_opts do
|
26
|
+
watch(%r{lib/.+\.rb})
|
27
|
+
end
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
2
|
+
|
3
|
+
Copyright 2015 Fletcher Nichol
|
4
|
+
|
5
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
you may not use this file except in compliance with the License.
|
7
|
+
You may obtain a copy of the License at
|
8
|
+
|
9
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
|
11
|
+
Unless required by applicable law or agreed to in writing, software
|
12
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
See the License for the specific language governing permissions and
|
15
|
+
limitations under the License.
|
data/README.md
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
# WinRM::Transport
|
2
|
+
|
3
|
+
[](http://badge.fury.io/rb/winrm-transport)
|
4
|
+
[](https://travis-ci.org/test-kitchen/winrm-transport)
|
5
|
+
[](https://codeclimate.com/github/test-kitchen/winrm-transport)
|
6
|
+
[](https://codeclimate.com/github/test-kitchen/winrm-transport)
|
7
|
+
[](http://inch-ci.org/github/test-kitchen/winrm-transport)
|
8
|
+
[](https://gemnasium.com/test-kitchen/winrm-transport)
|
9
|
+
|
10
|
+
WinRM transport logic for re-using remote shells and uploading files. The original code was extracted from the [Test Kitchen][test_kitchen] project and remains the primary reference use case.
|
11
|
+
|
12
|
+
## Installation
|
13
|
+
|
14
|
+
Add this line to your application's Gemfile:
|
15
|
+
|
16
|
+
```ruby
|
17
|
+
gem 'winrm-transport'
|
18
|
+
```
|
19
|
+
|
20
|
+
And then execute:
|
21
|
+
|
22
|
+
$ bundle
|
23
|
+
|
24
|
+
Or install it yourself as:
|
25
|
+
|
26
|
+
$ gem install winrm-transport
|
27
|
+
|
28
|
+
## Usage
|
29
|
+
|
30
|
+
This a library gem and doesn't have any CLI commands. There are 2 primary object classes:
|
31
|
+
|
32
|
+
* [WinRM::Transport::CommandExecutor][command_executor]: an object which can
|
33
|
+
execute multiple commands and PowerShell script in one shared remote shell
|
34
|
+
session.
|
35
|
+
* [WinRM::Transport::FileTransporter][file_transporter]: an object which can
|
36
|
+
upload one or more files or directories to a remote host over WinRM only
|
37
|
+
using PowerShell scripts and CMD commands.
|
38
|
+
|
39
|
+
## Versioning
|
40
|
+
|
41
|
+
WinRM::Transport aims to adhere to [Semantic Versioning 2.0.0][semver].
|
42
|
+
|
43
|
+
## Development
|
44
|
+
|
45
|
+
* Source hosted at [GitHub][repo]
|
46
|
+
* Report issues/questions/feature requests on [GitHub Issues][issues]
|
47
|
+
|
48
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run
|
49
|
+
`bin/console` for an interactive prompt that will allow you to experiment.
|
50
|
+
|
51
|
+
## Contributing
|
52
|
+
|
53
|
+
Pull requests are very welcome! Make sure your patches are well tested.
|
54
|
+
Ideally create a topic branch for every separate change you make. For
|
55
|
+
example:
|
56
|
+
|
57
|
+
1. Fork it ( https://github.com/test-kitchen/winrm-transport/fork )
|
58
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
59
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
60
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
61
|
+
5. Create a new Pull Request
|
62
|
+
|
63
|
+
## Authors
|
64
|
+
|
65
|
+
Created and maintained by [Fletcher Nichol][fnichol] (<fnichol@nichol.ca>) and
|
66
|
+
a growing community of [contributors][contributors].
|
67
|
+
|
68
|
+
## License
|
69
|
+
|
70
|
+
Apache License, Version 2.0 (see [LICENSE.txt][license])
|
71
|
+
|
72
|
+
[command_executor]: https://github.com/test-kitchen/winrm-transport/blob/master/lib/winrm/transport/command_executor.rb
|
73
|
+
[contributors]: https://github.com/test-kitchen/winrm-transport/graphs/contributors
|
74
|
+
[file_transporter]: https://github.com/test-kitchen/winrm-transport/blob/master/lib/winrm/transport/file_transporter.rb
|
75
|
+
[fnichol]: https://github.com/fnichol
|
76
|
+
[issues]: https://github.com/test-kitchen/winrm-transpor/issues
|
77
|
+
[license]: https://github.com/test-kitchen/winrm-transport/blob/master/LICENSE.txt
|
78
|
+
[repo]: https://github.com/test-kitchen/winrm-transport
|
79
|
+
[semver]: http://semver.org/
|
80
|
+
[test_kitchen]: http://kitchen.ci
|
data/Rakefile
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require "bundler/gem_tasks"
|
4
|
+
|
5
|
+
require "rake/testtask"
|
6
|
+
Rake::TestTask.new(:unit) do |t|
|
7
|
+
t.libs.push "lib"
|
8
|
+
t.test_files = FileList["spec/**/*_spec.rb"]
|
9
|
+
t.verbose = true
|
10
|
+
end
|
11
|
+
|
12
|
+
desc "Run all test suites"
|
13
|
+
task :test => [:unit]
|
14
|
+
|
15
|
+
desc "Display LOC stats"
|
16
|
+
task :stats do
|
17
|
+
puts "\n## Production Code Stats"
|
18
|
+
sh "countloc -r lib"
|
19
|
+
puts "\n## Test Code Stats"
|
20
|
+
sh "countloc -r spec"
|
21
|
+
end
|
22
|
+
|
23
|
+
require "finstyle"
|
24
|
+
require "rubocop/rake_task"
|
25
|
+
RuboCop::RakeTask.new(:style) do |task|
|
26
|
+
task.options << "--display-cop-names"
|
27
|
+
end
|
28
|
+
|
29
|
+
require "cane/rake_task"
|
30
|
+
desc "Run cane to check quality metrics"
|
31
|
+
Cane::RakeTask.new do |cane|
|
32
|
+
cane.canefile = "./.cane"
|
33
|
+
end
|
34
|
+
|
35
|
+
desc "Run all quality tasks"
|
36
|
+
task :quality => [:cane, :style, :stats]
|
37
|
+
|
38
|
+
require "yard"
|
39
|
+
YARD::Rake::YardocTask.new
|
40
|
+
|
41
|
+
desc "Generate gem dependency graph"
|
42
|
+
task :viz do
|
43
|
+
Bundler.with_clean_env do
|
44
|
+
sh "bundle viz --without test development guard " \
|
45
|
+
"--requirements --version"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
task :default => [:test, :quality]
|
data/bin/console
ADDED
data/bin/setup
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
4
|
+
#
|
5
|
+
# Copyright (C) 2015, Fletcher Nichol
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
|
19
|
+
require "winrm/transport/version"
|
20
|
+
|
21
|
+
module WinRM
|
22
|
+
|
23
|
+
# WinRM transport logic for re-using remote shells and uploading files.
|
24
|
+
#
|
25
|
+
# @author Fletcher Nichol <fnichol@nichol.ca>
|
26
|
+
module Transport
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,217 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Author:: Matt Wrock (<matt@mattwrock.com>)
|
4
|
+
#
|
5
|
+
# Copyright (C) 2014, Matt Wrock
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
|
19
|
+
require "winrm/transport/logging"
|
20
|
+
|
21
|
+
module WinRM
|
22
|
+
|
23
|
+
module Transport
|
24
|
+
|
25
|
+
# Object which can execute multiple commands and Powershell scripts in
|
26
|
+
# one shared remote shell session. The maximum number of commands per
|
27
|
+
# shell is determined by interrogating the remote host when the session
|
28
|
+
# is opened and the remote shell is automatically recycled before the
|
29
|
+
# threshold is reached.
|
30
|
+
#
|
31
|
+
# @author Matt Wrock <matt@mattwrock.com>
|
32
|
+
# @author Fletcher Nichol <fnichol@nichol.ca>
|
33
|
+
class CommandExecutor
|
34
|
+
|
35
|
+
include Logging
|
36
|
+
|
37
|
+
# @return [Integer,nil] the safe maximum number of commands that can
|
38
|
+
# be executed in one remote shell session, or `nil` if the
|
39
|
+
# threshold has not yet been determined
|
40
|
+
attr_reader :max_commands
|
41
|
+
|
42
|
+
# @return [String,nil] the identifier for the current open remote
|
43
|
+
# shell session, or `nil` if the session is not open
|
44
|
+
attr_reader :shell
|
45
|
+
|
46
|
+
# Creates a CommandExecutor given a `WinRM::WinRMWebService` object.
|
47
|
+
#
|
48
|
+
# @param service [WinRM::WinRMWebService] a winrm web service object
|
49
|
+
# @param logger [#debug,#info] an optional logger/ui object that
|
50
|
+
# responds to `#debug` and `#info` (default: `nil`)
|
51
|
+
# @param closer [ShellCloser] an optional object to automatically
|
52
|
+
# close the active open remote shell when CommandExecutor garbarge
|
53
|
+
# collects
|
54
|
+
def initialize(service, logger = nil, closer = nil)
|
55
|
+
@service = service
|
56
|
+
@logger = logger
|
57
|
+
@closer = closer
|
58
|
+
@command_count = 0
|
59
|
+
end
|
60
|
+
|
61
|
+
# Closes the open remote shell session. This method can be called
|
62
|
+
# multiple times, even if there is no open session.
|
63
|
+
def close
|
64
|
+
return if shell.nil?
|
65
|
+
|
66
|
+
service.close_shell(shell)
|
67
|
+
remove_finalizer
|
68
|
+
@shell = nil
|
69
|
+
end
|
70
|
+
|
71
|
+
# Opens a remote shell session for reuse. The maxiumum
|
72
|
+
# command-per-shell threshold is also determined the first time this
|
73
|
+
# method is invoked and cached for later invocations.
|
74
|
+
#
|
75
|
+
# @return [String] the remote shell session indentifier
|
76
|
+
def open
|
77
|
+
close
|
78
|
+
@shell = service.open_shell
|
79
|
+
add_finalizer(shell)
|
80
|
+
@command_count = 0
|
81
|
+
determine_max_commands unless max_commands
|
82
|
+
shell
|
83
|
+
end
|
84
|
+
|
85
|
+
# Runs a CMD command.
|
86
|
+
#
|
87
|
+
# @param command [String] the command to run on the remote system
|
88
|
+
# @param arguments [Array<String>] arguments to the command
|
89
|
+
# @yield [stdout, stderr] yields more live access the standard
|
90
|
+
# output and standard error streams as they are returns, if
|
91
|
+
# streaming behavior is desired
|
92
|
+
# @return [WinRM::Output] output object with stdout, stderr, and
|
93
|
+
# exit code
|
94
|
+
def run_cmd(command, arguments = [], &block)
|
95
|
+
reset if command_count_exceeded?
|
96
|
+
ensure_open_shell!
|
97
|
+
|
98
|
+
@command_count += 1
|
99
|
+
result = nil
|
100
|
+
service.run_command(shell, command, arguments) do |command_id|
|
101
|
+
result = service.get_command_output(shell, command_id, &block)
|
102
|
+
end
|
103
|
+
result
|
104
|
+
end
|
105
|
+
|
106
|
+
# Run a Powershell script that resides on the local box.
|
107
|
+
#
|
108
|
+
# @param script_file [IO,String] an IO reference for reading the
|
109
|
+
# Powershell script or the actual file contents
|
110
|
+
# @yield [stdout, stderr] yields more live access the standard
|
111
|
+
# output and standard error streams as they are returns, if
|
112
|
+
# streaming behavior is desired
|
113
|
+
# @return [WinRM::Output] output object with stdout, stderr, and
|
114
|
+
# exit code
|
115
|
+
def run_powershell_script(script_file, &block)
|
116
|
+
# this code looks overly compact in an attempt to limit local
|
117
|
+
# variable assignments that may contain large strings and
|
118
|
+
# consequently bloat the Ruby VM
|
119
|
+
run_cmd(
|
120
|
+
"powershell",
|
121
|
+
[
|
122
|
+
"-encodedCommand",
|
123
|
+
::WinRM::PowershellScript.new(
|
124
|
+
script_file.is_a?(IO) ? script_file.read : script_file
|
125
|
+
).encoded
|
126
|
+
],
|
127
|
+
&block
|
128
|
+
)
|
129
|
+
end
|
130
|
+
|
131
|
+
private
|
132
|
+
|
133
|
+
# @return [Integer] the default maximum number of commands which can be
|
134
|
+
# executed in one remote shell session on "older" versions of Windows
|
135
|
+
# @api private
|
136
|
+
LEGACY_LIMIT = 15
|
137
|
+
|
138
|
+
# @return [Integer] the default maximum number of commands which can be
|
139
|
+
# executed in one remote shell session on "modern" versions of Windows
|
140
|
+
# @api private
|
141
|
+
MODERN_LIMIT = 1500
|
142
|
+
|
143
|
+
# @return [String] the PowerShell command used to determine the version
|
144
|
+
# of Windows
|
145
|
+
# @api private
|
146
|
+
PS1_OS_VERSION = "[environment]::OSVersion.Version.tostring()".freeze
|
147
|
+
|
148
|
+
# @return [Integer] the number of executed commands on the remote
|
149
|
+
# shell session
|
150
|
+
# @api private
|
151
|
+
attr_accessor :command_count
|
152
|
+
|
153
|
+
# @return [#debug,#info] the logger
|
154
|
+
# @api private
|
155
|
+
attr_reader :logger
|
156
|
+
|
157
|
+
# @return [WinRM::WinRMWebService] a WinRM web service object
|
158
|
+
# @api private
|
159
|
+
attr_reader :service
|
160
|
+
|
161
|
+
# Creates a finalizer for this connection which will close the open
|
162
|
+
# remote shell session when the object is garabage collected or on
|
163
|
+
# Ruby VM shutdown.
|
164
|
+
#
|
165
|
+
# @param shell_id [String] the remote shell identifier
|
166
|
+
# @api private
|
167
|
+
def add_finalizer(shell_id)
|
168
|
+
ObjectSpace.define_finalizer(self, @closer.for(shell_id)) if @closer
|
169
|
+
end
|
170
|
+
|
171
|
+
# @return [true,false] whether or not the number of exeecuted commands
|
172
|
+
# have exceeded the maxiumum threshold
|
173
|
+
# @api private
|
174
|
+
def command_count_exceeded?
|
175
|
+
command_count > max_commands.to_i
|
176
|
+
end
|
177
|
+
|
178
|
+
# Ensures that there is an open remote shell session.
|
179
|
+
#
|
180
|
+
# @raise [WinRM::WinRMError] if there is no open shell
|
181
|
+
# @api private
|
182
|
+
def ensure_open_shell!
|
183
|
+
if shell.nil?
|
184
|
+
raise ::WinRM::WinRMError, "#{self.class}#open must be called " \
|
185
|
+
"before any run methods are invoked"
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
# Determines the safe maximum number of commands that can be executed
|
190
|
+
# on a remote shell session by interrogating the remote host.
|
191
|
+
#
|
192
|
+
# @api private
|
193
|
+
def determine_max_commands
|
194
|
+
os_version = run_powershell_script(PS1_OS_VERSION).stdout.chomp
|
195
|
+
@max_commands = os_version < "6.2" ? LEGACY_LIMIT : MODERN_LIMIT
|
196
|
+
@max_commands -= 2 # to be safe
|
197
|
+
end
|
198
|
+
|
199
|
+
# Removes any finalizers for this connection.
|
200
|
+
#
|
201
|
+
# @api private
|
202
|
+
def remove_finalizer
|
203
|
+
ObjectSpace.undefine_finalizer(self) if @closer
|
204
|
+
end
|
205
|
+
|
206
|
+
# Closes the remote shell session and opens a new one.
|
207
|
+
#
|
208
|
+
# @api private
|
209
|
+
def reset
|
210
|
+
debug {
|
211
|
+
"Resetting WinRM shell (Max command limit is #{max_commands})"
|
212
|
+
}
|
213
|
+
open
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|