winrm-transport 1.0.2 → 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -1,49 +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]
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 CHANGED
@@ -1,7 +1,7 @@
1
- #!/usr/bin/env ruby
2
-
3
- require "bundler/setup"
4
- require "winrm/transport"
5
-
6
- require "pry"
7
- Pry.start
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "winrm/transport"
5
+
6
+ require "pry"
7
+ Pry.start
data/bin/setup CHANGED
@@ -1,7 +1,7 @@
1
- #!/bin/bash
2
- set -euo pipefail
3
- IFS=$'\n\t'
4
-
5
- bundle install
6
-
7
- # Do any other automated setup that you need to do here
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -1,28 +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
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
@@ -1,217 +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
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