ridley 0.0.2 → 0.0.3
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/Guardfile +4 -1
- data/README.md +1 -0
- data/Thorfile +3 -3
- data/lib/ridley.rb +1 -0
- data/lib/ridley/connection.rb +25 -16
- data/lib/ridley/errors.rb +1 -1
- data/lib/ridley/middleware/chef_auth.rb +1 -1
- data/lib/ridley/middleware/parse_json.rb +1 -1
- data/lib/ridley/resource.rb +2 -2
- data/lib/ridley/resources/cookbook.rb +26 -0
- data/lib/ridley/resources/data_bag_item.rb +1 -1
- data/lib/ridley/resources/sandbox.rb +106 -0
- data/lib/ridley/version.rb +1 -1
- data/ridley.gemspec +1 -1
- data/spec/acceptance/sandbox_resource_spec.rb +41 -0
- data/spec/acceptance/search_resource_spec.rb +1 -1
- data/spec/fixtures/recipe_one.rb +1 -0
- data/spec/fixtures/recipe_two.rb +1 -0
- data/spec/support/shared_examples/ridley_resource.rb +2 -2
- data/spec/unit/ridley/connection_spec.rb +3 -3
- data/spec/unit/ridley/errors_spec.rb +8 -0
- metadata +12 -5
data/Guardfile
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
notification :off
|
2
|
+
interactor :coolline
|
3
|
+
|
1
4
|
guard 'spork' do
|
2
5
|
watch('Gemfile')
|
3
6
|
watch('spec/spec_helper.rb') { :rspec }
|
@@ -10,7 +13,7 @@ guard 'yard', stdout: '/dev/null', stderr: '/dev/null' do
|
|
10
13
|
watch(%r{ext/.+\.c})
|
11
14
|
end
|
12
15
|
|
13
|
-
guard 'rspec', version: 2, cli: "--color --drb --format Fuubar", all_on_start: false, all_after_pass: false
|
16
|
+
guard 'rspec', version: 2, cli: "--color --drb --format Fuubar", all_on_start: false, all_after_pass: false do
|
14
17
|
watch(%r{^spec/unit/.+_spec\.rb$})
|
15
18
|
watch(%r{^spec/acceptance/.+_spec\.rb$})
|
16
19
|
|
data/README.md
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# Ridley
|
2
2
|
[](http://travis-ci.org/reset/ridley)
|
3
|
+
[](https://gemnasium.com/reset/ridley)
|
3
4
|
[](https://codeclimate.com/github/reset/ridley)
|
4
5
|
|
5
6
|
A reliable Chef API client with a clean syntax
|
data/Thorfile
CHANGED
@@ -11,17 +11,17 @@ class Default < Thor
|
|
11
11
|
include Thor::RakeCompat
|
12
12
|
Bundler::GemHelper.install_tasks
|
13
13
|
|
14
|
-
desc "build", "Build
|
14
|
+
desc "build", "Build ridley-#{Ridley::VERSION}.gem into the pkg directory"
|
15
15
|
def build
|
16
16
|
Rake::Task["build"].execute
|
17
17
|
end
|
18
18
|
|
19
|
-
desc "install", "Build and install
|
19
|
+
desc "install", "Build and install ridley-#{Ridley::VERSION}.gem into system gems"
|
20
20
|
def install
|
21
21
|
Rake::Task["install"].execute
|
22
22
|
end
|
23
23
|
|
24
|
-
desc "release", "Create tag v#{Ridley::VERSION} and build and push
|
24
|
+
desc "release", "Create tag v#{Ridley::VERSION} and build and push ridley-#{Ridley::VERSION}.gem to Rubygems"
|
25
25
|
def release
|
26
26
|
Rake::Task["release"].execute
|
27
27
|
end
|
data/lib/ridley.rb
CHANGED
data/lib/ridley/connection.rb
CHANGED
@@ -5,6 +5,18 @@ module Ridley
|
|
5
5
|
def sync(options, &block)
|
6
6
|
new(options).sync(&block)
|
7
7
|
end
|
8
|
+
|
9
|
+
# @raise [ArgumentError]
|
10
|
+
#
|
11
|
+
# @return [Boolean]
|
12
|
+
def validate_options(options)
|
13
|
+
missing = (REQUIRED_OPTIONS - options.keys)
|
14
|
+
|
15
|
+
unless missing.empty?
|
16
|
+
missing.collect! { |opt| "'#{opt}'" }
|
17
|
+
raise ArgumentError, "Missing required option(s): #{missing.join(', ')}"
|
18
|
+
end
|
19
|
+
end
|
8
20
|
end
|
9
21
|
|
10
22
|
extend Forwardable
|
@@ -39,8 +51,15 @@ module Ridley
|
|
39
51
|
DEFAULT_THREAD_COUNT = 8
|
40
52
|
|
41
53
|
# @option options [String] :server_url
|
54
|
+
# URL to the Chef API
|
42
55
|
# @option options [String] :client_name
|
56
|
+
# name of the client used to authenticate with the Chef API
|
43
57
|
# @option options [String] :client_key
|
58
|
+
# filepath to the client's private key used to authenticate with
|
59
|
+
# the Chef API
|
60
|
+
# @option options [String] :organization
|
61
|
+
# the Organization to connect to. This is only used if you are connecting to
|
62
|
+
# private Chef or hosted Chef
|
44
63
|
# @option options [Integer] :thread_count
|
45
64
|
# @option options [Hash] :params
|
46
65
|
# URI query unencoded key/value pairs
|
@@ -53,14 +72,12 @@ module Ridley
|
|
53
72
|
# @option options [URI, String, Hash] :proxy
|
54
73
|
# URI, String, or Hash of HTTP proxy options
|
55
74
|
def initialize(options = {})
|
56
|
-
options
|
57
|
-
|
58
|
-
validate_options(options)
|
75
|
+
self.class.validate_options(options)
|
59
76
|
|
60
|
-
@client_name = options
|
61
|
-
@client_key = options
|
62
|
-
@organization = options
|
63
|
-
@thread_count = options
|
77
|
+
@client_name = options.fetch(:client_name)
|
78
|
+
@client_key = options.fetch(:client_key)
|
79
|
+
@organization = options.fetch(:organization, nil)
|
80
|
+
@thread_count = options.fetch(:thread_count, DEFAULT_THREAD_COUNT)
|
64
81
|
|
65
82
|
faraday_options = options.slice(:params, :headers, :request, :ssl, :proxy)
|
66
83
|
uri_hash = Addressable::URI.parse(options[:server_url]).to_hash.slice(:scheme, :host, :port)
|
@@ -69,7 +86,7 @@ module Ridley
|
|
69
86
|
uri_hash[:port] = (uri_hash[:scheme] == "https" ? 443 : 80)
|
70
87
|
end
|
71
88
|
|
72
|
-
|
89
|
+
unless organization.nil?
|
73
90
|
uri_hash[:path] = "/organizations/#{organization}"
|
74
91
|
end
|
75
92
|
|
@@ -119,13 +136,5 @@ module Ridley
|
|
119
136
|
def method_missing(method, *args, &block)
|
120
137
|
@self_before_instance_eval.send(method, *args, &block)
|
121
138
|
end
|
122
|
-
|
123
|
-
def validate_options(options)
|
124
|
-
missing = REQUIRED_OPTIONS - options.keys
|
125
|
-
unless missing.empty?
|
126
|
-
missing.collect! { |opt| "'#{opt}'" }
|
127
|
-
raise ArgumentError, "missing required option(s): #{missing.join(', ')}"
|
128
|
-
end
|
129
|
-
end
|
130
139
|
end
|
131
140
|
end
|
data/lib/ridley/errors.rb
CHANGED
@@ -23,7 +23,7 @@ module Ridley
|
|
23
23
|
user_id: client_name
|
24
24
|
)
|
25
25
|
authentication_headers = sign_obj.sign(client_key)
|
26
|
-
env[:request_headers] = env[:request_headers].merge(authentication_headers)
|
26
|
+
env[:request_headers] = default_headers.merge(env[:request_headers]).merge(authentication_headers)
|
27
27
|
env[:request_headers] = env[:request_headers].merge('Content-Length' => env[:body].bytesize.to_s) if env[:body]
|
28
28
|
|
29
29
|
Ridley.log.debug(env)
|
data/lib/ridley/resource.rb
CHANGED
@@ -255,7 +255,7 @@ module Ridley
|
|
255
255
|
#
|
256
256
|
# @return [Object]
|
257
257
|
def from_json(json, options = {})
|
258
|
-
self.attributes = MultiJson.
|
258
|
+
self.attributes = MultiJson.decode(json, options)
|
259
259
|
self
|
260
260
|
end
|
261
261
|
|
@@ -272,7 +272,7 @@ module Ridley
|
|
272
272
|
#
|
273
273
|
# @return [String]
|
274
274
|
def to_json(options = {})
|
275
|
-
MultiJson.
|
275
|
+
MultiJson.encode(self.attributes, options)
|
276
276
|
end
|
277
277
|
alias_method :as_json, :to_json
|
278
278
|
|
@@ -3,6 +3,32 @@ module Ridley
|
|
3
3
|
class Cookbook
|
4
4
|
include Ridley::Resource
|
5
5
|
|
6
|
+
class << self
|
7
|
+
# Save a new Cookbook Version of the given name, version with the
|
8
|
+
# given manifest of files and checksums.
|
9
|
+
#
|
10
|
+
# @param [Ridley::Connection] connection
|
11
|
+
# @param [String] name
|
12
|
+
# @param [String] version
|
13
|
+
# @param [String] manifest
|
14
|
+
# a JSON blob containing file names, file paths, and checksums for each
|
15
|
+
# that describe the cookbook version being uploaded.
|
16
|
+
#
|
17
|
+
# @option options [Boolean] :freeze
|
18
|
+
# @option options [Boolean] :force
|
19
|
+
#
|
20
|
+
# @return [Hash]
|
21
|
+
def save(connection, name, version, manifest, options = {})
|
22
|
+
freeze = options.fetch(:freeze, false)
|
23
|
+
force = options.fetch(:force, false)
|
24
|
+
|
25
|
+
url = "cookbooks/#{name}/#{version}"
|
26
|
+
url << "?force=true" if force
|
27
|
+
|
28
|
+
connection.put(url, manifest)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
6
32
|
set_chef_id "name"
|
7
33
|
set_chef_type "cookbook"
|
8
34
|
set_chef_json_class "Chef::Cookbook"
|
@@ -0,0 +1,106 @@
|
|
1
|
+
module Ridley
|
2
|
+
class Sandbox
|
3
|
+
class << self
|
4
|
+
# @param [Ridley::Connection] connection
|
5
|
+
# @param [Array] checksums
|
6
|
+
#
|
7
|
+
# @return [Ridley::Sandbox]
|
8
|
+
def create(connection, checksums = [])
|
9
|
+
sumhash = { checksums: Hash.new }.tap do |chks|
|
10
|
+
Array(checksums).each { |chk| chks[:checksums][chk] = nil }
|
11
|
+
end
|
12
|
+
|
13
|
+
attrs = connection.post("sandboxes", sumhash.to_json).body
|
14
|
+
new(connection, attrs[:sandbox_id], attrs[:checksums])
|
15
|
+
end
|
16
|
+
|
17
|
+
# Checksum the file at the given filepath for a Chef API.
|
18
|
+
#
|
19
|
+
# @param [String] path
|
20
|
+
#
|
21
|
+
# @return [String]
|
22
|
+
def checksum(path)
|
23
|
+
File.open(path, 'rb') { |f| checksum_io(f, Digest::MD5.new) }
|
24
|
+
end
|
25
|
+
|
26
|
+
# Checksum and encode the file at the given filepath for uploading
|
27
|
+
#
|
28
|
+
# @param [String] path
|
29
|
+
#
|
30
|
+
# @return [String]
|
31
|
+
# a base64 encoded checksum
|
32
|
+
def checksum64(path)
|
33
|
+
Base64.encode64([checksum(path)].pack("H*")).strip
|
34
|
+
end
|
35
|
+
|
36
|
+
# @param [String] io
|
37
|
+
# @param [Object] digest
|
38
|
+
#
|
39
|
+
# @return [String]
|
40
|
+
def checksum_io(io, digest)
|
41
|
+
while chunk = io.read(1024 * 8)
|
42
|
+
digest.update(chunk)
|
43
|
+
end
|
44
|
+
digest.hexdigest
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
attr_reader :sandbox_id
|
49
|
+
attr_reader :checksums
|
50
|
+
|
51
|
+
def initialize(connection, id, checksums)
|
52
|
+
@connection = connection
|
53
|
+
@sandbox_id = id
|
54
|
+
@checksums = checksums
|
55
|
+
end
|
56
|
+
|
57
|
+
def checksum(chk_id)
|
58
|
+
checksums.fetch(chk_id.to_sym)
|
59
|
+
end
|
60
|
+
|
61
|
+
# @param [String] chk_id
|
62
|
+
# @param [String] path
|
63
|
+
#
|
64
|
+
# @return [Hash, nil]
|
65
|
+
def upload(chk_id, path)
|
66
|
+
checksum = self.checksum(chk_id)
|
67
|
+
|
68
|
+
unless checksum[:needs_upload]
|
69
|
+
return nil
|
70
|
+
end
|
71
|
+
|
72
|
+
headers = {
|
73
|
+
'Content-Type' => 'application/x-binary',
|
74
|
+
'content-md5' => self.class.checksum64(path)
|
75
|
+
}
|
76
|
+
contents = File.open(path, 'rb') { |f| f.read }
|
77
|
+
|
78
|
+
Faraday.put(checksum[:url], contents, headers)
|
79
|
+
end
|
80
|
+
|
81
|
+
def commit
|
82
|
+
connection.put("sandboxes/#{sandbox_id}", { is_completed: true }.to_json).body
|
83
|
+
end
|
84
|
+
|
85
|
+
def to_s
|
86
|
+
"#{sandbox_id}: #{checksums}"
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
attr_reader :connection
|
92
|
+
end
|
93
|
+
|
94
|
+
module DSL
|
95
|
+
# Coerces instance functions into class functions on Ridley::Sandbox. This coercion
|
96
|
+
# sends an instance of the including class along to the class function.
|
97
|
+
#
|
98
|
+
# @see Ridley::Context
|
99
|
+
#
|
100
|
+
# @return [Ridley::Context]
|
101
|
+
# a context object to delegate instance functions to class functions on Ridley::Sandbox
|
102
|
+
def sandbox
|
103
|
+
Context.new(Ridley::Sandbox, self)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
data/lib/ridley/version.rb
CHANGED
data/ridley.gemspec
CHANGED
@@ -21,7 +21,7 @@ Gem::Specification.new do |s|
|
|
21
21
|
s.add_runtime_dependency 'mixlib-authentication'
|
22
22
|
s.add_runtime_dependency 'addressable'
|
23
23
|
s.add_runtime_dependency 'faraday'
|
24
|
-
s.add_runtime_dependency 'multi_json'
|
24
|
+
s.add_runtime_dependency 'multi_json', '>= 1.0.4'
|
25
25
|
s.add_runtime_dependency 'activemodel'
|
26
26
|
|
27
27
|
s.add_development_dependency 'rake'
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Sandbox API operations", type: "acceptance" do
|
4
|
+
let(:server_url) { "https://api.opscode.com" }
|
5
|
+
let(:client_name) { "reset" }
|
6
|
+
let(:client_key) { "/Users/reset/.chef/reset.pem" }
|
7
|
+
let(:organization) { "ridley" }
|
8
|
+
|
9
|
+
let(:connection) do
|
10
|
+
Ridley.connection(
|
11
|
+
server_url: server_url,
|
12
|
+
client_name: client_name,
|
13
|
+
client_key: client_key,
|
14
|
+
organization: organization
|
15
|
+
)
|
16
|
+
end
|
17
|
+
|
18
|
+
before(:all) { WebMock.allow_net_connect! }
|
19
|
+
after(:all) { WebMock.disable_net_connect! }
|
20
|
+
|
21
|
+
let(:checksums) do
|
22
|
+
[
|
23
|
+
Ridley::Sandbox.checksum(fixtures_path.join("recipe_one.rb")),
|
24
|
+
Ridley::Sandbox.checksum(fixtures_path.join("recipe_two.rb"))
|
25
|
+
]
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "creating a new sandbox" do
|
29
|
+
it "returns an instance of Ridley::Sandbox" do
|
30
|
+
connection.sandbox.create(checksums).should be_a(Ridley::Sandbox)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "contains a value for sandbox_id" do
|
34
|
+
connection.sandbox.create(checksums).sandbox_id.should_not be_nil
|
35
|
+
end
|
36
|
+
|
37
|
+
it "returns an instance with the same amount of checksums given to create" do
|
38
|
+
connection.sandbox.create(checksums).checksums.should have(2).items
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe "
|
3
|
+
describe "Search API operations", type: "acceptance" do
|
4
4
|
let(:server_url) { "https://api.opscode.com" }
|
5
5
|
let(:client_name) { "reset" }
|
6
6
|
let(:client_key) { "/Users/reset/.chef/reset.pem" }
|
@@ -0,0 +1 @@
|
|
1
|
+
testfile
|
@@ -0,0 +1 @@
|
|
1
|
+
testfile two
|
@@ -208,13 +208,13 @@ shared_examples_for "a Ridley Resource" do |resource_klass|
|
|
208
208
|
|
209
209
|
describe "#to_json" do
|
210
210
|
it "serializes the objects attributes using MultiJson" do
|
211
|
-
MultiJson.should_receive(:
|
211
|
+
MultiJson.should_receive(:encode).with(subject.attributes, kind_of(Hash))
|
212
212
|
|
213
213
|
subject.to_json
|
214
214
|
end
|
215
215
|
|
216
216
|
it "returns the seralized value" do
|
217
|
-
MultiJson.stub(:
|
217
|
+
MultiJson.stub(:encode).and_return("{}")
|
218
218
|
|
219
219
|
subject.to_json.should eql("{}")
|
220
220
|
end
|
@@ -68,7 +68,7 @@ describe Ridley::Connection do
|
|
68
68
|
client_name: client_name,
|
69
69
|
client_key: client_key
|
70
70
|
)
|
71
|
-
}.should raise_error(ArgumentError, "
|
71
|
+
}.should raise_error(ArgumentError, "Missing required option(s): 'server_url'")
|
72
72
|
end
|
73
73
|
|
74
74
|
it "raises if a value for client_name is not given" do
|
@@ -77,7 +77,7 @@ describe Ridley::Connection do
|
|
77
77
|
server_url: server_url,
|
78
78
|
client_key: client_key
|
79
79
|
)
|
80
|
-
}.should raise_error(ArgumentError, "
|
80
|
+
}.should raise_error(ArgumentError, "Missing required option(s): 'client_name'")
|
81
81
|
end
|
82
82
|
|
83
83
|
it "raises if a value for client_key is not given" do
|
@@ -86,7 +86,7 @@ describe Ridley::Connection do
|
|
86
86
|
server_url: server_url,
|
87
87
|
client_name: client_name
|
88
88
|
)
|
89
|
-
}.should raise_error(ArgumentError, "
|
89
|
+
}.should raise_error(ArgumentError, "Missing required option(s): 'client_key'")
|
90
90
|
end
|
91
91
|
end
|
92
92
|
|
@@ -30,5 +30,13 @@ describe Ridley::Errors do
|
|
30
30
|
end
|
31
31
|
end
|
32
32
|
end
|
33
|
+
|
34
|
+
context "with an HTML error payload" do
|
35
|
+
subject { Ridley::Errors::HTTPError.new(:body => "<html><body><h1>Redirected</h1></body></html>") }
|
36
|
+
|
37
|
+
it "has an HTML body" do
|
38
|
+
subject.message.should eq("<html><body><h1>Redirected</h1></body></html>")
|
39
|
+
end
|
40
|
+
end
|
33
41
|
end
|
34
42
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ridley
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
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: 2012-
|
12
|
+
date: 2012-09-16 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: yajl-ruby
|
@@ -98,7 +98,7 @@ dependencies:
|
|
98
98
|
requirements:
|
99
99
|
- - ! '>='
|
100
100
|
- !ruby/object:Gem::Version
|
101
|
-
version:
|
101
|
+
version: 1.0.4
|
102
102
|
type: :runtime
|
103
103
|
prerelease: false
|
104
104
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -106,7 +106,7 @@ dependencies:
|
|
106
106
|
requirements:
|
107
107
|
- - ! '>='
|
108
108
|
- !ruby/object:Gem::Version
|
109
|
-
version:
|
109
|
+
version: 1.0.4
|
110
110
|
- !ruby/object:Gem::Dependency
|
111
111
|
name: activemodel
|
112
112
|
requirement: !ruby/object:Gem::Requirement
|
@@ -363,6 +363,7 @@ files:
|
|
363
363
|
- lib/ridley/resources/environment.rb
|
364
364
|
- lib/ridley/resources/node.rb
|
365
365
|
- lib/ridley/resources/role.rb
|
366
|
+
- lib/ridley/resources/sandbox.rb
|
366
367
|
- lib/ridley/resources/search.rb
|
367
368
|
- lib/ridley/version.rb
|
368
369
|
- ridley.gemspec
|
@@ -373,7 +374,10 @@ files:
|
|
373
374
|
- spec/acceptance/environment_resource_spec.rb
|
374
375
|
- spec/acceptance/node_resource_spec.rb
|
375
376
|
- spec/acceptance/role_resource_spec.rb
|
377
|
+
- spec/acceptance/sandbox_resource_spec.rb
|
376
378
|
- spec/acceptance/search_resource_spec.rb
|
379
|
+
- spec/fixtures/recipe_one.rb
|
380
|
+
- spec/fixtures/recipe_two.rb
|
377
381
|
- spec/fixtures/reset.pem
|
378
382
|
- spec/spec_helper.rb
|
379
383
|
- spec/support/each_matcher.rb
|
@@ -414,7 +418,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
414
418
|
version: '0'
|
415
419
|
segments:
|
416
420
|
- 0
|
417
|
-
hash: -
|
421
|
+
hash: -1393828720209258724
|
418
422
|
requirements: []
|
419
423
|
rubyforge_project:
|
420
424
|
rubygems_version: 1.8.23
|
@@ -429,7 +433,10 @@ test_files:
|
|
429
433
|
- spec/acceptance/environment_resource_spec.rb
|
430
434
|
- spec/acceptance/node_resource_spec.rb
|
431
435
|
- spec/acceptance/role_resource_spec.rb
|
436
|
+
- spec/acceptance/sandbox_resource_spec.rb
|
432
437
|
- spec/acceptance/search_resource_spec.rb
|
438
|
+
- spec/fixtures/recipe_one.rb
|
439
|
+
- spec/fixtures/recipe_two.rb
|
433
440
|
- spec/fixtures/reset.pem
|
434
441
|
- spec/spec_helper.rb
|
435
442
|
- spec/support/each_matcher.rb
|