smart_proxy_salt 0.0.1 → 0.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 17e8351a98fec3158dd5afa43ae6b4f1780002fc
4
- data.tar.gz: bf054186755b76c3fabf3a0f72badd267abd3140
3
+ metadata.gz: acacbc60a4623c98351222437e7dc95180ffe154
4
+ data.tar.gz: 1eadaeb629d7defaeb6112606bfdd25566f47866
5
5
  SHA512:
6
- metadata.gz: a9109ea9464e2881a26f0210a5f1c847721a7e94ed524164e3e47a14ca6246841f1374e95d64d24c31dce67656bbe4e33e9e11f8099ae807d4d4511241767225
7
- data.tar.gz: 6e6c418f03a87bc0a83df611750dde9a196c0a7751324f28d341097383895c41848bab4d99bc14cc33448ed4fa9258896cdb6c7d69b05e577a8f4955668e296f
6
+ metadata.gz: fb6e7a820f206431e75d88010840e8d6f9a2ff4068680bcab3dd9ec148931f8b355da8fc66f0f55e5e8996bf20f80e55763890343fc2126c191160f4b253773f
7
+ data.tar.gz: 6dd63d90454b6becf490e615ca7dcd9bd58fc30a430af9651d9f02569e8103f43242f6636521fef4a61ca8f55faababeb80d03747398444c39099ed712baeffb
data/bin/foreman-node ADDED
@@ -0,0 +1,195 @@
1
+ #!/usr/bin/env ruby
2
+ # This is the external nodes script to allow Salt to retrieve info about a host
3
+ # from Foreman. It also uploads a node's grains to Foreman, if the setting is
4
+ # enabled.
5
+
6
+ require 'yaml'
7
+
8
+ $settings_file = "/etc/salt/foreman.yaml"
9
+ SETTINGS = YAML.load_file($settings_file)
10
+
11
+ require 'net/http'
12
+ require 'net/https'
13
+ require 'etc'
14
+ require 'timeout'
15
+
16
+ begin
17
+ require 'json'
18
+ rescue LoadError
19
+ # Debian packaging guidelines state to avoid needing rubygems, so
20
+ # we only try to load it if the first require fails (for RPMs)
21
+ begin
22
+ require 'rubygems' rescue nil
23
+ require 'json'
24
+ rescue LoadError => e
25
+ puts "You need the `json` gem to use the Foreman ENC script"
26
+ # code 1 is already used below
27
+ exit 2
28
+ end
29
+ end
30
+
31
+ def foreman_url
32
+ "#{SETTINGS[:proto]}://#{SETTINGS[:host]}:#{SETTINGS[:port]}"
33
+ end
34
+
35
+ def valid_hostname? hostname
36
+ hostname =~ /\A(([a-z0-9]|[a-z0-9][a-z0-9\-]*[a-z0-9])\.)*([a-z0-9]|[a-z0-9][a-z0-9\-]*[a-z0-9])\z/
37
+ end
38
+
39
+ def get_grains(minion)
40
+ begin
41
+ grains = {
42
+ :name => minion,
43
+ :facts => plain_grains(minion).merge({:_timestamp => Time.now, :_type => 'foreman_salt'})
44
+ }
45
+
46
+ grains[:facts][:operatingsystem] = grains[:facts]['os']
47
+ grains[:facts][:operatingsystemrelease] = grains[:facts]['osrelease']
48
+
49
+ JSON.pretty_generate(grains)
50
+ rescue => e
51
+ puts "Could not get grains: #{e}"
52
+ exit 1
53
+ end
54
+ end
55
+
56
+ def plain_grains minion
57
+ # We have to get the grains from the cache, because the client
58
+ # is probably running 'state.highstate' right now.
59
+ #
60
+ # salt-run doesn't support directly outputting to json,
61
+ # so we have resort to python to extract the grains.
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", mode='r+') do |python|
88
+ python.write script
89
+ python.close_write
90
+ result = python.read
91
+ end
92
+
93
+ grains = JSON.load(result)
94
+ plainify(grains[minion]).flatten.inject(&:merge)
95
+ end
96
+
97
+ def plainify(hash, prefix = nil)
98
+ result = []
99
+ hash.each_pair do |key, value|
100
+ if value.is_a?(Hash)
101
+ result.push plainify(value, get_key(key, prefix))
102
+ elsif value.is_a?(Array)
103
+ result.push plainify(array_to_hash(value), get_key(key, prefix))
104
+ else
105
+ new = {}
106
+ new[get_key(key, prefix)] = value
107
+ result.push new
108
+ end
109
+ end
110
+ result
111
+ end
112
+
113
+ def array_to_hash(array)
114
+ new = {}
115
+ array.each_with_index { |v, index| new[index.to_s] = v }
116
+ new
117
+ end
118
+
119
+ def get_key(key, prefix)
120
+ [prefix, key].compact.join('::')
121
+ end
122
+
123
+ def upload_grains(minion)
124
+ begin
125
+ grains = get_grains(minion)
126
+ uri = URI.parse("#{foreman_url}/api/hosts/facts")
127
+ req = Net::HTTP::Post.new(uri.request_uri)
128
+ req.add_field('Accept', 'application/json,version=2' )
129
+ req.content_type = 'application/json'
130
+ req.body = grains
131
+ res = Net::HTTP.new(uri.host, uri.port)
132
+ res.use_ssl = uri.scheme == 'https'
133
+ if res.use_ssl?
134
+ if SETTINGS[:ssl_ca] && !SETTINGS[:ssl_ca].empty?
135
+ res.ca_file = SETTINGS[:ssl_ca]
136
+ res.verify_mode = OpenSSL::SSL::VERIFY_PEER
137
+ else
138
+ res.verify_mode = OpenSSL::SSL::VERIFY_NONE
139
+ end
140
+ if SETTINGS[:ssl_cert] && !SETTINGS[:ssl_cert].empty? && SETTINGS[:ssl_key] && !SETTINGS[:ssl_key].empty?
141
+ res.cert = OpenSSL::X509::Certificate.new(File.read(SETTINGS[:ssl_cert]))
142
+ res.key = OpenSSL::PKey::RSA.new(File.read(SETTINGS[:ssl_key]), nil)
143
+ end
144
+ end
145
+ res.start { |http| http.request(req) }
146
+ rescue => e
147
+ raise "Could not send facts to Foreman: #{e}"
148
+ end
149
+ end
150
+
151
+ def enc(minion)
152
+ url = "#{foreman_url}/salt/node/#{minion}?format=yml"
153
+ uri = URI.parse(url)
154
+ req = Net::HTTP::Get.new(uri.request_uri)
155
+ http = Net::HTTP.new(uri.host, uri.port)
156
+ http.use_ssl = uri.scheme == 'https'
157
+ if http.use_ssl?
158
+ if SETTINGS[:ssl_ca] && !SETTINGS[:ssl_ca].empty?
159
+ http.ca_file = SETTINGS[:ssl_ca]
160
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
161
+ else
162
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
163
+ end
164
+ if SETTINGS[:ssl_cert] && !SETTINGS[:ssl_cert].empty? && SETTINGS[:ssl_key] && !SETTINGS[:ssl_key].empty?
165
+ http.cert = OpenSSL::X509::Certificate.new(File.read(SETTINGS[:ssl_cert]))
166
+ http.key = OpenSSL::PKey::RSA.new(File.read(SETTINGS[:ssl_key]), nil)
167
+ end
168
+ end
169
+
170
+ res = http.start { |http| http.request(req) }
171
+
172
+ raise "Error retrieving node #{minion}: #{res.class}\nCheck Foreman's /var/log/foreman/production.log for more information." unless res.code == "200"
173
+ res.body
174
+ end
175
+
176
+ minion = ARGV[0] || raise("Must provide minion as an argument")
177
+
178
+ raise "Invalid hostname" unless valid_hostname? minion
179
+ begin
180
+ result = ""
181
+
182
+ if SETTINGS[:upload_grains]
183
+ timeout(SETTINGS[:timeout]) do
184
+ upload_grains(minion)
185
+ end
186
+ end
187
+
188
+ timeout(SETTINGS[:timeout]) do
189
+ result = enc(minion)
190
+ end
191
+ puts result
192
+ rescue => e
193
+ puts "Couldn't retrieve ENC data: #{e}"
194
+ exit 1
195
+ end
@@ -0,0 +1,10 @@
1
+ ---
2
+ :proto: http
3
+ :host: foreman.example.com
4
+ :port: 3000
5
+ :ssl_ca: ""
6
+ :ssl_cert: ""
7
+ :ssl_key: ""
8
+ :timeout: 10
9
+ :salt: /usr/bin/salt
10
+ :upload_grains: true
@@ -1,4 +1,4 @@
1
1
  require 'smart_proxy_salt/salt_api'
2
2
  map "/salt" do
3
- run Proxy::Salt::Api
3
+ run Proxy::Salt::Api
4
4
  end
@@ -13,6 +13,7 @@ module Proxy::Salt
13
13
  return 0
14
14
  end
15
15
  Process.wait(c.pid)
16
+ logger.info("Result: #{c.read}")
16
17
  rescue Exception => e
17
18
  logger.error("Exception '#{e}' when executing '#{cmd}'")
18
19
  return false
@@ -84,7 +85,7 @@ module Proxy::Salt
84
85
 
85
86
  def highstate host
86
87
  find_salt_binaries
87
- cmd = [@sudo, '-u', Proxy::Salt::Plugin.settings.salt_command_user, @salt, "--async", "'#{escape_for_shell(host)}'", "state.highstate"]
88
+ cmd = [@sudo, '-u', Proxy::Salt::Plugin.settings.salt_command_user, @salt, "--async", escape_for_shell(host), "state.highstate"]
88
89
  logger.info "Will run state.highstate for #{host}. Full command: #{cmd.join(" ")}"
89
90
  shell_command(cmd)
90
91
  end
@@ -1,5 +1,5 @@
1
1
  module Proxy
2
2
  module Salt
3
- VERSION = '0.0.1'
3
+ VERSION = '0.0.2'
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: smart_proxy_salt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Moll
@@ -9,17 +9,22 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-08-21 00:00:00.000000000 Z
12
+ date: 2014-08-31 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: SaltStack Plug-In for Foreman's Smart Proxy
15
15
  email: foreman-dev@googlegroups.com
16
- executables: []
16
+ executables:
17
+ - foreman-node
17
18
  extensions: []
18
- extra_rdoc_files: []
19
+ extra_rdoc_files:
20
+ - README.md
21
+ - LICENSE
19
22
  files:
20
23
  - LICENSE
21
24
  - README.md
25
+ - bin/foreman-node
22
26
  - bundler.d/salt.rb
27
+ - etc/foreman.yaml.example
23
28
  - lib/smart_proxy_salt.rb
24
29
  - lib/smart_proxy_salt/salt.rb
25
30
  - lib/smart_proxy_salt/salt_api.rb
@@ -27,7 +32,7 @@ files:
27
32
  - lib/smart_proxy_salt/salt_main.rb
28
33
  - lib/smart_proxy_salt/version.rb
29
34
  - settings.d/salt.yml.example
30
- homepage: http://github.com/stbenjam/smart-proxy_salt
35
+ homepage: https://github.com/theforeman/smart_proxy_salt
31
36
  licenses:
32
37
  - GPLv3
33
38
  metadata: {}