triglav-agent 1.0.0.pre1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.rspec +2 -0
- data/.travis.yml +6 -0
- data/.yardopts +6 -0
- data/CHANGELOG.md +3 -0
- data/CODE_OF_CONDUCT.md +49 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +21 -0
- data/README.md +59 -0
- data/Rakefile +11 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/docs/Triglav/Agent/ApiClient/AuthenticationError.html +150 -0
- data/docs/Triglav/Agent/ApiClient/ConnectionError.html +150 -0
- data/docs/Triglav/Agent/ApiClient/Error.html +296 -0
- data/docs/Triglav/Agent/ApiClient.html +545 -0
- data/docs/Triglav/Agent/Base/CLI.html +498 -0
- data/docs/Triglav/Agent/Base/Connection.html +258 -0
- data/docs/Triglav/Agent/Base/Monitor.html +370 -0
- data/docs/Triglav/Agent/Base/Processor.html +623 -0
- data/docs/Triglav/Agent/Base/Setting.html +1081 -0
- data/docs/Triglav/Agent/Base/Worker.html +635 -0
- data/docs/Triglav/Agent/Base.html +121 -0
- data/docs/Triglav/Agent/Configuration.html +967 -0
- data/docs/Triglav/Agent/Error.html +130 -0
- data/docs/Triglav/Agent/HashUtil.html +351 -0
- data/docs/Triglav/Agent/LogFormatter.html +271 -0
- data/docs/Triglav/Agent/Logger.html +287 -0
- data/docs/Triglav/Agent/StorageFile.html +1130 -0
- data/docs/Triglav/Agent/Timer.html +424 -0
- data/docs/Triglav/Agent/TooManyError.html +134 -0
- data/docs/Triglav/Agent.html +131 -0
- data/docs/Triglav.html +119 -0
- data/docs/_index.html +335 -0
- data/docs/class_list.html +51 -0
- data/docs/css/common.css +1 -0
- data/docs/css/full_list.css +58 -0
- data/docs/css/style.css +481 -0
- data/docs/file.LICENSE.html +72 -0
- data/docs/file.README.html +137 -0
- data/docs/file_list.html +61 -0
- data/docs/frames.html +17 -0
- data/docs/index.html +137 -0
- data/docs/js/app.js +243 -0
- data/docs/js/full_list.js +216 -0
- data/docs/js/jquery.js +4 -0
- data/docs/method_list.html +659 -0
- data/docs/top-level-namespace.html +112 -0
- data/example/config.yml +40 -0
- data/lib/triglav/agent/api_client.rb +199 -0
- data/lib/triglav/agent/base/cli.rb +98 -0
- data/lib/triglav/agent/base/connection.rb +30 -0
- data/lib/triglav/agent/base/monitor.rb +32 -0
- data/lib/triglav/agent/base/processor.rb +136 -0
- data/lib/triglav/agent/base/setting.rb +112 -0
- data/lib/triglav/agent/base/worker.rb +95 -0
- data/lib/triglav/agent/configuration.rb +79 -0
- data/lib/triglav/agent/error.rb +4 -0
- data/lib/triglav/agent/hash_util.rb +36 -0
- data/lib/triglav/agent/logger.rb +50 -0
- data/lib/triglav/agent/storage_file.rb +144 -0
- data/lib/triglav/agent/timer.rb +80 -0
- data/lib/triglav/agent/version.rb +5 -0
- data/lib/triglav/agent.rb +20 -0
- data/lib/triglav-agent.rb +1 -0
- data/triglav-agent.gemspec +33 -0
- metadata +250 -0
@@ -0,0 +1,112 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6
|
+
<title>
|
7
|
+
Top Level Namespace
|
8
|
+
|
9
|
+
— Documentation by YARD 0.9.5
|
10
|
+
|
11
|
+
</title>
|
12
|
+
|
13
|
+
<link rel="stylesheet" href="css/style.css" type="text/css" charset="utf-8" />
|
14
|
+
|
15
|
+
<link rel="stylesheet" href="css/common.css" type="text/css" charset="utf-8" />
|
16
|
+
|
17
|
+
<script type="text/javascript" charset="utf-8">
|
18
|
+
pathId = "";
|
19
|
+
relpath = '';
|
20
|
+
</script>
|
21
|
+
|
22
|
+
|
23
|
+
<script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
|
24
|
+
|
25
|
+
<script type="text/javascript" charset="utf-8" src="js/app.js"></script>
|
26
|
+
|
27
|
+
|
28
|
+
</head>
|
29
|
+
<body>
|
30
|
+
<div class="nav_wrap">
|
31
|
+
<iframe id="nav" src="class_list.html"></iframe>
|
32
|
+
<div id="resizer"></div>
|
33
|
+
</div>
|
34
|
+
|
35
|
+
<div id="main" tabindex="-1">
|
36
|
+
<div id="header">
|
37
|
+
<div id="menu">
|
38
|
+
|
39
|
+
<a href="_index.html">Index</a> »
|
40
|
+
|
41
|
+
|
42
|
+
<span class="title">Top Level Namespace</span>
|
43
|
+
|
44
|
+
</div>
|
45
|
+
|
46
|
+
<div id="search">
|
47
|
+
|
48
|
+
<a class="full_list_link" id="class_list_link"
|
49
|
+
href="class_list.html">
|
50
|
+
|
51
|
+
<svg width="24" height="24">
|
52
|
+
<rect x="0" y="4" width="24" height="4" rx="1" ry="1"></rect>
|
53
|
+
<rect x="0" y="12" width="24" height="4" rx="1" ry="1"></rect>
|
54
|
+
<rect x="0" y="20" width="24" height="4" rx="1" ry="1"></rect>
|
55
|
+
</svg>
|
56
|
+
</a>
|
57
|
+
|
58
|
+
</div>
|
59
|
+
<div class="clear"></div>
|
60
|
+
</div>
|
61
|
+
|
62
|
+
<iframe id="search_frame" src="class_list.html"></iframe>
|
63
|
+
|
64
|
+
<div id="content"><h1>Top Level Namespace
|
65
|
+
|
66
|
+
|
67
|
+
|
68
|
+
</h1>
|
69
|
+
<div class="box_info">
|
70
|
+
|
71
|
+
|
72
|
+
|
73
|
+
|
74
|
+
|
75
|
+
|
76
|
+
|
77
|
+
|
78
|
+
|
79
|
+
|
80
|
+
|
81
|
+
</div>
|
82
|
+
|
83
|
+
<h2>Defined Under Namespace</h2>
|
84
|
+
<p class="children">
|
85
|
+
|
86
|
+
|
87
|
+
<strong class="modules">Modules:</strong> <span class='object_link'><a href="Triglav.html" title="Triglav (module)">Triglav</a></span>
|
88
|
+
|
89
|
+
|
90
|
+
|
91
|
+
|
92
|
+
</p>
|
93
|
+
|
94
|
+
|
95
|
+
|
96
|
+
|
97
|
+
|
98
|
+
|
99
|
+
|
100
|
+
|
101
|
+
|
102
|
+
</div>
|
103
|
+
|
104
|
+
<div id="footer">
|
105
|
+
Generated on Thu Feb 23 23:20:33 2017 by
|
106
|
+
<a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
107
|
+
0.9.5 (ruby-2.3.2).
|
108
|
+
</div>
|
109
|
+
|
110
|
+
</div>
|
111
|
+
</body>
|
112
|
+
</html>
|
data/example/config.yml
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
defaults: &defaults
|
2
|
+
serverengine:
|
3
|
+
log: 'STDOUT'
|
4
|
+
log_level: 'debug'
|
5
|
+
log_rotate_age: 5
|
6
|
+
log_rotate_size: 10485760
|
7
|
+
triglav:
|
8
|
+
url: <%= ENV['TRIGLAV_URL'] || 'http://localhost:7800' %>
|
9
|
+
credential:
|
10
|
+
username: <%= ENV['TRIGLAV_USERNAME'] || 'triglav_test' %>
|
11
|
+
password: <%= ENV['TRIGLAV_PASSWORD'] || 'triglav_test' %>
|
12
|
+
authenticator: local
|
13
|
+
timeout: 60
|
14
|
+
debugging: false
|
15
|
+
retries: 3
|
16
|
+
retry_interval: 3 # sec
|
17
|
+
vertica:
|
18
|
+
monitor_interval: 5
|
19
|
+
parallel_size: 1 # default: 1
|
20
|
+
parallel_type: 'thread' # thread or process. default: thread
|
21
|
+
connection_pool_size: 1 # default: same with parallel.size
|
22
|
+
connection_pool_timeout: 60 # sec. default: 60
|
23
|
+
date_column: d
|
24
|
+
timestamp_column: t
|
25
|
+
connection_info:
|
26
|
+
"vertica://":
|
27
|
+
host: <%= ENV['VERTICA_HOST'] %>
|
28
|
+
port: <%= ENV['VERTICA_PORT'] %>
|
29
|
+
database: <%= ENV['VERTICA_DATABASE'] %>
|
30
|
+
user: <%= ENV['VERTICA_USER'] %>
|
31
|
+
password: <%= ENV['VERTICA_PASSWORD'] %>
|
32
|
+
resource_pool: <%= ENV['VERTICA_RESOURCE_POOL'] %>
|
33
|
+
interruptable: true
|
34
|
+
read_timeout: 5
|
35
|
+
|
36
|
+
development:
|
37
|
+
<<: *defaults
|
38
|
+
|
39
|
+
test:
|
40
|
+
<<: *defaults
|
@@ -0,0 +1,199 @@
|
|
1
|
+
require 'triglav/agent/storage_file'
|
2
|
+
require 'triglav_client'
|
3
|
+
|
4
|
+
module Triglav::Agent
|
5
|
+
# This Triglav client connects to triglav API with $setting.triglav.url,
|
6
|
+
# and authenticates with $setting.triglav.credential, and
|
7
|
+
# stores the token into $setting.token_file.
|
8
|
+
#
|
9
|
+
# Re-authenticate automatically if token is expired
|
10
|
+
#
|
11
|
+
# require 'triglav/agent/api_client'
|
12
|
+
#
|
13
|
+
# api_client = Triglav::Agent::ApiClient.new
|
14
|
+
# resources = api_client.list_resources(uri_prefix)
|
15
|
+
# resources.each do |resource|
|
16
|
+
# events = get_events(resource) # implement this!
|
17
|
+
# api_client.send_messages(events)
|
18
|
+
# end
|
19
|
+
class ApiClient
|
20
|
+
class Error < StandardError
|
21
|
+
attr_reader :cause
|
22
|
+
def initialize(message, cause)
|
23
|
+
@cause = cause
|
24
|
+
super(message)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
class AuthenticationError < Error; end
|
28
|
+
class ConnectionError < Error; end
|
29
|
+
|
30
|
+
# Initialize TriglavClient
|
31
|
+
def initialize(opts = {})
|
32
|
+
@opts = opts || {}
|
33
|
+
config = TriglavClient::Configuration.new do |config|
|
34
|
+
uri = URI.parse(triglav_url)
|
35
|
+
config.scheme = uri.scheme
|
36
|
+
config.host = "#{uri.host}:#{uri.port}"
|
37
|
+
config.timeout = timeout if timeout
|
38
|
+
config.debugging = debugging if debugging
|
39
|
+
end
|
40
|
+
@api_client = TriglavClient::ApiClient.new(config)
|
41
|
+
initialize_current_token
|
42
|
+
authenticate
|
43
|
+
end
|
44
|
+
|
45
|
+
def close
|
46
|
+
# typhoeus makes a new connection and disconnects it on each request
|
47
|
+
end
|
48
|
+
|
49
|
+
# List resources required to be monitored
|
50
|
+
#
|
51
|
+
# @param [String] uri_prefix
|
52
|
+
# @return [Array of TriglavClient::ResourceEachResponse] array of resources
|
53
|
+
# @see TriglavClient::ResourceEachResponse
|
54
|
+
def list_aggregated_resources(uri_prefix)
|
55
|
+
$logger.debug { "ApiClient#list_aggregated_resources(#{uri_prefix.inspect})" }
|
56
|
+
resources_api = TriglavClient::ResourcesApi.new(@api_client)
|
57
|
+
handle_error { resources_api.list_aggregated_resources(uri_prefix) }
|
58
|
+
end
|
59
|
+
|
60
|
+
# Send messages
|
61
|
+
#
|
62
|
+
# @param [Array of TriglavClient::MessageRequest] array of event messages
|
63
|
+
# @see TriglavClient::MessageRequest
|
64
|
+
def send_messages(events)
|
65
|
+
$logger.debug { "ApiClient#send_messages(#{events.inspect})" }
|
66
|
+
messages_api = TriglavClient::MessagesApi.new(@api_client)
|
67
|
+
handle_error { messages_api.send_messages(events) }
|
68
|
+
end
|
69
|
+
|
70
|
+
def authorized?
|
71
|
+
@current_token.has_key?(:access_token)
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
# Authenticate
|
77
|
+
#
|
78
|
+
# 1. Another process saved a newer token onto the token_file => read it
|
79
|
+
# 2. The token saved on the token_file is same with current token => re-authenticate
|
80
|
+
# 3. The token saved on the token_file is older than the current token
|
81
|
+
# => unknown situation, re-authenticate and save into token_file to refresh anyway
|
82
|
+
# 4. No token is saved on the token_file => authenticate
|
83
|
+
def authenticate
|
84
|
+
$logger.debug { 'ApiClient#authenticate' }
|
85
|
+
StorageFile.open(token_file) do |fp|
|
86
|
+
token = fp.load
|
87
|
+
if should_read_token_from_file?(token)
|
88
|
+
$logger.debug { "Read token from file" }
|
89
|
+
update_current_token(token)
|
90
|
+
return
|
91
|
+
end
|
92
|
+
$logger.debug { "AuthApi#create_token" }
|
93
|
+
auth_api = TriglavClient::AuthApi.new(@api_client)
|
94
|
+
credential = TriglavClient::Credential.new(
|
95
|
+
username: username, password: password, authenticator: authenticator
|
96
|
+
)
|
97
|
+
handle_auth_error do
|
98
|
+
$logger.debug { 'TriglavClient::AuthApi' }
|
99
|
+
result = auth_api.create_token(credential)
|
100
|
+
token = {access_token: result.access_token}
|
101
|
+
update_current_token(token)
|
102
|
+
fp.dump(token)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def initialize_current_token
|
108
|
+
@current_token = {
|
109
|
+
access_token: (@api_client.config.api_key['Authorization'] = String.new),
|
110
|
+
}
|
111
|
+
end
|
112
|
+
|
113
|
+
def update_current_token(token)
|
114
|
+
@current_token[:access_token].replace(token[:access_token])
|
115
|
+
end
|
116
|
+
|
117
|
+
def should_read_token_from_file?(token)
|
118
|
+
return true if @current_token[:access_token].empty? && !(token[:access_token] ||= '').empty?
|
119
|
+
return @current_token[:access_token] != token[:access_token]
|
120
|
+
end
|
121
|
+
|
122
|
+
def handle_auth_error(&block)
|
123
|
+
retries = 0
|
124
|
+
begin
|
125
|
+
yield
|
126
|
+
rescue TriglavClient::ApiError => e
|
127
|
+
if e.code == 0
|
128
|
+
if retries < max_retries
|
129
|
+
sleep retry_interval
|
130
|
+
retries += 1
|
131
|
+
retry
|
132
|
+
end
|
133
|
+
raise ConnectionError.new("Could not connect to #{triglav_url} with #{retries} retries", e)
|
134
|
+
elsif e.message == 'Unauthorized'.freeze
|
135
|
+
raise AuthenticationError.new("Failed to authenticate on triglav API.".freeze, e)
|
136
|
+
else
|
137
|
+
raise Error.new(e.message, e)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def handle_error(&block)
|
143
|
+
retries = 0
|
144
|
+
begin
|
145
|
+
yield
|
146
|
+
rescue TriglavClient::ApiError => e
|
147
|
+
if e.code == 0
|
148
|
+
if retries < max_retries
|
149
|
+
sleep retry_interval
|
150
|
+
retries += 1
|
151
|
+
retry
|
152
|
+
end
|
153
|
+
raise ConnectionError.new("Could not connect to #{triglav_url} with #{retries} retries", e)
|
154
|
+
elsif e.message == 'Unauthorized'.freeze
|
155
|
+
authenticate
|
156
|
+
retry
|
157
|
+
else
|
158
|
+
raise Error.new(e.message, e)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def triglav_url
|
164
|
+
@opts[:url] || $setting.dig(:triglav, :url)
|
165
|
+
end
|
166
|
+
|
167
|
+
def username
|
168
|
+
@opts.dig(:credential, :username) || $setting.dig(:triglav, :credential, :username)
|
169
|
+
end
|
170
|
+
|
171
|
+
def password
|
172
|
+
@opts.dig(:credential, :password) || $setting.dig(:triglav, :credential, :password)
|
173
|
+
end
|
174
|
+
|
175
|
+
def authenticator
|
176
|
+
@opts.dig(:credential, :authenticator) || $setting.dig(:triglav, :credential, :authenticator)
|
177
|
+
end
|
178
|
+
|
179
|
+
def timeout
|
180
|
+
@opts[:timeout] || $setting.dig(:triglav, :timeout)
|
181
|
+
end
|
182
|
+
|
183
|
+
def debugging
|
184
|
+
@opts[:debugging] || $setting.dig(:triglav, :debugging)
|
185
|
+
end
|
186
|
+
|
187
|
+
def max_retries
|
188
|
+
@opts[:retries] || $setting.dig(:triglav, :retries) || 3
|
189
|
+
end
|
190
|
+
|
191
|
+
def retry_interval
|
192
|
+
@opts[:retry_interval] || $setting.dig(:triglav, :retry_interval) || 3 # second
|
193
|
+
end
|
194
|
+
|
195
|
+
def token_file
|
196
|
+
@opts[:token_file] || $setting.token_file
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require "triglav/agent/configuration"
|
2
|
+
require "triglav/agent/base/setting"
|
3
|
+
require 'optparse'
|
4
|
+
require 'serverengine'
|
5
|
+
|
6
|
+
module Triglav::Agent
|
7
|
+
module Base
|
8
|
+
# A base class for cli option parser
|
9
|
+
#
|
10
|
+
# This base class usually should be enough for agent plugins, but
|
11
|
+
# you can override this class and configure with Configuration#cli_classe=
|
12
|
+
class CLI
|
13
|
+
def run
|
14
|
+
opts, _ = parse_options(ARGV)
|
15
|
+
$setting = Configuration.setting_class.new(opts)
|
16
|
+
$logger = $setting.logger
|
17
|
+
se = ServerEngine.create(nil, Configuration.worker_module) do
|
18
|
+
$setting.serverengine_options
|
19
|
+
end
|
20
|
+
se.run
|
21
|
+
end
|
22
|
+
|
23
|
+
def default_opts
|
24
|
+
{
|
25
|
+
config: 'config.yml',
|
26
|
+
dotenv: false,
|
27
|
+
debug: false,
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
def option_parser(opts = {})
|
32
|
+
op = OptionParser.new
|
33
|
+
|
34
|
+
self.class.module_eval do
|
35
|
+
define_method(:usage) do |msg = nil|
|
36
|
+
puts op.to_s
|
37
|
+
puts "error: #{msg}" if msg
|
38
|
+
exit 1
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
op.on('-c', '--config VALUE', "Config file (default: #{opts[:config]})") {|v|
|
43
|
+
opts[:config] = v
|
44
|
+
}
|
45
|
+
op.on('-s', '--status VALUE', "Status stroage file (default: status.yml)") {|v|
|
46
|
+
opts[:status] = v
|
47
|
+
}
|
48
|
+
op.on('-t', '--token VALUE', "Triglav access token storage file (default: token.yml)") {|v|
|
49
|
+
opts[:token] = v
|
50
|
+
}
|
51
|
+
op.on('--dotenv', "Load environment variables from .env file (default: #{opts[:dotenv]})") {|v|
|
52
|
+
opts[:dotenv] = v
|
53
|
+
}
|
54
|
+
op.on('--debug', "Debug mode (default: #{opts[:debug]})") {|v|
|
55
|
+
opts[:debug] = v
|
56
|
+
}
|
57
|
+
op.on('-h', '--help', "help") {|v|
|
58
|
+
opts[:help] = v
|
59
|
+
}
|
60
|
+
# serverengine options
|
61
|
+
op.on('--log VALUE', "Log path (default: #{Setting::DEFAULT_LOG})") {|v|
|
62
|
+
opts[:log] = v
|
63
|
+
}
|
64
|
+
op.on('--log-level VALUE', "Log level (default: #{Setting::DEFAULT_LOG_LEVEL})") {|v|
|
65
|
+
opts[:log_level] = v
|
66
|
+
}
|
67
|
+
|
68
|
+
op.banner += ''
|
69
|
+
|
70
|
+
op
|
71
|
+
end
|
72
|
+
|
73
|
+
def parse_options(argv = ARGV)
|
74
|
+
opts = default_opts
|
75
|
+
op = option_parser(opts)
|
76
|
+
|
77
|
+
begin
|
78
|
+
args = op.parse(argv)
|
79
|
+
rescue OptionParser::InvalidOption => e
|
80
|
+
usage e.message
|
81
|
+
end
|
82
|
+
|
83
|
+
if opts[:help]
|
84
|
+
usage
|
85
|
+
end
|
86
|
+
|
87
|
+
if opts[:config].nil?
|
88
|
+
usage "--config VALUE is required"
|
89
|
+
end
|
90
|
+
if !File.readable?(opts[:config])
|
91
|
+
usage "Config file '#{opts[:config]}' does not exist or not readable"
|
92
|
+
end
|
93
|
+
|
94
|
+
[opts, args]
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Triglav::Agent
|
2
|
+
module Base
|
3
|
+
# An abstract base class of Connection.
|
4
|
+
#
|
5
|
+
# Wrap a connection to a storage.
|
6
|
+
# You can implement any methods which you want to use in your Monitor class.
|
7
|
+
#
|
8
|
+
# You have to implement following methods:
|
9
|
+
#
|
10
|
+
# * initialize
|
11
|
+
# * close
|
12
|
+
#
|
13
|
+
# An instance is created for each `resource_uri_prefix`, that is,
|
14
|
+
# shared among resources with of same `resource_uri_prefix`.
|
15
|
+
#
|
16
|
+
# Note that multiple connection instances would be created
|
17
|
+
# when multiple parallel threads are created in Processor class.
|
18
|
+
class Connection
|
19
|
+
# @param [Hash] connection_info
|
20
|
+
def initialize(connection_info)
|
21
|
+
raise NotImplementedError
|
22
|
+
end
|
23
|
+
|
24
|
+
# close the connection
|
25
|
+
def close
|
26
|
+
raise NotImplementedError
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Triglav::Agent
|
2
|
+
module Base
|
3
|
+
# An abstract class of Monitor.
|
4
|
+
#
|
5
|
+
# Monitor your storage and send messages to triglav.
|
6
|
+
#
|
7
|
+
# You have to implement following methods:
|
8
|
+
#
|
9
|
+
# * initialize
|
10
|
+
# * process
|
11
|
+
#
|
12
|
+
# An instance is created per a `resource`.
|
13
|
+
# Connection is shared among same `resource_uri_prefix`.
|
14
|
+
#
|
15
|
+
# Note that multiple instances would be created,
|
16
|
+
# one instance for one parallel thread basically, and
|
17
|
+
# `#process` is ran concurrently.
|
18
|
+
class Monitor
|
19
|
+
# @param [Triglav::Agent::Base::Connection] connection
|
20
|
+
# @param [TriglavClient::ResourceResponse] resource
|
21
|
+
def initialize(connection, resource)
|
22
|
+
raise NotImplementedError
|
23
|
+
end
|
24
|
+
|
25
|
+
# @yield [events] Gives an array of events
|
26
|
+
def process(&block)
|
27
|
+
raise NotImplementedError
|
28
|
+
# yield(events) if block_given?
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
require 'parallel'
|
2
|
+
require 'connection_pool'
|
3
|
+
|
4
|
+
module Triglav::Agent
|
5
|
+
module Base
|
6
|
+
# Triglav agent processor class.
|
7
|
+
#
|
8
|
+
# An instance is created for a `resource_uri_prefix`.
|
9
|
+
#
|
10
|
+
# You usually do not need to customize this class, but if you want to
|
11
|
+
# implement your original, configure
|
12
|
+
#
|
13
|
+
# Triglav::Agent::Configuration.processor_class
|
14
|
+
class Processor
|
15
|
+
attr_reader :worker, :resource_uri_prefix
|
16
|
+
|
17
|
+
def initialize(worker, resource_uri_prefix)
|
18
|
+
@worker = worker
|
19
|
+
@resource_uri_prefix = resource_uri_prefix
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.max_consecuitive_error_count
|
23
|
+
3
|
24
|
+
end
|
25
|
+
|
26
|
+
def process
|
27
|
+
before_process
|
28
|
+
success_count = 0
|
29
|
+
consecutive_error_count = 0
|
30
|
+
Parallel.each(resources, parallel_opts) do |resource|
|
31
|
+
raise Parallel::Break if stopped?
|
32
|
+
events = nil
|
33
|
+
begin
|
34
|
+
@connection_pool.with do |connection|
|
35
|
+
monitor = monitor_class.new(connection, resource)
|
36
|
+
monitor.process do |_events|
|
37
|
+
events = _events
|
38
|
+
$logger.info { "send_messages:#{events.map(&:to_hash).to_json}" }
|
39
|
+
@api_client_pool.with {|api_client| api_client.send_messages(events) }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
@mutex.synchronize do
|
43
|
+
success_count += 1
|
44
|
+
consecutive_error_count = 0
|
45
|
+
end
|
46
|
+
rescue => e
|
47
|
+
log_error(e)
|
48
|
+
$logger.info { "failed_events:#{events.map(&:to_hash).to_json}" } if events
|
49
|
+
@mutex.synchronize do
|
50
|
+
raise TooManyError if (consecutive_error_count += 1) > self.class.max_consecuitive_error_count
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
success_count
|
55
|
+
ensure
|
56
|
+
after_process
|
57
|
+
end
|
58
|
+
|
59
|
+
def total_count
|
60
|
+
resources.size
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def before_process
|
66
|
+
@connection_pool = ConnectionPool.new(connection_pool_opts) {
|
67
|
+
connection_class.new(get_connection_info(resource_uri_prefix))
|
68
|
+
}
|
69
|
+
@api_client_pool = ConnectionPool.new(connection_pool_opts) {
|
70
|
+
ApiClient.new # renew connection
|
71
|
+
}
|
72
|
+
@mutex = Mutex.new
|
73
|
+
end
|
74
|
+
|
75
|
+
def after_process
|
76
|
+
@connection_pool.shutdown {|conn| conn.close rescue nil }
|
77
|
+
@api_client_pool.shutdown {|conn| conn.close rescue nil }
|
78
|
+
end
|
79
|
+
|
80
|
+
def connection_class
|
81
|
+
Configuration.connection_class
|
82
|
+
end
|
83
|
+
|
84
|
+
def monitor_class
|
85
|
+
Configuration.monitor_class
|
86
|
+
end
|
87
|
+
|
88
|
+
def name
|
89
|
+
Configuration.name
|
90
|
+
end
|
91
|
+
|
92
|
+
def resources
|
93
|
+
return @resources if @resources
|
94
|
+
@resources = ApiClient.new.list_aggregated_resources(resource_uri_prefix) || []
|
95
|
+
$logger.debug { "resource_uri_prefix:#{resource_uri_prefix} resources.size:#{@resources.size}" }
|
96
|
+
@resources
|
97
|
+
end
|
98
|
+
|
99
|
+
def parallel_opts
|
100
|
+
parallel_type == 'process' ? {in_processes: parallel_size} : {in_threads: parallel_size}
|
101
|
+
end
|
102
|
+
|
103
|
+
def connection_pool_opts
|
104
|
+
{size: connection_pool_size, timeout: connection_pool_timeout}
|
105
|
+
end
|
106
|
+
|
107
|
+
def parallel_size
|
108
|
+
$setting.dig(name, :parallel_size) || 1
|
109
|
+
end
|
110
|
+
|
111
|
+
def parallel_type
|
112
|
+
$setting.dig(name, :parallel_type) || 'thread'
|
113
|
+
end
|
114
|
+
|
115
|
+
def connection_pool_size
|
116
|
+
$setting.dig(name, :connection_pool_size) || parallel_size
|
117
|
+
end
|
118
|
+
|
119
|
+
def connection_pool_timeout
|
120
|
+
$setting.dig(name, :connection_pool_timeout) || 60
|
121
|
+
end
|
122
|
+
|
123
|
+
def get_connection_info(resource_uri_prefix)
|
124
|
+
$setting.dig(name, :connection_info)[resource_uri_prefix]
|
125
|
+
end
|
126
|
+
|
127
|
+
def log_error(e)
|
128
|
+
$logger.error { "#{e.class} #{e.message} #{e.backtrace.join("\\n")}" } # one line
|
129
|
+
end
|
130
|
+
|
131
|
+
def stopped?
|
132
|
+
worker.stopped? if worker and worker.respond_to?(:stopped?)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|