cheffish 14.0.13 → 16.0.8

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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +3 -9
  3. data/Rakefile +1 -1
  4. data/cheffish.gemspec +3 -3
  5. data/lib/chef/resource/chef_acl.rb +17 -14
  6. data/lib/chef/resource/chef_client.rb +3 -3
  7. data/lib/chef/resource/chef_container.rb +4 -4
  8. data/lib/chef/resource/chef_data_bag.rb +3 -3
  9. data/lib/chef/resource/chef_data_bag_item.rb +13 -12
  10. data/lib/chef/resource/chef_environment.rb +2 -2
  11. data/lib/chef/resource/chef_group.rb +2 -2
  12. data/lib/chef/resource/chef_mirror.rb +6 -5
  13. data/lib/chef/resource/chef_node.rb +2 -2
  14. data/lib/chef/resource/chef_organization.rb +3 -3
  15. data/lib/chef/resource/chef_resolved_cookbooks.rb +5 -3
  16. data/lib/chef/resource/chef_role.rb +6 -2
  17. data/lib/chef/resource/chef_user.rb +2 -2
  18. data/lib/chef/resource/private_key.rb +11 -11
  19. data/lib/chef/resource/public_key.rb +5 -4
  20. data/lib/cheffish.rb +1 -0
  21. data/lib/cheffish/base_resource.rb +13 -11
  22. data/lib/cheffish/basic_chef_client.rb +4 -5
  23. data/lib/cheffish/chef_actor_base.rb +3 -2
  24. data/lib/cheffish/chef_run.rb +5 -6
  25. data/lib/cheffish/chef_run_listener.rb +1 -3
  26. data/lib/cheffish/key_formatter.rb +5 -13
  27. data/lib/cheffish/merged_config.rb +2 -2
  28. data/lib/cheffish/node_properties.rb +7 -3
  29. data/lib/cheffish/recipe_dsl.rb +2 -2
  30. data/lib/cheffish/rspec/chef_run_support.rb +2 -2
  31. data/lib/cheffish/rspec/matchers/have_updated.rb +5 -5
  32. data/lib/cheffish/rspec/recipe_run_wrapper.rb +2 -2
  33. data/lib/cheffish/rspec/repository_support.rb +1 -0
  34. data/lib/cheffish/version.rb +1 -1
  35. data/spec/functional/fingerprint_spec.rb +8 -6
  36. data/spec/integration/chef_acl_spec.rb +28 -20
  37. data/spec/integration/chef_group_spec.rb +2 -2
  38. data/spec/integration/chef_node_spec.rb +2 -2
  39. data/spec/integration/chef_role_spec.rb +2 -2
  40. metadata +7 -7
@@ -6,7 +6,7 @@ require "chef/chef_fs/data_handler/data_handler_base"
6
6
  class Chef
7
7
  class Resource
8
8
  class ChefOrganization < Cheffish::BaseResource
9
- resource_name :chef_organization
9
+ provides :chef_organization
10
10
 
11
11
  property :organization_name, Cheffish::NAME_REGEX, name_property: true
12
12
  property :full_name, String
@@ -68,7 +68,7 @@ class Chef
68
68
  end
69
69
  end
70
70
  new_resource.members.each do |user|
71
- if !existing_members.include?(user)
71
+ unless existing_members.include?(user)
72
72
  converge_by "Add #{user} to organization #{new_resource.organization_name}" do
73
73
  rest.post("#{rest.root_url}/organizations/#{new_resource.organization_name}/users/", { "username" => user })
74
74
  end
@@ -130,7 +130,7 @@ class Chef
130
130
  action_class.class_eval do
131
131
  def load_current_resource
132
132
  @current_resource = json_to_resource(rest.get("#{rest.root_url}/organizations/#{new_resource.organization_name}"))
133
- rescue Net::HTTPServerException => e
133
+ rescue Net::HTTPClientException => e
134
134
  if e.response.code == "404"
135
135
  @current_resource = not_found_resource
136
136
  else
@@ -4,7 +4,7 @@ require "chef_zero"
4
4
  class Chef
5
5
  class Resource
6
6
  class ChefResolvedCookbooks < Cheffish::BaseResource
7
- resource_name :chef_resolved_cookbooks
7
+ provides :chef_resolved_cookbooks
8
8
 
9
9
  def initialize(*args)
10
10
  super
@@ -43,7 +43,8 @@ class Chef
43
43
  new_resource.berksfile.upload(
44
44
  server_url: new_resource.chef_server[:chef_server_url],
45
45
  client_name: new_resource.chef_server[:options][:client_name],
46
- client_key: new_resource.chef_server[:options][:signing_key_filename])
46
+ client_key: new_resource.chef_server[:options][:signing_key_filename]
47
+ )
47
48
  else
48
49
  file = Tempfile.new("privatekey")
49
50
  begin
@@ -53,7 +54,8 @@ class Chef
53
54
  new_resource.berksfile.upload(
54
55
  server_url: new_resource.chef_server[:chef_server_url],
55
56
  client_name: new_resource.chef_server[:options][:client_name] || "me",
56
- client_key: file.path)
57
+ client_key: file.path
58
+ )
57
59
 
58
60
  ensure
59
61
  file.close
@@ -6,7 +6,7 @@ require "chef/chef_fs/data_handler/role_data_handler"
6
6
  class Chef
7
7
  class Resource
8
8
  class ChefRole < Cheffish::BaseResource
9
- resource_name :chef_role
9
+ provides :chef_role
10
10
 
11
11
  property :role_name, Cheffish::NAME_REGEX, name_property: true
12
12
  property :description, String
@@ -62,6 +62,7 @@ class Chef
62
62
  if recipes.size == 0
63
63
  raise ArgumentError, "At least one recipe must be specified"
64
64
  end
65
+
65
66
  @run_list_modifiers ||= []
66
67
  @run_list_modifiers += recipes.map { |recipe| Chef::RunList::RunListItem.new("recipe[#{recipe}]") }
67
68
  end
@@ -70,6 +71,7 @@ class Chef
70
71
  if roles.size == 0
71
72
  raise ArgumentError, "At least one role must be specified"
72
73
  end
74
+
73
75
  @run_list_modifiers ||= []
74
76
  @run_list_modifiers += roles.map { |role| Chef::RunList::RunListItem.new("role[#{role}]") }
75
77
  end
@@ -78,6 +80,7 @@ class Chef
78
80
  if recipes.size == 0
79
81
  raise ArgumentError, "At least one recipe must be specified"
80
82
  end
83
+
81
84
  @run_list_removers ||= []
82
85
  @run_list_removers += recipes.map { |recipe| Chef::RunList::RunListItem.new("recipe[#{recipe}]") }
83
86
  end
@@ -86,6 +89,7 @@ class Chef
86
89
  if roles.size == 0
87
90
  raise ArgumentError, "At least one role must be specified"
88
91
  end
92
+
89
93
  @run_list_removers ||= []
90
94
  @run_list_removers += roles.map { |recipe| Chef::RunList::RunListItem.new("role[#{role}]") }
91
95
  end
@@ -119,7 +123,7 @@ class Chef
119
123
  action_class.class_eval do
120
124
  def load_current_resource
121
125
  @current_resource = json_to_resource(rest.get("roles/#{new_resource.role_name}"))
122
- rescue Net::HTTPServerException => e
126
+ rescue Net::HTTPClientException => e
123
127
  if e.response.code == "404"
124
128
  @current_resource = not_found_resource
125
129
  else
@@ -4,7 +4,7 @@ require_relative "../../cheffish/chef_actor_base"
4
4
  class Chef
5
5
  class Resource
6
6
  class ChefUser < Cheffish::ChefActorBase
7
- resource_name :chef_user
7
+ provides :chef_user
8
8
 
9
9
  # Client attributes
10
10
  property :user_name, Cheffish::NAME_REGEX, name_property: true
@@ -25,7 +25,7 @@ class Chef
25
25
 
26
26
  # Output public key (if so desired)
27
27
  property :output_key_path, String
28
- property :output_key_format, [ :pem, :der, :openssh ], default: :openssh
28
+ property :output_key_format, %i{pem der openssh}, default: :openssh
29
29
 
30
30
  # Proc that runs just before the resource executes. Called with (resource)
31
31
  def before(&block)
@@ -1,23 +1,23 @@
1
1
  require "openssl/cipher"
2
2
  require_relative "../../cheffish/base_resource"
3
- require "openssl"
3
+ require "openssl" unless defined?(OpenSSL)
4
4
  require_relative "../../cheffish/key_formatter"
5
5
 
6
6
  class Chef
7
7
  class Resource
8
8
  class PrivateKey < Cheffish::BaseResource
9
- resource_name :private_key
9
+ provides :private_key
10
10
 
11
11
  allowed_actions :create, :delete, :regenerate, :nothing
12
12
  default_action :create
13
13
 
14
14
  # Path to private key. Set to :none to create the key in memory and not on disk.
15
15
  property :path, [ String, :none ], name_property: true
16
- property :format, [ :pem, :der ], default: :pem
17
- property :type, [ :rsa, :dsa ], default: :rsa # TODO support :ec
16
+ property :format, %i{pem der}, default: :pem
17
+ property :type, %i{rsa dsa}, default: :rsa # TODO support :ec
18
18
  # These specify an optional public_key you can spit out if you want.
19
19
  property :public_key_path, String
20
- property :public_key_format, [ :openssh, :pem, :der ], default: :openssh
20
+ property :public_key_format, %i{openssh pem der}, default: :openssh
21
21
  # Specify this if you want to copy another private key but give it a different format / password
22
22
  property :source_key
23
23
  property :source_key_path, String
@@ -31,7 +31,7 @@ class Chef
31
31
 
32
32
  # PEM-only
33
33
  property :pass_phrase, String
34
- property :cipher, String, equal_to: OpenSSL::Cipher.ciphers.map { |x| x.downcase }, default: "des-ede3-cbc", coerce: proc { |x| x.downcase }
34
+ property :cipher, String, equal_to: OpenSSL::Cipher.ciphers.map(&:downcase), default: "des-ede3-cbc", coerce: proc { |x| x.downcase }
35
35
 
36
36
  # Set this to regenerate the key if it does not have the desired characteristics (like size, type, etc.)
37
37
  property :regenerate_if_different, [TrueClass, FalseClass]
@@ -202,22 +202,22 @@ class Chef
202
202
  def new_key_with_path
203
203
  path = new_resource.path
204
204
  if path.is_a?(Symbol)
205
- return [ nil, path ]
205
+ [ nil, path ]
206
206
  elsif Pathname.new(path).relative?
207
207
  private_key, private_key_path = Cheffish.get_private_key_with_path(path, run_context.config)
208
208
  if private_key
209
- return [ private_key, (private_key_path || :none) ]
209
+ [ private_key, (private_key_path || :none) ]
210
210
  elsif run_context.config[:private_key_write_path]
211
211
  @should_create_directory = true
212
212
  path = ::File.join(run_context.config[:private_key_write_path], path)
213
- return [ nil, path ]
213
+ [ nil, path ]
214
214
  else
215
215
  raise "Could not find key #{path} and Chef::Config.private_key_write_path is not set."
216
216
  end
217
217
  elsif ::File.exist?(path)
218
- return [ IO.read(path), path ]
218
+ [ IO.read(path), path ]
219
219
  else
220
- return [ nil, path ]
220
+ [ nil, path ]
221
221
  end
222
222
  end
223
223
 
@@ -1,18 +1,18 @@
1
1
  require "openssl/cipher"
2
2
  require_relative "../../cheffish/base_resource"
3
- require "openssl"
3
+ require "openssl" unless defined?(OpenSSL)
4
4
  require_relative "../../cheffish/key_formatter"
5
5
 
6
6
  class Chef
7
7
  class Resource
8
8
  class PublicKey < Cheffish::BaseResource
9
- resource_name :public_key
9
+ provides :public_key
10
10
 
11
11
  allowed_actions :create, :delete, :nothing
12
12
  default_action :create
13
13
 
14
14
  property :path, String, name_property: true
15
- property :format, [ :pem, :der, :openssh ], default: :openssh
15
+ property :format, %i{pem der openssh}, default: :openssh
16
16
 
17
17
  property :source_key
18
18
  property :source_key_path, String
@@ -24,9 +24,10 @@ class Chef
24
24
  end
25
25
 
26
26
  action :create do
27
- if !new_source_key
27
+ unless new_source_key
28
28
  raise "No source key specified"
29
29
  end
30
+
30
31
  desired_output = encode_public_key(new_source_key)
31
32
  if Array(current_resource.action) == [ :delete ] || desired_output != IO.read(new_resource.path)
32
33
  converge_by "write #{new_resource.format} public key #{new_resource.path} from #{new_source_key_publicity} key #{new_resource.source_key_path}" do
@@ -98,6 +98,7 @@ module Cheffish
98
98
  elsif config[:private_key_paths]
99
99
  config[:private_key_paths].each do |private_key_path|
100
100
  next unless File.exist?(private_key_path)
101
+
101
102
  Dir.entries(private_key_path).sort.each do |key|
102
103
  ext = File.extname(key)
103
104
  if key == name || ext == "" || ext == ".pem"
@@ -91,7 +91,7 @@ module Cheffish
91
91
  end
92
92
 
93
93
  def json_differences_internal(old_json, new_json, print_values, name, result)
94
- if old_json.kind_of?(Hash) && new_json.kind_of?(Hash)
94
+ if old_json.is_a?(Hash) && new_json.is_a?(Hash)
95
95
  removed_keys = old_json.keys.inject({}) { |hash, key| hash[key] = true; hash }
96
96
  new_json.each_pair do |new_key, new_value|
97
97
  if old_json.key?(new_key)
@@ -101,18 +101,18 @@ module Cheffish
101
101
  end
102
102
  else
103
103
  if print_values
104
- result << " add #{name == '' ? new_key : "#{name}.#{new_key}"} = #{new_value.inspect}"
104
+ result << " add #{name == "" ? new_key : "#{name}.#{new_key}"} = #{new_value.inspect}"
105
105
  else
106
- result << " add #{name == '' ? new_key : "#{name}.#{new_key}"}"
106
+ result << " add #{name == "" ? new_key : "#{name}.#{new_key}"}"
107
107
  end
108
108
  end
109
109
  end
110
110
  removed_keys.keys.each do |removed_key|
111
- result << " remove #{name == '' ? removed_key : "#{name}.#{removed_key}"}"
111
+ result << " remove #{name == "" ? removed_key : "#{name}.#{removed_key}"}"
112
112
  end
113
113
  else
114
- old_json = old_json.to_s if old_json.kind_of?(Symbol)
115
- new_json = new_json.to_s if new_json.kind_of?(Symbol)
114
+ old_json = old_json.to_s if old_json.is_a?(Symbol)
115
+ new_json = new_json.to_s if new_json.is_a?(Symbol)
116
116
  if old_json != new_json
117
117
  if print_values
118
118
  result << " update #{name} from #{old_json.inspect} to #{new_json.inspect}"
@@ -134,8 +134,8 @@ module Cheffish
134
134
  end
135
135
 
136
136
  modifiers.each do |path, value|
137
- path = [path] if !path.kind_of?(Array)
138
- path = path.map { |path_part| path_part.to_s }
137
+ path = [path] unless path.is_a?(Array)
138
+ path = path.map(&:to_s)
139
139
  parent = 0.upto(path.size - 2).inject(json) do |hash, index|
140
140
  if hash.nil?
141
141
  nil
@@ -148,6 +148,7 @@ module Cheffish
148
148
  if !parent.nil? && !parent.is_a?(Hash)
149
149
  raise "Attempt to set #{path} to #{value} when #{path[0..-2]} is not a hash"
150
150
  end
151
+
151
152
  existing_value = parent ? parent[path[-1]] : nil
152
153
 
153
154
  if value.is_a?(Proc)
@@ -158,7 +159,7 @@ module Cheffish
158
159
  else
159
160
  # Create parent if necessary, overwriting values
160
161
  parent = path[0..-2].inject(json) do |hash, path_part|
161
- hash[path_part] = {} if !hash[path_part]
162
+ hash[path_part] = {} unless hash[path_part]
162
163
  hash[path_part]
163
164
  end
164
165
  if path.size > 0
@@ -173,6 +174,7 @@ module Cheffish
173
174
 
174
175
  def apply_run_list_modifiers(add_to_run_list, delete_from_run_list, run_list)
175
176
  return run_list if (!add_to_run_list || add_to_run_list.size == 0) && (!delete_from_run_list || !delete_from_run_list.size)
177
+
176
178
  delete_from_run_list ||= []
177
179
  add_to_run_list ||= []
178
180
 
@@ -191,7 +193,7 @@ module Cheffish
191
193
  # because found_desired will be less than add_to_run_list_index. The result will
192
194
  # be X, A, B, Y, Z.
193
195
  if found_desired >= add_to_run_list_index
194
- result += add_to_run_list[add_to_run_list_index..found_desired].map { |item| item.to_s }
196
+ result += add_to_run_list[add_to_run_list_index..found_desired].map(&:to_s)
195
197
  add_to_run_list_index = found_desired + 1
196
198
  end
197
199
  else
@@ -204,7 +206,7 @@ module Cheffish
204
206
  end
205
207
 
206
208
  # Copy any remaining desired items at the end
207
- result += add_to_run_list[add_to_run_list_index..-1].map { |item| item.to_s }
209
+ result += add_to_run_list[add_to_run_list_index..-1].map(&:to_s)
208
210
  result
209
211
  end
210
212
 
@@ -5,7 +5,7 @@ require "chef/event_dispatch/dispatcher"
5
5
  require "chef/node"
6
6
  require "chef/run_context"
7
7
  require "chef/runner"
8
- require "forwardable"
8
+ require "forwardable" unless defined?(Forwardable)
9
9
  require "chef/providers"
10
10
  require "chef/resources"
11
11
 
@@ -14,7 +14,7 @@ module Cheffish
14
14
  include Chef::DSL::Recipe
15
15
 
16
16
  def initialize(node = nil, events = nil, **chef_config)
17
- if !node
17
+ unless node
18
18
  node = Chef::Node.new
19
19
  node.name "basic_chef_client"
20
20
  node.automatic[:platform] = "basic_chef_client"
@@ -31,7 +31,7 @@ module Cheffish
31
31
  case events
32
32
  when Array
33
33
  events.each { |e| dispatcher.register(e) } if events
34
- when !nil
34
+ when !nil # rubocop: disable Lint/LiteralAsCondition
35
35
  dispatcher.register(events)
36
36
  end
37
37
  @run_context = Chef::RunContext.new(node, {}, dispatcher)
@@ -80,12 +80,11 @@ module Cheffish
80
80
  # add_resource() method.
81
81
  def self.build_resource(type, name, created_at = nil, &resource_attrs_block)
82
82
  created_at ||= caller[0]
83
- result = BasicChefClient.new.tap do |client|
83
+ BasicChefClient.new.tap do |client|
84
84
  client.with_chef_config do
85
85
  client.build_resource(type, name, created_at, &resource_attrs_block)
86
86
  end
87
87
  end
88
- result
89
88
  end
90
89
 
91
90
  def self.inline_resource(provider, provider_action, *resources, &block)
@@ -24,9 +24,10 @@ module Cheffish
24
24
  end
25
25
  else
26
26
  # Create the actor if it's missing
27
- if !new_public_key
27
+ unless new_public_key
28
28
  raise "You must specify a public key to create a #{actor_type}! Use the private_key resource to create a key, and pass it in with source_key_path."
29
29
  end
30
+
30
31
  description = [ "create #{actor_type} #{new_resource.name} at #{actor_path}" ] + differences
31
32
  converge_by description do
32
33
  result = rest.post((actor_path).to_s, normalize_for_post(new_json))
@@ -118,7 +119,7 @@ module Cheffish
118
119
  begin
119
120
  json = rest.get("#{actor_path}/#{new_resource.name}")
120
121
  @current_resource = json_to_resource(json)
121
- rescue Net::HTTPServerException => e
122
+ rescue Net::HTTPClientException => e
122
123
  if e.response.code == "404"
123
124
  @current_resource = not_found_resource
124
125
  else
@@ -34,15 +34,14 @@ module Cheffish
34
34
  def client
35
35
  @client ||= begin
36
36
  chef_config = self.chef_config.dup
37
- chef_config[:log_level] ||= :debug if !chef_config.key?(:log_level)
38
- chef_config[:verbose_logging] = false if !chef_config.key?(:verbose_logging)
37
+ chef_config[:log_level] ||= :debug unless chef_config.key?(:log_level)
38
+ chef_config[:verbose_logging] = false unless chef_config.key?(:verbose_logging)
39
39
  chef_config[:stdout] = StringIOTee.new(chef_config[:stdout])
40
40
  chef_config[:stderr] = StringIOTee.new(chef_config[:stderr])
41
41
  chef_config[:log_location] = StringIOTee.new(chef_config[:log_location])
42
42
  @client = ::Cheffish::BasicChefClient.new(nil,
43
43
  [ event_sink, Chef::Formatters.new(:doc, chef_config[:stdout], chef_config[:stderr]) ],
44
- chef_config
45
- )
44
+ chef_config)
46
45
  end
47
46
  end
48
47
 
@@ -125,14 +124,14 @@ module Cheffish
125
124
  message << "--- Chef Client Output ---\n"
126
125
  message << "--- ---\n"
127
126
  message << stdout
128
- message << "\n" if !stdout.end_with?("\n")
127
+ message << "\n" unless stdout.end_with?("\n")
129
128
  end
130
129
  if stderr && !stderr.empty?
131
130
  message << "--- ---\n"
132
131
  message << "--- Chef Client Error Output ---\n"
133
132
  message << "--- ---\n"
134
133
  message << stderr
135
- message << "\n" if !stderr.end_with?("\n")
134
+ message << "\n" unless stderr.end_with?("\n")
136
135
  end
137
136
  if logs && !logs.empty?
138
137
  message << "--- ---\n"
@@ -21,9 +21,7 @@ module Cheffish
21
21
  def disconnect
22
22
  # Stop the servers
23
23
  if node.run_context
24
- node.run_context.cheffish.local_servers.each do |server|
25
- server.stop
26
- end
24
+ node.run_context.cheffish.local_servers.each(&:stop)
27
25
  end
28
26
  end
29
27
  end
@@ -1,7 +1,7 @@
1
- require "openssl"
2
- require "net/ssh"
3
- require "etc"
4
- require "socket"
1
+ require "openssl" unless defined?(OpenSSL)
2
+ require "net/ssh" unless defined?(Net::SSH)
3
+ require "etc" unless defined?(Etc)
4
+ require "socket" unless defined?(Socket)
5
5
  require "digest/md5"
6
6
  require "base64"
7
7
 
@@ -55,15 +55,7 @@ module Cheffish
55
55
  hexes = Digest::MD5.hexdigest(data)
56
56
  hexes.scan(/../).join(":")
57
57
  when :pkcs8sha1fingerprint
58
- if RUBY_VERSION.to_f >= 2.0
59
- raise "PKCS8 SHA1 not supported in Ruby #{RUBY_VERSION}"
60
- end
61
- require "openssl_pkcs8"
62
- pkcs8_pem = key.to_pem_pkcs8
63
- pkcs8_base64 = pkcs8_pem.split("\n").reject { |l| l =~ /^-----/ }
64
- pkcs8_data = Base64.decode64(pkcs8_base64.join)
65
- hexes = Digest::SHA1.hexdigest(pkcs8_data)
66
- hexes.scan(/../).join(":")
58
+ raise "PKCS8 SHA1 not supported by Ruby 2.0 and later"
67
59
  else
68
60
  raise "Unrecognized key format #{format}"
69
61
  end