ridley 1.0.0.rc1 → 1.0.0.rc2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|