chef-metal 0.10.2 → 0.11.beta

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/CHANGELOG.md +9 -5
  3. data/README.md +3 -3
  4. data/bin/metal +5 -9
  5. data/lib/chef/provider/machine.rb +81 -32
  6. data/lib/chef/provider/machine_batch.rb +67 -58
  7. data/lib/chef/provider/machine_execute.rb +7 -7
  8. data/lib/chef/provider/machine_file.rb +11 -11
  9. data/lib/chef/resource/machine.rb +11 -15
  10. data/lib/chef/resource/machine_batch.rb +1 -1
  11. data/lib/chef/resource/machine_execute.rb +3 -4
  12. data/lib/chef/resource/machine_file.rb +3 -4
  13. data/lib/chef_metal.rb +26 -28
  14. data/lib/chef_metal/action_handler.rb +9 -7
  15. data/lib/chef_metal/add_prefix_action_handler.rb +7 -5
  16. data/lib/chef_metal/chef_machine_spec.rb +64 -0
  17. data/lib/chef_metal/{provider_action_handler.rb → chef_provider_action_handler.rb} +27 -14
  18. data/lib/chef_metal/chef_run_data.rb +68 -7
  19. data/lib/chef_metal/convergence_strategy.rb +14 -3
  20. data/lib/chef_metal/convergence_strategy/install_cached.rb +24 -10
  21. data/lib/chef_metal/convergence_strategy/install_msi.rb +17 -10
  22. data/lib/chef_metal/convergence_strategy/install_sh.rb +20 -10
  23. data/lib/chef_metal/convergence_strategy/no_converge.rb +20 -13
  24. data/lib/chef_metal/convergence_strategy/precreate_chef_objects.rb +51 -47
  25. data/lib/chef_metal/{provider.rb → driver.rb} +103 -79
  26. data/lib/chef_metal/machine.rb +13 -5
  27. data/lib/chef_metal/machine/basic_machine.rb +11 -11
  28. data/lib/chef_metal/machine/unix_machine.rb +6 -6
  29. data/lib/chef_metal/machine/windows_machine.rb +3 -3
  30. data/lib/chef_metal/machine_spec.rb +22 -25
  31. data/lib/chef_metal/recipe_dsl.rb +34 -9
  32. data/lib/chef_metal/transport.rb +7 -2
  33. data/lib/chef_metal/transport/ssh.rb +42 -9
  34. data/lib/chef_metal/transport/winrm.rb +8 -5
  35. data/lib/chef_metal/version.rb +1 -1
  36. data/spec/integration/machine.rb +29 -0
  37. metadata +21 -9
  38. data/lib/chef_metal/aws_credentials.rb +0 -58
  39. data/lib/chef_metal/openstack_credentials.rb +0 -44
  40. data/lib/chef_metal/provisioner.rb +0 -121
@@ -1,10 +1,12 @@
1
1
  require 'chef/provider/lwrp_base'
2
- require 'cheffish/cheffish_server_api'
3
- require 'chef_metal/provider_action_handler'
2
+ require 'chef_metal/chef_provider_action_handler'
3
+ require 'chef_metal/machine'
4
4
 
5
5
  class Chef::Provider::MachineFile < Chef::Provider::LWRPBase
6
6
 
7
- include ChefMetal::ProviderActionHandler
7
+ def action_handler
8
+ @action_handler ||= ChefMetal::ChefProviderActionHandler.new(self)
9
+ end
8
10
 
9
11
  use_inline_resources
10
12
 
@@ -17,18 +19,16 @@ class Chef::Provider::MachineFile < Chef::Provider::LWRPBase
17
19
  if new_resource.machine.kind_of?(ChefMetal::Machine)
18
20
  new_resource.machine
19
21
  else
20
- # TODO this is inefficient, can we cache or something?
21
- node = Cheffish::CheffishServerAPI.new(new_resource.chef_server).get("/nodes/#{new_resource.machine}")
22
- new_resource.provisioner.connect_to_machine(node)
22
+ run_context.chef_metal.connect_to_machine(new_resource.machine, new_resource.chef_server)
23
23
  end
24
24
  end
25
25
  end
26
26
 
27
27
  action :upload do
28
28
  if new_resource.content
29
- machine.write_file(self, new_resource.path, new_resource.content)
29
+ machine.write_file(action_handler, new_resource.path, new_resource.content)
30
30
  else
31
- machine.upload_file(self, new_resource.local_path, new_resource.path)
31
+ machine.upload_file(action_handler, new_resource.local_path, new_resource.path)
32
32
  end
33
33
 
34
34
  attributes = {}
@@ -36,14 +36,14 @@ class Chef::Provider::MachineFile < Chef::Provider::LWRPBase
36
36
  attributes[:owner] = new_resource.owner if new_resource.owner
37
37
  attributes[:mode] = new_resource.mode if new_resource.mode
38
38
 
39
- machine.set_attributes(self, new_resource.path, attributes)
39
+ machine.set_attributes(action_handler, new_resource.path, attributes)
40
40
  end
41
41
 
42
42
  action :download do
43
- machine.download_file(self, new_resource.path, new_resource.local_path)
43
+ machine.download_file(action_handler, new_resource.path, new_resource.local_path)
44
44
  end
45
45
 
46
46
  action :delete do
47
- machine.delete_file(self, new_resource.path)
47
+ machine.delete_file(action_handler, new_resource.path)
48
48
  end
49
49
  end
@@ -9,31 +9,27 @@ class Chef::Resource::Machine < Chef::Resource::LWRPBase
9
9
  super
10
10
  @chef_environment = run_context.cheffish.current_environment
11
11
  @chef_server = run_context.cheffish.current_chef_server
12
- @provisioner = run_context.chef_metal.current_provisioner
13
- @provisioner_options = run_context.chef_metal.current_provisioner_options
12
+ @driver = run_context.chef_metal.current_driver
13
+ @machine_options = run_context.chef_metal.current_machine_options
14
14
  if run_context.chef_metal.current_machine_batch
15
15
  run_context.chef_metal.current_machine_batch.machines << self
16
16
  end
17
17
  end
18
18
 
19
- def after_created
20
- # Notify the provisioner of this machine's creation
21
- @provisioner.resource_created(self)
22
- end
23
-
24
- actions :create, :delete, :stop, :converge, :nothing
25
- default_action :create
19
+ actions :allocate, :ready, :setup, :converge, :converge_only, :destroy, :stop
20
+ default_action :converge
26
21
 
27
- # Provisioner attributes
28
- attribute :provisioner
29
- attribute :provisioner_options
22
+ # Driver attributes
23
+ attribute :driver
24
+ attribute :machine_options
30
25
 
31
26
  # Node attributes
32
27
  Cheffish.node_attributes(self)
33
28
 
34
29
  # Client keys
35
30
  # Options to generate private key (size, type, etc.) when the server doesn't have it
36
- attribute :private_key_options, :kind_of => String
31
+ attribute :private_key_options, :kind_of => Hash
32
+ attribute :allow_overwrite_keys, :kind_of => [TrueClass, FalseClass]
37
33
 
38
34
  # Optionally pull the public key out to a file
39
35
  attribute :public_key_path, :kind_of => String
@@ -88,8 +84,8 @@ class Chef::Resource::Machine < Chef::Resource::LWRPBase
88
84
  end
89
85
  end
90
86
 
91
- def add_provisioner_options(options)
92
- @provisioner_options = Chef::Mixin::DeepMerge.hash_only_merge(@provisioner_options, options)
87
+ def add_machine_options(options)
88
+ @machine_options = Chef::Mixin::DeepMerge.hash_only_merge(@machine_options, options)
93
89
  end
94
90
 
95
91
  # chef client version and omnibus
@@ -11,7 +11,7 @@ class Chef::Resource::MachineBatch < Chef::Resource::LWRPBase
11
11
 
12
12
  # TODO there is a useful action sequence where one does an ohai on all machines,
13
13
  # waits for that to complete, save the nodes, and THEN converges.
14
- actions :acquire, :setup, :converge, :stop, :delete
14
+ actions :acquire, :setup, :converge, :stop, :destroy
15
15
  default_action :converge
16
16
 
17
17
  attribute :machines, :kind_of => [ Array ]
@@ -1,7 +1,7 @@
1
1
  require 'chef/resource/lwrp_base'
2
2
  require 'chef_metal'
3
3
  require 'chef_metal/machine'
4
- require 'chef_metal/provisioner'
4
+ require 'chef_metal/driver'
5
5
 
6
6
  class Chef::Resource::MachineExecute < Chef::Resource::LWRPBase
7
7
  self.resource_name = 'machine_execute'
@@ -9,15 +9,14 @@ class Chef::Resource::MachineExecute < Chef::Resource::LWRPBase
9
9
  def initialize(*args)
10
10
  super
11
11
  @chef_server = run_context.cheffish.current_chef_server
12
- @provisioner = run_context.chef_metal.current_provisioner
13
12
  end
14
13
 
15
14
  actions :run
16
15
  default_action :run
17
16
 
18
17
  attribute :command, :kind_of => String, :name_attribute => true
19
- attribute :machine, :kind_of => [String, ChefMetal::Machine]
18
+ attribute :machine, :kind_of => String
20
19
 
21
20
  attribute :chef_server, :kind_of => Hash
22
- attribute :provisioner, :kind_of => ChefMetal::Provisioner
21
+ attribute :driver, :kind_of => ChefMetal::Driver
23
22
  end
@@ -1,7 +1,7 @@
1
1
  require 'chef/resource/lwrp_base'
2
2
  require 'chef_metal'
3
3
  require 'chef_metal/machine'
4
- require 'chef_metal/provisioner'
4
+ require 'chef_metal/driver'
5
5
 
6
6
  class Chef::Resource::MachineFile < Chef::Resource::LWRPBase
7
7
  self.resource_name = 'machine_file'
@@ -9,14 +9,13 @@ class Chef::Resource::MachineFile < Chef::Resource::LWRPBase
9
9
  def initialize(*args)
10
10
  super
11
11
  @chef_server = run_context.cheffish.current_chef_server
12
- @provisioner = run_context.chef_metal.current_provisioner
13
12
  end
14
13
 
15
14
  actions :upload, :download, :delete, :nothing
16
15
  default_action :upload
17
16
 
18
17
  attribute :path, :kind_of => String, :name_attribute => true
19
- attribute :machine, :kind_of => [String, ChefMetal::Machine]
18
+ attribute :machine, :kind_of => String
20
19
  attribute :local_path, :kind_of => String
21
20
  attribute :content
22
21
 
@@ -25,5 +24,5 @@ class Chef::Resource::MachineFile < Chef::Resource::LWRPBase
25
24
  attribute :mode, :kind_of => String
26
25
 
27
26
  attribute :chef_server, :kind_of => Hash
28
- attribute :provisioner, :kind_of => ChefMetal::Provisioner
27
+ attribute :driver, :kind_of => ChefMetal::Driver
29
28
  end
data/lib/chef_metal.rb CHANGED
@@ -1,15 +1,8 @@
1
1
  # Include recipe basics so require 'chef_metal' will load everything
2
2
  require 'chef_metal/recipe_dsl'
3
- require 'chef/resource/machine'
4
- require 'chef/provider/machine'
5
- require 'chef/resource/machine_batch'
6
- require 'chef/provider/machine_batch'
7
- require 'chef/resource/machine_file'
8
- require 'chef/provider/machine_file'
9
- require 'chef/resource/machine_execute'
10
- require 'chef/provider/machine_execute'
11
3
  require 'chef/server_api'
12
4
  require 'cheffish/basic_chef_client'
5
+ require 'cheffish/merged_config'
13
6
 
14
7
  module ChefMetal
15
8
  def self.inline_resource(action_handler, &block)
@@ -26,35 +19,40 @@ module ChefMetal
26
19
 
27
20
  def resource_update_applied(resource, action, update)
28
21
  prefix = action_handler.should_perform_actions ? "" : "Would "
29
- update = Array(update).map { |u| "#{prefix}#{u}"}
22
+ update = Array(update).flatten.map { |u| "#{prefix}#{u}"}
30
23
  action_handler.performed_action(update)
31
24
  end
32
25
  end
33
26
 
27
+ # Helpers for driver inflation
28
+ @@registered_driver_classes = {}
29
+ def self.register_driver_class(name, driver)
30
+ @@registered_driver_classes[name] = driver
31
+ end
34
32
 
35
- # Helpers for provisioner inflation
36
- @@registered_provisioner_classes = {}
37
- def self.add_registered_provisioner_class(name, provisioner)
38
- @@registered_provisioner_classes[name] = provisioner
33
+ def self.config_for_url(driver_url, config = Chef::Config)
34
+ if config && config[:drivers] && config[:drivers][driver_url]
35
+ config = Cheffish::MergedConfig.new(config[:drivers][driver_url], config)
36
+ end
37
+ config || {}
39
38
  end
40
39
 
41
- def self.provisioner_for_node(node)
42
- provisioner_url = node['normal']['provisioner_output']['provisioner_url']
43
- cluster_type = provisioner_url.split(':', 2)[0]
44
- require "chef_metal/provisioner_init/#{cluster_type}_init"
45
- provisioner_class = @@registered_provisioner_classes[cluster_type]
46
- provisioner_class.inflate(node)
40
+ def self.driver_for_url(driver_url, config = Chef::Config)
41
+ cluster_type = driver_url.split(':', 2)[0]
42
+ require "chef_metal/driver_init/#{cluster_type}"
43
+ driver_class = @@registered_driver_classes[cluster_type]
44
+ config = config_for_url(driver_url, config)
45
+ driver_class.from_url(driver_url, config || {})
47
46
  end
48
47
 
49
- def self.connect_to_machine(name)
50
- rest = Chef::ServerAPI.new()
51
- node = rest.get("/nodes/#{name}")
52
- provisioner_output = node['normal']['provisioner_output']
53
- if !provisioner_output
54
- raise "Node #{name} was not provisioned with Metal."
48
+ def self.connect_to_machine(machine_spec, config = Chef::Config)
49
+ driver = driver_for_url(machine_spec.driver_url, config)
50
+ if driver
51
+ machine_options = { :convergence_options => { :chef_server => Cheffish.default_chef_server(config) } }
52
+ machine_options = Cheffish::MergedConfig.new(config[:machine_options], machine_options) if config[:machine_options]
53
+ driver.connect_to_machine(machine_spec, machine_options)
54
+ else
55
+ nil
55
56
  end
56
- provisioner = provisioner_for_node(node)
57
- machine = provisioner.connect_to_machine(node)
58
- [ machine, provisioner ]
59
57
  end
60
58
  end
@@ -30,8 +30,12 @@ module ChefMetal
30
30
  true
31
31
  end
32
32
 
33
+ def report_progress(description)
34
+ Array(description).each { |d| puts d }
35
+ end
36
+
33
37
  def performed_action(description)
34
- puts description
38
+ Array(description).each { |d| puts d }
35
39
  end
36
40
 
37
41
  # This should perform the actual action (e.g., converge) if there is an
@@ -43,12 +47,6 @@ module ChefMetal
43
47
  performed_action(description)
44
48
  end
45
49
 
46
- # This is the name that will show up in the output, so should be something
47
- # like a cookbook or driver name
48
- def debug_name
49
- raise ActionFailed, "ActionHandler behavior requires a debug_name"
50
- end
51
-
52
50
  # Open a stream which can be printed to and closed
53
51
  def open_stream(name)
54
52
  if block_given?
@@ -57,5 +55,9 @@ module ChefMetal
57
55
  STDOUT
58
56
  end
59
57
  end
58
+
59
+ # A URL identifying the host node. nil if no such node.
60
+ def host_node
61
+ end
60
62
  end
61
63
  end
@@ -12,16 +12,18 @@ module ChefMetal
12
12
  attr_reader :action_handler
13
13
  attr_reader :prefix
14
14
 
15
- def_delegators :@action_handler, :should_perform_actions, :updated!, :debug_name, :open_stream
16
- # TODO remove this as soon as HUMANLY POSSIBLE (looking at you, chef-metal-fog)
17
- def_delegators :@action_handler, :new_resource
15
+ def_delegators :@action_handler, :should_perform_actions, :updated!, :open_stream, :host_node
16
+
17
+ def report_progress(description)
18
+ action_handler.report_progress(Array(description).flatten.map { |d| "#{prefix}#{d}" })
19
+ end
18
20
 
19
21
  def performed_action(description)
20
- action_handler.performed_action(Array(description).map { |d| "#{prefix}#{d}" })
22
+ action_handler.performed_action(Array(description).flatten.map { |d| "#{prefix}#{d}" })
21
23
  end
22
24
 
23
25
  def perform_action(description, &block)
24
- action_handler.perform_action(Array(description).map { |d| "#{prefix}#{d}" }, &block)
26
+ action_handler.perform_action(Array(description).flatten.map { |d| "#{prefix}#{d}" }, &block)
25
27
  end
26
28
  end
27
29
  end
@@ -0,0 +1,64 @@
1
+ require 'chef_metal'
2
+ require 'cheffish'
3
+ require 'chef_metal/machine_spec'
4
+
5
+ module ChefMetal
6
+ #
7
+ # Specification for a machine. Sufficient information to find and contact it
8
+ # after it has been set up.
9
+ #
10
+ class ChefMachineSpec < MachineSpec
11
+ def initialize(node, chef_server)
12
+ super(node)
13
+ @chef_server = chef_server
14
+ end
15
+
16
+ #
17
+ # Get a MachineSpec from the chef server.
18
+ #
19
+ def self.get(name, chef_server = Cheffish.default_chef_server)
20
+ chef_api = Cheffish.chef_server_api(chef_server)
21
+ ChefMachineSpec.new(chef_api.get("/nodes/#{name}"), chef_server)
22
+ end
23
+
24
+ #
25
+ # Globally unique identifier for this machine. Does not depend on the machine's
26
+ # location or existence.
27
+ #
28
+ def id
29
+ ChefMachineSpec.id_from(chef_server, name)
30
+ end
31
+
32
+ def self.id_from(chef_server, name)
33
+ "#{chef_server[:chef_server_url]}/nodes/#{name}"
34
+ end
35
+
36
+ #
37
+ # Save this node to the server. If you have significant information that
38
+ # could be lost, you should do this as quickly as possible. Data will be
39
+ # saved automatically for you after allocate_machine and ready_machine.
40
+ #
41
+ def save(action_handler)
42
+ # Save the node to the server.
43
+ _self = self
44
+ _chef_server = _self.chef_server
45
+ ChefMetal.inline_resource(action_handler) do
46
+ chef_node _self.name do
47
+ chef_server _chef_server
48
+ raw_json _self.node
49
+ end
50
+ end
51
+ end
52
+
53
+ protected
54
+
55
+ attr_reader :chef_server
56
+
57
+ #
58
+ # Chef API object for the given Chef server
59
+ #
60
+ def chef_api
61
+ Cheffish.server_api_for(chef_server)
62
+ end
63
+ end
64
+ end
@@ -16,37 +16,46 @@
16
16
  # See the License for the specific language governing permissions and
17
17
  # limitations under the License.
18
18
 
19
- # This is included in the metal provisioners to proxy from generic requests needed
20
- # to specific provider actions
19
+ require 'chef_metal/action_handler'
20
+
21
+ # This is included in the metal drivers to proxy from generic requests needed
22
+ # to specific driver actions
21
23
  module ChefMetal
22
- module ProviderActionHandler
23
- # Implementation of ActionHandler interface
24
+ class ChefProviderActionHandler < ActionHandler
25
+ def initialize(provider)
26
+ @provider = provider
27
+ end
28
+
29
+ attr_reader :provider
24
30
 
25
31
  def updated!
26
- self.new_resource.updated_by_last_action(true)
32
+ provider.new_resource.updated_by_last_action(true)
27
33
  end
28
34
 
29
35
  def should_perform_actions
30
- !Chef::Config.why_run
36
+ !provider.run_context.config.why_run
31
37
  end
32
38
 
33
- def performed_action(description)
34
- self.converge_by description do
39
+ def report_progress(description)
40
+ # TODO this seems wrong but Chef doesn't have another thing
41
+ provider.converge_by description do
35
42
  # We already did the action, but we trust whoever told us that they did it.
36
43
  end
37
44
  end
38
45
 
39
- def perform_action(description, &block)
40
- self.converge_by(description, &block)
46
+ def performed_action(description)
47
+ provider.converge_by description do
48
+ # We already did the action, but we trust whoever told us that they did it.
49
+ end
41
50
  end
42
51
 
43
- def debug_name
44
- self.cookbook_name
52
+ def perform_action(description, &block)
53
+ provider.converge_by(description, &block)
45
54
  end
46
55
 
47
56
  def open_stream(name, &block)
48
- if self.run_context.respond_to?(:open_stream)
49
- self.run_context.open_stream({ :name => name }, &block)
57
+ if provider.run_context.respond_to?(:open_stream)
58
+ provider.run_context.open_stream({ :name => name }, &block)
50
59
  else
51
60
  if block_given?
52
61
  yield STDOUT
@@ -55,5 +64,9 @@ module ChefMetal
55
64
  end
56
65
  end
57
66
  end
67
+
68
+ def host_node
69
+ "#{provider.run_context.config[:chef_server_url]}/nodes/#{provider.run_context.node['name']}"
70
+ end
58
71
  end
59
72
  end