ridley 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
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, notification: false do
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
  [![Build Status](https://secure.travis-ci.org/reset/ridley.png?branch=master)](http://travis-ci.org/reset/ridley)
3
+ [![Dependency Status](https://gemnasium.com/reset/ridley.png?travis)](https://gemnasium.com/reset/ridley)
3
4
  [![Code Climate](https://codeclimate.com/badge.png)](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 berkshelf-#{Ridley::VERSION}.gem into the pkg directory"
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 berkshelf-#{Ridley::VERSION}.gem into system gems"
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 berkshelf-#{Ridley::VERSION}.gem to Rubygems"
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
@@ -9,6 +9,7 @@ require 'forwardable'
9
9
  require 'set'
10
10
  require 'thread'
11
11
 
12
+ require 'ridley/version'
12
13
  require 'ridley/errors'
13
14
 
14
15
  # @author Jamie Winsor <jamie@vialstudios.com>
@@ -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[:thread_count] ||= DEFAULT_THREAD_COUNT
57
-
58
- validate_options(options)
75
+ self.class.validate_options(options)
59
76
 
60
- @client_name = options[:client_name]
61
- @client_key = options[:client_key]
62
- @organization = options[:organization]
63
- @thread_count = options[:thread_count]
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
- if organization
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
@@ -47,7 +47,7 @@ module Ridley
47
47
 
48
48
  def initialize(env)
49
49
  @env = env
50
- @errors = Array(env[:body][:error]) || []
50
+ @errors = env[:body].is_a?(Hash) ? Array(env[:body][:error]) : []
51
51
 
52
52
  if errors.empty?
53
53
  @message = env[:body] || "no content body"
@@ -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).merge(default_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)
@@ -24,7 +24,7 @@ module Ridley
24
24
  #
25
25
  # @return [Hash]
26
26
  def parse(body)
27
- MultiJson.load(body, symbolize_keys: true)
27
+ MultiJson.decode(body, symbolize_keys: true)
28
28
  end
29
29
 
30
30
  # Extracts the type of the response from the response headers
@@ -255,7 +255,7 @@ module Ridley
255
255
  #
256
256
  # @return [Object]
257
257
  def from_json(json, options = {})
258
- self.attributes = MultiJson.load(json, options)
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.dump(self.attributes, options)
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"
@@ -167,7 +167,7 @@ module Ridley
167
167
  #
168
168
  # @return [String]
169
169
  def to_json(options = {})
170
- MultiJson.dump(self.attributes, options)
170
+ MultiJson.encode(self.attributes, options)
171
171
  end
172
172
  alias_method :as_json, :to_json
173
173
 
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Ridley
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
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 "Role API operations", type: "acceptance" do
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(:dump).with(subject.attributes, kind_of(Hash))
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(:dump).and_return("{}")
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, "missing required option(s): 'server_url'")
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, "missing required option(s): 'client_name'")
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, "missing required option(s): 'client_key'")
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.2
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-08-22 00:00:00.000000000 Z
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: '0'
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: '0'
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: -2920625488512692680
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