berkshelf-api 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.ruby-version +1 -0
- data/.travis.yml +17 -0
- data/CONTRIBUTING.md +33 -0
- data/Gemfile +40 -0
- data/Guardfile +20 -0
- data/LICENSE +201 -0
- data/README.md +37 -0
- data/Thorfile +39 -0
- data/berkshelf-api.gemspec +35 -0
- data/bin/berks-api +5 -0
- data/lib/berkshelf-api.rb +1 -0
- data/lib/berkshelf/api.rb +25 -0
- data/lib/berkshelf/api/application.rb +114 -0
- data/lib/berkshelf/api/cache_builder.rb +60 -0
- data/lib/berkshelf/api/cache_builder/worker.rb +116 -0
- data/lib/berkshelf/api/cache_builder/worker/chef_server.rb +46 -0
- data/lib/berkshelf/api/cache_builder/worker/opscode.rb +59 -0
- data/lib/berkshelf/api/cache_manager.rb +96 -0
- data/lib/berkshelf/api/config.rb +23 -0
- data/lib/berkshelf/api/cucumber.rb +11 -0
- data/lib/berkshelf/api/dependency_cache.rb +123 -0
- data/lib/berkshelf/api/endpoint.rb +17 -0
- data/lib/berkshelf/api/endpoint/v1.rb +19 -0
- data/lib/berkshelf/api/errors.rb +8 -0
- data/lib/berkshelf/api/generic_server.rb +50 -0
- data/lib/berkshelf/api/logging.rb +37 -0
- data/lib/berkshelf/api/mixin.rb +7 -0
- data/lib/berkshelf/api/mixin/services.rb +48 -0
- data/lib/berkshelf/api/rack_app.rb +5 -0
- data/lib/berkshelf/api/remote_cookbook.rb +3 -0
- data/lib/berkshelf/api/rest_gateway.rb +62 -0
- data/lib/berkshelf/api/rspec.rb +20 -0
- data/lib/berkshelf/api/rspec/server.rb +29 -0
- data/lib/berkshelf/api/site_connector.rb +7 -0
- data/lib/berkshelf/api/site_connector/opscode.rb +162 -0
- data/lib/berkshelf/api/srv_ctl.rb +63 -0
- data/lib/berkshelf/api/version.rb +5 -0
- data/spec/fixtures/reset.pem +27 -0
- data/spec/spec_helper.rb +53 -0
- data/spec/support/actor_mocking.rb +7 -0
- data/spec/support/chef_server.rb +73 -0
- data/spec/unit/berkshelf/api/application_spec.rb +24 -0
- data/spec/unit/berkshelf/api/cache_builder/worker/chef_server_spec.rb +59 -0
- data/spec/unit/berkshelf/api/cache_builder/worker/opscode_spec.rb +41 -0
- data/spec/unit/berkshelf/api/cache_builder/worker_spec.rb +80 -0
- data/spec/unit/berkshelf/api/cache_builder_spec.rb +37 -0
- data/spec/unit/berkshelf/api/cache_manager_spec.rb +123 -0
- data/spec/unit/berkshelf/api/config_spec.rb +24 -0
- data/spec/unit/berkshelf/api/dependency_cache_spec.rb +109 -0
- data/spec/unit/berkshelf/api/endpoint/v1_spec.rb +18 -0
- data/spec/unit/berkshelf/api/logging_spec.rb +28 -0
- data/spec/unit/berkshelf/api/mixin/services_spec.rb +68 -0
- data/spec/unit/berkshelf/api/rack_app_spec.rb +6 -0
- data/spec/unit/berkshelf/api/rest_gateway_spec.rb +26 -0
- data/spec/unit/berkshelf/api/site_connector/opscode_spec.rb +85 -0
- data/spec/unit/berkshelf/api/srv_ctl_spec.rb +56 -0
- metadata +293 -0
@@ -0,0 +1,29 @@
|
|
1
|
+
module Berkshelf::API::RSpec
|
2
|
+
module Server
|
3
|
+
class << self
|
4
|
+
include Berkshelf::API::Mixin::Services
|
5
|
+
|
6
|
+
def clear_cache
|
7
|
+
cache_manager.clear
|
8
|
+
end
|
9
|
+
|
10
|
+
def instance
|
11
|
+
Berkshelf::API::Application.instance
|
12
|
+
end
|
13
|
+
|
14
|
+
def running?
|
15
|
+
Berkshelf::API::Application.running?
|
16
|
+
end
|
17
|
+
|
18
|
+
def start(options = {})
|
19
|
+
options = options.reverse_merge(port: 26210, log_location: "/dev/null", endpoints: [])
|
20
|
+
Berkshelf::API::Application.config.endpoints = options[:endpoints]
|
21
|
+
Berkshelf::API::Application.run!(options) unless running?
|
22
|
+
end
|
23
|
+
|
24
|
+
def stop
|
25
|
+
Berkshelf::API::Application.shutdown
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,162 @@
|
|
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
|
+
# @param [Faraday::Connection] connection
|
40
|
+
# Optional parameter for setting the connection object
|
41
|
+
# This should only be set manually for testing
|
42
|
+
def initialize(uri = V1_API, options = {})
|
43
|
+
options = { retries: 5, retry_interval: 0.5 }.merge(options)
|
44
|
+
@api_uri = uri
|
45
|
+
|
46
|
+
@connection = Faraday.new(uri) do |c|
|
47
|
+
c.response :parse_json
|
48
|
+
c.use Faraday::Adapter::NetHttp
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# @return [Array<String>]
|
53
|
+
# A list of cookbook names available on the server
|
54
|
+
def cookbooks
|
55
|
+
start = 0
|
56
|
+
count = connection.get("cookbooks").body["total"]
|
57
|
+
cookbooks = Array.new
|
58
|
+
|
59
|
+
while count > 0
|
60
|
+
cookbooks += connection.get("cookbooks?start=#{start}&items=#{count}").body["items"]
|
61
|
+
start += 100
|
62
|
+
count -= 100
|
63
|
+
end
|
64
|
+
|
65
|
+
cookbooks.map { |cb| cb["cookbook_name"] }
|
66
|
+
end
|
67
|
+
|
68
|
+
# @param [String] cookbook
|
69
|
+
# the name of the cookbook to find version for
|
70
|
+
#
|
71
|
+
# @return [Array<String>]
|
72
|
+
# A list of versions of this cookbook available on the server
|
73
|
+
def versions(cookbook)
|
74
|
+
response = connection.get("cookbooks/#{cookbook}")
|
75
|
+
|
76
|
+
case response.status
|
77
|
+
when (200..299)
|
78
|
+
response.body['versions'].collect do |version_uri|
|
79
|
+
self.class.version_from_uri(version_uri)
|
80
|
+
end
|
81
|
+
else
|
82
|
+
Array.new
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# @param [String] cookbook
|
87
|
+
# The name of the cookbook to download
|
88
|
+
# @param [String] version
|
89
|
+
# The version of the cookbook to download
|
90
|
+
# @param [String] destination
|
91
|
+
# The directory to download the cookbook to
|
92
|
+
#
|
93
|
+
# @return [String, nil]
|
94
|
+
def download(name, version, destination = Dir.mktmpdir)
|
95
|
+
log.info "downloading #{name}(#{version})"
|
96
|
+
if uri = download_uri(name, version)
|
97
|
+
archive = stream(uri)
|
98
|
+
Archive.extract(archive.path, destination)
|
99
|
+
end
|
100
|
+
ensure
|
101
|
+
archive.unlink unless archive.nil?
|
102
|
+
end
|
103
|
+
|
104
|
+
# Return the location where a cookbook of the given name and version can be downloaded from
|
105
|
+
#
|
106
|
+
# @param [String] cookbook
|
107
|
+
# The name of the cookbook
|
108
|
+
# @param [String] version
|
109
|
+
# The version of the cookbook
|
110
|
+
#
|
111
|
+
# @return [String, nil]
|
112
|
+
def download_uri(name, version)
|
113
|
+
unless cookbook = find(name, version)
|
114
|
+
return nil
|
115
|
+
end
|
116
|
+
cookbook[:file]
|
117
|
+
end
|
118
|
+
|
119
|
+
# @param [String] cookbook
|
120
|
+
# The name of the cookbook to retrieve
|
121
|
+
# @param [String] version
|
122
|
+
# The version of the cookbook to retrieve
|
123
|
+
#
|
124
|
+
# @return [Hashie::Mash, nil]
|
125
|
+
def find(name, version)
|
126
|
+
response = connection.get("cookbooks/#{name}/versions/#{self.class.uri_escape_version(version)}")
|
127
|
+
|
128
|
+
case response.status
|
129
|
+
when (200..299)
|
130
|
+
response.body
|
131
|
+
else
|
132
|
+
nil
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# Stream the response body of a remote URL to a file on the local file system
|
137
|
+
#
|
138
|
+
# @param [String] target
|
139
|
+
# a URL to stream the response body from
|
140
|
+
#
|
141
|
+
# @return [Tempfile]
|
142
|
+
def stream(target)
|
143
|
+
local = Tempfile.new('opscode-site-stream')
|
144
|
+
local.binmode
|
145
|
+
|
146
|
+
retryable(tries: retries, on: OpenURI::HTTPError, sleep: retry_interval) do
|
147
|
+
open(target, 'rb', connection.headers) do |remote|
|
148
|
+
local.write(remote.read)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
local
|
153
|
+
ensure
|
154
|
+
local.close(false) unless local.nil?
|
155
|
+
end
|
156
|
+
|
157
|
+
private
|
158
|
+
|
159
|
+
attr_reader :connection
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require 'buff/extensions'
|
3
|
+
|
4
|
+
module Berkshelf
|
5
|
+
module API
|
6
|
+
class SrvCtl
|
7
|
+
class << self
|
8
|
+
# @param [Array] args
|
9
|
+
#
|
10
|
+
# @return [Hash]
|
11
|
+
def parse_options(args, filename)
|
12
|
+
options = Hash.new
|
13
|
+
|
14
|
+
OptionParser.new("Usage: #{filename} [options]") do |opts|
|
15
|
+
opts.on("-p", "--port PORT", Integer, "set the listening port") do |v|
|
16
|
+
options[:port] = v
|
17
|
+
end
|
18
|
+
|
19
|
+
opts.on("-v", "--verbose", "run with verbose output") do
|
20
|
+
options[:log_level] = "INFO"
|
21
|
+
end
|
22
|
+
|
23
|
+
opts.on("-d", "--debug", "run with debug output") do
|
24
|
+
options[:log_level] = "DEBUG"
|
25
|
+
end
|
26
|
+
|
27
|
+
opts.on("-q", "--quiet", "silence output") do
|
28
|
+
options[:log_location] = '/dev/null'
|
29
|
+
end
|
30
|
+
|
31
|
+
opts.on_tail("-h", "--help", "show this message") do
|
32
|
+
puts opts
|
33
|
+
exit
|
34
|
+
end
|
35
|
+
end.parse!(args)
|
36
|
+
|
37
|
+
options.symbolize_keys
|
38
|
+
end
|
39
|
+
|
40
|
+
# @param [Array] args
|
41
|
+
# @param [String] filename
|
42
|
+
def run(args, filename)
|
43
|
+
options = parse_options(args, filename)
|
44
|
+
new(options).start
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
attr_reader :options
|
49
|
+
|
50
|
+
# @param [Hash] options
|
51
|
+
# @see {Berkshelf::API::Application.run} for the list of valid options
|
52
|
+
def initialize(options = {})
|
53
|
+
@options = options
|
54
|
+
@options[:eager_build] = true
|
55
|
+
end
|
56
|
+
|
57
|
+
def start
|
58
|
+
require 'berkshelf/api'
|
59
|
+
Berkshelf::API::Application.run(options)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
-----BEGIN RSA PRIVATE KEY-----
|
2
|
+
MIIEpQIBAAKCAQEAyyUMqrTh1IzKOyE0fvXEWC7m0AdMI8/dr9JJMUKtK9vhhP0w
|
3
|
+
rm6m95GoybFM2IRryukFsAxpcir3M1ungTU3Smq4MshhMJ7H9FbvZVfQoknTbCsR
|
4
|
+
w6scg2fBepxT2+fcGRufr8nAh92M3uUkN9bMMTAkt18D4br6035YvdmvHDJERxYq
|
5
|
+
ByA/720AdI9VNSIvw+x8oqsIkXLEdF6dgT9MpG5iWZT66pbFsnNZpRrd4/bFNWBY
|
6
|
+
+13aOqdmjiTL08/EdgQFKMT5qimpos1TuQhA7mwInOjQgzVu9uCDkMiYejaLbUz0
|
7
|
+
lGyS8y4uxu6z2hA900Jg/z+JJuXymH5QAX3GZQIDAQABAoIBAQCtFXkwbYPI1Nht
|
8
|
+
/wG6du5+8B9K+hy+mppY9wPTy+q+Zs9Ev3Fd/fuXDm1QxBckl9c8AMUO1dR2KPOM
|
9
|
+
t7gFl/DvH/SnmCFvCqp1nijFIUgrLlnMXPn6zG0z7RBlxpKQ2IGohufNIEpBuNwR
|
10
|
+
Ag2U4hgChPGTp4ooJ2cVEh7MS5AupYPDbC62dWEdW68aRTWhh2BCGAWBb6s16yl9
|
11
|
+
aZ7+OcxW2eeRJVbRfLkLQEDutJZi5TfOEn5QPc86ZgxcCmnvwulnpnhpz6QCkgQt
|
12
|
+
OP/+KRqDhWSDVCFREVT30fUIj1EWvK7NFWASZQxueZStuIvMEKeFebYfrbHxRFzJ
|
13
|
+
UmaxJnWVAoGBAPbKLpeky6ClccBaHHrCgjzakoDfGgyNKDQ9g753lJxB8nn7d9X4
|
14
|
+
HQpkWpfqAGFRZp1hI2H+VxyUXLh2Ob5OUeTm0OZJll35vycOaQEtfgIScXTcvzn0
|
15
|
+
16J9eX2YY4wIHEEMh85nKk8BEGgiNP5nuEviHocCeYXoi/Zq3+qj6v63AoGBANK5
|
16
|
+
4nyi6LBQFs1CUc7Sh7vjtOE3ia7KeRmOr7gS6QhS3iK3Oa8FzBLJ6ETjN2a9Bw8N
|
17
|
+
cF7I/+cr4s7DUJjxdb53D/J6TVSYORNNCUVnpF/uB2LqqdXDYmpO0PvFkXFoYTnJ
|
18
|
+
kaLAN8uCoLKr6JH9tq3DfXIfDIHiZ+BOIvI070fDAoGBAMDyzEDFmGruTyRLj66u
|
19
|
+
+rJnVVmqlKwxhLhrS+CTj74nlVOnt0a0KMhiM65IRqnPwcHUG5zXBPaUTHXwAS93
|
20
|
+
/nFPwQ37hLPOupPnoVNJZRZrowbyPBQtCJbDMURv64ylHqoBCQDoCd0hANnZvMMX
|
21
|
+
BrFVhfaaibaXXS542r6SD/27AoGAECadHE5kJTdOOBcwK/jo3Fa8g1J9Y/8yvum3
|
22
|
+
wBT69V9clS6T5j08geglvDnqAh7UzquKBEnFi1NKw+wmXkKLcrivaTdEfApavYb3
|
23
|
+
AfHKoGue907jC3Y5Mcquq81ds2J7qTEwz1eKLzfo1yjj32ShvrmwALIuhDn1GjUC
|
24
|
+
6qtx938CgYEApEqvu0nocR1jmVVlLe5uKQBj949dh6NGq0R5Lztz6xufaTYzMC3d
|
25
|
+
AZG9XPPjRqSLs+ylSXJpwHEwoeyLFDaJcO+GgW1/ut4MC2HppOx6aImwDdXMHUWR
|
26
|
+
KYGIFF4AU/IYoBcanAm4s078EH/Oz01B2c7tR2TqabisPgLYe7PXSCw=
|
27
|
+
-----END RSA PRIVATE KEY-----
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
require 'rspec'
|
4
|
+
require 'spork'
|
5
|
+
require 'rack/test'
|
6
|
+
|
7
|
+
Spork.prefork do
|
8
|
+
Dir[File.join(File.expand_path("../../spec/support/**/*.rb", __FILE__))].each { |f| require f }
|
9
|
+
|
10
|
+
RSpec.configure do |config|
|
11
|
+
config.include Berkshelf::RSpec::ChefServer
|
12
|
+
|
13
|
+
config.expect_with :rspec do |c|
|
14
|
+
c.syntax = :expect
|
15
|
+
end
|
16
|
+
|
17
|
+
config.mock_with :rspec
|
18
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
19
|
+
config.filter_run focus: true
|
20
|
+
config.run_all_when_everything_filtered = true
|
21
|
+
|
22
|
+
config.before(:suite) { Berkshelf::RSpec::ChefServer.start }
|
23
|
+
config.before(:all) { Berkshelf::API::Logging.init(location: '/dev/null') }
|
24
|
+
|
25
|
+
config.before do
|
26
|
+
Celluloid.shutdown
|
27
|
+
Celluloid.boot
|
28
|
+
Berkshelf::API::CacheManager.cache_file = tmp_path.join('cerch').to_s
|
29
|
+
clean_tmp_path
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def app_root_path
|
34
|
+
Pathname.new(File.expand_path('../../', __FILE__))
|
35
|
+
end
|
36
|
+
|
37
|
+
def tmp_path
|
38
|
+
app_root_path.join('spec/tmp')
|
39
|
+
end
|
40
|
+
|
41
|
+
def fixtures_path
|
42
|
+
app_root_path.join('spec/fixtures')
|
43
|
+
end
|
44
|
+
|
45
|
+
def clean_tmp_path
|
46
|
+
FileUtils.rm_rf(tmp_path)
|
47
|
+
FileUtils.mkdir_p(tmp_path)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
Spork.each_run do
|
52
|
+
require 'berkshelf/api'
|
53
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'chef_zero/server'
|
2
|
+
|
3
|
+
module Berkshelf::RSpec
|
4
|
+
module ChefServer
|
5
|
+
class << self
|
6
|
+
def clear_request_log
|
7
|
+
@request_log = Array.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def request_log
|
11
|
+
@request_log ||= Array.new
|
12
|
+
end
|
13
|
+
|
14
|
+
def server
|
15
|
+
@server ||= ChefZero::Server.new(port: PORT, generate_real_keys: false)
|
16
|
+
end
|
17
|
+
|
18
|
+
def server_url
|
19
|
+
(@server && @server.url) || "http://localhost/#{PORT}"
|
20
|
+
end
|
21
|
+
|
22
|
+
def start
|
23
|
+
server.start_background
|
24
|
+
server.on_response do |request, response|
|
25
|
+
request_log << [ request, response ]
|
26
|
+
end
|
27
|
+
clear_request_log
|
28
|
+
|
29
|
+
server
|
30
|
+
end
|
31
|
+
|
32
|
+
def stop
|
33
|
+
@server.stop if @server
|
34
|
+
end
|
35
|
+
|
36
|
+
def running?
|
37
|
+
@server && @server.running?
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
PORT = 8889
|
42
|
+
|
43
|
+
def chef_client(name, hash = Hash.new)
|
44
|
+
load_data(:clients, name, hash)
|
45
|
+
end
|
46
|
+
|
47
|
+
def chef_cookbook(name, version, cookbook = Hash.new)
|
48
|
+
ChefServer.server.load_data("cookbooks" => { "#{name}-#{version}" => cookbook })
|
49
|
+
end
|
50
|
+
|
51
|
+
def chef_data_bag(name, hash = Hash.new)
|
52
|
+
ChefServer.server.load_data({ 'data' => { name => hash }})
|
53
|
+
end
|
54
|
+
|
55
|
+
def chef_environment(name, hash = Hash.new)
|
56
|
+
load_data(:environments, name, hash)
|
57
|
+
end
|
58
|
+
|
59
|
+
def chef_node(name, hash = Hash.new)
|
60
|
+
load_data(:nodes, name, hash)
|
61
|
+
end
|
62
|
+
|
63
|
+
def chef_role(name, hash = Hash.new)
|
64
|
+
load_data(:roles, name, hash)
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def load_data(key, name, hash)
|
70
|
+
ChefServer.server.load_data(key.to_s => { name => JSON.fast_generate(hash) })
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Berkshelf::API::Application do
|
4
|
+
describe "ClassMethods" do
|
5
|
+
subject { described_class }
|
6
|
+
|
7
|
+
its(:registry) { should be_a(Celluloid::Registry) }
|
8
|
+
|
9
|
+
describe "::run!" do
|
10
|
+
include Berkshelf::API::Mixin::Services
|
11
|
+
|
12
|
+
let(:options) { { log_location: '/dev/null' } }
|
13
|
+
subject(:run) { described_class.run!(options) }
|
14
|
+
|
15
|
+
context "when given true for :disable_http" do
|
16
|
+
it "does not start the REST Gateway" do
|
17
|
+
options[:disable_http] = true
|
18
|
+
run
|
19
|
+
expect { rest_gateway }.to raise_error(Berkshelf::API::NotStartedError)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|