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.

155 lines
5.1 KiB

import http.client
import logging
from experiment.experiment_store import ExperimentStore
from experiment.history_store import ExperimentHistoryStore
from rest.proxy import SplunkRestProxyException, SplunkRestException
import cexc
logger = cexc.get_logger(__name__)
def capture_exception(callback, request, url_parts):
"""
execute `callback` with `request` and `path_parts` parameters
and handles exceptions generated from `callback`
Args:
callback (function): the callback function to execute
request ([type]): the request object being passed in from rest handler
path_parts ([type]): the url parts passed in from rest handler
Returns:
dict
"""
try:
return callback(request, url_parts)
except (SplunkRestProxyException, SplunkRestException) as e:
return e.to_http_response()
except Exception as e:
logger.exception("exception")
return SplunkRestProxyException(
'Cannot complete the request: %s' % str(e),
logging.ERROR,
http.client.INTERNAL_SERVER_ERROR,
).to_http_response()
def get_invalid_path_error(path_parts):
return SplunkRestProxyException(
'Invalid request path. path: %s' % str(path_parts),
logging.ERROR,
http.client.BAD_REQUEST,
)
class Experiments(object):
"""
A handler for experiments endpoint
"""
experiment_store = ExperimentStore()
history_store = ExperimentHistoryStore(with_admin_token=True)
@classmethod
def check_experiment_exists(cls, request, url_parts):
"""
A util function to check if the experiment with the given id exists, and return the response if it does.
Args:
request: (dict): the request object being passed in from rest handler
url_parts: ([type]): the url parts passed in from rest handler
Returns: (dict) a dict of response from experiment GET request
"""
experiment_fetch_reply = cls.experiment_store.get(
request, url_parts, with_raw_reply=True
)
if not experiment_fetch_reply['success']:
raise SplunkRestException(experiment_fetch_reply)
return experiment_fetch_reply
@classmethod
def safe_handle_get(cls, request, path_parts):
path_part_length = len(path_parts)
url_parts = []
# Experiment GET request handling
if 0 < path_part_length <= 2:
if path_part_length == 2:
url_parts.append(path_parts[1])
return cls.experiment_store.get(request, url_parts)
# History GET request handling
elif path_part_length == 3:
if path_parts[2] != "history":
raise get_invalid_path_error(path_parts)
url_parts.append(path_parts[1])
cls.check_experiment_exists(request, url_parts)
return cls.history_store.get(request, url_parts)
# Oh noooo we can't do that
else:
raise get_invalid_path_error(path_parts)
@classmethod
def safe_handle_post(cls, request, path_parts):
path_part_length = len(path_parts)
url_parts = []
# Experiment POST request handling
if path_part_length <= 2:
if path_part_length == 2:
url_parts.append(path_parts[1])
return cls.experiment_store.post(request, url_parts)
elif path_part_length == 3:
# History POST request handling
if path_parts[2] == "history":
url_parts.append(path_parts[1])
cls.check_experiment_exists(request, url_parts)
return cls.history_store.post(request, url_parts)
# clone models POST request handling
elif path_parts[2] == 'clone_models':
url_parts.append(path_parts[1])
experiment_fetch_reply = cls.check_experiment_exists(request, url_parts)
return cls.experiment_store.clone_experiment_models(
experiment_fetch_reply, request, url_parts
)
else:
raise get_invalid_path_error(path_parts)
# Welp we don't know this
else:
raise get_invalid_path_error(path_parts)
@classmethod
def safe_handle_delete(cls, request, path_parts):
url_parts = []
# Experiment DELETE request handling
if len(path_parts) == 2:
url_parts.append(path_parts[1])
# Delete history when we delete the experiment
cls.history_store.delete(request, url_parts)
return cls.experiment_store.delete(request, url_parts)
else:
raise get_invalid_path_error(path_parts)
@classmethod
def handle_get(cls, request, path_parts):
return capture_exception(cls.safe_handle_get, request, path_parts)
@classmethod
def handle_post(cls, request, path_parts):
return capture_exception(cls.safe_handle_post, request, path_parts)
@classmethod
def handle_delete(cls, request, path_parts):
return capture_exception(cls.safe_handle_delete, request, path_parts)