Skip to content

Commit 31ae9c8

Browse files
author
Frederick Ross
committed
Got most things running with Ace.
Everything left appears to be an issue in the Ace beta, not the SDK.
1 parent c1ea5e2 commit 31ae9c8

File tree

9 files changed

+82
-24
lines changed

9 files changed

+82
-24
lines changed

splunklib/binding.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -696,7 +696,7 @@ def _abspath(self, path_segment,
696696
c._abspath('/a/b c/d') == '/a/b%20c/d'
697697
c._abspath('apps/local/search') == \
698698
'/servicesNS/boris/search/apps/local/search'
699-
c._abspath('apps/local/search', sharing='systmem') == \
699+
c._abspath('apps/local/search', sharing='system') == \
700700
'/servicesNS/nobody/system/apps/local/search'
701701
url = c.authority + c._abspath('apps/local/sharing')
702702
"""
@@ -722,8 +722,9 @@ def _abspath(self, path_segment,
722722

723723
oname = "-" if ns.owner is None else ns.owner
724724
aname = "-" if ns.app is None else ns.app
725-
return UrlEncoded("/servicesNS/%s/%s/%s" % (oname, aname, path_segment),
725+
path = UrlEncoded("/servicesNS/%s/%s/%s" % (oname, aname, path_segment),
726726
skip_encode=skip_encode)
727+
return path
727728

728729
def connect(**kwargs):
729730
"""Return an authenticated ``Context`` object.

splunklib/client.py

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,15 @@
110110
class IncomparableException(Exception):
111111
pass
112112

113+
def trailing(template, *targets):
114+
s = template
115+
for t in targets:
116+
n = s.find(t)
117+
if n == -1:
118+
raise ValueError("Target " + t + " not found in template.")
119+
s = s[n + len(t):]
120+
return s
121+
113122
# Filter the given state content record according to the given arg list.
114123
def _filter_content(content, *args):
115124
if len(args) > 0:
@@ -458,7 +467,8 @@ def get(self, path_segment="", owner=None, app=None, sharing=None, **query):
458467
if path_segment.startswith('/'):
459468
path = path_segment
460469
else:
461-
path = self.path + path_segment
470+
path = self.service._abspath(self.path + path_segment, owner=owner,
471+
app=app, sharing=sharing)
462472
# ^-- This was "%s%s" % (self.path, path_segment).
463473
# That doesn't work, because self.path may be UrlEncoded.
464474
return self.service.get(path,
@@ -513,7 +523,8 @@ def post(self, path_segment="", owner=None, app=None, sharing=None, **query):
513523
if path_segment.startswith('/'):
514524
path = path_segment
515525
else:
516-
path = self.path + path_segment
526+
path = self.service._abspath(self.path + path_segment, owner=owner,
527+
app=app, sharing=sharing)
517528
return self.service.post(path,
518529
owner=owner, app=app, sharing=sharing,
519530
**query)
@@ -986,7 +997,13 @@ def _entity_path(self, state):
986997
# This has been factored out so that it can be easily
987998
# overloaded by Configurations, which has to switch its
988999
# entities' endpoints from its own properties/ to configs/.
989-
return urllib.unquote(state.links.alternate)
1000+
raw_path = urllib.unquote(state.links.alternate)
1001+
if 'servicesNS/' in raw_path:
1002+
return trailing(raw_path, 'servicesNS/', '/', '/')
1003+
elif 'services/' in raw_path:
1004+
return trailing(raw_path, 'services/')
1005+
else:
1006+
return raw_path
9901007

9911008
def _load_list(self, response):
9921009
"""Converts *response* to a list of entities.
@@ -1080,7 +1097,7 @@ def create(self, name, **params):
10801097
state = _parse_atom_entry(entry)
10811098
entity = self.item(
10821099
self.service,
1083-
urllib.unquote(state.links.alternate),
1100+
self._entity_path(state),
10841101
state=state)
10851102
return entity
10861103

@@ -1278,7 +1295,7 @@ def _entity_path(self, state):
12781295
# Overridden to make all the ConfigurationFile objects
12791296
# returned refer to the configs/ path instead of the
12801297
# properties/ path used by Configrations.
1281-
return self.service._abspath(PATH_CONF % state['title'])
1298+
return PATH_CONF % state['title']
12821299

12831300

12841301
class Stanza(Entity):
@@ -1363,6 +1380,20 @@ def clean(self, timeout=60):
13631380
raise OperationError, "Operation timed out."
13641381
return self
13651382

1383+
def disable(self):
1384+
"""Disables this index."""
1385+
# Starting in Ace, we have to do this with specific sharing,
1386+
# unlike most other entities.
1387+
self.post("disable", sharing="system")
1388+
return self
1389+
1390+
def enable(self):
1391+
"""Enables this index."""
1392+
# Starting in Ace, we have to reenable this with a specific
1393+
# sharing unlike most other entities.
1394+
self.post("enable", sharing="system")
1395+
return self
1396+
13661397
def roll_hot_buckets(self):
13671398
"""Performs rolling hot buckets for this index."""
13681399
self.post("roll-hot-buckets")
@@ -1819,7 +1850,7 @@ def export(self, query, **params):
18191850
to two for create followed by preview), plus at most two more
18201851
if autologin is turned on.
18211852
1822-
:raises SyntaxError: on invalid queries.
1853+
:raises ValueError: on invalid queries.
18231854
18241855
:param query: Splunk search language query to run
18251856
:type query: ``str``
@@ -1831,8 +1862,8 @@ def export(self, query, **params):
18311862
try:
18321863
return self.post(path_segment="export", search=query, **params).body
18331864
except HTTPError as he:
1834-
if he.status == 400 and 'Search operation' in str(he):
1835-
raise SyntaxError(str(he))
1865+
if he.status == 400:
1866+
raise ValueError(str(he))
18361867
else:
18371868
raise
18381869

@@ -1858,7 +1889,7 @@ def oneshot(self, query, **params):
18581889
to two for create followed by results), plus at most two more
18591890
if autologin is turned on.
18601891
1861-
:raises SyntaxError: on invalid queries.
1892+
:raises ValueError: on invalid queries.
18621893
18631894
:param query: Splunk search language query to run
18641895
:type query: ``str``
@@ -1870,8 +1901,8 @@ def oneshot(self, query, **params):
18701901
try:
18711902
return self.post(search=query, exec_mode="oneshot", **params).body
18721903
except HTTPError as he:
1873-
if he.status == 400 and 'Search operation' in str(he):
1874-
raise SyntaxError(str(he))
1904+
if he.status == 400:
1905+
raise ValueError(str(he))
18751906
else:
18761907
raise
18771908

tests/test_app.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,19 @@ def check_app(self, app):
2828
def test_read(self):
2929
service = client.connect(**self.opts.kwargs)
3030

31+
disabled_app = 'sdk-test-app-disabled'
32+
if (disabled_app in service.apps):
33+
service.apps.delete(disabled_app)
34+
disabled = service.apps.create(disabled_app)
35+
disabled.disable()
36+
3137
for app in service.apps:
3238
self.check_app(app)
3339
app.refresh()
3440
self.check_app(app)
3541

42+
service.apps.delete(disabled_app)
43+
3644
def test_crud(self):
3745
service = client.connect(**self.opts.kwargs)
3846

tests/test_collection.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ def check_iterable(self, collection, count):
7777
seen = 0
7878
for item in collection:
7979
seen += 1
80-
print item.name
80+
item.name
8181
self.assertEqual(seen, count)
8282

8383
def test_apps(self):

tests/test_event_type.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,15 @@ def test_crud(self):
5656
kwargs['priority'] = 3
5757
event_type.update(**kwargs)
5858
event_type.refresh()
59+
testlib.restart(service)
5960
self.check_content(event_type, **kwargs)
6061

6162
event_type.enable()
6263
event_type.refresh()
6364
self.check_content(event_type, disabled=0)
6465

6566
event_types.delete('sdk-test')
66-
self.assertFalse('sdk-teset' in event_types)
67+
self.assertFalse('sdk-test' in event_types)
6768

6869
if __name__ == "__main__":
6970
testlib.main()

tests/test_fired_alert.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,9 @@ def test_crud(self):
8686

8787
# Wait for the saved search to run. When it runs we will see a new job
8888
# show up in the search's history.
89-
testlib.wait(search, lambda search: len(search.history()) == 1)
89+
def f(search):
90+
return len(search.history()) == 1
91+
testlib.wait(search, f)
9092
self.assertEqual(len(search.history()), 1)
9193

9294
# When it first runs the alert count should be zero.

tests/test_index.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,13 @@ def test_read(self):
5757

5858
def test_disable(self):
5959
self.index.disable()
60+
testlib.restart(self.service)
6061
self.index.refresh()
6162
self.assertEqual(self.index['disabled'], '1')
6263

6364
def test_enable(self):
6465
self.index.enable()
66+
testlib.restart(self.service)
6567
self.index.refresh()
6668
self.assertEqual(self.index['disabled'], '0')
6769

@@ -76,8 +78,11 @@ def test_attach(self):
7678
cn = self.index.attach()
7779
cn.send("Hello Boris!\r\n")
7880
cn.close()
79-
print count
80-
self.assertEventuallyEqual(lambda: self.index.refresh() and int(self.index['totalEventCount']), count+1)
81+
def f():
82+
self.index.refresh()
83+
n = int(self.index['totalEventCount'])
84+
return n
85+
self.assertEventuallyEqual(f, count+1)
8186

8287
def test_submit(self):
8388
self.index.refresh()

tests/test_job.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,13 +94,12 @@ def test_crud(self):
9494
result = results.ResultsReader(jobs.export("search index=_internal earliest=-1m | head 3"))
9595
self.assertEqual(result.is_preview, False)
9696
d = result.next()
97-
print d
9897
self.assertTrue(isinstance(d, dict) or isinstance(d, results.Message))
9998
self.assertTrue(len(list(d for d in result if isinstance(d, dict))) <= 3)
10099

101-
self.assertRaises(SyntaxError, jobs.oneshot, "asdaf;lkj2r23=")
100+
self.assertRaises(ValueError, jobs.oneshot, "asdaf;lkj2r23=")
102101

103-
self.assertRaises(SyntaxError, jobs.export, "asdaf;lkj2r23=")
102+
self.assertRaises(ValueError, jobs.export, "asdaf;lkj2r23=")
104103

105104
# Make sure we can create a job
106105
job = jobs.create("search index=sdk-tests earliest=-1m | head 1")
@@ -164,7 +163,9 @@ def test_results(self):
164163
index = service.indexes['_internal']
165164
self.assertTrue(index['totalEventCount'] > 0)
166165

167-
job = jobs.create("search index=_internal | head 1000 | stats count")
166+
job = jobs.create("search index=_internal | head 100 | stats count")
167+
job.refresh()
168+
self.assertEqual(job['isDone'], '0')
168169
self.assertRaises(ValueError, job.results)
169170
reader = results.ResultsReader(job.results(timeout=60))
170171
job.refresh()
@@ -177,14 +178,14 @@ def test_results(self):
177178
self.assertLessEqual(int(result["count"]), 1000)
178179

179180
# Repeat the same thing, but without the .is_preview reference.
180-
job = jobs.create("search index=_internal | head 1000 | stats count")
181+
job = jobs.create("search index=_internal | head 100 | stats count")
181182
self.assertRaises(ValueError, job.results)
182183
reader = results.ResultsReader(job.results(timeout=60))
183184
job.refresh()
184185
self.assertEqual(job['isDone'], '1')
185186
result = reader.next()
186187
self.assertTrue(isinstance(result, dict))
187-
self.assertLessEqual(int(result["count"]), 1000)
188+
self.assertLessEqual(int(result["count"]), 30)
188189

189190
def test_results_reader(self):
190191
# Run jobs.export("search index=_internal | stats count",

tests/test_service.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,15 @@ def test_namespaces(self):
125125
self.assertFalse(service.apps.contains(appname))
126126
self.assertFalse(service.users.contains(username))
127127

128+
def test_trailing(self):
129+
self.assertRaises(ValueError, client.trailing, 'this is a test', 'boris')
130+
self.assertRaises(ValueError, client.trailing, 'this is a test', 's is', 'boris')
131+
template = '/servicesNS/boris/search/another/path/segment/that runs on'
132+
self.assertEqual(template, client.trailing(template))
133+
self.assertEqual('boris/search/another/path/segment/that runs on', client.trailing(template, 'ervicesNS/'))
134+
self.assertEqual('another/path/segment/that runs on', client.trailing(template, 'servicesNS/', '/', '/'))
135+
136+
128137
def test_parse(self):
129138
service = client.connect(**self.opts.kwargs)
130139

0 commit comments

Comments
 (0)