kitchen-ssh 1.0.2 → 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: da447d64c6144ed70e6309db0446f8ef44d79bae
4
- data.tar.gz: 210aabce4232e41e815e38bced6230b5e3ad631d
2
+ SHA256:
3
+ metadata.gz: 65f7fd88777977ba368939cfbeb8890b8f0bf8ae1e14eeb75abc943ece3da4fc
4
+ data.tar.gz: 04acb0f9b849ce3be2dd61ac66458631e5c88b50116c4c8734966eef6fdf8b5d
5
5
  SHA512:
6
- metadata.gz: 41fed5b73a96ba20ab61c1bb4897dcfb4d96deb4ee647edf0cefe9040af616fd7f983d5349d11c97240ba29960b809519ffcb5b03f7ddc5aafe10ab180dd5e51
7
- data.tar.gz: 4ecb483b8ae03b3073b4e4361959b29894fedc5f725a94f44dfc5050958e50a2840cc8f7673573c7d8d9614f4b4275d76ba355b728dab680be25dfacc4321d89
6
+ metadata.gz: c17acb9cd005c1882e273d3886dc7113821ba82a47a1dcd5d39d44752b1afce5edfc6fd738317f58cabd9d4242d1029b198cf91193e54907df8d43f4143a08a2
7
+ data.tar.gz: a887f3ed1826e16cc45ff42eb78944d3c1c747867e691669181f2bf0ad613858bf6ba429fa4a2d031d5de85fe714c31a0e7bbc451a09e4c84f9d22bf002614f7
data/README.md CHANGED
@@ -1,79 +1,79 @@
1
- # kitchen-ssh
2
-
3
- ssh and ssh_gzip driver for test-kitchen for any running server with an ip address.
4
-
5
- As well as ssh it supports a second driver called ssh_gzip that will also gzip file before transfer which can provide
6
- a big performance improvement when alot of files are transfered.
7
-
8
- server must be created and destroyed natively (e.g. via cloudformation, heat, or cloud or virtualization console).
9
- specify driver parameters
10
- * hostname
11
- * port
12
- * username
13
- * password
14
- * sudo
15
- * ssh_key
16
- * forward_agent
17
-
18
- NOTE: ssh driver is compatibile with test-kitchen 1.4 while ssh_gzip has legacy driver compatiability
19
- with test-kitchen 1.4
20
-
21
-
22
- ## Installation
23
-
24
- Add this line to your application's Gemfile:
25
-
26
- gem 'kitchen-ssh', group: :integration
27
-
28
- And then execute:
29
-
30
- $ bundle
31
-
32
- Or install it yourself as:
33
-
34
- $ gem install kitchen-ssh
35
-
36
- ## Usage
37
-
38
- In your .kitchen.yml file set driver to be 'ssh' or 'ssh_gzip'.
39
-
40
- ##Example
41
-
42
- ```yaml
43
- ---
44
- driver:
45
- name: ssh
46
- hostname: your-ip
47
- port: 22
48
- username: username
49
- ssh_key: /path/to/id_rsa
50
- ```
51
-
52
- or
53
-
54
- ```yaml
55
- ---
56
- driver:
57
- name: ssh_gzip
58
- hostname: your-ip
59
- port: 22
60
- username: username
61
- ssh_key: /path/to/id_rsa
62
- ```
63
-
64
- ### Bastion Host
65
-
66
- If you use a bastion host, add the following lines:
67
-
68
- ```yaml
69
- transport:
70
- name: ssh
71
- ssh_gateway: bastion-ip
72
- ssh_gateway_username: bastion-user
73
- ```
74
-
75
- Alternatively add `ProxyCommand ssh -W %h:%p bastion-user@bastion-ip` to your `ssh_config(5)`
76
-
77
- ## Tips
78
-
79
- If you get a hang while running kitchen-ssh with a non-root user check that the user was not set to be NOPASSWORD in the sudoer file either. So it hang there waiting for input of the password prompted. After changing the user and key to be root in the .kitchen.yml file, everything worked.
1
+ # kitchen-ssh
2
+
3
+ ssh and ssh_gzip driver for test-kitchen for any running server with an ip address.
4
+
5
+ As well as ssh it supports a second driver called ssh_gzip that will also gzip file before transfer which can provide
6
+ a big performance improvement when alot of files are transfered.
7
+
8
+ server must be created and destroyed natively (e.g. via cloudformation, heat, or cloud or virtualization console).
9
+ specify driver parameters
10
+ * hostname
11
+ * port
12
+ * username
13
+ * password
14
+ * sudo
15
+ * ssh_key
16
+ * forward_agent
17
+
18
+ NOTE: ssh driver is compatibile with test-kitchen 1.4 while ssh_gzip has legacy driver compatiability
19
+ with test-kitchen 1.4
20
+
21
+
22
+ ## Installation
23
+
24
+ Add this line to your application's Gemfile:
25
+
26
+ gem 'kitchen-ssh', group: :integration
27
+
28
+ And then execute:
29
+
30
+ $ bundle
31
+
32
+ Or install it yourself as:
33
+
34
+ $ gem install kitchen-ssh
35
+
36
+ ## Usage
37
+
38
+ In your .kitchen.yml file set driver to be 'ssh' or 'ssh_gzip'.
39
+
40
+ ##Example
41
+
42
+ ```yaml
43
+ ---
44
+ driver:
45
+ name: ssh
46
+ hostname: your-ip
47
+ port: 22
48
+ username: username
49
+ ssh_key: /path/to/id_rsa
50
+ ```
51
+
52
+ or
53
+
54
+ ```yaml
55
+ ---
56
+ driver:
57
+ name: ssh_gzip
58
+ hostname: your-ip
59
+ port: 22
60
+ username: username
61
+ ssh_key: /path/to/id_rsa
62
+ ```
63
+
64
+ ### Bastion Host
65
+
66
+ If you use a bastion host, add the following lines:
67
+
68
+ ```yaml
69
+ transport:
70
+ name: ssh
71
+ ssh_gateway: bastion-ip
72
+ ssh_gateway_username: bastion-user
73
+ ```
74
+
75
+ Alternatively add `ProxyCommand ssh -W %h:%p bastion-user@bastion-ip` to your `ssh_config(5)`
76
+
77
+ ## Tips
78
+
79
+ If you get a hang while running kitchen-ssh with a non-root user check that the user was not set to be NOPASSWORD in the sudoer file either. So it hang there waiting for input of the password prompted. After changing the user and key to be root in the .kitchen.yml file, everything worked.
@@ -1,28 +1,28 @@
1
- # encoding: utf-8
2
-
3
- $:.unshift File.expand_path('../lib', __FILE__)
4
- require 'kitchen/ssh/version'
5
-
6
- Gem::Specification.new do |s|
7
- s.name = "kitchen-ssh"
8
- s.license = 'Apache-2.0'
9
- s.version = Kitchen::Ssh::VERSION
10
- s.authors = ["Neill Turner"]
11
- s.email = ["neillwturner@gmail.com"]
12
- s.homepage = "https://github.com/neillturner/kitchen-ssh"
13
- s.add_dependency('minitar', '~> 0.6')
14
- s.summary = "ssh and ssh_gzip driver for test-kitchen for any running server with an ip address"
15
- candidates = Dir.glob("{lib}/**/*") + ['README.md', 'LICENSE.txt', 'kitchen-ssh.gemspec', 'Gemfile']
16
- s.files = candidates.sort
17
- s.platform = Gem::Platform::RUBY
18
- s.require_paths = ['lib']
19
- s.rubyforge_project = '[none]'
20
- s.description = <<-EOF
21
- ssh and ssh_gzip driver for test-kitchen for any running server with an ip address
22
-
23
- *** As well as ssh it supports a second driver called ssh_gzip that will also gzip file before transfer which can provide
24
- a big performance improvement when alot of files are transfered. ****
25
-
26
- EOF
27
-
28
- end
1
+ # encoding: utf-8
2
+
3
+ $:.unshift File.expand_path('../lib', __FILE__)
4
+ require 'kitchen/ssh/version'
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "kitchen-ssh"
8
+ s.license = 'Apache-2.0'
9
+ s.version = Kitchen::Ssh::VERSION
10
+ s.authors = ["Neill Turner"]
11
+ s.email = ["neillwturner@gmail.com"]
12
+ s.homepage = "https://github.com/neillturner/kitchen-ssh"
13
+ s.add_dependency('minitar', '~> 0.6')
14
+ s.summary = "ssh and ssh_gzip driver for test-kitchen for any running server with an ip address"
15
+ candidates = Dir.glob("{lib}/**/*") + ['README.md', 'LICENSE.txt', 'kitchen-ssh.gemspec', 'Gemfile']
16
+ s.files = candidates.sort
17
+ s.platform = Gem::Platform::RUBY
18
+ s.require_paths = ['lib']
19
+ s.rubyforge_project = '[none]'
20
+ s.description = <<-EOF
21
+ ssh and ssh_gzip driver for test-kitchen for any running server with an ip address
22
+
23
+ *** As well as ssh it supports a second driver called ssh_gzip that will also gzip file before transfer which can provide
24
+ a big performance improvement when alot of files are transfered. ****
25
+
26
+ EOF
27
+
28
+ end
@@ -1,30 +1,30 @@
1
- require 'kitchen'
2
- require 'kitchen/driver/ssh_base'
3
-
4
- module Kitchen
5
- module Driver
6
- class Ssh < SSHBase
7
- def create(state)
8
- state[:sudo] = config[:sudo]
9
- state[:port] = config[:port]
10
- state[:ssh_key] = config[:ssh_key]
11
- state[:forward_agent] = config[:forward_agent] if config[:forward_agent]
12
- state[:username] = config[:username]
13
- state[:hostname] = config[:hostname]
14
- state[:password] = config[:password] if config[:password]?
15
- print "Kitchen-ssh does not start your server '#{state[:hostname]}' but will look for an ssh connection with user '#{state[:username]}'"
16
- wait_for_sshd(state[:hostname], state[:username], {:port => state[:port]})
17
- print "Kitchen-ssh found ssh ready on host '#{state[:hostname]}' with user '#{state[:username]}'\n"
18
- debug("ssh:create '#{state[:hostname]}'")
19
- end
20
-
21
- def destroy(state)
22
- print "Kitchen-ssh does not destroy your server '#{state[:hostname]}' by shutting it down..."
23
- print "Shutdown your server '#{state[:hostname]}' natively with user '#{state[:username]}'"
24
- print 'in your cloud or virtualisation console etc.'
25
- debug("ssh:destroy '#{state[:hostname]}'")
26
- end
27
-
28
- end
29
- end
30
- end
1
+ require 'kitchen'
2
+ require 'kitchen/driver/ssh_base'
3
+
4
+ module Kitchen
5
+ module Driver
6
+ class Ssh < SSHBase
7
+ def create(state)
8
+ state[:sudo] = config[:sudo]
9
+ state[:port] = config[:port]
10
+ state[:ssh_key] = config[:ssh_key]
11
+ state[:forward_agent] = config[:forward_agent] if config[:forward_agent]
12
+ state[:username] = config[:username]
13
+ state[:hostname] = config[:hostname]
14
+ state[:password] = config[:password] if config[:password]
15
+ print "Kitchen-ssh does not start your server '#{state[:hostname]}' but will look for an ssh connection with user '#{state[:username]}'"
16
+ wait_for_sshd(state[:hostname], state[:username], {:port => state[:port]})
17
+ print "Kitchen-ssh found ssh ready on host '#{state[:hostname]}' with user '#{state[:username]}'\n"
18
+ debug("ssh:create '#{state[:hostname]}'")
19
+ end
20
+
21
+ def destroy(state)
22
+ print "Kitchen-ssh does not destroy your server '#{state[:hostname]}' by shutting it down..."
23
+ print "Shutdown your server '#{state[:hostname]}' natively with user '#{state[:username]}'"
24
+ print 'in your cloud or virtualisation console etc.'
25
+ debug("ssh:destroy '#{state[:hostname]}'")
26
+ end
27
+
28
+ end
29
+ end
30
+ end
@@ -1,251 +1,251 @@
1
- # -*- encoding: utf-8 -*-
2
- #
3
- # Author:: Fletcher Nichol (<fnichol@nichol.ca>)
4
- #
5
- # Copyright (C) 2012, 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 'archive/tar/minitar'
20
-
21
- module Kitchen
22
-
23
- module Driver
24
-
25
- # Base class for a driver that uses SSH to communication with an instance.
26
- # A subclass must implement the following methods:
27
- # * #create(state)
28
- # * #destroy(state)
29
- #
30
- # @author Fletcher Nichol <fnichol@nichol.ca>
31
- class SSHBaseGzip < Kitchen::Driver::SSHBase
32
-
33
- default_config :sudo, true
34
- default_config :port, 22
35
- default_config :sandbox_archive, 'testkitchen-sandbox.tar.gz'
36
-
37
- # (see Base#create)
38
- def create(state) # rubocop:disable Lint/UnusedMethodArgument
39
- raise ClientError, "#{self.class}#create must be implemented"
40
- end
41
-
42
- # (see Base#converge)
43
- def converge(state)
44
- provisioner = instance.provisioner
45
- provisioner.create_sandbox
46
-
47
- Kitchen::SSH.new(*build_ssh_args(state)) do |conn|
48
- run_remote(provisioner.install_command, conn)
49
- run_remote(provisioner.init_command, conn)
50
- do_sandbox_transfer provisioner, conn
51
- run_remote(provisioner.prepare_command, conn)
52
- run_remote(provisioner.run_command, conn)
53
- end
54
- ensure
55
- provisioner && provisioner.cleanup_sandbox
56
- end
57
-
58
- # (see Base#setup)
59
- def setup(state)
60
- Kitchen::SSH.new(*build_ssh_args(state)) do |conn|
61
- run_remote(busser.setup_cmd, conn)
62
- end
63
- end
64
-
65
- # (see Base#verify) - changed in kitchen >=1.4
66
- #def verify(state)
67
- # Kitchen::SSH.new(*build_ssh_args(state)) do |conn|
68
- # run_remote(busser.sync_cmd, conn)
69
- # run_remote(busser.run_cmd, conn)
70
- # end
71
- #end
72
-
73
- # (see Base#destroy)
74
- def destroy(state) # rubocop:disable Lint/UnusedMethodArgument
75
- raise ClientError, "#{self.class}#destroy must be implemented"
76
- end
77
-
78
- # (see Base#login_command)
79
- def login_command(state)
80
- SSH.new(*build_ssh_args(state)).login_command
81
- end
82
-
83
- # Executes an arbitrary command on an instance over an SSH connection.
84
- #
85
- # @param state [Hash] mutable instance and driver state
86
- # @param command [String] the command to be executed
87
- # @raise [ActionFailed] if the command could not be successfully completed
88
- def remote_command(state, command)
89
- Kitchen::SSH.new(*build_ssh_args(state)) do |conn|
90
- run_remote(command, conn)
91
- end
92
- end
93
-
94
- # **(Deprecated)** Executes a remote command over SSH.
95
- #
96
- # @param ssh_args [Array] ssh arguments
97
- # @param command [String] remote command to invoke
98
- # @deprecated This method should no longer be called directly and exists
99
- # to support very old drivers. This will be removed in the future.
100
- def ssh(ssh_args, command)
101
- Kitchen::SSH.new(*ssh_args) do |conn|
102
- run_remote(command, conn)
103
- end
104
- end
105
-
106
- private
107
-
108
- # Builds arguments for constructing a `Kitchen::SSH` instance.
109
- #
110
- # @param state [Hash] state hash
111
- # @return [Array] SSH constructor arguments
112
- # @api private
113
- def build_ssh_args(state)
114
- combined = config.to_hash.merge(state)
115
-
116
- opts = Hash.new
117
- opts[:user_known_hosts_file] = "/dev/null"
118
- opts[:verify_host_key] = false
119
- opts[:keys_only] = true if combined[:ssh_key]
120
- opts[:password] = combined[:password] if combined[:password]
121
- opts[:forward_agent] = combined[:forward_agent] if combined[:forward_agent] # if combined.key? :forward_agent
122
- opts[:port] = combined[:port] if combined[:port]
123
- opts[:keys] = Array(combined[:ssh_key]) if combined[:ssh_key]
124
- opts[:logger] = logger
125
-
126
- [combined[:hostname], combined[:username], opts]
127
- end
128
-
129
- # Adds http and https proxy environment variables to a command, if set
130
- # in configuration data.
131
- #
132
- # @param cmd [String] command string
133
- # @return [String] command string
134
- # @api private
135
- def env_cmd(cmd)
136
- env = "env"
137
- env << " http_proxy=#{config[:http_proxy]}" if config[:http_proxy]
138
- env << " https_proxy=#{config[:https_proxy]}" if config[:https_proxy]
139
-
140
- env == "env" ? cmd : "#{env} #{cmd}"
141
- end
142
-
143
- # Executes a remote command over SSH.
144
- #
145
- # @param command [String] remove command to run
146
- # @param connection [Kitchen::SSH] an SSH connection
147
- # @raise [ActionFailed] if an exception occurs
148
- # @api private
149
- def run_remote(command, connection)
150
- return if command.nil?
151
-
152
- connection.exec(env_cmd(command))
153
- rescue SSHFailed, Net::SSH::Exception => ex
154
- raise ActionFailed, ex.message
155
- end
156
-
157
- # Transfers one or more local paths over SSH.
158
- #
159
- # @param locals [Array<String>] array of local paths
160
- # @param remote [String] remote destination path
161
- # @param connection [Kitchen::SSH] an SSH connection
162
- # @raise [ActionFailed] if an exception occurs
163
- # @api private
164
- def transfer_path(locals, remote, connection)
165
- return if locals.nil? || Array(locals).empty?
166
-
167
- info("Transferring files to #{instance.to_str}")
168
- locals.each { |local| connection.upload_path!(local, remote) }
169
- debug("Transfer complete")
170
- rescue SSHFailed, Net::SSH::Exception => ex
171
- raise ActionFailed, ex.message
172
- end
173
-
174
- # Blocks until a TCP socket is available where a remote SSH server
175
- # should be listening.
176
- #
177
- # @param hostname [String] remote SSH server host
178
- # @param username [String] SSH username (default: `nil`)
179
- # @param options [Hash] configuration hash (default: `{}`)
180
- # @api private
181
- def wait_for_sshd(hostname, username = nil, options = {})
182
- SSH.new(hostname, username, { :logger => logger }.merge(options)).wait
183
- end
184
-
185
-
186
- # Creates a temporary folder containing an archive of the current
187
- # TestKitchen sandbox.
188
- #
189
- # @param sandbox_path [String]
190
- def archive_sandbox(sandbox_path)
191
- archive_dir = Dir.mktmpdir("#{instance.name}-sandbox-archive-")
192
- archive_file = "#{archive_dir}/#{self[:sandbox_archive]}"
193
-
194
- Dir.chdir(sandbox_path) do |dir|
195
- tgz = Zlib::GzipWriter.new(File.open(archive_file, 'wb'), Zlib::DEFAULT_COMPRESSION, Zlib::DEFAULT_STRATEGY)
196
- Archive::Tar::Minitar.pack('.', tgz)
197
- end
198
-
199
- archive_dir
200
- end
201
-
202
- # Transfers the local sandbox to the instance.
203
- # - Archives/extracts if the tar command is available remotely.
204
- #
205
- # @param provisioner [Kitchen::Provisioner::Base] the provisioner
206
- # @param connection [Kitchen:SSH] an SSH connection
207
- def do_sandbox_transfer(provisioner, connection)
208
- root_path = provisioner[:root_path]
209
- sandbox_path = provisioner.sandbox_path
210
- archive_file = self[:sandbox_archive]
211
- archive_path = false
212
- do_archive = remote_supports_tar? connection
213
-
214
- begin
215
- # Archive sandbox if enabled (We keep a copy of the archive path so that we do not)
216
- # delete the sandbox if an exception is thrown
217
- if do_archive
218
- info 'Creating sandbox archive'
219
- archive_path = archive_sandbox sandbox_path
220
- sandbox_path = archive_path
221
- end
222
-
223
- # Initiate transfer
224
- transfer_path(Dir.glob("#{sandbox_path}/*"), root_path, connection)
225
-
226
- # Extract archive if enabled (and cleanup locally)
227
- if do_archive
228
- info 'Extracting sandbox archive remotely'
229
- run_remote("tar xf #{root_path}/#{archive_file} -C #{root_path}", connection)
230
- end
231
- ensure
232
- # Ensure archive temporary directory is removed, if used.
233
- FileUtils.rmtree(archive_path) if archive_path
234
- end
235
- end
236
-
237
- # Checks whether the remote instance supports archive extraction using
238
- # the `tar` command.
239
- #
240
- # @param connection [Kitchen::SSH] an SSH connection
241
- def remote_supports_tar?(connection)
242
- begin
243
- run_remote('tar --version > /dev/null 2>&1', connection)
244
- return true
245
- rescue ActionFailed => ex
246
- return false
247
- end
248
- end
249
- end
250
- end
251
- end
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Author:: Fletcher Nichol (<fnichol@nichol.ca>)
4
+ #
5
+ # Copyright (C) 2012, 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 'archive/tar/minitar'
20
+
21
+ module Kitchen
22
+
23
+ module Driver
24
+
25
+ # Base class for a driver that uses SSH to communication with an instance.
26
+ # A subclass must implement the following methods:
27
+ # * #create(state)
28
+ # * #destroy(state)
29
+ #
30
+ # @author Fletcher Nichol <fnichol@nichol.ca>
31
+ class SSHBaseGzip < Kitchen::Driver::SSHBase
32
+
33
+ default_config :sudo, true
34
+ default_config :port, 22
35
+ default_config :sandbox_archive, 'testkitchen-sandbox.tar.gz'
36
+
37
+ # (see Base#create)
38
+ def create(state) # rubocop:disable Lint/UnusedMethodArgument
39
+ raise ClientError, "#{self.class}#create must be implemented"
40
+ end
41
+
42
+ # (see Base#converge)
43
+ def converge(state)
44
+ provisioner = instance.provisioner
45
+ provisioner.create_sandbox
46
+
47
+ Kitchen::SSH.new(*build_ssh_args(state)) do |conn|
48
+ run_remote(provisioner.install_command, conn)
49
+ run_remote(provisioner.init_command, conn)
50
+ do_sandbox_transfer provisioner, conn
51
+ run_remote(provisioner.prepare_command, conn)
52
+ run_remote(provisioner.run_command, conn)
53
+ end
54
+ ensure
55
+ provisioner && provisioner.cleanup_sandbox
56
+ end
57
+
58
+ # (see Base#setup)
59
+ def setup(state)
60
+ Kitchen::SSH.new(*build_ssh_args(state)) do |conn|
61
+ run_remote(busser.setup_cmd, conn)
62
+ end
63
+ end
64
+
65
+ # (see Base#verify) - changed in kitchen >=1.4
66
+ #def verify(state)
67
+ # Kitchen::SSH.new(*build_ssh_args(state)) do |conn|
68
+ # run_remote(busser.sync_cmd, conn)
69
+ # run_remote(busser.run_cmd, conn)
70
+ # end
71
+ #end
72
+
73
+ # (see Base#destroy)
74
+ def destroy(state) # rubocop:disable Lint/UnusedMethodArgument
75
+ raise ClientError, "#{self.class}#destroy must be implemented"
76
+ end
77
+
78
+ # (see Base#login_command)
79
+ def login_command(state)
80
+ SSH.new(*build_ssh_args(state)).login_command
81
+ end
82
+
83
+ # Executes an arbitrary command on an instance over an SSH connection.
84
+ #
85
+ # @param state [Hash] mutable instance and driver state
86
+ # @param command [String] the command to be executed
87
+ # @raise [ActionFailed] if the command could not be successfully completed
88
+ def remote_command(state, command)
89
+ Kitchen::SSH.new(*build_ssh_args(state)) do |conn|
90
+ run_remote(command, conn)
91
+ end
92
+ end
93
+
94
+ # **(Deprecated)** Executes a remote command over SSH.
95
+ #
96
+ # @param ssh_args [Array] ssh arguments
97
+ # @param command [String] remote command to invoke
98
+ # @deprecated This method should no longer be called directly and exists
99
+ # to support very old drivers. This will be removed in the future.
100
+ def ssh(ssh_args, command)
101
+ Kitchen::SSH.new(*ssh_args) do |conn|
102
+ run_remote(command, conn)
103
+ end
104
+ end
105
+
106
+ private
107
+
108
+ # Builds arguments for constructing a `Kitchen::SSH` instance.
109
+ #
110
+ # @param state [Hash] state hash
111
+ # @return [Array] SSH constructor arguments
112
+ # @api private
113
+ def build_ssh_args(state)
114
+ combined = config.to_hash.merge(state)
115
+
116
+ opts = Hash.new
117
+ opts[:user_known_hosts_file] = "/dev/null"
118
+ opts[:verify_host_key] = false
119
+ opts[:keys_only] = true if combined[:ssh_key]
120
+ opts[:password] = combined[:password] if combined[:password]
121
+ opts[:forward_agent] = combined[:forward_agent] if combined[:forward_agent] # if combined.key? :forward_agent
122
+ opts[:port] = combined[:port] if combined[:port]
123
+ opts[:keys] = Array(combined[:ssh_key]) if combined[:ssh_key]
124
+ opts[:logger] = logger
125
+
126
+ [combined[:hostname], combined[:username], opts]
127
+ end
128
+
129
+ # Adds http and https proxy environment variables to a command, if set
130
+ # in configuration data.
131
+ #
132
+ # @param cmd [String] command string
133
+ # @return [String] command string
134
+ # @api private
135
+ def env_cmd(cmd)
136
+ env = "env"
137
+ env << " http_proxy=#{config[:http_proxy]}" if config[:http_proxy]
138
+ env << " https_proxy=#{config[:https_proxy]}" if config[:https_proxy]
139
+
140
+ env == "env" ? cmd : "#{env} #{cmd}"
141
+ end
142
+
143
+ # Executes a remote command over SSH.
144
+ #
145
+ # @param command [String] remove command to run
146
+ # @param connection [Kitchen::SSH] an SSH connection
147
+ # @raise [ActionFailed] if an exception occurs
148
+ # @api private
149
+ def run_remote(command, connection)
150
+ return if command.nil?
151
+
152
+ connection.exec(env_cmd(command))
153
+ rescue SSHFailed, Net::SSH::Exception => ex
154
+ raise ActionFailed, ex.message
155
+ end
156
+
157
+ # Transfers one or more local paths over SSH.
158
+ #
159
+ # @param locals [Array<String>] array of local paths
160
+ # @param remote [String] remote destination path
161
+ # @param connection [Kitchen::SSH] an SSH connection
162
+ # @raise [ActionFailed] if an exception occurs
163
+ # @api private
164
+ def transfer_path(locals, remote, connection)
165
+ return if locals.nil? || Array(locals).empty?
166
+
167
+ info("Transferring files to #{instance.to_str}")
168
+ locals.each { |local| connection.upload_path!(local, remote) }
169
+ debug("Transfer complete")
170
+ rescue SSHFailed, Net::SSH::Exception => ex
171
+ raise ActionFailed, ex.message
172
+ end
173
+
174
+ # Blocks until a TCP socket is available where a remote SSH server
175
+ # should be listening.
176
+ #
177
+ # @param hostname [String] remote SSH server host
178
+ # @param username [String] SSH username (default: `nil`)
179
+ # @param options [Hash] configuration hash (default: `{}`)
180
+ # @api private
181
+ def wait_for_sshd(hostname, username = nil, options = {})
182
+ SSH.new(hostname, username, { :logger => logger }.merge(options)).wait
183
+ end
184
+
185
+
186
+ # Creates a temporary folder containing an archive of the current
187
+ # TestKitchen sandbox.
188
+ #
189
+ # @param sandbox_path [String]
190
+ def archive_sandbox(sandbox_path)
191
+ archive_dir = Dir.mktmpdir("#{instance.name}-sandbox-archive-")
192
+ archive_file = "#{archive_dir}/#{self[:sandbox_archive]}"
193
+
194
+ Dir.chdir(sandbox_path) do |dir|
195
+ tgz = Zlib::GzipWriter.new(File.open(archive_file, 'wb'), Zlib::DEFAULT_COMPRESSION, Zlib::DEFAULT_STRATEGY)
196
+ Archive::Tar::Minitar.pack('.', tgz)
197
+ end
198
+
199
+ archive_dir
200
+ end
201
+
202
+ # Transfers the local sandbox to the instance.
203
+ # - Archives/extracts if the tar command is available remotely.
204
+ #
205
+ # @param provisioner [Kitchen::Provisioner::Base] the provisioner
206
+ # @param connection [Kitchen:SSH] an SSH connection
207
+ def do_sandbox_transfer(provisioner, connection)
208
+ root_path = provisioner[:root_path]
209
+ sandbox_path = provisioner.sandbox_path
210
+ archive_file = self[:sandbox_archive]
211
+ archive_path = false
212
+ do_archive = remote_supports_tar? connection
213
+
214
+ begin
215
+ # Archive sandbox if enabled (We keep a copy of the archive path so that we do not)
216
+ # delete the sandbox if an exception is thrown
217
+ if do_archive
218
+ info 'Creating sandbox archive'
219
+ archive_path = archive_sandbox sandbox_path
220
+ sandbox_path = archive_path
221
+ end
222
+
223
+ # Initiate transfer
224
+ transfer_path(Dir.glob("#{sandbox_path}/*"), root_path, connection)
225
+
226
+ # Extract archive if enabled (and cleanup locally)
227
+ if do_archive
228
+ info 'Extracting sandbox archive remotely'
229
+ run_remote("tar xf #{root_path}/#{archive_file} -C #{root_path}", connection)
230
+ end
231
+ ensure
232
+ # Ensure archive temporary directory is removed, if used.
233
+ FileUtils.rmtree(archive_path) if archive_path
234
+ end
235
+ end
236
+
237
+ # Checks whether the remote instance supports archive extraction using
238
+ # the `tar` command.
239
+ #
240
+ # @param connection [Kitchen::SSH] an SSH connection
241
+ def remote_supports_tar?(connection)
242
+ begin
243
+ run_remote('tar --version > /dev/null 2>&1', connection)
244
+ return true
245
+ rescue ActionFailed => ex
246
+ return false
247
+ end
248
+ end
249
+ end
250
+ end
251
+ end
@@ -1,30 +1,30 @@
1
- require 'kitchen'
2
- require 'kitchen/driver/ssh_base_gzip'
3
-
4
- module Kitchen
5
- module Driver
6
- class SshGzip < SSHBaseGzip
7
- def create(state)
8
- state[:sudo] = config[:sudo]
9
- state[:port] = config[:port]
10
- state[:ssh_key] = config[:ssh_key]
11
- state[:forward_agent] = config[:forward_agent]
12
- state[:username] = config[:username]
13
- state[:hostname] = config[:hostname]
14
- state[:password] = config[:password]
15
- print "Kitchen-sshGzip does not start your server '#{state[:hostname]}' but will look for an ssh connection with user '#{state[:username]}'"
16
- wait_for_sshd(state[:hostname], state[:username], {:port => state[:port]})
17
- print "Kitchen-sshGzip found ssh ready on host '#{state[:hostname]}' with user '#{state[:username]}'\n"
18
- debug("ssh:create '#{state[:hostname]}'")
19
- end
20
-
21
- def destroy(state)
22
- print "Kitchen-sshGzip does not destroy your server '#{state[:hostname]}' by shutting it down..."
23
- print "Shutdown your server '#{state[:hostname]}' natively with user '#{state[:username]}'"
24
- print 'in your cloud or virtualisation console etc.'
25
- debug("ssh:destroy '#{state[:hostname]}'")
26
- end
27
-
28
- end
29
- end
30
- end
1
+ require 'kitchen'
2
+ require 'kitchen/driver/ssh_base_gzip'
3
+
4
+ module Kitchen
5
+ module Driver
6
+ class SshGzip < SSHBaseGzip
7
+ def create(state)
8
+ state[:sudo] = config[:sudo]
9
+ state[:port] = config[:port]
10
+ state[:ssh_key] = config[:ssh_key]
11
+ state[:forward_agent] = config[:forward_agent]
12
+ state[:username] = config[:username]
13
+ state[:hostname] = config[:hostname]
14
+ state[:password] = config[:password]
15
+ print "Kitchen-sshGzip does not start your server '#{state[:hostname]}' but will look for an ssh connection with user '#{state[:username]}'"
16
+ wait_for_sshd(state[:hostname], state[:username], {:port => state[:port]})
17
+ print "Kitchen-sshGzip found ssh ready on host '#{state[:hostname]}' with user '#{state[:username]}'\n"
18
+ debug("ssh:create '#{state[:hostname]}'")
19
+ end
20
+
21
+ def destroy(state)
22
+ print "Kitchen-sshGzip does not destroy your server '#{state[:hostname]}' by shutting it down..."
23
+ print "Shutdown your server '#{state[:hostname]}' natively with user '#{state[:username]}'"
24
+ print 'in your cloud or virtualisation console etc.'
25
+ debug("ssh:destroy '#{state[:hostname]}'")
26
+ end
27
+
28
+ end
29
+ end
30
+ end
@@ -1,5 +1,5 @@
1
- module Kitchen
2
- module Ssh
3
- VERSION = "1.0.2"
4
- end
5
- end
1
+ module Kitchen
2
+ module Ssh
3
+ VERSION = "1.0.3"
4
+ end
5
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kitchen-ssh
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Neill Turner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-09-18 00:00:00.000000000 Z
11
+ date: 2018-12-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitar
@@ -64,7 +64,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
64
64
  version: '0'
65
65
  requirements: []
66
66
  rubyforge_project: "[none]"
67
- rubygems_version: 2.6.13
67
+ rubygems_version: 2.7.6
68
68
  signing_key:
69
69
  specification_version: 4
70
70
  summary: ssh and ssh_gzip driver for test-kitchen for any running server with an ip