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

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