spice 0.8.0 → 1.0.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/CHANGELOG.md +6 -0
- data/Gemfile +6 -6
- data/README.md +5 -63
- data/lib/spice.rb +56 -151
- data/lib/spice/client.rb +23 -36
- data/lib/spice/config.rb +52 -0
- data/lib/spice/connection.rb +89 -74
- data/lib/spice/connection/authentication.rb +47 -0
- data/lib/spice/connection/clients.rb +15 -0
- data/lib/spice/connection/cookbooks.rb +42 -0
- data/lib/spice/connection/data_bags.rb +35 -0
- data/lib/spice/connection/environments.rb +16 -0
- data/lib/spice/connection/nodes.rb +15 -0
- data/lib/spice/connection/roles.rb +15 -0
- data/lib/spice/connection/search.rb +49 -0
- data/lib/spice/cookbook.rb +13 -30
- data/lib/spice/cookbook_version.rb +43 -0
- data/lib/spice/data_bag.rb +17 -121
- data/lib/spice/data_bag_item.rb +35 -0
- data/lib/spice/environment.rb +15 -79
- data/lib/spice/error.rb +30 -0
- data/lib/spice/node.rb +19 -36
- data/lib/spice/persistence.rb +42 -0
- data/lib/spice/request.rb +27 -0
- data/lib/spice/request/auth.rb +14 -0
- data/lib/spice/response/client_error.rb +30 -0
- data/lib/spice/response/parse_json.rb +24 -0
- data/lib/spice/role.rb +18 -25
- data/lib/spice/version.rb +1 -1
- data/spec/spec_helper.rb +0 -1
- data/spice.gemspec +4 -3
- metadata +65 -42
- data/lib/spice/core_ext/hash.rb +0 -21
- data/lib/spice/search.rb +0 -23
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
data/Gemfile
CHANGED
@@ -3,14 +3,14 @@ source "http://rubygems.org"
|
|
3
3
|
gemspec
|
4
4
|
|
5
5
|
group :development, :test do
|
6
|
-
gem 'rspec', '>= 2.
|
7
|
-
gem "webmock", ">= 1.
|
6
|
+
gem 'rspec', '>= 2.8.0'
|
7
|
+
gem "webmock", ">= 1.7.10"
|
8
8
|
gem "timecop", ">= 0.3.5"
|
9
9
|
gem 'fakefs', '>= 0.3.2'
|
10
|
-
gem 'guard', '>= 0.
|
11
|
-
gem 'guard-rspec', '>= 0.
|
12
|
-
gem 'guard-spork', '>= 0.
|
13
|
-
gem 'spork', '>= 0.9.0.
|
10
|
+
gem 'guard', '>= 0.10.0'
|
11
|
+
gem 'guard-rspec', '>= 0.6.0'
|
12
|
+
gem 'guard-spork', '>= 0.5.1'
|
13
|
+
gem 'spork', '>= 0.9.0.rc9'
|
14
14
|
gem 'rb-fsevent', '>= 0.4.3.1'
|
15
15
|
gem 'growl', '>= 1.0.3'
|
16
16
|
end
|
data/README.md
CHANGED
@@ -10,71 +10,9 @@ Install this beast via Rubygems:
|
|
10
10
|
|
11
11
|
Of course, You can always grab the source from http://github.com/danryan/spice.
|
12
12
|
|
13
|
-
## Configuration
|
14
|
-
|
15
|
-
Spice has four configuration variables:
|
16
|
-
|
17
|
-
Spice.server_url # default: http://localhost:4000
|
18
|
-
Spice.chef_version # default: 0.10.4. Should be set to the version you have
|
19
|
-
Spice.client_name # default: nil. Must be set to a valid admin Chef client
|
20
|
-
Spice.key_file # default: nil. Must be set to a file path
|
21
|
-
|
22
|
-
To connect to a Chef server at https://chef.example.com:5000 with the "admin" API client, throw this somewhere your app can initialize:
|
23
|
-
|
24
|
-
Spice.server_url = "http://chef.example.com:4000"
|
25
|
-
Spice.client_name = "admin"
|
26
|
-
Spice.key_file = "/path/to/keyfile.pem"
|
27
|
-
|
28
|
-
Say you had a Chef server v0.10.4 running locally on port 4000 over HTTP, you only need to set your `client_name` and `key_file` path:
|
29
|
-
|
30
|
-
Spice.client_name = "admin"
|
31
|
-
Spice.key_file = "/path/to/keyfile.pem"
|
32
|
-
|
33
|
-
|
34
|
-
You can also use the Spice.setup block if you prefer this style:
|
35
|
-
|
36
|
-
Spice.setup do |s|
|
37
|
-
s.server_url = "http://chef.example.com:4000"
|
38
|
-
s.client_name = "admin"
|
39
|
-
s.key_file = "/path/to/keyfile.pem"
|
40
|
-
end
|
41
|
-
|
42
|
-
Next, we need to create the connection object you'll use to sign your requests and pass them to the Chef server. Previous versions of Spice required you to explicitly call `Spice.connect!` to set up the connection object. If you use the `Spice.setup` block, it will call `.connect!` for you:
|
43
|
-
|
44
|
-
Spice.connect!
|
45
|
-
|
46
|
-
If you want to reset your config to their default values:
|
47
|
-
|
48
|
-
Spice.reset!
|
49
|
-
|
50
13
|
### Deprecation notice
|
51
14
|
|
52
|
-
Explicitly setting a `host`, `port`, and `scheme` value has been deprecated in favor of setting a single variable, `server_url`, which matches the format of Chef's client config parameter, `chef_server_url`. The old way of defining `host`, `port`, and `scheme`
|
53
|
-
|
54
|
-
## Usage
|
55
|
-
|
56
|
-
### Low-level use
|
57
|
-
|
58
|
-
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`.
|
59
|
-
|
60
|
-
Get a list of all clients:
|
61
|
-
|
62
|
-
Spice.connection.get("/clients")
|
63
|
-
|
64
|
-
Get a specific node by the name "slappypants":
|
65
|
-
|
66
|
-
Spice.connection.get("/nodes/slappypants")
|
67
|
-
|
68
|
-
Create a new role called "awesome":
|
69
|
-
|
70
|
-
Spice.connection.post("/roles", :name => "awesome")
|
71
|
-
|
72
|
-
Make the client "sweet" an admin:
|
73
|
-
|
74
|
-
Spice.connection.put("/clients/sweet", :admin => true)
|
75
|
-
|
76
|
-
Read the wiki for more examples.
|
77
|
-
|
15
|
+
Explicitly setting a `host`, `port`, and `scheme` value has been deprecated in favor of setting a single variable, `server_url`, which matches the format of Chef's client config parameter, `chef_server_url`. The old way of defining `host`, `port`, and `scheme` has been removed.
|
78
16
|
|
79
17
|
### Contributors
|
80
18
|
|
@@ -82,6 +20,10 @@ Read the wiki for more examples.
|
|
82
20
|
* [Holger Just](https://github.com/meineerde) - Search functionality
|
83
21
|
* [Sean Porter](https://github.com/portertech) - Platform bug fixes
|
84
22
|
|
23
|
+
### Hat tip
|
24
|
+
|
25
|
+
Spice is very heavily inspired by the [Twitter gem](http://github.com/jnunemaker/twitter). Mad props to those folks.
|
26
|
+
|
85
27
|
## Contributing to spice
|
86
28
|
|
87
29
|
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
data/lib/spice.rb
CHANGED
@@ -1,174 +1,79 @@
|
|
1
|
-
require '
|
1
|
+
require 'toystore'
|
2
|
+
require 'adapter/memory'
|
2
3
|
require 'mixlib/authentication'
|
3
|
-
require 'yajl'
|
4
|
-
require 'cgi'
|
5
4
|
|
5
|
+
require 'spice/config'
|
6
|
+
require 'spice/error'
|
6
7
|
require 'spice/authentication'
|
7
8
|
require 'spice/chef'
|
8
9
|
|
9
|
-
require 'spice/core_ext/hash'
|
10
|
-
|
11
10
|
require 'spice/role'
|
12
11
|
require 'spice/client'
|
13
12
|
require 'spice/cookbook'
|
13
|
+
require 'spice/cookbook_version'
|
14
14
|
require 'spice/data_bag'
|
15
|
+
require 'spice/data_bag_item'
|
15
16
|
require 'spice/node'
|
16
17
|
require 'spice/environment'
|
17
|
-
require 'spice/search'
|
18
18
|
require 'spice/connection'
|
19
19
|
|
20
|
+
require 'spice/connection/clients'
|
21
|
+
require 'spice/connection/cookbooks'
|
22
|
+
require 'spice/connection/data_bags'
|
23
|
+
require 'spice/connection/environments'
|
24
|
+
require 'spice/connection/nodes'
|
25
|
+
require 'spice/connection/roles'
|
26
|
+
require 'spice/connection/search'
|
27
|
+
|
20
28
|
require 'spice/version'
|
21
29
|
require 'spice/mock'
|
22
30
|
|
23
31
|
module Spice
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
@default_url_path ||= ""
|
35
|
-
end
|
36
|
-
|
37
|
-
def default_host
|
38
|
-
@default_host ||= "localhost"
|
39
|
-
end
|
40
|
-
|
41
|
-
def default_port
|
42
|
-
@default_port ||= "4000"
|
43
|
-
end
|
44
|
-
|
45
|
-
def default_scheme
|
46
|
-
@default_scheme ||= "http"
|
47
|
-
end
|
48
|
-
|
49
|
-
def server_url
|
50
|
-
@server_url || default_server_url
|
51
|
-
end
|
52
|
-
|
53
|
-
def url_path
|
54
|
-
@url_path || default_url_path
|
55
|
-
end
|
56
|
-
|
57
|
-
def host
|
58
|
-
@host || default_host
|
59
|
-
end
|
60
|
-
|
61
|
-
def port
|
62
|
-
@port || default_port
|
63
|
-
end
|
64
|
-
|
65
|
-
def scheme
|
66
|
-
@scheme || default_scheme
|
67
|
-
end
|
32
|
+
extend Config
|
33
|
+
extend self
|
34
|
+
|
35
|
+
extend Spice::Connection::Clients
|
36
|
+
extend Spice::Connection::Cookbooks
|
37
|
+
extend Spice::Connection::DataBags
|
38
|
+
extend Spice::Connection::Environments
|
39
|
+
extend Spice::Connection::Nodes
|
40
|
+
extend Spice::Connection::Roles
|
41
|
+
extend Spice::Connection::Search
|
68
42
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
def raw_key
|
78
|
-
@raw_key
|
79
|
-
end
|
80
|
-
|
81
|
-
def key_file=(new_key_file)
|
82
|
-
raw_key = File.read(new_key_file)
|
83
|
-
assert_valid_key_format!(raw_key)
|
84
|
-
@key_file = new_key_file
|
85
|
-
@raw_key = raw_key
|
86
|
-
end
|
87
|
-
|
88
|
-
def default_chef_version
|
89
|
-
@default_chef_version ||= "0.10.4"
|
90
|
-
end
|
91
|
-
|
92
|
-
def chef_version
|
93
|
-
@chef_version || default_chef_version
|
94
|
-
end
|
95
|
-
|
96
|
-
def connection
|
97
|
-
@connection
|
98
|
-
end
|
99
|
-
|
100
|
-
def connect!
|
101
|
-
# allow old-style connection setup
|
102
|
-
if host != default_host || port != default_port || scheme != default_scheme || url_path != default_url_path
|
103
|
-
url = "#{scheme}://#{host}:#{port}#{url_path}"
|
104
|
-
else
|
105
|
-
url = server_url
|
106
|
-
end
|
107
|
-
@connection = Connection.new(
|
108
|
-
:server_url => url,
|
109
|
-
:client_name => client_name,
|
110
|
-
:key_file => key_file
|
111
|
-
)
|
112
|
-
end
|
113
|
-
|
114
|
-
def reset!
|
115
|
-
@server_url = default_server_url
|
116
|
-
@host = default_host
|
117
|
-
@port = default_port
|
118
|
-
@scheme = default_scheme
|
119
|
-
@chef_version = default_chef_version
|
120
|
-
@key_file = nil
|
121
|
-
@client_name = nil
|
122
|
-
@connection = nil
|
123
|
-
end
|
124
|
-
|
125
|
-
def setup
|
126
|
-
if block_given?
|
127
|
-
yield self
|
128
|
-
end
|
129
|
-
connect!
|
130
|
-
end
|
43
|
+
def connection
|
44
|
+
@connection ||= Connection.new(
|
45
|
+
:server_url => server_url,
|
46
|
+
:client_name => client_name,
|
47
|
+
:key_file => key_file
|
48
|
+
)
|
49
|
+
end
|
131
50
|
|
132
|
-
|
133
|
-
|
134
|
-
|
51
|
+
def mock
|
52
|
+
Spice::Mock.setup_mock_client
|
53
|
+
end
|
135
54
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
55
|
+
# def autoconfigure!(path=nil)
|
56
|
+
# path ||= "~/.chef/"
|
57
|
+
# knife = File.exist?("~/.chef/knife.rb") && File.expand_path(path + "~/.chef/knife.rb")
|
58
|
+
# client = File.exist?("/etc/chef/client.rb") && File.expand_path("/etc/chef/client.rb")
|
59
|
+
#
|
60
|
+
# if knife
|
61
|
+
# raw_config = IO.read(knife)
|
62
|
+
# elsif
|
63
|
+
# raw_config = IO.read(client)
|
64
|
+
# end
|
65
|
+
#
|
66
|
+
# @values = {}
|
67
|
+
# raw_config.each_line do |line|
|
68
|
+
# if line =~ /^chef_server_url.*/
|
69
|
+
# @values[:chef_server_url] = parse_line(line)
|
70
|
+
# elsif line =~ /^node_name.*/
|
71
|
+
# @values[:node_name] = parse_line(line)
|
72
|
+
# elsif line =~ /^client_key.*/
|
73
|
+
# @values[:client_key] = parse_line(line)
|
74
|
+
# end
|
75
|
+
# end
|
76
|
+
# end
|
158
77
|
|
159
|
-
private
|
160
78
|
|
161
|
-
def assert_valid_key_format!(raw_key)
|
162
|
-
unless (raw_key =~ /\A-----BEGIN RSA PRIVATE KEY-----$/) &&
|
163
|
-
(raw_key =~ /^-----END RSA PRIVATE KEY-----\Z/)
|
164
|
-
msg = "The file #{key_file} does not contain a correctly formatted private key.\n"
|
165
|
-
msg << "The key file should begin with '-----BEGIN RSA PRIVATE KEY-----' and end with '-----END RSA PRIVATE KEY-----'"
|
166
|
-
raise ArgumentError, msg
|
167
|
-
end
|
168
|
-
end
|
169
|
-
|
170
|
-
def parse_line(line)
|
171
|
-
line.strip.split.last.gsub("'", "")
|
172
|
-
end
|
173
|
-
end
|
174
79
|
end
|
data/lib/spice/client.rb
CHANGED
@@ -1,42 +1,29 @@
|
|
1
|
+
require 'spice/persistence'
|
2
|
+
|
1
3
|
module Spice
|
2
|
-
class Client
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
end
|
9
|
-
results
|
10
|
-
else
|
11
|
-
connection.get("/clients")
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.[](name)
|
16
|
-
connection.get("/clients/#{name}")
|
17
|
-
end
|
18
|
-
|
19
|
-
def self.show(options={})
|
20
|
-
raise ArgumentError, "Option :name must be present" unless options[:name]
|
21
|
-
name = options.delete(:name)
|
22
|
-
connection.get("/clients/#{name}")
|
23
|
-
end
|
24
|
-
|
25
|
-
def self.create(options={})
|
26
|
-
raise ArgumentError, "Option :name must be present" unless options[:name]
|
27
|
-
connection.post("/clients", options)
|
28
|
-
end
|
4
|
+
class Client
|
5
|
+
include Toy::Store
|
6
|
+
include Spice::Persistence
|
7
|
+
extend Spice::Persistence
|
8
|
+
store :memory, {}
|
9
|
+
endpoint "clients"
|
29
10
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
11
|
+
attribute :name, String
|
12
|
+
attribute :public_key, String
|
13
|
+
attribute :private_key, String
|
14
|
+
attribute :_rev, String
|
15
|
+
attribute :json_class, String, :default => "Chef::ApiClient"
|
16
|
+
attribute :admin, Boolean, :default => false
|
17
|
+
attribute :chef_type, String, :default => "client"
|
35
18
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
19
|
+
validates_presence_of :name, :json_class, :chef_type
|
20
|
+
|
21
|
+
|
22
|
+
def do_post
|
23
|
+
response = connection.post("/clients", :name => name)
|
24
|
+
update_attributes(response.body)
|
25
|
+
response = connection.get("/clients/#{name}")
|
26
|
+
update_attributes(response.body)
|
40
27
|
end
|
41
28
|
end
|
42
29
|
end
|
data/lib/spice/config.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'spice/version'
|
2
|
+
|
3
|
+
module Spice
|
4
|
+
module Config
|
5
|
+
DEFAULT_SERVER_URL = "http://localhost:4000"
|
6
|
+
|
7
|
+
DEFAULT_CHEF_VERSION = "0.10.8"
|
8
|
+
|
9
|
+
DEFAULT_USER_AGENT = "Spice #{Spice::VERSION}"
|
10
|
+
|
11
|
+
DEFAULT_CONNECTION_OPTIONS = {}
|
12
|
+
|
13
|
+
VALID_OPTIONS_KEYS = [
|
14
|
+
:server_url,
|
15
|
+
:client_name,
|
16
|
+
:key_file,
|
17
|
+
:raw_key,
|
18
|
+
:chef_version,
|
19
|
+
:adapter,
|
20
|
+
:user_agent,
|
21
|
+
:connection_options
|
22
|
+
]
|
23
|
+
|
24
|
+
attr_accessor *VALID_OPTIONS_KEYS
|
25
|
+
|
26
|
+
def self.extended(base)
|
27
|
+
base.reset
|
28
|
+
end
|
29
|
+
|
30
|
+
def setup
|
31
|
+
yield self
|
32
|
+
self
|
33
|
+
end
|
34
|
+
|
35
|
+
def options
|
36
|
+
options = {}
|
37
|
+
VALID_OPTIONS_KEYS.each{|k| options[k] = send(k)}
|
38
|
+
options
|
39
|
+
end
|
40
|
+
|
41
|
+
def reset
|
42
|
+
self.user_agent = DEFAULT_USER_AGENT
|
43
|
+
self.server_url = DEFAULT_SERVER_URL
|
44
|
+
self.chef_version = DEFAULT_CHEF_VERSION
|
45
|
+
self.client_name = nil
|
46
|
+
self.key_file = nil
|
47
|
+
self.raw_key = nil
|
48
|
+
self.connection_options = DEFAULT_CONNECTION_OPTIONS
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|