cheffish 0.7.1 → 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 (37) hide show
  1. checksums.yaml +4 -4
  2. data/lib/chef/provider/chef_acl.rb +434 -0
  3. data/lib/chef/provider/chef_client.rb +5 -1
  4. data/lib/chef/provider/chef_container.rb +50 -0
  5. data/lib/chef/provider/chef_group.rb +78 -0
  6. data/lib/chef/provider/chef_mirror.rb +138 -0
  7. data/lib/chef/provider/chef_organization.rb +150 -0
  8. data/lib/chef/provider/chef_user.rb +6 -1
  9. data/lib/chef/provider/public_key.rb +0 -1
  10. data/lib/chef/resource/chef_acl.rb +38 -44
  11. data/lib/chef/resource/chef_container.rb +18 -0
  12. data/lib/chef/resource/chef_group.rb +49 -0
  13. data/lib/chef/resource/chef_mirror.rb +47 -0
  14. data/lib/chef/resource/chef_organization.rb +64 -0
  15. data/lib/chef/resource/private_key.rb +6 -1
  16. data/lib/chef/resource/public_key.rb +5 -0
  17. data/lib/cheffish/actor_provider_base.rb +14 -9
  18. data/lib/cheffish/basic_chef_client.rb +18 -2
  19. data/lib/cheffish/chef_provider_base.rb +7 -0
  20. data/lib/cheffish/merged_config.rb +10 -2
  21. data/lib/cheffish/recipe_dsl.rb +34 -8
  22. data/lib/cheffish/server_api.rb +12 -2
  23. data/lib/cheffish/version.rb +1 -1
  24. data/lib/cheffish.rb +2 -2
  25. data/spec/functional/merged_config_spec.rb +20 -0
  26. data/spec/integration/chef_acl_spec.rb +914 -0
  27. data/spec/integration/chef_client_spec.rb +78 -44
  28. data/spec/integration/chef_container_spec.rb +34 -0
  29. data/spec/integration/chef_group_spec.rb +324 -0
  30. data/spec/integration/chef_mirror_spec.rb +244 -0
  31. data/spec/integration/chef_node_spec.rb +115 -93
  32. data/spec/integration/chef_organization_spec.rb +244 -0
  33. data/spec/integration/chef_user_spec.rb +51 -9
  34. data/spec/support/repository_support.rb +103 -0
  35. data/spec/support/spec_support.rb +55 -2
  36. metadata +23 -9
  37. data/lib/chef/resource/in_parallel.rb +0 -6
@@ -14,9 +14,9 @@ class Cheffish::ActorProviderBase < Cheffish::ChefProviderBase
14
14
  if current_resource_exists?
15
15
  # Update the actor if it's different
16
16
  if differences.size > 0
17
- description = [ "update #{actor_type} #{new_resource.name} at #{rest.url}" ] + differences
17
+ description = [ "update #{actor_type} #{new_resource.name} at #{actor_path}" ] + differences
18
18
  converge_by description do
19
- result = rest.put("#{actor_type}s/#{new_resource.name}", normalize_for_put(new_json))
19
+ result = rest.put("#{actor_path}/#{new_resource.name}", normalize_for_put(new_json))
20
20
  current_public_key, current_public_key_format = Cheffish::KeyFormatter.decode(result['public_key']) if result['public_key']
21
21
  end
22
22
  end
@@ -25,9 +25,9 @@ class Cheffish::ActorProviderBase < Cheffish::ChefProviderBase
25
25
  if !new_public_key
26
26
  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."
27
27
  end
28
- description = [ "create #{actor_type} #{new_resource.name} at #{rest.url}" ] + differences
28
+ description = [ "create #{actor_type} #{new_resource.name} at #{actor_path}" ] + differences
29
29
  converge_by description do
30
- result = rest.post("#{actor_type}s", normalize_for_post(new_json))
30
+ result = rest.post("#{actor_path}", normalize_for_post(new_json))
31
31
  current_public_key, current_public_key_format = Cheffish::KeyFormatter.decode(result['public_key']) if result['public_key']
32
32
  end
33
33
  end
@@ -58,8 +58,8 @@ class Cheffish::ActorProviderBase < Cheffish::ChefProviderBase
58
58
 
59
59
  def delete_actor
60
60
  if current_resource_exists?
61
- converge_by "delete #{actor_type} #{new_resource.name} at #{rest.url}" do
62
- rest.delete("#{actor_type}s/#{new_resource.name}")
61
+ converge_by "delete #{actor_type} #{new_resource.name} at #{actor_path}" do
62
+ rest.delete("#{actor_path}/#{new_resource.name}")
63
63
  Chef::Log.info("#{new_resource} deleted #{actor_type} #{new_resource.name} at #{rest.url}")
64
64
  end
65
65
  end
@@ -74,7 +74,13 @@ class Cheffish::ActorProviderBase < Cheffish::ChefProviderBase
74
74
  @new_public_key ||= begin
75
75
  if new_resource.source_key
76
76
  if new_resource.source_key.is_a?(String)
77
- Cheffish::KeyFormatter.decode(new_resource.source_key)
77
+ key, key_format = Cheffish::KeyFormatter.decode(new_resource.source_key)
78
+
79
+ if key.private?
80
+ key.public_key
81
+ else
82
+ key
83
+ end
78
84
  elsif new_resource.source_key.private?
79
85
  new_resource.source_key.public_key
80
86
  else
@@ -108,7 +114,7 @@ class Cheffish::ActorProviderBase < Cheffish::ChefProviderBase
108
114
 
109
115
  def load_current_resource
110
116
  begin
111
- json = rest.get("#{actor_type}s/#{new_resource.name}")
117
+ json = rest.get("#{actor_path}/#{new_resource.name}")
112
118
  @current_resource = json_to_resource(json)
113
119
  rescue Net::HTTPServerException => e
114
120
  if e.response.code == "404"
@@ -122,5 +128,4 @@ class Cheffish::ActorProviderBase < Cheffish::ChefProviderBase
122
128
  current_resource.output_key_path = new_resource.output_key_path
123
129
  end
124
130
  end
125
-
126
131
  end
@@ -37,6 +37,11 @@ module Cheffish
37
37
  attr_accessor :recipe_name
38
38
  def_delegators :@run_context, :resource_collection, :immediate_notifications, :delayed_notifications
39
39
 
40
+ def add_resource(resource)
41
+ resource.run_context = run_context
42
+ run_context.resource_collection.insert(resource)
43
+ end
44
+
40
45
  def load_block(&block)
41
46
  @recipe_name = 'block'
42
47
  instance_eval(&block)
@@ -54,10 +59,21 @@ module Cheffish
54
59
  @event_catcher.updates.size > 0
55
60
  end
56
61
 
57
- def self.inline_resource(provider, provider_action, &block)
62
+ # Builds a resource sans context, which can be later used in a new client's
63
+ # add_resource() method.
64
+ def self.build_resource(type, name, created_at=nil, &resource_attrs_block)
65
+ created_at ||= caller[0]
66
+ result = BasicChefClient.new.build_resource(type, name, created_at, &resource_attrs_block)
67
+ result
68
+ end
69
+
70
+ def self.inline_resource(provider, provider_action, *resources, &block)
58
71
  events = ProviderEventForwarder.new(provider, provider_action)
59
72
  client = BasicChefClient.new(provider.node, events)
60
- client.load_block(&block)
73
+ resources.each do |resource|
74
+ client.add_resource(resource)
75
+ end
76
+ client.load_block(&block) if block
61
77
  client.converge
62
78
  client.updated?
63
79
  end
@@ -215,10 +215,17 @@ module Cheffish
215
215
  def initialize(name, parent = nil)
216
216
  @name = name
217
217
  @parent = parent
218
+ @org = nil
218
219
  end
219
220
 
220
221
  attr_reader :name
221
222
  attr_reader :parent
223
+ attr_reader :org
222
224
  end
223
225
  end
226
+
227
+ # We are not interested in Chef's cloning behavior here.
228
+ def load_prior_resource
229
+ Chef::Log.debug("Overloading #{resource_name}.load_prior_resource with NOOP")
230
+ end
224
231
  end
@@ -45,8 +45,12 @@ module Cheffish
45
45
  end
46
46
  end
47
47
 
48
- def method_missing(name)
49
- self[name]
48
+ def method_missing(name, *args)
49
+ if args.count > 0
50
+ raise NoMethodError, "Unexpected method #{name} for MergedConfig with arguments #{args}"
51
+ else
52
+ self[name]
53
+ end
50
54
  end
51
55
 
52
56
  def key?(name)
@@ -82,5 +86,9 @@ module Cheffish
82
86
  end
83
87
  result
84
88
  end
89
+
90
+ def to_s
91
+ to_hash.to_s
92
+ end
85
93
  end
86
94
  end
@@ -1,5 +1,6 @@
1
1
  require 'cheffish'
2
2
 
3
+ require 'chef/version'
3
4
  require 'chef_zero/server'
4
5
  require 'chef/chef_fs/chef_fs_data_store'
5
6
  require 'chef/chef_fs/config'
@@ -7,26 +8,38 @@ require 'cheffish/chef_run_data'
7
8
  require 'cheffish/chef_run_listener'
8
9
  require 'chef/client'
9
10
  require 'chef/config'
11
+ require 'chef_zero/version'
10
12
  require 'cheffish/merged_config'
13
+ require 'chef/resource/chef_acl'
11
14
  require 'chef/resource/chef_client'
15
+ require 'chef/resource/chef_container'
12
16
  require 'chef/resource/chef_data_bag'
13
17
  require 'chef/resource/chef_data_bag_item'
14
18
  require 'chef/resource/chef_environment'
19
+ require 'chef/resource/chef_group'
20
+ require 'chef/resource/chef_mirror'
15
21
  require 'chef/resource/chef_node'
22
+ require 'chef/resource/chef_organization'
16
23
  require 'chef/resource/chef_role'
17
24
  require 'chef/resource/chef_user'
18
25
  require 'chef/resource/private_key'
19
26
  require 'chef/resource/public_key'
27
+ require 'chef/provider/chef_acl'
20
28
  require 'chef/provider/chef_client'
29
+ require 'chef/provider/chef_container'
21
30
  require 'chef/provider/chef_data_bag'
22
31
  require 'chef/provider/chef_data_bag_item'
23
32
  require 'chef/provider/chef_environment'
33
+ require 'chef/provider/chef_group'
34
+ require 'chef/provider/chef_mirror'
24
35
  require 'chef/provider/chef_node'
36
+ require 'chef/provider/chef_organization'
25
37
  require 'chef/provider/chef_role'
26
38
  require 'chef/provider/chef_user'
27
39
  require 'chef/provider/private_key'
28
40
  require 'chef/provider/public_key'
29
41
 
42
+
30
43
  class Chef
31
44
  module DSL
32
45
  module Recipe
@@ -49,7 +62,7 @@ class Chef
49
62
  def with_chef_local_server(options, &block)
50
63
  options[:host] ||= '127.0.0.1'
51
64
  options[:log_level] ||= Chef::Log.level
52
- options[:port] ||= 8901.upto(9900)
65
+ options[:port] ||= ChefZero::VERSION.to_f >= 2.2 ? 8901.upto(9900) : 8901
53
66
 
54
67
  # Create the data store chef-zero will use
55
68
  options[:data_store] ||= begin
@@ -59,16 +72,13 @@ class Chef
59
72
 
60
73
  # Ensure all paths are given
61
74
  %w(acl client cookbook container data_bag environment group node role).each do |type|
62
- options["#{type}_path".to_sym] ||= begin
75
+ options["#{type}_path"] ||= begin
63
76
  if options[:chef_repo_path].kind_of?(String)
64
- run_context.config.path_join(options[:chef_repo_path], "#{type}s")
77
+ Chef::Util::PathHelper.join(options[:chef_repo_path], "#{type}s")
65
78
  else
66
- options[:chef_repo_path].map { |path| run_context.config.path_join(path, "#{type}s")}
79
+ options[:chef_repo_path].map { |path| Chef::Util::PathHelper.join(path, "#{type}s")}
67
80
  end
68
81
  end
69
- # Work around issue in earlier versions of ChefFS where it expects strings for these
70
- # instead of symbols
71
- options["#{type}_path"] = options["#{type}_path".to_sym]
72
82
  end
73
83
 
74
84
  chef_fs = Chef::ChefFS::Config.new(options).local_fs
@@ -95,7 +105,7 @@ class Chef
95
105
  class Config
96
106
  default(:profile) { ENV['CHEF_PROFILE'] || 'default' }
97
107
  configurable(:private_keys)
98
- default(:private_key_paths) { [ path_join(config_dir, 'keys'), path_join(user_home, '.ssh') ] }
108
+ default(:private_key_paths) { [ Chef::Util::PathHelper.join(config_dir, 'keys'), Chef::Util::PathHelper.join(user_home, '.ssh') ] }
99
109
  default(:private_key_write_path) { private_key_paths.first }
100
110
  end
101
111
 
@@ -119,3 +129,19 @@ class Chef
119
129
  end
120
130
 
121
131
  end
132
+
133
+ # Chef 12 moved Chef::Config.path_join to PathHelper.join
134
+ if Chef::VERSION.to_i >= 12
135
+ require 'chef/util/path_helper'
136
+ else
137
+ require 'chef/config'
138
+ class Chef
139
+ class Util
140
+ class PathHelper
141
+ def join(*args)
142
+ Chef::Config.path_join(*args)
143
+ end
144
+ end
145
+ end
146
+ end
147
+ end
@@ -16,13 +16,16 @@
16
16
  # limitations under the License.
17
17
  #
18
18
 
19
+ require 'chef/version'
19
20
  require 'chef/http'
20
21
  require 'chef/http/authenticator'
21
22
  require 'chef/http/cookie_manager'
22
23
  require 'chef/http/decompressor'
23
24
  require 'chef/http/json_input'
24
25
  require 'chef/http/json_output'
25
- require 'chef/http/remote_request_id'
26
+ if Gem::Version.new(Chef::VERSION) >= Gem::Version.new('11.12')
27
+ require 'chef/http/remote_request_id'
28
+ end
26
29
 
27
30
  module Cheffish
28
31
  # Exactly like Chef::ServerAPI, but requires you to pass in what keys you want (no defaults)
@@ -30,13 +33,20 @@ module Cheffish
30
33
 
31
34
  def initialize(url, options = {})
32
35
  super(url, options)
36
+ root_url = URI.parse(url)
37
+ root_url.path = ''
38
+ @root_url = root_url.to_s
33
39
  end
34
40
 
41
+ attr_reader :root_url
42
+
35
43
  use Chef::HTTP::JSONInput
36
44
  use Chef::HTTP::JSONOutput
37
45
  use Chef::HTTP::CookieManager
38
46
  use Chef::HTTP::Decompressor
39
47
  use Chef::HTTP::Authenticator
40
- use Chef::HTTP::RemoteRequestID
48
+ if Gem::Version.new(Chef::VERSION) >= Gem::Version.new('11.12')
49
+ use Chef::HTTP::RemoteRequestID
50
+ end
41
51
  end
42
52
  end
@@ -1,3 +1,3 @@
1
1
  module Cheffish
2
- VERSION = '0.7.1'
2
+ VERSION = '0.8'
3
3
  end
data/lib/cheffish.rb CHANGED
@@ -9,8 +9,8 @@ require 'chef/application'
9
9
  module Cheffish
10
10
  NAME_REGEX = /^[.\-[:alnum:]_]+$/
11
11
 
12
- def self.inline_resource(provider, provider_action, &block)
13
- BasicChefClient.inline_resource(provider, provider_action, &block)
12
+ def self.inline_resource(provider, provider_action, *resources, &block)
13
+ BasicChefClient.inline_resource(provider, provider_action, *resources, &block)
14
14
  end
15
15
 
16
16
  def self.default_chef_server(config = profiled_config)
@@ -0,0 +1,20 @@
1
+ require 'cheffish/merged_config'
2
+
3
+ describe "merged_config" do
4
+
5
+ let(:config) do
6
+ Cheffish::MergedConfig.new({:test=>'val'})
7
+ end
8
+
9
+ it "returns value in config" do
10
+ expect(config.test).to eq('val')
11
+ end
12
+
13
+ it "raises a NoMethodError if calling an unknown method with arguments" do
14
+ expect{config.merge({:some => 'hash'})}.to raise_error(NoMethodError)
15
+ end
16
+
17
+ it "has an informative string representation" do
18
+ expect("#{config}").to eq("{:test=>\"val\"}")
19
+ end
20
+ end