ridley 0.12.4 → 1.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. data/Gemfile +1 -1
  2. data/lib/ridley.rb +3 -3
  3. data/lib/ridley/bootstrap_context.rb +100 -0
  4. data/lib/ridley/bootstrap_context/unix.rb +74 -0
  5. data/lib/ridley/bootstrap_context/windows.rb +120 -0
  6. data/lib/ridley/chef_objects/node_object.rb +8 -5
  7. data/lib/ridley/host_commander.rb +207 -0
  8. data/lib/ridley/host_connector.rb +49 -87
  9. data/lib/ridley/host_connector/ssh.rb +153 -39
  10. data/lib/ridley/host_connector/winrm.rb +164 -39
  11. data/lib/ridley/resources/node_resource.rb +52 -56
  12. data/lib/ridley/version.rb +1 -1
  13. data/ridley.gemspec +0 -2
  14. data/spec/spec_helper.rb +4 -4
  15. data/spec/support/chef_server.rb +9 -3
  16. data/spec/unit/ridley/{bootstrap_bindings/unix_template_binding_spec.rb → bootstrap_context/unix_spec.rb} +2 -2
  17. data/spec/unit/ridley/{bootstrap_bindings/windows_template_binding_spec.rb → bootstrap_context/windows_spec.rb} +2 -2
  18. data/spec/unit/ridley/{mixin/bootstrap_binding_spec.rb → bootstrap_context_spec.rb} +2 -6
  19. data/spec/unit/ridley/host_commander_spec.rb +208 -0
  20. data/spec/unit/ridley/host_connector/ssh_spec.rb +37 -31
  21. data/spec/unit/ridley/host_connector/winrm_spec.rb +124 -31
  22. data/spec/unit/ridley/host_connector_spec.rb +23 -147
  23. data/spec/unit/ridley/resources/node_resource_spec.rb +55 -115
  24. metadata +17 -66
  25. data/lib/ridley/bootstrap_bindings.rb +0 -3
  26. data/lib/ridley/bootstrap_bindings/unix_template_binding.rb +0 -108
  27. data/lib/ridley/bootstrap_bindings/windows_template_binding.rb +0 -163
  28. data/lib/ridley/bootstrapper.rb +0 -89
  29. data/lib/ridley/bootstrapper/context.rb +0 -81
  30. data/lib/ridley/host_connector/response_set.rb +0 -98
  31. data/lib/ridley/host_connector/ssh/worker.rb +0 -135
  32. data/lib/ridley/host_connector/winrm/worker.rb +0 -159
  33. data/lib/ridley/log.rb +0 -10
  34. data/lib/ridley/mixin/bootstrap_binding.rb +0 -77
  35. data/spec/unit/ridley/bootstrapper/context_spec.rb +0 -45
  36. data/spec/unit/ridley/bootstrapper_spec.rb +0 -96
  37. data/spec/unit/ridley/host_connector/response_set_spec.rb +0 -112
  38. data/spec/unit/ridley/host_connector/ssh/worker_spec.rb +0 -57
  39. 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,10 +0,0 @@
1
- require 'mixlib/log'
2
-
3
- module Ridley
4
- # @author Jamie Winsor <reset@riotgames.com>
5
- class Log
6
- extend Mixlib::Log
7
-
8
- init
9
- end
10
- end
@@ -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