smart_proxy_salt 2.1.8 → 3.1.2
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.
- checksums.yaml +5 -5
- data/bin/foreman-node +54 -83
- data/bundler.d/salt.rb +2 -0
- data/lib/smart_proxy_salt.rb +2 -0
- data/lib/smart_proxy_salt/api_request.rb +36 -31
- data/lib/smart_proxy_salt/cli.rb +139 -134
- data/lib/smart_proxy_salt/rest.rb +23 -20
- data/lib/smart_proxy_salt/salt.rb +27 -21
- data/lib/smart_proxy_salt/salt_api.rb +84 -79
- data/lib/smart_proxy_salt/salt_http_config.ru +2 -0
- data/lib/smart_proxy_salt/version.rb +4 -1
- data/salt/report_upload/README.md +31 -0
- data/salt/report_upload/master.snippet +3 -0
- data/salt/report_upload/srv/salt/_runners/foreman_report_upload.py +106 -0
- data/salt/report_upload/srv/salt/foreman_report_upload.sls +10 -0
- data/sbin/upload-salt-reports +33 -21
- data/settings.d/salt.saltfile.example +3 -0
- data/settings.d/salt.yml.example +1 -0
- metadata +94 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 5c5e6d0a2348b06d27789269578966ec1b2ae1413341ca1dc5bb318630653c44
|
4
|
+
data.tar.gz: 8238c8469d73c893ead9a9cba3692652b9227a5aa6bdc400cc53e1c83e28e7db
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2873b74a8f42b9e979c38da137674d92e3d0cccdfea62924d27b89ca3c76f4ffc3a5ed961c3e9935311ca1ca51868e44f4315d3cd4d86752d315de0434955b62
|
7
|
+
data.tar.gz: '091bdeb081d90458404ad84baba32db5830b170a28678f554174030722563935186e7fd9abcb52fa743edf5148aae76b65177e7e13e5b2113f48fb0f8f1c8b75'
|
data/bin/foreman-node
CHANGED
@@ -1,12 +1,14 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
2
4
|
# This is the external nodes script to allow Salt to retrieve info about a host
|
3
5
|
# from Foreman. It also uploads a node's grains to Foreman, if the setting is
|
4
6
|
# enabled.
|
5
7
|
|
6
8
|
require 'yaml'
|
7
9
|
|
8
|
-
|
9
|
-
SETTINGS = YAML.load_file(
|
10
|
+
settings_file = '/etc/salt/foreman.yaml'
|
11
|
+
SETTINGS = YAML.load_file(settings_file)
|
10
12
|
|
11
13
|
require 'net/http'
|
12
14
|
require 'net/https'
|
@@ -19,9 +21,13 @@ rescue LoadError
|
|
19
21
|
# Debian packaging guidelines state to avoid needing rubygems, so
|
20
22
|
# we only try to load it if the first require fails (for RPMs)
|
21
23
|
begin
|
22
|
-
|
24
|
+
begin
|
25
|
+
require 'rubygems'
|
26
|
+
rescue Exception
|
27
|
+
nil
|
28
|
+
end
|
23
29
|
require 'json'
|
24
|
-
rescue LoadError
|
30
|
+
rescue LoadError
|
25
31
|
puts 'You need the `json` gem to use the Foreman ENC script'
|
26
32
|
# code 1 is already used below
|
27
33
|
exit 2
|
@@ -37,66 +43,33 @@ def valid_hostname?(hostname)
|
|
37
43
|
end
|
38
44
|
|
39
45
|
def get_grains(minion)
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
exit 1
|
53
|
-
end
|
46
|
+
grains = {
|
47
|
+
:name => minion,
|
48
|
+
:facts => plain_grains(minion).merge(:_timestamp => Time.now, :_type => 'foreman_salt')
|
49
|
+
}
|
50
|
+
|
51
|
+
grains[:facts][:operatingsystem] = grains[:facts]['os']
|
52
|
+
grains[:facts][:operatingsystemrelease] = grains[:facts]['osrelease']
|
53
|
+
|
54
|
+
JSON.pretty_generate(grains)
|
55
|
+
rescue Exception => e
|
56
|
+
puts "Could not get grains: #{e}"
|
57
|
+
exit 1
|
54
58
|
end
|
55
59
|
|
56
60
|
def plain_grains(minion)
|
57
61
|
# We have to get the grains from the cache, because the client
|
58
62
|
# is probably running 'state.highstate' right now.
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
# Based on https://github.com/saltstack/salt/issues/9444
|
63
|
-
|
64
|
-
script = <<-EOF
|
65
|
-
#!/usr/bin/env python
|
66
|
-
import json
|
67
|
-
import os
|
68
|
-
import sys
|
69
|
-
|
70
|
-
import salt.config
|
71
|
-
import salt.runner
|
72
|
-
|
73
|
-
if __name__ == '__main__':
|
74
|
-
__opts__ = salt.config.master_config(
|
75
|
-
os.environ.get('SALT_MASTER_CONFIG', '/etc/salt/minion'))
|
76
|
-
runner = salt.runner.Runner(__opts__)
|
77
|
-
|
78
|
-
stdout_bak = sys.stdout
|
79
|
-
with open(os.devnull, 'wb') as f:
|
80
|
-
sys.stdout = f
|
81
|
-
ret = runner.cmd('cache.grains', ['#{minion}'])
|
82
|
-
sys.stdout = stdout_bak
|
83
|
-
|
84
|
-
print json.dumps(ret)
|
85
|
-
EOF
|
86
|
-
|
87
|
-
result = IO.popen('python 2>/dev/null', mode='r+') do |python|
|
88
|
-
python.write script
|
89
|
-
python.close_write
|
90
|
-
result = python.read
|
63
|
+
|
64
|
+
result = IO.popen(['salt-run', '-l', 'quiet', '--output=json', 'cache.grains', minion]) do |io|
|
65
|
+
io.read
|
91
66
|
end
|
92
67
|
|
93
|
-
grains = JSON.
|
68
|
+
grains = JSON.parse(result)
|
94
69
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
raise 'No grains received from Salt master'
|
99
|
-
end
|
70
|
+
raise 'No grains received from Salt master' unless grains
|
71
|
+
|
72
|
+
plainify(grains[minion]).flatten.inject(&:merge)
|
100
73
|
end
|
101
74
|
|
102
75
|
def plainify(hash, prefix = nil)
|
@@ -126,33 +99,31 @@ def get_key(key, prefix)
|
|
126
99
|
end
|
127
100
|
|
128
101
|
def upload_grains(minion)
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
if
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
res.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
144
|
-
end
|
145
|
-
if SETTINGS[:ssl_cert] && !SETTINGS[:ssl_cert].empty? && SETTINGS[:ssl_key] && !SETTINGS[:ssl_key].empty?
|
146
|
-
res.cert = OpenSSL::X509::Certificate.new(File.read(SETTINGS[:ssl_cert]))
|
147
|
-
res.key = OpenSSL::PKey::RSA.new(File.read(SETTINGS[:ssl_key]), nil)
|
148
|
-
end
|
149
|
-
elsif SETTINGS[:username] && SETTINGS[:password]
|
150
|
-
req.basic_auth(SETTINGS[:username], SETTINGS[:password])
|
102
|
+
grains = get_grains(minion)
|
103
|
+
uri = URI.parse("#{foreman_url}/api/hosts/facts")
|
104
|
+
req = Net::HTTP::Post.new(uri.request_uri)
|
105
|
+
req.add_field('Accept', 'application/json,version=2')
|
106
|
+
req.content_type = 'application/json'
|
107
|
+
req.body = grains
|
108
|
+
res = Net::HTTP.new(uri.host, uri.port)
|
109
|
+
res.use_ssl = uri.scheme == 'https'
|
110
|
+
if res.use_ssl?
|
111
|
+
if SETTINGS[:ssl_ca] && !SETTINGS[:ssl_ca].empty?
|
112
|
+
res.ca_file = SETTINGS[:ssl_ca]
|
113
|
+
res.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
114
|
+
else
|
115
|
+
res.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
151
116
|
end
|
152
|
-
|
153
|
-
|
154
|
-
|
117
|
+
if SETTINGS[:ssl_cert] && !SETTINGS[:ssl_cert].empty? && SETTINGS[:ssl_key] && !SETTINGS[:ssl_key].empty?
|
118
|
+
res.cert = OpenSSL::X509::Certificate.new(File.read(SETTINGS[:ssl_cert]))
|
119
|
+
res.key = OpenSSL::PKey::RSA.new(File.read(SETTINGS[:ssl_key]), nil)
|
120
|
+
end
|
121
|
+
elsif SETTINGS[:username] && SETTINGS[:password]
|
122
|
+
req.basic_auth(SETTINGS[:username], SETTINGS[:password])
|
155
123
|
end
|
124
|
+
res.start { |http| http.request(req) }
|
125
|
+
rescue Exception => e
|
126
|
+
raise "Could not send facts to Foreman: #{e}"
|
156
127
|
end
|
157
128
|
|
158
129
|
def enc(minion)
|
@@ -176,7 +147,7 @@ def enc(minion)
|
|
176
147
|
req.basic_auth(SETTINGS[:username], SETTINGS[:password])
|
177
148
|
end
|
178
149
|
|
179
|
-
res = http.start { |
|
150
|
+
res = http.start { |conn| conn.request(req) }
|
180
151
|
|
181
152
|
raise "Error retrieving node #{minion}: #{res.class}\nCheck Foreman's /var/log/foreman/production.log for more information." unless res.code == '200'
|
182
153
|
res.body
|
@@ -198,7 +169,7 @@ begin
|
|
198
169
|
result = enc(minion)
|
199
170
|
end
|
200
171
|
puts result
|
201
|
-
rescue => e
|
172
|
+
rescue Exception => e
|
202
173
|
puts "Couldn't retrieve ENC data: #{e}"
|
203
174
|
exit 1
|
204
175
|
end
|
data/bundler.d/salt.rb
CHANGED
data/lib/smart_proxy_salt.rb
CHANGED
@@ -1,44 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'json'
|
2
4
|
require 'net/http'
|
3
5
|
require 'net/https'
|
4
6
|
require 'uri'
|
5
7
|
|
6
|
-
module Proxy
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
8
|
+
module Proxy
|
9
|
+
module Salt
|
10
|
+
class ApiError < RuntimeError; end
|
11
|
+
class ConfigurationError < RuntimeError; end
|
12
|
+
|
13
|
+
# SaltStack's Rest API
|
14
|
+
class ApiRequest
|
15
|
+
attr_reader :url, :username, :password, :auth
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@url = Proxy::Salt::Plugin.settings.api_url
|
19
|
+
@auth = Proxy::Salt::Plugin.settings.api_auth
|
20
|
+
@username = Proxy::Salt::Plugin.settings.api_username
|
21
|
+
@password = Proxy::Salt::Plugin.settings.api_password
|
22
|
+
|
23
|
+
begin
|
24
|
+
URI.parse(url)
|
25
|
+
rescue URI::InvalidURIError => e
|
26
|
+
raise ConfigurationError.new("Invalid Salt api_url setting: #{e}")
|
27
|
+
end
|
22
28
|
end
|
23
|
-
end
|
24
29
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
30
|
+
def post(path, options = {})
|
31
|
+
uri = URI.parse(url)
|
32
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
33
|
+
http.use_ssl = uri.scheme == 'https'
|
34
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
35
|
+
path = [uri.path, path].join unless uri.path.empty?
|
36
|
+
|
37
|
+
request = Net::HTTP::Post.new(URI.join(uri.to_s, path).path)
|
38
|
+
request.add_field('Accept', 'application/json')
|
39
|
+
request.set_form_data(options.merge(:username => username, :password => password, :eauth => auth))
|
31
40
|
|
32
|
-
|
33
|
-
request.add_field('Accept', 'application/json')
|
34
|
-
request.set_form_data(options.merge(:username => username, :password => password, :eauth => auth))
|
41
|
+
response = http.request(request)
|
35
42
|
|
36
|
-
|
43
|
+
raise NotFound.new("Received 404 from Salt API: #{response.body}") if response.is_a?(Net::HTTPNotFound)
|
44
|
+
raise ApiError.new("Failed to query Salt API (#{response.code}): #{response.body}") unless response.is_a?(Net::HTTPOK)
|
37
45
|
|
38
|
-
|
39
|
-
JSON.load(response.body)
|
40
|
-
else
|
41
|
-
raise ApiError.new("Failed to query Salt API (#{response.code}): #{response.body}")
|
46
|
+
JSON.parse(response.body)
|
42
47
|
end
|
43
48
|
end
|
44
49
|
end
|
data/lib/smart_proxy_salt/cli.rb
CHANGED
@@ -1,163 +1,168 @@
|
|
1
|
-
|
2
|
-
extend ::Proxy::Log
|
3
|
-
extend ::Proxy::Util
|
1
|
+
# frozen_string_literal: true
|
4
2
|
|
5
|
-
|
6
|
-
def autosign_file
|
7
|
-
Proxy::Salt::Plugin.settings.autosign_file
|
8
|
-
end
|
3
|
+
require 'English'
|
9
4
|
|
10
|
-
|
11
|
-
|
5
|
+
module Proxy
|
6
|
+
module Salt
|
7
|
+
# CLI methods
|
8
|
+
module CLI
|
9
|
+
extend ::Proxy::Log
|
10
|
+
extend ::Proxy::Util
|
12
11
|
|
13
|
-
|
12
|
+
class << self
|
13
|
+
def autosign_file
|
14
|
+
Proxy::Salt::Plugin.settings.autosign_file
|
15
|
+
end
|
14
16
|
|
15
|
-
|
16
|
-
|
17
|
-
autosign.puts host unless found
|
18
|
-
autosign.close
|
17
|
+
def autosign_create(host)
|
18
|
+
FileUtils.touch(autosign_file) unless File.exist?(autosign_file)
|
19
19
|
|
20
|
-
|
21
|
-
logger.info result[:message]
|
22
|
-
result
|
23
|
-
end
|
20
|
+
autosign = open(autosign_file, File::RDWR)
|
24
21
|
|
25
|
-
|
26
|
-
|
22
|
+
found = false
|
23
|
+
autosign.each_line { |line| found = true if line.chomp == host }
|
24
|
+
autosign.puts host unless found
|
25
|
+
autosign.close
|
27
26
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
l
|
32
|
-
else
|
33
|
-
found = true
|
34
|
-
nil
|
27
|
+
result = { :message => "Added #{host} to autosign" }
|
28
|
+
logger.info result[:message]
|
29
|
+
result
|
35
30
|
end
|
36
|
-
end.uniq.compact
|
37
|
-
if found
|
38
|
-
autosign = open(autosign_file, File::TRUNC|File::RDWR)
|
39
|
-
autosign.write entries.join("\n")
|
40
|
-
autosign.write "\n"
|
41
|
-
autosign.close
|
42
|
-
result = {:message => "Removed #{host} from autosign"}
|
43
|
-
logger.info result[:message]
|
44
|
-
result
|
45
|
-
else
|
46
|
-
logger.info "Attempt to remove nonexistant client autosign for #{host}"
|
47
|
-
raise Proxy::Salt::NotFound, "Attempt to remove nonexistant client autosign for #{host}"
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
def autosign_list
|
52
|
-
return [] unless File.exist?(autosign_file)
|
53
|
-
File.read(autosign_file).split("\n").reject { |v|
|
54
|
-
v =~ /^\s*#.*|^$/ ## Remove comments and empty lines
|
55
|
-
}.map { |v|
|
56
|
-
v.chomp ## Strip trailing spaces
|
57
|
-
}
|
58
|
-
end
|
59
31
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
32
|
+
def autosign_remove(host)
|
33
|
+
raise "No such file #{autosign_file}" unless File.exist?(autosign_file)
|
34
|
+
|
35
|
+
found = false
|
36
|
+
entries = open(autosign_file, File::RDONLY).readlines.collect do |l|
|
37
|
+
if l.chomp != host
|
38
|
+
l
|
39
|
+
else
|
40
|
+
found = true
|
41
|
+
nil
|
42
|
+
end
|
43
|
+
end.uniq.compact
|
44
|
+
if found
|
45
|
+
autosign = open(autosign_file, File::TRUNC | File::RDWR)
|
46
|
+
autosign.write entries.join("\n")
|
47
|
+
autosign.write "\n"
|
48
|
+
autosign.close
|
49
|
+
result = { :message => "Removed #{host} from autosign" }
|
50
|
+
logger.info result[:message]
|
51
|
+
result
|
52
|
+
else
|
53
|
+
logger.info "Attempt to remove nonexistant client autosign for #{host}"
|
54
|
+
raise Proxy::Salt::NotFound.new("Attempt to remove nonexistant client autosign for #{host}")
|
55
|
+
end
|
56
|
+
end
|
78
57
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
58
|
+
def autosign_list
|
59
|
+
return [] unless File.exist?(autosign_file)
|
60
|
+
File.read(autosign_file).split("\n").reject do |v|
|
61
|
+
v =~ /^\s*#.*|^$/ ## Remove comments and empty lines
|
62
|
+
end.map(&:chomp)
|
63
|
+
end
|
84
64
|
|
85
|
-
|
65
|
+
def highstate(host)
|
66
|
+
find_salt_binaries
|
67
|
+
cmd = [@sudo, '-u', Proxy::Salt::Plugin.settings.salt_command_user, @salt, '--async', escape_for_shell(host), 'state.highstate']
|
68
|
+
logger.info "Will run state.highstate for #{host}. Full command: #{cmd.join(' ')}"
|
69
|
+
shell_command(cmd)
|
70
|
+
end
|
86
71
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
logger.warn "Failed to run salt-key: #{response}"
|
93
|
-
raise 'Execution of salt-key failed, check log files'
|
94
|
-
end
|
72
|
+
def key_delete(host)
|
73
|
+
find_salt_binaries
|
74
|
+
cmd = [@sudo, '-u', Proxy::Salt::Plugin.settings.salt_command_user, @salt_key, '--yes', '-d', escape_for_shell(host)]
|
75
|
+
shell_command(cmd)
|
76
|
+
end
|
95
77
|
|
96
|
-
|
78
|
+
def key_reject(host)
|
79
|
+
find_salt_binaries
|
80
|
+
cmd = [@sudo, '-u', Proxy::Salt::Plugin.settings.salt_command_user, @salt_key, '--include-accepted', '--yes', '-r', escape_for_shell(host)]
|
81
|
+
shell_command(cmd)
|
82
|
+
end
|
97
83
|
|
98
|
-
|
84
|
+
def key_accept(host)
|
85
|
+
find_salt_binaries
|
86
|
+
cmd = [@sudo, '-u', Proxy::Salt::Plugin.settings.salt_command_user, @salt_key, '--include-rejected', '--yes', '-a', escape_for_shell(host)]
|
87
|
+
shell_command(cmd)
|
88
|
+
end
|
99
89
|
|
100
|
-
|
101
|
-
|
90
|
+
def key_list
|
91
|
+
find_salt_binaries
|
92
|
+
command = "#{@sudo} -u #{Proxy::Salt::Plugin.settings.salt_command_user} #{@salt_key} --finger-all --output=json"
|
93
|
+
logger.debug "Executing #{command}"
|
94
|
+
response = `#{command}`
|
95
|
+
unless $CHILD_STATUS == 0
|
96
|
+
logger.warn "Failed to run salt-key: #{response}"
|
97
|
+
raise 'Execution of salt-key failed, check log files'
|
98
|
+
end
|
102
99
|
|
103
|
-
|
104
|
-
rejected_minions.keys.each { | rejected_minion | keys_hash[rejected_minion] = { 'state' => 'rejected', 'fingerprint' => rejected_minions[rejected_minion] } } if sk_hash.key? 'minions_rejected'
|
100
|
+
keys_hash = {}
|
105
101
|
|
106
|
-
|
107
|
-
unaccepted_minions.keys.each { | unaccepted_minion | keys_hash[unaccepted_minion] = { 'state' => 'unaccepted', 'fingerprint' => unaccepted_minions[unaccepted_minion] } } if sk_hash.key? 'minions_pre'
|
102
|
+
sk_hash = JSON.parse(response)
|
108
103
|
|
109
|
-
|
104
|
+
accepted_minions = sk_hash['minions']
|
105
|
+
accepted_minions.each_key { |accepted_minion| keys_hash[accepted_minion] = { 'state' => 'accepted', 'fingerprint' => accepted_minions[accepted_minion] } } if sk_hash.key? 'minions'
|
110
106
|
|
111
|
-
|
107
|
+
rejected_minions = sk_hash['minions_rejected']
|
108
|
+
rejected_minions.each_key { |rejected_minion| keys_hash[rejected_minion] = { 'state' => 'rejected', 'fingerprint' => rejected_minions[rejected_minion] } } if sk_hash.key? 'minions_rejected'
|
112
109
|
|
113
|
-
|
110
|
+
unaccepted_minions = sk_hash['minions_pre']
|
111
|
+
unaccepted_minions.each_key { |unaccepted_minion| keys_hash[unaccepted_minion] = { 'state' => 'unaccepted', 'fingerprint' => unaccepted_minions[unaccepted_minion] } } if sk_hash.key? 'minions_pre'
|
114
112
|
|
115
|
-
|
116
|
-
begin
|
117
|
-
c = popen(cmd)
|
118
|
-
unless wait
|
119
|
-
Process.detach(c.pid)
|
120
|
-
return 0
|
113
|
+
keys_hash
|
121
114
|
end
|
122
|
-
Process.wait(c.pid)
|
123
|
-
logger.info("Result: #{c.read}")
|
124
|
-
rescue Exception => e
|
125
|
-
logger.error("Exception '#{e}' when executing '#{cmd}'")
|
126
|
-
return false
|
127
|
-
end
|
128
|
-
logger.warn("Non-null exit code when executing '#{cmd}'") if $?.exitstatus != 0
|
129
|
-
$?.exitstatus == 0
|
130
|
-
end
|
131
115
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
116
|
+
private
|
117
|
+
|
118
|
+
def shell_command(cmd, wait = true)
|
119
|
+
begin
|
120
|
+
c = popen(cmd)
|
121
|
+
unless wait
|
122
|
+
Process.detach(c.pid)
|
123
|
+
return 0
|
124
|
+
end
|
125
|
+
Process.wait(c.pid)
|
126
|
+
logger.info("Result: #{c.read}")
|
127
|
+
rescue Exception => e
|
128
|
+
logger.error("Exception '#{e}' when executing '#{cmd}'")
|
129
|
+
return false
|
130
|
+
end
|
131
|
+
logger.warn("Non-null exit code when executing '#{cmd}'") unless $CHILD_STATUS.success?
|
132
|
+
$CHILD_STATUS.success?
|
133
|
+
end
|
146
134
|
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
135
|
+
def popen(cmd)
|
136
|
+
# 1.8.7 note: this assumes that cli options are space-separated
|
137
|
+
cmd = cmd.join(' ') unless RUBY_VERSION > '1.8.7'
|
138
|
+
logger.debug("about to execute: #{cmd}")
|
139
|
+
IO.popen(cmd)
|
140
|
+
end
|
153
141
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
142
|
+
def find_salt_binaries
|
143
|
+
@salt_key = which('salt-key')
|
144
|
+
unless File.exist?(@salt_key.to_s)
|
145
|
+
logger.warn 'unable to find salt-key binary'
|
146
|
+
raise 'unable to find salt-key'
|
147
|
+
end
|
148
|
+
logger.debug "Found salt-key at #{@salt_key}"
|
149
|
+
|
150
|
+
@salt = which('salt')
|
151
|
+
unless File.exist?(@salt.to_s)
|
152
|
+
logger.warn 'unable to find salt binary'
|
153
|
+
raise 'unable to find salt'
|
154
|
+
end
|
155
|
+
logger.debug "Found salt at #{@salt}"
|
156
|
+
|
157
|
+
@sudo = which('sudo')
|
158
|
+
unless File.exist?(@sudo)
|
159
|
+
logger.warn 'unable to find sudo binary'
|
160
|
+
raise 'Unable to find sudo'
|
161
|
+
end
|
162
|
+
logger.debug "Found sudo at #{@sudo}"
|
163
|
+
@sudo = @sudo.to_s
|
164
|
+
end
|
158
165
|
end
|
159
|
-
logger.debug "Found sudo at #{@sudo}"
|
160
|
-
@sudo = "#{@sudo}"
|
161
166
|
end
|
162
167
|
end
|
163
168
|
end
|