chef-provisioning 0.15

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 (47) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +207 -0
  3. data/LICENSE +201 -0
  4. data/README.md +260 -0
  5. data/Rakefile +6 -0
  6. data/lib/chef/provider/load_balancer.rb +77 -0
  7. data/lib/chef/provider/machine.rb +176 -0
  8. data/lib/chef/provider/machine_batch.rb +191 -0
  9. data/lib/chef/provider/machine_execute.rb +35 -0
  10. data/lib/chef/provider/machine_file.rb +54 -0
  11. data/lib/chef/provider/machine_image.rb +60 -0
  12. data/lib/chef/provisioning.rb +95 -0
  13. data/lib/chef/provisioning/action_handler.rb +68 -0
  14. data/lib/chef/provisioning/add_prefix_action_handler.rb +31 -0
  15. data/lib/chef/provisioning/chef_image_spec.rb +108 -0
  16. data/lib/chef/provisioning/chef_load_balancer_spec.rb +108 -0
  17. data/lib/chef/provisioning/chef_machine_spec.rb +84 -0
  18. data/lib/chef/provisioning/chef_provider_action_handler.rb +74 -0
  19. data/lib/chef/provisioning/chef_run_data.rb +139 -0
  20. data/lib/chef/provisioning/convergence_strategy.rb +28 -0
  21. data/lib/chef/provisioning/convergence_strategy/install_cached.rb +156 -0
  22. data/lib/chef/provisioning/convergence_strategy/install_msi.rb +58 -0
  23. data/lib/chef/provisioning/convergence_strategy/install_sh.rb +55 -0
  24. data/lib/chef/provisioning/convergence_strategy/no_converge.rb +39 -0
  25. data/lib/chef/provisioning/convergence_strategy/precreate_chef_objects.rb +183 -0
  26. data/lib/chef/provisioning/driver.rb +304 -0
  27. data/lib/chef/provisioning/image_spec.rb +72 -0
  28. data/lib/chef/provisioning/load_balancer_spec.rb +86 -0
  29. data/lib/chef/provisioning/machine.rb +112 -0
  30. data/lib/chef/provisioning/machine/basic_machine.rb +84 -0
  31. data/lib/chef/provisioning/machine/unix_machine.rb +278 -0
  32. data/lib/chef/provisioning/machine/windows_machine.rb +104 -0
  33. data/lib/chef/provisioning/machine_spec.rb +82 -0
  34. data/lib/chef/provisioning/recipe_dsl.rb +103 -0
  35. data/lib/chef/provisioning/transport.rb +95 -0
  36. data/lib/chef/provisioning/transport/ssh.rb +343 -0
  37. data/lib/chef/provisioning/transport/winrm.rb +151 -0
  38. data/lib/chef/provisioning/version.rb +5 -0
  39. data/lib/chef/resource/chef_data_bag_resource.rb +148 -0
  40. data/lib/chef/resource/load_balancer.rb +57 -0
  41. data/lib/chef/resource/machine.rb +124 -0
  42. data/lib/chef/resource/machine_batch.rb +78 -0
  43. data/lib/chef/resource/machine_execute.rb +28 -0
  44. data/lib/chef/resource/machine_file.rb +34 -0
  45. data/lib/chef/resource/machine_image.rb +35 -0
  46. data/lib/chef_metal.rb +1 -0
  47. metadata +217 -0
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require 'bundler'
2
+ require 'bundler/gem_tasks'
3
+
4
+ task :spec do
5
+ require File.expand_path('spec/run')
6
+ end
@@ -0,0 +1,77 @@
1
+ require 'chef/provider/lwrp_base'
2
+ require 'chef/provider/chef_node'
3
+ require 'openssl'
4
+ require 'chef/provisioning/chef_provider_action_handler'
5
+ require 'chef/provisioning/chef_load_balancer_spec'
6
+
7
+ class Chef
8
+ class Provider
9
+ class LoadBalancer < Chef::Provider::LWRPBase
10
+
11
+ def action_handler
12
+ @action_handler ||= Chef::Provisioning::ChefProviderActionHandler.new(self)
13
+ end
14
+
15
+ def whyrun_supported?
16
+ true
17
+ end
18
+
19
+ def new_driver
20
+ @new_driver ||= run_context.chef_provisioning.driver_for(new_resource.driver)
21
+ end
22
+
23
+ action :create do
24
+ lb_spec = Chef::Provisioning::ChefLoadBalancerSpec.get(new_resource.name, new_resource.chef_server) ||
25
+ Chef::Provisioning::ChefLoadBalancerSpec.empty(new_resource.name, new_resource.chef_server)
26
+
27
+ if lb_spec.location
28
+ # Updating
29
+ update_loadbalancer(lb_spec)
30
+ else
31
+ lb_spec.load_balancer_options = new_resource.load_balancer_options
32
+ lb_spec.machines = new_resource.machines
33
+ create_loadbalancer(lb_spec)
34
+ end
35
+ end
36
+
37
+ action :destroy do
38
+ lb_spec = Chef::Provisioning::ChefLoadBalancerSpec.get(new_resource.name, new_resource.chef_server)
39
+ new_driver.destroy_load_balancer(@action_handler, lb_spec, lb_options)
40
+ end
41
+
42
+ attr_reader :lb_spec
43
+
44
+
45
+ def update_loadbalancer(lb_spec)
46
+ machines = Hash[
47
+ *(new_resource.machines).collect {
48
+ |machine_name| [machine_name, get_machine_spec(machine_name)]
49
+ }.flatten
50
+ ]
51
+ new_driver.update_load_balancer(action_handler, lb_spec, lb_options, {
52
+ :machines => machines
53
+ }
54
+ )
55
+ lb_spec.load_balancer_options = new_resource.load_balancer_options
56
+ lb_spec.machines = new_resource.machines
57
+ lb_spec.save(action_handler)
58
+ end
59
+
60
+ def create_loadbalancer(lb_spec)
61
+ new_driver.allocate_load_balancer(action_handler, lb_spec, lb_options)
62
+ lb_spec.save(action_handler)
63
+ new_driver.ready_load_balancer(action_handler, lb_spec, lb_options)
64
+ end
65
+
66
+ private
67
+ def get_machine_spec(machine_name)
68
+ Chef::Provisioning::ChefMachineSpec.get(machine_name, new_resource.chef_server)
69
+ end
70
+
71
+ def lb_options
72
+ new_resource.load_balancer_options
73
+ end
74
+
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,176 @@
1
+ require 'chef/provider/lwrp_base'
2
+ require 'chef/provider/chef_node'
3
+ require 'openssl'
4
+ require 'chef/provisioning/chef_provider_action_handler'
5
+ require 'chef/provisioning/chef_machine_spec'
6
+
7
+ class Chef
8
+ class Provider
9
+ class Machine < Chef::Provider::LWRPBase
10
+
11
+ def action_handler
12
+ @action_handler ||= Chef::Provisioning::ChefProviderActionHandler.new(self)
13
+ end
14
+
15
+ use_inline_resources
16
+
17
+ def whyrun_supported?
18
+ true
19
+ end
20
+
21
+ action :allocate do
22
+ if current_driver && current_driver.driver_url != new_driver.driver_url
23
+ raise "Cannot move '#{machine_spec.name}' from #{current_driver.driver_url} to #{new_driver.driver_url}: machine moving is not supported. Destroy and recreate."
24
+ end
25
+ if !new_driver
26
+ raise "Driver not specified for machine #{machine_spec.name}"
27
+ end
28
+ new_driver.allocate_machine(action_handler, machine_spec, new_machine_options)
29
+ machine_spec.save(action_handler)
30
+ end
31
+
32
+ action :ready do
33
+ action_allocate
34
+ machine = current_driver.ready_machine(action_handler, machine_spec, current_machine_options)
35
+ machine_spec.save(action_handler)
36
+ machine
37
+ end
38
+
39
+ action :setup do
40
+ machine = action_ready
41
+ begin
42
+ machine.setup_convergence(action_handler)
43
+ machine_spec.save(action_handler)
44
+ upload_files(machine)
45
+ ensure
46
+ machine.disconnect
47
+ end
48
+ end
49
+
50
+ action :converge do
51
+ machine = action_ready
52
+ begin
53
+ machine.setup_convergence(action_handler)
54
+ machine_spec.save(action_handler)
55
+ upload_files(machine)
56
+ # If we were asked to converge, or anything changed, or if a converge has never succeeded, converge.
57
+ if new_resource.converge || (new_resource.converge.nil? && resource_updated?) ||
58
+ !machine_spec.node['automatic'] || machine_spec.node['automatic'].size == 0
59
+ machine.converge(action_handler)
60
+ end
61
+ ensure
62
+ machine.disconnect
63
+ end
64
+ end
65
+
66
+ action :converge_only do
67
+ machine = run_context.chef_provisioning.connect_to_machine(machine_spec, current_machine_options)
68
+ begin
69
+ machine.converge(action_handler)
70
+ ensure
71
+ machine.disconnect
72
+ end
73
+ end
74
+
75
+ action :stop do
76
+ if current_driver
77
+ current_driver.stop_machine(action_handler, machine_spec, current_machine_options)
78
+ end
79
+ end
80
+
81
+ action :destroy do
82
+ if current_driver
83
+ current_driver.destroy_machine(action_handler, machine_spec, current_machine_options)
84
+ end
85
+ end
86
+
87
+ attr_reader :machine_spec
88
+
89
+ def new_driver
90
+ run_context.chef_provisioning.driver_for(new_resource.driver)
91
+ end
92
+
93
+ def current_driver
94
+ if machine_spec.driver_url
95
+ run_context.chef_provisioning.driver_for(machine_spec.driver_url)
96
+ end
97
+ end
98
+
99
+ def from_image_spec
100
+ @from_image_spec ||= begin
101
+ if new_resource.from_image
102
+ Chef::Provisioning::ChefImageSpec.get(new_resource.from_image, new_resource.chef_server)
103
+ else
104
+ nil
105
+ end
106
+ end
107
+ end
108
+
109
+ def new_machine_options
110
+ machine_options(new_driver)
111
+ end
112
+
113
+ def current_machine_options
114
+ machine_options(current_driver)
115
+ end
116
+
117
+ def machine_options(driver)
118
+ configs = []
119
+
120
+ if from_image_spec && from_image_spec.machine_options
121
+ configs << from_image_spec.machine_options
122
+ end
123
+
124
+ configs << {
125
+ :convergence_options =>
126
+ [ :chef_server,
127
+ :allow_overwrite_keys,
128
+ :source_key, :source_key_path, :source_key_pass_phrase,
129
+ :private_key_options,
130
+ :ohai_hints,
131
+ :public_key_path, :public_key_format,
132
+ :admin, :validator
133
+ ].inject({}) do |result, key|
134
+ result[key] = new_resource.send(key)
135
+ result
136
+ end
137
+ }
138
+
139
+ configs << new_resource.machine_options if new_resource.machine_options
140
+ configs << driver.config[:machine_options] if driver.config[:machine_options]
141
+ Cheffish::MergedConfig.new(*configs)
142
+ end
143
+
144
+ def load_current_resource
145
+ node_driver = Chef::Provider::ChefNode.new(new_resource, run_context)
146
+ node_driver.load_current_resource
147
+ json = node_driver.new_json
148
+ json['normal']['chef_provisioning'] = node_driver.current_json['normal']['chef_provisioning']
149
+ @machine_spec = Chef::Provisioning::ChefMachineSpec.new(json, new_resource.chef_server)
150
+ end
151
+
152
+ def self.upload_files(action_handler, machine, files)
153
+ if files
154
+ files.each_pair do |remote_file, local|
155
+ if local.is_a?(Hash)
156
+ if local[:local_path]
157
+ machine.upload_file(action_handler, local[:local_path], remote_file)
158
+ else
159
+ machine.write_file(action_handler, remote_file, local[:content])
160
+ end
161
+ else
162
+ machine.upload_file(action_handler, local, remote_file)
163
+ end
164
+ end
165
+ end
166
+ end
167
+
168
+ private
169
+
170
+ def upload_files(machine)
171
+ Machine.upload_files(action_handler, machine, new_resource.files)
172
+ end
173
+
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,191 @@
1
+ require 'chef/chef_fs/parallelizer'
2
+ require 'chef/provider/lwrp_base'
3
+ require 'chef/provider/machine'
4
+ require 'chef/provisioning/chef_provider_action_handler'
5
+ require 'chef/provisioning/add_prefix_action_handler'
6
+ require 'chef/provisioning/machine_spec'
7
+ require 'chef/provisioning/chef_machine_spec'
8
+
9
+ class Chef
10
+ class Provider
11
+ class MachineBatch < Chef::Provider::LWRPBase
12
+
13
+ def action_handler
14
+ @action_handler ||= Chef::Provisioning::ChefProviderActionHandler.new(self)
15
+ end
16
+
17
+ use_inline_resources
18
+
19
+ def whyrun_supported?
20
+ true
21
+ end
22
+
23
+ def parallelizer
24
+ @parallelizer ||= Chef::ChefFS::Parallelizer.new(new_resource.max_simultaneous || 100)
25
+ end
26
+
27
+ action :allocate do
28
+ by_new_driver.each do |driver, specs_and_options|
29
+ driver.allocate_machines(action_handler, specs_and_options, parallelizer) do |machine_spec|
30
+ prefixed_handler = Chef::Provisioning::AddPrefixActionHandler.new(action_handler, "[#{machine_spec.name}] ")
31
+ machine_spec.save(prefixed_handler)
32
+ end
33
+ end
34
+ end
35
+
36
+ action :ready do
37
+ with_ready_machines
38
+ end
39
+
40
+ action :setup do
41
+ with_ready_machines do |m|
42
+ prefixed_handler = Chef::Provisioning::AddPrefixActionHandler.new(action_handler, "[#{m[:spec].name}] ")
43
+ m[:machine].setup_convergence(prefixed_handler)
44
+ m[:spec].save(prefixed_handler)
45
+ Chef::Provider::Machine.upload_files(prefixed_handler, m[:machine], m[:files])
46
+ end
47
+ end
48
+
49
+ action :converge do
50
+ with_ready_machines do |m|
51
+ prefixed_handler = Chef::Provisioning::AddPrefixActionHandler.new(action_handler, "[#{m[:spec].name}] ")
52
+ m[:machine].setup_convergence(prefixed_handler)
53
+ m[:spec].save(action_handler)
54
+ Chef::Provider::Machine.upload_files(prefixed_handler, m[:machine], m[:files])
55
+ # TODO only converge if machine was modified
56
+ m[:machine].converge(prefixed_handler)
57
+ m[:spec].save(prefixed_handler)
58
+ end
59
+ end
60
+
61
+ action :converge_only do
62
+ parallel_do(@machines) do |m|
63
+ prefixed_handler = Chef::Provisioning::AddPrefixActionHandler.new(action_handler, "[#{m[:spec].name}] ")
64
+ machine = run_context.chef_provisioning.connect_to_machine(m[:spec])
65
+ machine.converge(prefixed_handler)
66
+ end
67
+ end
68
+
69
+ action :destroy do
70
+ parallel_do(by_current_driver) do |driver, specs_and_options|
71
+ driver.destroy_machines(action_handler, specs_and_options, parallelizer)
72
+ end
73
+ end
74
+
75
+ action :stop do
76
+ parallel_do(by_current_driver) do |driver, specs_and_options|
77
+ driver.stop_machines(action_handler, specs_and_options, parallelizer)
78
+ end
79
+ end
80
+
81
+ def with_ready_machines
82
+ action_allocate
83
+ by_id = @machines.inject({}) { |hash,m| hash[m[:spec].id] = m; hash }
84
+ parallel_do(by_new_driver) do |driver, specs_and_options|
85
+ driver.ready_machines(action_handler, specs_and_options, parallelizer) do |machine|
86
+ machine.machine_spec.save(action_handler)
87
+
88
+ m = by_id[machine.machine_spec.id]
89
+
90
+ m[:machine] = machine
91
+ begin
92
+ yield m if block_given?
93
+ ensure
94
+ machine.disconnect
95
+ end
96
+ end
97
+ end
98
+ end
99
+
100
+ # TODO in many of these cases, the order of the results only matters because you
101
+ # want to match it up with the input. Make a parallelize method that doesn't
102
+ # care about order and spits back results as quickly as possible.
103
+ def parallel_do(enum, options = {}, &block)
104
+ parallelizer.parallelize(enum, options, &block).to_a
105
+ end
106
+
107
+ def by_new_driver
108
+ result = {}
109
+ drivers = {}
110
+ @machines.each do |m|
111
+ if m[:desired_driver]
112
+ drivers[m[:desired_driver]] ||= run_context.chef_provisioning.driver_for(m[:desired_driver])
113
+ driver = drivers[m[:desired_driver]]
114
+ # Check whether the current driver is same or different; we disallow
115
+ # moving a machine from one place to another.
116
+ if m[:spec].driver_url
117
+ drivers[m[:spec].driver_url] ||= run_context.chef_provisioning.driver_for(m[:spec].driver_url)
118
+ current_driver = drivers[m[:spec].driver_url]
119
+ if driver.driver_url != current_driver.driver_url
120
+ raise "Cannot move '#{m[:spec].name}' from #{current_driver.driver_url} to #{driver.driver_url}: machine moving is not supported. Destroy and recreate."
121
+ end
122
+ end
123
+ result[driver] ||= {}
124
+ result[driver][m[:spec]] = m[:machine_options].call(driver)
125
+ else
126
+ raise "No driver specified for #{m[:spec].name}"
127
+ end
128
+ end
129
+ result
130
+ end
131
+
132
+ def by_current_driver
133
+ result = {}
134
+ drivers = {}
135
+ @machines.each do |m|
136
+ if m[:spec].driver_url
137
+ drivers[m[:spec].driver_url] ||= run_context.chef_provisioning.driver_for(m[:spec].driver_url)
138
+ driver = drivers[m[:spec].driver_url]
139
+ result[driver] ||= {}
140
+ result[driver][m[:spec]] = m[:machine_options].call(driver)
141
+ end
142
+ end
143
+ result
144
+ end
145
+
146
+ def load_current_resource
147
+ # Load nodes in parallel
148
+ @machines = parallel_do(new_resource.machines) do |machine|
149
+ if machine.is_a?(Chef::Resource::Machine)
150
+ machine_resource = machine
151
+ provider = Chef::Provider::Machine.new(machine_resource, machine_resource.run_context)
152
+ provider.load_current_resource
153
+ {
154
+ :spec => provider.machine_spec,
155
+ :desired_driver => machine_resource.driver,
156
+ :files => machine_resource.files,
157
+ :machine_options => proc { |driver| provider.machine_options(driver) }
158
+ }
159
+ elsif machine.is_a?(Chef::Provisioning::MachineSpec)
160
+ machine_spec = machine
161
+ {
162
+ :spec => machine_spec,
163
+ :desired_driver => new_resource.driver,
164
+ :files => new_resource.files,
165
+ :machine_options => proc { |driver| machine_options(driver) }
166
+ }
167
+ else
168
+ name = machine
169
+ machine_spec = Chef::Provisioning::ChefMachineSpec.get(name, new_resource.chef_server) ||
170
+ Chef::Provisioning::ChefMachineSpec.empty(name, new_resource.chef_server)
171
+ {
172
+ :spec => machine_spec,
173
+ :desired_driver => new_resource.driver,
174
+ :files => new_resource.files,
175
+ :machine_options => proc { |driver| machine_options(driver) }
176
+ }
177
+ end
178
+ end.to_a
179
+ end
180
+
181
+ def machine_options(driver)
182
+ result = { :convergence_options => { :chef_server => new_resource.chef_server } }
183
+ result = Chef::Mixin::DeepMerge.hash_only_merge(result, run_context.chef_provisioning.config[:machine_options]) if run_context.chef_provisioning.config[:machine_options]
184
+ result = Chef::Mixin::DeepMerge.hash_only_merge(result, driver.config[:machine_options]) if driver.config && driver.config[:machine_options]
185
+ result = Chef::Mixin::DeepMerge.hash_only_merge(result, new_resource.machine_options)
186
+ result
187
+ end
188
+
189
+ end
190
+ end
191
+ end