chef-metal 0.9.4 → 0.10

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 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