kitchen-ssh 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -12,6 +12,10 @@ specify driver parameters
12
12
  * ssh_key
13
13
  * forward_agent
14
14
 
15
+ There is also a second driver called ssh_gzip that will also gzip file before transfer which can provide
16
+ a big performance improvement when alot of files are transfered.
17
+
18
+
15
19
  ## Installation
16
20
 
17
21
  Add this line to your application's Gemfile:
@@ -28,5 +32,5 @@ Or install it yourself as:
28
32
 
29
33
  ## Usage
30
34
 
31
- In your .kitchen.yml file set driver to be 'ssh'
35
+ In your .kitchen.yml file set driver to be 'ssh' or 'ssh_gzip'.
32
36
 
data/kitchen-ssh.gemspec CHANGED
@@ -9,6 +9,7 @@ Gem::Specification.new do |s|
9
9
  s.authors = ["Neill Turner"]
10
10
  s.email = ["neillwturner@gmail.com"]
11
11
  s.homepage = "https://github.com/neillturner/kitchen-ssh"
12
+ s.add_dependency('minitar', '~> 0.5')
12
13
  s.summary = "ssh driver for test-kitchen for any running server with an ip address"
13
14
  candidates = Dir.glob("{lib}/**/*") + ['README.md', 'LICENSE.txt', 'kitchen-ssh.gemspec']
14
15
  s.files = candidates.sort
@@ -0,0 +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 < Base
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)
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[:paranoid] = 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.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
@@ -0,0 +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.\n'
25
+ debug("ssh:destroy '#{state[:hostname]}'")
26
+ end
27
+
28
+ end
29
+ end
30
+ end
@@ -1,5 +1,5 @@
1
1
  module Kitchen
2
2
  module Ssh
3
- VERSION = "0.0.5"
3
+ VERSION = "0.0.6"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kitchen-ssh
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,8 +9,24 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-10-09 00:00:00.000000000 Z
13
- dependencies: []
12
+ date: 2015-01-14 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: minitar
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '0.5'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '0.5'
14
30
  description: ! '== DESCRIPTION:
15
31
 
16
32
 
@@ -34,6 +50,8 @@ files:
34
50
  - README.md
35
51
  - kitchen-ssh.gemspec
36
52
  - lib/kitchen/driver/ssh.rb
53
+ - lib/kitchen/driver/ssh_base_gzip.rb
54
+ - lib/kitchen/driver/ssh_gzip.rb
37
55
  - lib/kitchen/ssh/version.rb
38
56
  homepage: https://github.com/neillturner/kitchen-ssh
39
57
  licenses: []