berkshelf-api 1.4.0 → 2.0.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.
- data/CHANGELOG.md +12 -0
- data/README.md +19 -4
- data/lib/berkshelf/api.rb +2 -1
- data/lib/berkshelf/api/cache_builder.rb +1 -1
- data/lib/berkshelf/api/cache_builder/worker/file_store.rb +1 -1
- data/lib/berkshelf/api/cache_builder/worker/supermarket.rb +47 -0
- data/lib/berkshelf/api/config.rb +1 -4
- data/lib/berkshelf/api/remote_cookbook.rb +17 -1
- data/lib/berkshelf/api/rspec.rb +1 -1
- data/lib/berkshelf/api/site_connector.rb +1 -1
- data/lib/berkshelf/api/site_connector/supermarket.rb +67 -0
- data/lib/berkshelf/api/version.rb +1 -1
- data/spec/unit/berkshelf/api/application_spec.rb +6 -4
- data/spec/unit/berkshelf/api/cache_builder/worker/chef_server_spec.rb +5 -4
- data/spec/unit/berkshelf/api/cache_builder/worker/file_store_spec.rb +5 -4
- data/spec/unit/berkshelf/api/cache_builder/worker/github_spec.rb +13 -17
- data/spec/unit/berkshelf/api/cache_builder/worker/supermarket_spec.rb +103 -0
- data/spec/unit/berkshelf/api/cache_builder/worker_spec.rb +1 -1
- data/spec/unit/berkshelf/api/cache_builder_spec.rb +12 -8
- data/spec/unit/berkshelf/api/cache_manager_spec.rb +16 -15
- data/spec/unit/berkshelf/api/config_spec.rb +3 -4
- data/spec/unit/berkshelf/api/dependency_cache_spec.rb +10 -6
- data/spec/unit/berkshelf/api/endpoint/v1_spec.rb +58 -12
- data/spec/unit/berkshelf/api/rack_app_spec.rb +5 -2
- data/spec/unit/berkshelf/api/rest_gateway_spec.rb +31 -10
- data/spec/unit/berkshelf/api/site_connector/supermarket_spec.rb +90 -0
- metadata +9 -25
- data/lib/berkshelf/api/cache_builder/worker/opscode.rb +0 -67
- data/lib/berkshelf/api/site_connector/opscode.rb +0 -181
- data/spec/unit/berkshelf/api/cache_builder/worker/opscode_spec.rb +0 -43
- data/spec/unit/berkshelf/api/site_connector/opscode_spec.rb +0 -85
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
# 2.0.0
|
2
|
+
|
3
|
+
* Enhancements
|
4
|
+
* Opscode Cache builder is now the Supermarket cache builder
|
5
|
+
|
6
|
+
* Bug fixes
|
7
|
+
* API server will now be configured to run as API user instead of root
|
8
|
+
* Fix issue where Berkshelf API user's home directory was not created
|
9
|
+
|
10
|
+
* Backwards incompatible changes
|
11
|
+
* The Opscode cache builder was removed - the old community site is no longer a valid endpoint to cache
|
12
|
+
|
1
13
|
# 1.4.0
|
2
14
|
|
3
15
|
* Enhancements
|
data/README.md
CHANGED
@@ -91,15 +91,30 @@ Ruby 1.9 mode is required on all interpreters.
|
|
91
91
|
|
92
92
|
You may configure the endpoints to index by editing the JSON configuration file (default: `#{ENV['HOME']}/.berkshelf/api-server/config.json`).
|
93
93
|
|
94
|
-
###
|
94
|
+
### Supermarket Community Site
|
95
95
|
|
96
|
-
|
96
|
+
Please note: this is unnecessary. You may point your Berksfile at "https://supermarket.getchef.com" instead.
|
97
|
+
|
98
|
+
```json
|
99
|
+
{
|
100
|
+
"endpoints": [
|
101
|
+
{ "type": "supermarket" }
|
102
|
+
]
|
103
|
+
}
|
104
|
+
```
|
105
|
+
|
106
|
+
### Supermarket "Behind the Firewall"
|
107
|
+
|
108
|
+
Please note: this is unnecessary. You may point your Berksfile at "https://your-supermarket-install.example.com" instead.
|
109
|
+
|
110
|
+
|
111
|
+
```json
|
97
112
|
{
|
98
113
|
"endpoints": [
|
99
114
|
{
|
100
|
-
"type": "
|
115
|
+
"type": "supermarket",
|
101
116
|
"options": {
|
102
|
-
"url": "
|
117
|
+
"url": "https://your-supermarket-install.example.com/"
|
103
118
|
}
|
104
119
|
}
|
105
120
|
]
|
data/lib/berkshelf/api.rb
CHANGED
@@ -2,13 +2,14 @@ require 'berkshelf/api/version'
|
|
2
2
|
require 'celluloid'
|
3
3
|
require 'hashie'
|
4
4
|
require 'ridley'
|
5
|
-
require 'faraday'
|
6
5
|
require 'json'
|
7
6
|
|
8
7
|
require_relative 'api/core_ext'
|
9
8
|
|
10
9
|
module Berkshelf
|
11
10
|
module API
|
11
|
+
USER_AGENT = "Berkshelf API v#{Berkshelf::API::VERSION}".freeze
|
12
|
+
|
12
13
|
require_relative 'api/errors'
|
13
14
|
require_relative 'api/logging'
|
14
15
|
require_relative 'api/mixin'
|
@@ -20,7 +20,7 @@ module Berkshelf::API
|
|
20
20
|
@building = false
|
21
21
|
|
22
22
|
Application.config.endpoints.each_with_index do |endpoint, index|
|
23
|
-
endpoint_options = endpoint.options.to_hash.deep_symbolize_keys
|
23
|
+
endpoint_options = (endpoint.options || {}).to_hash.deep_symbolize_keys
|
24
24
|
@worker_supervisor.supervise(CacheBuilder::Worker[endpoint.type], endpoint_options.merge(priority: index))
|
25
25
|
end
|
26
26
|
end
|
@@ -18,7 +18,7 @@ module Berkshelf::API
|
|
18
18
|
log.warn "dependencies is *STRONGLY FROWNED UPON* and potentially *DANGEROUS*."
|
19
19
|
log.warn ""
|
20
20
|
log.warn "Please consider setting up a release process for the cookbooks you wish to retrieve from this"
|
21
|
-
log.warn "
|
21
|
+
log.warn "filepath where the cookbook is uploaded into a Hosted Chef organization, an internal"
|
22
22
|
log.warn "Chef Server, or the community site, and then replace this endpoint with a chef_server endpoint."
|
23
23
|
super(options)
|
24
24
|
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Berkshelf::API
|
2
|
+
class CacheBuilder
|
3
|
+
module Worker
|
4
|
+
class Supermarket < Worker::Base
|
5
|
+
worker_type 'supermarket'
|
6
|
+
|
7
|
+
# @param [Hash] options
|
8
|
+
# see {API::SiteConnector::Supermarket.new} for options
|
9
|
+
def initialize(options = {})
|
10
|
+
@connection = Berkshelf::API::SiteConnector::Supermarket.new(options)
|
11
|
+
super
|
12
|
+
end
|
13
|
+
|
14
|
+
# @return [Array<RemoteCookbook>]
|
15
|
+
# The list of cookbooks this builder can find
|
16
|
+
def cookbooks
|
17
|
+
connection.universe.inject([]) do |list, (name, versions)|
|
18
|
+
versions.each do |version, info|
|
19
|
+
list << RemoteCookbook.new(name, version, self.class.worker_type, connection.api_url, priority, info)
|
20
|
+
end
|
21
|
+
|
22
|
+
list
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Return the metadata of the given RemoteCookbook. If the metadata could not be found or parsed
|
27
|
+
# nil is returned.
|
28
|
+
#
|
29
|
+
# @param [RemoteCookbook] remote
|
30
|
+
#
|
31
|
+
# @return [Ridley::Chef::Cookbook::Metadata, nil]
|
32
|
+
def metadata(remote)
|
33
|
+
Ridley::Chef::Cookbook::Metadata.from_hash(
|
34
|
+
'name' => remote.name,
|
35
|
+
'version' => remote.version,
|
36
|
+
'dependencies' => remote.info['dependencies'] || {},
|
37
|
+
)
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
attr_accessor :connection
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/berkshelf/api/config.rb
CHANGED
@@ -1,5 +1,21 @@
|
|
1
1
|
module Berkshelf::API
|
2
|
-
class RemoteCookbook
|
2
|
+
class RemoteCookbook
|
3
|
+
attr_accessor :name
|
4
|
+
attr_accessor :version
|
5
|
+
attr_accessor :location_type
|
6
|
+
attr_accessor :location_path
|
7
|
+
attr_accessor :priority
|
8
|
+
attr_accessor :info
|
9
|
+
|
10
|
+
def initialize(name, version, location_type, location_path, priority, info = {})
|
11
|
+
@name = name
|
12
|
+
@version = version
|
13
|
+
@location_type = location_type
|
14
|
+
@location_path = location_path
|
15
|
+
@priority = priority
|
16
|
+
@info = info
|
17
|
+
end
|
18
|
+
|
3
19
|
def hash
|
4
20
|
"#{name}|#{version}".hash
|
5
21
|
end
|
data/lib/berkshelf/api/rspec.rb
CHANGED
@@ -10,7 +10,7 @@ module Berkshelf::API
|
|
10
10
|
options[:platforms] ||= Hash.new
|
11
11
|
options[:dependencies] ||= Hash.new
|
12
12
|
cookbook = RemoteCookbook.new(name, version,
|
13
|
-
CacheBuilder::Worker::
|
13
|
+
CacheBuilder::Worker::Supermarket.worker_type, SiteConnector::Supermarket::V1_API)
|
14
14
|
metadata = Ridley::Chef::Cookbook::Metadata.new
|
15
15
|
options[:platforms].each { |name, version| metadata.supports(name, version) }
|
16
16
|
options[:dependencies].each { |name, constraint| metadata.depends(name, constraint) }
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
require 'retryable'
|
3
|
+
require 'archive'
|
4
|
+
require 'tempfile'
|
5
|
+
|
6
|
+
module OpenURI
|
7
|
+
class << self
|
8
|
+
#
|
9
|
+
# The is a bug in Ruby's implementation of OpenURI that prevents redirects
|
10
|
+
# from HTTP -> HTTPS. That should totally be a valid redirect, so we
|
11
|
+
# override that method here and call it a day.
|
12
|
+
#
|
13
|
+
# Note: this does NOT permit HTTPS -> HTTP redirects, as that would be a
|
14
|
+
# major security hole in the fabric of space-time!
|
15
|
+
#
|
16
|
+
def redirectable?(uri1, uri2)
|
17
|
+
a, b = uri1.scheme.downcase, uri2.scheme.downcase
|
18
|
+
|
19
|
+
a == b || (a == 'http' && b == 'https')
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
module Berkshelf::API
|
25
|
+
module SiteConnector
|
26
|
+
class Supermarket
|
27
|
+
include Berkshelf::API::Logging
|
28
|
+
|
29
|
+
# The default API server
|
30
|
+
V1_API = 'https://supermarket.getchef.com/'.freeze
|
31
|
+
|
32
|
+
# The timeout for the HTTP request
|
33
|
+
TIMEOUT = 15
|
34
|
+
|
35
|
+
# @return [String]
|
36
|
+
attr_reader :api_url
|
37
|
+
|
38
|
+
# @option options [String] :url ({V1_API})
|
39
|
+
# url of community site
|
40
|
+
def initialize(options = {})
|
41
|
+
@api_url = options[:url] || V1_API
|
42
|
+
end
|
43
|
+
|
44
|
+
# @return [Hash]
|
45
|
+
def universe
|
46
|
+
universe_url = URI.parse(File.join(api_url, 'universe.json')).to_s
|
47
|
+
|
48
|
+
log.debug "Loading universe from `#{universe_url}'..."
|
49
|
+
|
50
|
+
Timeout.timeout(TIMEOUT) do
|
51
|
+
response = open(universe_url, 'User-Agent' => USER_AGENT)
|
52
|
+
JSON.parse(response.read)
|
53
|
+
end
|
54
|
+
rescue JSON::ParserError => e
|
55
|
+
log.error "Failed to parse JSON: #{e}"
|
56
|
+
rescue Timeout::Error
|
57
|
+
log.error "Failed to get `#{universe_url}' in #{TIMEOUT} seconds!"
|
58
|
+
rescue SocketError,
|
59
|
+
Errno::ECONNREFUSED,
|
60
|
+
Errno::ECONNRESET,
|
61
|
+
Errno::ENETUNREACH,
|
62
|
+
OpenURI::HTTPError => e
|
63
|
+
log.error "Failed to get `#{universe_url}': #{e}"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -2,9 +2,11 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe Berkshelf::API::Application do
|
4
4
|
describe "ClassMethods" do
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
describe '.registry' do
|
6
|
+
it 'returns a Celluloid::Registry' do
|
7
|
+
expect(described_class.registry).to be_a(Celluloid::Registry)
|
8
|
+
end
|
9
|
+
end
|
8
10
|
|
9
11
|
describe "::configure" do
|
10
12
|
let(:options) { Hash.new }
|
@@ -22,7 +24,7 @@ describe Berkshelf::API::Application do
|
|
22
24
|
generated.save
|
23
25
|
configure
|
24
26
|
|
25
|
-
expect(described_class.config.endpoints).to
|
27
|
+
expect(described_class.config.endpoints.size).to eq(1)
|
26
28
|
end
|
27
29
|
|
28
30
|
context "if the file cannot be found or loaded" do
|
@@ -1,9 +1,10 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Berkshelf::API::CacheBuilder::Worker::ChefServer do
|
4
|
-
describe
|
5
|
-
|
6
|
-
|
4
|
+
describe '.worker_type' do
|
5
|
+
it 'is chef_server' do
|
6
|
+
expect(described_class.worker_type).to eq('chef_server')
|
7
|
+
end
|
7
8
|
end
|
8
9
|
|
9
10
|
subject do
|
@@ -22,7 +23,7 @@ describe Berkshelf::API::CacheBuilder::Worker::ChefServer do
|
|
22
23
|
end
|
23
24
|
|
24
25
|
it "returns an array containing an item for each cookbook on the server" do
|
25
|
-
expect(subject.cookbooks).to
|
26
|
+
expect(subject.cookbooks.size).to eq(4)
|
26
27
|
end
|
27
28
|
|
28
29
|
it "returns an array of RemoteCookbooks" do
|
@@ -1,9 +1,10 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Berkshelf::API::CacheBuilder::Worker::FileStore do
|
4
|
-
describe
|
5
|
-
|
6
|
-
|
4
|
+
describe '.worker_type' do
|
5
|
+
it 'is file_store' do
|
6
|
+
expect(described_class.worker_type).to eq('file_store')
|
7
|
+
end
|
7
8
|
end
|
8
9
|
|
9
10
|
subject do
|
@@ -14,7 +15,7 @@ describe Berkshelf::API::CacheBuilder::Worker::FileStore do
|
|
14
15
|
|
15
16
|
describe "#cookbooks" do
|
16
17
|
it "returns an array containing an item for each valid cookbook on the server" do
|
17
|
-
expect(subject.cookbooks).to
|
18
|
+
expect(subject.cookbooks.size).to eq(1)
|
18
19
|
end
|
19
20
|
|
20
21
|
it "returns an array of RemoteCookbooks" do
|
@@ -1,9 +1,10 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Berkshelf::API::CacheBuilder::Worker::Github do
|
4
|
-
describe
|
5
|
-
|
6
|
-
|
4
|
+
describe '.worker_type' do
|
5
|
+
it 'is github' do
|
6
|
+
expect(described_class.worker_type).to eq('github')
|
7
|
+
end
|
7
8
|
end
|
8
9
|
|
9
10
|
let(:connection) do
|
@@ -11,28 +12,23 @@ describe Berkshelf::API::CacheBuilder::Worker::Github do
|
|
11
12
|
end
|
12
13
|
|
13
14
|
let(:good_tag) do
|
14
|
-
|
15
|
-
tag.stub(:name) { 'v1.0.0' }
|
16
|
-
tag
|
15
|
+
double('good_tag', name: 'v1.0.0')
|
17
16
|
end
|
18
17
|
|
19
18
|
let(:bad_tag) do
|
20
|
-
|
21
|
-
tag.stub(:name) { 'beta2' }
|
22
|
-
tag
|
19
|
+
double('good_tag', name: 'beta2')
|
23
20
|
end
|
24
21
|
|
25
22
|
let :contents do
|
26
|
-
|
27
|
-
contents.stub(:content) { 'dmVyc2lvbiAiMS4wLjAi' }
|
28
|
-
contents
|
23
|
+
double('contents', content: 'dmVyc2lvbiAiMS4wLjAi')
|
29
24
|
end
|
30
25
|
|
31
26
|
let(:repo) do
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
27
|
+
double('repo',
|
28
|
+
name: 'apt',
|
29
|
+
full_name: 'opscode-cookbooks/apt',
|
30
|
+
html_url: 'https://github.com/opscode-cookbooks/apt',
|
31
|
+
)
|
36
32
|
end
|
37
33
|
|
38
34
|
let(:repos) do
|
@@ -55,7 +51,7 @@ describe Berkshelf::API::CacheBuilder::Worker::Github do
|
|
55
51
|
end
|
56
52
|
|
57
53
|
it "returns an array containing an item for each valid cookbook on the server" do
|
58
|
-
expect(subject.cookbooks).to
|
54
|
+
expect(subject.cookbooks.size).to eq(1)
|
59
55
|
end
|
60
56
|
|
61
57
|
it "returns an array of RemoteCookbooks" do
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Berkshelf
|
4
|
+
module API
|
5
|
+
describe CacheBuilder::Worker::Supermarket do
|
6
|
+
describe '.worker_type' do
|
7
|
+
it 'is supermarket' do
|
8
|
+
expect(described_class.worker_type).to eq('supermarket')
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
let(:location_path) { SiteConnector::Supermarket::V1_API }
|
13
|
+
let(:location_type) { described_class.worker_type }
|
14
|
+
let(:priority) { 1 }
|
15
|
+
|
16
|
+
let(:universe) do
|
17
|
+
{
|
18
|
+
'chicken' => {
|
19
|
+
'1.0' => {
|
20
|
+
'location_type' => 'supermarket',
|
21
|
+
'location_path' => location_path,
|
22
|
+
'download_url' => "#{location_path}/cookbooks/chicken/versions/1.0/download",
|
23
|
+
},
|
24
|
+
'2.0' => {
|
25
|
+
'location_type' => 'supermarket',
|
26
|
+
'location_path' => location_path,
|
27
|
+
'download_url' => "#{location_path}/cookbooks/chicken/versions/2.0/download",
|
28
|
+
}
|
29
|
+
},
|
30
|
+
'tuna' => {
|
31
|
+
'3.0.0' => {
|
32
|
+
'location_type' => 'supermarket',
|
33
|
+
'location_path' => location_path,
|
34
|
+
'download_url' => "#{location_path}/cookbooks/tuna/versions/3.0.0/download",
|
35
|
+
},
|
36
|
+
'3.0.1' => {
|
37
|
+
'location_type' => 'supermarket',
|
38
|
+
'location_path' => location_path,
|
39
|
+
'download_url' => "#{location_path}/cookbooks/tuna/versions/3.0.1/download",
|
40
|
+
}
|
41
|
+
}
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
let(:connection) do
|
46
|
+
double(SiteConnector::Supermarket,
|
47
|
+
universe: universe,
|
48
|
+
api_url: location_path,
|
49
|
+
)
|
50
|
+
end
|
51
|
+
|
52
|
+
before do
|
53
|
+
allow(subject.wrapped_object).to receive(:connection)
|
54
|
+
.and_return(connection)
|
55
|
+
end
|
56
|
+
|
57
|
+
subject do
|
58
|
+
CacheManager.start
|
59
|
+
described_class.new(priority: priority)
|
60
|
+
end
|
61
|
+
|
62
|
+
it_behaves_like "a human-readable string"
|
63
|
+
|
64
|
+
describe "#cookbooks" do
|
65
|
+
it "returns an array of RemoteCookbooks described by the server" do
|
66
|
+
expected = [
|
67
|
+
RemoteCookbook.new('chicken', '1.0', location_type, location_path, priority),
|
68
|
+
RemoteCookbook.new('chicken', '2.0', location_type, location_path, priority),
|
69
|
+
RemoteCookbook.new('tuna', '3.0.0', location_type, location_path, priority),
|
70
|
+
RemoteCookbook.new('tuna', '3.0.1', location_type, location_path, priority),
|
71
|
+
]
|
72
|
+
|
73
|
+
result = subject.cookbooks
|
74
|
+
expect(result).to be_a(Array)
|
75
|
+
|
76
|
+
expect(result[0].name).to eq('chicken')
|
77
|
+
expect(result[0].version).to eq('1.0')
|
78
|
+
expect(result[0].location_type).to eq(location_type)
|
79
|
+
expect(result[0].location_path).to eq(location_path)
|
80
|
+
expect(result[0].priority).to eq(priority)
|
81
|
+
|
82
|
+
expect(result[1].name).to eq('chicken')
|
83
|
+
expect(result[1].version).to eq('2.0')
|
84
|
+
expect(result[1].location_type).to eq(location_type)
|
85
|
+
expect(result[1].location_path).to eq(location_path)
|
86
|
+
expect(result[1].priority).to eq(priority)
|
87
|
+
|
88
|
+
expect(result[2].name).to eq('tuna')
|
89
|
+
expect(result[2].version).to eq('3.0.0')
|
90
|
+
expect(result[2].location_type).to eq(location_type)
|
91
|
+
expect(result[2].location_path).to eq(location_path)
|
92
|
+
expect(result[2].priority).to eq(priority)
|
93
|
+
|
94
|
+
expect(result[3].name).to eq('tuna')
|
95
|
+
expect(result[3].version).to eq('3.0.1')
|
96
|
+
expect(result[3].location_type).to eq(location_type)
|
97
|
+
expect(result[3].location_path).to eq(location_path)
|
98
|
+
expect(result[3].priority).to eq(priority)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|