chef-provisioning 0.15

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