fluent-plugin-spectrum 0.0.3 → 0.0.5
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 +4 -4
- data/.gitignore +17 -0
- data/.travis.yml +14 -0
- data/README.md +14 -2
- data/fluent-plugin-spectrum.gemspec +5 -5
- data/lib/fluent/plugin/in_spectrum.rb +172 -96
- data/lib/fluent/plugin/out_spectrum.rb +193 -0
- data/sample/spectrum.conf.advanced_sample +35 -0
- data/sample/spectrum.conf.sample +10 -5
- data/test/plugin/test_in_spectrum.rb +5 -5
- metadata +28 -24
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b6ce4a6b4bf074348bde00e83c87e8559e07549c
|
4
|
+
data.tar.gz: cf2079f18bffc80dee8fe1c547d26460ff2a862e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dde69f607871058aa60138bd5a177323a0e0fac45ff6b62c0f13ef74699a5b948974161759b1417609abf02f0e01fc16bb26c5da60971da4dcbc85e6909c83dd
|
7
|
+
data.tar.gz: 656594019157e6a2555673e9d61094d89a420533c7fca7b1c0d6b909d5e669701edd895618c0b75e47af5c2c5438504dcab801101bbb0486dde1d14578aab052
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/README.md
CHANGED
@@ -2,6 +2,11 @@
|
|
2
2
|
|
3
3
|
fluent-plugin-spectrum is an input plug-in for [Fluentd](http://fluentd.org)
|
4
4
|
|
5
|
+
## Status
|
6
|
+
[](http://badge.fury.io/rb/fluent-plugin-spectrum)
|
7
|
+
[](https://travis-ci.org/Bigel0w/fluent-plugin-spectrum)
|
8
|
+
[](https://coveralls.io/r/Bigel0w/fluent-plugin-spectrum?branch=master)
|
9
|
+
|
5
10
|
## Installation
|
6
11
|
|
7
12
|
These instructions assume you already have fluentd installed.
|
@@ -77,9 +82,16 @@ Now startup fluentd
|
|
77
82
|
|
78
83
|
$ sudo fluentd -c fluent.conf &
|
79
84
|
|
80
|
-
|
85
|
+
Verify:
|
86
|
+
|
87
|
+
You should see output like the following if you have events in spectrum and connectivity works.
|
88
|
+
|
89
|
+
FluentD Log Lines:
|
90
|
+
2015-03-05 15:04:02 -0800 [info]: Spectrum :: Polling alerts for time period: 1425596639 - 1425596642
|
91
|
+
2015-03-05 15:04:07 -0800 [info]: Spectrum :: returned 1 alarms for period 1425596639 - 1425596647
|
81
92
|
|
82
|
-
|
93
|
+
Output:
|
94
|
+
2015-03-05 15:04:00 -0800 alert.spectrum: {"event_type":"alert.spectrum","intermediary_source":"spectrumapi001.corp.yourdomain.net","ALARM_ID":"54f8e0e0-e706-12c2-0165-005056a07ac5","CREATION_DATE":"1425596640","SEVERITY":"3","ALARM_TITLE":"LOGMATCH TRAPSEND CRIT","HOSTNAME":"yourhost001.corp.yourdomain.net","IP_ADDRESS":"10.10.0.14","ORIGINATING_EVENT_ATTR":"A SEC logmatch trapsend CRIT Your Alert Message here","MODEL_STRING":"Host_Device","ACKNOWLEDGED":"false","ALARM_STATUS":"","OCCURRENCES":"1","TROUBLE_SHOOTER":"","USER_CLEARABLE":"true","TROUBLE_TICKET_ID":"","PERSISTENT":"true","GC_NAME":"Your_Global_Collection"}
|
83
95
|
|
84
96
|
## To Do
|
85
97
|
* Add retry login. On timeout/failure retry, how often, increasing delay? (how would that affect polling time, possible duplicates?)
|
@@ -3,12 +3,12 @@ $:.push File.expand_path("../lib", __FILE__)
|
|
3
3
|
|
4
4
|
Gem::Specification.new do |gem|
|
5
5
|
gem.name = "fluent-plugin-spectrum"
|
6
|
-
gem.version = "0.0.
|
7
|
-
gem.date = '2015-
|
6
|
+
gem.version = "0.0.5"
|
7
|
+
gem.date = '2015-03-31'
|
8
8
|
gem.authors = ["Alex Pena"]
|
9
|
-
gem.email = ["
|
10
|
-
gem.summary = %q{Fluentd input plugin for Spectrum
|
11
|
-
gem.description = %q{Fluentd plugin for
|
9
|
+
gem.email = ["pena.alex@gmail.com"]
|
10
|
+
gem.summary = %q{Fluentd input plugin for pulling alerts from CA Spectrum}
|
11
|
+
gem.description = %q{Fluentd plugin for pulling monitoring alerts from CA Spectrum}
|
12
12
|
gem.homepage = 'https://github.com/Bigel0w/fluent-plugin-spectrum'
|
13
13
|
gem.license = 'MIT'
|
14
14
|
|
@@ -1,27 +1,72 @@
|
|
1
1
|
module Fluent
|
2
|
-
# TODO:
|
3
|
-
# Add a fields all or list option
|
4
|
-
# error checking in every section
|
5
|
-
# class for handling interval in loop
|
6
|
-
class TimerWatcher < Coolio::TimerWatcher
|
7
|
-
def initialize(interval, repeat, &callback)
|
8
|
-
@callback = callback
|
9
|
-
super(interval, repeat)
|
10
|
-
end # def initialize
|
11
|
-
def on_timer
|
12
|
-
@callback.call
|
13
|
-
end # def on_timer
|
14
|
-
end
|
15
|
-
|
16
2
|
class SpectrumInput < Input
|
17
3
|
Fluent::Plugin.register_input('spectrum', self)
|
18
4
|
config_param :tag, :string, :default => "alert.spectrum"
|
19
|
-
config_param :endpoint, :string, :default =>
|
20
|
-
config_param :
|
21
|
-
config_param :
|
22
|
-
config_param :
|
23
|
-
|
24
|
-
config_param :
|
5
|
+
config_param :endpoint, :string, :default => nil
|
6
|
+
config_param :username, :string, :default => nil
|
7
|
+
config_param :password, :string, :default => nil
|
8
|
+
config_param :interval, :integer, :default => 300 # shoud stay above 10, avg response is 5-7 seconds
|
9
|
+
|
10
|
+
config_param :state_file, :string, :default => nil
|
11
|
+
config_param :include_raw, :string, :default => "false"
|
12
|
+
config_param :attributes, :string, :default => "ALL"
|
13
|
+
config_param :select_limit, :time, :default => 10000
|
14
|
+
|
15
|
+
# Classes
|
16
|
+
class TimerWatcher < Coolio::TimerWatcher
|
17
|
+
def initialize(interval, repeat, &callback)
|
18
|
+
@callback = callback
|
19
|
+
super(interval, repeat)
|
20
|
+
end # def initialize
|
21
|
+
|
22
|
+
def on_timer
|
23
|
+
@callback.call
|
24
|
+
rescue
|
25
|
+
$log.error $!.to_s
|
26
|
+
$log.error_backtrace
|
27
|
+
end # def on_timer
|
28
|
+
end
|
29
|
+
|
30
|
+
class StateStore
|
31
|
+
def initialize(path)
|
32
|
+
require 'yaml'
|
33
|
+
@path = path
|
34
|
+
if File.exists?(@path)
|
35
|
+
@data = YAML.load_file(@path)
|
36
|
+
if @data == false || @data == []
|
37
|
+
# this happens if an users created an empty file accidentally
|
38
|
+
@data = {}
|
39
|
+
elsif !@data.is_a?(Hash)
|
40
|
+
raise "state_file on #{@path.inspect} is invalid"
|
41
|
+
end
|
42
|
+
else
|
43
|
+
@data = {}
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def last_records
|
48
|
+
@data['last_records'] ||= {}
|
49
|
+
end
|
50
|
+
|
51
|
+
def update!
|
52
|
+
File.open(@path, 'w') {|f|
|
53
|
+
f.write YAML.dump(@data)
|
54
|
+
}
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
class MemoryStateStore
|
59
|
+
def initialize
|
60
|
+
@data = {}
|
61
|
+
end
|
62
|
+
|
63
|
+
def last_records
|
64
|
+
@data['last_records'] ||= {}
|
65
|
+
end
|
66
|
+
|
67
|
+
def update!
|
68
|
+
end
|
69
|
+
end
|
25
70
|
|
26
71
|
# function to UTF8 encode
|
27
72
|
def to_utf8(str)
|
@@ -45,6 +90,11 @@ module Fluent
|
|
45
90
|
def configure(conf)
|
46
91
|
super
|
47
92
|
@conf = conf
|
93
|
+
|
94
|
+
unless @state_file
|
95
|
+
$log.warn "'state_file PATH' parameter is not set to a valid source."
|
96
|
+
$log.warn "this parameter is highly recommended to save the last known good timestamp to resume event consuming"
|
97
|
+
end
|
48
98
|
# map of Spectrum attribute codes to names
|
49
99
|
@spectrum_access_code={
|
50
100
|
"0x11f9c" => "ALARM_ID",
|
@@ -64,7 +114,6 @@ module Fluent
|
|
64
114
|
"0x12942" => "PERSISTENT",
|
65
115
|
"0x12adb" => "GC_NAME",
|
66
116
|
"0x57f0105" => "Custom_Project",
|
67
|
-
"0x11f4d" => "ACKNOWLEDGED",
|
68
117
|
#{}"0x11f51" => "CLEARED_BY_USER_NAME",
|
69
118
|
#{}"0x11f52" => "EVENT_ID_LIST",
|
70
119
|
#{}"0x11f53" => "MODEL_HANDLE",
|
@@ -95,78 +144,124 @@ module Fluent
|
|
95
144
|
@spectrum_access_code.each do |key, array|
|
96
145
|
@attr_of_interest += " <rs:requested-attribute id=\"#{key}\"/>"
|
97
146
|
end
|
147
|
+
|
98
148
|
# Setup URL Resource
|
99
|
-
|
100
|
-
|
101
|
-
RestClient::Resource.new(@url
|
149
|
+
def resource
|
150
|
+
@url = 'http://' + @endpoint.to_s + '/spectrum/restful/alarms'
|
151
|
+
RestClient::Resource.new(@url, :user => @username, :password => @password, :open_timeout => 3, :timeout => (@interval * 2))
|
102
152
|
end
|
153
|
+
|
154
|
+
### need to add this but first figure out how to pass a one time override for timeout since get takes a longtime to return
|
155
|
+
#test = resource.get
|
156
|
+
#if test.code.to_s == 200
|
157
|
+
# $log.info "Spectrum :: Config testing #{@endpoint} succeeded with #{test.code.to_s} response code"
|
158
|
+
#else
|
159
|
+
# raise Fluent::ConfigError, "http test failed"
|
160
|
+
#end
|
103
161
|
end # def configure
|
104
162
|
|
105
|
-
def start
|
106
|
-
|
163
|
+
def start
|
164
|
+
@stop_flag = false
|
165
|
+
@state_store = @state_file.nil? ? MemoryStateStore.new : StateStore.new(@state_file)
|
107
166
|
@loop = Coolio::Loop.new
|
108
|
-
|
109
|
-
timer_trigger.attach(@loop)
|
167
|
+
@loop.attach(TimerWatcher.new(@interval, true, &method(:on_timer)))
|
110
168
|
@thread = Thread.new(&method(:run))
|
111
|
-
$log.info "Spectrum :: starting poller, endpoint #{@endpoint} interval #{@interval}"
|
112
169
|
end # def start
|
113
170
|
|
114
171
|
def shutdown
|
115
|
-
|
172
|
+
#@loop.watchers.each {|w| w.detach}
|
173
|
+
@stop_flag = true
|
116
174
|
@loop.stop
|
117
175
|
@thread.join
|
118
|
-
rescue
|
119
|
-
$log.error "Spectrum :: unexpected error", :error=>$!.to_s
|
120
|
-
$log.error_backtrace
|
121
176
|
end # def shutdown
|
122
177
|
|
123
178
|
def run
|
124
179
|
@loop.run
|
125
180
|
rescue
|
126
|
-
|
127
|
-
|
181
|
+
$log.error "unexpected error", :error=>$!.to_s
|
182
|
+
$log.error_backtrace
|
128
183
|
end # def run
|
129
184
|
|
130
|
-
def
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
<
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
#
|
162
|
-
|
185
|
+
def on_timer
|
186
|
+
if not @stop_flag
|
187
|
+
pollingStart = Engine.now.to_i
|
188
|
+
if @state_store.last_records.has_key?("spectrum")
|
189
|
+
alertStartTime = @state_store.last_records['spectrum']
|
190
|
+
#$log.info "Spectrum :: Got time record from state_store - #{alertStartTime}"
|
191
|
+
else
|
192
|
+
alertStartTime = (pollingStart.to_i - @interval.to_i)
|
193
|
+
#$log.info "Spectrum :: Got time record from initial config - #{alertStartTime}"
|
194
|
+
end
|
195
|
+
pollingEnd = ''
|
196
|
+
pollingDuration = ''
|
197
|
+
#$log.info "Spectrum :: Polling alerts for time period < #{alertStartTime.to_i}"
|
198
|
+
|
199
|
+
# Format XML for spectrum post
|
200
|
+
@xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
|
201
|
+
<rs:alarm-request throttlesize=\"#{select_limit}\"
|
202
|
+
xmlns:rs=\"http://www.ca.com/spectrum/restful/schema/request\"
|
203
|
+
xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
|
204
|
+
xsi:schemaLocation=\"http://www.ca.com/spectrum/restful/schema/request ../../../xsd/Request.xsd \">
|
205
|
+
<rs:attribute-filter>
|
206
|
+
<search-criteria xmlns=\"http://www.ca.com/spectrum/restful/schema/filter\">
|
207
|
+
<filtered-models>
|
208
|
+
<greater-than>
|
209
|
+
<attribute id=\"0x11f4e\">
|
210
|
+
<value> #{alertStartTime} </value>
|
211
|
+
</attribute>
|
212
|
+
</greater-than>
|
213
|
+
</filtered-models>
|
214
|
+
</search-criteria>
|
215
|
+
</rs:attribute-filter>
|
216
|
+
#{@attr_of_interest}
|
217
|
+
</rs:alarm-request>"
|
218
|
+
|
219
|
+
# Post to Spectrum and parse results
|
220
|
+
begin
|
221
|
+
res=resource.post @xml,:content_type => 'application/xml',:accept => 'application/json'
|
222
|
+
#$log.info "Response code #{res.code.to_s}"
|
223
|
+
body = JSON.parse(res.body)
|
224
|
+
pollingEnd = Engine.now.to_i
|
225
|
+
@state_store.last_records['spectrum'] = pollingEnd
|
226
|
+
pollingDuration = pollingEnd - pollingStart
|
227
|
+
end
|
228
|
+
|
229
|
+
# Processing for multiple alerts returned
|
230
|
+
if body['ns1.alarm-response-list']['@total-alarms'].to_i > 1
|
231
|
+
$log.info "Spectrum :: returned #{body['ns1.alarm-response-list']['@total-alarms'].to_i} alarms for period < #{alertStartTime.to_i} took #{pollingDuration.to_i} seconds, ended at #{pollingEnd}"
|
232
|
+
# iterate through each alarm
|
233
|
+
body['ns1.alarm-response-list']['ns1.alarm-responses']['ns1.alarm'].each do |alarm|
|
234
|
+
# Create initial structure
|
235
|
+
record_hash = Hash.new # temp hash to hold attributes of alarm
|
236
|
+
raw_array = Array.new # temp hash to hold attributes of alarm for raw
|
237
|
+
record_hash['event_type'] = @tag.to_s
|
238
|
+
record_hash['intermediary_source'] = @endpoint.to_s
|
239
|
+
record_hash['recieved_time_input'] = pollingEnd.to_s
|
240
|
+
# iterate though alarm attributes
|
241
|
+
alarm['ns1.attribute'].each do |attribute|
|
242
|
+
key,value = parseAttributes(attribute)
|
243
|
+
record_hash[key] = value
|
244
|
+
if @include_raw.to_s == "true"
|
245
|
+
raw_array << { "#{key}" => "#{value}" }
|
246
|
+
end
|
247
|
+
end
|
248
|
+
# append raw object
|
249
|
+
if @include_raw.to_s == "true"
|
250
|
+
record_hash[:raw] = raw_array
|
251
|
+
end
|
252
|
+
Engine.emit(@tag, record_hash['CREATION_DATE'].to_i,record_hash)
|
253
|
+
end
|
254
|
+
# Processing for single alarm returned
|
255
|
+
elsif body['ns1.alarm-response-list']['@total-alarms'].to_i == 1
|
256
|
+
$log.info "Spectrum :: returned #{body['ns1.alarm-response-list']['@total-alarms'].to_i} alarms for period < #{alertStartTime.to_i} took #{pollingDuration.to_i} seconds, ended at #{pollingEnd}"
|
163
257
|
# Create initial structure
|
164
258
|
record_hash = Hash.new # temp hash to hold attributes of alarm
|
165
259
|
raw_array = Array.new # temp hash to hold attributes of alarm for raw
|
166
260
|
record_hash['event_type'] = @tag.to_s
|
167
261
|
record_hash['intermediary_source'] = @endpoint.to_s
|
168
|
-
|
169
|
-
alarm
|
262
|
+
record_hash['recieved_time_input'] = pollingEnd.to_s
|
263
|
+
# iterate though alarm attributes and add to temp hash
|
264
|
+
body['ns1.alarm-response-list']['ns1.alarm-responses']['ns1.alarm']['ns1.attribute'].each do |attribute|
|
170
265
|
key,value = parseAttributes(attribute)
|
171
266
|
record_hash[key] = value
|
172
267
|
if @include_raw.to_s == "true"
|
@@ -178,33 +273,14 @@ module Fluent
|
|
178
273
|
record_hash[:raw] = raw_array
|
179
274
|
end
|
180
275
|
Engine.emit(@tag, record_hash['CREATION_DATE'].to_i,record_hash)
|
276
|
+
# No alarms returned
|
277
|
+
else
|
278
|
+
$log.info "Spectrum :: returned #{body['ns1.alarm-response-list']['@total-alarms'].to_i} alarms for period < #{alertStartTime.to_i} took #{pollingDuration.to_i} seconds, ended at #{pollingEnd}"
|
181
279
|
end
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
record_hash = Hash.new # temp hash to hold attributes of alarm
|
187
|
-
raw_array = Array.new # temp hash to hold attributes of alarm for raw
|
188
|
-
record_hash['event_type'] = @tag.to_s
|
189
|
-
record_hash['intermediary_source'] = @endpoint.to_s
|
190
|
-
# iterate though alarm attributes and add to temp hash
|
191
|
-
body['ns1.alarm-response-list']['ns1.alarm-responses']['ns1.alarm']['ns1.attribute'].each do |attribute|
|
192
|
-
key,value = parseAttributes(attribute)
|
193
|
-
record_hash[key] = value
|
194
|
-
if @include_raw.to_s == "true"
|
195
|
-
raw_array << { "#{key}" => "#{value}" }
|
196
|
-
end
|
197
|
-
end
|
198
|
-
# append raw object
|
199
|
-
if @include_raw.to_s == "true"
|
200
|
-
record_hash[:raw] = raw_array
|
201
|
-
end
|
202
|
-
Engine.emit(@tag, record_hash['CREATION_DATE'].to_i,record_hash)
|
203
|
-
# No alarms returned
|
204
|
-
else
|
205
|
-
$log.info "Spectrum :: returned #{body['ns1.alarm-response-list']['@total-alarms'].to_i} alarms for period #{alertStartTime.to_i} - #{Engine.now.to_i}"
|
206
|
-
end
|
207
|
-
|
280
|
+
@state_store.update!
|
281
|
+
#return
|
282
|
+
#exit
|
283
|
+
end
|
208
284
|
end # def input
|
209
285
|
end # class SpectrumInput
|
210
286
|
end # module Fluent
|
@@ -0,0 +1,193 @@
|
|
1
|
+
module Fluent
|
2
|
+
class SpectrumOut < Output
|
3
|
+
# First, register the plugin. NAME is the name of this plugin
|
4
|
+
# and identifies the plugin in the configuration file.
|
5
|
+
Fluent::Plugin.register_output('spectrum', self)
|
6
|
+
|
7
|
+
config_param :tag, :string, default:'alert.spectrum.out'
|
8
|
+
#config_param :tag, :string, :default => "alert.spectrum"
|
9
|
+
config_param :endpoint, :string, :default => "pleasechangeme.com" #fqdn of endpoint
|
10
|
+
config_param :interval, :integer, :default => '300' #Default 5 minutes
|
11
|
+
config_param :user, :string, :default => "username"
|
12
|
+
config_param :pass, :string, :default => "password"
|
13
|
+
config_param :include_raw, :string, :default => "false" #Include original object as raw
|
14
|
+
config_param :attributes, :string, :default => "ALL" # fields to include, ALL for... well, ALL.
|
15
|
+
|
16
|
+
def parseAttributes(alarmAttribute)
|
17
|
+
key = @spectrum_access_code[alarmAttribute['@id'].to_s].to_s
|
18
|
+
value = ((to_utf8(alarmAttribute['$'].to_s)).strip).gsub(/\r?\n/, " ")
|
19
|
+
return key,value
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize
|
23
|
+
require 'rest-client'
|
24
|
+
require 'json'
|
25
|
+
require 'pp'
|
26
|
+
require 'cgi'
|
27
|
+
super
|
28
|
+
end # def initialize
|
29
|
+
|
30
|
+
|
31
|
+
# This method is called before starting.
|
32
|
+
def configure(conf)
|
33
|
+
super
|
34
|
+
# Read property file and create a hash
|
35
|
+
@rename_rules = []
|
36
|
+
conf_rename_rules = conf.keys.select { |k| k =~ /^rename_rule(\d+)$/ }
|
37
|
+
conf_rename_rules.sort_by { |r| r.sub('rename_rule', '').to_i }.each do |r|
|
38
|
+
key_regexp, new_key = parse_rename_rule conf[r]
|
39
|
+
|
40
|
+
if key_regexp.nil? || new_key.nil?
|
41
|
+
raise Fluent::ConfigError, "Failed to parse: #{r} #{conf[r]}"
|
42
|
+
end
|
43
|
+
|
44
|
+
if @rename_rules.map { |r| r[:key_regexp] }.include? /#{key_regexp}/
|
45
|
+
raise Fluent::ConfigError, "Duplicated rules for key #{key_regexp}: #{@rename_rules}"
|
46
|
+
end
|
47
|
+
|
48
|
+
#@rename_rules << { key_regexp: /#{key_regexp}/, new_key: new_key }
|
49
|
+
@rename_rules << { key_regexp: key_regexp, new_key: new_key }
|
50
|
+
$log.info "Added rename key rule: #{r} #{@rename_rules.last}"
|
51
|
+
end
|
52
|
+
|
53
|
+
raise Fluent::ConfigError, "No rename rules are given" if @rename_rules.empty?
|
54
|
+
@conf = conf
|
55
|
+
# map of Spectrum attribute codes to names
|
56
|
+
@spectrum_access_code={
|
57
|
+
"0x11f9c" => "ALARM_ID",
|
58
|
+
"0x11f4e" => "CREATION_DATE",
|
59
|
+
"0x11f56" => "SEVERITY",
|
60
|
+
"0x12b4c" => "ALARM_TITLE",
|
61
|
+
"0x1006e" => "HOSTNAME",
|
62
|
+
"0x12d7f" => "IP_ADDRESS",
|
63
|
+
"0x1296e" => "ORIGINATING_EVENT_ATTR",
|
64
|
+
"0x10000" => "MODEL_STRING",
|
65
|
+
"0x11f4d" => "ACKNOWLEDGED",
|
66
|
+
"0x11f4f" => "ALARM_STATUS",
|
67
|
+
"0x11fc5" => "OCCURRENCES",
|
68
|
+
"0x11f57" => "TROUBLE_SHOOTER",
|
69
|
+
"0x11f9b" => "USER_CLEARABLE",
|
70
|
+
"0x12022" => "TROUBLE_TICKET_ID",
|
71
|
+
"0x12942" => "PERSISTENT",
|
72
|
+
"0x12adb" => "GC_NAME",
|
73
|
+
"0x57f0105" => "Custom_Project",
|
74
|
+
"0x11f4d" => "ACKNOWLEDGED",
|
75
|
+
"0xffff00ed" => "application_name",
|
76
|
+
"0xffff00f1" => "business_unit_l1",
|
77
|
+
"0xffff00f2" => "business_unit_l2",
|
78
|
+
"0xffff00f3" => "business_unit_l3",
|
79
|
+
"0xffff00f4" => "business_unit_l4",
|
80
|
+
"0xffff00f0" => "cmdb_ci_sysid",
|
81
|
+
|
82
|
+
#{}"0x11f51" => "CLEARED_BY_USER_NAME",
|
83
|
+
#{}"0x11f52" => "EVENT_ID_LIST",
|
84
|
+
#{}"0x11f53" => "MODEL_HANDLE",
|
85
|
+
#{}"0x11f54" => "PRIMARY_ALARM",
|
86
|
+
#{}"0x11fc4" => "ALARM_SOURCE",
|
87
|
+
#{}"0x11fc6" => "TROUBLE_SHOOTER_MH",
|
88
|
+
#{}"0x12a6c" => "TROUBLE_SHOOTER_EMAIL",
|
89
|
+
#{}"0x1290d" => "IMPACT_SEVERITY",
|
90
|
+
#{}"0x1290e" => "IMPACT_SCOPE",
|
91
|
+
#{}"0x1298a" => "IMPACT_TYPE_LIST",
|
92
|
+
#{}"0x12948" => "DIAGNOSIS_LOG",
|
93
|
+
#{}"0x129aa" => "MODEL_ID",
|
94
|
+
#{}"0x129ab" => "MODEL_TYPE_ID",
|
95
|
+
#{}"0x129af" => "CLEAR_DATE",
|
96
|
+
#{}"0x12a04" => "SYMPTOM_LIST_ATTR",
|
97
|
+
#{}"0x12a6f" => "EVENT_SYMPTOM_LIST_ATTR",
|
98
|
+
#{}"0x12a05" => "CAUSE_LIST_ATTR",
|
99
|
+
#{}"0x12a06" => "SYMPTOM_COUNT_ATTR",
|
100
|
+
#{}"0x12a70" => "EVENT_SYMPTOM_COUNT_ATTR",
|
101
|
+
#{}"0x12a07" => "CAUSE_COUNT_ATTR",
|
102
|
+
#{}"0x12a63" => "WEB_CONTEXT_URL",
|
103
|
+
#{}"0x12a6b" => "COMBINED_IMPACT_TYPE_LIST",
|
104
|
+
#{}"0x11f50" => "CAUSE_CODE",
|
105
|
+
#{}"0x10009" => "SECURITY_STRING"
|
106
|
+
}
|
107
|
+
# Create XML chunk for attributes we care about
|
108
|
+
@attr_of_interest=""
|
109
|
+
@spectrum_access_code.each do |key, array|
|
110
|
+
@attr_of_interest += " <rs:requested-attribute id=\"#{key}\"/>"
|
111
|
+
end
|
112
|
+
|
113
|
+
|
114
|
+
# Setup URL Resource
|
115
|
+
@url = 'http://' + @endpoint.to_s + '/spectrum/restful/alarms/'
|
116
|
+
end
|
117
|
+
|
118
|
+
def parse_rename_rule rule
|
119
|
+
if rule.match /^([^\s]+)\s+(.+)$/
|
120
|
+
return $~.captures
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# This method is called when starting.
|
125
|
+
def start
|
126
|
+
super
|
127
|
+
end
|
128
|
+
|
129
|
+
# This method is called when shutting down.
|
130
|
+
def shutdown
|
131
|
+
super
|
132
|
+
end
|
133
|
+
|
134
|
+
# This method is called when an event reaches Fluentd.
|
135
|
+
# 'es' is a Fluent::EventStream object that includes multiple events.
|
136
|
+
# You can use 'es.each {|time,record["event"]| ... }' to retrieve events.
|
137
|
+
# 'chain' is an object that manages transactions. Call 'chain.next' at
|
138
|
+
# appropriate points and rollback if it raises an exception.
|
139
|
+
#
|
140
|
+
# NOTE! This method is called by Fluentd's main thread so you should not write slow routine here. It causes Fluentd's performance degression.
|
141
|
+
def emit(tag, es, chain)
|
142
|
+
chain.next
|
143
|
+
es.each {|time,record|
|
144
|
+
$stderr.puts "OK!"
|
145
|
+
## Check if the incoming event already has an event id (alarm id) and a corresponding tag of spectrum
|
146
|
+
if (record["event"].has_key?("source_event_id") && record["event"].has_key?("event_type"))
|
147
|
+
# If the value on event_type is spectrum, then it means that ti is already from spectrum and needs an update
|
148
|
+
if (record["event"].has_value?("alert.spectrum"))
|
149
|
+
|
150
|
+
# Create an empty hash
|
151
|
+
alertUpdateHash=Hash.new
|
152
|
+
|
153
|
+
# Parse thro the array hash that contains name value pairs for hash mapping and add new records to a new hash
|
154
|
+
@rename_rules.each { |rule|
|
155
|
+
pp rule[:new_key]
|
156
|
+
alertUpdateHash[rule[:key_regexp]]=record["event"][rule[:new_key]]
|
157
|
+
}
|
158
|
+
# construct the url and iterate to construct the uri
|
159
|
+
@urlrest = @url + record["event"]["source_event_id"]
|
160
|
+
alertUpdateHash.each do |attr, val|
|
161
|
+
if (val.nil? || val.empty?)
|
162
|
+
next
|
163
|
+
else
|
164
|
+
if (@urlrest =~ /#{record["event"]["source_event_id"]}\s*$/)
|
165
|
+
@urlrest = @urlrest + "?attr=" + attr + "&val=" + CGI.escape(val.to_s)
|
166
|
+
else
|
167
|
+
@urlrest = @urlrest + "&attr=" + attr + "&val=" + CGI.escape(val.to_s)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
$log.info "Rest url " + @urlrest
|
173
|
+
#RestClient::Resource.new(@user,@pass)
|
174
|
+
begin
|
175
|
+
responsePostAffEnt=RestClient::Resource.new(@urlrest,@user,@pass).put(@urlrest,:content_type => 'application/json')
|
176
|
+
rescue Exception => e
|
177
|
+
$log.error "Error in restful put call."
|
178
|
+
log.error e.backtrace.inspect
|
179
|
+
$log.error responsePostAffEnt
|
180
|
+
end
|
181
|
+
|
182
|
+
else
|
183
|
+
|
184
|
+
# For now just throw to stdout
|
185
|
+
$log.info record["event"]
|
186
|
+
|
187
|
+
end
|
188
|
+
|
189
|
+
end
|
190
|
+
}
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
<source>
|
2
|
+
type spectrum
|
3
|
+
endpoint spectrum.changeme.com
|
4
|
+
user changeme
|
5
|
+
pass changeme
|
6
|
+
tag alert.spectrum
|
7
|
+
interval 60
|
8
|
+
include_raw true
|
9
|
+
</source>
|
10
|
+
|
11
|
+
<match alert.spectrum>
|
12
|
+
type rename_key
|
13
|
+
deep_rename false
|
14
|
+
remove_tag_prefix alert.spectrum
|
15
|
+
append_tag alert
|
16
|
+
rename_rule1 HOSTNAME source_hostname
|
17
|
+
rename_rule2 IP_ADDRESS source_ip
|
18
|
+
rename_rule3 ALARM_TITLE event_name
|
19
|
+
rename_rule4 SEVERITY criticality
|
20
|
+
rename_rule5 CREATION_DATE creation_time
|
21
|
+
rename_rule6 ORIGINATING_EVENT_ATTR alert_description
|
22
|
+
rename_rule7 MODEL_STRING source_type
|
23
|
+
rename_rule8 ALARM_ID source_event_id
|
24
|
+
rename_rule9 GC_NAME environment
|
25
|
+
</match>
|
26
|
+
|
27
|
+
<match alert>
|
28
|
+
type key_picker
|
29
|
+
keys event_type,intermediary_source,source_event_id,creation_time,criticality,event_name,source_hostname,source_ip,alert_description,source_type,environment,raw
|
30
|
+
add_tag_prefix processed.
|
31
|
+
</match>
|
32
|
+
|
33
|
+
<match processed.alert>
|
34
|
+
type stdout
|
35
|
+
</match>
|
data/sample/spectrum.conf.sample
CHANGED
@@ -1,8 +1,13 @@
|
|
1
1
|
<source>
|
2
|
-
|
3
|
-
|
2
|
+
type spectrum
|
3
|
+
endpoint spectrum.changeme.com
|
4
|
+
user changeme
|
5
|
+
pass changeme
|
6
|
+
tag alert.spectrum
|
7
|
+
interval 60
|
8
|
+
include_raw false
|
4
9
|
</source>
|
5
10
|
|
6
|
-
<match alert.spectrum
|
7
|
-
|
8
|
-
</match>
|
11
|
+
<match alert.spectrum>
|
12
|
+
type stdout
|
13
|
+
</match>
|
@@ -6,9 +6,6 @@ class SpectrumInputTest < Test::Unit::TestCase
|
|
6
6
|
end
|
7
7
|
|
8
8
|
CONFIG = %[
|
9
|
-
host 0
|
10
|
-
port 1062
|
11
|
-
tag alert.spectrum
|
12
9
|
]
|
13
10
|
|
14
11
|
def create_driver(conf=CONFIG)
|
@@ -17,8 +14,11 @@ class SpectrumInputTest < Test::Unit::TestCase
|
|
17
14
|
|
18
15
|
def test_configure
|
19
16
|
d = create_driver('')
|
20
|
-
assert_equal "
|
21
|
-
assert_equal "
|
17
|
+
#assert_equal "pleasechangeme.com", d.instance.endpoint
|
18
|
+
#assert_equal "username", d.instance.user
|
19
|
+
#assert_equal "password", d.instance.pass
|
20
|
+
assert_equal "300".to_i, d.instance.interval
|
21
|
+
assert_equal "false", d.instance.include_raw
|
22
22
|
assert_equal 'alert.spectrum', d.instance.tag
|
23
23
|
end
|
24
24
|
end
|
metadata
CHANGED
@@ -1,107 +1,111 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fluent-plugin-spectrum
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alex Pena
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-03-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - ~>
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '0.9'
|
20
|
-
- -
|
20
|
+
- - ">="
|
21
21
|
- !ruby/object:Gem::Version
|
22
22
|
version: 0.9.6
|
23
23
|
type: :development
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
26
26
|
requirements:
|
27
|
-
- - ~>
|
27
|
+
- - "~>"
|
28
28
|
- !ruby/object:Gem::Version
|
29
29
|
version: '0.9'
|
30
|
-
- -
|
30
|
+
- - ">="
|
31
31
|
- !ruby/object:Gem::Version
|
32
32
|
version: 0.9.6
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
34
|
name: fluentd
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
36
36
|
requirements:
|
37
|
-
- - ~>
|
37
|
+
- - "~>"
|
38
38
|
- !ruby/object:Gem::Version
|
39
39
|
version: '0.10'
|
40
|
-
- -
|
40
|
+
- - ">="
|
41
41
|
- !ruby/object:Gem::Version
|
42
42
|
version: 0.10.52
|
43
43
|
type: :runtime
|
44
44
|
prerelease: false
|
45
45
|
version_requirements: !ruby/object:Gem::Requirement
|
46
46
|
requirements:
|
47
|
-
- - ~>
|
47
|
+
- - "~>"
|
48
48
|
- !ruby/object:Gem::Version
|
49
49
|
version: '0.10'
|
50
|
-
- -
|
50
|
+
- - ">="
|
51
51
|
- !ruby/object:Gem::Version
|
52
52
|
version: 0.10.52
|
53
53
|
- !ruby/object:Gem::Dependency
|
54
54
|
name: json
|
55
55
|
requirement: !ruby/object:Gem::Requirement
|
56
56
|
requirements:
|
57
|
-
- - ~>
|
57
|
+
- - "~>"
|
58
58
|
- !ruby/object:Gem::Version
|
59
59
|
version: '1.1'
|
60
|
-
- -
|
60
|
+
- - ">="
|
61
61
|
- !ruby/object:Gem::Version
|
62
62
|
version: 1.8.2
|
63
63
|
type: :runtime
|
64
64
|
prerelease: false
|
65
65
|
version_requirements: !ruby/object:Gem::Requirement
|
66
66
|
requirements:
|
67
|
-
- - ~>
|
67
|
+
- - "~>"
|
68
68
|
- !ruby/object:Gem::Version
|
69
69
|
version: '1.1'
|
70
|
-
- -
|
70
|
+
- - ">="
|
71
71
|
- !ruby/object:Gem::Version
|
72
72
|
version: 1.8.2
|
73
73
|
- !ruby/object:Gem::Dependency
|
74
74
|
name: rest-client
|
75
75
|
requirement: !ruby/object:Gem::Requirement
|
76
76
|
requirements:
|
77
|
-
- - ~>
|
77
|
+
- - "~>"
|
78
78
|
- !ruby/object:Gem::Version
|
79
79
|
version: '1.7'
|
80
|
-
- -
|
80
|
+
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: 1.7.3
|
83
83
|
type: :runtime
|
84
84
|
prerelease: false
|
85
85
|
version_requirements: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
|
-
- - ~>
|
87
|
+
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
89
|
version: '1.7'
|
90
|
-
- -
|
90
|
+
- - ">="
|
91
91
|
- !ruby/object:Gem::Version
|
92
92
|
version: 1.7.3
|
93
|
-
description: Fluentd plugin for
|
93
|
+
description: Fluentd plugin for pulling monitoring alerts from CA Spectrum
|
94
94
|
email:
|
95
|
-
-
|
95
|
+
- pena.alex@gmail.com
|
96
96
|
executables: []
|
97
97
|
extensions: []
|
98
98
|
extra_rdoc_files: []
|
99
99
|
files:
|
100
|
+
- ".gitignore"
|
101
|
+
- ".travis.yml"
|
100
102
|
- Gemfile
|
101
103
|
- README.md
|
102
104
|
- Rakefile
|
103
105
|
- fluent-plugin-spectrum.gemspec
|
104
106
|
- lib/fluent/plugin/in_spectrum.rb
|
107
|
+
- lib/fluent/plugin/out_spectrum.rb
|
108
|
+
- sample/spectrum.conf.advanced_sample
|
105
109
|
- sample/spectrum.conf.sample
|
106
110
|
- test/helper.rb
|
107
111
|
- test/plugin/test_in_spectrum.rb
|
@@ -115,20 +119,20 @@ require_paths:
|
|
115
119
|
- lib
|
116
120
|
required_ruby_version: !ruby/object:Gem::Requirement
|
117
121
|
requirements:
|
118
|
-
- -
|
122
|
+
- - ">="
|
119
123
|
- !ruby/object:Gem::Version
|
120
124
|
version: '0'
|
121
125
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
122
126
|
requirements:
|
123
|
-
- -
|
127
|
+
- - ">="
|
124
128
|
- !ruby/object:Gem::Version
|
125
129
|
version: '0'
|
126
130
|
requirements: []
|
127
131
|
rubyforge_project:
|
128
|
-
rubygems_version: 2.
|
132
|
+
rubygems_version: 2.4.5
|
129
133
|
signing_key:
|
130
134
|
specification_version: 4
|
131
|
-
summary: Fluentd input plugin for Spectrum
|
135
|
+
summary: Fluentd input plugin for pulling alerts from CA Spectrum
|
132
136
|
test_files:
|
133
137
|
- test/helper.rb
|
134
138
|
- test/plugin/test_in_spectrum.rb
|