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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +106 -0
- data/LICENSE +201 -0
- data/README.md +201 -0
- data/Rakefile +6 -0
- data/bin/metal +276 -0
- data/lib/chef/provider/machine.rb +147 -0
- data/lib/chef/provider/machine_batch.rb +130 -0
- data/lib/chef/provider/machine_execute.rb +30 -0
- data/lib/chef/provider/machine_file.rb +49 -0
- data/lib/chef/resource/machine.rb +95 -0
- data/lib/chef/resource/machine_batch.rb +20 -0
- data/lib/chef/resource/machine_execute.rb +22 -0
- data/lib/chef/resource/machine_file.rb +28 -0
- data/lib/chef_metal.rb +62 -0
- data/lib/chef_metal/action_handler.rb +63 -0
- data/lib/chef_metal/add_prefix_action_handler.rb +29 -0
- data/lib/chef_metal/chef_machine_spec.rb +64 -0
- data/lib/chef_metal/chef_provider_action_handler.rb +72 -0
- data/lib/chef_metal/chef_run_data.rb +80 -0
- data/lib/chef_metal/convergence_strategy.rb +26 -0
- data/lib/chef_metal/convergence_strategy/install_cached.rb +157 -0
- data/lib/chef_metal/convergence_strategy/install_msi.rb +56 -0
- data/lib/chef_metal/convergence_strategy/install_sh.rb +51 -0
- data/lib/chef_metal/convergence_strategy/no_converge.rb +38 -0
- data/lib/chef_metal/convergence_strategy/precreate_chef_objects.rb +180 -0
- data/lib/chef_metal/driver.rb +267 -0
- data/lib/chef_metal/machine.rb +110 -0
- data/lib/chef_metal/machine/basic_machine.rb +82 -0
- data/lib/chef_metal/machine/unix_machine.rb +276 -0
- data/lib/chef_metal/machine/windows_machine.rb +102 -0
- data/lib/chef_metal/machine_spec.rb +78 -0
- data/lib/chef_metal/recipe_dsl.rb +84 -0
- data/lib/chef_metal/transport.rb +87 -0
- data/lib/chef_metal/transport/ssh.rb +235 -0
- data/lib/chef_metal/transport/winrm.rb +109 -0
- data/lib/chef_metal/version.rb +3 -0
- 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
|