splunk-sdk-ruby 0.1.0

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.
Files changed (81) hide show
  1. data/CHANGELOG.md +160 -0
  2. data/Gemfile +8 -0
  3. data/LICENSE +177 -0
  4. data/README.md +310 -0
  5. data/Rakefile +40 -0
  6. data/examples/1_connect.rb +51 -0
  7. data/examples/2_manage.rb +103 -0
  8. data/examples/3_blocking_searches.rb +82 -0
  9. data/examples/4_asynchronous_searches.rb +79 -0
  10. data/examples/5_stream_data_to_splunk.rb +79 -0
  11. data/lib/splunk-sdk-ruby.rb +47 -0
  12. data/lib/splunk-sdk-ruby/ambiguous_entity_reference.rb +28 -0
  13. data/lib/splunk-sdk-ruby/atomfeed.rb +323 -0
  14. data/lib/splunk-sdk-ruby/collection.rb +417 -0
  15. data/lib/splunk-sdk-ruby/collection/apps.rb +35 -0
  16. data/lib/splunk-sdk-ruby/collection/case_insensitive_collection.rb +58 -0
  17. data/lib/splunk-sdk-ruby/collection/configuration_file.rb +50 -0
  18. data/lib/splunk-sdk-ruby/collection/configurations.rb +80 -0
  19. data/lib/splunk-sdk-ruby/collection/jobs.rb +136 -0
  20. data/lib/splunk-sdk-ruby/collection/messages.rb +51 -0
  21. data/lib/splunk-sdk-ruby/context.rb +522 -0
  22. data/lib/splunk-sdk-ruby/entity.rb +260 -0
  23. data/lib/splunk-sdk-ruby/entity/index.rb +191 -0
  24. data/lib/splunk-sdk-ruby/entity/job.rb +339 -0
  25. data/lib/splunk-sdk-ruby/entity/message.rb +36 -0
  26. data/lib/splunk-sdk-ruby/entity/saved_search.rb +71 -0
  27. data/lib/splunk-sdk-ruby/entity/stanza.rb +45 -0
  28. data/lib/splunk-sdk-ruby/entity_not_ready.rb +26 -0
  29. data/lib/splunk-sdk-ruby/illegal_operation.rb +27 -0
  30. data/lib/splunk-sdk-ruby/namespace.rb +239 -0
  31. data/lib/splunk-sdk-ruby/resultsreader.rb +716 -0
  32. data/lib/splunk-sdk-ruby/service.rb +339 -0
  33. data/lib/splunk-sdk-ruby/splunk_http_error.rb +49 -0
  34. data/lib/splunk-sdk-ruby/synonyms.rb +50 -0
  35. data/lib/splunk-sdk-ruby/version.rb +27 -0
  36. data/lib/splunk-sdk-ruby/xml_shim.rb +117 -0
  37. data/splunk-sdk-ruby.gemspec +27 -0
  38. data/test/atom_test_data.rb +472 -0
  39. data/test/data/atom/atom_feed_with_message.xml +19 -0
  40. data/test/data/atom/atom_with_feed.xml +99 -0
  41. data/test/data/atom/atom_with_several_entries.xml +101 -0
  42. data/test/data/atom/atom_with_simple_entries.xml +30 -0
  43. data/test/data/atom/atom_without_feed.xml +248 -0
  44. data/test/data/export/4.2.5/export_results.xml +88 -0
  45. data/test/data/export/4.3.5/export_results.xml +87 -0
  46. data/test/data/export/5.0.1/export_results.xml +78 -0
  47. data/test/data/export/5.0.1/nonreporting.xml +232 -0
  48. data/test/data/results/4.2.5/results-empty.xml +0 -0
  49. data/test/data/results/4.2.5/results-preview.xml +255 -0
  50. data/test/data/results/4.2.5/results.xml +336 -0
  51. data/test/data/results/4.3.5/results-empty.xml +0 -0
  52. data/test/data/results/4.3.5/results-preview.xml +1057 -0
  53. data/test/data/results/4.3.5/results.xml +626 -0
  54. data/test/data/results/5.0.2/results-empty.xml +1 -0
  55. data/test/data/results/5.0.2/results-empty_preview.xml +1 -0
  56. data/test/data/results/5.0.2/results-preview.xml +448 -0
  57. data/test/data/results/5.0.2/results.xml +501 -0
  58. data/test/export_test_data.json +360 -0
  59. data/test/resultsreader_test_data.json +1119 -0
  60. data/test/services.server.info.xml +43 -0
  61. data/test/services.xml +111 -0
  62. data/test/test_atomfeed.rb +71 -0
  63. data/test/test_collection.rb +278 -0
  64. data/test/test_configuration_file.rb +124 -0
  65. data/test/test_context.rb +119 -0
  66. data/test/test_entity.rb +95 -0
  67. data/test/test_helper.rb +250 -0
  68. data/test/test_http_error.rb +52 -0
  69. data/test/test_index.rb +91 -0
  70. data/test/test_jobs.rb +319 -0
  71. data/test/test_messages.rb +17 -0
  72. data/test/test_namespace.rb +188 -0
  73. data/test/test_restarts.rb +49 -0
  74. data/test/test_resultsreader.rb +106 -0
  75. data/test/test_roles.rb +41 -0
  76. data/test/test_saved_searches.rb +119 -0
  77. data/test/test_service.rb +65 -0
  78. data/test/test_users.rb +33 -0
  79. data/test/test_xml_shim.rb +28 -0
  80. data/test/testfile.txt +1 -0
  81. metadata +200 -0
@@ -0,0 +1,339 @@
1
+ #--
2
+ # Copyright 2011-2013 Splunk, Inc.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License"): you may
5
+ # not use this file except in compliance with the License. You may obtain
6
+ # a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
+ # License for the specific language governing permissions and limitations
14
+ # under the License.
15
+ #++
16
+
17
+ ##
18
+ # Provides an +Entity+ subclass to represent search jobs.
19
+ #
20
+
21
+ require_relative '../entity'
22
+ require_relative '../namespace'
23
+
24
+ module Splunk
25
+ ##
26
+ # A class to represent a Splunk asynchronous search job.
27
+ #
28
+ # When you create a job, you need to wait for it to be ready before you can
29
+ # interrogate it in an useful way. Typically, you will write something like
30
+ #
31
+ # job = @service.jobs.create("search *")
32
+ # while !job.is_ready?
33
+ # sleep(0.2)
34
+ # end
35
+ # # Now the job is ready to use.
36
+ #
37
+ # The most important methods on +Job+ beyond those provided by +Entity+
38
+ # are those that fetch results (+results+, +preview+), and those that control
39
+ # the job's execution (+cancel+, +pause+, +unpause+, +finalize+).
40
+ #
41
+ # Note that jobs are created with preview disabled by default. You need to
42
+ # call +enable_preview+ and wait for the field +"isPreviewEnabled"+ to be
43
+ # +"1"+ before you will get anything useful from +preview+.
44
+ #
45
+ class Job < Entity
46
+ def initialize(service, sid, state=nil)
47
+ @sid = sid
48
+ begin
49
+ super(service, Splunk::namespace(:sharing => "global"), PATH_JOBS, sid, state)
50
+ rescue EntityNotReady
51
+ # Jobs may not be ready (and so cannot be refreshed) when they are
52
+ # first created, so Entity#initialize may throw an EntityNotReady
53
+ # exception. It's nothing to be concerned about for jobs.
54
+ end
55
+ end
56
+
57
+ ##
58
+ # Cancels this search job.
59
+ #
60
+ # Cancelling the job stops the search and deletes the results cache.
61
+ #
62
+ # Returns nothing.
63
+ #
64
+ def cancel
65
+ begin
66
+ control(:action => "cancel")
67
+ rescue SplunkHTTPError => err
68
+ if err.code == 404
69
+ return self # Job already cancelled; cancelling twice is a nop.
70
+ else
71
+ raise err
72
+ end
73
+ end
74
+ end
75
+
76
+ ##
77
+ # Issues a control request to this job.
78
+ #
79
+ # _args_ should be a hash with at least the key +:action+ (with a value such
80
+ # as +"cancel"+ or +"setpriority"+).
81
+ #
82
+ # Returns: the +Job+.
83
+ #
84
+ def control(args) # :nodoc:
85
+ @service.request(:method => :POST,
86
+ :namespace => @namespace,
87
+ :resource => @resource + [sid, "control"],
88
+ :body => args)
89
+ self
90
+ end
91
+
92
+ ##
93
+ # Returns the raw events found by this search job.
94
+ #
95
+ # These events are the data from the search pipeline before the first
96
+ # "transforming" search command. This is the primary method for a client
97
+ # to fetch a set of _untransformed_ events from a search job. This call is
98
+ # only valid if the search has no transforming commands.
99
+ #
100
+ # If the job is not yet finished, this will return an empty set of events.
101
+ #
102
+ # See the {REST docs for this call}[http://docs.splunk.com/Documentation/Splunk/latest/RESTAPI/RESTsearch#search.2Fjobs.2F.7Bsearch_id.7D.2Fevents]
103
+ # for more info on valid parameters and results.
104
+ #
105
+ # Returns: a stream that can be read with +ResultsReader+.
106
+ #
107
+ def events(args={})
108
+ response = @service.request(
109
+ :method => :GET,
110
+ :resource => @resource + [sid, "events"],
111
+ :body => args)
112
+ return response.body
113
+ end
114
+
115
+ ##
116
+ # Enables preview generation for this job.
117
+ #
118
+ # Enabling previews may slow the search down considerably, but will
119
+ # make the +preview+ method return events before the job is finished.
120
+ #
121
+ # Returns: the +Job+.
122
+ #
123
+ def enable_preview
124
+ control(:action => "enablepreview")
125
+ end
126
+
127
+ ##
128
+ # Finalizes this search job.
129
+ #
130
+ # Stops the search and provides whatever results have been obtained so far.
131
+ # (retrievable via +results+).
132
+ #
133
+ # Returns: the +Job+.
134
+ #
135
+ def finalize
136
+ control(:action => "finalize")
137
+ end
138
+
139
+ ##
140
+ # Returns whether the search job is done.
141
+ #
142
+ # +is_done+ refreshes the +Job+, so its answer is always current.
143
+ #
144
+ # Returns: +true+ or +false+.
145
+ #
146
+ def is_done?()
147
+ begin
148
+ refresh()
149
+ return fetch("isDone") == "1"
150
+ rescue EntityNotReady
151
+ return false
152
+ end
153
+ end
154
+
155
+ ##
156
+ # Returns whether the search job is ready.
157
+ #
158
+ # +is_ready+ refreshes the +Job+, so once the job is ready, you need
159
+ # not call +refresh+ an additional time.
160
+ #
161
+ # Returns: +true+ or +false+.
162
+ #
163
+ def is_ready?()
164
+ begin
165
+ refresh()
166
+ return true
167
+ rescue EntityNotReady
168
+ return false
169
+ end
170
+ end
171
+
172
+ ##
173
+ # Pauses this search job.
174
+ #
175
+ # Use +unpause+ to resume.
176
+ #
177
+ # Returns: the +Job+.
178
+ #
179
+ def pause
180
+ control(:action => "pause")
181
+ end
182
+
183
+ # Returns a set of preview events from this +Job+.
184
+ #
185
+ # If the search job is finished, this method is identical to +results+.
186
+ # Otherwise, it will return an empty results set unless preview is enabled
187
+ # (for instance, by calling +enable_preview+).
188
+ #
189
+ # See the {REST docs for this call}[http://docs.splunk.com/Documentation/Splunk/latest/RESTAPI/RESTsearch#search.2Fjobs.2F.7Bsearch_id.7D.2Fresults_preview]
190
+ # for more info on valid parameters and results.
191
+ #
192
+ # Returns: a stream readable by +ResultsReader+.
193
+ #
194
+ def preview(args={})
195
+ response = @service.request(:method => :GET,
196
+ :resource => @resource +
197
+ [sid, "results_preview"],
198
+ :body => args)
199
+ return response.body
200
+ end
201
+
202
+ ##
203
+ # Returns search results for this job.
204
+ #
205
+ # These are the results after all processing from the search pipeline is
206
+ # finished, including transforming search commands.
207
+ #
208
+ # The results set will be empty unless the job is done.
209
+ #
210
+ # Returns: a stream readable by +ResultsReader+.
211
+ #
212
+ def results(args={})
213
+ response = @service.request(:resource => @resource + [sid, "results"],
214
+ :body => args)
215
+ return response.body
216
+ end
217
+
218
+ ##
219
+ # Returns the search log for this search job.
220
+ #
221
+ # The search log is a syslog style file documenting the job.
222
+ #
223
+ # See the {REST docs for this call}[http://docs.splunk.com/Documentation/Splunk/latest/RESTAPI/RESTsearch#search.2Fjobs.2F.7Bsearch_id.7D.2Fsearch.log]
224
+ # for more info on valid parameters and results.
225
+ #
226
+ # Returns: a stream containing the log.
227
+ #
228
+ def searchlog(args={})
229
+ response = @service.request(:resource => @resource + [sid, "search.log"],
230
+ :body => args)
231
+ return response.body
232
+ end
233
+
234
+ ##
235
+ # Sets the priority of this search Job.
236
+ #
237
+ # _value_ can be 0-10, but unless the Splunk instance is running as
238
+ # root or administrator, you can only reduce the priority.
239
+ #
240
+ # Arguments:
241
+ # * _value_: an Integer from 0 to 10.
242
+ #
243
+ # Returns: the +Job+.
244
+ #
245
+ def set_priority(value)
246
+ control(:action => "setpriority", :priority => value)
247
+ end
248
+
249
+ ##
250
+ # Return the +Job's+ search id.
251
+ #
252
+ # Returns: a +String+.
253
+ #
254
+ attr_reader :sid
255
+
256
+ ##
257
+ # Returns the distribution over time of the events available so far.
258
+ #
259
+ # See the {REST docs for this call}[http://docs.splunk.com/Documentation/Splunk/latest/RESTAPI/RESTsearch#search.2Fjobs.2F.7Bsearch_id.7D.2Ftimeline]
260
+ # for more info on valid parameters and results.
261
+ #
262
+ # Each bucket is represented as a Hash with the following fields:
263
+ # +:available_buckets+, +:event_count+, +:time_in_seconds+ (number of
264
+ # seconds since the epoch), +:bucket_duration+ (how much time this bucket
265
+ # covers), +:finished_scanning+ (is scanning for events in this bucket
266
+ # complete), +:earliest_timezone+ and +:latest_timezone+ (which can be
267
+ # different, for example when daylight savings time starts during a bucket's
268
+ # duration), and +:time+ (a string representing the bucket's time in human
269
+ # readable form).
270
+ #
271
+ # Returns: an +Array+ of +Hash+es describing each time bucket.
272
+ #
273
+ def timeline(args={})
274
+ response = @service.request(:resource => @resource + [sid, "timeline"],
275
+ :body => args)
276
+ if $splunk_xml_library == :nokogiri
277
+ doc = Nokogiri::XML(response.body)
278
+ matches = doc.xpath("/timeline/bucket").map() do |bucket|
279
+ {:available_buckets => Integer(bucket.attributes["a"].to_s),
280
+ :event_count => Integer(bucket.attributes["c"].to_s),
281
+ :time_in_seconds => Float(bucket.attributes["t"].to_s),
282
+ :bucket_duration => Integer(bucket.attributes["d"].to_s),
283
+ :finished_scanning => Integer(bucket.attributes["f"].to_s),
284
+ :earliest_timezone => Integer(bucket.attributes["etz"].to_s),
285
+ :latest_timezone => Integer(bucket.attributes["ltz"].to_s),
286
+ :time => bucket.children.to_s}
287
+ end
288
+ return matches
289
+ else
290
+ doc = REXML::Document.new(response.body)
291
+ matches = []
292
+ matches = doc.elements.each("/timeline/bucket") do |bucket|
293
+ {:available_buckets => Integer(bucket.attributes["a"]),
294
+ :event_count => Integer(bucket.attributes["c"]),
295
+ :time_in_seconds => Float(bucket.attributes["t"]),
296
+ :bucket_duration => Integer(bucket.attributes["d"]),
297
+ :finished_scanning => Integer(bucket.attributes["f"]),
298
+ :earliest_timezone => Integer(bucket.attributes["etz"]),
299
+ :latest_timezone => Integer(bucket.attributes["ltz"]),
300
+ :time => bucket.children.join("")}
301
+ end
302
+ return matches
303
+ end
304
+ end
305
+
306
+ ##
307
+ # Resets the time to live for this Job.
308
+ #
309
+ # Calling touch resets the remaining time to live for the Job to its
310
+ # original value.
311
+ #
312
+ # Returns: the +Job+.
313
+ #
314
+ def touch
315
+ control(:action => "touch")
316
+ end
317
+
318
+ ##
319
+ # Sets the time to live (TTL) of this +Job+.
320
+ #
321
+ # The time to live is a number in seconds saying how long the search job
322
+ # should be on the Splunk system before being deleted.
323
+ #
324
+ # Returns: the +Job+.
325
+ #
326
+ def set_ttl(value)
327
+ control(:action => "setttl", :ttl => value)
328
+ end
329
+
330
+ ##
331
+ # Resumes execution of this Job.
332
+ #
333
+ # Returns: the +Job+.
334
+ #
335
+ def unpause
336
+ control(:action => "unpause")
337
+ end
338
+ end
339
+ end
@@ -0,0 +1,36 @@
1
+ #--
2
+ # Copyright 2011-2013 Splunk, Inc.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License"): you may
5
+ # not use this file except in compliance with the License. You may obtain
6
+ # a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
+ # License for the specific language governing permissions and limitations
14
+ # under the License.
15
+ #++
16
+
17
+ require_relative '../entity'
18
+
19
+ module Splunk
20
+ ##
21
+ # Class to represent system wide messages.
22
+ #
23
+ # +Message+ differs from +Entity+ only in having a method +value+ to fetch
24
+ # the detail of the message.
25
+ #
26
+ class Message < Entity
27
+ ##
28
+ # Returns the message's details.
29
+ #
30
+ # Returns: a +String+.
31
+ #
32
+ def value
33
+ fetch(@name)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,71 @@
1
+ #--
2
+ # Copyright 2011-2013 Splunk, Inc.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License"): you may
5
+ # not use this file except in compliance with the License. You may obtain
6
+ # a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
+ # License for the specific language governing permissions and limitations
14
+ # under the License.
15
+ #++
16
+
17
+ require_relative '../entity'
18
+
19
+ module Splunk
20
+ ##
21
+ # Class representing saved searches.
22
+ #
23
+ class SavedSearch < Entity
24
+ ##
25
+ #
26
+ #
27
+ def dispatch(args={})
28
+ response = @service.request(:method => :POST,
29
+ :namespace => @namespace,
30
+ :resource => @resource + [name, "dispatch"],
31
+ :body => args)
32
+ sid = Splunk::text_at_xpath("//response/sid", response.body)
33
+ return Job.new(@service, sid)
34
+ end
35
+
36
+ ##
37
+ # Returns a list of the jobs dispatched from this saved search.
38
+ #
39
+ # Returns: an +Array+ of +Job+ objects.
40
+ #
41
+ def history()
42
+ response = @service.request(:namespace => @namespace,
43
+ :resource => @resource + [@name, "history"])
44
+ feed = AtomFeed.new(response.body)
45
+ return feed.entries.map do |entry|
46
+ Job.new(@service, entry["title"], entry)
47
+ end
48
+ end
49
+
50
+ ##
51
+ # Updates the state of this saved search.
52
+ #
53
+ # See the method on +Entity+ for documentation.
54
+ #
55
+ def update(args) # :nodoc:
56
+ # In versions before Splunk 5.0, updating a saved search requires passing
57
+ # a +search+ argument, or it will return an error or set the search to
58
+ # empty. This is fixed in 5.0, but while the 4.x series is supported, we
59
+ # set the search field on args if it's not already set. This, of course,
60
+ # has a race condition if someone else has set the search since the last
61
+ # time the entity was refreshed.
62
+ #
63
+ # You might want to check if "search" is in the +requiredFields+ list
64
+ # on the entity, but that isn't always returned.
65
+ if !args.has_key?(:search) && !args.has_key?("search")
66
+ args[:search] = fetch("search")
67
+ end
68
+ super(args)
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,45 @@
1
+ #--
2
+ # Copyright 2011-2013 Splunk, Inc.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License"): you may
5
+ # not use this file except in compliance with the License. You may obtain
6
+ # a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
+ # License for the specific language governing permissions and limitations
14
+ # under the License.
15
+ #++
16
+
17
+ ##
18
+ # Provides a subclass of +Entity+ to represent stanzas in configuration files.
19
+ #
20
+
21
+ module Splunk
22
+ ##
23
+ # A class representing a stanza in a configuration file.
24
+ #
25
+ # +Stanza+ differs from +Entity+ only in providing a +length+ method
26
+ # to count the number of keys in it.
27
+ #
28
+ class Stanza < Entity
29
+ synonym "submit", "update"
30
+
31
+ ##
32
+ # Returns the number of elements in the stanza.
33
+ #
34
+ # The actual Atom feed returned will have extra fields giving metadata
35
+ # about the stanza, which will not be counted.
36
+ #
37
+ # Returns: a nonnegative integer.
38
+ #
39
+ def length()
40
+ @state["content"].
41
+ reject() { |k| k.start_with?("eai") || k == "disabled" }.
42
+ length()
43
+ end
44
+ end
45
+ end