ztk 1.6.2 → 1.6.3

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.
@@ -0,0 +1,67 @@
1
+ module ZTK
2
+ class Report
3
+
4
+ # Report List Functionality
5
+ module List
6
+
7
+ # Displays data in a key-value list style.
8
+ #
9
+ # +-------------------------------------------------------------------+
10
+ # | PROVIDER: Cucumber::Chef::Provider::Vagrant |
11
+ # | ID: default |
12
+ # | STATE: aborted |
13
+ # | USERNAME: vagrant |
14
+ # | IP ADDRESS: 127.0.0.1 |
15
+ # | PORT: 2222 |
16
+ # | CHEF-SERVER API: http://127.0.0.1:4000 |
17
+ # | CHEF-SERVER WEBUI: http://127.0.0.1:4040 |
18
+ # | CHEF-SERVER DEFAULT USER: admin |
19
+ # | CHEF-SERVER DEFAULT PASSWORD: p@ssw0rd1 |
20
+ # +-------------------------------------------------------------------+
21
+ #
22
+ # @param [Array<Object>,Object] dataset A single object or an array of
23
+ # objects for which we want to generate a report
24
+ # @param [Array] headers An array of headers used for ordering the output.
25
+ # @return [OpenStruct]
26
+ def list(dataset, headers, &block)
27
+ !block_given? and log_and_raise(ReportError, "You must supply a block!")
28
+ headers.nil? and log_and_raise(ReportError, "Headers can not be nil!")
29
+ dataset.nil? and log_and_raise(ReportError, "Dataset can not be nil!")
30
+
31
+ rows = Array.new
32
+ max_lengths = OpenStruct.new
33
+ headers = headers.map(&:to_s).map(&:downcase).map(&:to_sym)
34
+
35
+ if dataset.is_a?(Array)
36
+ dataset.each do |data|
37
+ rows << block.call(data)
38
+ end
39
+ else
40
+ rows << block.call(dataset)
41
+ end
42
+ rows.compact!
43
+
44
+ if rows.count > 0
45
+ max_key_length = headers.collect{ |header| header.to_s.length }.max
46
+ max_value_length = rows.collect{ |row| headers.collect{ |header| row.send(:table)[header].to_s.length }.max }.max
47
+
48
+ width = (max_key_length + max_value_length + 2 + 2 + 2)
49
+
50
+ rows.each do |row|
51
+ config.ui.stdout.puts("+#{"-" * width}+")
52
+ headers.each do |header|
53
+ entry_line = format_entry(header, max_key_length, row.send(:table)[header], max_value_length)
54
+ config.ui.stdout.puts(entry_line)
55
+ end
56
+ end
57
+ config.ui.stdout.puts("+#{"-" * width}+")
58
+ OpenStruct.new(:rows => rows, :max_key_length => max_key_length, :max_value_length => max_value_length, :width => width)
59
+ else
60
+ OpenStruct.new(:rows => rows, :max_key_length => 0, :max_value_length => 0, :width => 0)
61
+ end
62
+ end
63
+
64
+ end
65
+
66
+ end
67
+ end
@@ -0,0 +1,44 @@
1
+ module ZTK
2
+ class Report
3
+
4
+ # Report Private Functionality
5
+ module Private
6
+
7
+ def max_spreadsheet_lengths(headers, rows)
8
+ max_lengths = OpenStruct.new
9
+ headers.each do |header|
10
+ collection = [header, rows.collect{|r| r.send(:table)[header] } ].flatten
11
+ maximum = collection.map(&:to_s).map(&:length).max
12
+ max_lengths.send(:table)[header] = maximum
13
+ end
14
+
15
+ max_lengths
16
+ end
17
+
18
+ def calculate_spreadsheet_width(headers, max_lengths)
19
+ header_lengths = ((headers.count * 3) - 3)
20
+ max_length = max_lengths.send(:table).values.reduce(:+)
21
+ (2 + max_length + header_lengths + 2)
22
+ end
23
+
24
+ def format_header(headers, lengths)
25
+ line = headers.collect do |header|
26
+ "-" * lengths.send(:table)[header]
27
+ end
28
+
29
+ ["+-", line.join("-+-"), "-+"].join.strip
30
+ end
31
+
32
+ def format_row(*args)
33
+ spacer = " "
34
+ [spacer, args, spacer].flatten.join(" | ").strip
35
+ end
36
+
37
+ def format_entry(key, key_length, value, value_length)
38
+ "| %#{key_length}s: %-#{value_length}s |" % [key.to_s.upcase, value.to_s]
39
+ end
40
+
41
+ end
42
+
43
+ end
44
+ end
@@ -0,0 +1,72 @@
1
+ module ZTK
2
+ class Report
3
+
4
+ # Report Spreadsheet Functionality
5
+ module Spreadsheet
6
+
7
+ # Displays data in a spreadsheet style.
8
+ #
9
+ # +-------------+-------+-------+--------+----------------+-------------------+--------------+---------+
10
+ # | NAME | ALIVE | ARCH | DISTRO | IP | MAC | CHEF VERSION | PERSIST |
11
+ # +-------------+-------+-------+--------+----------------+-------------------+--------------+---------+
12
+ # | sudo | false | amd64 | ubuntu | 192.168.99.110 | 00:00:5e:34:d6:aa | N/A | true |
13
+ # | timezone | false | amd64 | ubuntu | 192.168.122.47 | 00:00:5e:92:d7:f6 | N/A | true |
14
+ # | chef-client | false | amd64 | ubuntu | 192.168.159.98 | 00:00:5e:c7:ce:26 | N/A | true |
15
+ # | users | false | amd64 | ubuntu | 192.168.7.78 | 00:00:5e:89:f9:50 | N/A | true |
16
+ # +-------------+-------+-------+--------+----------------+-------------------+--------------+---------+
17
+ #
18
+ # @param [Array<Object>,Object] dataset A single object or an array of
19
+ # objects for which we want to generate a report
20
+ # @param [Array] headers An array of headers used for ordering the output.
21
+ # @return [OpenStruct]
22
+ def spreadsheet(dataset, headers, &block)
23
+ !block_given? and log_and_raise(ReportError, "You must supply a block!")
24
+ headers.nil? and log_and_raise(ReportError, "Headers can not be nil!")
25
+ dataset.nil? and log_and_raise(ReportError, "Dataset can not be nil!")
26
+
27
+ rows = Array.new
28
+ max_lengths = OpenStruct.new
29
+ headers = headers.map(&:to_s).map(&:downcase).map(&:to_sym)
30
+
31
+ if dataset.is_a?(Array)
32
+ dataset.each do |data|
33
+ rows << block.call(data)
34
+ end
35
+ else
36
+ rows << block.call(dataset)
37
+ end
38
+ rows.compact!
39
+
40
+ if rows.count > 0
41
+ max_lengths = max_spreadsheet_lengths(headers, rows)
42
+ header_line = headers.collect { |header| "%-#{max_lengths.send(:table)[header]}s" % header.to_s.upcase }
43
+ header_line = format_row(header_line)
44
+
45
+ config.ui.stdout.puts(format_header(headers, max_lengths))
46
+ config.ui.stdout.puts(header_line)
47
+ config.ui.stdout.puts(format_header(headers, max_lengths))
48
+
49
+ rows.each do |row|
50
+ row_line = headers.collect do |header|
51
+ header_length = max_lengths.send(:table)[header]
52
+ content = row.send(:table)[header]
53
+
54
+ "%-#{header_length}s" % content
55
+ end
56
+
57
+ row_line = format_row(row_line)
58
+ config.ui.stdout.puts(row_line)
59
+ end
60
+
61
+ config.ui.stdout.puts(format_header(headers, max_lengths))
62
+ OpenStruct.new(:rows => rows, :max_lengths => max_lengths, :width => calculate_spreadsheet_width(headers, max_lengths))
63
+ else
64
+ OpenStruct.new(:rows => rows, :max_lengths => 0, :width => 0)
65
+ end
66
+
67
+ end
68
+
69
+ end
70
+
71
+ end
72
+ end
@@ -1,8 +1,3 @@
1
- require 'ostruct'
2
- require 'net/ssh'
3
- require 'net/ssh/proxy/command'
4
- require 'net/sftp'
5
-
6
1
  module ZTK
7
2
 
8
3
  # SSH Error Class
@@ -24,7 +19,7 @@ module ZTK
24
19
  #
25
20
  # If you want to specify SSH options you can:
26
21
  #
27
- # keys = File.expand_path(File.join(ENV['HOME'], '.ssh', 'id_rsa'))
22
+ # keys = File.expand_path(File.join(Dir.home, '.ssh', 'id_rsa'))
28
23
  # ssh = ZTK::SSH.new(:host_name => '127.0.0.1', :user => ENV['USER'], :keys => keys)
29
24
  #
30
25
  # = Configuration Examples:
@@ -41,8 +36,8 @@ module ZTK
41
36
  # Specify an identity file:
42
37
  #
43
38
  # ssh.config do |config|
44
- # config.keys = File.expand_path(File.join(ENV['HOME'], '.ssh', 'id_rsa'))
45
- # config.proxy_keys = File.expand_path(File.join(ENV['HOME'], '.ssh', 'id_rsa'))
39
+ # config.keys = File.expand_path(File.join(Dir.home, '.ssh', 'id_rsa'))
40
+ # config.proxy_keys = File.expand_path(File.join(Dir.home, '.ssh', 'id_rsa'))
46
41
  # end
47
42
  #
48
43
  # Specify a timeout:
@@ -65,6 +60,11 @@ module ZTK
65
60
  #
66
61
  # @author Zachary Patten <zachary AT jovelabs DOT com>
67
62
  class SSH < ZTK::Base
63
+ require 'ostruct'
64
+ require 'net/ssh'
65
+ require 'net/ssh/proxy/command'
66
+ require 'net/sftp'
67
+
68
68
  # Exit Signal Mappings
69
69
  EXIT_SIGNALS = {
70
70
  1 => "SIGHUP",
@@ -96,15 +96,20 @@ module ZTK
96
96
  27 => "SIGPROF"
97
97
  }
98
98
 
99
- autoload :Bootstrap, 'ztk/ssh/bootstrap'
100
- autoload :Command, 'ztk/ssh/command'
101
- autoload :Download, 'ztk/ssh/download'
102
- autoload :Exec, 'ztk/ssh/exec'
103
- autoload :File, 'ztk/ssh/file'
104
- autoload :Upload, 'ztk/ssh/upload'
99
+ require 'ztk/ssh/bootstrap'
100
+ require 'ztk/ssh/command'
101
+ require 'ztk/ssh/console'
102
+ require 'ztk/ssh/core'
103
+ require 'ztk/ssh/download'
104
+ require 'ztk/ssh/exec'
105
+ require 'ztk/ssh/file'
106
+ require 'ztk/ssh/private'
107
+ require 'ztk/ssh/upload'
105
108
 
106
109
  include ZTK::SSH::Bootstrap
107
110
  include ZTK::SSH::Command
111
+ include ZTK::SSH::Console
112
+ include ZTK::SSH::Core
108
113
  include ZTK::SSH::Download
109
114
  include ZTK::SSH::Exec
110
115
  include ZTK::SSH::File
@@ -155,113 +160,14 @@ module ZTK
155
160
  :exit_code => 0,
156
161
  :silence => false
157
162
  }.merge(configuration))
158
- config.ui.logger.debug { "config=#{config.send(:table).inspect}" }
159
- end
160
-
161
- # Starts an SSH session. Can also be used to get the Net::SSH object.
162
- #
163
- # Primarily used internally.
164
- def ssh
165
- @ssh ||= Net::SSH.start(config.host_name, config.user, ssh_options)
166
- end
167
-
168
- # Starts an SFTP session. Can also be used to get the Net::SFTP object.
169
- #
170
- # Primarily used internally.
171
- def sftp
172
- @sftp ||= Net::SFTP.start(config.host_name, config.user, ssh_options)
173
- end
174
-
175
- # Close our session gracefully.
176
- def close
177
- config.ui.logger.debug { "close" }
178
- ssh and !ssh.closed? and ssh.close
179
- end
180
-
181
- # The on_retry method we'll use with the RescueRetry class.
182
- def on_retry(exception)
183
- close
184
- @ssh = nil
185
- @sftp = nil
186
- end
187
163
 
188
- # Launches an SSH console, replacing the current process with the console
189
- # process.
190
- #
191
- # @example Launch a console:
192
- # ssh = ZTK::SSH.new
193
- # ssh.config do |config|
194
- # config.user = ENV["USER"]
195
- # config.host_name = "127.0.0.1"
196
- # end
197
- # ssh.console
198
- def console
199
164
  config.ui.logger.debug { "config=#{config.send(:table).inspect}" }
200
- config.ui.logger.info { "console(#{console_command.inspect})" }
201
-
202
- config.ui.logger.fatal { "REPLACING CURRENT PROCESS - GOODBYE!" }
203
- Kernel.exec(console_command)
204
165
  end
205
166
 
206
167
 
207
168
  private
208
169
 
209
- # Builds our SSH options hash.
210
- def ssh_options
211
- options = {}
212
-
213
- # These are plainly documented on the Net::SSH config class.
214
- options.merge!(:encryption => config.encryption) if config.encryption
215
- options.merge!(:compression => config.compression) if config.compression
216
- options.merge!(:compression_level => config.compression_level) if config.compression_level
217
- options.merge!(:timeout => config.timeout) if config.timeout
218
- options.merge!(:forward_agent => config.forward_agent) if config.forward_agent
219
- options.merge!(:global_known_hosts_file => config.global_known_hosts_file) if config.global_known_hosts_file
220
- options.merge!(:auth_methods => config.auth_methods) if config.auth_methods
221
- options.merge!(:host_key => config.host_key) if config.host_key
222
- options.merge!(:host_key_alias => config.host_key_alias) if config.host_key_alias
223
- options.merge!(:host_name => config.host_name) if config.host_name
224
- options.merge!(:keys => config.keys) if config.keys
225
- options.merge!(:keys_only => config.keys_only) if config.keys_only
226
- options.merge!(:hmac => config.hmac) if config.hmac
227
- options.merge!(:port => config.port) if config.port
228
- options.merge!(:proxy => Net::SSH::Proxy::Command.new(proxy_command)) if config.proxy_host_name
229
- options.merge!(:rekey_limit => config.rekey_limit) if config.rekey_limit
230
- options.merge!(:user => config.user) if config.user
231
- options.merge!(:user_known_hosts_file => config.user_known_hosts_file) if config.user_known_hosts_file
232
-
233
- # This is not plainly documented on the Net::SSH config class.
234
- options.merge!(:password => config.password) if config.password
235
-
236
- config.ui.logger.debug { "ssh_options(#{options.inspect})" }
237
- options
238
- end
239
-
240
- # Builds a human readable tag about our connection. Used for internal
241
- # logging purposes.
242
- def tag
243
- tags = Array.new
244
-
245
- if config.proxy_host_name
246
- proxy_user_host = "#{config.proxy_user}@#{config.proxy_host_name}"
247
- proxy_port = (config.proxy_port ? ":#{config.proxy_port}" : nil)
248
- tags << [proxy_user_host, proxy_port].compact.join
249
- tags << " >>> "
250
- end
251
-
252
- user_host = "#{config.user}@#{config.host_name}"
253
- port = (config.port ? ":#{config.port}" : nil)
254
- tags << [user_host, port].compact.join
255
-
256
- tags.join.strip
257
- end
258
-
259
- def log_header(what)
260
- count = 8
261
- sep = ("=" * count)
262
- header = [sep, "[ #{what} ]", sep, "[ #{tag} ]", sep, "[ #{what} ]", sep].join
263
- "#{header}\n"
264
- end
170
+ include ZTK::SSH::Private
265
171
 
266
172
  end
267
173
 
@@ -32,7 +32,7 @@ module ZTK
32
32
  tempfile = Tempfile.new("bootstrap")
33
33
 
34
34
  local_tempfile = tempfile.path
35
- remote_tempfile = ::File.join("/", "tmp", ::File.basename(local_tempfile))
35
+ remote_tempfile = ::File.join(ZTK::Locator.root, "tmp", ::File.basename(local_tempfile))
36
36
 
37
37
  ::File.open(local_tempfile, 'w') do |file|
38
38
  file.puts(content)
@@ -0,0 +1,28 @@
1
+ module ZTK
2
+ class SSH
3
+
4
+ # SSH Console Functionality
5
+ module Console
6
+
7
+ # Launches an SSH console, replacing the current process with the console
8
+ # process.
9
+ #
10
+ # @example Launch a console:
11
+ # ssh = ZTK::SSH.new
12
+ # ssh.config do |config|
13
+ # config.user = ENV["USER"]
14
+ # config.host_name = "127.0.0.1"
15
+ # end
16
+ # ssh.console
17
+ def console
18
+ config.ui.logger.debug { "config=#{config.send(:table).inspect}" }
19
+ config.ui.logger.info { "console(#{console_command.inspect})" }
20
+
21
+ config.ui.logger.fatal { "REPLACING CURRENT PROCESS - GOODBYE!" }
22
+ Kernel.exec(console_command)
23
+ end
24
+
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,37 @@
1
+ module ZTK
2
+ class SSH
3
+
4
+ # SSH Core Functionality
5
+ module Core
6
+
7
+ # Starts an SSH session. Can also be used to get the Net::SSH object.
8
+ #
9
+ # Primarily used internally.
10
+ def ssh
11
+ @ssh ||= Net::SSH.start(config.host_name, config.user, ssh_options)
12
+ end
13
+
14
+ # Starts an SFTP session. Can also be used to get the Net::SFTP object.
15
+ #
16
+ # Primarily used internally.
17
+ def sftp
18
+ @sftp ||= Net::SFTP.start(config.host_name, config.user, ssh_options)
19
+ end
20
+
21
+ # Close our session gracefully.
22
+ def close
23
+ config.ui.logger.debug { "close" }
24
+ ssh and !ssh.closed? and ssh.close
25
+ end
26
+
27
+ # The on_retry method we'll use with the RescueRetry class.
28
+ def on_retry(exception)
29
+ close
30
+ @ssh = nil
31
+ @sftp = nil
32
+ end
33
+
34
+ end
35
+
36
+ end
37
+ end
@@ -21,8 +21,8 @@ module ZTK
21
21
  # config.user = ENV["USER"]
22
22
  # config.host_name = "127.0.0.1"
23
23
  # end
24
- # local = File.expand_path(File.join("/tmp", "id_rsa.pub"))
25
- # remote = File.expand_path(File.join(ENV["HOME"], ".ssh", "id_rsa.pub"))
24
+ # local = File.expand_path(File.join(ZTK::Locator.root, "tmp", "id_rsa.pub"))
25
+ # remote = File.expand_path(File.join(Dir.home, ".ssh", "id_rsa.pub"))
26
26
  # ssh.download(remote, local)
27
27
  def download(remote, local, options={})
28
28
  options = {:recursive => ::File.directory?(local) }.merge(options)