cheffish 14.0.13 → 16.0.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +3 -9
- data/Rakefile +1 -1
- data/cheffish.gemspec +3 -3
- data/lib/chef/resource/chef_acl.rb +17 -14
- data/lib/chef/resource/chef_client.rb +3 -3
- data/lib/chef/resource/chef_container.rb +4 -4
- data/lib/chef/resource/chef_data_bag.rb +3 -3
- data/lib/chef/resource/chef_data_bag_item.rb +13 -12
- data/lib/chef/resource/chef_environment.rb +2 -2
- data/lib/chef/resource/chef_group.rb +2 -2
- data/lib/chef/resource/chef_mirror.rb +6 -5
- data/lib/chef/resource/chef_node.rb +2 -2
- data/lib/chef/resource/chef_organization.rb +3 -3
- data/lib/chef/resource/chef_resolved_cookbooks.rb +5 -3
- data/lib/chef/resource/chef_role.rb +6 -2
- data/lib/chef/resource/chef_user.rb +2 -2
- data/lib/chef/resource/private_key.rb +11 -11
- data/lib/chef/resource/public_key.rb +5 -4
- data/lib/cheffish.rb +1 -0
- data/lib/cheffish/base_resource.rb +13 -11
- data/lib/cheffish/basic_chef_client.rb +4 -5
- data/lib/cheffish/chef_actor_base.rb +3 -2
- data/lib/cheffish/chef_run.rb +5 -6
- data/lib/cheffish/chef_run_listener.rb +1 -3
- data/lib/cheffish/key_formatter.rb +5 -13
- data/lib/cheffish/merged_config.rb +2 -2
- data/lib/cheffish/node_properties.rb +7 -3
- data/lib/cheffish/recipe_dsl.rb +2 -2
- data/lib/cheffish/rspec/chef_run_support.rb +2 -2
- data/lib/cheffish/rspec/matchers/have_updated.rb +5 -5
- data/lib/cheffish/rspec/recipe_run_wrapper.rb +2 -2
- data/lib/cheffish/rspec/repository_support.rb +1 -0
- data/lib/cheffish/version.rb +1 -1
- data/spec/functional/fingerprint_spec.rb +8 -6
- data/spec/integration/chef_acl_spec.rb +28 -20
- data/spec/integration/chef_group_spec.rb +2 -2
- data/spec/integration/chef_node_spec.rb +2 -2
- data/spec/integration/chef_role_spec.rb +2 -2
- metadata +7 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2680862bc4ccaf4bb8516f6242dc1fe04afc77592d215ed897a7dcc4f925fa63
|
4
|
+
data.tar.gz: 710ca780d8975283f9a1e202e3055257af74238624a97ba3d6bc6c536d4f88aa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b041113f8da4686453be3d9c84fa5dd205feb519fa5e2f3538252bedc18e4701f226452e24ca748d1905958039e8b4606b883b3e9c8ac05439f981b047ca5802
|
7
|
+
data.tar.gz: ab1425571b89f8fbe8bad89e4d4cdcbe617548c2adb2dd750242855810fbdb3bfcd350b99a66741aac785a2122f0deb4b8fbf280315b5e356577533ce1b7acec
|
data/Gemfile
CHANGED
@@ -3,7 +3,7 @@ source "https://rubygems.org"
|
|
3
3
|
gemspec
|
4
4
|
|
5
5
|
group :development do
|
6
|
-
gem "chefstyle",
|
6
|
+
gem "chefstyle", "1.2.1"
|
7
7
|
gem "rake"
|
8
8
|
gem "rspec", "~> 3.0"
|
9
9
|
end
|
@@ -14,8 +14,8 @@ if ENV["GEMFILE_MOD"]
|
|
14
14
|
instance_eval(ENV["GEMFILE_MOD"])
|
15
15
|
else
|
16
16
|
group :development do
|
17
|
-
gem "chef", "~>
|
18
|
-
gem "ohai", "~>
|
17
|
+
gem "chef", "~> 16"
|
18
|
+
gem "ohai", "~> 16"
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
@@ -31,9 +31,3 @@ group :debug do
|
|
31
31
|
gem "pry-stack_explorer"
|
32
32
|
gem "rb-readline"
|
33
33
|
end
|
34
|
-
|
35
|
-
instance_eval(ENV["GEMFILE_MOD"]) if ENV["GEMFILE_MOD"]
|
36
|
-
|
37
|
-
# If you want to load debugging tools into the bundle exec sandbox,
|
38
|
-
# add these additional dependencies into Gemfile.local
|
39
|
-
eval_gemfile(__FILE__ + ".local") if File.exist?(__FILE__ + ".local")
|
data/Rakefile
CHANGED
data/cheffish.gemspec
CHANGED
@@ -6,15 +6,15 @@ Gem::Specification.new do |s|
|
|
6
6
|
s.version = Cheffish::VERSION
|
7
7
|
s.platform = Gem::Platform::RUBY
|
8
8
|
s.license = "Apache-2.0"
|
9
|
-
s.summary = "A set of Chef resources for configuring Chef."
|
9
|
+
s.summary = "A set of Chef resources for configuring Chef Infra."
|
10
10
|
s.description = s.summary
|
11
11
|
s.author = "Chef Software Inc."
|
12
12
|
s.email = "oss@chef.io"
|
13
13
|
s.homepage = "https://github.com/chef/cheffish"
|
14
14
|
|
15
|
-
s.required_ruby_version = ">= 2.
|
15
|
+
s.required_ruby_version = ">= 2.6.0"
|
16
16
|
|
17
|
-
s.add_dependency "chef-zero", "
|
17
|
+
s.add_dependency "chef-zero", ">= 14.0"
|
18
18
|
s.add_dependency "net-ssh"
|
19
19
|
|
20
20
|
s.bindir = "bin"
|
@@ -2,12 +2,12 @@ require_relative "../../cheffish"
|
|
2
2
|
require_relative "../../cheffish/base_resource"
|
3
3
|
require "chef/chef_fs/data_handler/acl_data_handler"
|
4
4
|
require "chef/chef_fs/parallelizer"
|
5
|
-
require "uri"
|
5
|
+
require "uri" unless defined?(URI)
|
6
6
|
|
7
7
|
class Chef
|
8
8
|
class Resource
|
9
9
|
class ChefAcl < Cheffish::BaseResource
|
10
|
-
|
10
|
+
provides :chef_acl
|
11
11
|
|
12
12
|
# Path of the thing being secured, e.g. nodes, nodes/*, nodes/mynode,
|
13
13
|
# */*, **, roles/base, data/secrets, cookbooks/apache2, /users/*,
|
@@ -75,7 +75,7 @@ class Chef
|
|
75
75
|
end
|
76
76
|
end
|
77
77
|
|
78
|
-
action_class
|
78
|
+
action_class do
|
79
79
|
# Update the ACL if necessary.
|
80
80
|
def create_acl(path)
|
81
81
|
changed = false
|
@@ -99,6 +99,7 @@ class Chef
|
|
99
99
|
# NOTE: if superusers exist, this should turn into a warning.
|
100
100
|
raise "chef_acl attempted to remove all actors from GRANT! I'm sorry Dave, I can't let you remove access to an object with no hope of recovery."
|
101
101
|
end
|
102
|
+
|
102
103
|
modify[differences] ||= {}
|
103
104
|
modify[differences][permission] = desired_json
|
104
105
|
end
|
@@ -107,7 +108,7 @@ class Chef
|
|
107
108
|
if modify.size > 0
|
108
109
|
changed = true
|
109
110
|
description = [ "update acl #{path} at #{rest_url(path)}" ] + modify.flat_map do |diffs, permissions|
|
110
|
-
diffs.map { |diff| " #{permissions.keys.join(
|
111
|
+
diffs.map { |diff| " #{permissions.keys.join(", ")}:#{diff}" }
|
111
112
|
end
|
112
113
|
converge_by description do
|
113
114
|
modify.values.each do |permissions|
|
@@ -127,11 +128,13 @@ class Chef
|
|
127
128
|
children, _error = list(path, "*")
|
128
129
|
Chef::ChefFS::Parallelizer.parallel_do(children) do |child|
|
129
130
|
next if child.split("/")[-1] == "containers"
|
131
|
+
|
130
132
|
create_acl(child)
|
131
133
|
end
|
132
134
|
# containers mess up our descent, so we do them last
|
133
135
|
Chef::ChefFS::Parallelizer.parallel_do(children) do |child|
|
134
136
|
next if child.split("/")[-1] != "containers"
|
137
|
+
|
135
138
|
create_acl(child)
|
136
139
|
end
|
137
140
|
|
@@ -141,10 +144,10 @@ class Chef
|
|
141
144
|
# Get the current ACL for the given path
|
142
145
|
def current_acl(acl_path)
|
143
146
|
@current_acls ||= {}
|
144
|
-
|
147
|
+
unless @current_acls.key?(acl_path)
|
145
148
|
@current_acls[acl_path] = begin
|
146
149
|
rest.get(rest_url(acl_path))
|
147
|
-
rescue Net::
|
150
|
+
rescue Net::HTTPClientException => e
|
148
151
|
unless e.response.code == "404" && new_resource.path.split("/").any? { |p| p == "*" }
|
149
152
|
raise
|
150
153
|
end
|
@@ -252,8 +255,7 @@ class Chef
|
|
252
255
|
end
|
253
256
|
end
|
254
257
|
|
255
|
-
def load_current_resource
|
256
|
-
end
|
258
|
+
def load_current_resource; end
|
257
259
|
|
258
260
|
#
|
259
261
|
# Matches chef_acl paths like nodes, nodes/*.
|
@@ -270,7 +272,7 @@ class Chef
|
|
270
272
|
def match_paths(path)
|
271
273
|
# Turn multiple slashes into one
|
272
274
|
# nodes//x -> nodes/x
|
273
|
-
path = path.gsub(/
|
275
|
+
path = path.gsub(%r{[/]+}, "/")
|
274
276
|
# If it's absolute, start the matching with /. If it's relative, start with '' (relative root).
|
275
277
|
if path[0] == "/"
|
276
278
|
matches = [ "/" ]
|
@@ -305,6 +307,7 @@ class Chef
|
|
305
307
|
if parts[0..index - 1].all? { |p| p != "*" }
|
306
308
|
raise error
|
307
309
|
end
|
310
|
+
|
308
311
|
[]
|
309
312
|
else
|
310
313
|
found
|
@@ -421,21 +424,21 @@ class Chef
|
|
421
424
|
when 1
|
422
425
|
# /organizations/*, /users/*, roles/*, nodes/*, etc.
|
423
426
|
results, error = rest_list(path)
|
424
|
-
|
427
|
+
unless error
|
425
428
|
results = results.map { |result| ::File.join(path, result) }
|
426
429
|
end
|
427
430
|
|
428
431
|
when 2
|
429
432
|
# /organizations/NAME/*
|
430
433
|
results, error = rest_list(::File.join(path, "containers"))
|
431
|
-
|
434
|
+
unless error
|
432
435
|
results = results.map { |result| ::File.join(path, result) }
|
433
436
|
end
|
434
437
|
|
435
438
|
when 3
|
436
439
|
# /organizations/NAME/TYPE/*
|
437
440
|
results, error = rest_list(path)
|
438
|
-
|
441
|
+
unless error
|
439
442
|
results = results.map { |result| ::File.join(path, result) }
|
440
443
|
end
|
441
444
|
end
|
@@ -466,9 +469,9 @@ class Chef
|
|
466
469
|
end
|
467
470
|
|
468
471
|
def rest_list(path)
|
469
|
-
|
472
|
+
# All our rest lists are hashes where the keys are the names
|
470
473
|
[ rest.get(rest_url(path)).keys, nil ]
|
471
|
-
rescue Net::
|
474
|
+
rescue Net::HTTPClientException => e
|
472
475
|
if e.response.code == "405" || e.response.code == "404"
|
473
476
|
parts = path.split("/").select { |p| p != "" }.to_a
|
474
477
|
|
@@ -4,7 +4,7 @@ require_relative "../../cheffish/chef_actor_base"
|
|
4
4
|
class Chef
|
5
5
|
class Resource
|
6
6
|
class ChefClient < Cheffish::ChefActorBase
|
7
|
-
|
7
|
+
provides :chef_client
|
8
8
|
|
9
9
|
# Client attributes
|
10
10
|
property :chef_client_name, Cheffish::NAME_REGEX, name_property: true
|
@@ -18,7 +18,7 @@ class Chef
|
|
18
18
|
|
19
19
|
# Output public key (if so desired)
|
20
20
|
property :output_key_path, String
|
21
|
-
property :output_key_format, Symbol, default: :openssh, equal_to:
|
21
|
+
property :output_key_format, Symbol, default: :openssh, equal_to: %i{pem der openssh}
|
22
22
|
|
23
23
|
# Proc that runs just before the resource executes. Called with (resource)
|
24
24
|
def before(&block)
|
@@ -38,7 +38,7 @@ class Chef
|
|
38
38
|
delete_actor
|
39
39
|
end
|
40
40
|
|
41
|
-
action_class
|
41
|
+
action_class do
|
42
42
|
def actor_type
|
43
43
|
"client"
|
44
44
|
end
|
@@ -5,12 +5,12 @@ require "chef/chef_fs/data_handler/container_data_handler"
|
|
5
5
|
class Chef
|
6
6
|
class Resource
|
7
7
|
class ChefContainer < Cheffish::BaseResource
|
8
|
-
|
8
|
+
provides :chef_container
|
9
9
|
|
10
10
|
property :chef_container_name, Cheffish::NAME_REGEX, name_property: true
|
11
11
|
|
12
12
|
action :create do
|
13
|
-
|
13
|
+
unless @current_exists
|
14
14
|
converge_by "create container #{new_resource.chef_container_name} at #{rest.url}" do
|
15
15
|
rest.post("containers", normalize_for_post(new_json))
|
16
16
|
end
|
@@ -25,10 +25,10 @@ class Chef
|
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
|
-
action_class
|
28
|
+
action_class do
|
29
29
|
def load_current_resource
|
30
30
|
@current_exists = rest.get("containers/#{new_resource.chef_container_name}")
|
31
|
-
rescue Net::
|
31
|
+
rescue Net::HTTPClientException => e
|
32
32
|
if e.response.code == "404"
|
33
33
|
@current_exists = false
|
34
34
|
else
|
@@ -4,12 +4,12 @@ require_relative "../../cheffish/base_resource"
|
|
4
4
|
class Chef
|
5
5
|
class Resource
|
6
6
|
class ChefDataBag < Cheffish::BaseResource
|
7
|
-
|
7
|
+
provides :chef_data_bag
|
8
8
|
|
9
9
|
property :data_bag_name, Cheffish::NAME_REGEX, name_property: true
|
10
10
|
|
11
11
|
action :create do
|
12
|
-
|
12
|
+
unless current_resource_exists?
|
13
13
|
converge_by "create data bag #{new_resource.data_bag_name} at #{rest.url}" do
|
14
14
|
rest.post("data", { "name" => new_resource.data_bag_name })
|
15
15
|
end
|
@@ -27,7 +27,7 @@ class Chef
|
|
27
27
|
action_class.class_eval do
|
28
28
|
def load_current_resource
|
29
29
|
@current_resource = json_to_resource(rest.get("data/#{new_resource.data_bag_name}"))
|
30
|
-
rescue Net::
|
30
|
+
rescue Net::HTTPClientException => e
|
31
31
|
if e.response.code == "404"
|
32
32
|
@current_resource = not_found_resource
|
33
33
|
else
|
@@ -7,7 +7,7 @@ require "chef/encrypted_data_bag_item"
|
|
7
7
|
class Chef
|
8
8
|
class Resource
|
9
9
|
class ChefDataBagItem < Cheffish::BaseResource
|
10
|
-
|
10
|
+
provides :chef_data_bag_item
|
11
11
|
|
12
12
|
def initialize(*args)
|
13
13
|
super
|
@@ -103,7 +103,7 @@ class Chef
|
|
103
103
|
resource = Chef::Resource::ChefDataBagItem.new(new_resource.name, run_context)
|
104
104
|
resource.raw_data json
|
105
105
|
@current_resource = resource
|
106
|
-
rescue Net::
|
106
|
+
rescue Net::HTTPClientException => e
|
107
107
|
if e.response.code == "404"
|
108
108
|
@current_resource = not_found_resource
|
109
109
|
else
|
@@ -112,7 +112,7 @@ class Chef
|
|
112
112
|
end
|
113
113
|
|
114
114
|
# Determine if data bag is encrypted and if so, what its version is
|
115
|
-
_first_real_key, first_real_value = (current_resource.raw_data || {}).
|
115
|
+
_first_real_key, first_real_value = (current_resource.raw_data || {}).find { |key, value| key != "id" && !value.nil? }
|
116
116
|
if first_real_value
|
117
117
|
if first_real_value.is_a?(Hash) &&
|
118
118
|
first_real_value["version"].is_a?(Integer) &&
|
@@ -137,7 +137,7 @@ class Chef
|
|
137
137
|
|
138
138
|
# If the current secret doesn't work, look through the specified old secrets
|
139
139
|
|
140
|
-
|
140
|
+
unless current_resource.secret
|
141
141
|
old_secrets = []
|
142
142
|
if new_resource.old_secret
|
143
143
|
old_secrets += Array(new_resource.old_secret)
|
@@ -148,17 +148,17 @@ class Chef
|
|
148
148
|
end
|
149
149
|
end
|
150
150
|
old_secrets.each do |secret|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
151
|
+
|
152
|
+
Chef::EncryptedDataBagItem::Decryptor.for(first_real_value, secret).for_decrypted_item
|
153
|
+
current_resource.secret secret
|
154
|
+
rescue Chef::EncryptedDataBagItem::DecryptionFailure
|
155
|
+
decrypt_error = $!
|
156
|
+
|
157
157
|
end
|
158
158
|
|
159
159
|
# If we couldn't figure out the secret, emit a warning (this isn't a fatal flaw unless we
|
160
160
|
# need to reuse one of the values from the data bag)
|
161
|
-
|
161
|
+
unless current_resource.secret
|
162
162
|
if decrypt_error
|
163
163
|
Chef::Log.warn "Existing data bag is encrypted, but could not decrypt: #{decrypt_error.message}."
|
164
164
|
else
|
@@ -280,9 +280,10 @@ class Chef
|
|
280
280
|
elsif current_resource.encrypt
|
281
281
|
# Encryption is different and we can't read the old values. Only allow the change
|
282
282
|
# if we're overwriting the data bag item
|
283
|
-
|
283
|
+
unless new_resource.complete
|
284
284
|
raise "Cannot encrypt #{new_resource.name} due to failure to decrypt existing resource. Set 'complete true' to overwrite or add the old secret as old_secret / old_secret_path."
|
285
285
|
end
|
286
|
+
|
286
287
|
_differences = [ "overwrite data bag item (cannot decrypt old data bag item)"]
|
287
288
|
differences = (new_resource.raw_data.keys & current_resource.raw_data.keys).map { |key| "overwrite #{key}" }
|
288
289
|
differences += (new_resource.raw_data.keys - current_resource.raw_data.keys).map { |key| "add #{key}" }
|
@@ -6,7 +6,7 @@ require "chef/chef_fs/data_handler/environment_data_handler"
|
|
6
6
|
class Chef
|
7
7
|
class Resource
|
8
8
|
class ChefEnvironment < Cheffish::BaseResource
|
9
|
-
|
9
|
+
provides :chef_environment
|
10
10
|
|
11
11
|
property :environment_name, Cheffish::NAME_REGEX, name_property: true
|
12
12
|
property :description, String
|
@@ -84,7 +84,7 @@ class Chef
|
|
84
84
|
action_class.class_eval do
|
85
85
|
def load_current_resource
|
86
86
|
@current_resource = json_to_resource(rest.get("environments/#{new_resource.environment_name}"))
|
87
|
-
rescue Net::
|
87
|
+
rescue Net::HTTPClientException => e
|
88
88
|
if e.response.code == "404"
|
89
89
|
@current_resource = not_found_resource
|
90
90
|
else
|
@@ -6,7 +6,7 @@ require "chef/chef_fs/data_handler/group_data_handler"
|
|
6
6
|
class Chef
|
7
7
|
class Resource
|
8
8
|
class ChefGroup < Cheffish::BaseResource
|
9
|
-
|
9
|
+
provides :chef_group
|
10
10
|
|
11
11
|
property :group_name, Cheffish::NAME_REGEX, name_property: true
|
12
12
|
property :users, ArrayType
|
@@ -45,7 +45,7 @@ class Chef
|
|
45
45
|
action_class.class_eval do
|
46
46
|
def load_current_resource
|
47
47
|
@current_resource = json_to_resource(rest.get("groups/#{new_resource.group_name}"))
|
48
|
-
rescue Net::
|
48
|
+
rescue Net::HTTPClientException => e
|
49
49
|
if e.response.code == "404"
|
50
50
|
@current_resource = not_found_resource
|
51
51
|
else
|
@@ -9,7 +9,7 @@ require "chef/chef_fs/file_system/repository/chef_repository_file_system_root_di
|
|
9
9
|
class Chef
|
10
10
|
class Resource
|
11
11
|
class ChefMirror < Cheffish::BaseResource
|
12
|
-
|
12
|
+
provides :chef_mirror
|
13
13
|
|
14
14
|
# Path of the data to mirror, e.g. nodes, nodes/*, nodes/mynode,
|
15
15
|
# */*, **, roles/base, data/secrets, cookbooks/apache2, etc.
|
@@ -95,6 +95,7 @@ class Chef
|
|
95
95
|
if new_resource.concurrency <= 0
|
96
96
|
raise "chef_mirror.concurrency must be above 0! Was set to #{new_resource.concurrency}"
|
97
97
|
end
|
98
|
+
|
98
99
|
# Honor concurrency
|
99
100
|
Chef::ChefFS::Parallelizer.threads = new_resource.concurrency - 1
|
100
101
|
|
@@ -103,13 +104,14 @@ class Chef
|
|
103
104
|
if new_resource.path[0] == "/"
|
104
105
|
raise "Absolute paths in chef_mirror not yet supported."
|
105
106
|
end
|
107
|
+
|
106
108
|
# Copy!
|
107
109
|
path = Chef::ChefFS::FilePattern.new("/#{new_resource.path}")
|
108
110
|
ui = CopyListener.new(self)
|
109
111
|
error = Chef::ChefFS::FileSystem.copy_to(path, src_root, dest_root, nil, options, ui, proc { |p| p.path })
|
110
112
|
|
111
113
|
if error
|
112
|
-
raise "Errors while copying:#{ui.errors.map { |e| "#{e}\n" }.join(
|
114
|
+
raise "Errors while copying:#{ui.errors.map { |e| "#{e}\n" }.join("")}"
|
113
115
|
end
|
114
116
|
end
|
115
117
|
|
@@ -163,7 +165,7 @@ class Chef
|
|
163
165
|
end
|
164
166
|
|
165
167
|
def repo_mode
|
166
|
-
new_resource.chef_server[:chef_server_url]
|
168
|
+
%r{/organizations/}.match?(new_resource.chef_server[:chef_server_url]) ? "hosted_everything" : "everything"
|
167
169
|
end
|
168
170
|
|
169
171
|
def options
|
@@ -179,8 +181,7 @@ class Chef
|
|
179
181
|
result
|
180
182
|
end
|
181
183
|
|
182
|
-
def load_current_resource
|
183
|
-
end
|
184
|
+
def load_current_resource; end
|
184
185
|
|
185
186
|
class CopyListener
|
186
187
|
def initialize(mirror)
|
@@ -6,7 +6,7 @@ require_relative "../../cheffish/node_properties"
|
|
6
6
|
class Chef
|
7
7
|
class Resource
|
8
8
|
class ChefNode < Cheffish::BaseResource
|
9
|
-
|
9
|
+
provides :chef_node
|
10
10
|
|
11
11
|
include Cheffish::NodeProperties
|
12
12
|
|
@@ -39,7 +39,7 @@ class Chef
|
|
39
39
|
action_class.class_eval do
|
40
40
|
def load_current_resource
|
41
41
|
@current_resource = json_to_resource(rest.get("nodes/#{new_resource.name}"))
|
42
|
-
rescue Net::
|
42
|
+
rescue Net::HTTPClientException => e
|
43
43
|
if e.response.code == "404"
|
44
44
|
@current_resource = not_found_resource
|
45
45
|
else
|