spice 0.0.1.alpha.2 → 0.0.2.beta

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -0,0 +1 @@
1
+ pkg/*
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- spice (0.0.1.alpha)
4
+ spice (0.0.1.beta1)
5
5
  mixlib-authentication
6
6
  rest-client
7
7
  yajl-ruby
@@ -9,11 +9,56 @@ PATH
9
9
  GEM
10
10
  remote: http://rubygems.org/
11
11
  specs:
12
+ abstract (1.0.0)
13
+ addressable (2.2.2)
14
+ builder (3.0.0)
15
+ bunny (0.6.0)
16
+ chef (0.9.12)
17
+ bunny (>= 0.6.0)
18
+ erubis
19
+ extlib
20
+ highline
21
+ json (>= 1.4.4, <= 1.4.6)
22
+ mixlib-authentication (>= 1.1.0)
23
+ mixlib-cli (>= 1.1.0)
24
+ mixlib-config (>= 1.1.2)
25
+ mixlib-log (>= 1.2.0)
26
+ moneta
27
+ ohai (>= 0.5.7)
28
+ rest-client (>= 1.0.4, < 1.7.0)
29
+ uuidtools
30
+ crack (0.1.8)
31
+ cucumber (0.10.0)
32
+ builder (>= 2.1.2)
33
+ diff-lcs (~> 1.1.2)
34
+ gherkin (~> 2.3.2)
35
+ json (~> 1.4.6)
36
+ term-ansicolor (~> 1.0.5)
12
37
  diff-lcs (1.1.2)
38
+ erubis (2.6.6)
39
+ abstract (>= 1.0.0)
40
+ extlib (0.9.15)
41
+ forgery (0.3.6)
42
+ gherkin (2.3.2)
43
+ json (~> 1.4.6)
44
+ term-ansicolor (~> 1.0.5)
45
+ highline (1.6.1)
46
+ json (1.4.6)
13
47
  mime-types (1.16)
14
48
  mixlib-authentication (1.1.4)
15
49
  mixlib-log
50
+ mixlib-cli (1.2.0)
51
+ mixlib-config (1.1.2)
16
52
  mixlib-log (1.2.0)
53
+ moneta (0.6.0)
54
+ ohai (0.5.8)
55
+ extlib
56
+ json (>= 1.4.4, <= 1.4.6)
57
+ mixlib-cli
58
+ mixlib-config
59
+ mixlib-log
60
+ systemu
61
+ rcov (0.9.9)
17
62
  rest-client (1.6.1)
18
63
  mime-types (>= 1.16)
19
64
  rspec (2.4.0)
@@ -24,14 +69,31 @@ GEM
24
69
  rspec-expectations (2.4.0)
25
70
  diff-lcs (~> 1.1.2)
26
71
  rspec-mocks (2.4.0)
72
+ systemu (1.2.0)
73
+ term-ansicolor (1.0.5)
74
+ timecop (0.3.5)
75
+ uuidtools (2.1.1)
76
+ vcr (1.4.0)
77
+ webmock (1.6.1)
78
+ addressable (>= 2.2.2)
79
+ crack (>= 0.1.7)
27
80
  yajl-ruby (0.7.8)
81
+ yard (0.6.4)
28
82
 
29
83
  PLATFORMS
30
84
  ruby
31
85
 
32
86
  DEPENDENCIES
87
+ chef (= 0.9.12)
88
+ cucumber (~> 0.10.0)
89
+ forgery (~> 0.3.6)
33
90
  mixlib-authentication
91
+ rcov
34
92
  rest-client
35
- rspec (= 2.4.0)
93
+ rspec (~> 2.4.0)
36
94
  spice!
95
+ timecop (~> 0.3.5)
96
+ vcr (~> 1.4.0)
97
+ webmock (~> 1.6.1)
37
98
  yajl-ruby
99
+ yard (~> 0.6.4)
data/README.md CHANGED
@@ -1,8 +1,87 @@
1
- = spice
1
+ # spice
2
2
 
3
- Description goes here.
3
+ Spice is a zesty Chef API wrapper. It's primary purpose is to let you integrate your apps with a (Chef)[http://opscode.com/chef] server easily and succinctly. Spice provides support for the (entire released Chef API)[http://wiki.opscode.com/display/chef/Server+API]
4
4
 
5
- == Contributing to spice
5
+ ## Installation
6
+
7
+ Install this beast via Rubygems (note that for now, you'll need the --pre flag until I deem it to be perfectly stable):
8
+
9
+ gem install spice --pre
10
+
11
+ Of course, You can always grab the source from http://github.com/danryan/spice.
12
+
13
+ ## Configuration
14
+
15
+ Spice has five configuration variables:
16
+
17
+ Spice.host # default: localhost
18
+ Spice.port # default: 4000
19
+ Spice.scheme # default: http
20
+ Spice.client_name # default: nil. Must be set to a valid admin Chef client
21
+ Spice.key_file # default: nil. Must be set to a file path
22
+
23
+ To connect to a Chef server at https://chef.example.com:5000 with the "admin" API client, throw this somewhere your app can initialize:
24
+
25
+ Spice.host = "chef.example.com"
26
+ Spice.port = "5000"
27
+ Spice.scheme = "https"
28
+ Spice.client_name = "admin"
29
+ Spice.key_file = "/path/to/keyfile.pem"
30
+
31
+ Say you had a Chef server (or Chef solo) running locally on port 4000 over HTTP, you only need to set your `client_name` and `key_file` path:
32
+
33
+ Spice.client_name = "admin"
34
+ Spice.key_file = "/path/to/keyfile.pem"
35
+
36
+
37
+ You can also use the Spice.setup block if you prefer this style:
38
+
39
+ Spice.setup do |s|
40
+ s.host = "chef.example.com"
41
+ s.port = "5000"
42
+ s.scheme = "https"
43
+ s.client_name = "admin"
44
+ s.key_file = "/path/to/keyfile.pem"
45
+ end
46
+
47
+ After you have configured Spice, we need to create the connection object you'll use to sign your requests and pass them to the Chef server:
48
+
49
+ Spice.connect!
50
+
51
+ If you want to reset your config to their default values:
52
+
53
+ Spice.reset!
54
+
55
+ ## Usage
56
+
57
+ ### Low-level use
58
+
59
+ Setting up spice and running `Spice.connect!` creates a connection object that can then be used to send requests to your Chef server, accessed via `Spice.connection`.
60
+
61
+ Get a list of all clients:
62
+
63
+ Spice.connection.get("/clients")
64
+
65
+ Get a specific node by the name "slappypants":
66
+
67
+ Spice.connection.get("/nodes/slappypants")
68
+
69
+ Create a new role called "awesome":
70
+
71
+ Spice.connection.post("/roles", :name => "awesome")
72
+
73
+ Make the client "sweet" an admin:
74
+
75
+ Spice.connection.put("/clients/sweet", :admin => true)
76
+
77
+ Scope out (the official Chef API docs)[http://wiki.opscode.com/display/chef/Server+API] for a full list of wicked awesome things you can do.
78
+
79
+ ## High-level use
80
+
81
+ TODO
82
+
83
+
84
+ ## Contributing to spice
6
85
 
7
86
  * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
8
87
  * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
@@ -12,7 +91,7 @@ Description goes here.
12
91
  * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
13
92
  * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
14
93
 
15
- == Copyright
94
+ ## Copyright
16
95
 
17
96
  Copyright (c) 2010 Dan Ryan. See LICENSE.txt for
18
97
  further details.
data/Rakefile CHANGED
@@ -1,2 +1,21 @@
1
1
  require 'bundler'
2
2
  Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core'
5
+ require 'rspec/core/rake_task'
6
+ RSpec::Core::RakeTask.new(:spec) do |spec|
7
+ spec.pattern = FileList['spec/**/*_spec.rb']
8
+ end
9
+
10
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
11
+ spec.pattern = 'spec/**/*_spec.rb'
12
+ spec.rcov = true
13
+ end
14
+
15
+ require 'cucumber/rake/task'
16
+ Cucumber::Rake::Task.new(:cucumber)
17
+
18
+ task :default => :spec
19
+
20
+ require 'yard'
21
+ YARD::Rake::YardocTask.new
data/TODO.md ADDED
@@ -0,0 +1,2 @@
1
+ * Allow configurable variables instead of relying on class variables
2
+ * Refactor classes that inherity from Spice::Chef to take config values
@@ -11,3 +11,4 @@ $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../../lib')
11
11
  require 'spice'
12
12
 
13
13
  require 'rspec/expectations'
14
+ require 'webmock/cucumber'
data/file.txt ADDED
File without changes
data/lib/spice.rb CHANGED
@@ -1,8 +1,9 @@
1
- require 'yajl/json_gem'
2
- require 'rest-client'
1
+ require 'bundler'
2
+ Bundler.require
3
3
 
4
4
  require 'spice/authentication'
5
5
  require 'spice/chef'
6
+ require 'spice/role'
6
7
 
7
8
  require 'spice/client'
8
9
  require 'spice/cookbook'
@@ -11,4 +12,88 @@ require 'spice/node'
11
12
  require 'spice/connection'
12
13
 
13
14
  module Spice
15
+ class << self
16
+ attr_writer :host, :port, :scheme, :client_name, :connection, :key_file, :raw_key
17
+
18
+ def default_host
19
+ @default_host || "localhost"
20
+ end
21
+
22
+ def default_port
23
+ @default_port || "4000"
24
+ end
25
+
26
+ def default_scheme
27
+ @default_scheme || "http"
28
+ end
29
+
30
+ def host
31
+ @host || default_host
32
+ end
33
+
34
+ def port
35
+ @port || default_port
36
+ end
37
+
38
+ def scheme
39
+ @scheme || default_scheme
40
+ end
41
+
42
+ def client_name
43
+ @client_name
44
+ end
45
+
46
+ def key_file
47
+ @key_file
48
+ end
49
+
50
+ def raw_key
51
+ @raw_key
52
+ end
53
+
54
+ def key_file=(new_key_file)
55
+ raw_key = File.read(new_key_file)
56
+ assert_valid_key_format!(raw_key)
57
+ @key_file = new_key_file
58
+ @raw_key = raw_key
59
+ end
60
+
61
+ def connection
62
+ @connection
63
+ end
64
+
65
+ def connect!
66
+ @connection = Connection.new(
67
+ :url => "#{scheme}://#{host}:#{port}",
68
+ :client_name => client_name,
69
+ :key_file => key_file
70
+ )
71
+ end
72
+
73
+
74
+ def reset!
75
+ @host = default_host
76
+ @port = default_port
77
+ @scheme = default_scheme
78
+ @key_file = nil
79
+ @client_name = nil
80
+ @connection = nil
81
+ puts "Spice is reset"
82
+ end
83
+
84
+ def setup
85
+ yield self
86
+ end
87
+
88
+ private
89
+
90
+ def assert_valid_key_format!(raw_key)
91
+ unless (raw_key =~ /\A-----BEGIN RSA PRIVATE KEY-----$/) &&
92
+ (raw_key =~ /^-----END RSA PRIVATE KEY-----\Z/)
93
+ msg = "The file #{key_file} does not contain a correctly formatted private key.\n"
94
+ msg << "The key file should begin with '-----BEGIN RSA PRIVATE KEY-----' and end with '-----END RSA PRIVATE KEY-----'"
95
+ raise ArgumentError, msg
96
+ end
97
+ end
98
+ end
14
99
  end
@@ -29,7 +29,7 @@ module Spice
29
29
 
30
30
  def load_signing_key
31
31
  begin
32
- @raw_key = IO.read(key_file, :mode => "r").strip
32
+ @raw_key = File.read(key_file).strip
33
33
  rescue SystemCallError, IOError => e
34
34
  raise IOError, "Unable to read #{key_file}"
35
35
  end
data/lib/spice/chef.rb CHANGED
@@ -1,42 +1,46 @@
1
1
  module Spice
2
2
  class Chef
3
- attr_accessor :host, :client_name, :key_file, :port, :path, :scheme, :connection
3
+ attr_accessor :client_name, :key_file, :connection
4
4
 
5
-
6
- def initialize(options={})
7
- @@client_name ||= @client_name = options[:client_name]
8
- @@key_file ||= @key_file = options[:key_file]
9
- @@host ||= @host = options[:host] || 'localhost'
10
- @@port ||= @port = options[:port] || 4000
11
- @@path ||= @path = options[:path] || '/'
12
- @@scheme ||= @scheme = options[:scheme] || 'http'
13
- @@connection ||= @connection = Connection.new(
14
- :url => "#{@scheme}://#{@host}:#{@port}#{@path}",
15
- :client_name => options[:client_name],
16
- :key_file => options[:key_file]
17
- )
18
- @default_headers = options[:headers] || {}
19
- @sign_on_redirect, @sign_request = true, true
20
- end
21
-
22
- def connection
23
- @@connection
24
- end
5
+ # def initialize(options={})
6
+ # @client_name = options[:client_name] || Spice.client_name
7
+ # @key_file = options[:key_file] || Spice.key_file
8
+ # @host = options[:host] || Spice.host
9
+ # @port = options[:port] || Spice.port
10
+ # @scheme = options[:scheme] || Spice.scheme
11
+ # # @connection = Connection.new(
12
+ # # :url => "#{@scheme}://#{@host}:#{@port}",
13
+ # # :client_name => options[:client_name],
14
+ # # :key_file => options[:key_file]
15
+ # # ) || Spice.connection
16
+ # @connection = Spice.connection
17
+ # @sign_on_redirect, @sign_request = true, true
18
+ # end
25
19
 
26
20
  def self.connection
27
- @@connection
21
+ @connection ||= Spice.connection
28
22
  end
29
23
 
30
- def clients
31
- Client.all
32
- end
24
+ class << self
25
+ def clients
26
+ Client.all
27
+ end
33
28
 
34
- def nodes
35
- Node.all
36
- end
29
+ def nodes
30
+ Node.all
31
+ end
37
32
 
38
- def data_bags
39
- DataBag.all
33
+ def data_bags
34
+ DataBag.all
35
+ end
36
+
37
+ def roles
38
+ Role.all
39
+ end
40
+
41
+ def cookbooks
42
+ Cookbook.all
43
+ end
40
44
  end
41
45
  end
42
46
  end
data/lib/spice/client.rb CHANGED
@@ -32,7 +32,7 @@ module Spice
32
32
 
33
33
  def self.delete(options={})
34
34
  name = options.delete(:name)
35
- connection.delete("/clients/#{name}")
35
+ connection.delete("/clients/#{name}", options)
36
36
  end
37
37
  end
38
38
  end
@@ -1,8 +1,8 @@
1
- require 'rest-client'
1
+ require 'yajl/json_gem'
2
2
 
3
3
  module Spice
4
4
  class Connection
5
- attr_accessor :client_name, :key_file, :auth_credentials, :url, :path, :port, :scheme
5
+ attr_accessor :client_name, :key_file, :auth_credentials, :url, :path, :port, :scheme, :host
6
6
 
7
7
  def initialize(options={})
8
8
  endpoint = URI.parse(options[:url])
@@ -45,12 +45,11 @@ module Spice
45
45
  JSON.parse(response)
46
46
  end
47
47
 
48
- def delete(path, payload, headers={})
48
+ def delete(path, headers={})
49
49
  response = RestClient::Request.execute(
50
50
  :method => :DELETE,
51
51
  :url => "#{@url}#{path}",
52
- :headers => build_headers(:DELETE, path, headers, JSON.generate(payload)),
53
- :payload => JSON.generate(payload)
52
+ :headers => build_headers(:DELETE, path, headers)
54
53
  )
55
54
  JSON.parse(response)
56
55
  end