sensu_generator 0.0.25
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 +7 -0
- data/.gitignore +10 -0
- data/.rspec +2 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/README.md +87 -0
- data/Rakefile +6 -0
- data/bin/console +11 -0
- data/bin/setup +8 -0
- data/exe/sensu-generator +54 -0
- data/lib/sensu_generator/application.rb +134 -0
- data/lib/sensu_generator/check_file.rb +27 -0
- data/lib/sensu_generator/client.rb +60 -0
- data/lib/sensu_generator/config.rb +64 -0
- data/lib/sensu_generator/consul/consul_service.rb +47 -0
- data/lib/sensu_generator/consul/consul_state.rb +45 -0
- data/lib/sensu_generator/consul.rb +66 -0
- data/lib/sensu_generator/exceptions.rb +21 -0
- data/lib/sensu_generator/generator.rb +97 -0
- data/lib/sensu_generator/hash.rb +6 -0
- data/lib/sensu_generator/logger.rb +28 -0
- data/lib/sensu_generator/notifier.rb +15 -0
- data/lib/sensu_generator/restarter.rb +55 -0
- data/lib/sensu_generator/sensu_server.rb +70 -0
- data/lib/sensu_generator/server.rb +69 -0
- data/lib/sensu_generator/trigger.rb +40 -0
- data/lib/sensu_generator/version.rb +3 -0
- data/lib/sensu_generator.rb +18 -0
- data/sensu-generator.config.example +28 -0
- data/sensu_generator.gemspec +33 -0
- metadata +200 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: aa5b40932e162763cc44bfc51cd2051806b3d46a
|
4
|
+
data.tar.gz: 23194a317cde4a606d1358ef06fa70c5e7974bcd
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5d6afad7404f580509f9f189f92fc70b5ca0c11158fa4561325ed7b2aea4b29abebbd064ebfc5be466693a8de7f5304ae9ea8084c5c90a8f6f9833d308e5bb56
|
7
|
+
data.tar.gz: d818013b9f39db3898ba74924063754c505ed5327f0bc473a05f3e37c922272c25c8724270181b2373180d2d129e3ffcc8adc24dcaf09ddabe61951b9b23248f
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
# SensuGenerator
|
2
|
+
|
3
|
+
SensuGenerator is an intermediate layer between Consul and Sensu. It helps to set up dynamic monitoring systems. It generates check configurations from ERB templates according to *tags* listed in the KV and Consul service properties. It watches for changes Consul services state and special key in the KV. It triggers the following:
|
4
|
+
Sensu check configuration files are generated from the templates, the result will be synced via *rsync* and Sensu servers will be restarted using http Supervisord API. All files are generated when application starts and only changes will be processed.
|
5
|
+
|
6
|
+
All service checks *tag* are stored in the Consul Key-Value storage in *service/kv_tags_path* path, default *kv_tags_path* is "checks". Tag is the beginning of a service check template name and should be specified as a part of the template name in the Consul KV storage. Note that value should be comma-separated tags list. Rsync repo shuold be named as sensu service name.
|
7
|
+
|
8
|
+
It can can be used master server with multiple clients which send processed templates via tcp.
|
9
|
+
|
10
|
+
## Installation
|
11
|
+
|
12
|
+
Add this line to your application's Gemfile:
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
gem 'sensu_generator'
|
16
|
+
```
|
17
|
+
|
18
|
+
Install it yourself as:
|
19
|
+
|
20
|
+
$ gem install sensu_generator
|
21
|
+
|
22
|
+
## Usage
|
23
|
+
|
24
|
+
sensu_generator start|stop|status|run -- [options]
|
25
|
+
|
26
|
+
##### Example:
|
27
|
+
|
28
|
+
**consul_url***/kv/nginx/checks*
|
29
|
+
```
|
30
|
+
check-http, check-tcp
|
31
|
+
```
|
32
|
+
|
33
|
+
Use ***svc*** (contains service data form consul) and ***check*** (contains *tag* name) in the ERB template.
|
34
|
+
***svc.kv_svc_props(key: key)*** can be used to access to ***svc/key*** data.
|
35
|
+
If key is not specified it will be requested the whole ***svc/*** folder.
|
36
|
+
|
37
|
+
Use Slack as notifier if you want.
|
38
|
+
|
39
|
+
##### Check ERB template example:
|
40
|
+
|
41
|
+
```
|
42
|
+
{
|
43
|
+
"checks": {
|
44
|
+
<% svc.properties.each do |instance| %>
|
45
|
+
<% next if instance.ServiceTags.include? "udp" %>
|
46
|
+
"check-ports-tcp-<%= "#{svc.name}-#{instance.ServiceAddress}-#{instance.ServicePort}" %>": {
|
47
|
+
"command": "check-ports.rb -h <%= instance.ServiceAddress %> -p <%= instance.ServicePort %>",
|
48
|
+
"subscribers": ["roundrobin:sensu-checker-node"],
|
49
|
+
"handlers": ["slack"],
|
50
|
+
"source": "<%= svc.name %>.service"
|
51
|
+
}<%= "," if instance != svc.properties.last %>
|
52
|
+
<% end %>
|
53
|
+
}
|
54
|
+
}
|
55
|
+
|
56
|
+
|
57
|
+
```
|
58
|
+
|
59
|
+
## Configuration
|
60
|
+
|
61
|
+
##### server configuration:
|
62
|
+
|
63
|
+
```
|
64
|
+
"mode": "server",
|
65
|
+
"server": {
|
66
|
+
"addr": "", //ip address to listen or left it empty to listen on 0.0.0.0
|
67
|
+
"port": 12345 //listen port
|
68
|
+
}
|
69
|
+
```
|
70
|
+
|
71
|
+
##### client configuration:
|
72
|
+
|
73
|
+
```
|
74
|
+
"mode": "client",
|
75
|
+
"server": {
|
76
|
+
"addr": "", //ip address or domain to connect to
|
77
|
+
"port": 12345 //server port
|
78
|
+
}
|
79
|
+
```
|
80
|
+
|
81
|
+
See *sensu-generator.config.example* for more information.
|
82
|
+
|
83
|
+
## Development
|
84
|
+
|
85
|
+
## Contributing
|
86
|
+
|
87
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/aksentyev/sensu_generator. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "sensu_generator"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
require "pry"
|
11
|
+
Pry.start
|
data/bin/setup
ADDED
data/exe/sensu-generator
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'sensu_generator'
|
3
|
+
require 'optparse'
|
4
|
+
require 'daemons'
|
5
|
+
|
6
|
+
module SensuGenerator
|
7
|
+
class << self
|
8
|
+
def parse_args!
|
9
|
+
args = ARGV.dup
|
10
|
+
|
11
|
+
# get elements after '--' because of Daemons
|
12
|
+
args = args[(args.index('--')+1)..-1] if args.include? ('--')
|
13
|
+
config = nil
|
14
|
+
optparse = OptionParser.new do |opts|
|
15
|
+
opts.banner = "sensu-generator run|start|stop|status -- [options]"
|
16
|
+
|
17
|
+
opts.on("-c", "--config File", String, "Path to config file") do |item|
|
18
|
+
config = item
|
19
|
+
end
|
20
|
+
opts.on_tail("--version", "Show version") do
|
21
|
+
puts VERSION
|
22
|
+
exit
|
23
|
+
end
|
24
|
+
|
25
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
26
|
+
puts opts
|
27
|
+
exit
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
optparse.parse!(args)
|
32
|
+
config ? File.expand_path(config) : nil
|
33
|
+
end
|
34
|
+
|
35
|
+
def run(config_file = nil)
|
36
|
+
config = Config.new(config_file)
|
37
|
+
logger = Logger.new(config.get[:logger])
|
38
|
+
logger.level = eval("Logger::#{config.get[:logger][:log_level].upcase}")
|
39
|
+
notifier = Notifier.new(config.get[:slack])
|
40
|
+
trigger = Trigger.new
|
41
|
+
|
42
|
+
Application.new(config: config, logger: logger, notifier: notifier, trigger: trigger).run
|
43
|
+
rescue => e
|
44
|
+
msg = %("Sensu_generator exited with non-zero code.\n #{e.to_s} \n#{e.backtrace.join("\n\t")}")
|
45
|
+
Logger.new(file: STDOUT).fatal msg
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
config = SensuGenerator::parse_args!
|
51
|
+
|
52
|
+
Daemons.run_proc(__FILE__) do
|
53
|
+
SensuGenerator::run(config)
|
54
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
require 'thread'
|
2
|
+
|
3
|
+
module SensuGenerator
|
4
|
+
class Application
|
5
|
+
class << self
|
6
|
+
def logger
|
7
|
+
@@logger
|
8
|
+
end
|
9
|
+
|
10
|
+
def notifier
|
11
|
+
@@notifier
|
12
|
+
end
|
13
|
+
|
14
|
+
def config
|
15
|
+
@@config
|
16
|
+
end
|
17
|
+
|
18
|
+
def trigger
|
19
|
+
@@trigger
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def initialize(config:, logger:, notifier:, trigger:)
|
24
|
+
@@logger = logger
|
25
|
+
@@notifier = notifier
|
26
|
+
@@config = config
|
27
|
+
@@trigger = trigger
|
28
|
+
@threads = []
|
29
|
+
end
|
30
|
+
|
31
|
+
def logger
|
32
|
+
@@logger
|
33
|
+
end
|
34
|
+
|
35
|
+
def notifier
|
36
|
+
@@notifier
|
37
|
+
end
|
38
|
+
|
39
|
+
def config
|
40
|
+
@@config
|
41
|
+
end
|
42
|
+
|
43
|
+
def trigger
|
44
|
+
@@trigger
|
45
|
+
end
|
46
|
+
|
47
|
+
def run_restarter
|
48
|
+
logger.info "Starting restarter..."
|
49
|
+
loop do
|
50
|
+
logger.info 'Restarter is alive!'
|
51
|
+
if restarter.need_to_apply_new_configs?
|
52
|
+
restarter.perform_restart
|
53
|
+
end
|
54
|
+
sleep 60
|
55
|
+
end
|
56
|
+
rescue => e
|
57
|
+
raise ApplicationError, "Restarter error:\n\t #{e.to_s}\n\t #{e.backtrace}"
|
58
|
+
end
|
59
|
+
|
60
|
+
def run_generator
|
61
|
+
logger.info "Starting generator..."
|
62
|
+
generator.flush_results if config.get[:mode] == 'server'
|
63
|
+
state = ConsulState.new
|
64
|
+
loop do
|
65
|
+
logger.info 'Generator is alive!'
|
66
|
+
if state.changed? && state.actualized?
|
67
|
+
generator.services = state.changes
|
68
|
+
list = generator.generate!
|
69
|
+
logger.info "#{list.size} files processed: #{list.join(', ')}"
|
70
|
+
if config.get[:mode] == 'server' && list.empty? && state.changes.any? { |svc| svc.name == config.get[:sensu][:service] }
|
71
|
+
logger.info "Sensu-server service state was changed"
|
72
|
+
trigger.touch
|
73
|
+
end
|
74
|
+
end
|
75
|
+
sleep 60
|
76
|
+
state.actualize
|
77
|
+
end
|
78
|
+
rescue => e
|
79
|
+
raise ApplicationError, "Generator error:\n\t #{e.to_s}\n\t #{e.backtrace}"
|
80
|
+
end
|
81
|
+
|
82
|
+
def run_server
|
83
|
+
server = Server.new
|
84
|
+
rescue => e
|
85
|
+
server&.close
|
86
|
+
raise ApplicationError, "Server error:\n\t #{e.to_s}\n\t #{e.backtrace}"
|
87
|
+
end
|
88
|
+
|
89
|
+
def run
|
90
|
+
logger.info "Starting application #{VERSION}v in #{config.get[:mode]} mode"
|
91
|
+
threads = %w(generator)
|
92
|
+
if config.get[:mode] == 'server'
|
93
|
+
threads << 'restarter'
|
94
|
+
threads << 'server' if config.get[:server][:port]
|
95
|
+
end
|
96
|
+
threads.each do |thr|
|
97
|
+
@threads << run_thread(thr)
|
98
|
+
end
|
99
|
+
|
100
|
+
loop do
|
101
|
+
@threads.each do |thr|
|
102
|
+
unless thr.alive?
|
103
|
+
@threads.delete thr
|
104
|
+
@threads << run_thread(thr.name)
|
105
|
+
logger.error "#{thr.name.capitalize} is NOT ALIVE. Trying to restart."
|
106
|
+
end
|
107
|
+
end
|
108
|
+
sleep 60
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
def consul
|
115
|
+
@consul ||= Consul.new
|
116
|
+
end
|
117
|
+
|
118
|
+
def generator
|
119
|
+
@generator ||= Generator.new
|
120
|
+
end
|
121
|
+
|
122
|
+
def restarter
|
123
|
+
list = consul.sensu_servers
|
124
|
+
logger.info "Sensu servers discovered: #{list.map(&:address).join(', ')}"
|
125
|
+
Restarter.new(list)
|
126
|
+
end
|
127
|
+
|
128
|
+
def run_thread(name)
|
129
|
+
thr = eval("Thread.new { run_#{name} }")
|
130
|
+
thr.name = name
|
131
|
+
thr
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
module SensuGenerator
|
4
|
+
class CheckFile
|
5
|
+
def self.remove_all_with(prefix)
|
6
|
+
FileUtils.rm(Dir.glob("#{Application.config.result_dir}/#{prefix}*"))
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(filename)
|
10
|
+
@config = Application.config
|
11
|
+
@trigger = Application.trigger
|
12
|
+
@filename = filename
|
13
|
+
@fullpath = File.join(@config.result_dir, @filename)
|
14
|
+
end
|
15
|
+
|
16
|
+
def write(data)
|
17
|
+
file = File.open(@fullpath, 'w+')
|
18
|
+
file.write data
|
19
|
+
file.close
|
20
|
+
@trigger.touch
|
21
|
+
end
|
22
|
+
|
23
|
+
def remove
|
24
|
+
FileUtils.rm @fullpath
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'socket'
|
3
|
+
|
4
|
+
module SensuGenerator
|
5
|
+
class Client
|
6
|
+
def initialize
|
7
|
+
@logger = Application.logger
|
8
|
+
@config = Application.config
|
9
|
+
connection
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_reader :config, :logger
|
13
|
+
|
14
|
+
def connection
|
15
|
+
@connection ||= connect
|
16
|
+
end
|
17
|
+
|
18
|
+
def connect
|
19
|
+
logger.info "Client: connecting to server #{server_addr}:#{server_port}"
|
20
|
+
s = TCPSocket.new(server_addr, server_port)
|
21
|
+
logger.info "Client: connected"
|
22
|
+
s
|
23
|
+
rescue => e
|
24
|
+
raise ClientError, "Client: connection failed #{e.inspect} #{e.backtrace}\n"
|
25
|
+
end
|
26
|
+
|
27
|
+
def write_file(data)
|
28
|
+
connection.puts data
|
29
|
+
logger.info "Client: data transferred successfully"
|
30
|
+
true
|
31
|
+
rescue => e
|
32
|
+
close
|
33
|
+
raise ClientError, "Client: write failed #{e.inspect} #{e.backtrace}\n"
|
34
|
+
end
|
35
|
+
|
36
|
+
def flush_results
|
37
|
+
connection.puts JSON.fast_generate({"FLUSH_WITH_PREFIX" => "#{config.file_prefix}" })
|
38
|
+
rescue => e
|
39
|
+
close
|
40
|
+
raise ClientError, "Client: write failed #{e.inspect} #{e.backtrace}\n"
|
41
|
+
close
|
42
|
+
end
|
43
|
+
|
44
|
+
def close
|
45
|
+
@connection.close
|
46
|
+
@connection = nil
|
47
|
+
logger.info "Client: connection closed"
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def server_addr
|
53
|
+
@server_addr ||= config.get[:server][:addr]
|
54
|
+
end
|
55
|
+
|
56
|
+
def server_port
|
57
|
+
@server_port ||= config.get[:server][:port]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'socket'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module SensuGenerator
|
5
|
+
class Config
|
6
|
+
@@default = {
|
7
|
+
:sensu => {
|
8
|
+
:check_default_params => {
|
9
|
+
:refresh => 86400,
|
10
|
+
:interval => 60,
|
11
|
+
:aggregate => true
|
12
|
+
},
|
13
|
+
:minimal_to_restart => 2,
|
14
|
+
:service => "sensu-server",
|
15
|
+
:rsync_repo => "sensu-server",
|
16
|
+
:supervisor => {:user => "", :password => ""},
|
17
|
+
},
|
18
|
+
:mode => 'server',
|
19
|
+
:server => {
|
20
|
+
:addr => '',
|
21
|
+
:port => nil
|
22
|
+
},
|
23
|
+
:result_dir => "work/result",
|
24
|
+
:templates_dir => "work/templates",
|
25
|
+
:logger => {
|
26
|
+
:file => STDOUT,
|
27
|
+
:notify_level => "error",
|
28
|
+
:log_level => "debug"
|
29
|
+
},
|
30
|
+
:slack => {
|
31
|
+
:url => nil,
|
32
|
+
:channel => nil,
|
33
|
+
:level => "error"
|
34
|
+
},
|
35
|
+
:kv_tags_path => "checks",
|
36
|
+
# See diplomat documentation to set proper consul parameters
|
37
|
+
:consul => {
|
38
|
+
:url => "http://consul.service.consul:8500"
|
39
|
+
}
|
40
|
+
}
|
41
|
+
|
42
|
+
def initialize(path = nil)
|
43
|
+
@config = process(path)
|
44
|
+
end
|
45
|
+
|
46
|
+
def get
|
47
|
+
@config
|
48
|
+
end
|
49
|
+
|
50
|
+
def process(path)
|
51
|
+
custom = path ? JSON(File.read(path), :symbolize_names => true) : {}
|
52
|
+
@config = @@default.deep_merge(custom)
|
53
|
+
end
|
54
|
+
|
55
|
+
def result_dir
|
56
|
+
raise(GeneratorError, "Result dir is not defined!") unless get[:result_dir]
|
57
|
+
File.expand_path(get[:result_dir])
|
58
|
+
end
|
59
|
+
|
60
|
+
def file_prefix
|
61
|
+
@file_prefix ||= get[:mode] == 'server' ? "local_" : "#{Socket.gethostname}_"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module SensuGenerator
|
2
|
+
class ConsulService < Consul
|
3
|
+
|
4
|
+
attr_reader :name, :properties, :checks
|
5
|
+
|
6
|
+
def initialize(name:)
|
7
|
+
@name = name
|
8
|
+
@changed = true
|
9
|
+
super()
|
10
|
+
all_properties
|
11
|
+
self
|
12
|
+
end
|
13
|
+
|
14
|
+
def all_properties
|
15
|
+
properties = get_props.class == Array ? get_props.map {|el| el.to_h} : get_props.to_h
|
16
|
+
@all_properties ||= { checks: get_checks, properties: properties }
|
17
|
+
end
|
18
|
+
|
19
|
+
alias :get_all_properties :all_properties
|
20
|
+
|
21
|
+
def get_checks
|
22
|
+
@checks ||= kv_svc_props(key: config.get[:kv_tags_path])
|
23
|
+
end
|
24
|
+
|
25
|
+
def get_props
|
26
|
+
@properties ||= get_service_props(name)
|
27
|
+
end
|
28
|
+
|
29
|
+
def update
|
30
|
+
old_all_properties = all_properties.clone
|
31
|
+
reset
|
32
|
+
get_all_properties
|
33
|
+
@changed = true if all_properties != old_all_properties
|
34
|
+
end
|
35
|
+
|
36
|
+
def changed?
|
37
|
+
@changed
|
38
|
+
end
|
39
|
+
|
40
|
+
def reset
|
41
|
+
@all_properties = nil
|
42
|
+
@properties = nil
|
43
|
+
@checks = nil
|
44
|
+
@changed = false
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module SensuGenerator
|
2
|
+
class ConsulState < Consul
|
3
|
+
def initialize
|
4
|
+
@actual_state = []
|
5
|
+
super()
|
6
|
+
actualize
|
7
|
+
end
|
8
|
+
|
9
|
+
def show
|
10
|
+
@actual_state
|
11
|
+
end
|
12
|
+
|
13
|
+
def actualize
|
14
|
+
reset
|
15
|
+
@svc_list_diff = services.map {|name, _| name.to_s } - @actual_state.map { |svc| svc.name.to_s}
|
16
|
+
@actual_state.each(&:update)
|
17
|
+
@svc_list_diff.each do |name|
|
18
|
+
@actual_state << ConsulService.new(name: name)
|
19
|
+
end
|
20
|
+
@actualized = true
|
21
|
+
logger.debug "Services actualized list: #{@actual_state.map { |svc| svc.name.to_s} }"
|
22
|
+
self
|
23
|
+
end
|
24
|
+
|
25
|
+
def changed?
|
26
|
+
state = !(@svc_list_diff || []).empty? || !changes.empty?
|
27
|
+
logger.debug "Consul state was changed: #{state.to_s}"
|
28
|
+
state
|
29
|
+
end
|
30
|
+
|
31
|
+
def changes
|
32
|
+
@svc_changes ||= @actual_state.select(&:changed?)
|
33
|
+
end
|
34
|
+
|
35
|
+
def reset
|
36
|
+
@actualized = false
|
37
|
+
@svc_changes = nil
|
38
|
+
@svc_list_diff = nil
|
39
|
+
end
|
40
|
+
|
41
|
+
def actualized?
|
42
|
+
@actualized ? true : false # For the case when nil
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'diplomat'
|
3
|
+
|
4
|
+
module SensuGenerator
|
5
|
+
class Consul
|
6
|
+
attr_writer :config, :logger
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@config = config
|
10
|
+
Diplomat.configure do |consul|
|
11
|
+
config.get[:consul].each do |k, v|
|
12
|
+
consul.public_send("#{k}=", v)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def sensu_servers
|
18
|
+
get_service_props(config.get[:sensu][:service]).map {|el| el.ServiceAddress}.uniq.
|
19
|
+
map {|addr| SensuServer.new(address: addr)}
|
20
|
+
end
|
21
|
+
|
22
|
+
def services
|
23
|
+
Diplomat::Service.get_all.to_h
|
24
|
+
end
|
25
|
+
|
26
|
+
def get_service_props(svc)
|
27
|
+
result = Diplomat::Service.get(svc, :all)
|
28
|
+
result.class == Array ? result.map {|el| el.remove_consul_indexes} : result.remove_consul_indexes
|
29
|
+
end
|
30
|
+
|
31
|
+
def kv_svc_props(svc: name, key: nil)
|
32
|
+
opts = key ? nil : {recurse: true}
|
33
|
+
response = Diplomat::Kv.get("#{svc}/#{key}", opts)
|
34
|
+
key ? JSON(response) : response # Maybe the feature of JSON check configuration will be implemented
|
35
|
+
rescue
|
36
|
+
if response
|
37
|
+
if response.match(/\s+/) || key.to_s == config.get[:kv_tags_path] # tags value is designed to be a list even if it has only one element
|
38
|
+
response.gsub(/\s+/, '').split(',')
|
39
|
+
else
|
40
|
+
response
|
41
|
+
end
|
42
|
+
else
|
43
|
+
[]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def config
|
50
|
+
@config ||= Application.config
|
51
|
+
end
|
52
|
+
|
53
|
+
def logger
|
54
|
+
@logger ||= Application.logger
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class OpenStruct
|
60
|
+
def remove_consul_indexes
|
61
|
+
%w(CreateIndex ModifyIndex).each do |f|
|
62
|
+
self.delete_field(f) if self.respond_to?(f)
|
63
|
+
end
|
64
|
+
self
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module SensuGenerator
|
2
|
+
%w(ApplicationError RestarterError GeneratorError SensuServerError ClientError ServerError).each do |e|
|
3
|
+
eval(
|
4
|
+
%Q(
|
5
|
+
class #{e} < StandardError
|
6
|
+
def initialize(msg)
|
7
|
+
Application.logger.error msg
|
8
|
+
end
|
9
|
+
end
|
10
|
+
)
|
11
|
+
)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module Diplomat
|
16
|
+
class PathNotFound < StandardError
|
17
|
+
def initialize(*args)
|
18
|
+
::SensuGenerator::Application.logger.error "Could not connect to consul with provided url"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|