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 +1 -0
- data/Gemfile.lock +64 -2
- data/README.md +83 -4
- data/Rakefile +19 -0
- data/TODO.md +2 -0
- data/features/support/env.rb +1 -0
- data/file.txt +0 -0
- data/lib/spice.rb +87 -2
- data/lib/spice/authentication.rb +1 -1
- data/lib/spice/chef.rb +34 -30
- data/lib/spice/client.rb +1 -1
- data/lib/spice/connection.rb +4 -5
- data/lib/spice/cookbook.rb +2 -2
- data/lib/spice/data_bag.rb +1 -1
- data/lib/spice/node.rb +1 -1
- data/lib/spice/role.rb +30 -0
- data/lib/spice/version.rb +1 -1
- data/spec/spec_helper.rb +13 -3
- data/spec/spice/authentication_spec.rb +0 -0
- data/spec/spice/chef_spec.rb +105 -0
- data/spec/spice/client_spec.rb +69 -0
- data/spec/spice/connection_spec.rb +0 -0
- data/spec/spice/cookbook_spec.rb +35 -0
- data/spec/spice/data_bag_spec.rb +35 -0
- data/spec/spice/node_spec.rb +35 -0
- data/spec/spice/role_spec.rb +35 -0
- data/spec/spice_spec.rb +124 -2
- data/spec/support/authentication.rb +42 -0
- data/spec/support/headers.rb +18 -0
- data/spec/support/vcr.rb +8 -0
- data/spice.gemspec +10 -2
- metadata +149 -7
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.
|
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 (
|
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
|
-
|
1
|
+
# spice
|
2
2
|
|
3
|
-
|
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
|
-
|
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
|
-
|
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
data/features/support/env.rb
CHANGED
data/file.txt
ADDED
File without changes
|
data/lib/spice.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
|
-
require '
|
2
|
-
require
|
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
|
data/lib/spice/authentication.rb
CHANGED
data/lib/spice/chef.rb
CHANGED
@@ -1,42 +1,46 @@
|
|
1
1
|
module Spice
|
2
2
|
class Chef
|
3
|
-
attr_accessor :
|
3
|
+
attr_accessor :client_name, :key_file, :connection
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
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
|
-
|
21
|
+
@connection ||= Spice.connection
|
28
22
|
end
|
29
23
|
|
30
|
-
|
31
|
-
|
32
|
-
|
24
|
+
class << self
|
25
|
+
def clients
|
26
|
+
Client.all
|
27
|
+
end
|
33
28
|
|
34
|
-
|
35
|
-
|
36
|
-
|
29
|
+
def nodes
|
30
|
+
Node.all
|
31
|
+
end
|
37
32
|
|
38
|
-
|
39
|
-
|
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
data/lib/spice/connection.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
require '
|
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,
|
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
|
53
|
-
:payload => JSON.generate(payload)
|
52
|
+
:headers => build_headers(:DELETE, path, headers)
|
54
53
|
)
|
55
54
|
JSON.parse(response)
|
56
55
|
end
|