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 CHANGED
@@ -6,3 +6,4 @@ doc/**/*
6
6
  .yardoc/**/*
7
7
  .yardoc/*
8
8
  Gemfile.lock
9
+ fixture.rb
@@ -1,3 +1,9 @@
1
+ # Release Notes - Spice - Version 1.0.0
2
+
3
+ ## Removed
4
+
5
+ * Old-style connections are no longer supported. Please use the connection string like Chef uses (ex. http://chef.example.com:4000)
6
+
1
7
  # Release Notes - Spice - Version 0.5.0
2
8
 
3
9
  ## Bug
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.6.0'
7
- gem "webmock", ">= 1.6.2"
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.6.2'
11
- gem 'guard-rspec', '>= 0.4.2'
12
- gem 'guard-spork', '>= 0.2.1'
13
- gem 'spork', '>= 0.9.0.rc8'
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` are still currently available but will be removed from future versions.
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
@@ -1,174 +1,79 @@
1
- require 'rest-client'
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
- class << self
26
- attr_writer :server_url, :client_name, :connection, :host, :port, :scheme,
27
- :key_file, :raw_key, :chef_version, :url_path
28
-
29
- def default_server_url
30
- @default_server_url ||= "http://localhost:4000"
31
- end
32
-
33
- def default_url_path
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
- def client_name
70
- @client_name
71
- end
72
-
73
- def key_file
74
- @key_file
75
- end
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
- def mock
133
- Spice::Mock.setup_mock_client
134
- end
51
+ def mock
52
+ Spice::Mock.setup_mock_client
53
+ end
135
54
 
136
- # def autoconfigure!(path=nil)
137
- # path ||= "~/.chef/"
138
- # knife = File.exist?("~/.chef/knife.rb") && File.expand_path(path + "~/.chef/knife.rb")
139
- # client = File.exist?("/etc/chef/client.rb") && File.expand_path("/etc/chef/client.rb")
140
- #
141
- # if knife
142
- # raw_config = IO.read(knife)
143
- # elsif
144
- # raw_config = IO.read(client)
145
- # end
146
- #
147
- # @values = {}
148
- # raw_config.each_line do |line|
149
- # if line =~ /^chef_server_url.*/
150
- # @values[:chef_server_url] = parse_line(line)
151
- # elsif line =~ /^node_name.*/
152
- # @values[:node_name] = parse_line(line)
153
- # elsif line =~ /^client_key.*/
154
- # @values[:client_key] = parse_line(line)
155
- # end
156
- # end
157
- # end
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
@@ -1,42 +1,29 @@
1
+ require 'spice/persistence'
2
+
1
3
  module Spice
2
- class Client < Spice::Chef
3
- def self.all(options={})
4
- if options[:complete]
5
- results = []
6
- connection.get("clients").map { |c| c[0] }.each do |client|
7
- results << connection.get("/clients/#{client}")
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
- def self.update(options={})
31
- raise ArgumentError, "Option :name must be present" unless options[:name]
32
- name = options.delete(:name)
33
- connection.put("/clients/#{name}", options)
34
- end
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
- def self.delete(options={})
37
- raise ArgumentError, "Option :name must be present" unless options[:name]
38
- name = options.delete(:name)
39
- connection.delete("/clients/#{name}", options)
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
@@ -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