clc-fork-chef-metal 0.11.beta.5

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 (38) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +106 -0
  3. data/LICENSE +201 -0
  4. data/README.md +201 -0
  5. data/Rakefile +6 -0
  6. data/bin/metal +276 -0
  7. data/lib/chef/provider/machine.rb +147 -0
  8. data/lib/chef/provider/machine_batch.rb +130 -0
  9. data/lib/chef/provider/machine_execute.rb +30 -0
  10. data/lib/chef/provider/machine_file.rb +49 -0
  11. data/lib/chef/resource/machine.rb +95 -0
  12. data/lib/chef/resource/machine_batch.rb +20 -0
  13. data/lib/chef/resource/machine_execute.rb +22 -0
  14. data/lib/chef/resource/machine_file.rb +28 -0
  15. data/lib/chef_metal.rb +62 -0
  16. data/lib/chef_metal/action_handler.rb +63 -0
  17. data/lib/chef_metal/add_prefix_action_handler.rb +29 -0
  18. data/lib/chef_metal/chef_machine_spec.rb +64 -0
  19. data/lib/chef_metal/chef_provider_action_handler.rb +72 -0
  20. data/lib/chef_metal/chef_run_data.rb +80 -0
  21. data/lib/chef_metal/convergence_strategy.rb +26 -0
  22. data/lib/chef_metal/convergence_strategy/install_cached.rb +157 -0
  23. data/lib/chef_metal/convergence_strategy/install_msi.rb +56 -0
  24. data/lib/chef_metal/convergence_strategy/install_sh.rb +51 -0
  25. data/lib/chef_metal/convergence_strategy/no_converge.rb +38 -0
  26. data/lib/chef_metal/convergence_strategy/precreate_chef_objects.rb +180 -0
  27. data/lib/chef_metal/driver.rb +267 -0
  28. data/lib/chef_metal/machine.rb +110 -0
  29. data/lib/chef_metal/machine/basic_machine.rb +82 -0
  30. data/lib/chef_metal/machine/unix_machine.rb +276 -0
  31. data/lib/chef_metal/machine/windows_machine.rb +102 -0
  32. data/lib/chef_metal/machine_spec.rb +78 -0
  33. data/lib/chef_metal/recipe_dsl.rb +84 -0
  34. data/lib/chef_metal/transport.rb +87 -0
  35. data/lib/chef_metal/transport/ssh.rb +235 -0
  36. data/lib/chef_metal/transport/winrm.rb +109 -0
  37. data/lib/chef_metal/version.rb +3 -0
  38. metadata +223 -0
@@ -0,0 +1,30 @@
1
+ require 'chef/provider/lwrp_base'
2
+ require 'chef_metal/chef_provider_action_handler'
3
+ require 'chef_metal/machine'
4
+
5
+ class Chef::Provider::MachineExecute < Chef::Provider::LWRPBase
6
+
7
+ def action_handler
8
+ @action_handler ||= ChefMetal::ChefProviderActionHandler.new(self)
9
+ end
10
+
11
+ use_inline_resources
12
+
13
+ def whyrun_supported?
14
+ true
15
+ end
16
+
17
+ def machine
18
+ @machine ||= begin
19
+ if new_resource.machine.kind_of?(ChefMetal::Machine)
20
+ new_resource.machine
21
+ else
22
+ run_context.chef_metal.connect_to_machine(new_resource.machine, new_resource.chef_server)
23
+ end
24
+ end
25
+ end
26
+
27
+ action :run do
28
+ machine.execute(action_handler, new_resource.command)
29
+ end
30
+ end
@@ -0,0 +1,49 @@
1
+ require 'chef/provider/lwrp_base'
2
+ require 'chef_metal/chef_provider_action_handler'
3
+ require 'chef_metal/machine'
4
+
5
+ class Chef::Provider::MachineFile < Chef::Provider::LWRPBase
6
+
7
+ def action_handler
8
+ @action_handler ||= ChefMetal::ChefProviderActionHandler.new(self)
9
+ end
10
+
11
+ use_inline_resources
12
+
13
+ def whyrun_supported?
14
+ true
15
+ end
16
+
17
+ def machine
18
+ @machine ||= begin
19
+ if new_resource.machine.kind_of?(ChefMetal::Machine)
20
+ new_resource.machine
21
+ else
22
+ run_context.chef_metal.connect_to_machine(new_resource.machine, new_resource.chef_server)
23
+ end
24
+ end
25
+ end
26
+
27
+ action :upload do
28
+ if new_resource.content
29
+ machine.write_file(action_handler, new_resource.path, new_resource.content)
30
+ else
31
+ machine.upload_file(action_handler, new_resource.local_path, new_resource.path)
32
+ end
33
+
34
+ attributes = {}
35
+ attributes[:group] = new_resource.group if new_resource.group
36
+ attributes[:owner] = new_resource.owner if new_resource.owner
37
+ attributes[:mode] = new_resource.mode if new_resource.mode
38
+
39
+ machine.set_attributes(action_handler, new_resource.path, attributes)
40
+ end
41
+
42
+ action :download do
43
+ machine.download_file(action_handler, new_resource.path, new_resource.local_path)
44
+ end
45
+
46
+ action :delete do
47
+ machine.delete_file(action_handler, new_resource.path)
48
+ end
49
+ end
@@ -0,0 +1,95 @@
1
+ require 'chef/resource/lwrp_base'
2
+ require 'cheffish'
3
+ require 'chef_metal'
4
+
5
+ class Chef::Resource::Machine < Chef::Resource::LWRPBase
6
+ self.resource_name = 'machine'
7
+
8
+ def initialize(*args)
9
+ super
10
+ @chef_environment = run_context.cheffish.current_environment
11
+ @chef_server = run_context.cheffish.current_chef_server
12
+ @driver = run_context.chef_metal.current_driver
13
+ @machine_options = run_context.chef_metal.current_machine_options
14
+ if run_context.chef_metal.current_machine_batch
15
+ run_context.chef_metal.current_machine_batch.machines << self
16
+ end
17
+ end
18
+
19
+ actions :allocate, :ready, :setup, :converge, :converge_only, :destroy, :stop
20
+ default_action :converge
21
+
22
+ # Driver attributes
23
+ attribute :driver
24
+ attribute :machine_options
25
+
26
+ # Node attributes
27
+ Cheffish.node_attributes(self)
28
+
29
+ # Client keys
30
+ # Options to generate private key (size, type, etc.) when the server doesn't have it
31
+ attribute :private_key_options, :kind_of => Hash
32
+ attribute :allow_overwrite_keys, :kind_of => [TrueClass, FalseClass]
33
+
34
+ # Optionally pull the public key out to a file
35
+ attribute :public_key_path, :kind_of => String
36
+ attribute :public_key_format, :kind_of => String
37
+
38
+ # If you really want to force the private key to be a certain key, pass these
39
+ attribute :source_key
40
+ attribute :source_key_path, :kind_of => String
41
+ attribute :source_key_pass_phrase
42
+
43
+ # Client attributes
44
+ attribute :admin, :kind_of => [TrueClass, FalseClass]
45
+ attribute :validator, :kind_of => [TrueClass, FalseClass]
46
+
47
+ # Client Ohai hints, allows machine to enable hints
48
+ # e.g. ohai_hint 'ec2' => { 'a' => 'b' } creates file ec2.json with json contents { 'a': 'b' }
49
+ attribute :ohai_hints, :kind_of => Hash
50
+
51
+ # Allows you to turn convergence off in the :create action by writing "converge false"
52
+ # or force it with "true"
53
+ attribute :converge, :kind_of => [TrueClass, FalseClass]
54
+
55
+ # A list of files to upload, in the format REMOTE_PATH => LOCAL_PATH|HASH.
56
+ # == Examples
57
+ # files '/remote/path.txt' => '/local/path.txt'
58
+ # files '/remote/path.txt' => { :local_path => '/local/path.txt' }
59
+ # files '/remote/path.txt' => { :content => 'woo' }
60
+ attribute :files, :kind_of => Hash
61
+
62
+ # A single file to upload, in the format REMOTE_PATH, LOCAL_PATH|HASH.
63
+ # This directive may be passed multiple times, and multiple files will be uploaded.
64
+ # == Examples
65
+ # file '/remote/path.txt', '/local/path.txt'
66
+ # file '/remote/path.txt', { :local_path => '/local/path.txt' }
67
+ # file '/remote/path.txt', { :content => 'woo' }
68
+ def file(remote_path, local = nil)
69
+ @files ||= {}
70
+ if remote_path.is_a?(Hash)
71
+ if local
72
+ raise "file(Hash, something) does not make sense. Either pass a hash, or pass a pair, please."
73
+ end
74
+ remote_path.each_pair do |remote, local|
75
+ @files[remote] = local
76
+ end
77
+ elsif remote_path.is_a?(String)
78
+ if !local
79
+ raise "Must pass both a remote path and a local path to file directive"
80
+ end
81
+ @files[remote_path] = local
82
+ else
83
+ raise "file remote_path must be a String, but is a #{remote_path.class}"
84
+ end
85
+ end
86
+
87
+ def add_machine_options(options)
88
+ @machine_options = Chef::Mixin::DeepMerge.hash_only_merge(@machine_options, options)
89
+ end
90
+
91
+ # chef client version and omnibus
92
+ # chef-zero boot method?
93
+ # chef-client -z boot method?
94
+ # pushy boot method?
95
+ end
@@ -0,0 +1,20 @@
1
+ require 'chef/resource/lwrp_base'
2
+
3
+ class Chef::Resource::MachineBatch < Chef::Resource::LWRPBase
4
+ self.resource_name = 'machine_batch'
5
+
6
+ def initialize(*args)
7
+ super
8
+ @machines = []
9
+ @chef_server = run_context.cheffish.current_chef_server
10
+ end
11
+
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, :destroy
15
+ default_action :converge
16
+
17
+ attribute :machines, :kind_of => [ Array ]
18
+ attribute :max_simultaneous, :kind_of => [ Integer ]
19
+ attribute :chef_server
20
+ end
@@ -0,0 +1,22 @@
1
+ require 'chef/resource/lwrp_base'
2
+ require 'chef_metal'
3
+ require 'chef_metal/machine'
4
+ require 'chef_metal/driver'
5
+
6
+ class Chef::Resource::MachineExecute < Chef::Resource::LWRPBase
7
+ self.resource_name = 'machine_execute'
8
+
9
+ def initialize(*args)
10
+ super
11
+ @chef_server = run_context.cheffish.current_chef_server
12
+ end
13
+
14
+ actions :run
15
+ default_action :run
16
+
17
+ attribute :command, :kind_of => String, :name_attribute => true
18
+ attribute :machine, :kind_of => String
19
+
20
+ attribute :chef_server, :kind_of => Hash
21
+ attribute :driver, :kind_of => ChefMetal::Driver
22
+ end
@@ -0,0 +1,28 @@
1
+ require 'chef/resource/lwrp_base'
2
+ require 'chef_metal'
3
+ require 'chef_metal/machine'
4
+ require 'chef_metal/driver'
5
+
6
+ class Chef::Resource::MachineFile < Chef::Resource::LWRPBase
7
+ self.resource_name = 'machine_file'
8
+
9
+ def initialize(*args)
10
+ super
11
+ @chef_server = run_context.cheffish.current_chef_server
12
+ end
13
+
14
+ actions :upload, :download, :delete, :nothing
15
+ default_action :upload
16
+
17
+ attribute :path, :kind_of => String, :name_attribute => true
18
+ attribute :machine, :kind_of => String
19
+ attribute :local_path, :kind_of => String
20
+ attribute :content
21
+
22
+ attribute :owner, :kind_of => String
23
+ attribute :group, :kind_of => String
24
+ attribute :mode, :kind_of => String
25
+
26
+ attribute :chef_server, :kind_of => Hash
27
+ attribute :driver, :kind_of => ChefMetal::Driver
28
+ end
data/lib/chef_metal.rb ADDED
@@ -0,0 +1,62 @@
1
+ # Include recipe basics so require 'chef_metal' will load everything
2
+ require 'chef_metal/recipe_dsl'
3
+ require 'chef/server_api'
4
+ require 'cheffish/basic_chef_client'
5
+ require 'cheffish/merged_config'
6
+
7
+ module ChefMetal
8
+ def self.inline_resource(action_handler, &block)
9
+ events = ActionHandlerForward.new(action_handler)
10
+ Cheffish::BasicChefClient.converge_block(nil, events, &block)
11
+ end
12
+
13
+ class ActionHandlerForward < Chef::EventDispatch::Base
14
+ def initialize(action_handler)
15
+ @action_handler = action_handler
16
+ end
17
+
18
+ attr_reader :action_handler
19
+
20
+ def resource_update_applied(resource, action, update)
21
+ prefix = action_handler.should_perform_actions ? "" : "Would "
22
+ update = Array(update).flatten.map { |u| "#{prefix}#{u}"}
23
+ action_handler.performed_action(update)
24
+ end
25
+ end
26
+
27
+ # Helpers for driver inflation
28
+ @@registered_driver_classes = {}
29
+ def self.register_driver_class(name, driver)
30
+ @@registered_driver_classes[name] = driver
31
+ end
32
+
33
+ def self.config_for_url(driver_url, config = Cheffish.profiled_config)
34
+ if config && config[:drivers] && config[:drivers][driver_url]
35
+ config = Cheffish::MergedConfig.new(config[:drivers][driver_url], config)
36
+ end
37
+ config || {}
38
+ end
39
+
40
+ def self.default_driver(config = Cheffish.profiled_config)
41
+ driver_for_url(config[:driver], config)
42
+ end
43
+
44
+ def self.driver_for_url(driver_url, config = Cheffish.profiled_config)
45
+ cluster_type = driver_url.split(':', 2)[0]
46
+ require "chef_metal/driver_init/#{cluster_type}"
47
+ driver_class = @@registered_driver_classes[cluster_type]
48
+ config = config_for_url(driver_url, config)
49
+ driver_class.from_url(driver_url, config || {})
50
+ end
51
+
52
+ def self.connect_to_machine(machine_spec, config = Cheffish.profiled_config)
53
+ driver = driver_for_url(machine_spec.driver_url, config)
54
+ if driver
55
+ machine_options = { :convergence_options => { :chef_server => Cheffish.default_chef_server(config) } }
56
+ machine_options = Cheffish::MergedConfig.new(config[:machine_options], machine_options) if config[:machine_options]
57
+ driver.connect_to_machine(machine_spec, machine_options)
58
+ else
59
+ nil
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,63 @@
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
+ module ChefMetal
21
+ class ActionHandler
22
+
23
+ # This should be replaced with whatever records the update; by default it
24
+ # essentially does nothing here.
25
+ def updated!
26
+ @updated = true
27
+ end
28
+
29
+ def should_perform_actions
30
+ true
31
+ end
32
+
33
+ def report_progress(description)
34
+ Array(description).each { |d| puts d }
35
+ end
36
+
37
+ def performed_action(description)
38
+ Array(description).each { |d| puts d }
39
+ end
40
+
41
+ # This should perform the actual action (e.g., converge) if there is an
42
+ # action that needs to be done.
43
+ def perform_action(description)
44
+ if should_perform_actions
45
+ yield
46
+ end
47
+ performed_action(description)
48
+ end
49
+
50
+ # Open a stream which can be printed to and closed
51
+ def open_stream(name)
52
+ if block_given?
53
+ yield STDOUT
54
+ else
55
+ STDOUT
56
+ end
57
+ end
58
+
59
+ # A URL identifying the host node. nil if no such node.
60
+ def host_node
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,29 @@
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!, :open_stream, :host_node
16
+
17
+ def report_progress(description)
18
+ action_handler.report_progress(Array(description).flatten.map { |d| "#{prefix}#{d}" })
19
+ end
20
+
21
+ def performed_action(description)
22
+ action_handler.performed_action(Array(description).flatten.map { |d| "#{prefix}#{d}" })
23
+ end
24
+
25
+ def perform_action(description, &block)
26
+ action_handler.perform_action(Array(description).flatten.map { |d| "#{prefix}#{d}" }, &block)
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,64 @@
1
+ require 'chef_metal'
2
+ require 'cheffish'
3
+ require 'chef_metal/machine_spec'
4
+
5
+ module ChefMetal
6
+ #
7
+ # Specification for a machine. Sufficient information to find and contact it
8
+ # after it has been set up.
9
+ #
10
+ class ChefMachineSpec < MachineSpec
11
+ def initialize(node, chef_server)
12
+ super(node)
13
+ @chef_server = chef_server
14
+ end
15
+
16
+ #
17
+ # Get a MachineSpec from the chef server.
18
+ #
19
+ def self.get(name, chef_server = Cheffish.default_chef_server)
20
+ chef_api = Cheffish.chef_server_api(chef_server)
21
+ ChefMachineSpec.new(chef_api.get("/nodes/#{name}"), chef_server)
22
+ end
23
+
24
+ #
25
+ # Globally unique identifier for this machine. Does not depend on the machine's
26
+ # location or existence.
27
+ #
28
+ def id
29
+ ChefMachineSpec.id_from(chef_server, name)
30
+ end
31
+
32
+ def self.id_from(chef_server, name)
33
+ "#{chef_server[:chef_server_url]}/nodes/#{name}"
34
+ end
35
+
36
+ #
37
+ # Save this node to the server. If you have significant information that
38
+ # could be lost, you should do this as quickly as possible. Data will be
39
+ # saved automatically for you after allocate_machine and ready_machine.
40
+ #
41
+ def save(action_handler)
42
+ # Save the node to the server.
43
+ _self = self
44
+ _chef_server = _self.chef_server
45
+ ChefMetal.inline_resource(action_handler) do
46
+ chef_node _self.name do
47
+ chef_server _chef_server
48
+ raw_json _self.node
49
+ end
50
+ end
51
+ end
52
+
53
+ protected
54
+
55
+ attr_reader :chef_server
56
+
57
+ #
58
+ # Chef API object for the given Chef server
59
+ #
60
+ def chef_api
61
+ Cheffish.server_api_for(chef_server)
62
+ end
63
+ end
64
+ end