ridley 1.0.0.rc1 → 1.0.0.rc2
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/README.md +2 -2
- data/lib/ridley.rb +24 -17
- data/lib/ridley/chef/cookbook/syntax_check.rb +18 -14
- data/lib/ridley/command_context.rb +76 -0
- data/lib/ridley/command_context/unix_uninstall.rb +42 -0
- data/lib/ridley/command_context/windows_uninstall.rb +35 -0
- data/lib/ridley/host_commander.rb +25 -0
- data/lib/ridley/host_connector.rb +11 -0
- data/lib/ridley/host_connector/ssh.rb +25 -0
- data/lib/ridley/host_connector/winrm.rb +41 -8
- data/lib/ridley/mixin/shell_out.rb +84 -18
- data/lib/ridley/resources/node_resource.rb +26 -0
- data/lib/ridley/version.rb +1 -1
- data/ridley.gemspec +0 -1
- data/scripts/unix_uninstall_omnibus.erb +31 -0
- data/scripts/windows_uninstall_omnibus.erb +10 -0
- data/spec/support/actor_mocking.rb +2 -2
- data/spec/unit/ridley/host_connector_spec.rb +6 -0
- data/spec/unit/ridley/mixin/shell_out_spec.rb +38 -0
- metadata +9 -20
- data/spec/acceptance/bootstrapping_spec.rb +0 -29
data/README.md
CHANGED
@@ -184,7 +184,7 @@ _With the `#regenerate_key` function on an instance of a Client Object_
|
|
184
184
|
A data bag is managed exactly the same as any other Chef resource
|
185
185
|
|
186
186
|
ridley = Ridley.new(...)
|
187
|
-
ridley.data_bag.create("ridley-test")
|
187
|
+
ridley.data_bag.create(name: "ridley-test")
|
188
188
|
|
189
189
|
You can create, delete, update, or retrieve a data bag exactly how you would expect if you read through the
|
190
190
|
Manipulating Chef Resources portion of this document.
|
@@ -194,7 +194,7 @@ Unlike a role, node, client, or environment, a data bag is a container for other
|
|
194
194
|
### Creating a Data Bag Item
|
195
195
|
|
196
196
|
ridley = Ridley.new(...)
|
197
|
-
data_bag = ridley.data_bag.create("ridley-test")
|
197
|
+
data_bag = ridley.data_bag.create(name: "ridley-test")
|
198
198
|
|
199
199
|
data_bag.item.create(id: "appconfig", host: "reset.local", user: "jamie") #=>
|
200
200
|
#<Ridley::DataBagItemObject: chef_id:appconfig, host="reset.local", user="jamie">
|
data/lib/ridley.rb
CHANGED
@@ -15,23 +15,6 @@ JSON.create_id = nil
|
|
15
15
|
module Ridley
|
16
16
|
CHEF_VERSION = '11.4.0'.freeze
|
17
17
|
|
18
|
-
require_relative 'ridley/mixin'
|
19
|
-
require_relative 'ridley/logging'
|
20
|
-
require_relative 'ridley/bootstrap_context'
|
21
|
-
require_relative 'ridley/chef_object'
|
22
|
-
require_relative 'ridley/chef_objects'
|
23
|
-
require_relative 'ridley/client'
|
24
|
-
require_relative 'ridley/connection'
|
25
|
-
require_relative 'ridley/chef'
|
26
|
-
require_relative 'ridley/host_commander'
|
27
|
-
require_relative 'ridley/host_connector'
|
28
|
-
require_relative 'ridley/middleware'
|
29
|
-
require_relative 'ridley/resource'
|
30
|
-
require_relative 'ridley/resources'
|
31
|
-
require_relative 'ridley/sandbox_uploader'
|
32
|
-
require_relative 'ridley/version'
|
33
|
-
require_relative 'ridley/errors'
|
34
|
-
|
35
18
|
class << self
|
36
19
|
extend Forwardable
|
37
20
|
|
@@ -41,6 +24,7 @@ module Ridley
|
|
41
24
|
def_delegator "Ridley::Logging", :logger=
|
42
25
|
def_delegator "Ridley::Logging", :set_logger
|
43
26
|
|
27
|
+
# @return [Ridley::Client]
|
44
28
|
def new(*args)
|
45
29
|
Client.new(*args)
|
46
30
|
end
|
@@ -53,7 +37,30 @@ module Ridley
|
|
53
37
|
def root
|
54
38
|
@root ||= Pathname.new(File.expand_path('../', File.dirname(__FILE__)))
|
55
39
|
end
|
40
|
+
|
41
|
+
# @return [Pathname]
|
42
|
+
def scripts
|
43
|
+
root.join('scripts')
|
44
|
+
end
|
56
45
|
end
|
46
|
+
|
47
|
+
require_relative 'ridley/mixin'
|
48
|
+
require_relative 'ridley/logging'
|
49
|
+
require_relative 'ridley/bootstrap_context'
|
50
|
+
require_relative 'ridley/command_context'
|
51
|
+
require_relative 'ridley/chef_object'
|
52
|
+
require_relative 'ridley/chef_objects'
|
53
|
+
require_relative 'ridley/client'
|
54
|
+
require_relative 'ridley/connection'
|
55
|
+
require_relative 'ridley/chef'
|
56
|
+
require_relative 'ridley/host_commander'
|
57
|
+
require_relative 'ridley/host_connector'
|
58
|
+
require_relative 'ridley/middleware'
|
59
|
+
require_relative 'ridley/resource'
|
60
|
+
require_relative 'ridley/resources'
|
61
|
+
require_relative 'ridley/sandbox_uploader'
|
62
|
+
require_relative 'ridley/version'
|
63
|
+
require_relative 'ridley/errors'
|
57
64
|
end
|
58
65
|
|
59
66
|
Celluloid.logger = Ridley.logger
|
@@ -127,25 +127,29 @@ module Ridley::Chef
|
|
127
127
|
end
|
128
128
|
|
129
129
|
def validate_template(erb_file)
|
130
|
-
result =
|
131
|
-
|
130
|
+
result = shell_out("erubis -x #{erb_file.shellescape} | ruby -c")
|
131
|
+
|
132
|
+
if result.error?
|
133
|
+
file_relative_path = erb_file[/^#{Regexp.escape(cookbook_path+File::Separator)}(.*)/, 1]
|
134
|
+
log.error { "Erb template #{file_relative_path} has a syntax error:" }
|
135
|
+
result.stderr.each_line { |l| Ridley.log.fatal(l.chomp) }
|
136
|
+
return false
|
137
|
+
end
|
138
|
+
|
132
139
|
true
|
133
|
-
rescue Mixlib::ShellOut::ShellCommandFailed
|
134
|
-
file_relative_path = erb_file[/^#{Regexp.escape(cookbook_path+File::Separator)}(.*)/, 1]
|
135
|
-
log.error { "Erb template #{file_relative_path} has a syntax error:" }
|
136
|
-
result.stderr.each_line { |l| Ridley.log.fatal(l.chomp) }
|
137
|
-
false
|
138
140
|
end
|
139
141
|
|
140
142
|
def validate_ruby_file(ruby_file)
|
141
|
-
result =
|
142
|
-
|
143
|
+
result = shell_out("ruby -c #{ruby_file.shellescape}")
|
144
|
+
|
145
|
+
if result.error?
|
146
|
+
file_relative_path = ruby_file[/^#{Regexp.escape(cookbook_path+File::Separator)}(.*)/, 1]
|
147
|
+
log.error { "Cookbook file #{file_relative_path} has a ruby syntax error:" }
|
148
|
+
result.stderr.each_line { |l| Ridley.log.error(l.chomp) }
|
149
|
+
return false
|
150
|
+
end
|
151
|
+
|
143
152
|
true
|
144
|
-
rescue Mixlib::ShellOut::ShellCommandFailed
|
145
|
-
file_relative_path = ruby_file[/^#{Regexp.escape(cookbook_path+File::Separator)}(.*)/, 1]
|
146
|
-
log.error { "Cookbook file #{file_relative_path} has a ruby syntax error:" }
|
147
|
-
result.stderr.each_line { |l| Ridley.log.error(l.chomp) }
|
148
|
-
false
|
149
153
|
end
|
150
154
|
end
|
151
155
|
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'erubis'
|
2
|
+
|
3
|
+
module Ridley
|
4
|
+
module CommandContext
|
5
|
+
# A base class to provide common functionality between OS specific command contexts. A
|
6
|
+
# command context takes an options hash and binds it against a template file. You can then
|
7
|
+
# retrieve the command to be run on a node by calling {CommandContext::Base#command}.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# my_context = MyCommandContext.new(message: "hello, world!")
|
11
|
+
# my_context.command #=> "echo 'hello, world!'"
|
12
|
+
class Base
|
13
|
+
class << self
|
14
|
+
# Build a command context and immediately run it's command
|
15
|
+
#
|
16
|
+
# @param [Hash] options
|
17
|
+
# an options hash to pass to the new CommandContext
|
18
|
+
def command(options = {})
|
19
|
+
new(options).command
|
20
|
+
end
|
21
|
+
|
22
|
+
# Set or get the path to the template file for the inheriting class
|
23
|
+
#
|
24
|
+
# @param [String] filename
|
25
|
+
# the filename (without extension) of the template file to use to bind
|
26
|
+
# the inheriting command context class to
|
27
|
+
#
|
28
|
+
# @return [Pathname]
|
29
|
+
def template_file(filename = nil)
|
30
|
+
return @template_file if filename.nil?
|
31
|
+
@template_file = Ridley.scripts.join("#{filename}.erb")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# @param [Hash] options
|
36
|
+
def initialize(options = {}); end
|
37
|
+
|
38
|
+
# @return [String]
|
39
|
+
def command
|
40
|
+
template.evaluate(self)
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
# @return [Erubis::Eruby]
|
46
|
+
def template
|
47
|
+
@template ||= Erubis::Eruby.new(IO.read(self.class.template_file).chomp)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# A command context for Unix based OSes
|
52
|
+
class Unix < Base
|
53
|
+
# @return [Boolean]
|
54
|
+
attr_reader :sudo
|
55
|
+
|
56
|
+
# @option options [Boolean] :sudo (true)
|
57
|
+
# bootstrap with sudo (default: true)
|
58
|
+
def initialize(options = {})
|
59
|
+
options = options.reverse_merge(sudo: true)
|
60
|
+
@sudo = options[:sudo]
|
61
|
+
end
|
62
|
+
|
63
|
+
# @return [String]
|
64
|
+
def command
|
65
|
+
sudo ? "sudo #{super}" : super
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# A command context for Windows based OSes
|
70
|
+
class Windows < Base; end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
Dir["#{File.dirname(__FILE__)}/command_context/*.rb"].sort.each do |path|
|
75
|
+
require_relative "command_context/#{File.basename(path, '.rb')}"
|
76
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Ridley
|
2
|
+
module CommandContext
|
3
|
+
# Context class for generating an uninstall command for Unix based OSes
|
4
|
+
class UnixUninstall < CommandContext::Unix
|
5
|
+
template_file 'unix_uninstall_omnibus'
|
6
|
+
|
7
|
+
# @return [Boolean]
|
8
|
+
attr_reader :skip_chef
|
9
|
+
|
10
|
+
# @option options [Boolena] :skip_chef (false)
|
11
|
+
# skip removal of the Chef package and the contents of the installation
|
12
|
+
# directory. Setting this to true will only remove any data and configurations
|
13
|
+
# generated by running Chef client.
|
14
|
+
def initialize(options = {})
|
15
|
+
super(options)
|
16
|
+
options = options.reverse_merge(skip_chef: false)
|
17
|
+
@skip_chef = options[:skip_chef]
|
18
|
+
end
|
19
|
+
|
20
|
+
# The path to the Chef configuration directory on the target host
|
21
|
+
#
|
22
|
+
# @return [String]
|
23
|
+
def config_directory
|
24
|
+
"/etc/chef"
|
25
|
+
end
|
26
|
+
|
27
|
+
# The path to the Chef data directory on the target host
|
28
|
+
#
|
29
|
+
# @return [String]
|
30
|
+
def data_directory
|
31
|
+
"/var/chef"
|
32
|
+
end
|
33
|
+
|
34
|
+
# The path to the Omnibus Chef installation on the target host
|
35
|
+
#
|
36
|
+
# @return [String]
|
37
|
+
def install_directory
|
38
|
+
"/opt/chef"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Ridley
|
2
|
+
module CommandContext
|
3
|
+
# Context class for generating an uninstall command for Unix based OSes
|
4
|
+
class WindowsUninstall < CommandContext::Windows
|
5
|
+
template_file 'windows_uninstall_omnibus'
|
6
|
+
|
7
|
+
# @return [Boolean]
|
8
|
+
attr_reader :skip_chef
|
9
|
+
|
10
|
+
# @option options [Boolena] :skip_chef (false)
|
11
|
+
# skip removal of the Chef package and the contents of the installation
|
12
|
+
# directory. Setting this to true will only remove any data and configurations
|
13
|
+
# generated by running Chef client.
|
14
|
+
def initialize(options = {})
|
15
|
+
super(options)
|
16
|
+
options = options.reverse_merge(skip_chef: false)
|
17
|
+
@skip_chef = options[:skip_chef]
|
18
|
+
end
|
19
|
+
|
20
|
+
# The path to the Chef configuration directory on the target host
|
21
|
+
#
|
22
|
+
# @return [String]
|
23
|
+
def config_directory
|
24
|
+
"C:\\chef"
|
25
|
+
end
|
26
|
+
|
27
|
+
# The path to the Omnibus Chef installation on the target host
|
28
|
+
#
|
29
|
+
# @return [String]
|
30
|
+
def install_directory
|
31
|
+
"C:\\opscode\\chef"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -153,6 +153,31 @@ module Ridley
|
|
153
153
|
execute(__method__, host, command_lines, options)
|
154
154
|
end
|
155
155
|
|
156
|
+
# Uninstall Chef from a node
|
157
|
+
#
|
158
|
+
# @param [String] host
|
159
|
+
# the host to perform the action on
|
160
|
+
#
|
161
|
+
# @option options [Boolena] :skip_chef (false)
|
162
|
+
# skip removal of the Chef package and the contents of the installation
|
163
|
+
# directory. Setting this to true will only remove any data and configurations
|
164
|
+
# generated by running Chef client.
|
165
|
+
# @option options [Hash] :ssh
|
166
|
+
# * :user (String) a shell user that will login to each node and perform the bootstrap command on
|
167
|
+
# * :password (String) the password for the shell user that will perform the bootstrap
|
168
|
+
# * :keys (Array, String) an array of key(s) to authenticate the ssh user with instead of a password
|
169
|
+
# * :timeout (Float) timeout value for SSH bootstrap (5.0)
|
170
|
+
# * :sudo (Boolean) run as sudo (true)
|
171
|
+
# @option options [Hash] :winrm
|
172
|
+
# * :user (String) a user that will login to each node and perform the bootstrap command on
|
173
|
+
# * :password (String) the password for the user that will perform the bootstrap (required)
|
174
|
+
# * :port (Fixnum) the winrm port to connect on the node the bootstrap will be performed on (5985)
|
175
|
+
#
|
176
|
+
# @return [HostConnector::Response]
|
177
|
+
def uninstall_chef(host, options = {})
|
178
|
+
execute(__method__, host, options)
|
179
|
+
end
|
180
|
+
|
156
181
|
private
|
157
182
|
|
158
183
|
def execute(method, host, *args)
|
@@ -64,6 +64,17 @@ module Ridley
|
|
64
64
|
def ruby_script(host, command_lines, options = {})
|
65
65
|
raise RuntimeError, "abstract function: must be implemented on includer"
|
66
66
|
end
|
67
|
+
|
68
|
+
# Uninstall Chef from a node
|
69
|
+
#
|
70
|
+
# @param [String] host
|
71
|
+
# the host to perform the action on
|
72
|
+
# @param [Hash] options
|
73
|
+
#
|
74
|
+
# @return [HostConnector::Response]
|
75
|
+
def uninstall_chef(host, options = {})
|
76
|
+
raise RuntimeError, "abstract function: must be implemented on includer"
|
77
|
+
end
|
67
78
|
end
|
68
79
|
|
69
80
|
require_relative 'host_connector/response'
|
@@ -140,6 +140,31 @@ module Ridley
|
|
140
140
|
run(host, "#{EMBEDDED_RUBY_PATH} -e \"#{command_lines.join(';')}\"", options)
|
141
141
|
end
|
142
142
|
|
143
|
+
# Uninstall Chef from a node
|
144
|
+
#
|
145
|
+
# @param [String] host
|
146
|
+
# the host to perform the action on
|
147
|
+
#
|
148
|
+
# @option options [Boolena] :skip_chef (false)
|
149
|
+
# skip removal of the Chef package and the contents of the installation
|
150
|
+
# directory. Setting this to true will only remove any data and configurations
|
151
|
+
# generated by running Chef client.
|
152
|
+
# @option options [Hash] :ssh
|
153
|
+
# * :user (String) a shell user that will login to each node and perform the bootstrap command on
|
154
|
+
# * :password (String) the password for the shell user that will perform the bootstrap
|
155
|
+
# * :keys (Array, String) an array of key(s) to authenticate the ssh user with instead of a password
|
156
|
+
# * :timeout (Float) timeout value for SSH bootstrap (5.0)
|
157
|
+
# * :sudo (Boolean) run as sudo (true)
|
158
|
+
#
|
159
|
+
# @return [HostConnector::Response]
|
160
|
+
def uninstall_chef(host, options = {})
|
161
|
+
options = options.reverse_merge(ssh: Hash.new)
|
162
|
+
options[:ssh].reverse_merge!(sudo: true, timeout: 5.0)
|
163
|
+
|
164
|
+
log.info "Uninstalling Chef from host: #{host}"
|
165
|
+
run(host, CommandContext::UnixUninstall.command(options), options)
|
166
|
+
end
|
167
|
+
|
143
168
|
private
|
144
169
|
|
145
170
|
def channel_exec(channel, command, host, response)
|
@@ -11,8 +11,12 @@ module Ridley
|
|
11
11
|
class WinRM < HostConnector::Base
|
12
12
|
require_relative 'winrm/command_uploader'
|
13
13
|
|
14
|
-
DEFAULT_PORT
|
15
|
-
EMBEDDED_RUBY_PATH
|
14
|
+
DEFAULT_PORT = 5985
|
15
|
+
EMBEDDED_RUBY_PATH = 'C:\opscode\chef\embedded\bin\ruby'.freeze
|
16
|
+
SESSION_TYPE_COMMAND_METHODS = {
|
17
|
+
powershell: :run_powershell_script,
|
18
|
+
cmd: :run_cmd
|
19
|
+
}.freeze
|
16
20
|
|
17
21
|
# Execute a shell command on a node
|
18
22
|
#
|
@@ -20,6 +24,9 @@ module Ridley
|
|
20
24
|
# the host to perform the action on
|
21
25
|
# @param [String] command
|
22
26
|
#
|
27
|
+
# @option options [Symbol] :session_type (:cmd)
|
28
|
+
# * :powershell - run the given command in a powershell session
|
29
|
+
# * :cmd - run the given command in a cmd session
|
23
30
|
# @option options [Hash] :winrm
|
24
31
|
# * :user (String) a user that will login to each node and perform the bootstrap command on
|
25
32
|
# * :password (String) the password for the user that will perform the bootstrap (required)
|
@@ -27,7 +34,7 @@ module Ridley
|
|
27
34
|
#
|
28
35
|
# @return [HostConnector::Response]
|
29
36
|
def run(host, command, options = {})
|
30
|
-
options = options.reverse_merge(winrm: Hash.new)
|
37
|
+
options = options.reverse_merge(winrm: Hash.new, session_type: :cmd)
|
31
38
|
options[:winrm].reverse_merge!(port: DEFAULT_PORT)
|
32
39
|
|
33
40
|
command_uploaders = Array.new
|
@@ -36,6 +43,11 @@ module Ridley
|
|
36
43
|
port = options[:winrm][:port]
|
37
44
|
connection = winrm(host, port, options[:winrm].slice(:user, :password))
|
38
45
|
|
46
|
+
unless command_method = SESSION_TYPE_COMMAND_METHODS[options[:session_type]]
|
47
|
+
raise RuntimeError, "unknown session type: #{options[:session_type]}. Known session types " +
|
48
|
+
"are: #{SESSION_TYPE_COMMAND_METHODS.keys}"
|
49
|
+
end
|
50
|
+
|
39
51
|
HostConnector::Response.new(host).tap do |response|
|
40
52
|
command_uploaders << command_uploader = CommandUploader.new(connection)
|
41
53
|
command = get_command(command, command_uploader)
|
@@ -43,15 +55,15 @@ module Ridley
|
|
43
55
|
begin
|
44
56
|
log.info "Running WinRM Command: '#{command}' on: '#{host}' as: '#{user}'"
|
45
57
|
|
46
|
-
output = connection.
|
47
|
-
if stdout
|
58
|
+
output = connection.send(command_method, command) do |stdout, stderr|
|
59
|
+
if stdout && stdout.present?
|
48
60
|
response.stdout += stdout
|
49
61
|
log.info "[#{host}](WinRM) #{stdout}"
|
50
62
|
end
|
51
63
|
|
52
|
-
if stderr
|
53
|
-
response.stderr += stderr
|
54
|
-
log.info "[#{host}](WinRM) #{
|
64
|
+
if stderr && stderr.present?
|
65
|
+
response.stderr += stderr
|
66
|
+
log.info "[#{host}](WinRM) #{stderr}"
|
55
67
|
end
|
56
68
|
end
|
57
69
|
|
@@ -159,6 +171,27 @@ module Ridley
|
|
159
171
|
run(host, command, options)
|
160
172
|
end
|
161
173
|
|
174
|
+
# Uninstall Chef from a node
|
175
|
+
#
|
176
|
+
# @param [String] host
|
177
|
+
# the host to perform the action on
|
178
|
+
#
|
179
|
+
# @option options [Boolena] :skip_chef (false)
|
180
|
+
# skip removal of the Chef package and the contents of the installation
|
181
|
+
# directory. Setting this to true will only remove any data and configurations
|
182
|
+
# generated by running Chef client.
|
183
|
+
# @option options [Hash] :winrm
|
184
|
+
# * :user (String) a user that will login to each node and perform the bootstrap command on
|
185
|
+
# * :password (String) the password for the user that will perform the bootstrap (required)
|
186
|
+
# * :port (Fixnum) the winrm port to connect on the node the bootstrap will be performed on (5985)
|
187
|
+
#
|
188
|
+
# @return [HostConnector::Response]
|
189
|
+
def uninstall_chef(host, options = {})
|
190
|
+
options[:session_type] = :powershell
|
191
|
+
log.info "Uninstalling Chef from host: #{host}"
|
192
|
+
run(host, CommandContext::WindowsUninstall.command(options), options)
|
193
|
+
end
|
194
|
+
|
162
195
|
private
|
163
196
|
|
164
197
|
# @param [String] host
|
@@ -1,23 +1,89 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
1
|
+
module Ridley
|
2
|
+
module Mixin
|
3
|
+
# A Ruby platform agnostic way of executing shell commands on the local system
|
4
|
+
module ShellOut
|
5
|
+
class Response
|
6
|
+
extend Forwardable
|
7
|
+
|
8
|
+
# @return [String]
|
9
|
+
attr_reader :stdout
|
10
|
+
# @return [String]
|
11
|
+
attr_reader :stderr
|
12
|
+
|
13
|
+
def_delegator :process_status, :exitstatus
|
14
|
+
def_delegator :process_status, :pid
|
15
|
+
def_delegator :process_status, :success?
|
16
|
+
def_delegator :process_status, :exited?
|
17
|
+
def_delegator :process_status, :stopped?
|
18
|
+
|
19
|
+
# @param [Process::Status] process_status
|
20
|
+
# @param [String] stdout
|
21
|
+
# @param [String] stderr
|
22
|
+
def initialize(process_status, stdout, stderr)
|
23
|
+
@process_status = process_status
|
24
|
+
@stdout = stdout
|
25
|
+
@stderr = stderr
|
26
|
+
end
|
27
|
+
|
28
|
+
def error?
|
29
|
+
!success?
|
30
|
+
end
|
31
|
+
alias_method :failure?, :error?
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
# @return [Process::Status]
|
36
|
+
attr_reader :process_status
|
11
37
|
end
|
12
|
-
cmd.run_command
|
13
|
-
cmd
|
14
|
-
end
|
15
38
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
39
|
+
include Chozo::RubyEngine
|
40
|
+
extend self
|
41
|
+
|
42
|
+
# Executes the given shell command on the local system
|
43
|
+
#
|
44
|
+
# @param [String] command
|
45
|
+
# The command to execute
|
46
|
+
#
|
47
|
+
# @return [ShellOut::Response]
|
48
|
+
def shell_out(command)
|
49
|
+
process_status, out, err = jruby? ? jruby_out(command) : mri_out(command)
|
50
|
+
Response.new(process_status, out, err)
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
# @param [String] command
|
56
|
+
# The command to execute
|
57
|
+
def mri_out(command)
|
58
|
+
out, err = Tempfile.new('ridley.shell_out.stdout'), Tempfile.new('ridley.shell_out.stderr')
|
59
|
+
|
60
|
+
begin
|
61
|
+
pid = Process.spawn(command, out: out.to_i, err: err.to_i)
|
62
|
+
Process.waitpid(pid)
|
63
|
+
rescue Errno::ENOENT
|
64
|
+
out.write("")
|
65
|
+
err.write("command not found: #{command}")
|
66
|
+
end
|
67
|
+
|
68
|
+
out.close
|
69
|
+
err.close
|
70
|
+
|
71
|
+
[ $?, File.read(out), File.read(err) ]
|
72
|
+
end
|
73
|
+
|
74
|
+
# @param [String] command
|
75
|
+
# The command to execute
|
76
|
+
def jruby_out(command)
|
77
|
+
out, err = StringIO.new, StringIO.new
|
78
|
+
$stdout, $stderr = out, err
|
79
|
+
system(command)
|
80
|
+
|
81
|
+
out.rewind
|
82
|
+
err.rewind
|
83
|
+
[ $?, out.read, err.read ]
|
84
|
+
ensure
|
85
|
+
$stdout, $stderr = STDOUT, STDERR
|
86
|
+
end
|
21
87
|
end
|
22
88
|
end
|
23
89
|
end
|
@@ -160,6 +160,32 @@ module Ridley
|
|
160
160
|
update(node.merge_data(options))
|
161
161
|
end
|
162
162
|
|
163
|
+
# Uninstall Chef from a node
|
164
|
+
#
|
165
|
+
# @param [String] host
|
166
|
+
# the host to perform the action on
|
167
|
+
#
|
168
|
+
# @option options [Boolena] :skip_chef (false)
|
169
|
+
# skip removal of the Chef package and the contents of the installation
|
170
|
+
# directory. Setting this to true will only remove any data and configurations
|
171
|
+
# generated by running Chef client.
|
172
|
+
# @option options [Hash] :ssh
|
173
|
+
# * :user (String) a shell user that will login to each node and perform the bootstrap command on
|
174
|
+
# * :password (String) the password for the shell user that will perform the bootstrap
|
175
|
+
# * :keys (Array, String) an array of key(s) to authenticate the ssh user with instead of a password
|
176
|
+
# * :timeout (Float) timeout value for SSH bootstrap (5.0)
|
177
|
+
# * :sudo (Boolean) run as sudo (true)
|
178
|
+
# @option options [Hash] :winrm
|
179
|
+
# * :user (String) a user that will login to each node and perform the bootstrap command on
|
180
|
+
# * :password (String) the password for the user that will perform the bootstrap (required)
|
181
|
+
# * :port (Fixnum) the winrm port to connect on the node the bootstrap will be performed on (5985)
|
182
|
+
#
|
183
|
+
# @return [HostConnector::Response]
|
184
|
+
def uninstall_chef(host, options = {})
|
185
|
+
options = options.reverse_merge(ssh: ssh, winrm: winrm)
|
186
|
+
host_commander.uninstall_chef(host, options)
|
187
|
+
end
|
188
|
+
|
163
189
|
private
|
164
190
|
|
165
191
|
# @return [Ridley::HostCommander]
|
data/lib/ridley/version.rb
CHANGED
data/ridley.gemspec
CHANGED
@@ -23,7 +23,6 @@ Gem::Specification.new do |s|
|
|
23
23
|
s.add_runtime_dependency 'erubis'
|
24
24
|
s.add_runtime_dependency 'faraday', '>= 0.8.4'
|
25
25
|
s.add_runtime_dependency 'hashie', '>= 2.0.2'
|
26
|
-
s.add_runtime_dependency 'mixlib-shellout', '>= 1.1.0'
|
27
26
|
s.add_runtime_dependency 'mixlib-authentication', '>= 1.3.0'
|
28
27
|
s.add_runtime_dependency 'net-http-persistent', '>= 2.8'
|
29
28
|
s.add_runtime_dependency 'net-ssh'
|
@@ -0,0 +1,31 @@
|
|
1
|
+
bash -c '
|
2
|
+
if [ -f "/etc/lsb-release" ]; then
|
3
|
+
platform=$(grep DISTRIB_ID /etc/lsb-release | cut -d "=" -f 2 | tr "[A-Z]" "[a-z]")
|
4
|
+
elif [ -f "/etc/debian_version" ]; then
|
5
|
+
platform="debian"
|
6
|
+
elif [ -f "/etc/redhat-release" ]; then
|
7
|
+
platform="el"
|
8
|
+
elif [ -f "/etc/system-release" ]; then
|
9
|
+
platform=$(sed "s/^\(.\+\) release.\+/\1/" /etc/system-release | tr "[A-Z]" "[a-z]")
|
10
|
+
if [ "$platform" = "amazon linux ami" ]; then
|
11
|
+
platform="el"
|
12
|
+
fi
|
13
|
+
elif [ -f "/etc/SuSE-release" ]; then
|
14
|
+
platform="el"
|
15
|
+
fi
|
16
|
+
|
17
|
+
<% unless skip_chef -%>
|
18
|
+
echo "Un-Installing installed Chef package"
|
19
|
+
case "$platform" in
|
20
|
+
"el") yum remove chef -y ;;
|
21
|
+
"debian") apt-get purge chef -y ;;
|
22
|
+
esac
|
23
|
+
<% end -%>
|
24
|
+
|
25
|
+
rm -Rdf <%= config_directory %>
|
26
|
+
rm -Rdf <%= data_directory %>
|
27
|
+
|
28
|
+
<% unless skip_chef -%>
|
29
|
+
rm -Rdf <%= install_directory %>
|
30
|
+
<% end -%>
|
31
|
+
'
|
@@ -0,0 +1,10 @@
|
|
1
|
+
$productName = "Chef"
|
2
|
+
$installDirectory = "<%= install_directory %>"
|
3
|
+
$configDirectory = "<%= config_directory %>"
|
4
|
+
|
5
|
+
<% unless skip_chef -%>
|
6
|
+
$app = Get-WmiObject -Class Win32_Product | Where-Object { $_.Name -match $productName }
|
7
|
+
If ($app) { $app.Uninstall() }
|
8
|
+
If (Test-Path $installDirectory) { Remove-Item -Recurse -Force $installDirectory }
|
9
|
+
<% end -%>
|
10
|
+
If (Test-Path $configDirectory) { Remove-Item -Recurse -Force $configDirectory }
|
@@ -2,8 +2,8 @@ RSpec.configuration.before(:each) do
|
|
2
2
|
class Celluloid::ActorProxy
|
3
3
|
unless @rspec_compatible
|
4
4
|
@rspec_compatible = true
|
5
|
-
undef_method :should_receive
|
6
|
-
undef_method :stub
|
5
|
+
undef_method :should_receive if method_defined?(:should_receive)
|
6
|
+
undef_method :stub if method_defined?(:stub)
|
7
7
|
end
|
8
8
|
end
|
9
9
|
end
|
@@ -41,4 +41,10 @@ describe Ridley::HostConnector::Base do
|
|
41
41
|
expect { subject.ruby_script(host, command_lines, options) }.to raise_error(RuntimeError)
|
42
42
|
end
|
43
43
|
end
|
44
|
+
|
45
|
+
describe "#uninstall_chef" do
|
46
|
+
it "raises a RuntimeError" do
|
47
|
+
expect { subject.uninstall_chef(host, options) }.to raise_error(RuntimeError)
|
48
|
+
end
|
49
|
+
end
|
44
50
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Ridley::Mixin::ShellOut do
|
4
|
+
describe "shell_out" do
|
5
|
+
let(:command) { "ls" }
|
6
|
+
|
7
|
+
subject(:result) { described_class.shell_out(command) }
|
8
|
+
|
9
|
+
it "returns a ShellOut::Response" do
|
10
|
+
expect(result).to be_a(described_class::Response)
|
11
|
+
end
|
12
|
+
|
13
|
+
its(:stdout) { should be_a(String) }
|
14
|
+
its(:stderr) { should be_a(String) }
|
15
|
+
its(:exitstatus) { should be_a(Fixnum) }
|
16
|
+
its(:pid) { should be_a(Fixnum) }
|
17
|
+
its(:success?) { should be_true }
|
18
|
+
its(:error?) { should be_false }
|
19
|
+
|
20
|
+
context "when on MRI" do
|
21
|
+
before { described_class.stub(jruby?: false) }
|
22
|
+
|
23
|
+
it "delegates to #mri_out" do
|
24
|
+
described_class.should_receive(:mri_out).with(command)
|
25
|
+
result
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context "when on JRuby" do
|
30
|
+
before { described_class.stub(jruby?: true) }
|
31
|
+
|
32
|
+
it "delegates to #jruby_out" do
|
33
|
+
described_class.should_receive(:jruby_out).with(command)
|
34
|
+
result
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ridley
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.0.
|
4
|
+
version: 1.0.0.rc2
|
5
5
|
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-05
|
12
|
+
date: 2013-06-05 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: addressable
|
@@ -107,22 +107,6 @@ dependencies:
|
|
107
107
|
- - ! '>='
|
108
108
|
- !ruby/object:Gem::Version
|
109
109
|
version: 2.0.2
|
110
|
-
- !ruby/object:Gem::Dependency
|
111
|
-
name: mixlib-shellout
|
112
|
-
requirement: !ruby/object:Gem::Requirement
|
113
|
-
none: false
|
114
|
-
requirements:
|
115
|
-
- - ! '>='
|
116
|
-
- !ruby/object:Gem::Version
|
117
|
-
version: 1.1.0
|
118
|
-
type: :runtime
|
119
|
-
prerelease: false
|
120
|
-
version_requirements: !ruby/object:Gem::Requirement
|
121
|
-
none: false
|
122
|
-
requirements:
|
123
|
-
- - ! '>='
|
124
|
-
- !ruby/object:Gem::Version
|
125
|
-
version: 1.1.0
|
126
110
|
- !ruby/object:Gem::Dependency
|
127
111
|
name: mixlib-authentication
|
128
112
|
requirement: !ruby/object:Gem::Requirement
|
@@ -257,6 +241,9 @@ files:
|
|
257
241
|
- lib/ridley/chef_objects/role_object.rb
|
258
242
|
- lib/ridley/chef_objects/sandbox_object.rb
|
259
243
|
- lib/ridley/client.rb
|
244
|
+
- lib/ridley/command_context.rb
|
245
|
+
- lib/ridley/command_context/unix_uninstall.rb
|
246
|
+
- lib/ridley/command_context/windows_uninstall.rb
|
260
247
|
- lib/ridley/connection.rb
|
261
248
|
- lib/ridley/errors.rb
|
262
249
|
- lib/ridley/host_commander.rb
|
@@ -290,7 +277,8 @@ files:
|
|
290
277
|
- lib/ridley/sandbox_uploader.rb
|
291
278
|
- lib/ridley/version.rb
|
292
279
|
- ridley.gemspec
|
293
|
-
-
|
280
|
+
- scripts/unix_uninstall_omnibus.erb
|
281
|
+
- scripts/windows_uninstall_omnibus.erb
|
294
282
|
- spec/acceptance/client_resource_spec.rb
|
295
283
|
- spec/acceptance/cookbook_resource_spec.rb
|
296
284
|
- spec/acceptance/data_bag_item_resource_spec.rb
|
@@ -350,6 +338,7 @@ files:
|
|
350
338
|
- spec/unit/ridley/middleware/chef_response_spec.rb
|
351
339
|
- spec/unit/ridley/middleware/gzip_spec.rb
|
352
340
|
- spec/unit/ridley/middleware/parse_json_spec.rb
|
341
|
+
- spec/unit/ridley/mixin/shell_out_spec.rb
|
353
342
|
- spec/unit/ridley/resource_spec.rb
|
354
343
|
- spec/unit/ridley/resources/client_resource_spec.rb
|
355
344
|
- spec/unit/ridley/resources/cookbook_resource_spec.rb
|
@@ -388,7 +377,6 @@ signing_key:
|
|
388
377
|
specification_version: 3
|
389
378
|
summary: A reliable Chef API client with a clean syntax
|
390
379
|
test_files:
|
391
|
-
- spec/acceptance/bootstrapping_spec.rb
|
392
380
|
- spec/acceptance/client_resource_spec.rb
|
393
381
|
- spec/acceptance/cookbook_resource_spec.rb
|
394
382
|
- spec/acceptance/data_bag_item_resource_spec.rb
|
@@ -448,6 +436,7 @@ test_files:
|
|
448
436
|
- spec/unit/ridley/middleware/chef_response_spec.rb
|
449
437
|
- spec/unit/ridley/middleware/gzip_spec.rb
|
450
438
|
- spec/unit/ridley/middleware/parse_json_spec.rb
|
439
|
+
- spec/unit/ridley/mixin/shell_out_spec.rb
|
451
440
|
- spec/unit/ridley/resource_spec.rb
|
452
441
|
- spec/unit/ridley/resources/client_resource_spec.rb
|
453
442
|
- spec/unit/ridley/resources/cookbook_resource_spec.rb
|
@@ -1,29 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe "Bootstrapping a node", type: "acceptance" do
|
4
|
-
let(:server_url) { "https://api.opscode.com" }
|
5
|
-
let(:client_name) { "reset" }
|
6
|
-
let(:client_key) { "/Users/reset/.chef/reset.pem" }
|
7
|
-
let(:organization) { "vialstudios" }
|
8
|
-
|
9
|
-
let(:connection) do
|
10
|
-
Ridley.new(
|
11
|
-
server_url: server_url,
|
12
|
-
client_name: client_name,
|
13
|
-
client_key: client_key,
|
14
|
-
organization: organization,
|
15
|
-
validator_client: "vialstudios-validator",
|
16
|
-
validator_path: "/Users/reset/.chef/vialstudios-validator.pem",
|
17
|
-
ssh: {
|
18
|
-
user: "vagrant",
|
19
|
-
password: "vagrant"
|
20
|
-
}
|
21
|
-
)
|
22
|
-
end
|
23
|
-
|
24
|
-
it "returns an array of response objects" do
|
25
|
-
pending
|
26
|
-
|
27
|
-
connection.node.bootstrap("33.33.33.10").should_not have_errors
|
28
|
-
end
|
29
|
-
end
|