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 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