remotus 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Remotus
4
+ # Remotus gem version
5
+ VERSION = "0.1.0"
6
+ end
@@ -0,0 +1,186 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "remotus"
4
+ require "remotus/result"
5
+ require "remotus/auth"
6
+ require "winrm"
7
+ require "winrm-fs"
8
+
9
+ module Remotus
10
+ # Class representing a WinRM connection to a host
11
+ class WinrmConnection
12
+ # Standard WinRM remote port
13
+ REMOTE_PORT = 5985
14
+
15
+ # @return [Integer] Remote port
16
+ attr_reader :port
17
+
18
+ # @return [String] host hostname
19
+ attr_reader :host
20
+
21
+ #
22
+ # Creates a WinrmConnection
23
+ #
24
+ # @param [String] host hostname
25
+ # @param [Integer] port remote port
26
+ #
27
+ def initialize(host, port = REMOTE_PORT)
28
+ @host = host
29
+ @port = port
30
+ end
31
+
32
+ #
33
+ # Connection type
34
+ #
35
+ # @return [Symbol] returns :winrm
36
+ #
37
+ def type
38
+ :winrm
39
+ end
40
+
41
+ #
42
+ # Retrieves/creates the base WinRM connection for the host
43
+ # If the base connection already exists, the existing connection will be retrieved
44
+ #
45
+ # @return [WinRM::Connection] base WinRM remote connection
46
+ #
47
+ def base_connection(reload: false)
48
+ return @base_connection if !reload && !restart_base_connection?
49
+
50
+ Remotus.logger.debug { "Initializing WinRM connection to #{Remotus::Auth.credential(self).user}@#{@host}:#{@port}" }
51
+ @base_connection = WinRM::Connection.new(
52
+ endpoint: "http://#{@host}:#{@port}/wsman",
53
+ transport: :negotiate,
54
+ user: Remotus::Auth.credential(self).user,
55
+ password: Remotus::Auth.credential(self).password
56
+ )
57
+ end
58
+
59
+ #
60
+ # Retrieves/creates the WinRM shell connection for the host
61
+ # If the connection already exists, the existing connection will be retrieved
62
+ #
63
+ # @return [WinRM::Shells::Powershell] remote connection
64
+ #
65
+ def connection
66
+ return @connection unless restart_connection?
67
+
68
+ @connection = base_connection(reload: true).shell(:powershell)
69
+ end
70
+
71
+ #
72
+ # Whether the remote host's WinRM port is available
73
+ #
74
+ # @return [Boolean] true if available, false otherwise
75
+ #
76
+ def port_open?
77
+ Remotus.port_open?(@host, @port)
78
+ end
79
+
80
+ #
81
+ # Runs a command on the host
82
+ #
83
+ # @param [String] command command to run
84
+ # @param [Array] args command arguments
85
+ # @param [Hash] _options unused command options
86
+ #
87
+ # @return [Remotus::Result] result describing the stdout, stderr, and exit status of the command
88
+ #
89
+ def run(command, *args, **_options)
90
+ command = "#{command}#{args.empty? ? "" : " "}#{args.join(" ")}"
91
+ run_result = connection.run(command)
92
+ Remotus::Result.new(command, run_result.stdout, run_result.stderr, run_result.output, run_result.exitcode)
93
+ rescue WinRM::WinRMAuthorizationError => e
94
+ raise Remotus::AuthenticationError, e.to_s
95
+ end
96
+
97
+ #
98
+ # Uploads a script and runs it on the host
99
+ #
100
+ # @param [String] local_path local path of the script (source)
101
+ # @param [String] remote_path remote path for the script (destination)
102
+ # @param [Array] args script arguments
103
+ # @param [Hash] options command options
104
+ #
105
+ # @return [Remotus::Result] result describing the stdout, stderr, and exit status of the command
106
+ #
107
+ def run_script(local_path, remote_path, *args, **options)
108
+ upload(local_path, remote_path)
109
+ run(remote_path, *args, **options)
110
+ end
111
+
112
+ #
113
+ # Uploads a file from the local host to the remote host
114
+ #
115
+ # @param [String] local_path local path to upload the file from (source)
116
+ # @param [String] remote_path remote path to upload the file to (destination)
117
+ # @param [Hash] _options unused upload options
118
+ #
119
+ # @return [String] remote path
120
+ #
121
+ def upload(local_path, remote_path, _options = {})
122
+ Remotus.logger.debug { "Uploading file #{local_path} to #{@host}:#{remote_path}" }
123
+ WinRM::FS::FileManager.new(base_connection).upload(local_path, remote_path)
124
+ remote_path
125
+ end
126
+
127
+ #
128
+ # Downloads a file from the remote host to the local host
129
+ #
130
+ # @param [String] remote_path remote path to download the file from (source)
131
+ # @param [String] local_path local path to download the file to (destination)
132
+ # @param [Hash] _options unused download options
133
+ #
134
+ # @return [String] local path
135
+ #
136
+ def download(remote_path, local_path, _options = {})
137
+ Remotus.logger.debug { "Downloading file #{local_path} from #{@host}:#{remote_path}" }
138
+ WinRM::FS::FileManager.new(base_connection).download(remote_path, local_path)
139
+ local_path
140
+ end
141
+
142
+ #
143
+ # Checks if a remote file or directory exists
144
+ #
145
+ # @param [String] remote_path remote path to the file or directory
146
+ # @param [Hash] _options unused command options
147
+ #
148
+ # @return [Boolean] true if the file or directory exists, false otherwise
149
+ #
150
+ def file_exist?(remote_path, **_options)
151
+ Remotus.logger.debug { "Checking if file #{remote_path} exists on #{@host}" }
152
+ WinRM::FS::FileManager.new(base_connection).exists?(remote_path)
153
+ end
154
+
155
+ private
156
+
157
+ #
158
+ # Whether to restart the current WinRM base connection
159
+ #
160
+ # @return [Boolean] whether to restart the current base connection
161
+ #
162
+ def restart_base_connection?
163
+ return restart_connection? if @connection
164
+ return true unless @base_connection
165
+ return true if @host != @base_connection.instance_values["connection_opts"][:endpoint].scan(%r{//(.*):}).flatten.first
166
+ return true if Remotus::Auth.credential(self).user != @base_connection.instance_values["connection_opts"][:user]
167
+ return true if Remotus::Auth.credential(self).password != @base_connection.instance_values["connection_opts"][:password]
168
+
169
+ false
170
+ end
171
+
172
+ #
173
+ # Whether to restart the current WinRM connection
174
+ #
175
+ # @return [Boolean] whether to restart the current connection
176
+ #
177
+ def restart_connection?
178
+ return true unless @connection
179
+ return true if @host != @connection.connection_opts[:endpoint].scan(%r{//(.*):}).flatten.first
180
+ return true if Remotus::Auth.credential(self).user != @connection.connection_opts[:user]
181
+ return true if Remotus::Auth.credential(self).password != @connection.connection_opts[:password]
182
+
183
+ false
184
+ end
185
+ end
186
+ end
data/remotus.gemspec ADDED
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/remotus/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "remotus"
7
+ spec.version = Remotus::VERSION
8
+ spec.authors = ["Matthew Newell"]
9
+ spec.email = ["matthewtnewell@gmail.com"]
10
+
11
+ spec.summary = "Ruby gem for connecting to remote systems seamlessly via WinRM or SSH."
12
+ spec.description = "Ruby gem for connecting to remote systems seamlessly via WinRM or SSH."
13
+ spec.homepage = "https://github.com/wheatevo/remotus"
14
+ spec.license = "MIT"
15
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.4.0")
16
+
17
+ spec.metadata["homepage_uri"] = spec.homepage
18
+ spec.metadata["source_code_uri"] = "https://github.com/wheatevo/remotus"
19
+ spec.metadata["documentation_uri"] = "https://wheatevo.github.io/remotus/"
20
+ spec.metadata["changelog_uri"] = "https://github.com/wheatevo/remotus/blob/master/CHANGELOG.md"
21
+
22
+ # Specify which files should be added to the gem when it is released.
23
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
24
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
25
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
26
+ end
27
+ spec.bindir = "exe"
28
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
29
+ spec.require_paths = ["lib"]
30
+
31
+ # Dependencies
32
+ spec.add_dependency "connection_pool", "~> 2.2"
33
+ spec.add_dependency "net-scp", "~> 3.0"
34
+ spec.add_dependency "net-ssh", "~> 6.1"
35
+ spec.add_dependency "winrm", "~> 2.3"
36
+ spec.add_dependency "winrm-fs", "~> 1.3"
37
+
38
+ # Development dependencies
39
+ spec.add_development_dependency "rake", "~> 13.0"
40
+ spec.add_development_dependency "rspec", "~> 3.0"
41
+ spec.add_development_dependency "rubocop", "~> 1.7"
42
+ spec.add_development_dependency "rubocop-rake", "~> 0.5"
43
+ spec.add_development_dependency "rubocop-rspec", "~> 2.2"
44
+ spec.add_development_dependency "yard", "~> 0.9"
45
+ end
metadata ADDED
@@ -0,0 +1,226 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: remotus
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Matthew Newell
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2021-03-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: connection_pool
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: net-scp
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '3.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: net-ssh
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '6.1'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '6.1'
55
+ - !ruby/object:Gem::Dependency
56
+ name: winrm
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '2.3'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '2.3'
69
+ - !ruby/object:Gem::Dependency
70
+ name: winrm-fs
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.3'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.3'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '13.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '13.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '3.0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '3.0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rubocop
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '1.7'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '1.7'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rubocop-rake
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '0.5'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '0.5'
139
+ - !ruby/object:Gem::Dependency
140
+ name: rubocop-rspec
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '2.2'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '2.2'
153
+ - !ruby/object:Gem::Dependency
154
+ name: yard
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '0.9'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: '0.9'
167
+ description: Ruby gem for connecting to remote systems seamlessly via WinRM or SSH.
168
+ email:
169
+ - matthewtnewell@gmail.com
170
+ executables: []
171
+ extensions: []
172
+ extra_rdoc_files: []
173
+ files:
174
+ - ".github/workflows/main.yml"
175
+ - ".gitignore"
176
+ - ".rspec"
177
+ - ".rubocop.yml"
178
+ - CHANGELOG.md
179
+ - Gemfile
180
+ - Gemfile.lock
181
+ - LICENSE.txt
182
+ - README.md
183
+ - Rakefile
184
+ - bin/console
185
+ - bin/setup
186
+ - lib/remotus.rb
187
+ - lib/remotus/auth.rb
188
+ - lib/remotus/auth/credential.rb
189
+ - lib/remotus/auth/hash_store.rb
190
+ - lib/remotus/auth/store.rb
191
+ - lib/remotus/host_pool.rb
192
+ - lib/remotus/logger.rb
193
+ - lib/remotus/pool.rb
194
+ - lib/remotus/result.rb
195
+ - lib/remotus/ssh_connection.rb
196
+ - lib/remotus/version.rb
197
+ - lib/remotus/winrm_connection.rb
198
+ - remotus.gemspec
199
+ homepage: https://github.com/wheatevo/remotus
200
+ licenses:
201
+ - MIT
202
+ metadata:
203
+ homepage_uri: https://github.com/wheatevo/remotus
204
+ source_code_uri: https://github.com/wheatevo/remotus
205
+ documentation_uri: https://wheatevo.github.io/remotus/
206
+ changelog_uri: https://github.com/wheatevo/remotus/blob/master/CHANGELOG.md
207
+ post_install_message:
208
+ rdoc_options: []
209
+ require_paths:
210
+ - lib
211
+ required_ruby_version: !ruby/object:Gem::Requirement
212
+ requirements:
213
+ - - ">="
214
+ - !ruby/object:Gem::Version
215
+ version: 2.4.0
216
+ required_rubygems_version: !ruby/object:Gem::Requirement
217
+ requirements:
218
+ - - ">="
219
+ - !ruby/object:Gem::Version
220
+ version: '0'
221
+ requirements: []
222
+ rubygems_version: 3.1.4
223
+ signing_key:
224
+ specification_version: 4
225
+ summary: Ruby gem for connecting to remote systems seamlessly via WinRM or SSH.
226
+ test_files: []