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.
@@ -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
@@ -96,7 +96,6 @@ class Chef::Application::Knife < Chef::Application
96
96
  :description => "Accept default values for all questions"
97
97
 
98
98
  option :print_after,
99
- :short => "-p",
100
99
  :long => "--print-after",
101
100
  :description => "Show the data after a destructive operation"
102
101
 
@@ -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 = @moneta.fetch(key)
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 => /^[\-[:alnum:]_]+$/
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}]"
@@ -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
- raise Exceptions::ValidationFailed, "Data Bag Items must contain a Hash or Mash!" unless new_data.kind_of?(Hash) || new_data.kind_of?(Mash)
95
- raise Exceptions::ValidationFailed, "Data Bag Items must have an id key in the hash! #{new_data.inspect}" unless new_data.has_key?("id")
96
- raise Exceptions::ValidationFailed, "Data Bag Item id does not match alphanumeric/-/_!" unless new_data["id"] =~ /^[\-[:alnum:]_]+$/
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)