chef-metal 0.10.2 → 0.11.beta

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