testlab 1.7.1 → 1.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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