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
@@ -0,0 +1,35 @@
1
+ require 'chef/provider/lwrp_base'
2
+ require 'chef/provisioning/chef_provider_action_handler'
3
+ require 'chef/provisioning/machine'
4
+
5
+ class Chef
6
+ class Provider
7
+ class MachineExecute < Chef::Provider::LWRPBase
8
+
9
+ def action_handler
10
+ @action_handler ||= Chef::Provisioning::ChefProviderActionHandler.new(self)
11
+ end
12
+
13
+ use_inline_resources
14
+
15
+ def whyrun_supported?
16
+ true
17
+ end
18
+
19
+ def machine
20
+ @machine ||= begin
21
+ if new_resource.machine.kind_of?(Chef::Provisioning::Machine)
22
+ new_resource.machine
23
+ else
24
+ run_context.chef_provisioning.connect_to_machine(new_resource.machine, new_resource.chef_server)
25
+ end
26
+ end
27
+ end
28
+
29
+ action :run do
30
+ machine.execute(action_handler, new_resource.command)
31
+ end
32
+
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,54 @@
1
+ require 'chef/provider/lwrp_base'
2
+ require 'chef/provisioning/chef_provider_action_handler'
3
+ require 'chef/provisioning/machine'
4
+
5
+ class Chef
6
+ class Provider
7
+ class MachineFile < Chef::Provider::LWRPBase
8
+
9
+ def action_handler
10
+ @action_handler ||= Chef::Provisioning::ChefProviderActionHandler.new(self)
11
+ end
12
+
13
+ use_inline_resources
14
+
15
+ def whyrun_supported?
16
+ true
17
+ end
18
+
19
+ def machine
20
+ @machine ||= begin
21
+ if new_resource.machine.kind_of?(Chef::Provisioning::Machine)
22
+ new_resource.machine
23
+ else
24
+ run_context.chef_provisioning.connect_to_machine(new_resource.machine, new_resource.chef_server)
25
+ end
26
+ end
27
+ end
28
+
29
+ action :upload do
30
+ if new_resource.content
31
+ machine.write_file(action_handler, new_resource.path, new_resource.content)
32
+ else
33
+ machine.upload_file(action_handler, new_resource.local_path, new_resource.path)
34
+ end
35
+
36
+ attributes = {}
37
+ attributes[:group] = new_resource.group if new_resource.group
38
+ attributes[:owner] = new_resource.owner if new_resource.owner
39
+ attributes[:mode] = new_resource.mode if new_resource.mode
40
+
41
+ machine.set_attributes(action_handler, new_resource.path, attributes)
42
+ end
43
+
44
+ action :download do
45
+ machine.download_file(action_handler, new_resource.path, new_resource.local_path)
46
+ end
47
+
48
+ action :delete do
49
+ machine.delete_file(action_handler, new_resource.path)
50
+ end
51
+
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,60 @@
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_image_spec'
6
+
7
+ class Chef
8
+ class Provider
9
+ class MachineImage < Chef::Provider::LWRPBase
10
+
11
+ def action_handler
12
+ @action_handler ||= Chef::Provisioning::ChefProviderActionHandler.new(self)
13
+ end
14
+
15
+ def load_current_resource
16
+ end
17
+
18
+ # Get the driver specified in the resource
19
+ def new_driver
20
+ @new_driver ||= run_context.chef_provisioning.driver_for(new_resource.driver)
21
+ end
22
+
23
+ action :create do
24
+ # Get the image mapping on the server (from name to image-id)
25
+ image_spec = Chef::Provisioning::ChefImageSpec.get(new_resource.name, new_resource.chef_server) ||
26
+ Chef::Provisioning::ChefImageSpec.empty(new_resource.name, new_resource.chef_server)
27
+ if image_spec.location
28
+ # TODO check for real existence and maybe update
29
+ else
30
+ #
31
+ # Create a new image
32
+ #
33
+ image_spec.machine_options = new_resource.machine_options
34
+ create_image(image_spec)
35
+ end
36
+ end
37
+
38
+ action :destroy do
39
+ end
40
+
41
+ def create_image(image_spec)
42
+ # 1. Create the exemplar machine
43
+ machine_provider = Chef::Provider::Machine.new(new_resource, run_context)
44
+ machine_provider.load_current_resource
45
+ machine_provider.action_converge
46
+
47
+ # 2. Create the image
48
+ new_driver.allocate_image(action_handler, image_spec, new_resource.image_options,
49
+ machine_provider.machine_spec)
50
+
51
+ # 3. Save the linkage from name -> image id
52
+ image_spec.save(action_handler)
53
+
54
+ # 4. Wait for image to be ready
55
+ new_driver.ready_image(action_handler, image_spec, new_resource.image_options)
56
+ end
57
+
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,95 @@
1
+ # Include recipe basics so require 'chef/provisioning' will load everything
2
+ require 'chef/provisioning/recipe_dsl'
3
+ require 'chef/server_api'
4
+ require 'cheffish/basic_chef_client'
5
+ require 'cheffish/merged_config'
6
+
7
+ class Chef
8
+ module Provisioning
9
+ def self.inline_resource(action_handler, &block)
10
+ events = ActionHandlerForward.new(action_handler)
11
+ Cheffish::BasicChefClient.converge_block(nil, events, &block)
12
+ end
13
+
14
+ class ActionHandlerForward < Chef::EventDispatch::Base
15
+ def initialize(action_handler)
16
+ @action_handler = action_handler
17
+ end
18
+
19
+ attr_reader :action_handler
20
+
21
+ def resource_update_applied(resource, action, update)
22
+ prefix = action_handler.should_perform_actions ? "" : "Would "
23
+ update = Array(update).flatten.map { |u| "#{prefix}#{u}"}
24
+ action_handler.performed_action(update)
25
+ end
26
+ end
27
+
28
+ # Helpers for driver inflation
29
+ @@registered_driver_classes = {}
30
+ def self.register_driver_class(name, driver)
31
+ @@registered_driver_classes[name] = driver
32
+ end
33
+
34
+ def self.default_driver(config = Cheffish.profiled_config)
35
+ driver_for_url(config[:driver], config)
36
+ end
37
+
38
+ def self.driver_for_url(driver_url, config = Cheffish.profiled_config, allow_different_config = false)
39
+ #
40
+ # Create and cache the driver
41
+ #
42
+ #
43
+ # Figure out the driver class
44
+ #
45
+ scheme = driver_url.split(':', 2)[0]
46
+ begin
47
+ require "chef/provisioning/driver_init/#{scheme}"
48
+ rescue LoadError => e
49
+ require "chef_metal/driver_init/#{scheme}"
50
+ end
51
+ driver_class = @@registered_driver_classes[scheme]
52
+
53
+ #
54
+ # Merge in any driver-specific config
55
+ #
56
+ if config[:drivers] && config[:drivers][driver_url]
57
+ config = Cheffish::MergedConfig.new(config[:drivers][driver_url], config)
58
+ end
59
+
60
+ #
61
+ # Canonicalize the URL
62
+ #
63
+ canonicalized_url, canonicalized_config = driver_class.canonicalize_url(driver_url, config)
64
+ config = canonicalized_config if canonicalized_config
65
+
66
+ #
67
+ # Merge in config from the canonicalized URL if it is different
68
+ #
69
+ if canonicalized_url != driver_url
70
+ if config[:drivers] && config[:drivers][canonicalized_url]
71
+ config = Cheffish::MergedConfig.new(config[:drivers][canonicalized_url], config)
72
+ end
73
+ end
74
+
75
+ driver_class.from_url(canonicalized_url, config)
76
+ end
77
+
78
+ def self.connect_to_machine(machine_spec, config = Cheffish.profiled_config)
79
+ chef_server = Cheffish.default_chef_server(config)
80
+ if machine_spec.is_a?(String)
81
+ machine_spec = ChefMachineSpec.get(machine_spec, chef_server)
82
+ end
83
+ driver = driver_for_url(machine_spec.driver_url, config)
84
+ if driver
85
+ machine_options = { :convergence_options => { :chef_server => chef_server } }
86
+ machine_options = Cheffish::MergedConfig.new(config[:machine_options], machine_options) if config[:machine_options]
87
+ driver.connect_to_machine(machine_spec, machine_options)
88
+ else
89
+ nil
90
+ end
91
+ end
92
+ end
93
+ end
94
+
95
+ ChefMetal = Chef::Provisioning
@@ -0,0 +1,68 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Author:: Douglas Triggs (<doug@getchef.com>)
4
+ #
5
+ # Copyright (C) 2014, Chef, Inc.
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+
19
+ # This is the generic action handler
20
+ class Chef
21
+ module Provisioning
22
+ class ActionHandler
23
+
24
+ # This should be replaced with whatever records the update; by default it
25
+ # essentially does nothing here.
26
+ def updated!
27
+ @updated = true
28
+ end
29
+
30
+ def should_perform_actions
31
+ true
32
+ end
33
+
34
+ def report_progress(description)
35
+ Array(description).each { |d| puts d }
36
+ end
37
+
38
+ def performed_action(description)
39
+ Array(description).each { |d| puts d }
40
+ end
41
+
42
+ # This should perform the actual action (e.g., converge) if there is an
43
+ # action that needs to be done.
44
+ def perform_action(description)
45
+ if should_perform_actions
46
+ result = yield
47
+ else
48
+ result = nil
49
+ end
50
+ performed_action(description)
51
+ result
52
+ end
53
+
54
+ # Open a stream which can be printed to and closed
55
+ def open_stream(name)
56
+ if block_given?
57
+ yield STDOUT
58
+ else
59
+ STDOUT
60
+ end
61
+ end
62
+
63
+ # A URL identifying the host node. nil if no such node.
64
+ def host_node
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,31 @@
1
+ require 'chef/provisioning/action_handler'
2
+
3
+ class Chef
4
+ module Provisioning
5
+ class AddPrefixActionHandler
6
+ extend Forwardable
7
+
8
+ def initialize(action_handler, prefix)
9
+ @action_handler = action_handler
10
+ @prefix = prefix
11
+ end
12
+
13
+ attr_reader :action_handler
14
+ attr_reader :prefix
15
+
16
+ def_delegators :@action_handler, :should_perform_actions, :updated!, :open_stream, :host_node
17
+
18
+ def report_progress(description)
19
+ action_handler.report_progress(Array(description).flatten.map { |d| "#{prefix}#{d}" })
20
+ end
21
+
22
+ def performed_action(description)
23
+ action_handler.performed_action(Array(description).flatten.map { |d| "#{prefix}#{d}" })
24
+ end
25
+
26
+ def perform_action(description, &block)
27
+ action_handler.perform_action(Array(description).flatten.map { |d| "#{prefix}#{d}" }, &block)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,108 @@
1
+ require 'chef/provisioning'
2
+ require 'cheffish'
3
+ require 'chef/provisioning/image_spec'
4
+
5
+ class Chef
6
+ module Provisioning
7
+ #
8
+ # Specification for a image. Sufficient information to find and contact it
9
+ # after it has been set up.
10
+ #
11
+ class ChefImageSpec < ImageSpec
12
+ def initialize(node, chef_server)
13
+ super(node)
14
+ @chef_server = chef_server
15
+ end
16
+
17
+ #
18
+ # Get a ImageSpec from the chef server. If the node does not exist on the
19
+ # server, it returns nil.
20
+ #
21
+ def self.get(name, chef_server = Cheffish.default_chef_server)
22
+ chef_api = Cheffish.chef_server_api(chef_server)
23
+ begin
24
+ data = chef_api.get("/data/images/#{name}")
25
+ data['machine_options'] = strings_to_symbols(data['machine_options'])
26
+ ChefImageSpec.new(data, chef_server)
27
+ rescue Net::HTTPServerException => e
28
+ if e.response.code == '404'
29
+ nil
30
+ else
31
+ raise
32
+ end
33
+ end
34
+ end
35
+
36
+ # Creates a new empty ImageSpec with the given name.
37
+ def self.empty(id, chef_server = Cheffish.default_chef_server)
38
+ ChefImageSpec.new({ 'id' => id }, chef_server)
39
+ end
40
+
41
+ #
42
+ # Globally unique identifier for this image. Does not depend on the image's
43
+ # location or existence.
44
+ #
45
+ def id
46
+ ChefImageSpec.id_from(chef_server, name)
47
+ end
48
+
49
+ def self.id_from(chef_server, name)
50
+ "#{chef_server[:chef_server_url]}/data/images/#{name}"
51
+ end
52
+
53
+ #
54
+ # Save this node to the server. If you have significant information that
55
+ # could be lost, you should do this as quickly as possible. Data will be
56
+ # saved automatically for you after allocate_image and ready_image.
57
+ #
58
+ def save(action_handler)
59
+ # Save the node to the server.
60
+ _self = self
61
+ _chef_server = _self.chef_server
62
+ Chef::Provisioning.inline_resource(action_handler) do
63
+ chef_data_bag_item _self.name do
64
+ data_bag 'images'
65
+ chef_server _chef_server
66
+ raw_data _self.image_data
67
+ end
68
+ end
69
+ end
70
+
71
+ def delete(action_handler)
72
+ # Save the node to the server.
73
+ _self = self
74
+ _chef_server = _self.chef_server
75
+ Chef::Provisioning.inline_resource(action_handler) do
76
+ chef_data_bag_item _self.name do
77
+ data_bag 'images'
78
+ chef_server _chef_server
79
+ action :destroy
80
+ end
81
+ end
82
+ end
83
+
84
+ protected
85
+
86
+ attr_reader :chef_server
87
+
88
+ #
89
+ # Chef API object for the given Chef server
90
+ #
91
+ def chef_api
92
+ Cheffish.server_api_for(chef_server)
93
+ end
94
+
95
+ def self.strings_to_symbols(data)
96
+ if data.is_a?(Hash)
97
+ result = {}
98
+ data.each_pair do |key, value|
99
+ result[key.to_sym] = strings_to_symbols(value)
100
+ end
101
+ result
102
+ else
103
+ data
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end