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,111 +1,73 @@
1
- require 'socket'
2
- require 'timeout'
3
-
4
1
  module Ridley
5
2
  # @author Kyle Allan <kallan@riotgames.com>
6
3
  module HostConnector
7
- require_relative 'host_connector/response'
8
- require_relative 'host_connector/response_set'
9
- require_relative 'host_connector/ssh'
10
- require_relative 'host_connector/winrm'
11
-
12
- DEFAULT_SSH_PORT = 22.freeze
13
- DEFAULT_WINRM_PORT = 5985.freeze
4
+ class Base
5
+ include Celluloid
6
+ include Ridley::Logging
14
7
 
15
- class << self
16
- # Create a new connection worker for the given host. An SSH or WinRM connection will be returned
17
- # depending on which ports are open on the target host.
8
+ # Execute a shell command on a node
18
9
  #
19
10
  # @param [String] host
20
- # host to create a connector for
11
+ # the host to perform the action on
12
+ # @param [String] command
13
+ # @param [Hash] options
21
14
  #
22
- # @option options [Hash] ssh
23
- # * :user (String) a shell user that will login to each node and perform the bootstrap command on
24
- # * :password (String) the password for the shell user that will perform the bootstrap
25
- # * :keys (Array, String) an array of keys (or a single key) to authenticate the ssh user with instead of a password
26
- # * :timeout (Float) [5.0] timeout value for SSH bootstrap
27
- # @option options [Hash] :winrm
28
- # * :user (String) a user that will login to each node and perform the bootstrap command on
29
- # * :password (String) the password for the user that will perform the bootstrap
30
- # * :port (Fixnum) the winrm port to connect on the node the bootstrap will be performed on
31
- #
32
- # @return [SSH::Worker, WinRM::Worker]
33
- def new(host, options = {})
34
- HostConnector.best_connector_for(host, options) do |host_connector|
35
- host_connector::Worker.new(host, options)
36
- end
15
+ # @return [HostConnector::Response]
16
+ def run(host, command, options = {})
17
+ raise RuntimeError, "abstract function: must be implemented on includer"
37
18
  end
38
19
 
39
- # Finds and returns the best HostConnector for a given host
20
+ # Bootstrap a node
40
21
  #
41
- # @param host [String]
42
- # the host to attempt to connect to
43
- # @option options [Hash] :ssh
44
- # * :port (Fixnum) the ssh port to connect on the node the bootstrap will be performed on (22)
45
- # * :timeout (Float) [5.0] timeout value for testing SSH connection
46
- # @option options [Hash] :winrm
47
- # * :port (Fixnum) the winrm port to connect on the node the bootstrap will be performed on (5985)
48
- # @param block [Proc]
49
- # an optional block that is yielded the best HostConnector
22
+ # @param [String] host
23
+ # the host to perform the action on
24
+ # @param [Hash] options
50
25
  #
51
- # @return [Ridley::HostConnector] a class under Ridley::HostConnector
52
- def best_connector_for(host, options = {}, &block)
53
- ssh_port, winrm_port = parse_port_options(options)
54
- timeout = options[:ssh] && options[:ssh][:timeout]
55
-
56
- if connector_port_open?(host, winrm_port)
57
- host_connector = Ridley::HostConnector::WinRM
58
- elsif connector_port_open?(host, ssh_port, timeout)
59
- host_connector = Ridley::HostConnector::SSH
60
- else
61
- raise Ridley::Errors::HostConnectionError, "No available connection method available on #{host}."
62
- end
63
-
64
- if block_given?
65
- yield host_connector
66
- else
67
- host_connector
68
- end
26
+ # @return [HostConnector::Response]
27
+ def bootstrap(host, options = {})
28
+ raise RuntimeError, "abstract function: must be implemented on includer"
69
29
  end
70
30
 
71
- # Checks to see if the given port is open for TCP connections
72
- # on the given host.
31
+ # Perform a chef client run on a node
73
32
  #
74
- # @param host [String]
75
- # the host to attempt to connect to
76
- # @param port [Fixnum]
77
- # the port to attempt to connect on
78
- # @param timeout [Float]
79
- # the number of seconds to wait (default: 3)
33
+ # @param [String] host
34
+ # the host to perform the action on
35
+ # @param [Hash] options
80
36
  #
81
- # @return [Boolean]
82
- def connector_port_open?(host, port, timeout = nil)
83
- timeout ||= 3
84
-
85
- Timeout::timeout(timeout) do
86
- socket = TCPSocket.new(host, port)
87
- socket.close
88
- end
37
+ # @return [HostConnector::Response]
38
+ def chef_client(host, options = {})
39
+ raise RuntimeError, "abstract function: must be implemented on includer"
40
+ end
89
41
 
90
- true
91
- rescue Timeout::Error, SocketError, Errno::ECONNREFUSED, Errno::EHOSTUNREACH
92
- false
42
+ # Write your encrypted data bag secret on a node
43
+ #
44
+ # @param [String] host
45
+ # the host to perform the action on
46
+ # @param [String] secret
47
+ # your organization's encrypted data bag secret
48
+ # @param [Hash] options
49
+ #
50
+ # @return [HostConnector::Response]
51
+ def put_secret(host, secret, options = {})
52
+ raise RuntimeError, "abstract function: must be implemented on includer"
93
53
  end
94
54
 
95
- # Parses the options Hash and returns an array of
96
- # [SSH_PORT, WINRM_PORT] used to attempt to connect to.
55
+ # Execute line(s) of Ruby code on a node using Chef's embedded Ruby
97
56
  #
98
- # @option options [Hash] :ssh
99
- # * :port (Fixnum) the ssh port to connect on the node the bootstrap will be performed on (22)
100
- # @option options [Hash] :winrm
101
- # * :port (Fixnum) the winrm port to connect on the node the bootstrap will be performed on (5985)
57
+ # @param [String] host
58
+ # the host to perform the action on
59
+ # @param [Array<String>] command_lines
60
+ # An Array of lines of the command to be executed
61
+ # @param [Hash] options
102
62
  #
103
- # @return [Array]
104
- def parse_port_options(options)
105
- ssh_port = options[:ssh][:port] if options[:ssh]
106
- winrm_port = options[:winrm][:port] if options[:winrm]
107
- [ssh_port || DEFAULT_SSH_PORT, winrm_port || DEFAULT_WINRM_PORT]
63
+ # @return [HostConnector::Response]
64
+ def ruby_script(host, command_lines, options = {})
65
+ raise RuntimeError, "abstract function: must be implemented on includer"
108
66
  end
109
67
  end
68
+
69
+ require_relative 'host_connector/response'
70
+ require_relative 'host_connector/ssh'
71
+ require_relative 'host_connector/winrm'
110
72
  end
111
73
  end
@@ -3,56 +3,170 @@ require 'net/ssh'
3
3
  module Ridley
4
4
  module HostConnector
5
5
  # @author Jamie Winsor <reset@riotgames.com>
6
- class SSH
7
- require_relative 'ssh/worker'
8
-
9
- class << self
10
- # @param [Ridley::NodeObject, Array<Ridley::NodeObject>] nodes
11
- # @param [Hash] options
12
- def start(nodes, options = {}, &block)
13
- runner = new(nodes, options)
14
- result = yield runner
15
- runner.terminate
16
-
17
- result
18
- ensure
19
- runner.terminate if runner && runner.alive?
6
+ class SSH < HostConnector::Base
7
+ DEFAULT_PORT = 22
8
+ EMBEDDED_RUBY_PATH = '/opt/chef/embedded/bin/ruby'.freeze
9
+
10
+ # Execute a shell command on a node
11
+ #
12
+ # @param [String] host
13
+ # the host to perform the action on
14
+ # @param [String] command
15
+ #
16
+ # @option options [Hash] :ssh
17
+ # * :user (String) a shell user that will login to each node and perform the bootstrap command on
18
+ # * :password (String) the password for the shell user that will perform the bootstrap
19
+ # * :keys (Array, String) an array of key(s) to authenticate the ssh user with instead of a password
20
+ # * :timeout (Float) timeout value for SSH bootstrap (5.0)
21
+ # * :sudo (Boolean) run as sudo
22
+ #
23
+ # @return [HostConnector::Response]
24
+ def run(host, command, options = {})
25
+ options = options.reverse_merge(ssh: Hash.new)
26
+ options[:ssh].reverse_merge!(port: DEFAULT_PORT, paranoid: false, sudo: false)
27
+
28
+ command = "sudo #{command}" if options[:sudo]
29
+
30
+ Ridley::HostConnector::Response.new(host).tap do |response|
31
+ begin
32
+ log.info "Running SSH command: '#{command}' on: '#{host}' as: '#{options[:ssh][:user]}'"
33
+
34
+ Net::SSH.start(host, options[:ssh][:user], options[:ssh].slice(*Net::SSH::VALID_OPTIONS)) do |ssh|
35
+ ssh.open_channel do |channel|
36
+ if options[:sudo]
37
+ channel.request_pty do |channel, success|
38
+ unless success
39
+ raise "Could not aquire pty: A pty is required for running sudo commands."
40
+ end
41
+
42
+ channel_exec(channel, command, host, response)
43
+ end
44
+ else
45
+ channel_exec(channel, command, host, response)
46
+ end
47
+ end
48
+ ssh.loop
49
+ end
50
+ rescue Net::SSH::Exception => ex
51
+ response.exit_code = -1
52
+ response.stderr = ex.message
53
+ return response
54
+ end
55
+
56
+ case response.exit_code
57
+ when 0
58
+ log.info "Successfully ran SSH command on: '#{host}' as: '#{options[:ssh][:user]}'"
59
+ else
60
+ log.info "Successfully ran SSH command on: '#{host}' as: '#{options[:ssh][:user]}' but it failed"
61
+ end
20
62
  end
21
63
  end
22
64
 
23
- include Celluloid
24
- include Celluloid::Logger
65
+ # Bootstrap a node
66
+ #
67
+ # @param [String] host
68
+ # the host to perform the action on
69
+ #
70
+ # @option options [Hash] :ssh
71
+ # * :user (String) a shell user that will login to each node and perform the bootstrap command on
72
+ # * :password (String) the password for the shell user that will perform the bootstrap
73
+ # * :keys (Array, String) an array of key(s) to authenticate the ssh user with instead of a password
74
+ # * :timeout (Float) timeout value for SSH bootstrap (5.0)
75
+ # * :sudo (Boolean) run as sudo
76
+ #
77
+ # @return [HostConnector::Response]
78
+ def bootstrap(host, options = {})
79
+ options = options.reverse_merge(ssh: Hash.new)
80
+ options[:ssh].reverse_merge!(sudo: true, timeout: 5.0)
81
+ context = BootstrapContext::Unix.new(options)
25
82
 
26
- attr_reader :nodes
27
- attr_reader :options
83
+ log.info "Bootstrapping host: #{host}"
84
+ run(host, context.boot_command, options)
85
+ end
28
86
 
29
- # @param [Ridley::NodeObject, Array<Ridley::NodeObject>] nodes
30
- # @param [Hash] options
31
- # @see Net::SSH
32
- def initialize(nodes, options = {})
33
- @nodes = Array(nodes)
34
- @options = options
87
+ # Perform a chef client run on a node
88
+ #
89
+ # @param [String] host
90
+ # the host to perform the action on
91
+ #
92
+ # @option options [Hash] :ssh
93
+ # * :user (String) a shell user that will login to each node and perform the bootstrap command on
94
+ # * :password (String) the password for the shell user that will perform the bootstrap
95
+ # * :keys (Array, String) an array of key(s) to authenticate the ssh user with instead of a password
96
+ # * :timeout (Float) timeout value for SSH bootstrap (5.0)
97
+ # * :sudo (Boolean) run as sudo
98
+ #
99
+ # @return [HostConnector::Response]
100
+ def chef_client(host, options = {})
101
+ run(host, "chef-client", options)
35
102
  end
36
103
 
37
- # @param [String] command
104
+ # Write your encrypted data bag secret on a node
38
105
  #
39
- # @return [Array]
40
- def run(command)
41
- workers = Array.new
42
- futures = self.nodes.collect do |node|
43
- workers << worker = Worker.new(node.public_hostname, self.options.freeze)
44
- worker.future.run(command)
45
- end
106
+ # @param [String] host
107
+ # the host to perform the action on
108
+ # @param [String] secret
109
+ # your organization's encrypted data bag secret
110
+ #
111
+ # @option options [Hash] :ssh
112
+ # * :user (String) a shell user that will login to each node and perform the bootstrap command on
113
+ # * :password (String) the password for the shell user that will perform the bootstrap
114
+ # * :keys (Array, String) an array of key(s) to authenticate the ssh user with instead of a password
115
+ # * :timeout (Float) timeout value for SSH bootstrap (5.0)
116
+ # * :sudo (Boolean) run as sudo
117
+ #
118
+ # @return [HostConnector::Response]
119
+ def put_secret(host, secret, options = {})
120
+ cmd = "echo '#{secret}' > /etc/chef/encrypted_data_bag_secret; chmod 0600 /etc/chef/encrypted_data_bag_secret"
121
+ run(host, cmd, options)
122
+ end
46
123
 
47
- ResponseSet.new.tap do |response_set|
48
- futures.each do |future|
49
- status, response = future.value
50
- response_set.add_response(response)
124
+ # Execute line(s) of Ruby code on a node using Chef's embedded Ruby
125
+ #
126
+ # @param [String] host
127
+ # the host to perform the action on
128
+ # @param [Array<String>] command_lines
129
+ # An Array of lines of the command to be executed
130
+ #
131
+ # @option options [Hash] :ssh
132
+ # * :user (String) a shell user that will login to each node and perform the bootstrap command on
133
+ # * :password (String) the password for the shell user that will perform the bootstrap
134
+ # * :keys (Array, String) an array of key(s) to authenticate the ssh user with instead of a password
135
+ # * :timeout (Float) timeout value for SSH bootstrap (5.0)
136
+ # * :sudo (Boolean) run as sudo
137
+ #
138
+ # @return [HostConnector::Response]
139
+ def ruby_script(host, command_lines, options = {})
140
+ run(host, "#{EMBEDDED_RUBY_PATH} -e \"#{command_lines.join(';')}\"", options)
141
+ end
142
+
143
+ private
144
+
145
+ def channel_exec(channel, command, host, response)
146
+ channel.exec(command) do |ch, success|
147
+ unless success
148
+ raise "Channel execution failed while executing command #{command}"
149
+ end
150
+
151
+ channel.on_data do |ch, data|
152
+ response.stdout += data
153
+ log.info "[#{host}](SSH) #{data}" if data.present? and data != "\r\n"
154
+ end
155
+
156
+ channel.on_extended_data do |ch, type, data|
157
+ response.stderr += data
158
+ log.info "[#{host}](SSH) #{data}" if data.present? and data != "\r\n"
159
+ end
160
+
161
+ channel.on_request("exit-status") do |ch, data|
162
+ response.exit_code = data.read_long
163
+ end
164
+
165
+ channel.on_request("exit-signal") do |ch, data|
166
+ response.exit_signal = data.read_string
167
+ end
51
168
  end
52
169
  end
53
- ensure
54
- workers.map(&:terminate)
55
- end
56
170
  end
57
171
  end
58
172
  end
@@ -1,56 +1,181 @@
1
+ require 'active_support/core_ext/kernel/reporting'
2
+ # Silencing warnings because not all versions of GSSAPI support all of the GSSAPI methods
3
+ # the gssapi gem attempts to attach to and these warnings are dumped to STDERR.
4
+ silence_warnings do
5
+ require 'winrm'
6
+ end
7
+
1
8
  module Ridley
2
9
  module HostConnector
3
10
  # @author Kyle Allan <kallan@riotgames.com>
4
- class WinRM
11
+ class WinRM < HostConnector::Base
5
12
  require_relative 'winrm/command_uploader'
6
- require_relative 'winrm/worker'
7
-
8
- class << self
9
- # @param [Ridley::NodeResource, Array<Ridley::NodeResource>] nodes
10
- # @param [Hash] options
11
- def start(nodes, options = {}, &block)
12
- runner = new(nodes, options)
13
- result = yield runner
14
- runner.terminate
15
-
16
- result
17
- ensure
18
- runner.terminate if runner && runner.alive?
13
+
14
+ DEFAULT_PORT = 5985
15
+ EMBEDDED_RUBY_PATH = 'C:\opscode\chef\embedded\bin\ruby'.freeze
16
+
17
+ # Execute a shell command on a node
18
+ #
19
+ # @param [String] host
20
+ # the host to perform the action on
21
+ # @param [String] command
22
+ #
23
+ # @option options [Hash] :winrm
24
+ # * :user (String) a user that will login to each node and perform the bootstrap command on
25
+ # * :password (String) the password for the user that will perform the bootstrap (required)
26
+ # * :port (Fixnum) the winrm port to connect on the node the bootstrap will be performed on (5985)
27
+ #
28
+ # @return [HostConnector::Response]
29
+ def run(host, command, options = {})
30
+ options = options.reverse_merge(winrm: Hash.new)
31
+ options[:winrm].reverse_merge!(port: DEFAULT_PORT)
32
+
33
+ command_uploaders = Array.new
34
+ user = options[:winrm][:user]
35
+ password = options[:winrm][:password]
36
+ port = options[:winrm][:port]
37
+ connection = winrm(host, port, options[:winrm].slice(:user, :password))
38
+
39
+ HostConnector::Response.new(host).tap do |response|
40
+ command_uploaders << command_uploader = CommandUploader.new(connection)
41
+ command = get_command(command, command_uploader)
42
+
43
+ begin
44
+ log.info "Running WinRM Command: '#{command}' on: '#{host}' as: '#{user}'"
45
+
46
+ output = connection.run_cmd(command) do |stdout, stderr|
47
+ if stdout
48
+ response.stdout += stdout
49
+ log.info "[#{host}](WinRM) #{stdout}"
50
+ end
51
+
52
+ if stderr
53
+ response.stderr += stderr unless stderr.nil?
54
+ log.info "[#{host}](WinRM) #{stdout}"
55
+ end
56
+ end
57
+
58
+ response.exit_code = output[:exitcode]
59
+ rescue ::WinRM::WinRMHTTPTransportError => ex
60
+ response.exit_code = -1
61
+ response.stderr = ex.message
62
+ return response
63
+ end
64
+
65
+ case response.exit_code
66
+ when 0
67
+ log.info "Successfully ran WinRM command on: '#{host}' as: '#{user}'"
68
+ else
69
+ log.info "Successfully ran WinRM command on: '#{host}' as: '#{user}', but it failed"
70
+ end
71
+ end
72
+ ensure
73
+ command_uploaders.map(&:cleanup)
74
+ end
75
+
76
+ # Returns the command if it does not break the WinRM command length
77
+ # limit. Otherwise, we return an execution of the command as a batch file.
78
+ #
79
+ # @param command [String]
80
+ #
81
+ # @return [String]
82
+ def get_command(command, command_uploader)
83
+ if command.length < CommandUploader::CHUNK_LIMIT
84
+ command
85
+ else
86
+ log.debug "Detected a command that was longer than #{CommandUploader::CHUNK_LIMIT} characters. " +
87
+ "Uploading command as a file to the host."
88
+ command_uploader.upload(command)
89
+ command_uploader.command
19
90
  end
20
91
  end
21
92
 
22
- include Celluloid
23
- include Celluloid::Logger
93
+ # Bootstrap a node
94
+ #
95
+ # @param [String] host
96
+ # the host to perform the action on
97
+ #
98
+ # @option options [Hash] :winrm
99
+ # * :user (String) a user that will login to each node and perform the bootstrap command on
100
+ # * :password (String) the password for the user that will perform the bootstrap (required)
101
+ # * :port (Fixnum) the winrm port to connect on the node the bootstrap will be performed on (5985)
102
+ #
103
+ # @return [HostConnector::Response]
104
+ def bootstrap(host, options = {})
105
+ context = BootstrapContext::Windows.new(options)
24
106
 
25
- attr_reader :nodes
26
- attr_reader :options
107
+ log.info "Bootstrapping host: #{host}"
108
+ run(host, context.boot_command, options)
109
+ end
27
110
 
28
- # @param [Ridley::NodeResource, Array<Ridley::NodeResource>] nodes
29
- # @param [Hash] options
30
- def initialize(nodes, options = {})
31
- @nodes = Array(nodes)
32
- @options = options
111
+ # Perform a chef client run on a node
112
+ #
113
+ # @param [String] host
114
+ # the host to perform the action on
115
+ #
116
+ # @option options [Hash] :winrm
117
+ # * :user (String) a user that will login to each node and perform the bootstrap command on
118
+ # * :password (String) the password for the user that will perform the bootstrap (required)
119
+ # * :port (Fixnum) the winrm port to connect on the node the bootstrap will be performed on (5985)
120
+ #
121
+ # @return [HostConnector::Response]
122
+ def chef_client(host, options = {})
123
+ run(host, "chef-client", options)
33
124
  end
34
125
 
35
- # @param [String] command
126
+ # Write your encrypted data bag secret on a node
36
127
  #
37
- # @return [Array]
38
- def run(command)
39
- workers = Array.new
40
- futures = self.nodes.collect do |node|
41
- workers << worker = Worker.new(node.public_hostname, self.options.freeze)
42
- worker.future.run(command)
43
- end
128
+ # @param [String] host
129
+ # the host to perform the action on
130
+ # @param [String] secret
131
+ # your organization's encrypted data bag secret
132
+ #
133
+ # @option options [Hash] :winrm
134
+ # * :user (String) a user that will login to each node and perform the bootstrap command on
135
+ # * :password (String) the password for the user that will perform the bootstrap (required)
136
+ # * :port (Fixnum) the winrm port to connect on the node the bootstrap will be performed on (5985)
137
+ #
138
+ # @return [HostConnector::Response]
139
+ def put_secret(host, secret, options = {})
140
+ command = "echo #{secret} > C:\\chef\\encrypted_data_bag_secret"
141
+ run(host, command, options)
142
+ end
44
143
 
45
- Ridley::HostConnector::ResponseSet.new.tap do |response_set|
46
- futures.each do |future|
47
- status, response = future.value
48
- response_set.add_response(response)
49
- end
50
- end
51
- ensure
52
- workers.map(&:terminate)
144
+ # Execute line(s) of Ruby code on a node using Chef's embedded Ruby
145
+ #
146
+ # @param [String] host
147
+ # the host to perform the action on
148
+ # @param [Array<String>] command_lines
149
+ # An Array of lines of the command to be executed
150
+ #
151
+ # @option options [Hash] :winrm
152
+ # * :user (String) a user that will login to each node and perform the bootstrap command on
153
+ # * :password (String) the password for the user that will perform the bootstrap (required)
154
+ # * :port (Fixnum) the winrm port to connect on the node the bootstrap will be performed on (5985)
155
+ #
156
+ # @return [HostConnector::Response]
157
+ def ruby_script(host, command_lines, options = {})
158
+ command = "#{EMBEDDED_RUBY_PATH} -e \"#{command_lines.join(';')}\""
159
+ run(host, command, options)
53
160
  end
161
+
162
+ private
163
+
164
+ # @param [String] host
165
+ # @param [Integer] port
166
+ #
167
+ # @option options [String] :user
168
+ # @option options [String] :password
169
+ #
170
+ # @return [WinRM::WinRMWebService]
171
+ def winrm(host, port, options = {})
172
+ winrm_opts = { disable_sspi: true, basic_auth_only: true }
173
+ winrm_opts[:user] = options[:user]
174
+ winrm_opts[:pass] = options[:password]
175
+ client = ::WinRM::WinRMWebService.new("http://#{host}:#{port}/wsman", :plaintext, winrm_opts)
176
+ client.set_timeout(6000)
177
+ client
178
+ end
54
179
  end
55
180
  end
56
181
  end