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