7070PATH_SAVED_SEARCHES = "saved/searches/"
7171PATH_STANZA = "configs/conf-%s/%s" # (file, stanza)
7272PATH_USERS = "authentication/users/"
73+ PATH_RECEIVERS_STREAM = "receivers/stream"
74+ PATH_RECEIVERS_SIMPLE = "receivers/simple"
7375
7476XNAMEF_ATOM = "{http://www.w3.org/2005/Atom}%s"
7577XNAME_ENTRY = XNAMEF_ATOM % "entry"
@@ -297,7 +299,7 @@ def restart(self):
297299 @property
298300 def roles (self ):
299301 """Returns a collection of user roles."""
300- return Collection (self , PATH_ROLES )
302+ return Roles (self )
301303
302304 def search (self , query , ** kwargs ):
303305 return self .jobs .create (query , ** kwargs )
@@ -493,9 +495,6 @@ def __init__(self, service, path, **kwargs):
493495 self ._state = None
494496 self .refresh (kwargs .get ('state' , None )) # "Prefresh"
495497
496- def __call__ (self , * args ):
497- return self .content (* args )
498-
499498 def __eq__ (self , other ):
500499 """Raises IncomparableException.
501500
@@ -991,27 +990,31 @@ def attach(self, host=None, source=None, sourcetype=None):
991990 if host is not None : args ['host' ] = host
992991 if source is not None : args ['source' ] = source
993992 if sourcetype is not None : args ['sourcetype' ] = sourcetype
994- path = "receivers/stream?%s" % urllib .urlencode (args )
993+ path = UrlEncoded ( PATH_RECEIVERS_STREAM + "?" + urllib .urlencode (args ), skip_encode = True )
995994
996995 # Since we need to stream to the index connection, we have to keep
997996 # the connection open and use the Splunk extension headers to note
998997 # the input mode
999- cn = self .service .connect ()
1000- cn .write ("POST %s HTTP/1.1\r \n " % self .service ._abspath (path ))
1001- cn .write ("Host: %s:%s\r \n " % (self .service .host , self .service .port ))
1002- cn .write ("Accept-Encoding: identity\r \n " )
1003- cn .write ("Authorization: %s\r \n " % self .service .token )
1004- cn .write ("X-Splunk-Input-Mode: Streaming\r \n " )
1005- cn .write ("\r \n " )
1006- return cn
998+ sock = self .service .connect ()
999+ headers = ["POST %s HTTP/1.1\r \n " % self .service ._abspath (path ),
1000+ "Host: %s:%s\r \n " % (self .service .host , int (self .service .port )),
1001+ "Accept-Encoding: identity\r \n " ,
1002+ "Authorization: %s\r \n " % self .service .token ,
1003+ "X-Splunk-Input-Mode: Streaming\r \n " ,
1004+ "\r \n " ]
1005+ for h in headers :
1006+ sock .write (h )
1007+ return sock
10071008
10081009 def clean (self , timeout = 60 ):
10091010 """Deletes the contents of the index.
10101011
10111012 :param `timeout`: The time-out period for the operation, in seconds (the
10121013 default is 60).
10131014 """
1014- saved = self .refresh ()('maxTotalDataSizeMB' , 'frozenTimePeriodInSecs' )
1015+ self .refresh ()
1016+ tds = self ['maxTotalDataSizeMB' ]
1017+ ftp = self ['frozenTimePeriodInSecs' ]
10151018 self .update (maxTotalDataSizeMB = 1 , frozenTimePeriodInSecs = 1 )
10161019 self .roll_hot_buckets ()
10171020
@@ -1022,7 +1025,9 @@ def clean(self, timeout=60):
10221025 count += 1
10231026 self .refresh ()
10241027
1025- self .update (** saved ) # Restore original values
1028+ # Restore original values
1029+ self .update (maxTotalDataSizeMB = tds ,
1030+ frozenTimePeriodInSecs = ftp )
10261031 if self .content .totalEventCount != '0' :
10271032 raise OperationError , "Operation timed out."
10281033 return self
@@ -1033,7 +1038,7 @@ def roll_hot_buckets(self):
10331038 return self
10341039
10351040 def submit (self , event , host = None , source = None , sourcetype = None ):
1036- """Submits an event to the index using ``HTTP POST``.
1041+ """Submit a single event to the index using ``HTTP POST``.
10371042
10381043 :param `host`: The host value of the event.
10391044 :param `source`: The source value of the event.
@@ -1048,7 +1053,7 @@ def submit(self, event, host=None, source=None, sourcetype=None):
10481053 # is that we are not sending a POST request encoded using
10491054 # x-www-form-urlencoded (as we do not have a key=value body),
10501055 # because we aren't really sending a "form".
1051- path = UrlEncoded ("receivers/simple?%s" % urllib .urlencode (args ), skip_encode = True )
1056+ path = UrlEncoded (PATH_RECEIVERS_SIMPLE + "?" + urllib .urlencode (args ), skip_encode = True )
10521057 self .service .request (path , method = "POST" , body = event )
10531058 return self
10541059
@@ -1311,7 +1316,7 @@ def preview(self, **query_params):
13111316 """Fetch an InputStream IO handle of preview search results.
13121317
13131318 Unlike ``results``, which requires a job to be finished to
1314- return any results, ``results_preview `` returns whatever
1319+ return any results, ``preview `` returns whatever
13151320 Splunk has so far, whether the job is running or not. The
13161321 returned search results are the raw data from the server. Pass
13171322 the handle returned to ``results.ResultsReader`` to get a
@@ -1321,7 +1326,7 @@ def preview(self, **query_params):
13211326 import splunklib.results as results
13221327 s = client.connect(...)
13231328 job = s.jobs.create("search * | head 5")
1324- r = results.ResultsReader(job.results_preview ())
1329+ r = results.ResultsReader(job.preview ())
13251330 if r.is_preview:
13261331 print "Preview of a running search job."
13271332 else:
@@ -1636,8 +1641,15 @@ def __init__(self, service):
16361641 def __getitem__ (self , key ):
16371642 return Collection .__getitem__ (self , key .lower ())
16381643
1644+ def __contains__ (self , name ):
1645+ return Collection .__contains__ (self , name .lower ())
1646+
16391647 def contains (self , name ):
1640- return Collection .contains (self , name .lower ())
1648+ """Deprecated: Use in operator instead.
1649+
1650+ Check if there is a user *name* in this Splunk instance.
1651+ """
1652+ return Collection .__contains__ (self , name .lower ())
16411653
16421654 def create (self , username , password , roles , ** params ):
16431655 """Create a new user.
@@ -1667,6 +1679,8 @@ def create(self, username, password, roles, **params):
16671679 raise ValueError ("Invalid username: %s" % str (username ))
16681680 username = username .lower ()
16691681 self .post (name = username , password = password , roles = roles , ** params )
1682+ # splunkd doesn't return the user in the POST response body,
1683+ # so we have to make a second round trip to fetch it.
16701684 response = self .get (username )
16711685 entry = _load_atom (response , XNAME_ENTRY ).entry
16721686 state = _parse_atom_entry (entry )
@@ -1679,6 +1693,62 @@ def create(self, username, password, roles, **params):
16791693 def delete (self , name ):
16801694 return Collection .delete (self , name .lower ())
16811695
1696+ class Roles (Collection ):
1697+ """Roles in the Splunk instance."""
1698+ def __init__ (self , service ):
1699+ return Collection .__init__ (self , service , PATH_ROLES )
1700+
1701+ def __getitem__ (self , key ):
1702+ return Collection .__getitem__ (self , key .lower ())
1703+
1704+ def __contains__ (self , name ):
1705+ return Collection .__contains__ (self , name .lower ())
1706+
1707+ def contains (self , name ):
1708+ """Deprecated: Use in operator instead.
1709+
1710+ Check if there is a user *name* in this Splunk instance.
1711+ """
1712+ return Collection .__contains__ (self , name .lower ())
1713+
1714+ def create (self , name , ** params ):
1715+ """Create a new role.
1716+
1717+ This function makes two roundtrips to the server, plus at most
1718+ two more if autologin is turned on.
1719+
1720+ :param name: Name for the role
1721+ :type name: string
1722+ :param params: Optional parameters. See the `REST API documentation<http://docs/Documentation/Splunk/4.3.2/RESTAPI/RESTaccess#POST_authorization.2Froles>`_.
1723+ :return: A reference to the new role.
1724+ :rtype: ``Entity``
1725+
1726+ **Example**::
1727+
1728+ import splunklib.client as client
1729+ c = client.connect(...)
1730+ roles = c.roles
1731+ paltry = roles.create("paltry", imported_roles="user", defaultApp="search")
1732+ """
1733+ if not isinstance (name , basestring ):
1734+ raise ValueError ("Invalid role name: %s" % str (name ))
1735+ name = name .lower ()
1736+ self .post (name = name , ** params )
1737+ # splunkd doesn't return the user in the POST response body,
1738+ # so we have to make a second round trip to fetch it.
1739+ response = self .get (name )
1740+ entry = _load_atom (response , XNAME_ENTRY ).entry
1741+ state = _parse_atom_entry (entry )
1742+ entity = self .item (
1743+ self .service ,
1744+ urllib .unquote (state .links .alternate ),
1745+ state = state )
1746+ return entity
1747+
1748+ def delete (self , name ):
1749+ return Collection .delete (self , name .lower ())
1750+
1751+
16821752class OperationError (Exception ):
16831753 """Raised for a failed operation, such as a time out."""
16841754 pass
0 commit comments