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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2d4288f068c625207769f4fa29e28d38f942ad83
4
- data.tar.gz: fb7cbc18c897472e626cea9320d0680cfc2de45d
3
+ metadata.gz: b6ce4a6b4bf074348bde00e83c87e8559e07549c
4
+ data.tar.gz: cf2079f18bffc80dee8fe1c547d26460ff2a862e
5
5
  SHA512:
6
- metadata.gz: 52fa80683e053aea5ae9cbc7a4575a6c7076fa72f01ebc6f650028e0ee36cc908cf6f7119c975de14f8099b4a5d50f11877ea6a726795b728dc27525851cf56c
7
- data.tar.gz: 270493f647b3fa8d156941e27772b2f9f3662b8eb91f4c256edea218e72b5c1db04e54189b474884afa15505de36136ddc534f8ed11704aab8da8908fc8ff365
6
+ metadata.gz: dde69f607871058aa60138bd5a177323a0e0fac45ff6b62c0f13ef74699a5b948974161759b1417609abf02f0e01fc16bb26c5da60971da4dcbc85e6909c83dd
7
+ data.tar.gz: 656594019157e6a2555673e9d61094d89a420533c7fca7b1c0d6b909d5e669701edd895618c0b75e47af5c2c5438504dcab801101bbb0486dde1d14578aab052
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.travis.yml ADDED
@@ -0,0 +1,14 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+ - 2.0.0-p451
5
+ - 2.1.0
6
+
7
+ gemfile:
8
+ - Gemfile
9
+
10
+ branches:
11
+ only:
12
+ - master
13
+
14
+ script: bundle exec rake test
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
+ [![Gem Version](https://badge.fury.io/rb/fluent-plugin-spectrum.png)](http://badge.fury.io/rb/fluent-plugin-spectrum)
7
+ [![Build Status](https://travis-ci.org/Bigel0w/fluent-plugin-spectrum.png?branch=master)](https://travis-ci.org/Bigel0w/fluent-plugin-spectrum)
8
+ [![Coverage Status](https://coveralls.io/repos/Bigel0w/fluent-plugin-spectrum/badge.png?branch=master)](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
- Send a test
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
- TBD: Still need to create an example
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.3"
7
- gem.date = '2015-02-24'
6
+ gem.version = "0.0.5"
7
+ gem.date = '2015-03-31'
8
8
  gem.authors = ["Alex Pena"]
9
- gem.email = ["alex_pena@intuit.com"]
10
- gem.summary = %q{Fluentd input plugin for Spectrum Alerts}
11
- gem.description = %q{Fluentd plugin for Spectrum Alerts... WIP}
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 => "pleasechangeme.com" #fqdn of endpoint
20
- config_param :interval, :integer, :default => '300' #Default 5 minutes
21
- config_param :user, :string, :default => "username"
22
- config_param :pass, :string, :default => "password"
23
- config_param :include_raw, :string, :default => "false" #Include original object as raw
24
- config_param :attributes, :string, :default => "ALL" # fields to include, ALL for... well, ALL.
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
- @url = 'http://' + @endpoint.to_s + '/spectrum/restful/alarms'
100
- def spectrumEnd
101
- RestClient::Resource.new(@url,@user,@pass)
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
- super
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
- timer_trigger = TimerWatcher.new(@interval, true, &method(:input))
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
- super
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
- $log.error "Spectrum :: unexpected error", :error=>$!.to_s
127
- $log.error_backtrace
181
+ $log.error "unexpected error", :error=>$!.to_s
182
+ $log.error_backtrace
128
183
  end # def run
129
184
 
130
- def input
131
- alertStartTime = Engine.now.to_i - @interval.to_i
132
- $log.info "Spectrum :: Polling alerts for time period: #{alertStartTime.to_i} - #{Engine.now.to_i}"
133
-
134
- # Format XML for spectrum post
135
- @xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
136
- <rs:alarm-request throttlesize=\"10000\"
137
- xmlns:rs=\"http://www.ca.com/spectrum/restful/schema/request\"
138
- xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
139
- xsi:schemaLocation=\"http://www.ca.com/spectrum/restful/schema/request ../../../xsd/Request.xsd \">
140
- <rs:attribute-filter>
141
- <search-criteria xmlns=\"http://www.ca.com/spectrum/restful/schema/filter\">
142
- <filtered-models>
143
- <greater-than>
144
- <attribute id=\"0x11f4e\">
145
- <value> #{alertStartTime} </value>
146
- </attribute>
147
- </greater-than>
148
- </filtered-models>
149
- </search-criteria>
150
- </rs:attribute-filter>
151
- #{@attr_of_interest}
152
- </rs:alarm-request>"
153
-
154
- # Post to Spectrum and parse results
155
- responsePost=spectrumEnd.post @xml,:content_type => 'application/xml',:accept => 'application/json'
156
- body = JSON.parse(responsePost.body)
157
-
158
- # Processing for multiple alerts returned
159
- if body['ns1.alarm-response-list']['@total-alarms'].to_i > 1
160
- $log.info "Spectrum :: returned #{body['ns1.alarm-response-list']['@total-alarms'].to_i} alarms for period #{alertStartTime.to_i} - #{Engine.now.to_i}"
161
- # iterate through each alarm
162
- body['ns1.alarm-response-list']['ns1.alarm-responses']['ns1.alarm'].each do |alarm|
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
- # iterate though alarm attributes
169
- alarm['ns1.attribute'].each do |attribute|
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
- # Processing for single alarm returned
183
- elsif body['ns1.alarm-response-list']['@total-alarms'].to_i == 1
184
- $log.info "Spectrum :: returned #{body['ns1.alarm-response-list']['@total-alarms'].to_i} alarms for period #{alertStartTime.to_i} - #{Engine.now.to_i}"
185
- # Create initial structure
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>
@@ -1,8 +1,13 @@
1
1
  <source>
2
- type spectrum
3
- tag alert.spectrum
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
- type stdout
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 "0".to_i, d.instance.host
21
- assert_equal "1062".to_i, d.instance.port
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.3
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-02-24 00:00:00.000000000 Z
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 Spectrum Alerts... WIP
93
+ description: Fluentd plugin for pulling monitoring alerts from CA Spectrum
94
94
  email:
95
- - alex_pena@intuit.com
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.3.0
132
+ rubygems_version: 2.4.5
129
133
  signing_key:
130
134
  specification_version: 4
131
- summary: Fluentd input plugin for Spectrum Alerts
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