cheffish 0.3 → 0.4

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: 5f6b8abbcddf03b097bc9380a4bad5367f760f2f
4
- data.tar.gz: 3f17d2781c140a66a869ecbedfd4c0c74326f1f9
3
+ metadata.gz: 2c99e67f4f2af51e4be1bb7f4d127973b0060789
4
+ data.tar.gz: e8547a16bc4df37aa4d29b00f6f36af3ec57c381
5
5
  SHA512:
6
- metadata.gz: 798aeb7bfd711164e71e613c2a3124aaf2cb2a8a344010aa6b97e17637802fc6ded341525677f97adc388f96360f7c28ce67145e519cf2ccc5b22fc199acd9b7
7
- data.tar.gz: 0cbe97227f83d68327b8023f4ba23eaa81459f034fe31f5ee3e9a69bdb395cfdaaf7785b3dc1a458513312d32ff8a984ef10a6a210133d4462f3a77728f5433a
6
+ metadata.gz: 5ac67f69abb511dab697a2a6d77b058dcfb665864d0d647b332a7a820cb59e576406fbabb1fb22a417c2dbb4cb66b7683d537ebe1b97dfa1779a4e985577dcea
7
+ data.tar.gz: 85e3d63ac54c4b1665d2b4957be6982731f1a701cab9709537e545890c7415331773c47ff187cbf31a1b5328813cd6c8c6d361ad1aa9a4404f8a73a49c1b0f89
@@ -5,11 +5,11 @@ require 'cheffish/key_formatter'
5
5
  class Chef::Provider::PrivateKey < Chef::Provider::LWRPBase
6
6
 
7
7
  action :create do
8
- create_key(false)
8
+ create_key(false, :create)
9
9
  end
10
10
 
11
11
  action :regenerate do
12
- create_key(true)
12
+ create_key(true, :regenerate)
13
13
  end
14
14
 
15
15
  action :delete do
@@ -26,7 +26,7 @@ class Chef::Provider::PrivateKey < Chef::Provider::LWRPBase
26
26
  true
27
27
  end
28
28
 
29
- def create_key(regenerate)
29
+ def create_key(regenerate, action)
30
30
  final_private_key = nil
31
31
  if new_source_key
32
32
  #
@@ -92,7 +92,7 @@ class Chef::Provider::PrivateKey < Chef::Provider::LWRPBase
92
92
  if new_resource.public_key_path
93
93
  public_key_path = new_resource.public_key_path
94
94
  public_key_format = new_resource.public_key_format
95
- Cheffish.inline_resource(self) do
95
+ Cheffish.inline_resource(self, action) do
96
96
  public_key public_key_path do
97
97
  source_key final_private_key
98
98
  format public_key_format
@@ -139,7 +139,7 @@ class Chef::Provider::PrivateKey < Chef::Provider::LWRPBase
139
139
  attr_reader :current_private_key
140
140
 
141
141
  def load_current_resource
142
- resource = Chef::Resource::PrivateKey.new(new_resource.name)
142
+ resource = Chef::Resource::PrivateKey.new(new_resource.name, run_context)
143
143
 
144
144
  if new_resource.path != :none && ::File.exist?(new_resource.path)
145
145
  resource.path new_resource.path
@@ -62,7 +62,7 @@ class Chef::Provider::PublicKey < Chef::Provider::LWRPBase
62
62
 
63
63
  def load_current_resource
64
64
  if ::File.exist?(new_resource.path)
65
- resource = Chef::Resource::PublicKey.new(new_resource.path)
65
+ resource = Chef::Resource::PublicKey.new(new_resource.path, run_context)
66
66
  begin
67
67
  key, key_format = Cheffish::KeyFormatter.decode(IO.read(new_resource.path), nil, new_resource.path)
68
68
  if key
@@ -9,7 +9,7 @@ class Chef::Resource::ChefClient < Chef::Resource::LWRPBase
9
9
 
10
10
  def initialize(*args)
11
11
  super
12
- chef_server Cheffish.enclosing_chef_server
12
+ chef_server run_context.cheffish.current_chef_server
13
13
  end
14
14
 
15
15
  # Client attributes
@@ -9,7 +9,7 @@ class Chef::Resource::ChefDataBag < Chef::Resource::LWRPBase
9
9
 
10
10
  def initialize(*args)
11
11
  super
12
- chef_server Cheffish.enclosing_chef_server
12
+ chef_server run_context.cheffish.current_chef_server
13
13
  end
14
14
 
15
15
  attribute :name, :kind_of => String, :regex => Cheffish::NAME_REGEX, :name_attribute => true
@@ -12,18 +12,18 @@ class Chef::Resource::ChefDataBagItem < Chef::Resource::LWRPBase
12
12
  super
13
13
  name @name
14
14
  if !data_bag
15
- data_bag Cheffish.enclosing_data_bag
15
+ data_bag run_context.cheffish.current_data_bag
16
16
  end
17
- if Cheffish.enclosing_data_bag_item_encryption
18
- @encrypt = true if Cheffish.enclosing_data_bag_item_encryption[:encrypt_all]
19
- @secret = Cheffish.enclosing_data_bag_item_encryption[:secret]
20
- @secret_path = Cheffish.enclosing_data_bag_item_encryption[:secret_path] || Chef::Config[:encrypted_data_bag_secret]
21
- @encryption_cipher = Cheffish.enclosing_data_bag_item_encryption[:encryption_cipher]
22
- @encryption_version = Cheffish.enclosing_data_bag_item_encryption[:encryption_version]
23
- @old_secret = Cheffish.enclosing_data_bag_item_encryption[:old_secret]
24
- @old_secret_path = Cheffish.enclosing_data_bag_item_encryption[:old_secret_path]
17
+ if run_context.cheffish.current_data_bag_item_encryption
18
+ @encrypt = true if run_context.cheffish.current_data_bag_item_encryption[:encrypt_all]
19
+ @secret = run_context.cheffish.current_data_bag_item_encryption[:secret]
20
+ @secret_path = run_context.cheffish.current_data_bag_item_encryption[:secret_path] || Chef::Config[:encrypted_data_bag_secret]
21
+ @encryption_cipher = run_context.cheffish.current_data_bag_item_encryption[:encryption_cipher]
22
+ @encryption_version = run_context.cheffish.current_data_bag_item_encryption[:encryption_version]
23
+ @old_secret = run_context.cheffish.current_data_bag_item_encryption[:old_secret]
24
+ @old_secret_path = run_context.cheffish.current_data_bag_item_encryption[:old_secret_path]
25
25
  end
26
- chef_server Cheffish.enclosing_chef_server
26
+ chef_server run_context.cheffish.current_chef_server
27
27
  end
28
28
 
29
29
  def name(*args)
@@ -10,7 +10,7 @@ class Chef::Resource::ChefEnvironment < Chef::Resource::LWRPBase
10
10
 
11
11
  def initialize(*args)
12
12
  super
13
- chef_server Cheffish.enclosing_chef_server
13
+ chef_server run_context.cheffish.current_chef_server
14
14
  end
15
15
 
16
16
  attribute :name, :kind_of => String, :regex => Cheffish::NAME_REGEX, :name_attribute => true
@@ -68,4 +68,4 @@ class Chef::Resource::ChefEnvironment < Chef::Resource::LWRPBase
68
68
 
69
69
  alias :attributes :default_attributes
70
70
  alias :attribute :default
71
- end
71
+ end
@@ -10,8 +10,8 @@ class Chef::Resource::ChefNode < Chef::Resource::LWRPBase
10
10
  # Grab environment from with_environment
11
11
  def initialize(*args)
12
12
  super
13
- chef_environment Cheffish.enclosing_environment
14
- chef_server Cheffish.enclosing_chef_server
13
+ chef_environment run_context.cheffish.current_environment
14
+ chef_server run_context.cheffish.current_chef_server
15
15
  end
16
16
 
17
17
  Cheffish.node_attributes(self)
@@ -11,7 +11,7 @@ class Chef::Resource::ChefRole < Chef::Resource::LWRPBase
11
11
  # Grab environment from with_environment
12
12
  def initialize(*args)
13
13
  super
14
- chef_server Cheffish.enclosing_chef_server
14
+ chef_server run_context.cheffish.current_chef_server
15
15
  end
16
16
 
17
17
  attribute :name, :kind_of => String, :regex => Cheffish::NAME_REGEX, :name_attribute => true
@@ -10,7 +10,7 @@ class Chef::Resource::ChefUser < Chef::Resource::LWRPBase
10
10
  # Grab environment from with_environment
11
11
  def initialize(*args)
12
12
  super
13
- chef_server Cheffish.enclosing_chef_server
13
+ chef_server run_context.cheffish.current_chef_server
14
14
  end
15
15
 
16
16
  # Client attributes
data/lib/cheffish.rb CHANGED
@@ -1,56 +1,11 @@
1
1
  require 'chef/run_list/run_list_item'
2
- require 'cheffish/inline_resource'
2
+ require 'cheffish/basic_chef_client'
3
3
 
4
4
  module Cheffish
5
5
  NAME_REGEX = /^[.\-[:alnum:]_]+$/
6
6
 
7
- @@enclosing_data_bag = nil
8
- def self.enclosing_data_bag
9
- @@enclosing_data_bag
10
- end
11
- def self.enclosing_data_bag=(name)
12
- @@enclosing_data_bag = name
13
- end
14
-
15
- @@enclosing_environment = nil
16
- def self.enclosing_environment
17
- @@enclosing_environment
18
- end
19
- def self.enclosing_environment=(name)
20
- @@enclosing_environment = name
21
- end
22
-
23
- @@enclosing_data_bag_item_encryption = nil
24
- def self.enclosing_data_bag_item_encryption
25
- @@enclosing_data_bag_item_encryption
26
- end
27
- def self.enclosing_data_bag_item_encryption=(options)
28
- @@enclosing_data_bag_item_encryption = options
29
- end
30
-
31
- def self.inline_resource(provider, &block)
32
- InlineResource.new(provider).instance_eval(&block)
33
- end
34
-
35
- @@enclosing_chef_server = nil
36
- def self.enclosing_chef_server
37
- @@enclosing_chef_server || {
38
- :chef_server_url => Chef::Config[:chef_server_url],
39
- :options => {
40
- :client_name => Chef::Config[:node_name],
41
- :signing_key_filename => Chef::Config[:client_key]
42
- }
43
- }
44
- end
45
- def self.enclosing_chef_server=(chef_server)
46
- @@enclosing_chef_server = chef_server
47
- end
48
-
49
- def self.reset
50
- @@enclosing_data_bag = nil
51
- @@enclosing_environment = nil
52
- @@enclosing_data_bag_item_encryption = nil
53
- @@enclosing_chef_server = nil
7
+ def self.inline_resource(provider, provider_action, &block)
8
+ BasicChefClient.inline_resource(provider, provider_action, &block)
54
9
  end
55
10
 
56
11
  NOT_PASSED=Object.new
@@ -0,0 +1,96 @@
1
+ require 'chef/dsl/recipe'
2
+ require 'chef/event_dispatch/base'
3
+ require 'chef/event_dispatch/dispatcher'
4
+ require 'chef/node'
5
+ require 'chef/run_context'
6
+ require 'chef/runner'
7
+ require 'forwardable'
8
+
9
+ module Cheffish
10
+ class BasicChefClient
11
+ include Chef::DSL::Recipe
12
+
13
+ def initialize(node = nil, events = nil)
14
+ if !node
15
+ node = Chef::Node.new
16
+ node.name 'basic_client'
17
+ node.automatic[:platform] = 'test'
18
+ node.automatic[:platform_version] = 'test'
19
+ end
20
+
21
+ @event_catcher = BasicChefClientEvents.new
22
+ dispatcher = Chef::EventDispatch::Dispatcher.new(@event_catcher)
23
+ dispatcher.register(events) if events
24
+ @run_context = Chef::RunContext.new(node, {}, dispatcher)
25
+ @updated = []
26
+ @cookbook_name = 'basic_client'
27
+ end
28
+
29
+ extend Forwardable
30
+
31
+ # Stuff recipes need
32
+ attr_reader :run_context
33
+ attr_accessor :cookbook_name
34
+ attr_accessor :recipe_name
35
+ def_delegators :@run_context, :resource_collection, :immediate_notifications, :delayed_notifications
36
+
37
+ def load_block(&block)
38
+ @recipe_name = 'block'
39
+ instance_eval(&block)
40
+ end
41
+
42
+ def converge
43
+ Chef::Runner.new(self).converge
44
+ end
45
+
46
+ def updates
47
+ @event_catcher.updates
48
+ end
49
+
50
+ def updated?
51
+ @event_catcher.updates.size > 0
52
+ end
53
+
54
+ def self.inline_resource(provider, provider_action, &block)
55
+ events = ProviderEventForwarder.new(provider, provider_action)
56
+ client = BasicChefClient.new(provider.node)
57
+ client.load_block(&block)
58
+ client.converge
59
+ client.updated?
60
+ end
61
+
62
+ def self.converge_block(node = nil, events = nil, &block)
63
+ client = BasicChefClient.new(node, events)
64
+ client.load_block(&block)
65
+ client.converge
66
+ client.updated?
67
+ end
68
+
69
+ class BasicChefClientEvents < Chef::EventDispatch::Base
70
+ def initialize
71
+ @updates = []
72
+ end
73
+
74
+ attr_reader :updates
75
+
76
+ # Called after a resource has been completely converged.
77
+ def resource_updated(resource, action)
78
+ updates << [ resource, action ]
79
+ end
80
+ end
81
+
82
+ class ProviderEventForwarder < Chef::EventDispatch::Base
83
+ def initialize(provider, provider_action)
84
+ @provider = provider
85
+ @provider_action = provider_action
86
+ end
87
+
88
+ attr_reader :provider
89
+ attr_reader :provider_action
90
+
91
+ def resource_update_applied(resource, action, update)
92
+ provider.run_context.events.resource_update_applied(provider.new_resource, provider_action, update)
93
+ end
94
+ end
95
+ end
96
+ end
@@ -14,7 +14,7 @@ module Cheffish
14
14
  end
15
15
 
16
16
  def not_found_resource
17
- resource = resource_class.new(new_resource.name)
17
+ resource = resource_class.new(new_resource.name, run_context)
18
18
  resource.action :delete
19
19
  resource
20
20
  end
@@ -67,7 +67,7 @@ module Cheffish
67
67
  end
68
68
 
69
69
  def json_to_resource(json)
70
- resource = resource_class.new(new_resource.name)
70
+ resource = resource_class.new(new_resource.name, run_context)
71
71
  keys.each do |json_key, resource_key|
72
72
  resource.send(resource_key, json.delete(json_key))
73
73
  end
@@ -0,0 +1,25 @@
1
+ require 'chef/config'
2
+ require 'cheffish/with_pattern'
3
+
4
+ module Cheffish
5
+ class ChefRunData
6
+ def initialize
7
+ @local_servers = []
8
+ @current_chef_server = {
9
+ :chef_server_url => Chef::Config[:chef_server_url],
10
+ :options => {
11
+ :client_name => Chef::Config[:node_name],
12
+ :signing_key_filename => Chef::Config[:client_key]
13
+ }
14
+ }
15
+ end
16
+
17
+ extend Cheffish::WithPattern
18
+ with :data_bag
19
+ with :environment
20
+ with :data_bag_item_encryption
21
+ with :chef_server
22
+
23
+ attr_reader :local_servers
24
+ end
25
+ end
@@ -0,0 +1,28 @@
1
+ require 'chef/event_dispatch/base'
2
+
3
+ module Cheffish
4
+ class ChefRunListener < Chef::EventDispatch::Base
5
+ def initialize(run_context)
6
+ @run_context = run_context
7
+ end
8
+
9
+ attr_reader :run_context
10
+
11
+ def run_complete(node)
12
+ disconnect
13
+ end
14
+
15
+ def run_failed(exception)
16
+ disconnect
17
+ end
18
+
19
+ private
20
+
21
+ def disconnect
22
+ # Stop the servers
23
+ run_context.cheffish.local_servers.each do |server|
24
+ server.stop
25
+ end
26
+ end
27
+ end
28
+ end
@@ -3,6 +3,8 @@ require 'net/ssh'
3
3
  require 'etc'
4
4
  require 'socket'
5
5
  require 'digest/md5'
6
+ require 'base64'
7
+ require 'openssl_pkcs8'
6
8
 
7
9
  module Cheffish
8
10
  class KeyFormatter
@@ -44,10 +46,21 @@ module Cheffish
44
46
  end
45
47
  when :der
46
48
  key.to_der
47
- when :fingerprint
49
+ when :fingerprint, :pkcs1md5fingerprint
48
50
  hexes = Digest::MD5.hexdigest(key.to_der)
49
51
  # Put : between every pair of hexes
50
52
  hexes.scan(/../).join(':')
53
+ when :rfc4716md5fingerprint
54
+ type, base64_data, etc = encode_openssh_key(key).split
55
+ data = Base64.decode64(base64_data)
56
+ hexes = Digest::MD5.hexdigest(data)
57
+ hexes.scan(/../).join(':')
58
+ when :pkcs8sha1fingerprint
59
+ pkcs8_pem = key.to_pem_pkcs8
60
+ pkcs8_base64 = pkcs8_pem.split("\n").reject { |l| l =~ /^-----/ }
61
+ pkcs8_data = Base64.decode64(pkcs8_base64.join)
62
+ hexes = Digest::SHA1.hexdigest(pkcs8_data)
63
+ hexes.scan(/../).join(':')
51
64
  else
52
65
  raise "Unrecognized key format #{format}"
53
66
  end
@@ -3,109 +3,84 @@ require 'cheffish'
3
3
  require 'chef_zero/server'
4
4
  require 'chef/chef_fs/chef_fs_data_store'
5
5
  require 'chef/chef_fs/config'
6
+ require 'cheffish/chef_run_data'
7
+ require 'cheffish/chef_run_listener'
8
+ require 'chef/client'
6
9
 
7
10
  class Chef
8
- class Recipe
9
- def with_chef_data_bag(name)
10
- old_enclosing_data_bag = Cheffish.enclosing_data_bag
11
- Cheffish.enclosing_data_bag = name
12
- if block_given?
13
- begin
14
- yield
15
- ensure
16
- Cheffish.enclosing_data_bag = old_enclosing_data_bag
17
- end
11
+ module DSL
12
+ module Recipe
13
+ def with_chef_data_bag(name)
14
+ run_context.cheffish.with_data_bag(name, &block)
18
15
  end
19
- end
20
16
 
21
- def with_chef_environment(name)
22
- old_enclosing_environment = Cheffish.enclosing_environment
23
- Cheffish.enclosing_environment = name
24
- if block_given?
25
- begin
26
- yield
27
- ensure
28
- Cheffish.enclosing_environment = old_enclosing_environment
29
- end
17
+ def with_chef_environment(name, &block)
18
+ run_context.cheffish.with_environment(name, &block)
30
19
  end
31
- end
32
20
 
33
- def with_chef_data_bag_item_encryption(encryption_options)
34
- old_enclosing_data_bag_item_encryption = Cheffish.enclosing_data_bag_item_encryption
35
- Cheffish.enclosing_data_bag_item_encryption = encryption_options
36
- if block_given?
37
- begin
38
- yield
39
- ensure
40
- Cheffish.enclosing_data_bag_item_encryption = old_enclosing_data_bag_item_encryption
41
- end
21
+ def with_chef_data_bag_item_encryption(encryption_options, &block)
22
+ run_context.cheffish.with_data_bag_item_encryption(encryption_options, &block)
42
23
  end
43
- end
44
24
 
45
- def with_chef_server(server_url, options = {})
46
- old_enclosing_chef_server = Cheffish.enclosing_chef_server
47
- Cheffish.enclosing_chef_server = { :chef_server_url => server_url, :options => options }
48
- if block_given?
49
- begin
50
- yield
51
- ensure
52
- Cheffish.enclosing_chef_server = old_enclosing_chef_server
53
- end
25
+ def with_chef_server(server_url, options = {}, &block)
26
+ run_context.cheffish.with_chef_server({ :chef_server_url => server_url, :options => options }, &block)
54
27
  end
55
- end
56
28
 
57
- def with_chef_local_server(options, &block)
58
- options[:host] ||= '127.0.0.1'
59
- options[:log_level] ||= Chef::Log.level
60
- options[:port] ||= 8900
29
+ def with_chef_local_server(options, &block)
30
+ options[:host] ||= '127.0.0.1'
31
+ options[:log_level] ||= Chef::Log.level
32
+ options[:port] ||= 8900
61
33
 
62
- # Create the data store chef-zero will use
63
- options[:data_store] ||= begin
64
- if !options[:chef_repo_path]
65
- raise "chef_repo_path must be specified to with_chef_local_server"
66
- end
34
+ # Create the data store chef-zero will use
35
+ options[:data_store] ||= begin
36
+ if !options[:chef_repo_path]
37
+ raise "chef_repo_path must be specified to with_chef_local_server"
38
+ end
67
39
 
68
- # Ensure all paths are given
69
- %w(acl client cookbook container data_bag environment group node role).each do |type|
70
- options["#{type}_path".to_sym] ||= begin
71
- if options[:chef_repo_path].kind_of?(String)
72
- Chef::Config.path_join(options[:chef_repo_path], "#{type}s")
73
- else
74
- options[:chef_repo_path].map { |path| Chef::Config.path_join(path, "#{type}s")}
40
+ # Ensure all paths are given
41
+ %w(acl client cookbook container data_bag environment group node role).each do |type|
42
+ options["#{type}_path".to_sym] ||= begin
43
+ if options[:chef_repo_path].kind_of?(String)
44
+ Chef::Config.path_join(options[:chef_repo_path], "#{type}s")
45
+ else
46
+ options[:chef_repo_path].map { |path| Chef::Config.path_join(path, "#{type}s")}
47
+ end
75
48
  end
49
+ # Work around issue in earlier versions of ChefFS where it expects strings for these
50
+ # instead of symbols
51
+ options["#{type}_path"] = options["#{type}_path".to_sym]
76
52
  end
77
- # Work around issue in earlier versions of ChefFS where it expects strings for these
78
- # instead of symbols
79
- options["#{type}_path"] = options["#{type}_path".to_sym]
80
- end
81
53
 
82
- chef_fs = Chef::ChefFS::Config.new(options).local_fs
83
- chef_fs.write_pretty_json = true
84
- Chef::ChefFS::ChefFSDataStore.new(chef_fs)
85
- end
54
+ chef_fs = Chef::ChefFS::Config.new(options).local_fs
55
+ chef_fs.write_pretty_json = true
56
+ Chef::ChefFS::ChefFSDataStore.new(chef_fs)
57
+ end
86
58
 
87
- # Start the chef-zero server
88
- Chef::Log.info("Starting chef-zero on port #{options[:port]} with repository at #{options[:data_store].chef_fs.fs_description}")
89
- chef_zero_server = ChefZero::Server.new(options)
90
- chef_zero_server.start_background
59
+ # Start the chef-zero server
60
+ Chef::Log.info("Starting chef-zero on port #{options[:port]} with repository at #{options[:data_store].chef_fs.fs_description}")
61
+ chef_zero_server = ChefZero::Server.new(options)
62
+ chef_zero_server.start_background
91
63
 
92
- @@local_servers ||= []
93
- @@local_servers << chef_zero_server
64
+ run_context.cheffish.local_servers << chef_zero_server
94
65
 
95
- with_chef_server(chef_zero_server.url, &block)
66
+ with_chef_server(chef_zero_server.url, &block)
67
+ end
96
68
  end
69
+ end
97
70
 
98
- def self.stop_local_servers
99
- # Just in case we're running this out of order:
100
- @@local_servers ||= []
101
-
102
- # Stop the servers
103
- @@local_servers.each do |server|
104
- server.stop
71
+ class RunContext
72
+ def cheffish
73
+ @cheffish ||= begin
74
+ run_data = Cheffish::ChefRunData.new
75
+ events.register(Cheffish::ChefRunListener.new(self))
76
+ run_data
105
77
  end
106
-
107
- # Clean up after ourselves (don't want to stop a server twice)
108
- @@local_servers = []
109
78
  end
110
79
  end
80
+
81
+ Chef::Client.when_run_starts do |run_status|
82
+ # Pulling on cheffish_run_data makes it initialize right now
83
+ run_status.run_context.cheffish
84
+ end
85
+
111
86
  end
@@ -1,3 +1,3 @@
1
1
  module Cheffish
2
- VERSION = '0.3'
2
+ VERSION = '0.4'
3
3
  end
@@ -0,0 +1,21 @@
1
+ module Cheffish
2
+ module WithPattern
3
+ def with(symbol)
4
+ class_eval <<EOM
5
+ attr_accessor :current_#{symbol}
6
+
7
+ def with_#{symbol}(value)
8
+ old_value = self.current_#{symbol}
9
+ self.current_#{symbol} = value
10
+ if block_given?
11
+ begin
12
+ yield
13
+ ensure
14
+ self.current_#{symbol} = old_value
15
+ end
16
+ end
17
+ end
18
+ EOM
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,64 @@
1
+ require 'cheffish/key_formatter'
2
+ require 'support/key_support'
3
+
4
+ describe 'Cheffish fingerprint key formatter' do
5
+
6
+ # Sample key: 0x9a6fa4c43b328c3d04c1fbc0498539218b6728e41cd35f6d27d491ef705f0b2083dc1ac977da19f54ba82b044773f20667e9627c543abb3b41b6eb9e4318ca3c68f487bbd0f1c9eea9a3101b7d1d180983c5440ac4183e78e9e256fa687d8aac63b21617a4b02b35bf5e307a3b76961a16cd8493e923536b34cc2b2da8d45220d57ef2243b081b555b84f1da0ade0e896c2aa96911b41430b59eaf75dbffb7eaa7c5b3a686f2d47a24e3b7f1acb0844f84a2fedc63660ae366b800cd9448093d6b1d96503ebb7807b48257e16c3d8a7c9a8cc5dd63116aa673bd9e09754de09358486e743e34c6a3642eeb64b2208efc96df39151572557a75638bd059c21a55 = 0xd6e92677d4e1d2aa6d14f87b5f49ee6916c6b92411536254fae4a21e82eebb0a40600247c701c1c938b21ca9f25b7b330c35fded57b4de3a951e83329a80bdbf2ba138fe2f190bffce43967b5fa93b179367bcd15cb1db7f9e3ab62caca95dc9489b62bc0a10b53841b932455a43409f96eed90dc80abc8cce5593ead8f0a26d * 0xb7f68cd427045788d5e315375f71d3a416784ec2597776a60ed77c821294d9bd66e96658bdcb43072cee0c849d297bd9f94991738f1a0df313ceb51b093a9372f12a61987f40e7a03d773911deb270916a574962ae8ff4f2d8bfcedee1c885e9c3e54212471636a6330b05b78c3a7ddf96b013be389a08ab7971db2f68fb2689
7
+
8
+ sample_private_key = <<EOF
9
+ -----BEGIN RSA PRIVATE KEY-----
10
+ MIIEowIBAAKCAQEAmm+kxDsyjD0EwfvASYU5IYtnKOQc019tJ9SR73BfCyCD3BrJd9oZ9UuoKwRH
11
+ c/IGZ+lifFQ6uztBtuueQxjKPGj0h7vQ8cnuqaMQG30dGAmDxUQKxBg+eOniVvpofYqsY7IWF6Sw
12
+ KzW/XjB6O3aWGhbNhJPpI1NrNMwrLajUUiDVfvIkOwgbVVuE8doK3g6JbCqpaRG0FDC1nq912/+3
13
+ 6qfFs6aG8tR6JOO38aywhE+Eov7cY2YK42a4AM2USAk9ax2WUD67eAe0glfhbD2KfJqMxd1jEWqm
14
+ c72eCXVN4JNYSG50PjTGo2Qu62SyII78lt85FRVyVXp1Y4vQWcIaVQIDAQABAoIBABY+JC37FLGs
15
+ DCZgOvab0HmrWUVDbX9oDBGjhQ1GUvoISdWGqiOv7vMsXWEssZnabt/CdmPPwdG7nCBbWSTyyhXf
16
+ S/DMtTBN1CjsimJbJ7iRjj/4J9DMaRsDHI1IbYo/UcreGF55YsImcJSBSOmNj9rcE+eXYgmrdxJY
17
+ oZNm8IWPaZ1/8KdPHSq6/HfTzRxXhcGOMGnf3lGfzkzIbV9Ee88Lv9sSV3bYrOsWMNabOe2TeTpC
18
+ UTfFkC++0RkFjEDINSCnoCi+ybzHLUDnurANCwnRWLTVEAeffwNVmiDfgimuqFtzCInW5/5bOTPz
19
+ rBmcC6QAFbyk2WKAlY8Zd4SBYqECgYEA1ukmd9Th0qptFPh7X0nuaRbGuSQRU2JU+uSiHoLuuwpA
20
+ YAJHxwHByTiyHKnyW3szDDX97Ve03jqVHoMymoC9vyuhOP4vGQv/zkOWe1+pOxeTZ7zRXLHbf546
21
+ tiysqV3JSJtivAoQtThBuTJFWkNAn5bu2Q3ICryMzlWT6tjwom0CgYEAt/aM1CcEV4jV4xU3X3HT
22
+ pBZ4TsJZd3amDtd8ghKU2b1m6WZYvctDByzuDISdKXvZ+UmRc48aDfMTzrUbCTqTcvEqYZh/QOeg
23
+ PXc5Ed6ycJFqV0liro/08ti/zt7hyIXpw+VCEkcWNqYzCwW3jDp935awE744mgireXHbL2j7JokC
24
+ gYAOHErRTWHyYgw9dz8qd4E21y7/EvYsQmWP/5kBZdlk4HxvkVbDI0NlAdr39NSb2w/z+kuM3Nhc
25
+ Sv5lfXnCGTfcKHIyesX+4AHQujFUMmi7H4YnJoecjXT7ARmbwn0ntae0o7cs34BPVb1C+qEBFy9U
26
+ CyXtjHEY+15HYekPX2UVVQKBgBT8Nwxsdv5VSbDh1rM4lN//ADJb0UDjdAX1ZuqfnANKq9asKitc
27
+ aIUFBxK+ff8hdbgOQF1iUaKNvBC0cCUZXYCbKi5/6uRIh+r7ErOLJ+fXbr4OTQeEvHiHaTn8Ct2J
28
+ CSWjnWngWhRZ2TDEsi947Kr40ZUu+d34ZzcvWcWKwDuhAoGBAJzCRoGOu6YGy+rBPxaIg0vB+Grx
29
+ rxs0NeNqGdrzmyAPN35OHXYclPwfp+DbtbJHgGMRc/9VFPqW9PeTKjIByeEsXyrcdreR35AR/fwR
30
+ AUcSSKTvw+PobCpXhdkiw4TgJhFNuZnoC63FOjNqA5mu1ICZYBb4ZVlgUAgSmDQxSIgK
31
+ -----END RSA PRIVATE KEY-----
32
+ EOF
33
+ sample_public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCab6TEOzKMPQTB+8BJhTkhi2co5BzTX20n1JHvcF8LIIPcGsl32hn1S6grBEdz8gZn6WJ8VDq7O0G2655DGMo8aPSHu9Dxye6poxAbfR0YCYPFRArEGD546eJW+mh9iqxjshYXpLArNb9eMHo7dpYaFs2Ek+kjU2s0zCstqNRSINV+8iQ7CBtVW4Tx2greDolsKqlpEbQUMLWer3Xb/7fqp8Wzpoby1Hok47fxrLCET4Si/txjZgrjZrgAzZRICT1rHZZQPrt4B7SCV+FsPYp8mozF3WMRaqZzvZ4JdU3gk1hIbnQ+NMajZC7rZLIgjvyW3zkVFXJVenVji9BZwhpV"
34
+
35
+ def key_to_format(key, format)
36
+ keyobj, f = Cheffish::KeyFormatter.decode(key)
37
+ Cheffish::KeyFormatter.encode(keyobj, {:format => format})
38
+ end
39
+
40
+ context 'when computing key fingperprints' do
41
+
42
+ it 'computes the PKCS#8 SHA1 private key fingerprint correctly' do
43
+ expect(key_to_format(sample_private_key, :pkcs8sha1fingerprint)).to eq(
44
+ '88:7e:3a:bd:26:9f:b5:c5:d8:ae:52:f9:df:0b:64:a4:5c:17:0a:87')
45
+ end
46
+
47
+ it 'computes the PKCS#1 MD5 public key fingerprint correctly' do
48
+ expect(key_to_format(sample_public_key, :pkcs1md5fingerprint)).to eq(
49
+ '1f:e8:da:c1:16:c3:72:7d:90:e2:b7:64:c4:b4:55:20')
50
+ end
51
+
52
+ it 'computes the RFC4716 MD5 public key fingerprint correctly' do
53
+ expect(key_to_format(sample_public_key, :rfc4716md5fingerprint)).to eq(
54
+ 'b0:13:4f:da:cf:8c:dc:a7:4a:1f:d2:3a:51:92:cf:6b')
55
+ end
56
+
57
+ it 'defaults to the PKCS#1 MD5 public key fingerprint' do
58
+ expect(key_to_format(sample_public_key, :fingerprint)).to eq(
59
+ key_to_format(sample_public_key, :pkcs1md5fingerprint))
60
+ end
61
+
62
+ end
63
+
64
+ end
@@ -20,13 +20,21 @@ module SpecSupport
20
20
  @event_sink.events
21
21
  end
22
22
 
23
- def run_recipe(&block)
24
- node = Chef::Node.new
25
- node.name 'test'
26
- node.automatic[:platform] = 'test'
27
- node.automatic[:platform_version] = 'test'
23
+ def run_context
24
+ @run_context ||= begin
25
+ node = Chef::Node.new
26
+ node.name 'test'
27
+ node.automatic[:platform] = 'test'
28
+ node.automatic[:platform_version] = 'test'
29
+ Chef::RunContext.new(node, {}, Chef::EventDispatch::Dispatcher.new(event_sink))
30
+ end
31
+ end
32
+
33
+ def event_sink
28
34
  @event_sink ||= EventSink.new
29
- run_context = Chef::RunContext.new(node, {}, Chef::EventDispatch::Dispatcher.new(@event_sink))
35
+ end
36
+
37
+ def run_recipe(&block)
30
38
  recipe = Chef::Recipe.new('test', 'test', run_context)
31
39
  recipe.instance_eval(&block)
32
40
  Chef::Runner.new(run_context).converge
@@ -77,76 +85,7 @@ RSpec.configure do |config|
77
85
 
78
86
  config.before :each do
79
87
  Chef::Config.reset
80
- Cheffish.reset
81
88
  end
82
89
  end
83
90
 
84
- # Stuff that should have been required in Chef, but wasn't (Chef will be fixed)
85
- require 'chef/platform'
86
-
87
- require 'chef/provider/service/simple'
88
- require 'chef/provider/service/init'
89
-
90
- require 'chef/provider/batch'
91
- require 'chef/provider/cron'
92
- require 'chef/provider/cron/aix'
93
- require 'chef/provider/cron/solaris'
94
- require 'chef/provider/directory'
95
- require 'chef/provider/env/windows'
96
- require 'chef/provider/erl_call'
97
- require 'chef/provider/execute'
98
- require 'chef/provider/file'
99
- require 'chef/provider/group/aix'
100
- require 'chef/provider/group/dscl'
101
- require 'chef/provider/group/gpasswd'
102
- require 'chef/provider/group/groupmod'
103
- require 'chef/provider/group/pw'
104
- require 'chef/provider/group/suse'
105
- require 'chef/provider/group/usermod'
106
- require 'chef/provider/group/windows'
107
- require 'chef/provider/http_request'
108
- require 'chef/provider/ifconfig'
109
- require 'chef/provider/ifconfig/aix'
110
- require 'chef/provider/ifconfig/debian'
111
- require 'chef/provider/ifconfig/redhat'
112
- require 'chef/provider/link'
113
- require 'chef/provider/log'
114
- require 'chef/provider/mdadm'
115
- require 'chef/provider/mount/aix'
116
- require 'chef/provider/mount/mount'
117
- require 'chef/provider/mount/windows'
118
- require 'chef/provider/package/aix'
119
- require 'chef/provider/package/apt'
120
- require 'chef/provider/package/freebsd'
121
- require 'chef/provider/package/ips'
122
- require 'chef/provider/package/macports'
123
- require 'chef/provider/package/pacman'
124
- require 'chef/provider/package/portage'
125
- require 'chef/provider/package/solaris'
126
- require 'chef/provider/package/smartos'
127
- require 'chef/provider/package/yum'
128
- require 'chef/provider/package/zypper'
129
- require 'chef/provider/powershell_script'
130
- require 'chef/provider/remote_directory'
131
- require 'chef/provider/route'
132
- require 'chef/provider/ruby_block'
133
- require 'chef/provider/script'
134
- require 'chef/provider/service/arch'
135
- require 'chef/provider/service/debian'
136
- require 'chef/provider/service/freebsd'
137
- require 'chef/provider/service/gentoo'
138
- require 'chef/provider/service/init'
139
- require 'chef/provider/service/insserv'
140
- require 'chef/provider/service/macosx'
141
- require 'chef/provider/service/redhat'
142
- require 'chef/provider/service/solaris'
143
- require 'chef/provider/service/systemd'
144
- require 'chef/provider/service/upstart'
145
- require 'chef/provider/service/windows'
146
- require 'chef/provider/template'
147
- require 'chef/provider/user/dscl'
148
- require 'chef/provider/user/pw'
149
- require 'chef/provider/user/useradd'
150
- require 'chef/provider/user/solaris'
151
- require 'chef/provider/user/windows'
152
- require 'chef/provider/whyrun_safe_ruby_block'
91
+ require 'chef/providers'
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.3'
4
+ version: '0.4'
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-04-24 00:00:00.000000000 Z
11
+ date: 2014-05-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: chef
@@ -24,6 +24,20 @@ 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'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: rake
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -83,13 +97,17 @@ files:
83
97
  - lib/chef/resource/private_key.rb
84
98
  - lib/chef/resource/public_key.rb
85
99
  - lib/cheffish/actor_provider_base.rb
100
+ - lib/cheffish/basic_chef_client.rb
86
101
  - lib/cheffish/chef_provider_base.rb
102
+ - lib/cheffish/chef_run_data.rb
103
+ - lib/cheffish/chef_run_listener.rb
87
104
  - lib/cheffish/cheffish_server_api.rb
88
- - lib/cheffish/inline_resource.rb
89
105
  - lib/cheffish/key_formatter.rb
90
106
  - lib/cheffish/recipe_dsl.rb
91
107
  - lib/cheffish/version.rb
108
+ - lib/cheffish/with_pattern.rb
92
109
  - lib/cheffish.rb
110
+ - spec/functional/fingerprint_spec.rb
93
111
  - spec/integration/chef_client_spec.rb
94
112
  - spec/integration/chef_node_spec.rb
95
113
  - spec/integration/chef_user_spec.rb
@@ -1,88 +0,0 @@
1
- module Cheffish
2
- class InlineResource
3
- def initialize(provider)
4
- @provider = provider
5
- end
6
-
7
- attr_reader :provider
8
-
9
- def run_context
10
- provider.run_context
11
- end
12
-
13
- def method_missing(method_symbol, *args, &block)
14
- # Stolen ruthlessly from Chef's chef/dsl/recipe.rb
15
-
16
- # Checks the new platform => short_name => resource mapping initially
17
- # then fall back to the older approach (Chef::Resource.const_get) for
18
- # backward compatibility
19
- resource_class = Chef::Resource.resource_for_node(method_symbol, provider.run_context.node)
20
-
21
- super unless resource_class
22
- raise ArgumentError, "You must supply a name when declaring a #{method_symbol} resource" unless args.size > 0
23
-
24
- # If we have a resource like this one, we want to steal its state
25
- args << run_context
26
- resource = resource_class.new(*args)
27
- resource.source_line = caller[0]
28
- resource.load_prior_resource
29
- resource.cookbook_name = provider.cookbook_name
30
- resource.recipe_name = @recipe_name
31
- resource.params = @params
32
- # Determine whether this resource is being created in the context of an enclosing Provider
33
- resource.enclosing_provider = provider.is_a?(Chef::Provider) ? provider : nil
34
- # Evaluate resource attribute DSL
35
- resource.instance_eval(&block) if block
36
-
37
- # Run optional resource hook
38
- resource.after_created
39
-
40
- # Do NOT put this in the resource collection.
41
- #run_context.resource_collection.insert(resource)
42
-
43
- # Instead, run the action directly.
44
- Array(resource.action).each do |action|
45
- resource.updated_by_last_action(false)
46
- run_provider_action(resource.provider_for_action(action))
47
- provider.new_resource.updated_by_last_action(true) if resource.updated_by_last_action?
48
- end
49
- resource
50
- end
51
-
52
- # Do Chef::Provider.run_action, but without events
53
- def run_provider_action(inline_provider)
54
- if !inline_provider.whyrun_supported?
55
- raise "#{inline_provider} is not why-run-safe. Only why-run-safe resources are supported in inline_resource."
56
- end
57
-
58
- # Blatantly ripped off from chef/provider run_action
59
-
60
- # TODO: it would be preferable to get the action to be executed in the
61
- # constructor...
62
-
63
- # user-defined LWRPs may include unsafe load_current_resource methods that cannot be run in whyrun mode
64
- inline_provider.load_current_resource
65
- inline_provider.define_resource_requirements
66
- inline_provider.process_resource_requirements
67
-
68
- # user-defined providers including LWRPs may
69
- # not include whyrun support - if they don't support it
70
- # we can't execute any actions while we're running in
71
- # whyrun mode. Instead we 'fake' whyrun by documenting that
72
- # we can't execute the action.
73
- # in non-whyrun mode, this will still cause the action to be
74
- # executed normally.
75
- if inline_provider.whyrun_supported? && !inline_provider.requirements.action_blocked?(@action)
76
- inline_provider.send("action_#{inline_provider.action}")
77
- elsif !inline_provider.whyrun_mode?
78
- inline_provider.send("action_#{inline_provider.action}")
79
- end
80
-
81
- if inline_provider.resource_updated?
82
- inline_provider.new_resource.updated_by_last_action(true)
83
- end
84
-
85
- inline_provider.cleanup_after_converge
86
- end
87
- end
88
- end