berkshelf-api 1.4.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (31) hide show
  1. data/CHANGELOG.md +12 -0
  2. data/README.md +19 -4
  3. data/lib/berkshelf/api.rb +2 -1
  4. data/lib/berkshelf/api/cache_builder.rb +1 -1
  5. data/lib/berkshelf/api/cache_builder/worker/file_store.rb +1 -1
  6. data/lib/berkshelf/api/cache_builder/worker/supermarket.rb +47 -0
  7. data/lib/berkshelf/api/config.rb +1 -4
  8. data/lib/berkshelf/api/remote_cookbook.rb +17 -1
  9. data/lib/berkshelf/api/rspec.rb +1 -1
  10. data/lib/berkshelf/api/site_connector.rb +1 -1
  11. data/lib/berkshelf/api/site_connector/supermarket.rb +67 -0
  12. data/lib/berkshelf/api/version.rb +1 -1
  13. data/spec/unit/berkshelf/api/application_spec.rb +6 -4
  14. data/spec/unit/berkshelf/api/cache_builder/worker/chef_server_spec.rb +5 -4
  15. data/spec/unit/berkshelf/api/cache_builder/worker/file_store_spec.rb +5 -4
  16. data/spec/unit/berkshelf/api/cache_builder/worker/github_spec.rb +13 -17
  17. data/spec/unit/berkshelf/api/cache_builder/worker/supermarket_spec.rb +103 -0
  18. data/spec/unit/berkshelf/api/cache_builder/worker_spec.rb +1 -1
  19. data/spec/unit/berkshelf/api/cache_builder_spec.rb +12 -8
  20. data/spec/unit/berkshelf/api/cache_manager_spec.rb +16 -15
  21. data/spec/unit/berkshelf/api/config_spec.rb +3 -4
  22. data/spec/unit/berkshelf/api/dependency_cache_spec.rb +10 -6
  23. data/spec/unit/berkshelf/api/endpoint/v1_spec.rb +58 -12
  24. data/spec/unit/berkshelf/api/rack_app_spec.rb +5 -2
  25. data/spec/unit/berkshelf/api/rest_gateway_spec.rb +31 -10
  26. data/spec/unit/berkshelf/api/site_connector/supermarket_spec.rb +90 -0
  27. metadata +9 -25
  28. data/lib/berkshelf/api/cache_builder/worker/opscode.rb +0 -67
  29. data/lib/berkshelf/api/site_connector/opscode.rb +0 -181
  30. data/spec/unit/berkshelf/api/cache_builder/worker/opscode_spec.rb +0 -43
  31. data/spec/unit/berkshelf/api/site_connector/opscode_spec.rb +0 -85
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: berkshelf-api
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.0
4
+ version: 2.0.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2014-06-06 00:00:00.000000000 Z
13
+ date: 2014-07-10 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: ridley
@@ -130,22 +130,6 @@ dependencies:
130
130
  - - <
131
131
  - !ruby/object:Gem::Version
132
132
  version: 3.0.0
133
- - !ruby/object:Gem::Dependency
134
- name: faraday
135
- requirement: !ruby/object:Gem::Requirement
136
- none: false
137
- requirements:
138
- - - ~>
139
- - !ruby/object:Gem::Version
140
- version: 0.9.0
141
- type: :runtime
142
- prerelease: false
143
- version_requirements: !ruby/object:Gem::Requirement
144
- none: false
145
- requirements:
146
- - - ~>
147
- - !ruby/object:Gem::Version
148
- version: 0.9.0
149
133
  - !ruby/object:Gem::Dependency
150
134
  name: retryable
151
135
  requirement: !ruby/object:Gem::Requirement
@@ -242,7 +226,7 @@ files:
242
226
  - lib/berkshelf/api/cache_builder/worker/chef_server.rb
243
227
  - lib/berkshelf/api/cache_builder/worker/file_store.rb
244
228
  - lib/berkshelf/api/cache_builder/worker/github.rb
245
- - lib/berkshelf/api/cache_builder/worker/opscode.rb
229
+ - lib/berkshelf/api/cache_builder/worker/supermarket.rb
246
230
  - lib/berkshelf/api/cache_builder/worker.rb
247
231
  - lib/berkshelf/api/cache_builder.rb
248
232
  - lib/berkshelf/api/cache_manager.rb
@@ -263,7 +247,7 @@ files:
263
247
  - lib/berkshelf/api/rest_gateway.rb
264
248
  - lib/berkshelf/api/rspec/server.rb
265
249
  - lib/berkshelf/api/rspec.rb
266
- - lib/berkshelf/api/site_connector/opscode.rb
250
+ - lib/berkshelf/api/site_connector/supermarket.rb
267
251
  - lib/berkshelf/api/site_connector.rb
268
252
  - lib/berkshelf/api/srv_ctl.rb
269
253
  - lib/berkshelf/api/version.rb
@@ -278,7 +262,7 @@ files:
278
262
  - spec/unit/berkshelf/api/cache_builder/worker/chef_server_spec.rb
279
263
  - spec/unit/berkshelf/api/cache_builder/worker/file_store_spec.rb
280
264
  - spec/unit/berkshelf/api/cache_builder/worker/github_spec.rb
281
- - spec/unit/berkshelf/api/cache_builder/worker/opscode_spec.rb
265
+ - spec/unit/berkshelf/api/cache_builder/worker/supermarket_spec.rb
282
266
  - spec/unit/berkshelf/api/cache_builder/worker_spec.rb
283
267
  - spec/unit/berkshelf/api/cache_builder_spec.rb
284
268
  - spec/unit/berkshelf/api/cache_manager_spec.rb
@@ -289,7 +273,7 @@ files:
289
273
  - spec/unit/berkshelf/api/mixin/services_spec.rb
290
274
  - spec/unit/berkshelf/api/rack_app_spec.rb
291
275
  - spec/unit/berkshelf/api/rest_gateway_spec.rb
292
- - spec/unit/berkshelf/api/site_connector/opscode_spec.rb
276
+ - spec/unit/berkshelf/api/site_connector/supermarket_spec.rb
293
277
  - spec/unit/berkshelf/api/srv_ctl_spec.rb
294
278
  - bin/berks-api
295
279
  homepage: https://github.com/berkshelf/berkshelf-api
@@ -313,7 +297,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
313
297
  version: '0'
314
298
  segments:
315
299
  - 0
316
- hash: 80644279196753361
300
+ hash: -144777955995008759
317
301
  requirements: []
318
302
  rubyforge_project:
319
303
  rubygems_version: 1.8.23
@@ -331,7 +315,7 @@ test_files:
331
315
  - spec/unit/berkshelf/api/cache_builder/worker/chef_server_spec.rb
332
316
  - spec/unit/berkshelf/api/cache_builder/worker/file_store_spec.rb
333
317
  - spec/unit/berkshelf/api/cache_builder/worker/github_spec.rb
334
- - spec/unit/berkshelf/api/cache_builder/worker/opscode_spec.rb
318
+ - spec/unit/berkshelf/api/cache_builder/worker/supermarket_spec.rb
335
319
  - spec/unit/berkshelf/api/cache_builder/worker_spec.rb
336
320
  - spec/unit/berkshelf/api/cache_builder_spec.rb
337
321
  - spec/unit/berkshelf/api/cache_manager_spec.rb
@@ -342,6 +326,6 @@ test_files:
342
326
  - spec/unit/berkshelf/api/mixin/services_spec.rb
343
327
  - spec/unit/berkshelf/api/rack_app_spec.rb
344
328
  - spec/unit/berkshelf/api/rest_gateway_spec.rb
345
- - spec/unit/berkshelf/api/site_connector/opscode_spec.rb
329
+ - spec/unit/berkshelf/api/site_connector/supermarket_spec.rb
346
330
  - spec/unit/berkshelf/api/srv_ctl_spec.rb
347
331
  has_rdoc:
@@ -1,67 +0,0 @@
1
- module Berkshelf::API
2
- class CacheBuilder
3
- module Worker
4
- class Opscode < Worker::Base
5
- worker_type "opscode"
6
-
7
- finalizer :finalize_callback
8
-
9
- # @param [Hash] options
10
- # see {API::SiteConnector::Opscode.new} for options
11
- def initialize(options = {})
12
- @connection = Berkshelf::API::SiteConnector::Opscode.pool_link(size: 25, args: [ options ])
13
- super
14
- end
15
-
16
- # @return [Array<RemoteCookbook>]
17
- # The list of cookbooks this builder can find
18
- def cookbooks
19
- [].tap do |cookbook_versions|
20
- connection.cookbooks.collect do |cookbook|
21
- [ cookbook, connection.future(:versions, cookbook) ]
22
- end.each do |cookbook, versions|
23
- versions.value.each do |version|
24
- cookbook_versions << RemoteCookbook.new(cookbook, version, self.class.worker_type, @connection.api_uri, priority)
25
- end
26
- end
27
- end
28
- end
29
-
30
- # Return the metadata of the given RemoteCookbook. If the metadata could not be found or parsed
31
- # nil is returned.
32
- #
33
- # @param [RemoteCookbook] remote
34
- #
35
- # @return [Ridley::Chef::Cookbook::Metadata, nil]
36
- def metadata(remote)
37
- Dir.mktmpdir('metadata') do |destination|
38
- if connection.download(remote.name, remote.version, destination)
39
- load_metadata(destination, remote.name)
40
- end
41
- end
42
- end
43
-
44
- private
45
-
46
- attr_accessor :connection
47
-
48
- def finalize_callback
49
- connection.terminate if connection && connection.alive?
50
- end
51
-
52
- def load_metadata(directory, cookbook)
53
- # The community site does not enforce the name of the cookbook contained in the archive
54
- # downloaded and extracted. This will just find the first metadata.json and load it.
55
- file = Dir["#{directory}/**/*/metadata.json"].first
56
- return nil if file.nil?
57
-
58
- metadata = File.read(file)
59
- Ridley::Chef::Cookbook::Metadata.from_json(metadata)
60
- rescue JSON::ParserError => ex
61
- log.warn "Error loading metadata for #{cookbook} from: #{file}"
62
- abort MetadataLoadError.new(ex)
63
- end
64
- end
65
- end
66
- end
67
- end
@@ -1,181 +0,0 @@
1
- require 'open-uri'
2
- require 'retryable'
3
- require 'archive'
4
- require 'tempfile'
5
-
6
- module Berkshelf::API
7
- module SiteConnector
8
- class Opscode
9
- class << self
10
- # @param [String] version
11
- #
12
- # @return [String]
13
- def uri_escape_version(version)
14
- version.to_s.gsub('.', '_')
15
- end
16
-
17
- # @param [String] uri
18
- #
19
- # @return [String]
20
- def version_from_uri(uri)
21
- File.basename(uri.to_s).gsub('_', '.')
22
- end
23
- end
24
-
25
- include Celluloid
26
- include Berkshelf::API::Logging
27
-
28
- V1_API = 'http://cookbooks.opscode.com/api/v1'.freeze
29
-
30
- # @return [String]
31
- attr_reader :api_uri
32
- # @return [Integer]
33
- # how many retries to attempt on HTTP requests
34
- attr_reader :retries
35
- # @return [Float]
36
- # time to wait between retries
37
- attr_reader :retry_interval
38
-
39
- # @option options [String] :url ({V1_API})
40
- # url of community site
41
- # @option options [Integer] :retries (5)
42
- # how many download retry attempts to make
43
- # @option options [Float] :retry_interval (0.5)
44
- # how long to wait before retrying again
45
- def initialize(options = {})
46
- options = { url: V1_API, retries: 5, retry_interval: 0.5 }.merge(options)
47
- @api_uri = options[:url]
48
-
49
- @connection = Faraday.new(@api_uri) do |c|
50
- c.response :parse_json
51
- c.use Faraday::Adapter::NetHttp
52
- end
53
- end
54
-
55
- # @return [Array<String>]
56
- # A list of cookbook names available on the server
57
- def cookbooks
58
- start = 0
59
- count = connection.get("cookbooks").body["total"]
60
- cookbooks = Array.new
61
-
62
- while count > 0
63
- req = connection.get("cookbooks?start=#{start}&items=#{count}")
64
- chunk = req.body["items"]
65
- if chunk
66
- cookbooks += chunk
67
- start += 100
68
- count -= 100
69
- else
70
- log.warn "Didn't get any cookbooks - #{req.body}"
71
- end
72
- end
73
-
74
- cookbooks.map { |cb| cb["cookbook_name"] }
75
- end
76
-
77
- # @param [String] cookbook
78
- # the name of the cookbook to find version for
79
- #
80
- # @return [Array<String>]
81
- # A list of versions of this cookbook available on the server
82
- def versions(cookbook)
83
- response = connection.get("cookbooks/#{cookbook}")
84
-
85
- case response.status
86
- when (200..299)
87
- response.body['versions'].collect do |version_uri|
88
- self.class.version_from_uri(version_uri)
89
- end
90
- else
91
- Array.new
92
- end
93
- end
94
-
95
- # Download the cookbook with the given name and version to the destination. The directory
96
- # containing the extracted contents will be returned on success. On failure, nil will
97
- # be returned.
98
- #
99
- # @param [String] cookbook
100
- # The name of the cookbook to download
101
- # @param [String] version
102
- # The version of the cookbook to download
103
- # @param [String] destination
104
- # The directory to download the cookbook to
105
- #
106
- # @return [String, nil]
107
- def download(name, version, destination = Dir.mktmpdir)
108
- log.debug "Downloading #{name}(#{version})"
109
- if uri = download_uri(name, version)
110
- begin
111
- archive = stream(uri)
112
- Archive.extract(archive.path, destination)
113
- destination
114
- rescue => ex
115
- log.warn "Error downloading/extracting #{name} (#{version}): #{ex}"
116
- nil
117
- ensure
118
- archive.unlink unless archive.nil?
119
- end
120
- end
121
- end
122
-
123
- # Return the location where a cookbook of the given name and version can be downloaded from
124
- #
125
- # @param [String] cookbook
126
- # The name of the cookbook
127
- # @param [String] version
128
- # The version of the cookbook
129
- #
130
- # @return [String, nil]
131
- def download_uri(name, version)
132
- unless cookbook = find(name, version)
133
- return nil
134
- end
135
- cookbook[:file]
136
- end
137
-
138
- # @param [String] cookbook
139
- # The name of the cookbook to retrieve
140
- # @param [String] version
141
- # The version of the cookbook to retrieve
142
- #
143
- # @return [Hashie::Mash, nil]
144
- def find(name, version)
145
- response = connection.get("cookbooks/#{name}/versions/#{self.class.uri_escape_version(version)}")
146
-
147
- case response.status
148
- when (200..299)
149
- response.body
150
- else
151
- nil
152
- end
153
- end
154
-
155
- # Stream the response body of a remote URL to a file on the local file system
156
- #
157
- # @param [String] target
158
- # a URL to stream the response body from
159
- #
160
- # @return [Tempfile]
161
- def stream(target)
162
- local = Tempfile.new('opscode-site-stream')
163
- local.binmode
164
-
165
- retryable(tries: retries, on: OpenURI::HTTPError, sleep: retry_interval) do
166
- open(target, 'rb', connection.headers) do |remote|
167
- local.write(remote.read)
168
- end
169
- end
170
-
171
- local
172
- ensure
173
- local.close(false) unless local.nil?
174
- end
175
-
176
- private
177
-
178
- attr_reader :connection
179
- end
180
- end
181
- end
@@ -1,43 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Berkshelf::API::CacheBuilder::Worker::Opscode do
4
- describe "ClassMethods" do
5
- subject { described_class }
6
- its(:worker_type) { should eql("opscode") }
7
- end
8
-
9
- let(:cookbooks) { ["chicken", "tuna"] }
10
- let(:chicken_versions) { ["1.0", "2.0"] }
11
- let(:tuna_versions) { ["3.0.0", "3.0.1"] }
12
- let(:connection) do
13
- connection = double('connection')
14
- connection.stub(:cookbooks).and_return(cookbooks)
15
- connection
16
- end
17
-
18
- subject do
19
- Berkshelf::API::CacheManager.start
20
- described_class.new
21
- end
22
-
23
- it_behaves_like "a human-readable string"
24
-
25
- describe "#cookbooks" do
26
- let(:location_type) { described_class.worker_type }
27
- let(:location_path) { Berkshelf::API::SiteConnector::Opscode::V1_API}
28
-
29
- it "returns an array of RemoteCookbooks described by the server" do
30
- expected_value = [
31
- Berkshelf::API::RemoteCookbook.new("chicken", "1.0", location_type, location_path),
32
- Berkshelf::API::RemoteCookbook.new("chicken", "2.0", location_type, location_path),
33
- Berkshelf::API::RemoteCookbook.new("tuna", "3.0.0", location_type, location_path),
34
- Berkshelf::API::RemoteCookbook.new("tuna", "3.0.1", location_type, location_path)
35
- ]
36
-
37
- connection.should_receive(:future).with(:versions, "chicken").and_return(double(value: chicken_versions))
38
- connection.should_receive(:future).with(:versions, "tuna").and_return(double(value: tuna_versions))
39
- subject.should_receive(:connection).at_least(1).times.and_return(connection)
40
- expect(subject.cookbooks).to eql(expected_value)
41
- end
42
- end
43
- end
@@ -1,85 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Berkshelf::API::SiteConnector::Opscode do
4
- let(:connection) { double("connection") }
5
- let(:total_response) { double("total", status: 200, body: { "total" => 10 } ) }
6
- let(:cookbooks_response) do
7
- double("cookbooks", status: 200, body: {
8
- "items"=> [
9
- {"cookbook_name" => "chicken"},
10
- {"cookbook_name" => "tuna"}
11
- ]})
12
- end
13
- let(:chicken_versions_response) do
14
- double("chicken_versions", status: 200, body: {
15
- "versions" => [
16
- "http://www.example.com/api/v1/cookbooks/chicken/versions/1_0",
17
- "http://www.example.com/api/v1/cookbooks/chicken/versions/2_0"
18
- ]})
19
- end
20
-
21
- subject { described_class.new }
22
-
23
- describe "#cookbooks" do
24
- it "should fetch all the cookbooks and return a list of their names" do
25
- connection.should_receive(:get).
26
- with("cookbooks").
27
- and_return(total_response)
28
-
29
- connection.should_receive(:get).
30
- with("cookbooks?start=0&items=10").
31
- and_return(cookbooks_response)
32
-
33
- subject.should_receive(:connection).at_least(1).times.and_return(connection)
34
- expect(subject.cookbooks).to eql(["chicken", "tuna"])
35
- end
36
- end
37
-
38
- describe "#versions" do
39
- it "should call the server for the cookbook provied and return a list of available version number" do
40
- connection.should_receive(:get).
41
- with("cookbooks/chicken").
42
- and_return(chicken_versions_response)
43
-
44
- subject.should_receive(:connection).at_least(1).times.and_return(connection)
45
- expect(subject.versions("chicken")).to eql(["1.0", "2.0"])
46
- end
47
- end
48
-
49
- describe "#find" do
50
- let(:name) { "nginx" }
51
- let(:version) { "1.4.0" }
52
- let(:result) { subject.find(name, version) }
53
-
54
- it "returns the cookbook and version information" do
55
- expect(result.cookbook).to eq('http://cookbooks.opscode.com/api/v1/cookbooks/nginx')
56
- expect(result.version).to eq('1.4.0')
57
- end
58
-
59
- context "when the cookbook is not found" do
60
- let(:name) { "not_a_real_cookbook_that_anyone_should_ever_make" }
61
-
62
- it "returns nil" do
63
- expect(result).to be_nil
64
- end
65
- end
66
- end
67
-
68
- describe "#download" do
69
- let(:name) { "chicken" }
70
- let(:version) { "1.0.0" }
71
- let(:destination) { "location" }
72
-
73
- it "should download then ungzip/tar the cookbook" do
74
- response = { file: "http://file" }
75
- tempfile = double('tempfile', path: '/some/path', unlink: nil)
76
-
77
- subject.should_receive(:find).with(name, version).and_return(response)
78
- subject.should_receive(:stream).with("http://file").and_return(tempfile)
79
- Archive.should_receive(:extract).with(tempfile.path, destination)
80
-
81
- subject.download(name, version, destination)
82
- end
83
- end
84
- end
85
-