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
@@ -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