def _executeSingle(self, stanza, key, value=''): ''' Commits a write action on a single key/value pair ''' if self.isImportMode: return logger.debug('_executeSingle: stanza=%s => %s=%s' % (stanza, key, value)) # first check if stanza exists; create if necessary try: uri = self.getEndpointPath(self.name, stanza) rest.simpleRequest(uri, sessionKey=self.sessionKey) except splunk.ResourceNotFound: createUri = self.getEndpointPath(self.name) serverResponse, serverContent = rest.simpleRequest( createUri, self.sessionKey, postargs={'__stanza': stanza}) # now write the key serverResponse, serverContent = rest.simpleRequest( uri, self.sessionKey, postargs={key: value}, method=self._getWriteMethod()) if serverResponse.status != 200: logger.error('_executeSingle - HTTP error=%s server returned: %s' % (serverResponse.status, serverContent)) raise splunk.RESTException, ( serverResponse.status, '_executeSingle - server returned: %s' % serverContent)
def _executeBatch(self, stanza, kvPairs): if self.isImportMode: return logger.debug('_executeBatch: stanza=%s => %s' % (stanza, kvPairs)) # first check if stanza exists; create if necessary try: uri = self.getEndpointPath(self.name, stanza) rest.simpleRequest(uri, sessionKey=self.sessionKey) except splunk.ResourceNotFound: createUri = self.getEndpointPath(self.name) serverResponse, serverContent = rest.simpleRequest( createUri, self.sessionKey, postargs={'__stanza': stanza}) # now write out the keys serverResponse, serverContent = rest.simpleRequest( uri, self.sessionKey, postargs=kvPairs, method=self._getWriteMethod()) if serverResponse.status != 200: logger.error('_executeBatch - HTTP error=%s server returned: %s' % (serverResponse.status, serverContent)) raise splunk.RESTException, ( serverResponse.status, '_executeBatch - server returned: %s' % serverContent)
def controlEntity(action, entityURI, sessionKey=None): if action == 'remove': serverResponse, serverContent = rest.simpleRequest( entityURI, sessionKey=sessionKey, method='DELETE', raiseAllErrors=True) elif action == 'enable': serverResponse, serverContent = rest.simpleRequest( entityURI, sessionKey=sessionKey, method='POST', raiseAllErrors=True) elif action == 'disable': serverResponse, serverContent = rest.simpleRequest( entityURI, sessionKey=sessionKey, method='POST', raiseAllErrors=True) else: raise Exception, 'unknown action=%s' % action if serverResponse.status == 200: return True else: raise Exception, 'unhandled HTTP status=%s' % serverResponse.status
def _executeBatch(self, stanza, kvPairs): if self.isImportMode: return logger.debug('_executeBatch: stanza=%s => %s' % (stanza, kvPairs)) # first check if stanza exists; create if necessary try: uri = self.getEndpointPath(self.name, stanza) rest.simpleRequest(uri, sessionKey=self.sessionKey) except splunk.ResourceNotFound: createUri = self.getEndpointPath(self.name) serverResponse, serverContent = rest.simpleRequest( createUri, self.sessionKey, postargs={'__stanza': stanza} ) # now write out the keys serverResponse, serverContent = rest.simpleRequest( uri, self.sessionKey, postargs=kvPairs, method=self._getWriteMethod() ) if serverResponse.status != 200: logger.error('_executeBatch - HTTP error=%s server returned: %s' % (serverResponse.status, serverContent)) raise splunk.RESTException, (serverResponse.status, '_executeBatch - server returned: %s' % serverContent)
def _executeSingle(self, stanza, key, value = ''): ''' Commits a write action on a single key/value pair ''' if self.isImportMode: return logger.debug('_executeSingle: stanza=%s => %s=%s' % (stanza, key, value)) # first check if stanza exists; create if necessary try: uri = self.getEndpointPath(self.name, stanza) rest.simpleRequest(uri, sessionKey=self.sessionKey) except splunk.ResourceNotFound: createUri = self.getEndpointPath(self.name) serverResponse, serverContent = rest.simpleRequest( createUri, self.sessionKey, postargs={'__stanza': stanza} ) # now write the key serverResponse, serverContent = rest.simpleRequest( uri, self.sessionKey, postargs={key: value}, method=self._getWriteMethod() ) if serverResponse.status != 200: logger.error('_executeSingle - HTTP error=%s server returned: %s' % (serverResponse.status, serverContent)) raise splunk.RESTException, (serverResponse.status, '_executeSingle - server returned: %s' % serverContent)
def controlEntity(action, entityURI, sessionKey=None): if action == 'remove': serverResponse, serverContent = rest.simpleRequest(entityURI, sessionKey=sessionKey, method='DELETE', raiseAllErrors=True) elif action == 'enable': serverResponse, serverContent = rest.simpleRequest(entityURI, sessionKey=sessionKey, method='POST', raiseAllErrors=True) elif action == 'disable': serverResponse, serverContent = rest.simpleRequest(entityURI, sessionKey=sessionKey, method='POST', raiseAllErrors=True) else: raise Exception, 'unknown action=%s' % action if serverResponse.status == 200: return True else: raise Exception, 'unhandled HTTP status=%s' % serverResponse.status
def getEntity(entityPath, entityName, uri=None, namespace=None, owner=None, sessionKey=None, hostPath=None, **kwargs): ''' Retrieves a generic Splunkd entity from the REST endpoint @param entityPath: the class of objects to retrieve @param entityName: the specific name of the entity to retrieve @param namespace: the namespace within which to look for the entities. if None, then pull from merged @param owner: the owner within which to look for the entity. defaults to current user ''' # get default params if not owner: owner = auth.getCurrentUser()['name'] if not uri: if not entityName: raise ValueError, "entityName cannot be empty" uri = buildEndpoint(entityPath, entityName=entityName, namespace=namespace, owner=owner, hostPath=hostPath) serverResponse, serverContent = rest.simpleRequest(uri, getargs=kwargs, sessionKey=sessionKey, raiseAllErrors=True) if serverResponse.status != 200: logger.warn('getEntity - unexpected HTTP status=%s while fetching "%s"' % (serverResponse.status, uri)) atomEntry = rest.format.parseFeedDocument(serverContent) if isinstance(atomEntry, rest.format.AtomFeed): try: atomEntry = atomEntry[0] except IndexError, e: # Handle cases where no entry is found return None
def dispatchSavedSearch(savedSearchName, sessionKey=None, namespace=None, owner=None, hostPath=None, now=0, triggerActions=0, **kwargs): """Initiates a new job based on a saved search.""" uri = entity.buildEndpoint(['saved', 'searches', savedSearchName, 'dispatch'], namespace=namespace, owner=owner) if hostPath: uri = splunk.mergeHostPath(hostPath) + uri args = { 'now': now, 'trigger_actions' : triggerActions } for key, val in kwargs.items(): if key in SAVED_SEARCH_DISPATCH_ARG_MAP: args[SAVED_SEARCH_DISPATCH_ARG_MAP[key]] = val # Pass through for dispatch.* formated kwargs elif key.startswith('dispatch.'): args[key] = val serverResponse, serverContent = rest.simpleRequest(uri, postargs=args, sessionKey=sessionKey) root = et.fromstring(serverContent) # normal messages from splunkd are propogated via SplunkdException; if not 201 == serverResponse.status: extractedMessages = rest.extractMessages(root) for msg in extractedMessages: raise splunk.SearchException, msg['text'] # get the search ID sid = root.findtext('sid').strip() # instantiate result object return splunk.search.SearchJob(sid, hostPath, sessionKey, namespace, owner)
def deleteEntity(entityPath, entityName, namespace, owner, sessionKey=None, hostPath=None): ''' Deletes an entity ''' uri = buildEndpoint(entityPath, entityName, namespace=namespace, owner=owner, hostPath=hostPath) serverResponse, serverContent = rest.simpleRequest(uri, sessionKey=sessionKey, method='DELETE', raiseAllErrors=True) if serverResponse.status == 200: logger.info('deleteEntity - deleted entity=%s' % uri) return True else: raise Exception, 'deleteSearch - unhandled HTTP status=%s' % serverResponse.status
def getSessionKey(username, password, hostPath=None): ''' Get a session key from the auth system ''' uri = '/services/auth/login' if hostPath: uri = splunk.mergeHostPath(hostPath) + uri args = {'username': username, 'password': password } # To prove the theory of timing issue of Splunkd not in running state # in Windows Bamboo tests, sleep for 10 seconds # An attempt to fix SPL-37413 # if platform.system() == 'Windows': # time.sleep(10) serverResponse, serverContent = rest.simpleRequest(uri, postargs=args) if serverResponse.status != 200: logger.error('getSessionKey - unable to login; check credentials') rest.extractMessages(et.fromstring(serverContent)) return None root = et.fromstring(serverContent) sessionKey = root.findtext('sessionKey') splunk.setDefault('username', username) splunk.setDefault('sessionKey', sessionKey) return sessionKey
def _getEntitiesAtomFeed(entityPath, namespace=None, owner=None, search=None, count=None, offset=0, sort_key=None, sort_dir=None , sessionKey=None, uri=None, hostPath=None, **kwargs): # fallback to currently authed user if not owner: owner = auth.getCurrentUser()['name'] # construct URI to get entities if not uri: uri = buildEndpoint(entityPath, namespace=namespace, owner=owner, hostPath=hostPath) if search: kwargs["search"] = search if count != None: kwargs["count"] = count if offset: kwargs["offset"] = offset if sort_key: kwargs["sort_key"] = sort_key if sort_dir: kwargs["sort_dir"] = sort_dir # fetch list of entities serverResponse, serverContent = rest.simpleRequest(uri, getargs=kwargs, sessionKey=sessionKey, raiseAllErrors=True) if serverResponse.status != 200: raise splunk.RESTException, (serverResponse.status, serverResponse.messages) atomFeed = rest.format.parseFeedDocument(serverContent) return atomFeed
def getSessionKey(username, password, hostPath=None): ''' Get a session key from the auth system ''' uri = '/services/auth/login' if hostPath: uri = splunk.mergeHostPath(hostPath) + uri args = {'username': username, 'password': password} # To prove the theory of timing issue of Splunkd not in running state # in Windows Bamboo tests, sleep for 10 seconds # An attempt to fix SPL-37413 # if platform.system() == 'Windows': # time.sleep(10) serverResponse, serverContent = rest.simpleRequest(uri, postargs=args) if serverResponse.status != 200: logger.error('getSessionKey - unable to login; check credentials') rest.extractMessages(et.fromstring(serverContent)) return None root = et.fromstring(serverContent) sessionKey = root.findtext('sessionKey') splunk.setDefault('username', username) splunk.setDefault('sessionKey', sessionKey) return sessionKey
def createConf(confName, namespace=None, owner=None, sessionKey=None, hostPath=None): ''' Creates a new conf file. Returns a conf instance of the newly created .conf file. ''' uri = entity.buildEndpoint('properties', namespace=namespace, owner=owner, hostPath=hostPath) postargs = {'__conf': confName} status, response = rest.simpleRequest(uri, postargs=postargs, sessionKey=sessionKey, raiseAllErrors=True) # Expect 201 on creation or 200 on preexisting file (automatic handling of 303 redirect). if not ((status.status == 201) or (status.previous is not None and status.status == 200)): logger.error( 'createConf - unexpected server response while creating conf file "%s"; HTTP=%s' % (confName, status.status)) return getConf(confName, namespace=namespace, owner=owner, sessionKey=sessionKey, hostPath=hostPath)
def getConf(confName, sessionKey=None, namespace=None, owner=None, overwriteStanzas=False, hostPath=None): ''' Parses a logical bundle file and returns a Conf() object If namespace=None, then the behavior is 3.2-style, where all writes are done to conf files in etc/system/local. All reads will merge every conf file that is accessible in etc/system and etc/apps/*. If a namespace is provided, then writes are done in etc/apps/<namespace>/local/, and reads are restricted to values in etc/apps/<namespace>/(default|local). If overwriteStanzas is true, old keys in edited stanzas will not be preserved. For the 3.2-style reading, the endpoint uses the following priority: system/local apps/<namespace>/local apps/<namespace>/default system/default ''' # fallback to current user if not owner: owner = auth.getCurrentUser()['name'] uri = entity.buildEndpoint(entityClass='properties', entityName=confName, namespace=namespace, owner=owner, hostPath=hostPath) # the fillcontents arg will push all stanza keys down in 1 request instead # of iterating over all stanzas serverResponse, serverContent = rest.simpleRequest(uri, getargs={'fillcontents':1}, sessionKey=sessionKey) if serverResponse.status != 200: logger.info('getConf - server returned status=%s when asked for conf=%s' % (serverResponse.status, confName)) # convert the atom feed into dict confFeed = rest.format.parseFeedDocument(serverContent) stanzas = confFeed.toPrimitive() # create Conf/Stanzas output = Conf(confName, namespace=namespace, owner=owner, overwriteStanzas=overwriteStanzas) output.sessionKey = sessionKey output.isImportMode = True for name in stanzas: stanza = output.createStanza(name) stanza.needsPopulation = False for k in stanzas[name]: if stanzas[name][k] == None: stanza[k] = '' else: stanza[k] = stanzas[name][k] output.isImportMode = False return output
def _refreshStanza(self, stanzaName): uri = self.getEndpointPath(self.name, stanzaName) serverResponse, serverContent = rest.simpleRequest(uri, sessionKey=self.sessionKey) #logger.debug('_refreshStanza - got stanza data back') keys = rest.format.parseFeedDocument(serverContent) keys = keys.toPrimitive() #logger.debug('_refreshStanza - parsed stanza data; got %s keys' % len(keys)) self.isImportMode = True for k in keys: self.stanzas[stanzaName][k] = keys[k] self.isImportMode = False
def _getEntitiesAtomFeed(entityPath, namespace=None, owner=None, search=None, count=None, offset=0, sort_key=None, sort_dir=None, sessionKey=None, uri=None, hostPath=None, **kwargs): # fallback to currently authed user if not owner: owner = auth.getCurrentUser()['name'] # construct URI to get entities if not uri: uri = buildEndpoint(entityPath, namespace=namespace, owner=owner, hostPath=hostPath) if search: kwargs["search"] = search if count != None: kwargs["count"] = count if offset: kwargs["offset"] = offset if sort_key: kwargs["sort_key"] = sort_key if sort_dir: kwargs["sort_dir"] = sort_dir # fetch list of entities serverResponse, serverContent = rest.simpleRequest(uri, getargs=kwargs, sessionKey=sessionKey, raiseAllErrors=True) if serverResponse.status != 200: raise splunk.RESTException, (serverResponse.status, serverResponse.messages) atomFeed = rest.format.parseFeedDocument(serverContent) return atomFeed
def ping(hostPath=None, sessionKey=None): ''' Pings services server and returns a bool for a users session. This method is useful for synchronizing an applications authentication with Splunk's services authentication. ''' uri = '/services' if hostPath: uri = splunk.mergeHostPath(hostPath) + uri try: serverResponse, serverContent = rest.simpleRequest(uri, sessionKey=sessionKey) return True except: return False
def _refreshStanza(self, stanzaName): uri = self.getEndpointPath(self.name, stanzaName) serverResponse, serverContent = rest.simpleRequest( uri, sessionKey=self.sessionKey) #logger.debug('_refreshStanza - got stanza data back') keys = rest.format.parseFeedDocument(serverContent) keys = keys.toPrimitive() #logger.debug('_refreshStanza - parsed stanza data; got %s keys' % len(keys)) self.isImportMode = True for k in keys: self.stanzas[stanzaName][k] = keys[k] self.isImportMode = False
def ping(hostPath=None, sessionKey=None): ''' Pings services server and returns a bool for a users session. This method is useful for synchronizing an applications authentication with Splunk's services authentication. ''' uri = '/services' if hostPath: uri = splunk.mergeHostPath(hostPath) + uri try: serverResponse, serverContent = rest.simpleRequest( uri, sessionKey=sessionKey) return True except: return False
def getEntity(entityPath, entityName, uri=None, namespace=None, owner=None, sessionKey=None, hostPath=None, **kwargs): ''' Retrieves a generic Splunkd entity from the REST endpoint @param entityPath: the class of objects to retrieve @param entityName: the specific name of the entity to retrieve @param namespace: the namespace within which to look for the entities. if None, then pull from merged @param owner: the owner within which to look for the entity. defaults to current user ''' # get default params if not owner: owner = auth.getCurrentUser()['name'] if not uri: if not entityName: raise ValueError, "entityName cannot be empty" uri = buildEndpoint(entityPath, entityName=entityName, namespace=namespace, owner=owner, hostPath=hostPath) serverResponse, serverContent = rest.simpleRequest(uri, getargs=kwargs, sessionKey=sessionKey, raiseAllErrors=True) if serverResponse.status != 200: logger.warn( 'getEntity - unexpected HTTP status=%s while fetching "%s"' % (serverResponse.status, uri)) atomEntry = rest.format.parseFeedDocument(serverContent) if isinstance(atomEntry, rest.format.AtomFeed): try: atomEntry = atomEntry[0] except IndexError, e: # Handle cases where no entry is found return None
def createConf(confName, namespace=None, owner=None, sessionKey=None, hostPath=None): ''' Creates a new conf file. Returns a conf instance of the newly created .conf file. ''' uri = entity.buildEndpoint('properties', namespace=namespace, owner=owner, hostPath=hostPath) postargs = {'__conf': confName} status, response = rest.simpleRequest(uri, postargs=postargs, sessionKey=sessionKey, raiseAllErrors=True) # Expect 201 on creation or 200 on preexisting file (automatic handling of 303 redirect). if not ((status.status == 201) or (status.previous is not None and status.status == 200)): logger.error('createConf - unexpected server response while creating conf file "%s"; HTTP=%s' % (confName, status.status)) return getConf(confName, namespace=namespace, owner=owner, sessionKey=sessionKey, hostPath=hostPath)
def getSessionKeyForTrustedUser(username, hostPath=None): ''' Get a session key from the auth system ''' uri = '/services/auth/trustedlogin' if hostPath: uri = splunk.mergeHostPath(hostPath) + uri args = {'username': username} serverResponse, serverContent = rest.simpleRequest(uri, postargs=args) if serverResponse.status != 200: logger.error('getSessionKey - unable to login; check credentials') rest.extractMessages(et.fromstring(serverContent)) return None root = et.fromstring(serverContent) sessionKey = root.findtext('sessionKey') splunk.setDefault('username', username) splunk.setDefault('sessionKey', sessionKey) return sessionKey
def getEntities(entityPath, namespace=None, owner=None, search=None, count=None, offset=0, sort_key=None, sort_dir=None , sessionKey=None, uri=None, unique_key='title', hostPath=None, **kwargs): ''' Retrieves generic entities from the Splunkd endpoint, restricted to a namespace and owner context. @param entityPath: the class of objects to retrieve @param namespace: the namespace within which to look for the entities. default set by splunk.getDefault('namespace') @param owner: the owner within which to look for the entity. defaults to current user @param search: simple key=value filter @param offset: the starting index of the first item to return. defaults to 0 @param count: the maximum number of entities to return. defaults to -1 (all) @param sort_key: the key to sort against @param sort_dir: the direction to sort (asc or desc) @param uri: force a specific path to the objects @param unique_key: specify the uniquifying key ''' # fallback to currently authed user if not owner: owner = auth.getCurrentUser()['name'] # construct URI to get entities if not uri: uri = buildEndpoint(entityPath, namespace=namespace, owner=owner, hostPath=hostPath) if search: kwargs["search"] = search if count != None: kwargs["count"] = count if offset: kwargs["offset"] = offset if sort_key: kwargs["sort_key"] = sort_key if sort_dir: kwargs["sort_dir"] = sort_dir # fetch list of entities serverResponse, serverContent = rest.simpleRequest(uri, getargs=kwargs, sessionKey=sessionKey, raiseAllErrors=True) if serverResponse.status != 200: raise splunk.RESTException, (serverResponse.status, serverResponse.messages) atomFeed = rest.format.parseFeedDocument(serverContent) offset = int(atomFeed.os_startIndex or -1) totalResults = int(atomFeed.os_totalResults or -1) itemsPerPage = int(atomFeed.os_itemsPerPage or -1) links = atomFeed.links messages = atomFeed.messages # preserves order of returned elements # EntityCollection is a new subclass or util.OrderedDict, it still preserves # the order, but it allows some additional params to be added on. collection = EntityCollection(None, search, count, offset, totalResults, itemsPerPage, sort_key, sort_dir, links, messages) for atomEntry in atomFeed: contents = atomEntry.toPrimitive() entity = Entity(entityPath, atomEntry.title, contents, namespace) entity.owner = atomEntry.author entity.createTime = atomEntry.published entity.updateTime = atomEntry.updated entity.summary = atomEntry.summary entity.links = atomEntry.links entity.id = atomEntry.id entity.hostPath = hostPath # use the same semantics as in the C++ code: make the first item in the # list win if two stanzas with the same name exist attr = getattr(atomEntry, unique_key) if attr not in collection: collection[attr] = entity return collection
def setEntity(entity, sessionKey=None, uri=None, msgObj=None): ''' Commits the properties of a generic entity object ''' if not entity: raise Exception, 'Cannot set entity; no entity provided' if not entity.path: raise Exception, 'Entity does not have path defined' if not entity.name: raise Exception, 'Entity does not have name defined' if not entity.namespace: raise Exception, 'Cannot set entity without a namespace; %s' % entity.name # if editing entities that were owned by the system name, then convert to # to current user if not entity.owner: entity.owner = auth.getCurrentUser()['name'] if not uri: # This is where we determine edit / create behavior. WoNkY! if len(entity.links) > 0: for action, link in entity.links: if action == 'edit': uri = link if uri == None: uri = entity.getFullPath() postargs = entity.getCommitProperties() """ logger.debug("*" * 25) logger.debug("entity: %s." % entity) logger.debug("uri: %s." % uri) logger.debug("postargs: %s." % postargs) logger.debug("*" * 25) """ if not postargs: logger.warn('setEntity - tried to commit empty entity') raise Exception, 'setEntity - tried to commit empty entity' # if exists, then update by POST to own endpoint if rest.checkResourceExists(uri, sessionKey=sessionKey): # EAI sets entity.name to new for the new template... # so it will exist and not fall into the else case # do any of the endpoints used by Entity post back to # a nonexistent name for the create action? # EAI posts to the basePath. if entity.name == '_new': logger.debug("setting properties to create a new guy.") uri = entity.getBasePath() createName = entity.properties['name'] logger.debug("creating %s on %s." % (createName,uri)) entity.name = createName serverResponse, serverContent = rest.simpleRequest(uri, sessionKey=sessionKey, postargs=postargs, raiseAllErrors=True) if (serverResponse.status == 201): if msgObj: msgObj['messages'] = serverResponse.messages if serverResponse.status not in [200, 201]: logger.warn("Server did not return status 200 or 201.") else: try: atomFeed = rest.format.parseFeedDocument(serverContent) entity.id = atomFeed[0].id except Exception, e: pass return True
def setEntity(entity, sessionKey=None, uri=None, msgObj=None): ''' Commits the properties of a generic entity object ''' if not entity: raise Exception, 'Cannot set entity; no entity provided' if not entity.path: raise Exception, 'Entity does not have path defined' if not entity.name: raise Exception, 'Entity does not have name defined' if not entity.namespace: raise Exception, 'Cannot set entity without a namespace; %s' % entity.name # if editing entities that were owned by the system name, then convert to # to current user if not entity.owner: entity.owner = auth.getCurrentUser()['name'] if not uri: # This is where we determine edit / create behavior. WoNkY! if len(entity.links) > 0: for action, link in entity.links: if action == 'edit': uri = link if uri == None: uri = entity.getFullPath() postargs = entity.getCommitProperties() """ logger.debug("*" * 25) logger.debug("entity: %s." % entity) logger.debug("uri: %s." % uri) logger.debug("postargs: %s." % postargs) logger.debug("*" * 25) """ if not postargs: logger.warn('setEntity - tried to commit empty entity') raise Exception, 'setEntity - tried to commit empty entity' # if exists, then update by POST to own endpoint if rest.checkResourceExists(uri, sessionKey=sessionKey): # EAI sets entity.name to new for the new template... # so it will exist and not fall into the else case # do any of the endpoints used by Entity post back to # a nonexistent name for the create action? # EAI posts to the basePath. if entity.name == '_new': logger.debug("setting properties to create a new guy.") uri = entity.getBasePath() createName = entity.properties['name'] logger.debug("creating %s on %s." % (createName, uri)) entity.name = createName serverResponse, serverContent = rest.simpleRequest( uri, sessionKey=sessionKey, postargs=postargs, raiseAllErrors=True) if (serverResponse.status == 201): if msgObj: msgObj['messages'] = serverResponse.messages if serverResponse.status not in [200, 201]: logger.warn("Server did not return status 200 or 201.") else: try: atomFeed = rest.format.parseFeedDocument(serverContent) entity.id = atomFeed[0].id except Exception, e: pass return True
def getEntities(entityPath, namespace=None, owner=None, search=None, count=None, offset=0, sort_key=None, sort_dir=None, sessionKey=None, uri=None, unique_key='title', hostPath=None, **kwargs): ''' Retrieves generic entities from the Splunkd endpoint, restricted to a namespace and owner context. @param entityPath: the class of objects to retrieve @param namespace: the namespace within which to look for the entities. default set by splunk.getDefault('namespace') @param owner: the owner within which to look for the entity. defaults to current user @param search: simple key=value filter @param offset: the starting index of the first item to return. defaults to 0 @param count: the maximum number of entities to return. defaults to -1 (all) @param sort_key: the key to sort against @param sort_dir: the direction to sort (asc or desc) @param uri: force a specific path to the objects @param unique_key: specify the uniquifying key ''' # fallback to currently authed user if not owner: owner = auth.getCurrentUser()['name'] # construct URI to get entities if not uri: uri = buildEndpoint(entityPath, namespace=namespace, owner=owner, hostPath=hostPath) if search: kwargs["search"] = search if count != None: kwargs["count"] = count if offset: kwargs["offset"] = offset if sort_key: kwargs["sort_key"] = sort_key if sort_dir: kwargs["sort_dir"] = sort_dir # fetch list of entities serverResponse, serverContent = rest.simpleRequest(uri, getargs=kwargs, sessionKey=sessionKey, raiseAllErrors=True) if serverResponse.status != 200: raise splunk.RESTException, (serverResponse.status, serverResponse.messages) atomFeed = rest.format.parseFeedDocument(serverContent) offset = int(atomFeed.os_startIndex or -1) totalResults = int(atomFeed.os_totalResults or -1) itemsPerPage = int(atomFeed.os_itemsPerPage or -1) links = atomFeed.links messages = atomFeed.messages # preserves order of returned elements # EntityCollection is a new subclass or util.OrderedDict, it still preserves # the order, but it allows some additional params to be added on. collection = EntityCollection(None, search, count, offset, totalResults, itemsPerPage, sort_key, sort_dir, links, messages) for atomEntry in atomFeed: contents = atomEntry.toPrimitive() entity = Entity(entityPath, atomEntry.title, contents, namespace) entity.owner = atomEntry.author entity.createTime = atomEntry.published entity.updateTime = atomEntry.updated entity.summary = atomEntry.summary entity.links = atomEntry.links entity.id = atomEntry.id entity.hostPath = hostPath # use the same semantics as in the C++ code: make the first item in the # list win if two stanzas with the same name exist attr = getattr(atomEntry, unique_key) if attr not in collection: collection[attr] = entity return collection
atomFeed = rest.format.parseFeedDocument(serverContent) entity.id = atomFeed[0].id except Exception, e: pass return True # otherwise, create new by POST to parent endpoint else: # ensure that a name is included in the args if entity.name and 'name' not in postargs: postargs['name'] = entity.name uri = entity.getBasePath() serverResponse, serverContent = rest.simpleRequest( uri, sessionKey=sessionKey, postargs=postargs, raiseAllErrors=True) if serverResponse.status == 201: if msgObj: msgObj['messages'] = serverResponse.messages try: atomFeed = rest.format.parseFeedDocument(serverContent) entity.id = atomFeed[0].id except Exception, e: pass return True # if we haven't existed, then raise raise splunk.RESTException, (serverResponse.status,
entity.id = atomFeed[0].id except Exception, e: pass return True # otherwise, create new by POST to parent endpoint else: # ensure that a name is included in the args if entity.name and 'name' not in postargs: postargs['name'] = entity.name uri = entity.getBasePath() serverResponse, serverContent = rest.simpleRequest(uri, sessionKey=sessionKey, postargs=postargs, raiseAllErrors=True) if serverResponse.status == 201: if msgObj: msgObj['messages'] = serverResponse.messages try: atomFeed = rest.format.parseFeedDocument(serverContent) entity.id = atomFeed[0].id except Exception, e: pass return True # if we haven't existed, then raise raise splunk.RESTException, (serverResponse.status, serverResponse.messages)
def setEntity(entity, sessionKey=None, uri=None, msgObj=None, strictCreate=False, filterArguments=None): ''' Commits the properties of a generic entity object ''' logger.debug("entity.setEntity() is deprecated") if not entity: raise Exception, 'Cannot set entity; no entity provided' if not entity.path: raise Exception, 'Entity does not have path defined' if not entity.name: raise Exception, 'Entity does not have name defined' if not entity.namespace: raise Exception, 'Cannot set entity without a namespace; %s' % entity.name # if editing entities that were owned by the system name, then convert to # to current user if not entity.owner: entity.owner = auth.getCurrentUser()['name'] #check if we should filter arguments based on optional/required/wildcardFields #only enabled for datamodel and data/ui/views for now if filterArguments is None: filterArguments = False if entity.path.startswith("data/models") or re.match("^\/?data\/ui\/views(\/|$)", entity.path) or re.match("^\/?saved\/searches(\/|$)", entity.path): filterArguments = True tmpEntity = None if not uri: # This is where we determine edit / create behavior. WoNkY! if len(entity.links) > 0: for action, link in entity.links: if action == 'edit': uri = link if uri == None: uri = entity.getFullPath() if filterArguments: tmpEntity = getEntity(entity.path, None, uri=uri + "/_new", sessionKey=sessionKey) if filterArguments and tmpEntity == None: tmpEntity = getEntity(entity.path, entity.name, uri=uri, sessionKey=sessionKey) if filterArguments: postargs = entity.getCommitProperties(optionalFields=tmpEntity.optionalFields, requiredFields=tmpEntity.requiredFields, wildcardFields=tmpEntity.wildcardFields, isACL=uri.endswith('/acl'), filterArguments=filterArguments) else: postargs = entity.getCommitProperties() """ logger.debug("*" * 25) logger.debug("entity: %s." % entity) logger.debug("uri: %s." % uri) logger.debug("postargs: %s." % postargs) logger.debug("*" * 25) """ if not postargs: logger.warn('setEntity - tried to commit empty entity') raise Exception, 'setEntity - tried to commit empty entity' # if exists, then update by POST to own endpoint if rest.checkResourceExists(uri, sessionKey=sessionKey) and not strictCreate: # EAI sets entity.name to new for the new template... # so it will exist and not fall into the else case # do any of the endpoints used by Entity post back to # a nonexistent name for the create action? # EAI posts to the basePath. if entity.name == '_new': logger.debug("setting properties to create a new guy.") uri = entity.getBasePath() createName = entity.properties['name'] logger.debug("creating %s on %s." % (createName,uri)) entity.name = createName serverResponse, serverContent = rest.simpleRequest(uri, sessionKey=sessionKey, postargs=postargs, raiseAllErrors=True) if (serverResponse.status == 201): if msgObj: msgObj['messages'] = serverResponse.messages if serverResponse.status not in [200, 201]: logger.warn("Server did not return status 200 or 201.") else: try: atomFeed = rest.format.parseFeedDocument(serverContent) entity.id = atomFeed[0].id except Exception, e: pass return True
def setEntity(entity, sessionKey=None, uri=None, msgObj=None, strictCreate=False, filterArguments=None): ''' Commits the properties of a generic entity object ''' logger.debug("entity.setEntity() is deprecated") if not entity: raise Exception, 'Cannot set entity; no entity provided' if not entity.path: raise Exception, 'Entity does not have path defined' if not entity.name: raise Exception, 'Entity does not have name defined' if not entity.namespace: raise Exception, 'Cannot set entity without a namespace; %s' % entity.name # if editing entities that were owned by the system name, then convert to # to current user if not entity.owner: entity.owner = auth.getCurrentUser()['name'] #check if we should filter arguments based on optional/required/wildcardFields #only enabled for datamodel and data/ui/views for now if filterArguments is None: filterArguments = False if entity.path.startswith("data/models") or re.match( "^\/?data\/ui\/views(\/|$)", entity.path) or re.match( "^\/?saved\/searches(\/|$)", entity.path): filterArguments = True tmpEntity = None if not uri: # This is where we determine edit / create behavior. WoNkY! if len(entity.links) > 0: for action, link in entity.links: if action == 'edit': uri = link if uri == None: uri = entity.getFullPath() if filterArguments: tmpEntity = getEntity(entity.path, None, uri=uri + "/_new", sessionKey=sessionKey) if filterArguments and tmpEntity == None: tmpEntity = getEntity(entity.path, entity.name, uri=uri, sessionKey=sessionKey) if filterArguments: postargs = entity.getCommitProperties( optionalFields=tmpEntity.optionalFields, requiredFields=tmpEntity.requiredFields, wildcardFields=tmpEntity.wildcardFields, isACL=uri.endswith('/acl'), filterArguments=filterArguments) else: postargs = entity.getCommitProperties() """ logger.debug("*" * 25) logger.debug("entity: %s." % entity) logger.debug("uri: %s." % uri) logger.debug("postargs: %s." % postargs) logger.debug("*" * 25) """ if not postargs: logger.warn('setEntity - tried to commit empty entity') raise Exception, 'setEntity - tried to commit empty entity' # if exists, then update by POST to own endpoint if rest.checkResourceExists(uri, sessionKey=sessionKey) and not strictCreate: # EAI sets entity.name to new for the new template... # so it will exist and not fall into the else case # do any of the endpoints used by Entity post back to # a nonexistent name for the create action? # EAI posts to the basePath. if entity.name == '_new': logger.debug("setting properties to create a new guy.") uri = entity.getBasePath() createName = entity.properties['name'] logger.debug("creating %s on %s." % (createName, uri)) entity.name = createName serverResponse, serverContent = rest.simpleRequest( uri, sessionKey=sessionKey, postargs=postargs, raiseAllErrors=True) if (serverResponse.status == 201): if msgObj: msgObj['messages'] = serverResponse.messages if serverResponse.status not in [200, 201]: logger.warn("Server did not return status 200 or 201.") else: try: atomFeed = rest.format.parseFeedDocument(serverContent) entity.id = atomFeed[0].id except Exception, e: pass return True
def getConf(confName, sessionKey=None, namespace=None, owner=None, overwriteStanzas=False, hostPath=None): ''' Parses a logical bundle file and returns a Conf() object If namespace=None, then the behavior is 3.2-style, where all writes are done to conf files in etc/system/local. All reads will merge every conf file that is accessible in etc/system and etc/apps/*. If a namespace is provided, then writes are done in etc/apps/<namespace>/local/, and reads are restricted to values in etc/apps/<namespace>/(default|local). If overwriteStanzas is true, old keys in edited stanzas will not be preserved. For the 3.2-style reading, the endpoint uses the following priority: system/local apps/<namespace>/local apps/<namespace>/default system/default ''' # fallback to current user if not owner: owner = auth.getCurrentUser()['name'] uri = entity.buildEndpoint(entityClass='properties', entityName=confName, namespace=namespace, owner=owner, hostPath=hostPath) # the fillcontents arg will push all stanza keys down in 1 request instead # of iterating over all stanzas serverResponse, serverContent = rest.simpleRequest( uri, getargs={'fillcontents': 1}, sessionKey=sessionKey) if serverResponse.status != 200: logger.info( 'getConf - server returned status=%s when asked for conf=%s' % (serverResponse.status, confName)) # convert the atom feed into dict confFeed = rest.format.parseFeedDocument(serverContent) stanzas = confFeed.toPrimitive() # create Conf/Stanzas output = Conf(confName, namespace=namespace, owner=owner, overwriteStanzas=overwriteStanzas) output.sessionKey = sessionKey output.isImportMode = True for name in stanzas: stanza = output.createStanza(name) stanza.needsPopulation = False for k in stanzas[name]: if stanzas[name][k] == None: stanza[k] = '' else: stanza[k] = stanzas[name][k] output.isImportMode = False return output