cheffish 0.5 → 0.6

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