chef 0.9.14 → 0.9.16
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/lib/chef/application.rb +4 -4
- data/lib/chef/application/knife.rb +0 -1
- data/lib/chef/checksum_cache.rb +25 -9
- data/lib/chef/data_bag.rb +33 -25
- data/lib/chef/data_bag_item.rb +39 -26
- data/lib/chef/exceptions.rb +7 -4
- data/lib/chef/knife.rb +6 -2
- data/lib/chef/knife/bootstrap.rb +43 -1
- data/lib/chef/knife/bootstrap/archlinux-gems.erb +2 -1
- data/lib/chef/knife/bootstrap/centos5-gems.erb +15 -6
- data/lib/chef/knife/bootstrap/fedora13-gems.erb +4 -3
- data/lib/chef/knife/bootstrap/ubuntu10.04-apt.erb +2 -2
- data/lib/chef/knife/bootstrap/ubuntu10.04-gems.erb +4 -2
- data/lib/chef/knife/ssh.rb +8 -0
- data/lib/chef/mixin/language.rb +19 -10
- data/lib/chef/rest.rb +7 -7
- data/lib/chef/rest/auth_credentials.rb +8 -15
- data/lib/chef/rest/rest_request.rb +16 -0
- data/lib/chef/version.rb +1 -1
- metadata +306 -382
data/lib/chef/application.rb
CHANGED
@@ -35,16 +35,16 @@ class Chef::Application
|
|
35
35
|
end
|
36
36
|
|
37
37
|
unless RUBY_PLATFORM =~ /mswin|mingw32|windows/
|
38
|
+
trap("QUIT") do
|
39
|
+
Chef::Log.info("SIGQUIT received, call stack:\n " + caller.join("\n "))
|
40
|
+
end
|
41
|
+
|
38
42
|
trap("HUP") do
|
39
43
|
Chef::Log.info("SIGHUP received, reconfiguring")
|
40
44
|
reconfigure
|
41
45
|
end
|
42
46
|
end
|
43
47
|
|
44
|
-
at_exit do
|
45
|
-
# tear down the logger
|
46
|
-
end
|
47
|
-
|
48
48
|
# Always switch to a readable directory. Keeps subsequent Dir.chdir() {}
|
49
49
|
# from failing due to permissions when launched as a less privileged user.
|
50
50
|
end
|
data/lib/chef/checksum_cache.rb
CHANGED
@@ -8,9 +8,9 @@
|
|
8
8
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
9
9
|
# you may not use this file except in compliance with the License.
|
10
10
|
# You may obtain a copy of the License at
|
11
|
-
#
|
11
|
+
#
|
12
12
|
# http://www.apache.org/licenses/LICENSE-2.0
|
13
|
-
#
|
13
|
+
#
|
14
14
|
# Unless required by applicable law or agreed to in writing, software
|
15
15
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
16
16
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
@@ -27,28 +27,28 @@ require 'chef/mixin/convert_to_class_name'
|
|
27
27
|
require 'singleton'
|
28
28
|
require 'moneta'
|
29
29
|
|
30
|
-
class Chef
|
30
|
+
class Chef
|
31
31
|
class ChecksumCache
|
32
32
|
include Chef::Mixin::ConvertToClassName
|
33
33
|
include ::Singleton
|
34
|
-
|
34
|
+
|
35
35
|
attr_reader :moneta
|
36
|
-
|
36
|
+
|
37
37
|
def initialize(*args)
|
38
38
|
self.reset!(*args)
|
39
39
|
end
|
40
|
-
|
40
|
+
|
41
41
|
def reset!(backend=nil, options=nil)
|
42
42
|
backend ||= Chef::Config[:cache_type]
|
43
43
|
options ||= Chef::Config[:cache_options]
|
44
|
-
|
44
|
+
|
45
45
|
begin
|
46
46
|
require "moneta/#{convert_to_snake_case(backend, 'Moneta')}"
|
47
47
|
rescue LoadError => e
|
48
48
|
Chef::Log.fatal("Could not load Moneta back end #{backend.inspect}")
|
49
49
|
raise e
|
50
50
|
end
|
51
|
-
|
51
|
+
|
52
52
|
@moneta = Moneta.const_get(backend).new(options)
|
53
53
|
end
|
54
54
|
|
@@ -112,7 +112,7 @@ class Chef
|
|
112
112
|
end
|
113
113
|
|
114
114
|
def lookup_checksum(key, fstat)
|
115
|
-
cached =
|
115
|
+
cached = fetch(key)
|
116
116
|
if cached && file_unchanged?(cached, fstat)
|
117
117
|
validate_checksum(key)
|
118
118
|
cached["checksum"]
|
@@ -146,6 +146,22 @@ class Chef
|
|
146
146
|
|
147
147
|
private
|
148
148
|
|
149
|
+
def fetch(key)
|
150
|
+
@moneta.fetch(key)
|
151
|
+
rescue ArgumentError => e
|
152
|
+
Log.warn "Error loading cached checksum for key #{key.inspect}"
|
153
|
+
Log.warn(e)
|
154
|
+
repair_checksum_cache
|
155
|
+
nil
|
156
|
+
end
|
157
|
+
|
158
|
+
def repair_checksum_cache
|
159
|
+
Chef::Log.info("Removing invalid checksum cache files")
|
160
|
+
Dir["#{Chef::Config[:cache_options][:path]}/*"].each do |file_path|
|
161
|
+
File.unlink(file_path) unless File.size?(file_path)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
149
165
|
def file_unchanged?(cached, fstat)
|
150
166
|
cached["mtime"].to_f == fstat.mtime.to_f
|
151
167
|
end
|
data/lib/chef/data_bag.rb
CHANGED
@@ -8,9 +8,9 @@
|
|
8
8
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
9
9
|
# you may not use this file except in compliance with the License.
|
10
10
|
# You may obtain a copy of the License at
|
11
|
-
#
|
11
|
+
#
|
12
12
|
# http://www.apache.org/licenses/LICENSE-2.0
|
13
|
-
#
|
13
|
+
#
|
14
14
|
# Unless required by applicable law or agreed to in writing, software
|
15
15
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
16
16
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
@@ -28,19 +28,21 @@ require 'extlib'
|
|
28
28
|
require 'chef/json_compat'
|
29
29
|
|
30
30
|
class Chef
|
31
|
-
class DataBag
|
32
|
-
|
31
|
+
class DataBag
|
32
|
+
|
33
33
|
include Chef::Mixin::FromFile
|
34
34
|
include Chef::Mixin::ParamsValidate
|
35
35
|
include Chef::IndexQueue::Indexable
|
36
|
-
|
36
|
+
|
37
|
+
VALID_NAME = /^[\-[:alnum:]_]+$/
|
38
|
+
|
37
39
|
DESIGN_DOCUMENT = {
|
38
40
|
"version" => 2,
|
39
41
|
"language" => "javascript",
|
40
42
|
"views" => {
|
41
43
|
"all" => {
|
42
44
|
"map" => <<-EOJS
|
43
|
-
function(doc) {
|
45
|
+
function(doc) {
|
44
46
|
if (doc.chef_type == "data_bag") {
|
45
47
|
emit(doc.name, doc);
|
46
48
|
}
|
@@ -49,7 +51,7 @@ class Chef
|
|
49
51
|
},
|
50
52
|
"all_id" => {
|
51
53
|
"map" => <<-EOJS
|
52
|
-
function(doc) {
|
54
|
+
function(doc) {
|
53
55
|
if (doc.chef_type == "data_bag") {
|
54
56
|
emit(doc.name, doc.name);
|
55
57
|
}
|
@@ -68,21 +70,27 @@ class Chef
|
|
68
70
|
}
|
69
71
|
}
|
70
72
|
|
73
|
+
def self.validate_name!(name)
|
74
|
+
unless name =~ VALID_NAME
|
75
|
+
raise Exceptions::InvalidDataBagName, "DataBags must have a name matching #{VALID_NAME.inspect}, you gave #{name.inspect}"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
71
79
|
attr_accessor :couchdb_rev, :couchdb_id, :couchdb
|
72
|
-
|
80
|
+
|
73
81
|
# Create a new Chef::DataBag
|
74
82
|
def initialize(couchdb=nil)
|
75
|
-
@name = ''
|
83
|
+
@name = ''
|
76
84
|
@couchdb_rev = nil
|
77
85
|
@couchdb_id = nil
|
78
86
|
@couchdb = (couchdb || Chef::CouchDB.new)
|
79
87
|
end
|
80
88
|
|
81
|
-
def name(arg=nil)
|
89
|
+
def name(arg=nil)
|
82
90
|
set_or_return(
|
83
91
|
:name,
|
84
92
|
arg,
|
85
|
-
:regex =>
|
93
|
+
:regex => VALID_NAME
|
86
94
|
)
|
87
95
|
end
|
88
96
|
|
@@ -96,7 +104,7 @@ class Chef
|
|
96
104
|
result
|
97
105
|
end
|
98
106
|
|
99
|
-
# Serialize this object as a hash
|
107
|
+
# Serialize this object as a hash
|
100
108
|
def to_json(*a)
|
101
109
|
to_hash.to_json(*a)
|
102
110
|
end
|
@@ -108,7 +116,7 @@ class Chef
|
|
108
116
|
def self.chef_server_rest
|
109
117
|
Chef::REST.new(Chef::Config[:chef_server_url])
|
110
118
|
end
|
111
|
-
|
119
|
+
|
112
120
|
# Create a Chef::Role from JSON
|
113
121
|
def self.json_create(o)
|
114
122
|
bag = new
|
@@ -118,7 +126,7 @@ class Chef
|
|
118
126
|
bag.index_id = bag.couchdb_id
|
119
127
|
bag
|
120
128
|
end
|
121
|
-
|
129
|
+
|
122
130
|
# List all the Chef::DataBag objects in the CouchDB. If inflate is set to true, you will get
|
123
131
|
# the full list of all Roles, fully inflated.
|
124
132
|
def self.cdb_list(inflate=false, couchdb=nil)
|
@@ -126,7 +134,7 @@ class Chef
|
|
126
134
|
lookup = (inflate ? "value" : "key")
|
127
135
|
rs["rows"].collect { |r| r[lookup] }
|
128
136
|
end
|
129
|
-
|
137
|
+
|
130
138
|
def self.list(inflate=false)
|
131
139
|
if inflate
|
132
140
|
# Can't search for all data bags like other objects, fall back to N+1 :(
|
@@ -138,17 +146,17 @@ class Chef
|
|
138
146
|
Chef::REST.new(Chef::Config[:chef_server_url]).get_rest("data")
|
139
147
|
end
|
140
148
|
end
|
141
|
-
|
149
|
+
|
142
150
|
# Load a Data Bag by name from CouchDB
|
143
151
|
def self.cdb_load(name, couchdb=nil)
|
144
152
|
(couchdb || Chef::CouchDB.new).load("data_bag", name)
|
145
153
|
end
|
146
|
-
|
154
|
+
|
147
155
|
# Load a Data Bag by name via the RESTful API
|
148
156
|
def self.load(name)
|
149
157
|
Chef::REST.new(Chef::Config[:chef_server_url]).get_rest("data/#{name}")
|
150
158
|
end
|
151
|
-
|
159
|
+
|
152
160
|
# Remove this Data Bag from CouchDB
|
153
161
|
def cdb_destroy
|
154
162
|
removed = @couchdb.delete("data_bag", @name, @couchdb_rev)
|
@@ -159,17 +167,17 @@ class Chef
|
|
159
167
|
end
|
160
168
|
removed
|
161
169
|
end
|
162
|
-
|
170
|
+
|
163
171
|
def destroy
|
164
172
|
chef_server_rest.delete_rest("data/#{@name}")
|
165
173
|
end
|
166
|
-
|
174
|
+
|
167
175
|
# Save this Data Bag to the CouchDB
|
168
176
|
def cdb_save
|
169
177
|
results = @couchdb.store("data_bag", @name, self)
|
170
178
|
@couchdb_rev = results["rev"]
|
171
179
|
end
|
172
|
-
|
180
|
+
|
173
181
|
# Save the Data Bag via RESTful API
|
174
182
|
def save
|
175
183
|
begin
|
@@ -180,7 +188,7 @@ class Chef
|
|
180
188
|
end
|
181
189
|
self
|
182
190
|
end
|
183
|
-
|
191
|
+
|
184
192
|
#create a data bag via RESTful API
|
185
193
|
def create
|
186
194
|
chef_server_rest.post_rest("data", self)
|
@@ -190,7 +198,7 @@ class Chef
|
|
190
198
|
# List all the items in this Bag from CouchDB
|
191
199
|
# The self.load method does this through the REST API
|
192
200
|
def list(inflate=false)
|
193
|
-
rs = nil
|
201
|
+
rs = nil
|
194
202
|
if inflate
|
195
203
|
rs = @couchdb.get_view("data_bags", "entries", :include_docs => true, :startkey => @name, :endkey => @name)
|
196
204
|
rs["rows"].collect { |r| r["doc"] }
|
@@ -199,12 +207,12 @@ class Chef
|
|
199
207
|
rs["rows"].collect { |r| r["value"] }
|
200
208
|
end
|
201
209
|
end
|
202
|
-
|
210
|
+
|
203
211
|
# Set up our CouchDB design document
|
204
212
|
def self.create_design_document(couchdb=nil)
|
205
213
|
(couchdb || Chef::CouchDB.new).create_design_document("data_bags", DESIGN_DOCUMENT)
|
206
214
|
end
|
207
|
-
|
215
|
+
|
208
216
|
# As a string
|
209
217
|
def to_s
|
210
218
|
"data_bag[#{@name}]"
|
data/lib/chef/data_bag_item.rb
CHANGED
@@ -8,9 +8,9 @@
|
|
8
8
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
9
9
|
# you may not use this file except in compliance with the License.
|
10
10
|
# You may obtain a copy of the License at
|
11
|
-
#
|
11
|
+
#
|
12
12
|
# http://www.apache.org/licenses/LICENSE-2.0
|
13
|
-
#
|
13
|
+
#
|
14
14
|
# Unless required by applicable law or agreed to in writing, software
|
15
15
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
16
16
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
@@ -33,18 +33,20 @@ class Chef
|
|
33
33
|
class DataBagItem
|
34
34
|
|
35
35
|
extend Forwardable
|
36
|
-
|
36
|
+
|
37
37
|
include Chef::Mixin::FromFile
|
38
38
|
include Chef::Mixin::ParamsValidate
|
39
39
|
include Chef::IndexQueue::Indexable
|
40
|
-
|
40
|
+
|
41
|
+
VALID_ID = /^[\-[:alnum:]_]+$/
|
42
|
+
|
41
43
|
DESIGN_DOCUMENT = {
|
42
44
|
"version" => 1,
|
43
45
|
"language" => "javascript",
|
44
46
|
"views" => {
|
45
47
|
"all" => {
|
46
48
|
"map" => <<-EOJS
|
47
|
-
function(doc) {
|
49
|
+
function(doc) {
|
48
50
|
if (doc.chef_type == "data_bag_item") {
|
49
51
|
emit(doc.name, doc);
|
50
52
|
}
|
@@ -53,7 +55,7 @@ class Chef
|
|
53
55
|
},
|
54
56
|
"all_id" => {
|
55
57
|
"map" => <<-EOJS
|
56
|
-
function(doc) {
|
58
|
+
function(doc) {
|
57
59
|
if (doc.chef_type == "data_bag_item") {
|
58
60
|
emit(doc.name, doc.name);
|
59
61
|
}
|
@@ -63,12 +65,18 @@ class Chef
|
|
63
65
|
}
|
64
66
|
}
|
65
67
|
|
68
|
+
def self.validate_id!(id_str)
|
69
|
+
if id_str.nil? || ( id_str !~ VALID_ID )
|
70
|
+
raise Exceptions::InvalidDataBagItemID, "Data Bag items must have an id matching #{VALID_ID.inspect}, you gave: #{id_str.inspect}"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
66
74
|
# Define all Hash's instance methods as delegating to @raw_data
|
67
75
|
def_delegators(:@raw_data, *(Hash.instance_methods - Object.instance_methods))
|
68
76
|
|
69
77
|
attr_accessor :couchdb_rev, :couchdb_id, :couchdb
|
70
78
|
attr_reader :raw_data
|
71
|
-
|
79
|
+
|
72
80
|
# Create a new Chef::DataBagItem
|
73
81
|
def initialize(couchdb=nil)
|
74
82
|
@couchdb_rev = nil
|
@@ -79,25 +87,30 @@ class Chef
|
|
79
87
|
end
|
80
88
|
|
81
89
|
def chef_server_rest
|
82
|
-
Chef::REST.new(Chef::Config[:chef_server_url])
|
90
|
+
Chef::REST.new(Chef::Config[:chef_server_url])
|
83
91
|
end
|
84
92
|
|
85
93
|
def self.chef_server_rest
|
86
|
-
Chef::REST.new(Chef::Config[:chef_server_url])
|
94
|
+
Chef::REST.new(Chef::Config[:chef_server_url])
|
87
95
|
end
|
88
96
|
|
89
97
|
def raw_data
|
90
98
|
@raw_data
|
91
99
|
end
|
92
100
|
|
101
|
+
def validate_id!(id_str)
|
102
|
+
self.class.validate_id!(id_str)
|
103
|
+
end
|
104
|
+
|
93
105
|
def raw_data=(new_data)
|
94
|
-
|
95
|
-
|
96
|
-
|
106
|
+
unless new_data.respond_to?(:[]) && new_data.respond_to?(:keys)
|
107
|
+
raise Exceptions::ValidationFailed, "Data Bag Items must contain a Hash or Mash!"
|
108
|
+
end
|
109
|
+
validate_id!(new_data["id"])
|
97
110
|
@raw_data = new_data
|
98
111
|
end
|
99
112
|
|
100
|
-
def data_bag(arg=nil)
|
113
|
+
def data_bag(arg=nil)
|
101
114
|
set_or_return(
|
102
115
|
:data_bag,
|
103
116
|
arg,
|
@@ -112,7 +125,7 @@ class Chef
|
|
112
125
|
def object_name
|
113
126
|
raise Exceptions::ValidationFailed, "You must have an 'id' or :id key in the raw data" unless raw_data.has_key?('id')
|
114
127
|
raise Exceptions::ValidationFailed, "You must have declared what bag this item belongs to!" unless data_bag
|
115
|
-
|
128
|
+
|
116
129
|
id = raw_data['id']
|
117
130
|
"data_bag_item_#{data_bag}_#{id}"
|
118
131
|
end
|
@@ -129,7 +142,7 @@ class Chef
|
|
129
142
|
result
|
130
143
|
end
|
131
144
|
|
132
|
-
# Serialize this object as a hash
|
145
|
+
# Serialize this object as a hash
|
133
146
|
def to_json(*a)
|
134
147
|
result = {
|
135
148
|
"name" => self.object_name,
|
@@ -157,7 +170,7 @@ class Chef
|
|
157
170
|
o.delete("json_class")
|
158
171
|
o.delete("name")
|
159
172
|
if o.has_key?("_rev")
|
160
|
-
bag_item.couchdb_rev = o["_rev"]
|
173
|
+
bag_item.couchdb_rev = o["_rev"]
|
161
174
|
o.delete("_rev")
|
162
175
|
end
|
163
176
|
if o.has_key?("_id")
|
@@ -173,7 +186,7 @@ class Chef
|
|
173
186
|
def self.cdb_load(data_bag, name, couchdb=nil)
|
174
187
|
(couchdb || Chef::CouchDB.new).load("data_bag_item", object_name(data_bag, name))
|
175
188
|
end
|
176
|
-
|
189
|
+
|
177
190
|
# Load a Data Bag Item by name via RESTful API
|
178
191
|
def self.load(data_bag, name)
|
179
192
|
item = Chef::REST.new(Chef::Config[:chef_server_url]).get_rest("data/#{data_bag}/#{name}")
|
@@ -185,22 +198,22 @@ class Chef
|
|
185
198
|
item
|
186
199
|
end
|
187
200
|
end
|
188
|
-
|
201
|
+
|
189
202
|
# Remove this Data Bag Item from CouchDB
|
190
203
|
def cdb_destroy
|
191
204
|
Chef::Log.debug "destroying data bag item: #{self.inspect}"
|
192
205
|
@couchdb.delete("data_bag_item", object_name, @couchdb_rev)
|
193
206
|
end
|
194
|
-
|
207
|
+
|
195
208
|
def destroy(data_bag=data_bag, databag_item=name)
|
196
209
|
chef_server_rest.delete_rest("data/#{data_bag}/#{databag_item}")
|
197
210
|
end
|
198
|
-
|
211
|
+
|
199
212
|
# Save this Data Bag Item to CouchDB
|
200
213
|
def cdb_save
|
201
214
|
@couchdb_rev = @couchdb.store("data_bag_item", object_name, self)["rev"]
|
202
215
|
end
|
203
|
-
|
216
|
+
|
204
217
|
# Save this Data Bag Item via RESTful API
|
205
218
|
def save(item_id=@raw_data['id'])
|
206
219
|
r = chef_server_rest
|
@@ -208,17 +221,17 @@ class Chef
|
|
208
221
|
r.put_rest("data/#{data_bag}/#{item_id}", @raw_data)
|
209
222
|
rescue Net::HTTPServerException => e
|
210
223
|
raise e unless e.response.code == "404"
|
211
|
-
r.post_rest("data/#{data_bag}", @raw_data)
|
224
|
+
r.post_rest("data/#{data_bag}", @raw_data)
|
212
225
|
end
|
213
226
|
self
|
214
227
|
end
|
215
|
-
|
228
|
+
|
216
229
|
# Create this Data Bag Item via RESTful API
|
217
230
|
def create
|
218
|
-
chef_server_rest.post_rest("data/#{data_bag}", @raw_data)
|
231
|
+
chef_server_rest.post_rest("data/#{data_bag}", @raw_data)
|
219
232
|
self
|
220
|
-
end
|
221
|
-
|
233
|
+
end
|
234
|
+
|
222
235
|
# Set up our CouchDB design document
|
223
236
|
def self.create_design_document(couchdb=nil)
|
224
237
|
(couchdb || Chef::CouchDB.new).create_design_document("data_bag_items", DESIGN_DOCUMENT)
|