|
| 1 | +Introduction |
| 2 | +------------ |
| 3 | + |
| 4 | +Here's a simple program using the Python SDK. Obviously you'll have to |
| 5 | +change the host, username, password, and any other data that you may |
| 6 | +have customized. And don't experiment on your production Splunk |
| 7 | +server! Install the free version of Splunk on your own machine to |
| 8 | +experiment.:: |
| 9 | + |
| 10 | + import splunklib.client as client |
| 11 | + c = client.connect(host="localhost", |
| 12 | + port=8089, |
| 13 | + scheme="https", |
| 14 | + username="admin", |
| 15 | + password="changeme") |
| 16 | + saved_searches = c.saved_searches |
| 17 | + mss = saved_searches.create("my_saved_search", "search * | head 10") |
| 18 | + assert "my_saved_search" in saved_searches |
| 19 | + saved_searches.delete("my_saved_search") |
| 20 | + |
| 21 | +It's worth spending a few minute in ``ipython`` examining the objects |
| 22 | +produced in this example. ``c`` is a ``Service``[[TODO: link to |
| 23 | +reference docs]], which has [fields](link to list of fields in |
| 24 | +Service's docs) that provide access to most of Splunk's contents. |
| 25 | +``saved_searches`` is a ``Collection``, and each entity in it is |
| 26 | +identified by a unique name (``"my_saved_search"`` in the example). |
| 27 | +All the names should be alphanumeric plus ``_`` and ``-``; no spaces |
| 28 | +are allowed[#]_. |
| 29 | + |
| 30 | +.. [#] Splunk has two names for each entity: the pretty one meant to |
| 31 | +be displayed to users in the web browser, and the alphanumeric one |
| 32 | +that shows up in the URL of the REST call. It is the latter that is |
| 33 | +used in the SDK. Thus the Search app in Splunk is called "Search" |
| 34 | +in the web interface, but to fetch it via the SDK, you would write |
| 35 | +``c.apps['search']``, not ``c.apps['Search']``. The "Getting |
| 36 | +Started" app is ``c.apps['gettingstarted']``, not ``c.apps['Getting Started']``. |
| 37 | + |
| 38 | +A ``Collection`` acts like a dictionary. You can call ``keys``, |
| 39 | +``iteritems``, and ``itervalues`` just like on a dictionary. However, |
| 40 | +you cannot assign to keys. ``saved_searches['some_name'] = ...`` is |
| 41 | +nonsense. Use the ``create`` method instead. Also, |
| 42 | +``del saved_searches['some_name']`` does not currently work. Use the |
| 43 | +``delete`` method instead. |
| 44 | + |
| 45 | +Note that in the example code we did not assert:: |
| 46 | + |
| 47 | + mss == saved_searches["my_saved_search"] |
| 48 | + |
| 49 | +The Python objects you are manipulating represent snapshots of the |
| 50 | +server's state at some point in the past. There is no good way of |
| 51 | +defining equality on these that isn't misleading in many cases, so we |
| 52 | +have made ``==`` and ``!=`` raise exceptions for entities. |
| 53 | + |
| 54 | +Another side effect of using snapshots: after we delete the saved |
| 55 | +search in the example, ``mss`` is still bound to the same local object |
| 56 | +representing that search, even though it no longer exists on the |
| 57 | +server. If you need to update your snapshot, call the ``refresh`` |
| 58 | +method[#]_. For more on caching and snapshots, see [[TODO: link to |
| 59 | +section on roundtrips and caching]] |
| 60 | + |
| 61 | +.. [#] Calling ``refresh`` on an entity that has already been deleted |
| 62 | +raises an ``HTTPError``. |
| 63 | + |
| 64 | +You can access the fields of an entity either as if they were keys in |
| 65 | +a dictionary, or fields of an object:: |
| 66 | + |
| 67 | + mss['search'] == "search * | head 10" |
| 68 | + mss.search == "search * | head 10" |
| 69 | + |
| 70 | + mss['action.email'] == '0' |
| 71 | + mss.action.email == '0' |
| 72 | + |
| 73 | +A ``.`` isn't a valid character in identifiers in Python. The second |
| 74 | +form is actually a series of field lookups. As as side effect, you can |
| 75 | +get groups of fields that share prefixes.:: |
| 76 | + |
| 77 | + mss['action'] == {'email': '0', |
| 78 | + 'populate_lookup': '0', |
| 79 | + 'rss': '0', |
| 80 | + 'script': '0', |
| 81 | + 'summary_index': '0'} |
| 82 | + mss.action == {'email': '0', |
| 83 | + 'populate_lookup': '0', |
| 84 | + 'rss': '0', |
| 85 | + 'script': '0', |
| 86 | + 'summary_index': '0'} |
| 87 | + |
| 88 | +Those look like dictionaries, but they're actually a subclass called |
| 89 | +``Record`` [[TODO: link to reference documentation]] that allows keys |
| 90 | +to be looked up as fields. [[TODO: Implement keys() on entities, and |
| 91 | +document it here]] In addition to fields, each kind of entity has a |
| 92 | +range of methods.:: |
| 93 | + |
| 94 | + mss.dispatch() # Runs the saved search. |
| 95 | + mss.suppress(30) # Suppress all alerts from this saved search for 30 seconds |
| 96 | + |
| 97 | +This should be enough information to understand the reference |
| 98 | +documentation and start using the SDK productively. |
| 99 | + |
| 100 | +Roundtrips and caching |
| 101 | +---------------------- |
| 102 | + |
| 103 | +The rate limiting step in most programs that call REST APIs is calls |
| 104 | +to the server. The SDK is designed to minimize and postpone these as |
| 105 | +much as possible. When you fetch an object from the SDK, you get a |
| 106 | +snapshot. If there are updates on the server after that snapshot, you |
| 107 | +won't know about them until you call ``refresh`` on your object. The |
| 108 | +object might even have been deleted. |
| 109 | + |
| 110 | + |
| 111 | + |
| 112 | + |
| 113 | + |
0 commit comments