spice 0.8.0 → 1.0.0.pre
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/.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
|