splunker 0.0.1 → 0.0.2

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.
data/README.md CHANGED
@@ -101,3 +101,7 @@ The API client raises an exception when a non-2XX [response codes](http://docs.s
101
101
  * Token Auth
102
102
  * Resource creation handling, blocking & polling options, with a timeout.
103
103
  * Build console into gem (bin/)
104
+ * Search all models in addition to getting by ID
105
+ * Support search paramters (or, validate support)
106
+ * Strat for acknowledge, dispatch, history, etc.
107
+ * XML parsing -- detect nodes with children, detect types?
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.1
1
+ 0.0.2
@@ -2,6 +2,7 @@ require 'logger'
2
2
  require "splunker/version"
3
3
  require "splunker/client"
4
4
  require "splunker/errors"
5
+ require "splunker/models"
5
6
 
6
7
  # The parent Splunker module can directly invoke any method invokable by the
7
8
  # client returned in Splunker.client, so long as Splunker.client has been
@@ -6,7 +6,7 @@ module Splunker
6
6
  end
7
7
 
8
8
  def on_complete(env)
9
- env[:body] = Nokogiri::Slop(env[:body])
9
+ env[:body] = Nokogiri::XML(env[:body])
10
10
  Splunker.logger.debug("Response Body: #{env[:body]}")
11
11
  Splunker::Errors.raise_error_for_status!(env[:status], env[:body])
12
12
  Splunker.logger.debug "Request successful!"
@@ -0,0 +1,4 @@
1
+ require 'splunker/models/resource'
2
+ Dir[File.dirname(__FILE__) + '/models/*/*.rb'].each do |file|
3
+ require file
4
+ end
@@ -1,7 +1,8 @@
1
- module Models
1
+ module Splunker::Models
2
2
  module Finders
3
3
  module ClassMethods
4
4
  def where(options={})
5
+ raise NotImplemented, "Not yet implemented!"
5
6
  find(:all, options)
6
7
  end
7
8
 
@@ -19,12 +20,13 @@ module Models
19
20
  end
20
21
 
21
22
  def find_all(options)
23
+ raise NotImplemented, "Not yet implemented!"
22
24
  self.client.get @service_path, options
23
25
  end
24
26
 
25
- def find_by_id(object_id, options)
26
- object_path = assemble_path("#{@service_path}/#{escape_object_id(id)}")
27
- self.client.get object_path
27
+ def find_by_id(object_id, options={})
28
+ object_path = "#{@service_path}/#{escape_object_id(object_id)}"
29
+ self.new(self.client.get(object_path))
28
30
  end
29
31
  end
30
32
 
@@ -1,9 +1,13 @@
1
1
  module Splunker
2
2
  module Models
3
3
  require 'cgi'
4
+ require 'splunker/models/finders'
5
+ require 'splunker/models/xml_processor'
4
6
 
5
7
  class Resource
6
8
 
9
+ attr_accessor :attributes
10
+
7
11
  include Finders
8
12
 
9
13
  def self.service_path(path)
@@ -14,12 +18,57 @@ module Splunker
14
18
  Splunker.client
15
19
  end
16
20
 
21
+ def initialize(xml_doc)
22
+ self.attributes = XmlProcessor.hashify(xml_doc)
23
+ end
24
+
25
+ def method_missing(method_symbol, *arguments)
26
+ method_name = method_symbol.to_s
27
+ if method_name =~ /(=|\?)$/
28
+ case $1
29
+ when "="
30
+ write_attribute($`, arguments.first)
31
+ when "?"
32
+ if attributes.include?($`)
33
+ attributes[$`] ? true : false
34
+ else
35
+ raise NoMethodError
36
+ end
37
+ end
38
+ elsif attributes.include?(method_name)
39
+ return attributes[method_name]
40
+ else
41
+ super
42
+ end
43
+ end
44
+
45
+ def respond_to?(method_symbol, include_private=false)
46
+ if super
47
+ return true
48
+ else
49
+ method_name = method_symbol.to_s
50
+
51
+ if method_name =~ /=$/
52
+ true
53
+ elsif method_name =~ /(\?)$/
54
+ attributes.include?($`)
55
+ else
56
+ attributes.include?(method_name)
57
+ end
58
+
59
+ end
60
+ end
61
+
17
62
  protected
18
63
 
19
64
  # Escapes a object ID for use in a URI
20
65
  def self.escape_object_id(id_str)
21
66
  CGI.escape(id_str)
22
67
  end
68
+
69
+ def write_attribute(attribute, value)
70
+ attributes[attribute] = value
71
+ end
23
72
  end
24
73
  end
25
74
  end
@@ -0,0 +1,8 @@
1
+ module Splunker::Models
2
+ module Search
3
+ class Job < Splunker::Models::Resource
4
+ # http://docs.splunk.com/Documentation/Splunk/latest/RESTAPI/RESTsearch#search.2Fjobs.2F.7Bsearch_id.7D
5
+ service_path "jobs"
6
+ end
7
+ end
8
+ end
@@ -1,17 +1,16 @@
1
- module Splunker
2
- module Models
3
- class Search::Saved < Resource
4
- # http://docs.splunk.com/Documentation/Splunk/4.3.3/RESTAPI/RESTsearch#search.2Fjobs
1
+ module Splunker::Models
2
+ module Search
3
+ class Saved < Splunker::Models::Resource
4
+ # http://docs.splunk.com/Documentation/Splunk/4.3.4/RESTAPI/RESTsearch#saved.2Fsearches.2F.7Bname.7D
5
5
  service_path "saved/searches"
6
- # service_path
7
- # service_path/id
8
6
 
9
- # Dispatch these?
7
+ =begin Can these actions be standardized?
10
8
  def acknowledge; end
11
9
  def dispatch; end
12
10
  def history; end
13
11
  def scheduled_times; end
14
12
  def suppress; end
13
+ =end
15
14
  end
16
15
  end
17
16
  end
@@ -0,0 +1,77 @@
1
+ module Splunker
2
+ module Models
3
+ module XmlProcessor
4
+ # TODO: Process dates as dates.
5
+ # How to handle, in hash, things like action.email = 0 when
6
+ # action.email also needs to == hash...
7
+ # Process links and other non hash nodes as NOT text.
8
+ def hashify(xml_doc)
9
+ hash = {}
10
+ top_node(xml_doc).children.each do |t_node|
11
+ hash = self.send("process_#{t_node.name}".to_sym, hash, t_node)
12
+ end
13
+ hash
14
+ end
15
+
16
+ ###
17
+ # Defined custom processors here. Hopefully, there ain't many!
18
+ ###
19
+ def process_content(hash, node)
20
+ # So far, looks like content == dict.
21
+ node.xpath("./s:dict/s:key").each do |key|
22
+ hash = place_in_nested_hash(key.attribute("name").value,
23
+ key.text, hash)
24
+ end
25
+ hash
26
+ end
27
+
28
+ def process_text(hash, node)
29
+ hash
30
+ end
31
+
32
+ def place_in_nested_hash(name, text, hash)
33
+ nested_hash(name.split("."), text, hash)
34
+ hash
35
+ end
36
+
37
+ def nested_hash(name_array, text, hash)
38
+ e = name_array.shift
39
+ return text if e.nil?
40
+ #hash[e] ||= {} TODO!
41
+ hash[e] = {} unless hash[e].is_a?(Hash)
42
+ hash[e] = nested_hash(name_array, text, hash[e])
43
+ hash
44
+ end
45
+
46
+ def top_node(xml_doc)
47
+ # Handle the various types of XML structure
48
+ ["/xmlns:feed/xmlns:entry",
49
+ "/xmlns:entry"].each do |path|
50
+ begin
51
+ if xml_doc.xpath("#{path}/*").size > 0
52
+ return xml_doc.xpath(path)
53
+ end
54
+ rescue Nokogiri::XML::XPath::SyntaxError => e
55
+ # Ignore...
56
+ end
57
+ end
58
+
59
+ xml_doc
60
+ end
61
+
62
+ def method_missing(method, *args, &block)
63
+ if self.respond_to?(method)
64
+ self.send(method, *args, &block)
65
+ else
66
+ hash = args.first
67
+ node = args[1]
68
+ # TODO: Only text nodes
69
+ hash[node.name] = node.text
70
+ hash
71
+ end
72
+ end
73
+
74
+ extend self
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,211 @@
1
+ <entry
2
+ xmlns="http://www.w3.org/2005/Atom"
3
+ xmlns:s="http://dev.splunk.com/ns/rest"
4
+ xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/">
5
+ <title>search index</title>
6
+ <id>https://localhost:8089/services/search/jobs/mysearch</id>
7
+ <updated>2011-07-07T20:49:58.000-07:00</updated>
8
+ <link href="/services/search/jobs/mysearch" rel="alternate"/>
9
+ <published>2011-07-07T20:49:57.000-07:00</published>
10
+ <link href="/services/search/jobs/mysearch/search.log" rel="search.log"/>
11
+ <link href="/services/search/jobs/mysearch/events" rel="events"/>
12
+ <link href="/services/search/jobs/mysearch/results" rel="results"/>
13
+ <link href="/services/search/jobs/mysearch/results_preview" rel="results_preview"/>
14
+ <link href="/services/search/jobs/mysearch/timeline" rel="timeline"/>
15
+ <link href="/services/search/jobs/mysearch/summary" rel="summary"/>
16
+ <link href="/services/search/jobs/mysearch/control" rel="control"/>
17
+ <author>
18
+ <name>admin</name>
19
+ </author>
20
+ <content type="text/xml">
21
+ <s:dict>
22
+ <s:key name="cursorTime">1969-12-31T16:00:00.000-08:00</s:key>
23
+ <s:key name="delegate"></s:key>
24
+ <s:key name="diskUsage">2174976</s:key>
25
+ <s:key name="dispatchState">DONE</s:key>
26
+ <s:key name="doneProgress">1.00000</s:key>
27
+ <s:key name="dropCount">0</s:key>
28
+ <s:key name="earliestTime">2011-07-07T11:18:08.000-07:00</s:key>
29
+ <s:key name="eventAvailableCount">287</s:key>
30
+ <s:key name="eventCount">287</s:key>
31
+ <s:key name="eventFieldCount">6</s:key>
32
+ <s:key name="eventIsStreaming">1</s:key>
33
+ <s:key name="eventIsTruncated">0</s:key>
34
+ <s:key name="eventSearch">search index</s:key>
35
+ <s:key name="eventSorting">desc</s:key>
36
+ <s:key name="isDone">1</s:key>
37
+ <s:key name="isFailed">0</s:key>
38
+ <s:key name="isFinalized">0</s:key>
39
+ <s:key name="isPaused">0</s:key>
40
+ <s:key name="isPreviewEnabled">0</s:key>
41
+ <s:key name="isRealTimeSearch">0</s:key>
42
+ <s:key name="isRemoteTimeline">0</s:key>
43
+ <s:key name="isSaved">0</s:key>
44
+ <s:key name="isSavedSearch">0</s:key>
45
+ <s:key name="isZombie">0</s:key>
46
+ <s:key name="keywords">index</s:key>
47
+ <s:key name="label"></s:key>
48
+ <s:key name="latestTime">1969-12-31T16:00:00.000-08:00</s:key>
49
+ <s:key name="numPreviews">0</s:key>
50
+ <s:key name="priority">5</s:key>
51
+ <s:key name="remoteSearch">litsearch index | fields keepcolorder=t "host" "index" "linecount" "source" "sourcetype" "splunk_server"</s:key>
52
+ <s:key name="reportSearch"></s:key>
53
+ <s:key name="resultCount">287</s:key>
54
+ <s:key name="resultIsStreaming">1</s:key>
55
+ <s:key name="resultPreviewCount">287</s:key>
56
+ <s:key name="runDuration">1.004000</s:key>
57
+ <s:key name="scanCount">287</s:key>
58
+ <s:key name="sid">mysearch</s:key>
59
+ <s:key name="statusBuckets">0</s:key>
60
+ <s:key name="ttl">516</s:key>
61
+ <s:key name="performance">
62
+ <s:dict>
63
+ <s:key name="command.fields">
64
+ <s:dict>
65
+ <s:key name="duration_secs">0.004</s:key>
66
+ <s:key name="invocations">4</s:key>
67
+ <s:key name="input_count">287</s:key>
68
+ <s:key name="output_count">287</s:key>
69
+ </s:dict>
70
+ </s:key>
71
+ <s:key name="command.search">
72
+ <s:dict>
73
+ <s:key name="duration_secs">0.089</s:key>
74
+ <s:key name="invocations">4</s:key>
75
+ <s:key name="input_count">0</s:key>
76
+ <s:key name="output_count">287</s:key>
77
+ </s:dict>
78
+ </s:key>
79
+ <s:key name="command.search.fieldalias">
80
+ <s:dict>
81
+ <s:key name="duration_secs">0.002</s:key>
82
+ <s:key name="invocations">2</s:key>
83
+ <s:key name="input_count">287</s:key>
84
+ <s:key name="output_count">287</s:key>
85
+ </s:dict>
86
+ </s:key>
87
+ <s:key name="command.search.index">
88
+ <s:dict>
89
+ <s:key name="duration_secs">0.005</s:key>
90
+ <s:key name="invocations">4</s:key>
91
+ </s:dict>
92
+ </s:key>
93
+ <s:key name="command.search.kv">
94
+ <s:dict>
95
+ <s:key name="duration_secs">0.002</s:key>
96
+ <s:key name="invocations">2</s:key>
97
+ </s:dict>
98
+ </s:key>
99
+ <s:key name="command.search.lookups">
100
+ <s:dict>
101
+ <s:key name="duration_secs">0.002</s:key>
102
+ <s:key name="invocations">2</s:key>
103
+ <s:key name="input_count">287</s:key>
104
+ <s:key name="output_count">287</s:key>
105
+ </s:dict>
106
+ </s:key>
107
+ <s:key name="command.search.rawdata">
108
+ <s:dict>
109
+ <s:key name="duration_secs">0.083</s:key>
110
+ <s:key name="invocations">2</s:key>
111
+ </s:dict>
112
+ </s:key>
113
+ <s:key name="command.search.tags">
114
+ <s:dict>
115
+ <s:key name="duration_secs">0.004</s:key>
116
+ <s:key name="invocations">4</s:key>
117
+ <s:key name="input_count">287</s:key>
118
+ <s:key name="output_count">287</s:key>
119
+ </s:dict>
120
+ </s:key>
121
+ <s:key name="command.search.typer">
122
+ <s:dict>
123
+ <s:key name="duration_secs">0.004</s:key>
124
+ <s:key name="invocations">4</s:key>
125
+ <s:key name="input_count">287</s:key>
126
+ <s:key name="output_count">287</s:key>
127
+ </s:dict>
128
+ </s:key>
129
+ <s:key name="dispatch.createProviderQueue">
130
+ <s:dict>
131
+ <s:key name="duration_secs">0.059</s:key>
132
+ <s:key name="invocations">1</s:key>
133
+ </s:dict>
134
+ </s:key>
135
+ <s:key name="dispatch.evaluate">
136
+ <s:dict>
137
+ <s:key name="duration_secs">0.037</s:key>
138
+ <s:key name="invocations">1</s:key>
139
+ </s:dict>
140
+ </s:key>
141
+ <s:key name="dispatch.evaluate.search">
142
+ <s:dict>
143
+ <s:key name="duration_secs">0.036</s:key>
144
+ <s:key name="invocations">1</s:key>
145
+ </s:dict>
146
+ </s:key>
147
+ <s:key name="dispatch.fetch">
148
+ <s:dict>
149
+ <s:key name="duration_secs">0.092</s:key>
150
+ <s:key name="invocations">5</s:key>
151
+ </s:dict>
152
+ </s:key>
153
+ <s:key name="dispatch.readEventsInResults">
154
+ <s:dict>
155
+ <s:key name="duration_secs">0.110</s:key>
156
+ <s:key name="invocations">1</s:key>
157
+ </s:dict>
158
+ </s:key>
159
+ <s:key name="dispatch.stream.local">
160
+ <s:dict>
161
+ <s:key name="duration_secs">0.089</s:key>
162
+ <s:key name="invocations">4</s:key>
163
+ </s:dict>
164
+ </s:key>
165
+ <s:key name="dispatch.timeline">
166
+ <s:dict>
167
+ <s:key name="duration_secs">0.359</s:key>
168
+ <s:key name="invocations">5</s:key>
169
+ </s:dict>
170
+ </s:key>
171
+ </s:dict>
172
+ </s:key>
173
+ <s:key name="messages">
174
+ <s:dict/>
175
+ </s:key>
176
+ <s:key name="request">
177
+ <s:dict>
178
+ <s:key name="id">mysearch</s:key>
179
+ <s:key name="search">search index</s:key>
180
+ </s:dict>
181
+ </s:key>
182
+ <s:key name="eai:acl">
183
+ <s:dict>
184
+ <s:key name="perms">
185
+ <s:dict>
186
+ <s:key name="read">
187
+ <s:list>
188
+ <s:item>admin</s:item>
189
+ </s:list>
190
+ </s:key>
191
+ <s:key name="write">
192
+ <s:list>
193
+ <s:item>admin</s:item>
194
+ </s:list>
195
+ </s:key>
196
+ </s:dict>
197
+ </s:key>
198
+ <s:key name="owner">admin</s:key>
199
+ <s:key name="modifiable">true</s:key>
200
+ <s:key name="sharing">global</s:key>
201
+ <s:key name="app">search</s:key>
202
+ <s:key name="can_write">true</s:key>
203
+ </s:dict>
204
+ </s:key>
205
+ <s:key name="searchProviders">
206
+ <s:list>
207
+ <s:item>vgenovese-mbp15.splunk.com</s:item>
208
+ </s:list>
209
+ </s:key>
210
+ </s:dict>
211
+ </content>
@@ -0,0 +1,267 @@
1
+ <feed xmlns="http://www.w3.org/2005/Atom"
2
+ xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/"
3
+ xmlns:s="http://dev.splunk.com/ns/rest">
4
+ <title>savedsearch</title>
5
+ <id>https://localhost:8089/servicesNS/admin/search/saved/searches</id>
6
+ <updated>2011-07-13T11:57:54-07:00</updated>
7
+ <generator version="102824"/>
8
+ <author>
9
+ <name>Splunk</name>
10
+ </author>
11
+ <link href="/servicesNS/admin/search/saved/searches/_new" rel="create"/>
12
+ <link href="/servicesNS/admin/search/saved/searches/_reload" rel="_reload"/>
13
+ <!-- opensearch nodes elided for brevity. -->
14
+ <s:messages/>
15
+ <entry>
16
+ <title>MySavedSearch</title>
17
+ <id>https://localhost:8089/servicesNS/admin/search/saved/searches/MySavedSearch</id>
18
+ <updated>2011-07-13T11:57:54-07:00</updated>
19
+ <link href="/servicesNS/admin/search/saved/searches/MySavedSearch" rel="alternate"/>
20
+ <author>
21
+ <name>admin</name>
22
+ </author>
23
+ <link href="/servicesNS/admin/search/saved/searches/MySavedSearch" rel="list"/>
24
+ <link href="/servicesNS/admin/search/saved/searches/MySavedSearch/_reload" rel="_reload"/>
25
+ <link href="/servicesNS/admin/search/saved/searches/MySavedSearch" rel="edit"/>
26
+ <link href="/servicesNS/admin/search/saved/searches/MySavedSearch" rel="remove"/>
27
+ <link href="/servicesNS/admin/search/saved/searches/MySavedSearch/move" rel="move"/>
28
+ <link href="/servicesNS/admin/search/saved/searches/MySavedSearch/disable" rel="disable"/>
29
+ <link href="/servicesNS/admin/search/saved/searches/MySavedSearch/dispatch" rel="dispatch"/>
30
+ <link href="/servicesNS/admin/search/saved/searches/MySavedSearch/history" rel="history"/>
31
+ <content type="text/xml">
32
+ <s:dict>
33
+ <s:key name="action.email">0</s:key>
34
+ <s:key name="action.email.auth_password"/>
35
+ <s:key name="action.email.auth_username"/>
36
+ <s:key name="action.email.bcc"/>
37
+ <s:key name="action.email.cc"/>
38
+ <s:key name="action.email.command">
39
+ <![CDATA[$action.email.preprocess_results{default=""}$
40
+ | sendemail "server=$action.email.mailserver{default=localhost}$" "use_ssl=$action.email.use_ssl{default=false}$"
41
+ "use_tls=$action.email.use_tls{default=false}$" "to=$action.email.to$" "cc=$action.email.cc$"
42
+ "bcc=$action.email.bcc$" "from=$action.email.from{default=splunk@localhost}$" "subject=$action.email.subject{recurse=yes}$"
43
+ "format=$action.email.format{default=csv}$" "sssummary=Saved Search [$name$]: $counttype$($results.count$)"
44
+ "sslink=$results.url$" "ssquery=$search$" "ssname=$name$" "inline=$action.email.inline{default=False}$"
45
+ "sendresults=$action.email.sendresults{default=False}$" "sendpdf=$action.email.sendpdf{default=False}$"
46
+ "pdfview=$action.email.pdfview$" "searchid=$search_id$" "graceful=$graceful{default=True}$"
47
+ maxinputs="$action.email.maxresults{default=10000}$" maxtime="$action.email.maxtime{default=5m}$"]]>
48
+ </s:key>
49
+ <s:key name="action.email.format">html</s:key>
50
+ <s:key name="action.email.from">splunk</s:key>
51
+ <s:key name="action.email.hostname"/>
52
+ <s:key name="action.email.inline">0</s:key>
53
+ <s:key name="action.email.mailserver">localhost</s:key>
54
+ <s:key name="action.email.maxresults">10000</s:key>
55
+ <s:key name="action.email.maxtime">5m</s:key>
56
+ <s:key name="action.email.preprocess_results"/>
57
+ <s:key name="action.email.reportPaperOrientation">portrait</s:key>
58
+ <s:key name="action.email.reportPaperSize">letter</s:key>
59
+ <s:key name="action.email.reportServerEnabled">0</s:key>
60
+ <s:key name="action.email.reportServerURL"/>
61
+ <s:key name="action.email.sendpdf">0</s:key>
62
+ <s:key name="action.email.sendresults">0</s:key>
63
+ <s:key name="action.email.subject">Splunk Alert: $name$</s:key>
64
+ <s:key name="action.email.to"/>
65
+ <s:key name="action.email.track_alert">1</s:key>
66
+ <s:key name="action.email.ttl">86400</s:key>
67
+ <s:key name="action.email.use_ssl">0</s:key>
68
+ <s:key name="action.email.use_tls">0</s:key>
69
+ <s:key name="action.populate_lookup">0</s:key>
70
+ <s:key name="action.populate_lookup.command">
71
+ copyresults dest="$action.populate_lookup.dest$" sid="$search_id$"
72
+ </s:key>
73
+ <s:key name="action.populate_lookup.hostname"/>
74
+ <s:key name="action.populate_lookup.maxresults">10000</s:key>
75
+ <s:key name="action.populate_lookup.maxtime">5m</s:key>
76
+ <s:key name="action.populate_lookup.track_alert">0</s:key>
77
+ <s:key name="action.populate_lookup.ttl">120</s:key>
78
+ <s:key name="action.rss">0</s:key>
79
+ <s:key name="action.rss.command">
80
+ createrss "path=$name$.xml" "name=$name$" "link=$results.url$"
81
+ "descr=Alert trigger: $name$, results.count=$results.count$ " "count=30"
82
+ "graceful=$graceful{default=1}$" maxtime="$action.rss.maxtime{default=1m}$"
83
+ </s:key>
84
+ <s:key name="action.rss.hostname"/>
85
+ <s:key name="action.rss.maxresults">10000</s:key>
86
+ <s:key name="action.rss.maxtime">1m</s:key>
87
+ <s:key name="action.rss.track_alert">0</s:key>
88
+ <s:key name="action.rss.ttl">86400</s:key>
89
+ <s:key name="action.script">0</s:key>
90
+ <s:key name="action.script.command">runshellscript "$action.script.filename$"
91
+ "$results.count$" "$search$" "$search$" "$name$"
92
+ "Saved Search [$name$] $counttype$($results.count$)" "$results.url$"
93
+ "$deprecated_arg$" "$search_id$"
94
+ maxtime="$action.script.maxtime{default=5m}$"
95
+ </s:key>
96
+ <s:key name="action.script.hostname"/>
97
+ <s:key name="action.script.maxresults">10000</s:key>
98
+ <s:key name="action.script.maxtime">5m</s:key>
99
+ <s:key name="action.script.track_alert">1</s:key>
100
+ <s:key name="action.script.ttl">600</s:key>
101
+ <s:key name="action.summary_index">0</s:key>
102
+ <s:key name="action.summary_index._name">summary</s:key>
103
+ <s:key name="action.summary_index.command">
104
+ <![CDATA[summaryindex spool=t uselb=t addtime=t index="$action.summary_index._name{required=yes}$"
105
+ file="$name$_$#random$.stash_new" name="$name$"
106
+ marker="$action.summary_index*{format=$KEY=\\\"$VAL\\\",
107
+ key_regex="action.summary_index.(?!(?:command|inline|maxresults|maxtime|ttl|track_alert|(?:_.*))$)(.*)"}$"]]>
108
+ </s:key>
109
+ <s:key name="action.summary_index.hostname"/>
110
+ <s:key name="action.summary_index.inline">1</s:key>
111
+ <s:key name="action.summary_index.maxresults">10000</s:key>
112
+ <s:key name="action.summary_index.maxtime">5m</s:key>
113
+ <s:key name="action.summary_index.track_alert">0</s:key>
114
+ <s:key name="action.summary_index.ttl">120</s:key>
115
+ <s:key name="alert.digest_mode">1</s:key>
116
+ <s:key name="alert.expires">24h</s:key>
117
+ <s:key name="alert.severity">3</s:key>
118
+ <s:key name="alert.suppress"/>
119
+ <s:key name="alert.suppress.period"/>
120
+ <s:key name="alert.track">auto</s:key>
121
+ <s:key name="alert_comparator"/>
122
+ <s:key name="alert_condition"/>
123
+ <s:key name="alert_threshold"/>
124
+ <s:key name="alert_type">always</s:key>
125
+ <s:key name="cron_schedule"/>
126
+ <s:key name="description"/>
127
+ <s:key name="disabled">0</s:key>
128
+ <s:key name="dispatch.buckets">0</s:key>
129
+ <s:key name="dispatch.earliest_time"/>
130
+ <s:key name="dispatch.latest_time"/>
131
+ <s:key name="dispatch.lookups">1</s:key>
132
+ <s:key name="dispatch.max_count">500000</s:key>
133
+ <s:key name="dispatch.max_time">0</s:key>
134
+ <s:key name="dispatch.reduce_freq">10</s:key>
135
+ <s:key name="dispatch.spawn_process">1</s:key>
136
+ <s:key name="dispatch.time_format">%FT%T.%Q%:z</s:key>
137
+ <s:key name="dispatch.ttl">2p</s:key>
138
+ <s:key name="displayview"/>
139
+ <!-- eai:acl nodes elided for brevity. -->
140
+ <s:key name="eai:attributes">
141
+ <s:dict>
142
+ <s:key name="optionalFields">
143
+ <s:list>
144
+ <s:item>action.email</s:item>
145
+ <s:item>action.email.auth_password</s:item>
146
+ <s:item>action.email.auth_username</s:item>
147
+ <s:item>action.email.bcc</s:item>
148
+ <s:item>action.email.cc</s:item>
149
+ <s:item>action.email.command</s:item>
150
+ <s:item>action.email.format</s:item>
151
+ <s:item>action.email.from</s:item>
152
+ <s:item>action.email.hostname</s:item>
153
+ <s:item>action.email.inline</s:item>
154
+ <s:item>action.email.mailserver</s:item>
155
+ <s:item>action.email.maxresults</s:item>
156
+ <s:item>action.email.maxtime</s:item>
157
+ <s:item>action.email.preprocess_results</s:item>
158
+ <s:item>action.email.reportPaperOrientation</s:item>
159
+ <s:item>action.email.reportPaperSize</s:item>
160
+ <s:item>action.email.reportServerEnabled</s:item>
161
+ <s:item>action.email.reportServerURL</s:item>
162
+ <s:item>action.email.sendpdf</s:item>
163
+ <s:item>action.email.sendresults</s:item>
164
+ <s:item>action.email.subject</s:item>
165
+ <s:item>action.email.to</s:item>
166
+ <s:item>action.email.track_alert</s:item>
167
+ <s:item>action.email.ttl</s:item>
168
+ <s:item>action.email.use_ssl</s:item>
169
+ <s:item>action.email.use_tls</s:item>
170
+ <s:item>action.populate_lookup</s:item>
171
+ <s:item>action.populate_lookup.command</s:item>
172
+ <s:item>action.populate_lookup.hostname</s:item>
173
+ <s:item>action.populate_lookup.maxresults</s:item>
174
+ <s:item>action.populate_lookup.maxtime</s:item>
175
+ <s:item>action.populate_lookup.track_alert</s:item>
176
+ <s:item>action.populate_lookup.ttl</s:item>
177
+ <s:item>action.rss</s:item>
178
+ <s:item>action.rss.command</s:item>
179
+ <s:item>action.rss.hostname</s:item>
180
+ <s:item>action.rss.maxresults</s:item>
181
+ <s:item>action.rss.maxtime</s:item>
182
+ <s:item>action.rss.track_alert</s:item>
183
+ <s:item>action.rss.ttl</s:item>
184
+ <s:item>action.script</s:item>
185
+ <s:item>action.script.command</s:item>
186
+ <s:item>action.script.hostname</s:item>
187
+ <s:item>action.script.maxresults</s:item>
188
+ <s:item>action.script.maxtime</s:item>
189
+ <s:item>action.script.track_alert</s:item>
190
+ <s:item>action.script.ttl</s:item>
191
+ <s:item>action.summary_index</s:item>
192
+ <s:item>action.summary_index._name</s:item>
193
+ <s:item>action.summary_index.command</s:item>
194
+ <s:item>action.summary_index.hostname</s:item>
195
+ <s:item>action.summary_index.inline</s:item>
196
+ <s:item>action.summary_index.maxresults</s:item>
197
+ <s:item>action.summary_index.maxtime</s:item>
198
+ <s:item>action.summary_index.track_alert</s:item>
199
+ <s:item>action.summary_index.ttl</s:item>
200
+ <s:item>actions</s:item>
201
+ <s:item>alert.digest_mode</s:item>
202
+ <s:item>alert.expires</s:item>
203
+ <s:item>alert.severity</s:item>
204
+ <s:item>alert.suppress</s:item>
205
+ <s:item>alert.suppress.period</s:item>
206
+ <s:item>alert.track</s:item>
207
+ <s:item>alert_comparator</s:item>
208
+ <s:item>alert_condition</s:item>
209
+ <s:item>alert_threshold</s:item>
210
+ <s:item>alert_type</s:item>
211
+ <s:item>cron_schedule</s:item>
212
+ <s:item>description</s:item>
213
+ <s:item>disabled</s:item>
214
+ <s:item>dispatch.buckets</s:item>
215
+ <s:item>dispatch.earliest_time</s:item>
216
+ <s:item>dispatch.latest_time</s:item>
217
+ <s:item>dispatch.lookups</s:item>
218
+ <s:item>dispatch.max_count</s:item>
219
+ <s:item>dispatch.max_time</s:item>
220
+ <s:item>dispatch.reduce_freq</s:item>
221
+ <s:item>dispatch.spawn_process</s:item>
222
+ <s:item>dispatch.time_format</s:item>
223
+ <s:item>dispatch.ttl</s:item>
224
+ <s:item>displayview</s:item>
225
+ <s:item>is_scheduled</s:item>
226
+ <s:item>is_visible</s:item>
227
+ <s:item>max_concurrent</s:item>
228
+ <s:item>next_scheduled_time</s:item>
229
+ <s:item>qualifiedSearch</s:item>
230
+ <s:item>realtime_schedule</s:item>
231
+ <s:item>request.ui_dispatch_app</s:item>
232
+ <s:item>request.ui_dispatch_view</s:item>
233
+ <s:item>restart_on_searchpeer_add</s:item>
234
+ <s:item>run_on_startup</s:item>
235
+ <s:item>vsid</s:item>
236
+ </s:list>
237
+ </s:key>
238
+ <s:key name="requiredFields">
239
+ <s:list>
240
+ <s:item>search</s:item>
241
+ </s:list>
242
+ </s:key>
243
+ <s:key name="wildcardFields">
244
+ <s:list>
245
+ <s:item>action\..*</s:item>
246
+ <s:item>args\..*</s:item>
247
+ <s:item>dispatch\..*</s:item>
248
+ </s:list>
249
+ </s:key>
250
+ </s:dict>
251
+ </s:key>
252
+ <s:key name="is_scheduled">0</s:key>
253
+ <s:key name="is_visible">1</s:key>
254
+ <s:key name="max_concurrent">1</s:key>
255
+ <s:key name="next_scheduled_time"/>
256
+ <s:key name="qualifiedSearch">search index</s:key>
257
+ <s:key name="realtime_schedule">1</s:key>
258
+ <s:key name="request.ui_dispatch_app"/>
259
+ <s:key name="request.ui_dispatch_view"/>
260
+ <s:key name="restart_on_searchpeer_add">1</s:key>
261
+ <s:key name="run_on_startup">0</s:key>
262
+ <s:key name="search">index</s:key>
263
+ <s:key name="vsid"/>
264
+ </s:dict>
265
+ </content>
266
+ </entry>
267
+ </feed>
@@ -11,7 +11,7 @@ RSpec.configure do |config|
11
11
  end
12
12
 
13
13
  def fixture(file)
14
- File.new( File.expand_path('../fixtures', __FILE__) + "/" + file)
14
+ File.new( File.expand_path('../fixtures', __FILE__) + "/" + file).read
15
15
  end
16
16
 
17
17
  def basic_auth_resource_builder(client, resource)
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ describe Splunker::Models::Finders do
4
+ let(:resource) do
5
+ Splunker::Models::Search::Saved
6
+ end
7
+
8
+ let(:search_fixture) do
9
+ Nokogiri::XML(fixture("saved_search.xml"))
10
+ end
11
+
12
+ before(:each) do
13
+ object_path = "saved/searches/MyFinderTestSavedSearch"
14
+ resource.client.stub(:get).with(object_path).and_return(search_fixture)
15
+ end
16
+
17
+ it "should find_by_id" do
18
+ a = resource.find_by_id("MyFinderTestSavedSearch")
19
+ a.should be_a(Splunker::Models::Search::Saved)
20
+ a.title.should eq("MySavedSearch")
21
+ end
22
+
23
+ it "should find by id by default" do
24
+ a = resource.find("MyFinderTestSavedSearch")
25
+ a.should be_a(Splunker::Models::Search::Saved)
26
+ a.title.should eq("MySavedSearch")
27
+ end
28
+ end
29
+
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+
3
+ describe Splunker::Models::Resource do
4
+
5
+ let(:model) do
6
+ xml = Nokogiri::XML(fixture("saved_search.xml"))
7
+ Splunker::Models::Resource.new(xml)
8
+ end
9
+
10
+ it "should reference a client" do
11
+ model.class.client.should be_a(Splunker::Client)
12
+ end
13
+
14
+ it "should act on attribute methods" do
15
+ model.title.should eq("MySavedSearch")
16
+ end
17
+
18
+ it "should write to attributes through assignment methods" do
19
+ model.title = "josh's search"
20
+ model.title.should eq("josh's search")
21
+ end
22
+
23
+ it "should respond to attribute methods" do
24
+ model.respond_to?(:updated).should be_true
25
+ end
26
+
27
+ it "should not respond to missing methods" do
28
+ model.respond_to?(:fake_method).should be_false
29
+ end
30
+
31
+ it "should raise a NoMethodError when accessing missing methods" do
32
+ expect {
33
+ model.fake_method
34
+ }.to raise_exception NoMethodError
35
+ end
36
+
37
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ describe Splunker::Models::Search::Job do
4
+ let(:resource) do
5
+ Splunker::Models::Search::Job
6
+ end
7
+
8
+ let(:job_fixture) do
9
+ Nokogiri::XML(fixture("job_mysearch.xml"))
10
+ end
11
+
12
+ # Covered in finders_spec, but I'm feeling redundant this morning.
13
+ context "searching" do
14
+ before(:each) do
15
+ object_path = "jobs/MyFinderTestJob"
16
+ resource.client.stub(:get).with(object_path).and_return(job_fixture)
17
+ end
18
+
19
+ it "should find by id by default" do
20
+ a = resource.find("MyFinderTestJob")
21
+ a.should be_a(Splunker::Models::Search::Job)
22
+ a.title.should eq("search index")
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,4 @@
1
+ require 'spec_helper'
2
+
3
+ describe Splunker::Models::Search::Saved do
4
+ end
@@ -0,0 +1,83 @@
1
+ require 'spec_helper'
2
+
3
+ describe Splunker::Models::XmlProcessor do
4
+
5
+ let(:processor) do
6
+ Splunker::Models::XmlProcessor
7
+ end
8
+
9
+ let(:xml) do
10
+ Nokogiri::Slop(fixture("saved_search.xml"))
11
+ end
12
+
13
+ context "hashify xml" do
14
+ let(:hash) do
15
+ processor.hashify(xml)
16
+ end
17
+
18
+ it "should find top level attributes" do
19
+ hash["id"].should eq("https://localhost:8089/servicesNS/admin/search/saved/searches/MySavedSearch")
20
+ hash["title"].should eq("MySavedSearch")
21
+ end
22
+
23
+ it "should process the inner dict of content" do
24
+ hash["action"]["email"]["mailserver"].should eq("localhost")
25
+ end
26
+ end
27
+
28
+ context "top node detection" do
29
+ it "should return the feed node if available" do
30
+ node = processor.top_node(xml)
31
+ # TODO: I'm aware this is dumb.
32
+ node.children.each do |n|
33
+ if n.name == "title"
34
+ n.text.should eq("MySavedSearch")
35
+ break
36
+ end
37
+ end
38
+ end
39
+
40
+ it "should return the entry node if no feed is found" do
41
+ entry = Nokogiri::XML(xml.xpath("//xmlns:author").to_xml)
42
+ node = processor.top_node(entry)
43
+ node.text.strip.should eq("Splunk")
44
+ end
45
+ end
46
+
47
+ context "dictionary builders" do
48
+ it "should build a nested hash from a string in dot notation" do
49
+ h = {
50
+ "action" => {
51
+ "email" => {
52
+ "format" => "html"
53
+ }
54
+ }
55
+ }
56
+
57
+ h = processor.place_in_nested_hash("action.fun.times", "yes", h)
58
+ h = processor.place_in_nested_hash("joshua", "murray", h)
59
+ h["action"]["email"]["format"].should eq("html")
60
+ h["action"]["fun"]["times"].should eq("yes")
61
+ h["joshua"].should eq("murray")
62
+ end
63
+
64
+ it "should have the power of recursion with nested_hash" do
65
+ h = {
66
+ "action" => {
67
+ "email" => {
68
+ "format" => "html"
69
+ }
70
+ }
71
+ }
72
+
73
+ processor.nested_hash(["action","email","maxtime"], "5m", h)
74
+ processor.nested_hash(["action","populate_lookup","maxresults"], 10000, h)
75
+ processor.nested_hash(["dispatch", "buckets"], 0, h)
76
+
77
+ h["action"]["email"]["format"].should eq("html")
78
+ h["action"]["email"]["maxtime"].should eq("5m")
79
+ h["action"]["populate_lookup"]["maxresults"].should eq(10000)
80
+ h["dispatch"]["buckets"].should eq(0)
81
+ end
82
+ end
83
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: splunker
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-09-20 00:00:00.000000000 Z
12
+ date: 2012-09-24 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: nokogiri
@@ -132,14 +132,17 @@ files:
132
132
  - lib/splunker/connection.rb
133
133
  - lib/splunker/errors.rb
134
134
  - lib/splunker/faraday_middleware.rb
135
+ - lib/splunker/models.rb
135
136
  - lib/splunker/models/finders.rb
136
137
  - lib/splunker/models/resource.rb
137
- - lib/splunker/models/search/jobs.rb
138
- - lib/splunker/models/search/results.rb
138
+ - lib/splunker/models/search/job.rb
139
139
  - lib/splunker/models/search/saved.rb
140
+ - lib/splunker/models/xml_processor.rb
140
141
  - lib/splunker/request.rb
141
142
  - lib/splunker/version.rb
142
143
  - script/console
144
+ - spec/fixtures/job_mysearch.xml
145
+ - spec/fixtures/saved_search.xml
143
146
  - spec/fixtures/search_results_from_job.xml
144
147
  - spec/functional/request_spec.rb
145
148
  - spec/rspec_let_definitions.rb
@@ -149,6 +152,11 @@ files:
149
152
  - spec/unit/client_spec.rb
150
153
  - spec/unit/configuration_spec.rb
151
154
  - spec/unit/errors_spec.rb
155
+ - spec/unit/models/finders_spec.rb
156
+ - spec/unit/models/resource_spec.rb
157
+ - spec/unit/models/search/job_spec.rb
158
+ - spec/unit/models/search/saved_spec.rb
159
+ - spec/unit/models/xml_processor_spec.rb
152
160
  - spec/unit/request_spec.rb
153
161
  - spec/unit/splunker_spec.rb
154
162
  - splunker.gemspec
@@ -177,6 +185,8 @@ signing_key:
177
185
  specification_version: 3
178
186
  summary: A Ruby client for the Splunk API
179
187
  test_files:
188
+ - spec/fixtures/job_mysearch.xml
189
+ - spec/fixtures/saved_search.xml
180
190
  - spec/fixtures/search_results_from_job.xml
181
191
  - spec/functional/request_spec.rb
182
192
  - spec/rspec_let_definitions.rb
@@ -186,5 +196,10 @@ test_files:
186
196
  - spec/unit/client_spec.rb
187
197
  - spec/unit/configuration_spec.rb
188
198
  - spec/unit/errors_spec.rb
199
+ - spec/unit/models/finders_spec.rb
200
+ - spec/unit/models/resource_spec.rb
201
+ - spec/unit/models/search/job_spec.rb
202
+ - spec/unit/models/search/saved_spec.rb
203
+ - spec/unit/models/xml_processor_spec.rb
189
204
  - spec/unit/request_spec.rb
190
205
  - spec/unit/splunker_spec.rb
@@ -1,12 +0,0 @@
1
- module Splunker
2
- module Models
3
- class Search::Jobs < Resource
4
- # http://docs.splunk.com/Documentation/Splunk/4.3.3/RESTAPI/RESTsearch#search.2Fjobs
5
- # Jobs are a data structure in themselves
6
- # Jobs have subresources for:
7
- # * scheduled search results
8
- def self.results(scheduled_search_id)
9
- end
10
- end
11
- end
12
- end
@@ -1,6 +0,0 @@
1
- module Splunker
2
- module Models
3
- class Search::Results < Resource
4
- end
5
- end
6
- end