chef-metal 0.9.4 → 0.10

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: 00a282ef18ac2646f17721192ffadb941fdcb633
4
- data.tar.gz: 5661ed9e46d23ca6d8a58a7b7ea83e2004dea534
3
+ metadata.gz: 91ee1320eb59919be2805020ac09ec0b05661f7a
4
+ data.tar.gz: 60dd728cdbb222d29baf94fa0c8b142a84f986c5
5
5
  SHA512:
6
- metadata.gz: 14715c670bde674c517bf4239b558e0cd435e0a9b9bcfee580c71653fc10699b792461563c818f004519c089272365fc38bf47c0c818eb094a451177dd68991a
7
- data.tar.gz: f11ccb2cea40c9afab0ad34eddd177c297a8ba169a9f34f757048866f36af6ceffea92bc9e5852ad27e78928c536218698c9b62e40b2f45dbc27df71b4eba93c
6
+ metadata.gz: 29ee96e2d9905ede692ab859a084065027b3645a523e1a9705cde2e73c9c39b1169096b16d977da12ad6641c92d91ffaf25fc8143196c3023f2f1561b181cd7f
7
+ data.tar.gz: 5a2acc8d69b8031a83c404306251c1738900c08322bc2d5fff68d24c74d24e570cbc9e2961e91264f5175b881f848dfe14c109f741cbe573b0b0fa590b10d7db
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Chef Metal Changelog
2
2
 
3
+ ## Unreleased
4
+
5
+ - Parallelism!
6
+ - All machines by default will be created in parallel just before the first "machine" definition. They will attempt to run all the way to converge. If they fail, add "with_machine_batch 'mybatch', :setup"
7
+ - Use "with_machine_batch 'mybatch'" before any machines if you want tighter control. Actions include :delete, :acquire, :setup, and :converge.
8
+ - Parallelizableness: chef-metal now stores data in the run_context instead of globally, so that it can be run multiple times in parallel. This capability is not yet being used.
9
+
3
10
  ## 0.9.4 (4/23/2014)
4
11
 
5
12
  - Preserve provisioner_output in machine resource (don't destroy it!!)
@@ -64,15 +64,13 @@ class Chef::Provider::Machine < Chef::Provider::LWRPBase
64
64
  attr_reader :node_provider
65
65
 
66
66
  def load_current_resource
67
- @node_provider = Chef::Provider::ChefNode.new(new_resource, nil)
67
+ @node_provider = Chef::Provider::ChefNode.new(new_resource, run_context)
68
68
  @node_provider.load_current_resource
69
69
  end
70
70
 
71
- private
72
-
73
- def upload_files(machine)
74
- if new_resource.files
75
- new_resource.files.each_pair do |remote_file, local|
71
+ def self.upload_files(action_handler, machine, files)
72
+ if files
73
+ files.each_pair do |remote_file, local|
76
74
  if local.is_a?(Hash)
77
75
  if local[:local_path]
78
76
  machine.upload_file(self, local[:local_path], remote_file)
@@ -85,4 +83,10 @@ class Chef::Provider::Machine < Chef::Provider::LWRPBase
85
83
  end
86
84
  end
87
85
  end
86
+
87
+ private
88
+
89
+ def upload_files(machine)
90
+ Machine.upload_files(self, machine, new_resource.files)
91
+ end
88
92
  end
@@ -1,6 +1,8 @@
1
+ require 'chef/chef_fs/parallelizer'
1
2
  require 'chef/provider/lwrp_base'
3
+ require 'chef/provider/machine'
2
4
  require 'chef_metal/provider_action_handler'
3
- require 'chef/chef_fs/parallelizer'
5
+ require 'chef_metal/add_prefix_action_handler'
4
6
 
5
7
  class Chef::Provider::MachineBatch < Chef::Provider::LWRPBase
6
8
 
@@ -12,37 +14,102 @@ class Chef::Provider::MachineBatch < Chef::Provider::LWRPBase
12
14
  true
13
15
  end
14
16
 
15
- action :create do
16
- # Collect nodes by provisioner
17
+ def parallelizer
18
+ @parallelizer ||= Chef::ChefFS::Parallelizer.new(new_resource.max_simultaneous || 100)
19
+ end
20
+
21
+ action :boot do
22
+ with_booted_machines
23
+ end
24
+
25
+ action :setup do
26
+ with_booted_machines do |machine|
27
+ prefixed_handler = ChefMetal::AddPrefixActionHandler.new(self, "[#{machine[:resource].name}] ")
28
+ machine[:machine].setup_convergence(prefixed_handler, machine[:resource])
29
+ Chef::Provider::Machine.upload_files(prefixed_handler, machine[:machine], machine[:resource].files)
30
+ end
31
+ end
32
+
33
+ action :converge do
34
+ with_booted_machines do |machine|
35
+ prefixed_handler = ChefMetal::AddPrefixActionHandler.new(self, "[#{machine[:resource].name}] ")
36
+ machine[:machine].setup_convergence(prefixed_handler, machine[:resource])
37
+ Chef::Provider::Machine.upload_files(prefixed_handler, machine[:machine], machine[:resource].files)
38
+ machine[:machine].converge(prefixed_handler, machine[:resource].chef_server)
39
+ end
40
+ end
41
+
42
+ action :stop do
43
+ parallel_do(@by_provisioner) do |provisioner, node_urls|
44
+ provisioner.stop_machines(self, node_urls.map { |n| @by_node[n][:provider].node_provider.current_json }, parallelizer)
45
+ end
46
+ end
47
+
48
+ action :delete do
49
+ parallel_do(@by_provisioner) do |provisioner, node_urls|
50
+ provisioner.delete_machines(self, node_urls.map { |n| @by_node[n][:provider].node_provider.current_json }, parallelizer)
51
+ end
52
+ end
17
53
 
18
- by_provisioner = new_resource.machines.group_by { |machine| machine.provisioner }
19
- # Talk to each provisioner in parallel
20
- Chef::ChefFS::Parallelizer.parallelize(by_provisioner) do |provisioner, machines|
21
- nodes_json = machines.map do |machine|
22
- node_json = node_providers[machine].node_json
23
- node_json['normal']['provisioner_options'] = machine.provisioner_options
24
- node_json
54
+ def with_booted_machines
55
+ parallel_do(@by_provisioner) do |provisioner, node_urls|
56
+ machines = node_urls.map do |node_url|
57
+ # Fill in the provisioner options and output in case they got overwritten
58
+ machine = @by_node[node_url]
59
+ machine[:node] = machine[:provider].node_provider.new_json
60
+ machine[:node]['normal']['provisioner_options'] = machine[:resource].provisioner_options
61
+ machine[:node]['normal']['provisioner_output'] = machine[:provider].node_provider.current_json['normal']['provisioner_output']
62
+ machine
25
63
  end
26
- if provisioner.respond_to?(:acquire_machines)
27
- provisioner.acquire_machines(self, nodes_json)
28
- else
29
- Chef::ChefFS::Parallelizer.parallelize(nodes_json) do |node_json|
30
- provisioner.acquire_machine(self, node_json)
64
+
65
+ # TODO I don't understand why the object_id hack was necessary. Using the
66
+ # node as a key didn't work. If we could pass node_urls through acquire_machines,
67
+ # that would solve the problem in a bestest way (nodes themselves are not
68
+ # necessarily unique without knowing the chef_server with which they are
69
+ # associated)
70
+ by_node_json = machines.inject({}) { |result, machine| result[machine[:node].object_id] = machine; result }
71
+ provisioner.acquire_machines(self, by_node_json.values.map { |m| m[:node] }, parallelizer) do |node_json, machine_obj|
72
+ machine = by_node_json[node_json.object_id]
73
+
74
+ machine[:machine] = machine_obj
75
+ begin
76
+ yield machine if block_given?
77
+ ensure
78
+ machine_obj.disconnect
31
79
  end
32
80
  end
33
81
  end
34
82
  end
35
83
 
36
- attr_reader :node_providers
84
+ # TODO in many of these cases, the order of the results only matters because you
85
+ # want to match it up with the input. Make a parallelize method that doesn't
86
+ # care about order and spits back results as quickly as possible.
87
+ def parallel_do(enum, options = {}, &block)
88
+ parallelizer.parallelize(enum, options, &block).to_a
89
+ end
90
+
91
+ def node_url(machine_resource)
92
+ "#{machine_resource.chef_server[:chef_server_url]}/nodes/#{machine_resource.name}"
93
+ end
37
94
 
38
95
  def load_current_resource
39
- @node_providers = {}
40
- new_resource.machines.each do |machine|
41
- @node_providers[machine] = Chef::Provider.ChefNode.new(machine, nil)
96
+ # Figure out which machines are in the batch, remove duplicates, and retrieve
97
+ # the nodes from the Chef server if they exist.
98
+ @by_provisioner = {}
99
+ @by_node = {}
100
+ new_resource.machines.each do |machine_resource|
101
+ next if @by_node.has_key?(node_url(machine_resource))
102
+ next unless Array(machine_resource.action).include?(:create)
103
+ @by_node[node_url(machine_resource)] = {
104
+ :resource => machine_resource,
105
+ :provider => Chef::Provider::Machine.new(machine_resource, run_context)
106
+ }
107
+ @by_provisioner[machine_resource.provisioner] ||= []
108
+ @by_provisioner[machine_resource.provisioner] << node_url(machine_resource)
42
109
  end
43
110
  # Load nodes in parallel
44
- Chef::ChefFS::Parallelizer.parallelize(@node_providers.values) do |node_provider|
45
- node_provider.load_current_resource
111
+ parallel_do(@by_node.values) do |machine|
112
+ machine[:provider].load_current_resource
46
113
  end
47
114
  end
48
115
 
@@ -1,5 +1,6 @@
1
1
  require 'chef/provider/lwrp_base'
2
2
  require 'cheffish/cheffish_server_api'
3
+ require 'chef_metal/provider_action_handler'
3
4
 
4
5
  class Chef::Provider::MachineExecute < Chef::Provider::LWRPBase
5
6
 
@@ -1,5 +1,6 @@
1
1
  require 'chef/provider/lwrp_base'
2
2
  require 'cheffish/cheffish_server_api'
3
+ require 'chef_metal/provider_action_handler'
3
4
 
4
5
  class Chef::Provider::MachineFile < Chef::Provider::LWRPBase
5
6
 
@@ -7,10 +7,13 @@ class Chef::Resource::Machine < Chef::Resource::LWRPBase
7
7
 
8
8
  def initialize(*args)
9
9
  super
10
- @chef_environment = Cheffish.enclosing_environment
11
- @chef_server = Cheffish.enclosing_chef_server
12
- @provisioner = ChefMetal.enclosing_provisioner
13
- @provisioner_options = ChefMetal.enclosing_provisioner_options
10
+ @chef_environment = run_context.cheffish.current_environment
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
14
+ if run_context.chef_metal.current_machine_batch
15
+ run_context.chef_metal.current_machine_batch.machines << self
16
+ end
14
17
  end
15
18
 
16
19
  def after_created
@@ -85,6 +88,10 @@ class Chef::Resource::Machine < Chef::Resource::LWRPBase
85
88
  end
86
89
  end
87
90
 
91
+ def add_provisioner_options(options)
92
+ @provisioner_options = Chef::Mixin::DeepMerge.hash_only_merge(@provisioner_options, options)
93
+ end
94
+
88
95
  # chef client version and omnibus
89
96
  # chef-zero boot method?
90
97
  # chef-client -z boot method?
@@ -1,13 +1,20 @@
1
1
  require 'chef/resource/lwrp_base'
2
2
 
3
3
  class Chef::Resource::MachineBatch < Chef::Resource::LWRPBase
4
+ self.resource_name = 'machine_batch'
5
+
4
6
  def initialize(*args)
5
7
  super
6
8
  @machines = []
9
+ @chef_server = run_context.cheffish.current_chef_server
7
10
  end
8
11
 
9
- actions :create, :setup, :converge, :stop
10
- default_action :create
12
+ # TODO there is a useful action sequence where one does an ohai on all machines,
13
+ # waits for that to complete, save the nodes, and THEN converges.
14
+ actions :acquire, :setup, :converge, :stop, :delete
15
+ default_action :converge
11
16
 
12
17
  attribute :machines, :kind_of => [ Array ]
18
+ attribute :max_simultaneous, :kind_of => [ Integer ]
19
+ attribute :chef_server
13
20
  end
@@ -8,8 +8,8 @@ class Chef::Resource::MachineExecute < Chef::Resource::LWRPBase
8
8
 
9
9
  def initialize(*args)
10
10
  super
11
- @chef_server = Cheffish.enclosing_chef_server
12
- @provisioner = ChefMetal.enclosing_provisioner
11
+ @chef_server = run_context.cheffish.current_chef_server
12
+ @provisioner = run_context.chef_metal.current_provisioner
13
13
  end
14
14
 
15
15
  actions :run
@@ -8,8 +8,8 @@ class Chef::Resource::MachineFile < Chef::Resource::LWRPBase
8
8
 
9
9
  def initialize(*args)
10
10
  super
11
- @chef_server = Cheffish.enclosing_chef_server
12
- @provisioner = ChefMetal.enclosing_provisioner
11
+ @chef_server = run_context.cheffish.current_chef_server
12
+ @provisioner = run_context.chef_metal.current_provisioner
13
13
  end
14
14
 
15
15
  actions :upload, :download, :delete, :nothing
data/lib/chef_metal.rb CHANGED
@@ -2,59 +2,37 @@
2
2
  require 'chef_metal/recipe_dsl'
3
3
  require 'chef/resource/machine'
4
4
  require 'chef/provider/machine'
5
+ require 'chef/resource/machine_batch'
6
+ require 'chef/provider/machine_batch'
5
7
  require 'chef/resource/machine_file'
6
8
  require 'chef/provider/machine_file'
7
9
  require 'chef/resource/machine_execute'
8
10
  require 'chef/provider/machine_execute'
9
-
10
- require 'chef_metal/inline_resource'
11
+ require 'chef/server_api'
12
+ require 'cheffish/basic_chef_client'
11
13
 
12
14
  module ChefMetal
13
- def self.with_provisioner(provisioner)
14
- old_provisioner = ChefMetal.enclosing_provisioner
15
- ChefMetal.enclosing_provisioner = provisioner
16
- if block_given?
17
- begin
18
- yield
19
- ensure
20
- ChefMetal.enclosing_provisioner = old_provisioner
21
- end
22
- end
15
+ def self.inline_resource(action_handler, &block)
16
+ events = ActionHandlerForward.new(action_handler)
17
+ Cheffish::BasicChefClient.converge_block(nil, events, &block)
23
18
  end
24
19
 
25
- def self.with_provisioner_options(provisioner_options)
26
- old_provisioner_options = ChefMetal.enclosing_provisioner_options
27
- ChefMetal.enclosing_provisioner_options = provisioner_options
28
- if block_given?
29
- begin
30
- yield
31
- ensure
32
- ChefMetal.enclosing_provisioner_options = old_provisioner_options
33
- end
20
+ class ActionHandlerForward < Chef::EventDispatch::Base
21
+ def initialize(action_handler)
22
+ @action_handler = action_handler
34
23
  end
35
- end
36
24
 
37
- def self.inline_resource(action_handler, &block)
38
- InlineResource.new(action_handler).instance_eval(&block)
39
- end
25
+ attr_reader :action_handler
40
26
 
41
- @@enclosing_provisioner = nil
42
- def self.enclosing_provisioner
43
- @@enclosing_provisioner
44
- end
45
- def self.enclosing_provisioner=(provisioner)
46
- @@enclosing_provisioner = provisioner
47
- end
48
-
49
- @@enclosing_provisioner_options = nil
50
- def self.enclosing_provisioner_options
51
- @@enclosing_provisioner_options
27
+ def resource_update_applied(resource, action, update)
28
+ prefix = action_handler.should_perform_actions ? "" : "Would "
29
+ update = Array(update).map { |u| "#{prefix}#{u}"}
30
+ action_handler.performed_action(update)
31
+ end
52
32
  end
53
33
 
54
- def self.enclosing_provisioner_options=(provisioner_options)
55
- @@enclosing_provisioner_options = provisioner_options
56
- end
57
34
 
35
+ # Helpers for provisioner inflation
58
36
  @@registered_provisioner_classes = {}
59
37
  def self.add_registered_provisioner_class(name, provisioner)
60
38
  @@registered_provisioner_classes[name] = provisioner
@@ -20,24 +20,27 @@
20
20
  module ChefMetal
21
21
  class ActionHandler
22
22
 
23
- # This should be the run context
24
- def recipe_context
25
- raise ActionFailed, "ActionHandler behavior requires a recipe_context"
26
- end
27
-
28
- # This should be repaced with whatever records the update; by default it
23
+ # This should be replaced with whatever records the update; by default it
29
24
  # essentially does nothing here.
30
25
  def updated!
31
26
  @updated = true
32
27
  end
33
28
 
29
+ def should_perform_actions
30
+ true
31
+ end
32
+
33
+ def performed_action(description)
34
+ puts description
35
+ end
36
+
34
37
  # This should perform the actual action (e.g., converge) if there is an
35
38
  # action that needs to be done.
36
- #
37
- # By default, it will simply execute the block as so:
38
- def perform_action(description, &block)
39
- puts description
40
- block.call
39
+ def perform_action(description)
40
+ if should_perform_actions
41
+ yield
42
+ end
43
+ performed_action(description)
41
44
  end
42
45
 
43
46
  # This is the name that will show up in the output, so should be something
@@ -45,5 +48,14 @@ module ChefMetal
45
48
  def debug_name
46
49
  raise ActionFailed, "ActionHandler behavior requires a debug_name"
47
50
  end
51
+
52
+ # Open a stream which can be printed to and closed
53
+ def open_stream(name)
54
+ if block_given?
55
+ yield STDOUT
56
+ else
57
+ STDOUT
58
+ end
59
+ end
48
60
  end
49
61
  end
@@ -0,0 +1,27 @@
1
+ require 'chef_metal/action_handler'
2
+
3
+ module ChefMetal
4
+ class AddPrefixActionHandler
5
+ extend Forwardable
6
+
7
+ def initialize(action_handler, prefix)
8
+ @action_handler = action_handler
9
+ @prefix = prefix
10
+ end
11
+
12
+ attr_reader :action_handler
13
+ attr_reader :prefix
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
18
+
19
+ def performed_action(description)
20
+ action_handler.performed_action(Array(description).map { |d| "#{prefix}#{d}" })
21
+ end
22
+
23
+ def perform_action(description, &block)
24
+ action_handler.perform_action(Array(description).map { |d| "#{prefix}#{d}" }, &block)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,15 @@
1
+ require 'cheffish/with_pattern'
2
+ require 'chef/mixin/deep_merge'
3
+
4
+ module ChefMetal
5
+ class ChefRunData
6
+ extend Cheffish::WithPattern
7
+ with :provisioner
8
+ with :provisioner_options
9
+ with :machine_batch
10
+
11
+ def add_provisioner_options(options, &block)
12
+ with_provisioner_options(Chef::Mixin::DeepMerge.hash_only_merge(current_provisioner_options, options), &block)
13
+ end
14
+ end
15
+ end
@@ -35,8 +35,15 @@ module ChefMetal
35
35
 
36
36
  def converge(action_handler, machine, chef_server)
37
37
  super
38
-
39
- machine.execute(action_handler, "chef-client -l #{Chef::Config.log_level.to_s}", :stream => true, :timeout => @chef_client_timeout)
38
+
39
+ action_handler.open_stream(machine.node['name']) do |stdout|
40
+ action_handler.open_stream(machine.node['name']) do |stderr|
41
+ machine.execute(action_handler, "chef-client -l #{Chef::Config.log_level.to_s}",
42
+ :stream_stdout => stdout,
43
+ :stream_stderr => stderr,
44
+ :timeout => @chef_client_timeout)
45
+ end
46
+ end
40
47
  end
41
48
 
42
49
  private
@@ -75,7 +75,7 @@ module ChefMetal
75
75
  else
76
76
 
77
77
  # If the server does not already have keys, create them and upload
78
- Cheffish.inline_resource(action_handler) do
78
+ ChefMetal.inline_resource(action_handler) do
79
79
  private_key 'in_memory' do
80
80
  path :none
81
81
  if machine_resource.private_key_options
@@ -22,14 +22,20 @@ module ChefMetal
22
22
  module ProviderActionHandler
23
23
  # Implementation of ActionHandler interface
24
24
 
25
- def recipe_context
26
- self.run_context
27
- end
28
-
29
25
  def updated!
30
26
  self.new_resource.updated_by_last_action(true)
31
27
  end
32
28
 
29
+ def should_perform_actions
30
+ !Chef::Config.why_run
31
+ end
32
+
33
+ def performed_action(description)
34
+ self.converge_by description do
35
+ # We already did the action, but we trust whoever told us that they did it.
36
+ end
37
+ end
38
+
33
39
  def perform_action(description, &block)
34
40
  self.converge_by(description, &block)
35
41
  end
@@ -37,5 +43,17 @@ module ChefMetal
37
43
  def debug_name
38
44
  self.cookbook_name
39
45
  end
46
+
47
+ def open_stream(name, &block)
48
+ if self.run_context.respond_to?(:open_stream)
49
+ self.run_context.open_stream({ :name => name }, &block)
50
+ else
51
+ if block_given?
52
+ yield STDOUT
53
+ else
54
+ STDOUT
55
+ end
56
+ end
57
+ end
40
58
  end
41
59
  end
@@ -1,3 +1,5 @@
1
+ require 'chef_metal/add_prefix_action_handler'
2
+
1
3
  module ChefMetal
2
4
  class Provisioner
3
5
  # Inflate a provisioner from node information; we don't want to force the
@@ -71,6 +73,35 @@ module ChefMetal
71
73
  def resource_created(machine)
72
74
  end
73
75
 
76
+ #
77
+ # Batch methods
78
+ #
79
+
80
+ # Acquire machines in batch, in parallel if possible.
81
+ def acquire_machines(action_handler, nodes_json, parallelizer)
82
+ parallelizer.parallelize(nodes_json) do |node_json|
83
+ machine = acquire_machine(add_prefix(node_json, action_handler), node_json)
84
+ yield node_json, machine if block_given?
85
+ machine
86
+ end.to_a
87
+ end
88
+
89
+ # Stop machines in batch, in parallel if possible.
90
+ def stop_machines(action_handler, nodes_json, parallelizer)
91
+ parallelizer.parallelize(nodes_json) do |node_json|
92
+ stop_machine(add_prefix(node_json, action_handler), node_json)
93
+ yield node_json if block_given?
94
+ end.to_a
95
+ end
96
+
97
+ # Delete machines in batch, in parallel if possible.
98
+ def delete_machines(action_handler, nodes_json, parallelizer)
99
+ parallelizer.parallelize(nodes_json) do |node_json|
100
+ delete_machine(add_prefix(node_json, action_handler), node_json)
101
+ yield node_json if block_given?
102
+ end.to_a
103
+ end
104
+
74
105
  protected
75
106
 
76
107
  def save_node(provider, node, chef_server)
@@ -82,5 +113,9 @@ module ChefMetal
82
113
  end
83
114
  end
84
115
  end
116
+
117
+ def add_prefix(node_json, action_handler)
118
+ AddPrefixActionHandler.new(action_handler, "[#{node_json['name']}] ")
119
+ end
85
120
  end
86
121
  end
@@ -1,13 +1,53 @@
1
- require 'chef_metal'
1
+ require 'chef_metal/chef_run_data'
2
+ require 'chef/resource_collection'
2
3
 
3
4
  class Chef
4
- class Recipe
5
- def with_provisioner(provisioner, &block)
6
- ChefMetal.with_provisioner(provisioner, &block)
5
+ module DSL
6
+ module Recipe
7
+ def with_provisioner(provisioner, &block)
8
+ run_context.chef_metal.with_provisioner(provisioner, &block)
9
+ end
10
+
11
+ def with_provisioner_options(provisioner_options, &block)
12
+ run_context.chef_metal.with_provisioner_options(provisioner_options, &block)
13
+ end
14
+
15
+ def with_machine_batch(the_machine_batch, options = {}, &block)
16
+ if the_machine_batch.is_a?(String)
17
+ the_machine_batch = machine_batch the_machine_batch do
18
+ if options[:action]
19
+ action options[:action]
20
+ end
21
+ if options[:max_simultaneous]
22
+ max_simultaneous options[:max_simultaneous]
23
+ end
24
+ end
25
+ end
26
+ run_context.chef_metal.with_machine_batch(the_machine_batch, &block)
27
+ end
28
+
29
+ def current_provisioner_options
30
+ run_context.chef_metal.current_provisioner_options
31
+ end
32
+
33
+ def add_provisioner_options(options, &block)
34
+ run_context.chef_metal.add_provisioner_options(options, &block)
35
+ end
36
+
37
+ # When the machine resource is first declared, create a machine_batch (if there
38
+ # isn't one already)
39
+ def machine(name, &block)
40
+ if !run_context.chef_metal.current_machine_batch
41
+ run_context.chef_metal.with_machine_batch declare_resource(:machine_batch, 'default', caller[0])
42
+ end
43
+ declare_resource(:machine, name, caller[0], &block)
44
+ end
7
45
  end
46
+ end
8
47
 
9
- def with_provisioner_options(provisioner_options, &block)
10
- ChefMetal.with_provisioner_options(provisioner_options, &block)
48
+ class RunContext
49
+ def chef_metal
50
+ @chef_metal ||= ChefMetal::ChefRunData.new
11
51
  end
12
52
  end
13
- end
53
+ end
@@ -154,17 +154,15 @@ module ChefMetal
154
154
  channel = Net::SCP.new(session).download(path, local_path)
155
155
  begin
156
156
  channel.wait
157
- rescue Net::SCP::Error
157
+ rescue Net::SCP::Error => e
158
+ # TODO we need a way to distinguish between "directory of file does not exist" and "SCP did not finish successfully"
158
159
  nil
159
- rescue
160
- # This works around https://github.com/net-ssh/net-scp/pull/10 until a new net-scp is merged.
161
- begin
162
- channel.close
163
- channel.wait
164
- rescue Net::SCP::Error
165
- nil
166
- end
160
+ # ensure the channel is closed when a rescue happens above
161
+ ensure
162
+ channel.close
163
+ channel.wait
167
164
  end
165
+ nil
168
166
  end
169
167
 
170
168
  class SSHResult
@@ -1,3 +1,3 @@
1
1
  module ChefMetal
2
- VERSION = '0.9.4'
2
+ VERSION = '0.10'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chef-metal
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.4
4
+ version: '0.10'
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,20 +24,6 @@ dependencies:
24
24
  - - '>='
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
- - !ruby/object:Gem::Dependency
28
- name: cheffish
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: net-ssh
43
29
  requirement: !ruby/object:Gem::Requirement
@@ -80,34 +66,48 @@ dependencies:
80
66
  - - ~>
81
67
  - !ruby/object:Gem::Version
82
68
  version: '2.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: cheffish
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: '0.4'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: '0.4'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: chef-metal-fog
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - ~>
88
88
  - !ruby/object:Gem::Version
89
- version: '0.3'
89
+ version: '0.4'
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - ~>
95
95
  - !ruby/object:Gem::Version
96
- version: '0.3'
96
+ version: '0.4'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: chef-metal-vagrant
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - ~>
102
102
  - !ruby/object:Gem::Version
103
- version: '0.2'
103
+ version: '0.3'
104
104
  type: :runtime
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - ~>
109
109
  - !ruby/object:Gem::Version
110
- version: '0.2'
110
+ version: '0.3'
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: rspec
113
113
  requirement: !ruby/object:Gem::Requirement
@@ -159,14 +159,15 @@ files:
159
159
  - lib/chef/resource/machine_execute.rb
160
160
  - lib/chef/resource/machine_file.rb
161
161
  - lib/chef_metal/action_handler.rb
162
+ - lib/chef_metal/add_prefix_action_handler.rb
162
163
  - lib/chef_metal/aws_credentials.rb
164
+ - lib/chef_metal/chef_run_data.rb
163
165
  - lib/chef_metal/convergence_strategy/install_cached.rb
164
166
  - lib/chef_metal/convergence_strategy/install_msi.rb
165
167
  - lib/chef_metal/convergence_strategy/install_sh.rb
166
168
  - lib/chef_metal/convergence_strategy/no_converge.rb
167
169
  - lib/chef_metal/convergence_strategy/precreate_chef_objects.rb
168
170
  - lib/chef_metal/convergence_strategy.rb
169
- - lib/chef_metal/inline_resource.rb
170
171
  - lib/chef_metal/machine/basic_machine.rb
171
172
  - lib/chef_metal/machine/unix_machine.rb
172
173
  - lib/chef_metal/machine/windows_machine.rb
@@ -1,91 +0,0 @@
1
- module ChefMetal
2
- class InlineResource
3
- def initialize(action_handler)
4
- @action_handler = action_handler
5
- end
6
-
7
- attr_reader :action_handler
8
-
9
- def recipe_context
10
- action_handler.recipe_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,
20
- action_handler.recipe_context.node)
21
-
22
- super unless resource_class
23
- raise ArgumentError, "You must supply a name when declaring a #{method_symbol} resource" unless args.size > 0
24
-
25
- # If we have a resource like this one, we want to steal its state
26
- args << recipe_context
27
- resource = resource_class.new(*args)
28
- resource.source_line = caller[0]
29
- resource.load_prior_resource
30
- resource.cookbook_name = action_handler.debug_name
31
- resource.recipe_name = @recipe_name
32
- resource.params = @params
33
- # Determine whether this resource is being created in the context of an
34
- # enclosing Provider
35
- resource.enclosing_provider =
36
- action_handler.is_a?(Chef::Provider) ? action_handler : nil
37
- # Evaluate resource attribute DSL
38
- resource.instance_eval(&block) if block
39
-
40
- # Run optional resource hook
41
- resource.after_created
42
-
43
- # Do NOT put this in the resource collection.
44
- #recipe_context.resource_collection.insert(resource)
45
-
46
- # Instead, run the action directly.
47
- Array(resource.action).each do |action|
48
- resource.updated_by_last_action(false)
49
- run_provider_action(resource.provider_for_action(action))
50
- action_handler.updated! if resource.updated_by_last_action?
51
- end
52
- resource
53
- end
54
-
55
- # Do Chef::Provider.run_action, but without events
56
- def run_provider_action(inline_provider)
57
- if !inline_provider.whyrun_supported?
58
- raise "#{inline_provider} is not why-run-safe. Only why-run-safe resources are supported in inline_resource."
59
- end
60
-
61
- # Blatantly ripped off from chef/provider run_action
62
-
63
- # TODO: it would be preferable to get the action to be executed in the
64
- # constructor...
65
-
66
- # user-defined LWRPs may include unsafe load_current_resource methods that cannot be run in whyrun mode
67
- inline_provider.load_current_resource
68
- inline_provider.define_resource_requirements
69
- inline_provider.process_resource_requirements
70
-
71
- # user-defined providers including LWRPs may
72
- # not include whyrun support - if they don't support it
73
- # we can't execute any actions while we're running in
74
- # whyrun mode. Instead we 'fake' whyrun by documenting that
75
- # we can't execute the action.
76
- # in non-whyrun mode, this will still cause the action to be
77
- # executed normally.
78
- if inline_provider.whyrun_supported? && !inline_provider.requirements.action_blocked?(@action)
79
- inline_provider.send("action_#{inline_provider.action}")
80
- elsif !inline_provider.whyrun_mode?
81
- inline_provider.send("action_#{inline_provider.action}")
82
- end
83
-
84
- if inline_provider.resource_updated?
85
- inline_provider.new_resource.updated_by_last_action(true)
86
- end
87
-
88
- inline_provider.cleanup_after_converge
89
- end
90
- end
91
- end