chef 0.9.14 → 0.9.16

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