You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
293 lines
10 KiB
293 lines
10 KiB
import splunk
|
|
import splunk.admin as admin
|
|
import splunk.entity as en
|
|
import copy
|
|
#from core.manager import logger
|
|
import logging
|
|
|
|
logger = logging.getLogger("splunk")
|
|
|
|
class BaseRestHandler(admin.MConfigHandler):
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
admin.MConfigHandler.__init__(self, *args, **kwargs)
|
|
|
|
def model(self):
|
|
return self._model
|
|
|
|
def get_method(self, name):
|
|
return getattr(self._model, name, None)
|
|
|
|
def setup(self):
|
|
|
|
if 0 != len(self.customAction):
|
|
# let go while custom action is for acl.
|
|
if self.customAction in ['acl']: return
|
|
|
|
elif self.requestedAction in [admin.ACTION_CREATE, admin.ACTION_EDIT]:
|
|
for arg in self._model.required_args:
|
|
self.supportedArgs.addReqArg(arg)
|
|
|
|
for arg in self._model.optional_args:
|
|
self.supportedArgs.addOptArg(arg)
|
|
|
|
def getSortDir(self):
|
|
''' return correct sort direction '''
|
|
if self.sortAscending:
|
|
return 'asc'
|
|
else:
|
|
return 'desc'
|
|
|
|
def makeConfItem(self, name, obj, confInfo):
|
|
''' given a name and entity object, return a confItem '''
|
|
confItem = confInfo[name]
|
|
for key, val in obj.items():
|
|
confItem[key] = str(val)
|
|
acl = {}
|
|
for k, v in obj[admin.EAI_ENTRY_ACL].items():
|
|
if None != v:
|
|
acl[k] = v
|
|
confItem.setMetadata(admin.EAI_ENTRY_ACL, acl)
|
|
|
|
#add links
|
|
confItem.removeAllActions()
|
|
|
|
#need to write out a bitfield to the XML that encodes the actions
|
|
for action, link in obj.links:
|
|
if action == 'create':
|
|
confItem.actions |= admin.ACTION_CREATE
|
|
elif action == 'list':
|
|
confItem.actions |= admin.ACTION_LIST
|
|
elif action == 'edit':
|
|
confItem.actions |= admin.ACTION_EDIT
|
|
elif action == 'remove':
|
|
confItem.actions |= admin.ACTION_REMOVE
|
|
elif action == 'members':
|
|
confItem.actions |= admin.ACTION_MEMBERS
|
|
elif action == '_reload':
|
|
confItem.actions |= admin.ACTION_RELOAD
|
|
|
|
return confItem
|
|
|
|
def handleList(self, confInfo):
|
|
if self.callerArgs.id is None:
|
|
ent = self.all()
|
|
|
|
for name, obj in ent.items():
|
|
confItem = self.makeConfItem(name, obj, confInfo)
|
|
else:
|
|
try:
|
|
ent = self.get()
|
|
|
|
confItem = self.makeConfItem(self.callerArgs.id, ent, confInfo)
|
|
except splunk.ResourceNotFound:
|
|
pass
|
|
|
|
def handleACL(self, confInfo):
|
|
try:
|
|
ent = self.get()
|
|
meta = ent[admin.EAI_ENTRY_ACL]
|
|
|
|
# for POST acl only.
|
|
if self.requestedAction in [admin.ACTION_CREATE, admin.ACTION_EDIT] and len(self.callerArgs.data)>0:
|
|
|
|
# control only update acl data, no more other fields
|
|
ent.properties = dict()
|
|
|
|
ent['sharing'] = meta['sharing']
|
|
ent['owner'] = meta['owner']
|
|
|
|
# SPL-69050 and SPL-68306
|
|
ent['perms.read'] = [None]
|
|
ent['perms.write'] = [None]
|
|
|
|
'''
|
|
if 'perms' in meta:
|
|
perms = meta['perms']
|
|
|
|
# SPL-67185
|
|
if perms and isinstance(perms, dict):
|
|
if 'write' in perms:
|
|
ent['perms.write'] = perms['write']
|
|
if 'read' in perms:
|
|
ent['perms.read'] = perms['read']
|
|
'''
|
|
|
|
# user should not POST non acl related fields, if so, it will throw errors anyway.
|
|
for k, v in self.callerArgs.data.items():
|
|
ent[k] = v
|
|
|
|
en.setEntity(ent, self.getSessionKey(), uri=ent.id+'/acl')
|
|
ent = self.get()
|
|
|
|
confItem = confInfo[self.callerArgs.id]
|
|
acl = copy.deepcopy(meta)
|
|
confItem.actions = self.requestedAction
|
|
confItem.setMetadata(admin.EAI_ENTRY_ACL, acl)
|
|
|
|
except splunk.ResourceNotFound as ex:
|
|
logger.exception('handleACL Failed - arguments = %s, exception = %s' % (self.callerArgs, ex))
|
|
|
|
def handleCreate(self, confInfo):
|
|
logger.debug('handleCreate is called. -- action = %s, id = %s' % (self.customAction, self.callerArgs.id))
|
|
try:
|
|
args = self.getCallerArgs()
|
|
self.create(**args)
|
|
except BaseException as ex:
|
|
logger.exception('handleCreate Failed - arguments = %s, exception = %s' % (self.callerArgs, ex))
|
|
#raise an exception when we fail to create!
|
|
raise admin.AlreadyExistsException('Failed to create model: %s' % (self.callerArgs.id))
|
|
|
|
self.handleList(confInfo)
|
|
|
|
def handleRemove(self, confInfo):
|
|
try:
|
|
self.delete()
|
|
except BaseException as ex:
|
|
#for datamodel, throw an exception when remove fails.
|
|
raise admin.InternalException('Failed to delete model: %s' % (self.callerArgs.id))
|
|
|
|
def handleEdit(self, confInfo):
|
|
logger.debug('handleEdit is called. -- action = %s, id = %s' % (self.customAction, self.callerArgs.id))
|
|
|
|
try:
|
|
args = self.getCallerArgs()
|
|
self.update(**args)
|
|
self.handleList(confInfo)
|
|
except BaseException as ex:
|
|
#for datamodel, throw an exception when edit fails
|
|
raise admin.InternalException('Failed to edit model: %s' % (self.callerArgs.id))
|
|
|
|
def getCallerArgs(self):
|
|
callargs = dict()
|
|
for n, v in self.callerArgs.data.items():
|
|
callargs.update({n : v[0]})
|
|
|
|
return callargs
|
|
|
|
def handleCustom(self, confInfo):
|
|
if self.customAction in ['acl']:
|
|
return self.handleACL(confInfo)
|
|
|
|
if self.customAction == 'disable':
|
|
self.update(disabled='1')
|
|
elif self.customAction == 'enable':
|
|
self.update(disabled='0')
|
|
else:
|
|
meth = self.get_method(self.customAction)
|
|
if meth:
|
|
ctx = self.getContext()
|
|
meth(ctx)
|
|
self.makeConfItem(self.callerArgs.id, ctx.entity, confInfo)
|
|
else:
|
|
raise splunk.ResourceNotFound()
|
|
|
|
def getContext(self):
|
|
ctx = type('Context', (dict, object), {}) ()
|
|
ctx.entity = self.get()
|
|
ctx.data = self.callerArgs.data
|
|
|
|
return ctx
|
|
|
|
@property
|
|
def _endpoint(self):
|
|
return self._model.endpoint
|
|
|
|
@property
|
|
def _optional_args(self):
|
|
return self._model.optional_args
|
|
|
|
@property
|
|
def _required_args(self):
|
|
return self._model.required_args
|
|
|
|
def _namespace_and_owner(self):
|
|
app = self.context != admin.CONTEXT_NONE and self.appName or "-"
|
|
user = self.context == admin.CONTEXT_APP_AND_USER and self.userName or "nobody"
|
|
|
|
return app, user
|
|
|
|
|
|
def all(self):
|
|
app, user = self._namespace_and_owner()
|
|
|
|
return en.getEntities(self._endpoint,
|
|
namespace=app,
|
|
owner=user,
|
|
sessionKey=self.getSessionKey(),
|
|
count=self.maxCount+self.posOffset,
|
|
sort_key=self.sortByKey,
|
|
sort_dir=self.getSortDir(),
|
|
offset=self.posOffset)
|
|
|
|
def get(self):
|
|
app, user = self._namespace_and_owner()
|
|
|
|
return en.getEntity(self._endpoint,
|
|
self.callerArgs.id,
|
|
namespace=app,
|
|
owner=user,
|
|
sessionKey=self.getSessionKey())
|
|
|
|
def create(self, **params):
|
|
app, user = self._namespace_and_owner()
|
|
|
|
new = en.Entity(self._endpoint,
|
|
self.callerArgs.id,
|
|
namespace=app,
|
|
owner=user)
|
|
|
|
for arg in self._required_args:
|
|
new[arg] = params[arg]
|
|
|
|
for arg in self._optional_args:
|
|
try:
|
|
new[arg] = params[arg]
|
|
except:
|
|
pass
|
|
|
|
en.setEntity(new, sessionKey=self.getSessionKey(), strictCreate=True)
|
|
|
|
def delete(self):
|
|
app, user = self._namespace_and_owner()
|
|
en.deleteEntity(self._endpoint,
|
|
self.callerArgs.id,
|
|
namespace=app,
|
|
owner=user,
|
|
sessionKey=self.getSessionKey())
|
|
|
|
def update(self, **params):
|
|
app, user = self._namespace_and_owner()
|
|
|
|
ent = en.getEntity(self._endpoint,
|
|
self.callerArgs.id,
|
|
namespace=app,
|
|
owner=user,
|
|
sessionKey=self.getSessionKey())
|
|
|
|
for arg in params.keys():
|
|
if arg in self._required_args + self._optional_args:
|
|
ent[arg] = params[arg]
|
|
|
|
#check which args are allowed to be posted
|
|
allowedArgs = []
|
|
if 'eai:attributes' in ent and 'requiredFields' in ent['eai:attributes'] and 'optionalFields' in ent['eai:attributes']:
|
|
allowedArgs = ent['eai:attributes']['requiredFields'] + ent['eai:attributes']['optionalFields']
|
|
|
|
#filter out args that aren't allowed
|
|
for arg in ent.keys():
|
|
if arg not in allowedArgs:
|
|
del ent.properties[arg]
|
|
|
|
en.setEntity(ent, sessionKey=self.getSessionKey())
|
|
|
|
|
|
# no longer used, but keep it here for compatibility purpose.
|
|
class BaseResource(object):
|
|
pass
|
|
|
|
def ResourceHandler(model, handler=BaseRestHandler):
|
|
handler._model = model()
|
|
return type(model.__class__.__name__, (handler, object), {})
|
|
|