testlab 1.7.1 → 1.8.0

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.
@@ -173,12 +173,11 @@ EOF
173
173
  import.flag [:input]
174
174
 
175
175
  import.action do |global_options, options, args|
176
- if (options[:name].nil? || options[:input].nil?)
176
+ if options[:name].nil?
177
177
  help_now!('a name is required') if options[:name].nil?
178
- help_now!('a filename is required') if options[:input].nil?
179
178
  else
180
179
  iterate_objects_by_name(options[:name], TestLab::Container) do |container|
181
- container.import(options[:input])
180
+ container.import(options[:input] || "")
182
181
  end
183
182
  end
184
183
  end
@@ -11,14 +11,14 @@ class TestLab
11
11
  # container "server-west-1" do
12
12
  # domain "west.zone"
13
13
  #
14
- # distro "ubuntu"
15
- # release "precise"
14
+ # distro "ubuntu"
15
+ # release "precise"
16
16
  #
17
17
  # user do
18
18
  # username "deployer"
19
19
  # password "deployer"
20
- # uid 2600
21
- # gid 2600
20
+ # uid 2600
21
+ # gid 2600
22
22
  # end
23
23
  #
24
24
  # interface do
@@ -31,14 +31,14 @@ class TestLab
31
31
  #
32
32
  # @example Multiple interfaces can be defined as well:
33
33
  # container "dual-nic" do
34
- # distro "ubuntu"
35
- # release "precise"
34
+ # distro "ubuntu"
35
+ # release "precise"
36
36
  #
37
37
  # user do
38
38
  # username "deployer"
39
39
  # password "deployer"
40
- # uid 2600
41
- # gid 2600
40
+ # uid 2600
41
+ # gid 2600
42
42
  # end
43
43
  #
44
44
  # interface do
@@ -127,6 +127,8 @@ class TestLab
127
127
 
128
128
  attribute :mounts, :default => Array.new
129
129
 
130
+ attribute :sc_url
131
+
130
132
  attribute :aa_profile
131
133
  attribute :cap_drop
132
134
 
@@ -2,8 +2,42 @@ class TestLab
2
2
  class Container
3
3
 
4
4
  module IO
5
+ require 'net/http'
6
+ require 'net/https' if RUBY_VERSION < '1.9'
5
7
  require 'tempfile'
6
- PBZIP2_MEMORY = 256
8
+
9
+ PBZIP2_MEMORY = 1024
10
+ READ_SIZE = ((64 * 1024) - 1)
11
+ TRANSFER_MESSAGE = "transferring '%s' at %0.2fMB/s -- %0.2fMB of %0.2fMB -- %d%% \r"
12
+
13
+ def progress_callback(action, args)
14
+ @total_size ||= 0
15
+
16
+ case action
17
+ when :open then
18
+ @start_time = Time.now
19
+ if (@total_size == 0)
20
+ @total_size = args[0].size
21
+ @total_size_mb = (@total_size.to_f / (1024 * 1024).to_f)
22
+ end
23
+
24
+ when :get, :put then
25
+ current_size = (args[1] + args[2].length)
26
+ current_size_mb = (current_size.to_f / (1024 * 1024).to_f)
27
+
28
+ elapsed = (Time.now - @start_time)
29
+ speed_mb = (current_size.to_f / elapsed.to_f) / (1024 * 1024).to_f
30
+
31
+ percentage_done = ((current_size * 100) / @total_size)
32
+
33
+ @ui.stdout.print(format_message(TRANSFER_MESSAGE.yellow % [File.basename(args[0].local), speed_mb, current_size_mb, @total_size_mb, percentage_done]))
34
+
35
+ when :finish
36
+ @ui.stdout.puts
37
+ @total_size = 0
38
+
39
+ end
40
+ end
7
41
 
8
42
  # Export the container
9
43
  #
@@ -44,10 +78,19 @@ ls -lah #{remote_file}
44
78
  EOF
45
79
  end
46
80
 
47
- please_wait(:ui => @ui, :message => format_object_action(self, 'Export', :cyan)) do
48
- File.exists?(local_file) and FileUtils.rm_f(local_file)
49
- self.node.download(remote_file, local_file)
50
- end
81
+ File.exists?(local_file) and FileUtils.rm_f(local_file)
82
+
83
+ @total_size = self.node.ssh.sftp.stat!(remote_file).size
84
+ @total_size_mb = (@total_size.to_f / (1024 * 1024).to_f)
85
+
86
+ self.node.download(remote_file, local_file, :on_progress => method(:progress_callback), :read_size => READ_SIZE)
87
+
88
+ self.node.bootstrap(<<-EOF)
89
+ set -x
90
+ set -e
91
+
92
+ rm -fv #{remote_file}
93
+ EOF
51
94
 
52
95
  @ui.stdout.puts(format_message("Your shipping container is now exported and available at '#{local_file}'!".green.bold))
53
96
 
@@ -60,11 +103,21 @@ EOF
60
103
  def import(local_file)
61
104
  @ui.logger.debug { "Container Import: #{self.id} " }
62
105
 
106
+ if !File.exists?(local_file)
107
+ self.sc_url.nil? and raise ContainerError, "You failed to supply a filename or URL to import from!"
108
+
109
+ @ui.stdout.puts(format_message("Downloading shipping container for #{self.id}...".green.bold))
110
+
111
+ local_file = File.expand_path("#{self.id}.sc")
112
+ sc_download(local_file, self.sc_url, 16)
113
+ end
114
+
63
115
  # Ensure we are not in ephemeral mode.
64
116
  self.persistent
65
117
 
66
118
  self.down
67
119
  self.destroy
120
+
68
121
  self.create
69
122
 
70
123
  import_tempfile = Tempfile.new('import')
@@ -75,10 +128,8 @@ EOF
75
128
  local_file = File.expand_path(local_file)
76
129
  root_fs_path = self.lxc.fs_root.split(File::SEPARATOR).last
77
130
 
78
- please_wait(:ui => @ui, :message => format_object_action(self, 'Import', :cyan)) do
79
- self.node.exec(%(sudo rm -fv #{remote_file}), :silence => true, :ignore_exit_status => true)
80
- self.node.upload(local_file, remote_file)
81
- end
131
+ self.node.exec(%(sudo rm -fv #{remote_file}), :silence => true, :ignore_exit_status => true)
132
+ self.node.upload(local_file, remote_file, :on_progress => method(:progress_callback), :read_size => READ_SIZE)
82
133
 
83
134
  please_wait(:ui => @ui, :message => format_object_action(self, 'Expand', :cyan)) do
84
135
  self.node.bootstrap(<<-EOF)
@@ -92,6 +143,8 @@ cd #{self.lxc.container_root}
92
143
  pbzip2 -vdcm#{PBZIP2_MEMORY} #{remote_file} | cpio -uid && rm -fv #{remote_file}
93
144
 
94
145
  du -sh #{self.lxc.container_root}
146
+
147
+ rm -fv #{remote_file}
95
148
  EOF
96
149
  end
97
150
 
@@ -135,6 +188,73 @@ EOF
135
188
  true
136
189
  end
137
190
 
191
+ # Downloads a given shipping container image
192
+ #
193
+ # @return [Boolean] True if successful.
194
+ def sc_download(local_file, url, count)
195
+ (count <= 0) and raise ContainerError, "Too many redirects, aborting!"
196
+
197
+ uri = URI(url)
198
+ http = Net::HTTP.new(uri.host, uri.port)
199
+
200
+ if (uri.scheme.downcase == 'https')
201
+ http.use_ssl = true
202
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE # lets be really permissive for now
203
+ end
204
+
205
+ http.request_get(uri.path) do |response|
206
+ case response
207
+ when Net::HTTPNotFound then
208
+ raise ContainerError, "The supplied sc_url for this container was 404 Not Found!"
209
+
210
+ when Net::HTTPClientError then
211
+ raise ContainerError, "Client Error: #{response.inspect}"
212
+
213
+ when Net::HTTPRedirection then
214
+ location = response['location']
215
+ @ui.stdout.puts(format_message("REDIRECTED #{url} --> #{location}".black))
216
+ return sc_download(local_file, location, (count - 1))
217
+
218
+ when Net::HTTPOK then
219
+ tempfile = Tempfile.new(%(download-#{self.id}))
220
+ tempfile.binmode
221
+
222
+ current_size = 0
223
+ progress = 0
224
+ total_size = response['content-length'].to_i
225
+ total_size_mb = total_size.to_f / (1024 * 1024).to_f
226
+
227
+ start_time = Time.now
228
+ response.read_body do |chunk|
229
+ tempfile << chunk
230
+
231
+ current_size += chunk.size
232
+ current_size_mb = current_size.to_f / (1024 * 1024).to_f
233
+
234
+ new_progress = (current_size * 100) / total_size
235
+ unless new_progress == progress
236
+ elapsed = (Time.now - start_time)
237
+ speed_mb = (current_size.to_f / elapsed.to_f) / (1024 * 1024).to_f
238
+ @ui.stdout.print(format_message(TRANSFER_MESSAGE.yellow % [File.basename(local_file), speed_mb, current_size_mb, total_size_mb, new_progress]))
239
+ end
240
+ progress = new_progress
241
+ end
242
+ @ui.stdout.puts
243
+
244
+ tempfile.close
245
+
246
+ FileUtils.mkdir_p(File.dirname(local_file))
247
+ File.exists?(local_file) and File.unlink(local_file)
248
+ FileUtils.mv(tempfile.path, local_file, :force => true)
249
+
250
+ true
251
+ else
252
+ raise ContainerError, "Unknown HTTP response when attempt to download your shipping container!"
253
+ end
254
+ end
255
+
256
+ end
257
+
138
258
  end
139
259
 
140
260
  end
@@ -1,6 +1,6 @@
1
1
  class TestLab
2
2
  unless const_defined?(:VERSION)
3
3
  # TestLab Gem Version
4
- VERSION = "1.7.1"
4
+ VERSION = "1.8.0"
5
5
  end
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: testlab
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.7.1
4
+ version: 1.8.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-09-09 00:00:00.000000000 Z
12
+ date: 2013-09-15 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: gli
@@ -343,7 +343,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
343
343
  version: '0'
344
344
  segments:
345
345
  - 0
346
- hash: 1929450895573458590
346
+ hash: -2347575770462916440
347
347
  required_rubygems_version: !ruby/object:Gem::Requirement
348
348
  none: false
349
349
  requirements:
@@ -352,7 +352,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
352
352
  version: '0'
353
353
  segments:
354
354
  - 0
355
- hash: 1929450895573458590
355
+ hash: -2347575770462916440
356
356
  requirements: []
357
357
  rubyforge_project:
358
358
  rubygems_version: 1.8.25