cheffish 0.5 → 0.6

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1ddab480a3b4a6de49b00633583e17cc04d6c90a
4
- data.tar.gz: 249421b4118a974b9ae6d100394d9af3c1d45628
3
+ metadata.gz: 5f9cd98545fd8f6719d7e8ffbfbae5f13cf45126
4
+ data.tar.gz: 5e9c9755839e5f8af8e5c1c7c194d660928739fd
5
5
  SHA512:
6
- metadata.gz: c3c48ef29afb2df5f61ceb44efc65011cfe037426948d80a2e80e2061713fbac97cb6ffe3a60cdb9ea41d12fee792faa13a24d81407a9c35462eb6d5940161ad
7
- data.tar.gz: 79723d6d54d41ab88ec8a6ec71a7539536910c59a26b2d753ea0aa6f4c365709183d3198d85aaf210a5c40005fc8783c3c16a65df0e67eb8e09ae2ba54a3c2a4
6
+ metadata.gz: c38963743b1c66de812d573e8d814959fb393c817d0ce8c2a085129c2ae9608daa3cb2333a1ffa835a4c9b167f4407dba1f7097e357ef70827e89a3dc1a20e66
7
+ data.tar.gz: ec28e151c2ca132970c3674e25fb02cc270eece3731531dedf17676a0611d9b6521e7108d939e3cb35f86dcb22f931706ad08ad47581abf4f07a8392ecfed80e
@@ -0,0 +1,41 @@
1
+ require 'chef/provider/lwrp_base'
2
+ require 'chef_zero'
3
+
4
+ class Chef::Provider::ChefResolvedCookbooks < Chef::Provider::LWRPBase
5
+
6
+ action :resolve do
7
+ new_resource.cookbooks_from.each do |path|
8
+ ::Dir.entries(path).each do |name|
9
+ if ::File.directory?(::File.join(path, name)) && name != '.' && name != '..'
10
+ new_resource.berksfile.cookbook name, :path => ::File.join(path, name)
11
+ end
12
+ end
13
+ end
14
+
15
+ new_resource.berksfile.install
16
+
17
+ # Ridley really really wants a key :/
18
+ if new_resource.chef_server[:options][:signing_key_filename]
19
+ new_resource.berksfile.upload(
20
+ :server_url => new_resource.chef_server[:chef_server_url],
21
+ :client_name => new_resource.chef_server[:options][:client_name],
22
+ :client_key => new_resource.chef_server[:options][:signing_key_filename])
23
+ else
24
+ file = Tempfile.new('privatekey')
25
+ begin
26
+ file.write(ChefZero::PRIVATE_KEY)
27
+ file.close
28
+
29
+ new_resource.berksfile.upload(
30
+ :server_url => new_resource.chef_server[:chef_server_url],
31
+ :client_name => new_resource.chef_server[:options][:client_name] || 'me',
32
+ :client_key => file.path)
33
+
34
+ ensure
35
+ file.close
36
+ file.unlink
37
+ end
38
+ end
39
+ end
40
+
41
+ end
@@ -13,7 +13,7 @@ class Chef::Provider::PrivateKey < Chef::Provider::LWRPBase
13
13
  end
14
14
 
15
15
  action :delete do
16
- if Array(current_resource.action) == [ :create ]
16
+ if current_resource.path
17
17
  converge_by "delete private key #{new_path}" do
18
18
  ::File.unlink(new_path)
19
19
  end
@@ -39,7 +39,7 @@ class Chef::Provider::PrivateKey < Chef::Provider::LWRPBase
39
39
  # Create private key from source
40
40
  #
41
41
  desired_output = encode_private_key(new_source_key)
42
- if Array(current_resource.action) == [ :delete ] || desired_output != IO.read(new_path)
42
+ if current_resource.path == :none || desired_output != IO.read(new_path)
43
43
  converge_by "reformat key at #{new_resource.source_key_path} to #{new_resource.format} private key #{new_path} (#{new_resource.pass_phrase ? ", #{new_resource.cipher} password" : ""})" do
44
44
  IO.write(new_path, desired_output)
45
45
  end
@@ -49,28 +49,41 @@ class Chef::Provider::PrivateKey < Chef::Provider::LWRPBase
49
49
 
50
50
  else
51
51
  #
52
- # Create private key file
52
+ # Generate a new key
53
53
  #
54
- if Array(current_resource.action) == [ :delete ] || regenerate ||
54
+ if !current_private_key || regenerate ||
55
55
  (new_resource.regenerate_if_different &&
56
56
  (current_resource.size != new_resource.size ||
57
57
  current_resource.type != new_resource.type))
58
- action = (Array(current_resource.action) == [ :delete ]) ? "create" : "overwrite"
59
- converge_by "#{action} #{new_resource.type} private key #{new_path} (#{new_resource.size} bits#{new_resource.pass_phrase ? ", #{new_resource.cipher} password" : ""})" do
60
- case new_resource.type
61
- when :rsa
62
- if new_resource.exponent
63
- final_private_key = OpenSSL::PKey::RSA.generate(new_resource.size, new_resource.exponent)
64
- else
65
- final_private_key = OpenSSL::PKey::RSA.generate(new_resource.size)
66
- end
67
- when :dsa
68
- final_private_key = OpenSSL::PKey::DSA.generate(new_resource.size)
58
+
59
+ case new_resource.type
60
+ when :rsa
61
+ if new_resource.exponent
62
+ final_private_key = OpenSSL::PKey::RSA.generate(new_resource.size, new_resource.exponent)
63
+ else
64
+ final_private_key = OpenSSL::PKey::RSA.generate(new_resource.size)
69
65
  end
66
+ when :dsa
67
+ final_private_key = OpenSSL::PKey::DSA.generate(new_resource.size)
68
+ end
69
+
70
+ generated_key = true
71
+ else
72
+ final_private_key = current_private_key
73
+ generated_key = false
74
+ end
70
75
 
71
- if new_path != :none
76
+ if generated_key
77
+ generated_description = " (#{new_resource.size} bits#{new_resource.pass_phrase ? ", #{new_resource.cipher} password" : ""})"
78
+
79
+ if new_path != :none
80
+ action = current_resource.path == :none ? 'create' : 'overwrite'
81
+ converge_by "#{action} #{new_resource.type} private key #{new_path}#{generated_description}" do
72
82
  write_private_key(final_private_key)
73
83
  end
84
+ else
85
+ converge_by "generate private key#{generated_description}" do
86
+ end
74
87
  end
75
88
  else
76
89
  # Warn if existing key has different characteristics than expected
@@ -80,8 +93,6 @@ class Chef::Provider::PrivateKey < Chef::Provider::LWRPBase
80
93
  Chef::Log.warn("Mismatched key type! #{current_resource.path} is #{current_resource.type}, desired is #{new_resource.type} bytes. Use action :regenerate to force key regeneration.")
81
94
  end
82
95
 
83
- final_private_key = current_private_key
84
-
85
96
  if current_resource.format != new_resource.format
86
97
  converge_by "change format of #{new_resource.type} private key #{new_path} from #{current_resource.format} to #{new_resource.format}" do
87
98
  write_private_key(current_private_key)
@@ -145,25 +156,45 @@ class Chef::Provider::PrivateKey < Chef::Provider::LWRPBase
145
156
  attr_reader :current_private_key
146
157
 
147
158
  def new_path
159
+ new_key_with_path[1]
160
+ end
161
+
162
+ def new_key_with_path
148
163
  path = new_resource.path
149
164
  if path.is_a?(Symbol)
150
- path
151
- elsif Pathname.new(path).relative? && run_context.config[:private_key_write_path]
152
- @should_create_directory = true
153
- ::File.join(run_context.config[:private_key_write_path], path)
165
+ return [ nil, path ]
166
+ elsif Pathname.new(path).relative?
167
+ private_key, private_key_path = Cheffish.get_private_key_with_path(path, run_context.config)
168
+ if private_key
169
+ return [ private_key, (private_key_path || :none) ]
170
+ elsif run_context.config[:private_key_write_path]
171
+ @should_create_directory = true
172
+ path = ::File.join(run_context.config[:private_key_write_path], path)
173
+ return [ nil, path ]
174
+ else
175
+ raise "Could not find key #{path} and Chef::Config.private_key_write_path is not set."
176
+ end
177
+ elsif ::File.exist?(path)
178
+ return [ IO.read(path), path ]
154
179
  else
155
- path
180
+ return [ nil, path ]
156
181
  end
157
182
  end
158
183
 
159
184
  def load_current_resource
160
185
  resource = Chef::Resource::PrivateKey.new(new_resource.name, run_context)
161
186
 
187
+ new_key, new_path = new_key_with_path
162
188
  if new_path != :none && ::File.exist?(new_path)
163
189
  resource.path new_path
190
+ @current_file_mode = ::File.stat(new_path).mode
191
+ else
192
+ resource.path :none
193
+ end
164
194
 
195
+ if new_key
165
196
  begin
166
- key, key_format = Cheffish::KeyFormatter.decode(IO.read(new_path), new_resource.pass_phrase, new_path)
197
+ key, key_format = Cheffish::KeyFormatter.decode(new_key, new_resource.pass_phrase, new_path)
167
198
  if key
168
199
  @current_private_key = key
169
200
  resource.format key_format[:format]
@@ -173,7 +204,6 @@ class Chef::Provider::PrivateKey < Chef::Provider::LWRPBase
173
204
  resource.pass_phrase key_format[:pass_phrase]
174
205
  resource.cipher key_format[:cipher]
175
206
  end
176
- @current_file_mode = ::File.stat(new_path).mode
177
207
  rescue
178
208
  # If there's an error reading, we assume format and type are wrong and don't futz with them
179
209
  end
@@ -0,0 +1,31 @@
1
+ require 'chef/resource/lwrp_base'
2
+
3
+ class Chef::Resource::ChefResolvedCookbooks < Chef::Resource::LWRPBase
4
+ self.resource_name = 'chef_resolved_cookbooks'
5
+
6
+ actions :resolve, :nothing
7
+ default_action :resolve
8
+
9
+ def initialize(*args)
10
+ super
11
+ require 'berkshelf'
12
+ berksfile Berkshelf::Berksfile.new('/tmp/Berksfile')
13
+ chef_server run_context.cheffish.current_chef_server
14
+ @cookbooks_from = []
15
+ end
16
+
17
+ extend Forwardable
18
+
19
+ def_delegators :@berksfile, :cookbook, :extension, :group, :metadata, :source
20
+
21
+ def cookbooks_from(path = nil)
22
+ if path
23
+ @cookbooks_from << path
24
+ else
25
+ @cookbooks_from
26
+ end
27
+ end
28
+
29
+ attribute :berksfile
30
+ attribute :chef_server
31
+ end
@@ -81,7 +81,13 @@ class Cheffish::ActorProviderBase < Cheffish::ChefProviderBase
81
81
  new_resource.source_key
82
82
  end
83
83
  elsif new_resource.source_key_path
84
- source_key, source_key_format = Cheffish::KeyFormatter.decode(IO.read(new_resource.source_key_path), new_resource.source_key_pass_phrase, new_resource.source_key_path)
84
+ source_key_path = new_resource.source_key_path
85
+ if Pathname.new(source_key_path).relative?
86
+ source_key_str, source_key_path = Cheffish.get_private_key_with_path(source_key_path, run_context.config)
87
+ else
88
+ source_key_str = IO.read(source_key_path)
89
+ end
90
+ source_key, source_key_format = Cheffish::KeyFormatter.decode(source_key_str, new_resource.source_key_pass_phrase, source_key_path)
85
91
  if source_key.private?
86
92
  source_key.public_key
87
93
  else
@@ -117,4 +123,4 @@ class Cheffish::ActorProviderBase < Cheffish::ChefProviderBase
117
123
  end
118
124
  end
119
125
 
120
- end
126
+ end
@@ -4,7 +4,6 @@ require 'etc'
4
4
  require 'socket'
5
5
  require 'digest/md5'
6
6
  require 'base64'
7
- require 'openssl_pkcs8'
8
7
 
9
8
  module Cheffish
10
9
  class KeyFormatter
@@ -59,6 +58,7 @@ module Cheffish
59
58
  if RUBY_VERSION.to_f >= 2.0
60
59
  raise "PKCS8 SHA1 not supported in Ruby #{RUBY_VERSION}"
61
60
  end
61
+ require 'openssl_pkcs8'
62
62
  pkcs8_pem = key.to_pem_pkcs8
63
63
  pkcs8_base64 = pkcs8_pem.split("\n").reject { |l| l =~ /^-----/ }
64
64
  pkcs8_data = Base64.decode64(pkcs8_base64.join)
@@ -8,6 +8,26 @@ require 'cheffish/chef_run_listener'
8
8
  require 'chef/client'
9
9
  require 'chef/config'
10
10
  require 'cheffish/merged_config'
11
+ require 'chef/resource/chef_client'
12
+ require 'chef/resource/chef_data_bag'
13
+ require 'chef/resource/chef_data_bag_item'
14
+ require 'chef/resource/chef_environment'
15
+ require 'chef/resource/chef_node'
16
+ require 'chef/resource/chef_resolved_cookbooks'
17
+ require 'chef/resource/chef_role'
18
+ require 'chef/resource/chef_user'
19
+ require 'chef/resource/private_key'
20
+ require 'chef/resource/public_key'
21
+ require 'chef/provider/chef_client'
22
+ require 'chef/provider/chef_data_bag'
23
+ require 'chef/provider/chef_data_bag_item'
24
+ require 'chef/provider/chef_environment'
25
+ require 'chef/provider/chef_node'
26
+ require 'chef/provider/chef_resolved_cookbooks'
27
+ require 'chef/provider/chef_role'
28
+ require 'chef/provider/chef_user'
29
+ require 'chef/provider/private_key'
30
+ require 'chef/provider/public_key'
11
31
 
12
32
  class Chef
13
33
  module DSL
@@ -67,6 +87,10 @@ class Chef
67
87
 
68
88
  with_chef_server(chef_zero_server.url, &block)
69
89
  end
90
+
91
+ def get_private_key(name)
92
+ Cheffish.get_private_key(name, run_context.config)
93
+ end
70
94
  end
71
95
  end
72
96
 
@@ -1,3 +1,3 @@
1
1
  module Cheffish
2
- VERSION = '0.5'
2
+ VERSION = '0.6'
3
3
  end
data/lib/cheffish.rb CHANGED
@@ -74,12 +74,16 @@ module Cheffish
74
74
  end
75
75
  end
76
76
 
77
- def self.get_private_key(name, config = profiled_chef_config)
77
+ def self.get_private_key(name, config = profiled_config)
78
+ get_private_key_with_path(name, config)[0]
79
+ end
80
+
81
+ def self.get_private_key_with_path(name, config = profiled_config)
78
82
  if config[:private_keys] && config[:private_keys][name]
79
83
  if config[:private_keys][name].is_a?(String)
80
- IO.read(config[:private_keys][name])
84
+ return [ IO.read(config[:private_keys][name]), config[:private_keys][name] ]
81
85
  else
82
- config[:private_keys][name].to_pem
86
+ return [ config[:private_keys][name].to_pem, nil ]
83
87
  end
84
88
  elsif config[:private_key_paths]
85
89
  config[:private_key_paths].each do |private_key_path|
@@ -88,12 +92,13 @@ module Cheffish
88
92
  if ext == '' || ext == '.pem'
89
93
  key_name = key[0..-(ext.length+1)]
90
94
  if key_name == name
91
- return IO.read("#{private_key_path}/#{key}")
95
+ return [ IO.read("#{private_key_path}/#{key}"), "#{private_key_path}/#{key}" ]
92
96
  end
93
97
  end
94
98
  end
95
99
  end
96
100
  end
101
+ nil
97
102
  end
98
103
 
99
104
  NOT_PASSED=Object.new
@@ -207,21 +212,3 @@ end
207
212
  # Include all recipe objects so require 'cheffish' brings in the whole recipe DSL
208
213
 
209
214
  require 'cheffish/recipe_dsl'
210
- require 'chef/resource/chef_client'
211
- require 'chef/resource/chef_data_bag'
212
- require 'chef/resource/chef_data_bag_item'
213
- require 'chef/resource/chef_environment'
214
- require 'chef/resource/chef_node'
215
- require 'chef/resource/chef_role'
216
- require 'chef/resource/chef_user'
217
- require 'chef/resource/private_key'
218
- require 'chef/resource/public_key'
219
- require 'chef/provider/chef_client'
220
- require 'chef/provider/chef_data_bag'
221
- require 'chef/provider/chef_data_bag_item'
222
- require 'chef/provider/chef_environment'
223
- require 'chef/provider/chef_node'
224
- require 'chef/provider/chef_role'
225
- require 'chef/provider/chef_user'
226
- require 'chef/provider/private_key'
227
- require 'chef/provider/public_key'
@@ -9,7 +9,7 @@ describe Chef::Resource::ChefClient do
9
9
  extend SpecSupport
10
10
 
11
11
  when_the_chef_server 'is empty' do
12
- context 'and we have a private key' do
12
+ context 'and we have a private key with a path' do
13
13
  with_recipe do
14
14
  private_key "#{repo_path}/blah.pem"
15
15
  end
@@ -44,5 +44,33 @@ describe Chef::Resource::ChefClient do
44
44
  end
45
45
  end
46
46
  end
47
+
48
+ context "and a private_key 'blah' resource" do
49
+ before :each do
50
+ Chef::Config.private_key_paths = [ repo_path ]
51
+ end
52
+
53
+ with_recipe do
54
+ private_key 'blah'
55
+ end
56
+
57
+ context "and a chef_client 'foobar' resource with source_key_path 'blah'" do
58
+ with_converge do
59
+ chef_client 'foobar' do
60
+ source_key_path 'blah'
61
+ end
62
+ end
63
+
64
+ it 'the client is accessible via the given private key' do
65
+ chef_run.should have_updated 'chef_client[foobar]', :create
66
+ client = get('/clients/foobar')
67
+ key, format = Cheffish::KeyFormatter.decode(client['public_key'])
68
+ key.should be_public_key_for("#{repo_path}/blah.pem")
69
+
70
+ private_key = Cheffish::KeyFormatter.decode(Cheffish.get_private_key('blah'))
71
+ key.should be_public_key_for(private_key)
72
+ end
73
+ end
74
+ end
47
75
  end
48
76
  end
@@ -27,6 +27,41 @@ describe Chef::Resource::PrivateKey do
27
27
  end
28
28
  end
29
29
 
30
+ context 'with a private_key "blah" resource' do
31
+ before :each do
32
+ Dir.mkdir("#{repo_path}/other_keys")
33
+ Chef::Config.private_key_paths = [ repo_path, "#{repo_path}/other_keys" ]
34
+ end
35
+
36
+ with_recipe do
37
+ private_key 'blah'
38
+ end
39
+
40
+ it 'the private key is created in the private_key_write_path' do
41
+ chef_run.should have_updated "private_key[blah]", :create
42
+ Chef::Config.private_key_write_path.should == repo_path
43
+ File.exist?("#{repo_path}/blah").should be_true
44
+ File.exist?("#{repo_path}/other_keys/blah").should be_false
45
+ OpenSSL::PKey.read(IO.read("#{repo_path}/blah")).kind_of?(OpenSSL::PKey::RSA).should be_true
46
+ OpenSSL::PKey.read(Cheffish.get_private_key('blah')).kind_of?(OpenSSL::PKey::RSA).should be_true
47
+ end
48
+
49
+ context 'and the private key already exists somewhere not in the write path' do
50
+ before :each do
51
+ Cheffish::BasicChefClient.converge_block do
52
+ private_key "#{repo_path}/other_keys/blah"
53
+ end
54
+ end
55
+
56
+ it 'the private key should not update' do
57
+ chef_run.should_not have_updated "private_key[blah]", :create
58
+
59
+ File.exist?("#{repo_path}/blah").should be_false
60
+ File.exist?("#{repo_path}/other_keys/blah").should be_true
61
+ end
62
+ end
63
+ end
64
+
30
65
  context 'with a private key' do
31
66
  before :each do
32
67
  Cheffish::BasicChefClient.converge_block do
@@ -99,6 +99,16 @@ RSpec::Matchers.define :have_updated do |resource_name, *expected_actions|
99
99
  end
100
100
  result
101
101
  end
102
+ failure_message_for_should_not do |actual|
103
+ updates = actual.select { |event, resource, action| event == :resource_updated }.to_a
104
+ result = "expected that the chef_run would not #{expected_actions.join(',')} #{resource_name}."
105
+ if updates.size > 0
106
+ result << " Actual updates were #{updates.map { |event, resource, action| "#{resource.to_s} => #{action.inspect}" }.join(', ')}"
107
+ else
108
+ result << " Nothing was updated."
109
+ end
110
+ result
111
+ end
102
112
  end
103
113
 
104
114
  RSpec.configure do |config|
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cheffish
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.5'
4
+ version: '0.6'
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Keiser
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-06-04 00:00:00.000000000 Z
11
+ date: 2014-06-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: chef
@@ -24,20 +24,6 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
- - !ruby/object:Gem::Dependency
28
- name: openssl_pkcs8
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: '0'
34
- type: :runtime
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: '0'
41
27
  - !ruby/object:Gem::Dependency
42
28
  name: rake
43
29
  requirement: !ruby/object:Gem::Requirement
@@ -82,6 +68,7 @@ files:
82
68
  - lib/chef/provider/chef_data_bag_item.rb
83
69
  - lib/chef/provider/chef_environment.rb
84
70
  - lib/chef/provider/chef_node.rb
71
+ - lib/chef/provider/chef_resolved_cookbooks.rb
85
72
  - lib/chef/provider/chef_role.rb
86
73
  - lib/chef/provider/chef_user.rb
87
74
  - lib/chef/provider/private_key.rb
@@ -91,6 +78,7 @@ files:
91
78
  - lib/chef/resource/chef_data_bag_item.rb
92
79
  - lib/chef/resource/chef_environment.rb
93
80
  - lib/chef/resource/chef_node.rb
81
+ - lib/chef/resource/chef_resolved_cookbooks.rb
94
82
  - lib/chef/resource/chef_role.rb
95
83
  - lib/chef/resource/chef_user.rb
96
84
  - lib/chef/resource/in_parallel.rb