right_scraper 3.2.6 → 5.0.1

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.
Files changed (92) hide show
  1. checksums.yaml +7 -0
  2. data/lib/right_scraper.rb +16 -34
  3. data/lib/right_scraper/builders.rb +32 -0
  4. data/lib/right_scraper/builders/base.rb +19 -20
  5. data/lib/right_scraper/builders/filesystem.rb +8 -6
  6. data/lib/right_scraper/builders/union.rb +4 -1
  7. data/lib/right_scraper/loggers.rb +31 -0
  8. data/lib/right_scraper/loggers/base.rb +113 -0
  9. data/lib/right_scraper/loggers/default.rb +98 -0
  10. data/lib/right_scraper/{scraper.rb → main.rb} +53 -9
  11. data/lib/right_scraper/processes.rb +33 -0
  12. data/lib/right_scraper/processes/shell.rb +227 -0
  13. data/lib/right_scraper/processes/{ssh.rb → ssh_agent.rb} +4 -0
  14. data/lib/right_scraper/processes/svn_client.rb +117 -0
  15. data/lib/right_scraper/processes/warden.rb +358 -0
  16. data/lib/right_scraper/registered_base.rb +154 -0
  17. data/lib/right_scraper/repositories.rb +33 -0
  18. data/lib/right_scraper/repositories/base.rb +271 -232
  19. data/lib/right_scraper/repositories/download.rb +8 -6
  20. data/lib/right_scraper/repositories/git.rb +8 -9
  21. data/lib/right_scraper/repositories/svn.rb +8 -8
  22. data/lib/right_scraper/resources.rb +32 -0
  23. data/lib/right_scraper/resources/base.rb +5 -1
  24. data/lib/right_scraper/resources/cookbook.rb +34 -27
  25. data/lib/right_scraper/resources/workflow.rb +27 -28
  26. data/lib/right_scraper/retrievers.rb +34 -0
  27. data/lib/right_scraper/retrievers/base.rb +80 -84
  28. data/lib/right_scraper/retrievers/checkout_base.rb +178 -0
  29. data/lib/right_scraper/retrievers/download.rb +125 -117
  30. data/lib/right_scraper/retrievers/git.rb +377 -223
  31. data/lib/right_scraper/retrievers/svn.rb +102 -62
  32. data/lib/right_scraper/scanners.rb +37 -0
  33. data/lib/right_scraper/scanners/base.rb +77 -80
  34. data/lib/right_scraper/scanners/cookbook_manifest.rb +31 -30
  35. data/lib/right_scraper/scanners/cookbook_metadata.rb +380 -35
  36. data/lib/right_scraper/scanners/cookbook_s3_upload.rb +56 -53
  37. data/lib/right_scraper/scanners/union.rb +61 -58
  38. data/lib/right_scraper/scanners/workflow_manifest.rb +55 -54
  39. data/lib/right_scraper/scanners/workflow_metadata.rb +41 -39
  40. data/lib/right_scraper/scanners/workflow_s3_upload.rb +59 -55
  41. data/lib/right_scraper/scrapers.rb +32 -0
  42. data/lib/right_scraper/scrapers/base.rb +217 -205
  43. data/lib/right_scraper/scrapers/cookbook.rb +42 -40
  44. data/lib/right_scraper/scrapers/workflow.rb +57 -58
  45. data/lib/right_scraper/version.rb +3 -0
  46. data/right_scraper.gemspec +12 -16
  47. metadata +57 -163
  48. data/Gemfile +0 -15
  49. data/Rakefile +0 -89
  50. data/lib/right_scraper/logger.rb +0 -107
  51. data/lib/right_scraper/loggers/noisy.rb +0 -85
  52. data/lib/right_scraper/repositories/mock.rb +0 -70
  53. data/lib/right_scraper/retrievers/checkout.rb +0 -79
  54. data/lib/right_scraper/scraper_logger.rb +0 -66
  55. data/lib/right_scraper/svn_client.rb +0 -164
  56. data/right_scraper.rconf +0 -13
  57. data/spec/builder_spec.rb +0 -50
  58. data/spec/cookbook_helper.rb +0 -73
  59. data/spec/cookbook_manifest_spec.rb +0 -93
  60. data/spec/cookbook_s3_upload_spec.rb +0 -159
  61. data/spec/download/download_retriever_spec.rb +0 -118
  62. data/spec/download/download_retriever_spec_helper.rb +0 -72
  63. data/spec/download/download_spec.rb +0 -128
  64. data/spec/download/multi_dir_spec.rb +0 -106
  65. data/spec/download/multi_dir_spec_helper.rb +0 -40
  66. data/spec/git/cookbook_spec.rb +0 -165
  67. data/spec/git/demokey +0 -27
  68. data/spec/git/demokey.pub +0 -1
  69. data/spec/git/password_key +0 -30
  70. data/spec/git/password_key.pub +0 -1
  71. data/spec/git/repository_spec.rb +0 -110
  72. data/spec/git/retriever_spec.rb +0 -553
  73. data/spec/git/retriever_spec_helper.rb +0 -112
  74. data/spec/git/scraper_spec.rb +0 -151
  75. data/spec/git/ssh_spec.rb +0 -174
  76. data/spec/git/url_spec.rb +0 -103
  77. data/spec/logger_spec.rb +0 -185
  78. data/spec/repository_spec.rb +0 -111
  79. data/spec/retriever_spec_helper.rb +0 -146
  80. data/spec/scanner_spec.rb +0 -61
  81. data/spec/scraper_helper.rb +0 -88
  82. data/spec/scraper_spec.rb +0 -147
  83. data/spec/spec_helper.rb +0 -185
  84. data/spec/svn/cookbook_spec.rb +0 -96
  85. data/spec/svn/multi_svn_spec.rb +0 -64
  86. data/spec/svn/multi_svn_spec_helper.rb +0 -40
  87. data/spec/svn/repository_spec.rb +0 -72
  88. data/spec/svn/retriever_spec.rb +0 -266
  89. data/spec/svn/scraper_spec.rb +0 -90
  90. data/spec/svn/svn_retriever_spec_helper.rb +0 -90
  91. data/spec/svn/url_spec.rb +0 -47
  92. data/spec/url_spec.rb +0 -164
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright: Copyright (c) 2010-2011 RightScale, Inc.
2
+ # Copyright: Copyright (c) 2010-2013 RightScale, Inc.
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining
5
5
  # a copy of this software and associated documentation files (the
@@ -21,49 +21,394 @@
21
21
  # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
22
  #++
23
23
 
24
+ # ancestor
25
+ require 'right_scraper/scanners'
26
+
24
27
  require 'json'
28
+ require 'right_popen'
29
+ require 'right_popen/safe_output_buffer'
30
+ require 'tmpdir'
31
+
32
+ module RightScraper::Scanners
33
+
34
+ # Load cookbook metadata from a filesystem.
35
+ class CookbookMetadata < ::RightScraper::Scanners::Base
36
+ JSON_METADATA = 'metadata.json'
37
+ RUBY_METADATA = 'metadata.rb'
38
+
39
+ UNDEFINED_COOKBOOK_NAME = 'undefined'
40
+ KNIFE_METADATA_SCRIPT_NAME = 'knife_metadata.rb'
41
+
42
+ JAILED_FILE_SIZE_CONSTRAINT = 128 * 1024 # 128 KB
43
+ FREED_FILE_SIZE_CONSTRAINT = 64 * 1024 # 64 KB
44
+
45
+ TARBALL_CREATE_TIMEOUT = 30 # ..to create the tarball
46
+ TARBALL_ARCHIVE_NAME = 'cookbook.tar'
47
+
48
+ # exceptions
49
+ class MetadataError < Exception; end
50
+
51
+ def tls
52
+ Thread.current[self.class.to_s.to_sym] ||= {}
53
+ end
54
+
55
+ def begin(resource)
56
+ @read_blk = nil
57
+ @cookbook = resource
58
+ true
59
+ end
60
+
61
+ # Complete a scan for the given resource.
62
+ #
63
+ # === Parameters ===
64
+ # resource(RightScraper::Resources::Base):: resource to scan
65
+ def end(resource)
66
+ @logger.operation(:metadata_parsing) do
67
+ if @read_blk
68
+ metadata = ::JSON.parse(@read_blk.call)
69
+ resource.metadata = metadata
70
+
71
+ # check for undefined cookbook name.
72
+ #
73
+ # note that many specs in right_scraper use badly formed metadata
74
+ # that is not even a hash so, to avoid having to fix all of them
75
+ # (and also in case the user's metadata.json is not a hash) check
76
+ # for the has_key? method.
77
+ #
78
+ # if real metadata is not a hash then that should cause failure
79
+ # at a higher level. if the cookbook name is actually defined as
80
+ # being 'undefined' then the user gets a warning anyway.
81
+ if (metadata.respond_to?(:has_key?) &&
82
+ metadata['name'] == UNDEFINED_COOKBOOK_NAME)
83
+ message =
84
+ 'Cookbook name appears to be undefined and has been' +
85
+ ' supplied automatically.'
86
+ @logger.note_warning(message)
87
+ end
88
+ else
89
+ # should not be scanning at all unless one of the metadata files was
90
+ # detected before starting scan.
91
+ fail 'Unexpected missing metadata'
92
+ end
93
+ end
94
+ true
95
+ ensure
96
+ @read_blk = nil
97
+ @cookbook = nil
98
+ end
99
+
100
+ # All done scanning this repository, we can tear down the warden container we may or
101
+ # may not have created while parsing the cookbooks for this repository.
102
+ #
103
+ def finish
104
+ begin
105
+ FileUtils.remove_entry_secure(tls[:tmpdir]) if tls[:tmpdir]
106
+ rescue ::Exception => e
107
+ @logger.note_warning(e.message)
108
+ end
25
109
 
26
- module RightScraper
27
- module Scanners
28
- # Load cookbook metadata from a filesystem.
29
- class CookbookMetadata < Base
30
- # Begin a scan for the given cookbook.
31
- #
32
- # === Parameters
33
- # cookbook(RightScraper::Resources::Cookbook):: cookbook to scan
34
- def begin(cookbook)
35
- @cookbook = cookbook
110
+ if warden = tls[:warden]
111
+ begin
112
+ warden.cleanup
113
+ rescue ::Exception => e
114
+ @logger.note_warning(e.message)
115
+ end
36
116
  end
37
117
 
38
- # Notice a file during scanning.
39
- #
40
- # === Block
41
- # Return the data for this file. We use a block because it may
42
- # not always be necessary to read the data.
43
- #
44
- # === Parameters
45
- # relative_position(String):: relative pathname for the file from root of cookbook
46
- def notice(relative_position)
47
- if relative_position == "metadata.json"
48
- @logger.operation(:metadata_parsing) do
49
- @cookbook.metadata = JSON.parse(yield)
118
+ ensure
119
+ # Cleanup thread-local storage
120
+ tls.clear
121
+ end
122
+
123
+ # Notice a file during scanning.
124
+ #
125
+ # === Block
126
+ # Return the data for this file. We use a block because it may
127
+ # not always be necessary to read the data.
128
+ #
129
+ # === Parameters
130
+ # relative_position(String):: relative pathname for the file from root of cookbook
131
+ def notice(relative_position, &blk)
132
+ case relative_position
133
+ when JSON_METADATA
134
+ # preferred over RUBY_METADATA.
135
+ @read_blk = blk
136
+ when RUBY_METADATA
137
+ # defer to any JSON_METADATA, which we hope refers to the same info.
138
+ @read_blk ||= self.method(:generate_metadata_json)
139
+ end
140
+ true
141
+ end
142
+
143
+ # Notice a directory during scanning. Since metadata.{json,rb} is by
144
+ # definition only in the root directory we don't need to recurse,
145
+ # but we do need to go into the first directory (identified by
146
+ # +relative_position+ being +nil+).
147
+ #
148
+ # === Parameters
149
+ # relative_position(String):: relative pathname for the directory from root of cookbook
150
+ #
151
+ # === Returns
152
+ # Boolean:: should the scanning recurse into the directory
153
+ def notice_dir(relative_position)
154
+ relative_position == nil
155
+ end
156
+
157
+ private
158
+
159
+ # Executes the 'metadata.rb' file from a cookbook. Because we don't want
160
+ # to evaluate arbitrary Ruby code, we need to sandbox it first using
161
+ # Warden.
162
+ #
163
+ # in order for knife metadata to succeed in the general case we need to
164
+ # copy some (but not all) of the cookbook directory AND its ancestors (if
165
+ # any) into the container. we will try and restrict copying to what might
166
+ # plausibly be referenced by 'metadata.rb' but this could be anything like
167
+ # a LICENSE, README, etc. the best heuristic seems to be to copy any file
168
+ # whose size is small (less than 128K) because 'metadata.rb' should not be
169
+ # executing binaries and should only consume text files of a reasonable
170
+ # size. if these restrictions cause a problem then the user is free to
171
+ # pre-knife his own 'metadata.json' file and check it into the repo.
172
+ #
173
+ # note the selection of the jailed cookbook dir is specific to the
174
+ # behavior of knife metadata. the cookbook name is defined when the
175
+ # 'metadata.rb' declares the name attribute, but the name attribute is
176
+ # optional. when no name attribute is declared, the metadata automagically
177
+ # uses the parent directory name. this works okay so long as the parent
178
+ # directory name is actually the cookbook name. in the case of a repo with
179
+ # 'metadata.rb' at the root (i.e. no checked-in parent directory) then the
180
+ # cookbook name is undefined. in this case, we want the cookbook name to
181
+ # be 'undefined' to remind the user to declare the name explicitly.
182
+ #
183
+ # === Returns
184
+ # @return [String] metadata JSON text
185
+ def generate_metadata_json
186
+ @logger.operation(:metadata_generation) do
187
+ # note we will use the same tmpdir path inside and outside the
188
+ # container only because it is non-trivial to invoke mktmpdir inside
189
+ # the container.
190
+ tmpdir = create_tmpdir
191
+
192
+ # arrest
193
+ knife_metadata_script_path = ::File.join(tmpdir, KNIFE_METADATA_SCRIPT_NAME)
194
+ jailed_repo_dir = ::File.join(tmpdir, UNDEFINED_COOKBOOK_NAME)
195
+ jailed_cookbook_dir = (@cookbook.pos == '.' && jailed_repo_dir) || ::File.join(jailed_repo_dir, @cookbook.pos)
196
+ jailed_metadata_json_path = ::File.join(jailed_cookbook_dir, JSON_METADATA)
197
+ freed_metadata_json_path = ::File.join(tmpdir, JSON_METADATA)
198
+
199
+ # police brutality
200
+ copy_out = { jailed_metadata_json_path => freed_metadata_json_path }
201
+
202
+ begin
203
+ # jail the repo
204
+ unless warden = tls[:warden]
205
+ # Get a list of the files in the repo we need
206
+ create_knife_metadata_script(knife_metadata_script_path)
207
+ copy_in = generate_copy_in
208
+ copy_in << knife_metadata_script_path
209
+
210
+ # Create the container, one for all in this repo
211
+ warden = tls[:warden] = create_warden
212
+
213
+ # tar up the required pieces of the repo and copy them into the container
214
+ cookbook_tarball_path = ::File.join(tmpdir, TARBALL_ARCHIVE_NAME)
215
+ # prosecute
216
+ create_cookbook_tarball(cookbook_tarball_path, copy_in, jailed_repo_dir)
217
+
218
+ # unarchive the tarball on the otherside (this is faster than single file copies)
219
+ cmd = "tar -Pxf #{cookbook_tarball_path.inspect}"
220
+ warden.run_command_in_jail(cmd, cookbook_tarball_path, nil)
50
221
  end
222
+
223
+ # Generate the metadata
224
+ cmd = "export LC_ALL='en_US.UTF-8'; ruby #{knife_metadata_script_path.inspect} #{jailed_cookbook_dir.inspect}"
225
+ warden.run_command_in_jail(cmd, nil, copy_out)
226
+
227
+ # constraining the generate file size is debatable, but our UI
228
+ # attempts to load metadata JSON into memory far too often to be
229
+ # blasé about generating multi-megabyte JSON files.
230
+ unless ::File.file?(freed_metadata_json_path)
231
+ raise MetadataError, 'Generated JSON file not found.'
232
+ end
233
+ freed_metadata_json_size = ::File.stat(freed_metadata_json_path).size
234
+ if freed_metadata_json_size <= FREED_FILE_SIZE_CONSTRAINT
235
+ # parole for good behavior
236
+ return ::File.read(freed_metadata_json_path)
237
+ else
238
+ # life imprisonment.
239
+ raise MetadataError,
240
+ "Generated metadata size of" +
241
+ " #{freed_metadata_json_size / 1024} KB" +
242
+ " exceeded the allowed limit of" +
243
+ " #{FREED_FILE_SIZE_CONSTRAINT / 1024} KB"
244
+ end
245
+ rescue ::RightScraper::Processes::Warden::LinkError => e
246
+ raise MetadataError,
247
+ "Failed to generate metadata from source: #{e.message}" +
248
+ "\n#{e.link_result.stdout}" +
249
+ "\n#{e.link_result.stderr}"
51
250
  end
52
251
  end
252
+ end
253
+
254
+ def stdout_tarball(data)
255
+ @stdout_buffer << data
256
+ end
257
+
258
+ def stderr_tarball(data)
259
+ @stderr_buffer.safe_buffer_data(data)
260
+ end
261
+
262
+ def timeout_tarball
263
+ raise MetadataError,
264
+ "Timed out waiting for tarball to build.\n" +
265
+ "stdout: #{@stdout_buffer.join}\n" +
266
+ "stderr: #{@stderr_buffer.display_text}"
267
+ end
53
268
 
54
- # Notice a directory during scanning. Since metadata.json is by
55
- # definition only in the root directory we don't need to recurse,
56
- # but we do need to go into the first directory (identified by
57
- # +relative_position+ being +nil+).
58
- #
59
- # === Parameters
60
- # relative_position(String):: relative pathname for the directory from root of cookbook
61
- #
62
- # === Returns
63
- # Boolean:: should the scanning recurse into the directory
64
- def notice_dir(relative_position)
65
- relative_position == nil
269
+ # @param [String] dest_file
270
+ # @param [Array] contents
271
+ # @param [String] dest_path
272
+ def create_cookbook_tarball(dest_file, contents, dest_path)
273
+ @logger.operation(:tarball_generation) do
274
+ tarball_cmd = [
275
+ 'tar',
276
+ "-Pcf #{dest_file}",
277
+ "--transform='s,#{@cookbook.repo_dir},#{dest_path},'",
278
+ '-T', '-'
279
+ ]
280
+
281
+ @stdout_buffer = []
282
+ @stderr_buffer = ::RightScale::RightPopen::SafeOutputBuffer.new
283
+ begin
284
+ ::RightScale::RightPopen.popen3_sync(
285
+ tarball_cmd.join(' '),
286
+ :target => self,
287
+ :timeout_handler => :timeout_tarball,
288
+ :input => contents.join("\n"),
289
+ :stderr_handler => :stderr_tarball,
290
+ :stdout_handler => :stdout_tarball,
291
+ :inherit_io => true, # avoid killing any rails connection
292
+ :timeout_seconds => TARBALL_CREATE_TIMEOUT)
293
+ rescue Exception => e
294
+ raise MetadataError,
295
+ "Failed to generate cookbook tarball from source files: #{e.message}\n" +
296
+ "stdout: #{@stdout_buffer.join}\n" +
297
+ "stderr: #{@stderr_buffer.display_text}"
298
+ end
66
299
  end
67
300
  end
301
+
302
+ # generates a script that runs Chef's knife tool. it presumes the jail
303
+ # contains a ruby interpreter that has chef installed as a gem.
304
+ #
305
+ # we want to avoid using the knife command line only because it requires a
306
+ # '$HOME/.chef/knife.rb' configuration file even though we won't use that
307
+ # configuration file in any way. :@
308
+ #
309
+ # the simplest solution is to execute the knife tool within a ruby script
310
+ # because it has no pre-configuration requirement and it does not require
311
+ # the knife binstub to be on the PATH.
312
+ def create_knife_metadata_script(script_path)
313
+ script = <<EOS
314
+ require 'rubygems'
315
+ require 'chef'
316
+ require 'chef/knife/cookbook_metadata'
317
+
318
+ jailed_cookbook_dir = ARGV.pop
319
+ knife_metadata = ::Chef::Knife::CookbookMetadata.new
320
+ knife_metadata.name_args = [::File.basename(jailed_cookbook_dir)]
321
+ knife_metadata.config[:cookbook_path] = ::File.dirname(jailed_cookbook_dir)
322
+ knife_metadata.run
323
+ EOS
324
+ ::File.open(script_path, 'w') { |f| f.puts script }
325
+ true
326
+ end
327
+
328
+ # need to enumerate files relative to the cookbook directory because we
329
+ # have no idea what the metadata script will attempt to consume from the
330
+ # files available in its repository. it may even attempt to manipulate
331
+ # files in the system or go out to the network, which may or may not be
332
+ # allowed by the conditions of the jail.
333
+ #
334
+ # some cookbooks (for Windows, especially) will have large binaries
335
+ # included in the repository. we don't want to spend time copying these
336
+ # files into jail so limit the files that metadata can reference by size.
337
+ # presumably the jail would also be limiting disk space so it is important
338
+ # to avoid this source of failure.
339
+ #
340
+ # again, the user can work around these contraints by generating his own
341
+ # metadata and checking it into the repository.
342
+ #
343
+ # @return [Array] list of files to copy into jail
344
+ def generate_copy_in()
345
+ copy_in = []
346
+ start_path = @cookbook.repo_dir
347
+ recursive_generate_copy_in(copy_in, start_path)
348
+ copy_in
349
+ end
350
+
351
+ # recursive part of generate_copy_in
352
+ def recursive_generate_copy_in(copy_in, current_path)
353
+ limited_files_of(current_path) { |file| copy_in << file }
354
+ directories_of(current_path) do |dir|
355
+ recursive_generate_copy_in(copy_in, ::File.join(dir))
356
+ end
357
+ true
358
+ end
359
+
360
+ # yields files in parent meeting size criteria.
361
+ def limited_files_of(parent)
362
+ ::Dir["#{parent}/*"].each do |item|
363
+ if ::File.file?(item)
364
+ if ::File.stat(item).size <= JAILED_FILE_SIZE_CONSTRAINT
365
+ yield item
366
+ else
367
+ if ::File.basename(item) == RUBY_METADATA
368
+ raise MetadataError,
369
+ 'Metadata source file' +
370
+ " #{relative_to_repo_dir(item).inspect}" +
371
+ ' in repository exceeded size constraint of' +
372
+ " #{JAILED_FILE_SIZE_CONSTRAINT / 1024} KB"
373
+ else
374
+ message = 'Ignored a repository file during metadata' +
375
+ ' generation due to exceeding size constraint of' +
376
+ " #{JAILED_FILE_SIZE_CONSTRAINT / 1024} KB:" +
377
+ " #{relative_to_repo_dir(item).inspect}"
378
+ @logger.info(message)
379
+ end
380
+ end
381
+ end
382
+ end
383
+ end
384
+
385
+ # yields directories of parent.
386
+ def directories_of(parent)
387
+ ::Dir["#{parent}/*"].each do |item|
388
+ case item
389
+ when '.', '..'
390
+ # do nothing
391
+ else
392
+ yield item if ::File.directory?(item)
393
+ end
394
+ end
395
+ end
396
+
397
+ # converts the given absolute path to be relative to repo_dir.
398
+ def relative_to_repo_dir(path)
399
+ path[(@cookbook.repo_dir.length + 1)..-1]
400
+ end
401
+
402
+ # factory method for an object capable of running command in jail
403
+ # (convenient for testing).
404
+ def create_warden
405
+ ::RightScraper::Processes::Warden.new
406
+ end
407
+
408
+ # factory method for tmpdir (convenient for testing).
409
+ def create_tmpdir
410
+ tls[:tmpdir] ||= ::Dir.mktmpdir
411
+ end
412
+
68
413
  end
69
414
  end
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright: Copyright (c) 2010-2012 RightScale, Inc.
2
+ # Copyright: Copyright (c) 2010-2013 RightScale, Inc.
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining
5
5
  # a copy of this software and associated documentation files (the
@@ -20,65 +20,68 @@
20
20
  # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21
21
  # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
22
  #++
23
+
24
+ # ancestor
25
+ require 'right_scraper/scanners'
26
+
23
27
  require 'right_aws'
24
28
  require 'json'
25
29
  require 'digest/md5'
26
30
 
27
- module RightScraper
28
- module Scanners
29
- # Upload scanned files to an S3 bucket.
30
- class CookbookS3Upload < Base
31
- # Create a new S3Upload. In addition to the options recognized
32
- # by Scanner, this class recognizes <tt>:s3_key</tt>,
33
- # <tt>:s3_secret</tt>, and <tt>:s3_bucket</tt> and requires all
34
- # of those.
35
- #
36
- # === Options
37
- # <tt>:s3_key</tt>:: Required. S3 access key.
38
- # <tt>:s3_secret</tt>:: Required. S3 secret key.
39
- # <tt>:s3_bucket</tt>:: Required. Bucket to upload cookbooks to.
40
- #
41
- # === Parameters
42
- # options(Hash):: scanner options
43
- def initialize(options={})
44
- super
45
- s3_key = options.fetch(:s3_key)
46
- s3_secret = options.fetch(:s3_secret)
47
- s3 = RightAws::S3.new(aws_access_key_id=s3_key,
48
- aws_secret_access_key=s3_secret,
49
- :logger => Logger.new)
50
- @bucket = s3.bucket(options.fetch(:s3_bucket))
51
- raise "Need an actual, existing S3 bucket!" if @bucket.nil?
52
- end
31
+ module RightScraper::Scanners
53
32
 
54
- # Upon ending a scan for a cookbook, upload the cookbook
55
- # contents to S3.
56
- #
57
- # === Parameters
58
- # cookbook(RightScraper::Cookbook):: cookbook to scan
59
- def end(cookbook)
60
- path = File.join('Cooks', cookbook.resource_hash)
61
- unless @bucket.key(path).exists?
62
- contents = cookbook.manifest_json
63
- @bucket.put(path, contents)
64
- end
33
+ # Upload scanned files to an S3 bucket.
34
+ class CookbookS3Upload < ::RightScraper::Scanners::Base
35
+ # Create a new S3Upload. In addition to the options recognized
36
+ # by Scanner, this class recognizes <tt>:s3_key</tt>,
37
+ # <tt>:s3_secret</tt>, and <tt>:s3_bucket</tt> and requires all
38
+ # of those.
39
+ #
40
+ # === Options
41
+ # <tt>:s3_key</tt>:: Required. S3 access key.
42
+ # <tt>:s3_secret</tt>:: Required. S3 secret key.
43
+ # <tt>:s3_bucket</tt>:: Required. Bucket to upload cookbooks to.
44
+ #
45
+ # === Parameters
46
+ # options(Hash):: scanner options
47
+ def initialize(options={})
48
+ super
49
+ s3_key = options.fetch(:s3_key)
50
+ s3_secret = options.fetch(:s3_secret)
51
+ s3 = RightAws::S3.new(aws_access_key_id=s3_key,
52
+ aws_secret_access_key=s3_secret,
53
+ :logger => @logger)
54
+ @bucket = s3.bucket(options.fetch(:s3_bucket))
55
+ raise "Need an actual, existing S3 bucket!" if @bucket.nil?
56
+ end
57
+
58
+ # Upon ending a scan for a cookbook, upload the cookbook
59
+ # contents to S3.
60
+ #
61
+ # === Parameters
62
+ # cookbook(RightScraper::Cookbook):: cookbook to scan
63
+ def end(cookbook)
64
+ path = File.join('Cooks', cookbook.resource_hash)
65
+ unless @bucket.key(path).exists?
66
+ contents = cookbook.manifest_json
67
+ @bucket.put(path, contents)
65
68
  end
69
+ end
66
70
 
67
- # Upload a file during scanning.
68
- #
69
- # === Block
70
- # Return the data for this file. We use a block because it may
71
- # not always be necessary to read the data.
72
- #
73
- # === Parameters
74
- # relative_position(String):: relative pathname for file from root of cookbook
75
- def notice(relative_position)
76
- contents = yield
77
- name = Digest::MD5.hexdigest(contents)
78
- path = File.join('Files', name)
79
- unless @bucket.key(path).exists?
80
- @bucket.put(path, contents)
81
- end
71
+ # Upload a file during scanning.
72
+ #
73
+ # === Block
74
+ # Return the data for this file. We use a block because it may
75
+ # not always be necessary to read the data.
76
+ #
77
+ # === Parameters
78
+ # relative_position(String):: relative pathname for file from root of cookbook
79
+ def notice(relative_position)
80
+ contents = yield
81
+ name = Digest::MD5.hexdigest(contents)
82
+ path = File.join('Files', name)
83
+ unless @bucket.key(path).exists?
84
+ @bucket.put(path, contents)
82
85
  end
83
86
  end
84
87
  end