ridley 0.12.4 → 1.0.0.rc1
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.
- data/Gemfile +1 -1
- data/lib/ridley.rb +3 -3
- data/lib/ridley/bootstrap_context.rb +100 -0
- data/lib/ridley/bootstrap_context/unix.rb +74 -0
- data/lib/ridley/bootstrap_context/windows.rb +120 -0
- data/lib/ridley/chef_objects/node_object.rb +8 -5
- data/lib/ridley/host_commander.rb +207 -0
- data/lib/ridley/host_connector.rb +49 -87
- data/lib/ridley/host_connector/ssh.rb +153 -39
- data/lib/ridley/host_connector/winrm.rb +164 -39
- data/lib/ridley/resources/node_resource.rb +52 -56
- data/lib/ridley/version.rb +1 -1
- data/ridley.gemspec +0 -2
- data/spec/spec_helper.rb +4 -4
- data/spec/support/chef_server.rb +9 -3
- data/spec/unit/ridley/{bootstrap_bindings/unix_template_binding_spec.rb → bootstrap_context/unix_spec.rb} +2 -2
- data/spec/unit/ridley/{bootstrap_bindings/windows_template_binding_spec.rb → bootstrap_context/windows_spec.rb} +2 -2
- data/spec/unit/ridley/{mixin/bootstrap_binding_spec.rb → bootstrap_context_spec.rb} +2 -6
- data/spec/unit/ridley/host_commander_spec.rb +208 -0
- data/spec/unit/ridley/host_connector/ssh_spec.rb +37 -31
- data/spec/unit/ridley/host_connector/winrm_spec.rb +124 -31
- data/spec/unit/ridley/host_connector_spec.rb +23 -147
- data/spec/unit/ridley/resources/node_resource_spec.rb +55 -115
- metadata +17 -66
- data/lib/ridley/bootstrap_bindings.rb +0 -3
- data/lib/ridley/bootstrap_bindings/unix_template_binding.rb +0 -108
- data/lib/ridley/bootstrap_bindings/windows_template_binding.rb +0 -163
- data/lib/ridley/bootstrapper.rb +0 -89
- data/lib/ridley/bootstrapper/context.rb +0 -81
- data/lib/ridley/host_connector/response_set.rb +0 -98
- data/lib/ridley/host_connector/ssh/worker.rb +0 -135
- data/lib/ridley/host_connector/winrm/worker.rb +0 -159
- data/lib/ridley/log.rb +0 -10
- data/lib/ridley/mixin/bootstrap_binding.rb +0 -77
- data/spec/unit/ridley/bootstrapper/context_spec.rb +0 -45
- data/spec/unit/ridley/bootstrapper_spec.rb +0 -96
- data/spec/unit/ridley/host_connector/response_set_spec.rb +0 -112
- data/spec/unit/ridley/host_connector/ssh/worker_spec.rb +0 -57
- data/spec/unit/ridley/host_connector/winrm/worker_spec.rb +0 -139
@@ -1,159 +0,0 @@
|
|
1
|
-
module Ridley
|
2
|
-
module HostConnector
|
3
|
-
class WinRM
|
4
|
-
# @author Kyle Allan <kallan@riotgames.com>
|
5
|
-
# @api private
|
6
|
-
class Worker
|
7
|
-
include Celluloid
|
8
|
-
include Celluloid::Logger
|
9
|
-
|
10
|
-
# @return [String]
|
11
|
-
attr_reader :user
|
12
|
-
# @return [String]
|
13
|
-
attr_reader :password
|
14
|
-
# @return [String]
|
15
|
-
attr_reader :host
|
16
|
-
# @return [Hash]
|
17
|
-
attr_reader :options
|
18
|
-
# @return [String]
|
19
|
-
attr_reader :winrm_endpoint
|
20
|
-
# @return [CommandUploader]
|
21
|
-
attr_reader :command_uploader
|
22
|
-
# @return [Array]
|
23
|
-
attr_reader :command_uploaders
|
24
|
-
|
25
|
-
finalizer :finalize_callback
|
26
|
-
|
27
|
-
EMBEDDED_RUBY_PATH = 'C:\opscode\chef\embedded\bin\ruby'.freeze
|
28
|
-
|
29
|
-
# @param host [String]
|
30
|
-
# the host the worker is going to work on
|
31
|
-
# @option options [Hash] :winrm
|
32
|
-
# * :user (String) a user that will login to each node and perform the bootstrap command on (required)
|
33
|
-
# * :password (String) the password for the user that will perform the bootstrap
|
34
|
-
# * :port (Fixnum) the winrm port to connect on the node the bootstrap will be performed on (5985)
|
35
|
-
def initialize(host, options = {})
|
36
|
-
options = options.deep_symbolize_keys
|
37
|
-
@options = options[:winrm] || Hash.new
|
38
|
-
@host = host
|
39
|
-
@user = @options[:user]
|
40
|
-
@password = @options[:password]
|
41
|
-
@winrm_endpoint = "http://#{host}:#{winrm_port}/wsman"
|
42
|
-
@command_uploaders = Array.new
|
43
|
-
end
|
44
|
-
|
45
|
-
def run(command)
|
46
|
-
response = Ridley::HostConnector::Response.new(host)
|
47
|
-
command_uploaders << command_uploader = CommandUploader.new(winrm)
|
48
|
-
command = get_command(command, command_uploader)
|
49
|
-
|
50
|
-
debug "Running WinRM Command: '#{command}' on: '#{host}' as: '#{user}'"
|
51
|
-
|
52
|
-
output = winrm.run_cmd(command) do |stdout, stderr|
|
53
|
-
if stdout
|
54
|
-
response.stdout += stdout
|
55
|
-
info "NODE[#{host}] #{stdout}"
|
56
|
-
end
|
57
|
-
|
58
|
-
if stderr
|
59
|
-
response.stderr += stderr unless stderr.nil?
|
60
|
-
info "NODE[#{host}] #{stdout}"
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
response.exit_code = output[:exitcode]
|
65
|
-
|
66
|
-
case response.exit_code
|
67
|
-
when 0
|
68
|
-
debug "Successfully ran WinRM command on: '#{host}' as: '#{user}'"
|
69
|
-
[ :ok, response ]
|
70
|
-
else
|
71
|
-
error "Successfully ran WinRM command on: '#{host}' as: '#{user}', but it failed"
|
72
|
-
error response.stdout
|
73
|
-
[ :error, response ]
|
74
|
-
end
|
75
|
-
rescue => e
|
76
|
-
error "Failed to run WinRM command on: '#{host}' as: '#{user}'"
|
77
|
-
error "#{e.class}: #{e.message}"
|
78
|
-
response.exit_code = -1
|
79
|
-
response.stderr = e.message
|
80
|
-
[ :error, response ]
|
81
|
-
end
|
82
|
-
|
83
|
-
# @return [WinRM::WinRMWebService]
|
84
|
-
def winrm
|
85
|
-
@winrm_client ||= begin
|
86
|
-
require 'active_support/core_ext/kernel/reporting'
|
87
|
-
# Silencing warnings because not all versions of GSSAPI support all of the GSSAPI methods
|
88
|
-
# the gssapi gem attempts to attach to and these warnings are dumped to STDERR.
|
89
|
-
silence_warnings do
|
90
|
-
require 'winrm'
|
91
|
-
end
|
92
|
-
|
93
|
-
client = ::WinRM::WinRMWebService.new(winrm_endpoint, :plaintext,
|
94
|
-
user: user, pass: password, disable_sspi: true, basic_auth_only: true)
|
95
|
-
client.set_timeout(6000)
|
96
|
-
client
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
# @return [Fixnum]
|
101
|
-
def winrm_port
|
102
|
-
options[:port] || Ridley::HostConnector::DEFAULT_WINRM_PORT
|
103
|
-
end
|
104
|
-
|
105
|
-
# Returns the command if it does not break the WinRM command length
|
106
|
-
# limit. Otherwise, we return an execution of the command as a batch file.
|
107
|
-
#
|
108
|
-
# @param command [String]
|
109
|
-
#
|
110
|
-
# @return [String]
|
111
|
-
def get_command(command, command_uploader)
|
112
|
-
if command.length < CommandUploader::CHUNK_LIMIT
|
113
|
-
command
|
114
|
-
else
|
115
|
-
debug "Detected a command that was longer than #{CommandUploader::CHUNK_LIMIT} characters, \
|
116
|
-
uploading command as a file to the host."
|
117
|
-
command_uploader.upload(command)
|
118
|
-
command_uploader.command
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
# Executes a chef-client run on the nodes
|
123
|
-
#
|
124
|
-
# @return [#run]
|
125
|
-
def chef_client
|
126
|
-
run("chef-client")
|
127
|
-
end
|
128
|
-
|
129
|
-
# Writes the given encrypted data bag secret to the node
|
130
|
-
#
|
131
|
-
# @param [String] secret
|
132
|
-
# your organization's encrypted data bag secret
|
133
|
-
#
|
134
|
-
# @return [#run]
|
135
|
-
def put_secret(secret)
|
136
|
-
command = "echo #{secret} > C:\\chef\\encrypted_data_bag_secret"
|
137
|
-
run(command)
|
138
|
-
end
|
139
|
-
|
140
|
-
# Executes a provided Ruby script in the embedded Ruby installation
|
141
|
-
#
|
142
|
-
# @param [Array<String>] command_lines
|
143
|
-
# An Array of lines of the command to be executed
|
144
|
-
#
|
145
|
-
# @return [#run]
|
146
|
-
def ruby_script(command_lines)
|
147
|
-
command = "#{EMBEDDED_RUBY_PATH} -e \"#{command_lines.join(';')}\""
|
148
|
-
run(command)
|
149
|
-
end
|
150
|
-
|
151
|
-
private
|
152
|
-
|
153
|
-
def finalize_callback
|
154
|
-
command_uploaders.map(&:cleanup)
|
155
|
-
end
|
156
|
-
end
|
157
|
-
end
|
158
|
-
end
|
159
|
-
end
|
data/lib/ridley/log.rb
DELETED
@@ -1,77 +0,0 @@
|
|
1
|
-
require 'erubis'
|
2
|
-
|
3
|
-
module Ridley
|
4
|
-
module BootstrapBinding
|
5
|
-
module ClassMethods
|
6
|
-
def validate_options(options = {})
|
7
|
-
if options[:server_url].nil?
|
8
|
-
raise Errors::ArgumentError, "A server_url is required for bootstrapping"
|
9
|
-
end
|
10
|
-
|
11
|
-
if options[:validator_path].nil?
|
12
|
-
raise Errors::ArgumentError, "A path to a validator is required for bootstrapping"
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
# A hash of default options to be used in the Context initializer
|
17
|
-
#
|
18
|
-
# @return [Hash]
|
19
|
-
def default_options
|
20
|
-
@default_options ||= {
|
21
|
-
validator_client: "chef-validator",
|
22
|
-
attributes: Hash.new,
|
23
|
-
run_list: Array.new,
|
24
|
-
environment: "_default",
|
25
|
-
sudo: true,
|
26
|
-
hints: Hash.new
|
27
|
-
}
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
class << self
|
32
|
-
def included(base)
|
33
|
-
base.extend(ClassMethods)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
attr_reader :template_file
|
38
|
-
attr_reader :bootstrap_proxy
|
39
|
-
attr_reader :chef_version
|
40
|
-
attr_reader :default_options
|
41
|
-
attr_reader :validator_path
|
42
|
-
attr_reader :encrypted_data_bag_secret
|
43
|
-
attr_reader :server_url
|
44
|
-
attr_reader :validator_client
|
45
|
-
attr_reader :node_name
|
46
|
-
attr_reader :attributes
|
47
|
-
attr_reader :run_list
|
48
|
-
attr_reader :environment
|
49
|
-
|
50
|
-
# @return [Pathname]
|
51
|
-
def templates_path
|
52
|
-
Ridley.root.join('bootstrappers')
|
53
|
-
end
|
54
|
-
|
55
|
-
# @return [String]
|
56
|
-
def first_boot
|
57
|
-
JSON.fast_generate(attributes.merge(run_list: run_list))
|
58
|
-
end
|
59
|
-
|
60
|
-
# The validation key to create a new client for the node
|
61
|
-
#
|
62
|
-
# @raise [Ridley::Errors::ValidatorNotFound]
|
63
|
-
#
|
64
|
-
# @return [String]
|
65
|
-
def validation_key
|
66
|
-
IO.read(File.expand_path(validator_path)).chomp
|
67
|
-
rescue Errno::ENOENT
|
68
|
-
raise Errors::ValidatorNotFound, "Error bootstrapping: Validator not found at '#{validator_path}'"
|
69
|
-
end
|
70
|
-
|
71
|
-
# @return [Erubis::Eruby]
|
72
|
-
def template
|
73
|
-
Erubis::Eruby.new(IO.read(template_file).chomp)
|
74
|
-
end
|
75
|
-
|
76
|
-
end
|
77
|
-
end
|
@@ -1,45 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Ridley::Bootstrapper::Context do
|
4
|
-
let(:host) { "reset.riotgames.com" }
|
5
|
-
|
6
|
-
let(:options) do
|
7
|
-
{
|
8
|
-
server_url: "https://api.opscode.com/organizations/vialstudios",
|
9
|
-
validator_client: "chef-validator",
|
10
|
-
validator_path: fixtures_path.join("reset.pem").to_s,
|
11
|
-
encrypted_data_bag_secret: File.read(fixtures_path.join("reset.pem"))
|
12
|
-
}
|
13
|
-
end
|
14
|
-
|
15
|
-
describe "ClassMethods" do
|
16
|
-
subject { Ridley::Bootstrapper::Context }
|
17
|
-
|
18
|
-
describe "::create" do
|
19
|
-
context "when the best connection is SSH" do
|
20
|
-
it "sets template_binding to a Ridley::UnixTemplateBinding" do
|
21
|
-
Ridley::HostConnector.stub(:best_connector_for).and_return(Ridley::HostConnector::SSH)
|
22
|
-
context = subject.create(host, options)
|
23
|
-
context.template_binding.should be_a(Ridley::UnixTemplateBinding)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
context "when the best connection is WinRM" do
|
28
|
-
it "sets template_binding to a Ridley::WindowsTemplateBinding" do
|
29
|
-
Ridley::HostConnector.stub(:best_connector_for).and_return(Ridley::HostConnector::WinRM)
|
30
|
-
context = subject.create(host, options)
|
31
|
-
context.template_binding.should be_a(Ridley::WindowsTemplateBinding)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
context "when there is no good connection option" do
|
36
|
-
it "raises an error" do
|
37
|
-
Ridley::HostConnector.stub(:best_connector_for).and_return(nil)
|
38
|
-
expect {
|
39
|
-
context = subject.create(host, options)
|
40
|
-
}.to raise_error(Ridley::Errors::HostConnectionError)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
@@ -1,96 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Ridley::Bootstrapper do
|
4
|
-
let(:nodes) do
|
5
|
-
[
|
6
|
-
"33.33.33.10"
|
7
|
-
]
|
8
|
-
end
|
9
|
-
|
10
|
-
let(:options) do
|
11
|
-
{
|
12
|
-
ssh_user: "vagrant",
|
13
|
-
ssh_password: "vagrant",
|
14
|
-
server_url: "https://api.opscode.com/organizations/vialstudios",
|
15
|
-
validator_client: "vialstudios-validator",
|
16
|
-
validator_path: fixtures_path.join("reset.pem").to_s,
|
17
|
-
encrypted_data_bag_secret: File.read(fixtures_path.join("reset.pem"))
|
18
|
-
}
|
19
|
-
end
|
20
|
-
|
21
|
-
before(:each) { Ridley::HostConnector.stub(:best_connector_for).and_return(Ridley::HostConnector::SSH) }
|
22
|
-
|
23
|
-
describe "ClassMethods" do
|
24
|
-
subject { Ridley::Bootstrapper }
|
25
|
-
|
26
|
-
describe "::new" do
|
27
|
-
context "given a single string for nodes" do
|
28
|
-
before(:each) do
|
29
|
-
@obj = subject.new("33.33.33.10", options)
|
30
|
-
end
|
31
|
-
|
32
|
-
it "has one node" do
|
33
|
-
@obj.hosts.should have(1).item
|
34
|
-
end
|
35
|
-
|
36
|
-
it "has one context" do
|
37
|
-
@obj.contexts.should have(1).item
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
context "given an an array of strings nodes" do
|
42
|
-
before(:each) do
|
43
|
-
@obj = subject.new(["33.33.33.10", "33.33.33.11"], options)
|
44
|
-
end
|
45
|
-
|
46
|
-
it "has a host for each item given" do
|
47
|
-
@obj.hosts.should have(2).items
|
48
|
-
end
|
49
|
-
|
50
|
-
it "has a context for each item given" do
|
51
|
-
@obj.contexts.should have(2).items
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
subject { Ridley::Bootstrapper.new(nodes, options) }
|
58
|
-
|
59
|
-
describe "#hosts" do
|
60
|
-
it "returns an array of strings" do
|
61
|
-
subject.hosts.should be_a(Array)
|
62
|
-
subject.hosts.should each be_a(String)
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
describe "#contexts" do
|
67
|
-
before do
|
68
|
-
Ridley::Bootstrapper::Context.stub(:create).and_return(double)
|
69
|
-
end
|
70
|
-
|
71
|
-
it "creates a new context for each host" do
|
72
|
-
Ridley::Bootstrapper::Context.should_receive(:create).exactly(nodes.length).times
|
73
|
-
subject.contexts
|
74
|
-
end
|
75
|
-
|
76
|
-
it "contains a item for each host" do
|
77
|
-
subject.contexts.should have(nodes.length).items
|
78
|
-
end
|
79
|
-
|
80
|
-
context "when a host is unreachable" do
|
81
|
-
before do
|
82
|
-
Ridley::Bootstrapper::Context.stub(:create).and_raise(Ridley::Errors::HostConnectionError)
|
83
|
-
end
|
84
|
-
|
85
|
-
it "raises a HostConnectionError" do
|
86
|
-
expect {
|
87
|
-
subject.contexts
|
88
|
-
}.to raise_error(Ridley::Errors::HostConnectionError)
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
describe "#run" do
|
94
|
-
pending
|
95
|
-
end
|
96
|
-
end
|
@@ -1,112 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Ridley::HostConnector::ResponseSet do
|
4
|
-
describe "ClassMethods" do
|
5
|
-
subject { described_class }
|
6
|
-
|
7
|
-
describe "::merge!" do
|
8
|
-
let(:target) { Ridley::HostConnector::ResponseSet.new }
|
9
|
-
let(:other) { Ridley::HostConnector::ResponseSet.new }
|
10
|
-
|
11
|
-
before(:each) do
|
12
|
-
other.add_response(Ridley::HostConnector::Response.new('host.local'))
|
13
|
-
end
|
14
|
-
|
15
|
-
it "returns the mutated target" do
|
16
|
-
result = subject.merge!(target, other)
|
17
|
-
|
18
|
-
result.should eql(target)
|
19
|
-
result.should have(1).item
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
subject { described_class.new }
|
25
|
-
|
26
|
-
describe "#add_response" do
|
27
|
-
it "accepts an array of responses" do
|
28
|
-
responses = [
|
29
|
-
Ridley::HostConnector::Response.new("one.riotgames.com"),
|
30
|
-
Ridley::HostConnector::Response.new("two.riotgames.com")
|
31
|
-
]
|
32
|
-
subject.add_response(responses)
|
33
|
-
|
34
|
-
subject.responses.should have(2).items
|
35
|
-
end
|
36
|
-
|
37
|
-
it "accepts a single response" do
|
38
|
-
response = Ridley::HostConnector::Response.new("one.riotgames.com")
|
39
|
-
subject.add_response(response)
|
40
|
-
|
41
|
-
subject.responses.should have(1).item
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
describe "#responses" do
|
46
|
-
it "returns an array of Ridley::HostConnector::Response objects including both failures and successes" do
|
47
|
-
responses = [
|
48
|
-
double('success', error?: false),
|
49
|
-
double('failure', error?: true)
|
50
|
-
]
|
51
|
-
subject.add_response(responses)
|
52
|
-
|
53
|
-
subject.responses.should have(2).items
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
describe "#successes" do
|
58
|
-
it "returns an array of Ridley::HostConnector::Response objects only including the successes" do
|
59
|
-
responses = [
|
60
|
-
double('success', error?: false),
|
61
|
-
double('failure', error?: true)
|
62
|
-
]
|
63
|
-
subject.add_response(responses)
|
64
|
-
|
65
|
-
subject.successes.should have(1).item
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
describe "#failures" do
|
70
|
-
it "returns an array of Ridley::HostConnector::Response objects only including the failures" do
|
71
|
-
responses = [
|
72
|
-
double('success', error?: false),
|
73
|
-
double('failure', error?: true)
|
74
|
-
]
|
75
|
-
subject.add_response(responses)
|
76
|
-
|
77
|
-
subject.failures.should have(1).item
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
describe "#merge" do
|
82
|
-
let(:target) { Ridley::HostConnector::ResponseSet.new }
|
83
|
-
let(:other) { Ridley::HostConnector::ResponseSet.new }
|
84
|
-
|
85
|
-
before(:each) do
|
86
|
-
other.add_response(Ridley::HostConnector::Response.new('host.local'))
|
87
|
-
end
|
88
|
-
|
89
|
-
it "returns a new Ridley::HostConnector::ResponseSet object" do
|
90
|
-
result = target.merge(other)
|
91
|
-
|
92
|
-
result.should have(1).item
|
93
|
-
target.should have(0).items
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
describe "#merge!" do
|
98
|
-
let(:target) { Ridley::HostConnector::ResponseSet.new }
|
99
|
-
let(:other) { Ridley::HostConnector::ResponseSet.new }
|
100
|
-
|
101
|
-
before(:each) do
|
102
|
-
other.add_response(Ridley::HostConnector::Response.new('host.local'))
|
103
|
-
end
|
104
|
-
|
105
|
-
it "returns the mutated target" do
|
106
|
-
result = target.merge!(other)
|
107
|
-
|
108
|
-
result.should have(1).item
|
109
|
-
target.should have(1).item
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|