chef 0.9.14 → 0.9.16
Sign up to get free protection for your applications and to get access to all the features.
- 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)
|