Пример #1
0
    def _validateDimensionsValidJson(self, identifier, informational,
                                     dimensions):
        try:
            identifier_dimensions = json.loads(
                identifier) if type(identifier) is str else identifier
            informational_dimensions = json.loads(
                informational) if type(informational) is str else informational
            dimensions = json.loads(
                dimensions) if type(dimensions) is str else dimensions
        except Exception:
            raise ArgValidationException(
                'Invalid JSON supplied to REST handler!')

        # Make sure the correct arg types are provided for the endpoint
        if type(dimensions) is not dict:
            raise ArgValidationException(
                'Dimensions provided should be JSON object!')
        if type(informational_dimensions) is not list:
            raise ArgValidationException(
                'Informational dimensions provided should be list!')
        if type(identifier_dimensions) is not list:
            raise ArgValidationException(
                'Identifier dimensions provided should be list!')

        # If all the checks pass without exception, return the dimensions as
        # valid objects
        return (dimensions, informational_dimensions, identifier_dimensions)
Пример #2
0
    def handleBulkDelete(self, handler, confInfo):
        """
        :param handler instance of the en_entity_interface:
        :param confInfo confInfo for the current request:
        :return:

        Delete the entities based on a query and calls list as response.
        Query param is required for bulk delete.
        """
        self._setup_kv_store(handler)
        self._setup_savedsearch_manager(handler)
        kvstore_delete_query = EMCommon.get_query_from_request_args(
            handler.callerArgs.data.get('delete_query', [''])[0])
        if not kvstore_delete_query:
            raise ArgValidationException('Delete query can not be empty')
        delete_query = {'query': kvstore_delete_query}
        entities_deleted_list = self._handleListAll(confInfo,
                                                    fields='_key',
                                                    query_params=delete_query)
        savedsearch_delete_query = EMCommon.get_list_of_admin_managedby(
            entities_deleted_list, em_constants.APP_NAME)
        logger.info('User triggered action "bulk_delete" on entities')
        self.entity_store.bulk_delete(query=delete_query)
        self.savedsearch_manager.bulk_delete(
            savedsearch_query=savedsearch_delete_query)
        handler.callerArgs.data.pop('delete_query')
        self.handleList(handler, confInfo)
Пример #3
0
    def filter_groups_by(self,
                         criteria,
                         earliest='-24h',
                         latest='now',
                         count=0):

        spl_template = self.get_search_template().get('filter_groups_by')

        def by_entity_ids(entity_ids):
            entity_predicate = ' OR '.join(
                map(lambda e: '_key="%s"' % e, entity_ids))
            return execute_spl(entity_predicate)

        def by_entity_names(entity_names):
            entity_predicate = ' OR '.join(
                map(lambda e: 'title="%s"' % e, entity_names))
            return execute_spl(entity_predicate)

        def execute_spl(entity_predicate):
            spl = spl_template % (EMConstants.STORE_ENTITIES, entity_predicate,
                                  self.CUSTOM_SEARCH_CMD, EMConstants.ACTIVE,
                                  EMConstants.INACTIVE, EMConstants.DISABLED)
            results = self.search_one_shot(spl, earliest, latest, count)
            return EMSearchManager.parse_group_entites_count_results(results)

        if criteria == EMSearchManager.BY_ENTITY_IDS:
            return by_entity_ids
        elif criteria == EMSearchManager.BY_ENTITY_NAMES:
            return by_entity_names
        else:
            raise ArgValidationException(
                'Filter criteria specified is not allowed!')
Пример #4
0
    def _batch_save_to_mbus(self, data, url):
        """
        Perform multiple save operations in a batch
        """
        if not data:
            raise ArgValidationException(
                _('Batch saving failed: Batch is empty.'))

        batches = (data[x:x + DEFAULT_BATCH_SIZE]
                   for x in range(0, len(data), DEFAULT_BATCH_SIZE))
        for batch in batches:
            try:
                payload = {
                    "publisher": "Splunk App for Infrastructure",
                    "entities": batch
                }
                response, content = splunk.rest.simpleRequest(
                    url,
                    method='POST',
                    sessionKey=session['authtoken'],
                    jsonargs=json.dumps(payload))
                if response.status != 200:
                    logger.error(
                        "Failed to publish entities to message bus -- status:%s content:%s"
                        % (response.status, content))
            except Exception as e:
                logger.error(e)
                raise e
Пример #5
0
    def handleBulkDelete(self, handler, confInfo):
        """
        :param handler instance of the em_group_interface:
        :param confInfo confInfo for the current request:
        :return:

        Delete the groups based on a query and calls list as response.
        Query param is required for bulk delete.
        """
        self._setupKVStore(handler)
        self._setupSavedSearchManager(handler)
        groups_deleted_list = json.loads(
            handler.callerArgs.data.get('delete_query', ['{}'])[0])
        if not groups_deleted_list:
            # If no query is provided, delete all groups, and therefore all saved
            # searches associated with all groups
            groups_deleted_list = self._handleListAll(fields='_key')
        savedsearch_delete_query = EMCommon.get_list_of_admin_managedby(
            groups_deleted_list, EMConstants.APP_NAME)
        kvstore_delete_query = EMCommon.get_query_from_request_args(
            handler.callerArgs.data.get('delete_query', [''])[0])
        if not kvstore_delete_query:
            raise ArgValidationException('Delete query can not be empty')
        logger.info('User triggered action "bulk_delete" on groups')
        delete_query = {"query": kvstore_delete_query}
        self.groups_store.bulk_delete(query=delete_query)
        self.savedsearch_manager.bulk_delete(
            savedsearch_query=savedsearch_delete_query)
        handler.callerArgs.data.pop('delete_query')
        self.handleList(handler, confInfo)
Пример #6
0
def build_mongodb_query(filters, options=None):
    """
    Ex1: for a input  {"title": ["a*"]}
    this function would return  {"title": {"$regex": "a*", , "$options": "i"}}

    Ex2: for a input {"title": ["a*", "b"]}
    returns:  {"$or": [{"title": {"$regex": "a*", "$options": "i"}}, {"title": {"$regex": "b", , "$options": "i"}} ]}

    Ex3: for a input {"title": ["a*", "b"], "os": ["windows"]}
    returns:  {"$and": [
        {"$or": [{"title": {"$regex": "a*", "$options": "i"}},  {"$regex": "b", , "$options": "i"}} ]},
        {"os":  {"$regex": "windows", , "$options": "i"}}}
    ]}

    NOTE: This code needs to be updated when  https://jira.splunk.com/browse/PBL-9076 is implemented.

    :param filters dictionary, filters object passed by the UI
    :param options dictionary of supported options
    :return mongoDB format query dictionary:
    """
    # if filters is empty object return as no query constructions required
    if not bool(filters):
        return filters

    if not options:
        options = _get_default_options()
    elif isinstance(options, str):
        options = json.loads(options)
    elif not isinstance(options, dict):
        raise ArgValidationException(
            _('When provided, options must be string or dict'))

    mongo_options = _construct_mongo_options(options)

    # if filter is not a dict or options if passed in is not a dict a error will be thrown
    if not isinstance(filters, dict):
        raise ArgValidationException(_('Filter must be a dict'))

    sub_queries = [
        _construct_query_for(key, value, mongo_options)
        for key, value in filters.items()
    ]

    # if number of sub-queries is 1 return else wrap it around a "$and"
    return sub_queries[0] if len(sub_queries) == 1 else {"$and": sub_queries}
Пример #7
0
    def _load_valid_metric_names_query_param(self, query_param):
        """
        Query params are expected to be a dictionary with dimension name as key, list of dimension values as value
        """
        message = (
            'Cannot parse query parameter: %s. ' % query_param +
            'Expected format is {<dimension name>: [ <dimension values, wildcards>]}'
        )
        # Check if it's a valid json string
        try:
            query_param = json.loads(query_param)
        except:
            raise ArgValidationException(message)
        if isinstance(query_param, dict):
            # Check if key is string and value is list
            is_query_param_valid = all(
                isinstance(key, basestring) and isinstance(value, list)
                for key, value in query_param.items())
            if is_query_param_valid is False:
                raise ArgValidationException(message)
        else:
            raise ArgValidationException(message)

        return query_param
Пример #8
0
def convert_query_params_to_mongoDB_query(query=None, options=None):
    """
    Converts query params to mongoDB format
    :param query: dict or string, the query containing filter to be converted to mongo format
    :param options: dict or string, options for mongo search (example: is search case sensitive or not)
    :return: dict or nothing
    """
    if not query:
        return {}
    if isinstance(query, str):
        query = json.loads(query)
    try:
        return build_mongodb_query(query, options=options)
    # Throws ArgalidationException when we provide invalid dict for mongodb query, a cleaner
    # exception message than default ValueError returned
    except ValueError:
        raise ArgValidationException(
            _('Invalid dict supplied as part of query!'))
Пример #9
0
 def handleMetricData(self, handler, confInfo):
     """
     Return metric metadata by entity name
     """
     count = handler.callerArgs.get('count', 0)
     query_params = handler.callerArgs.data.get('query', '')
     if not query_params:
         raise ArgValidationException('Missing required key: query')
     query_params = self._load_valid_metric_metadata_query(query_params[0])
     self._setup_kv_store(handler)
     dimensions = query_params.get('dimensions', {})
     execute_search = normalizeBoolean(
         query_params.get('executeSearch', True))
     reformated_dimensions = dimensions
     if dimensions:
         reformated_dimensions = {
             'dimensions.{}'.format(key): value
             for key, value in dimensions.iteritems()
         }
     kvstore_query = EMCommon.get_query_from_request_args(
         json.dumps(reformated_dimensions))
     filtered_entities = self._handleListAll(
         confInfo,
         fields='_key,dimensions,collectors.name',
         query_params={'query': kvstore_query})
     collectors = self._handleListAllConfigs(confInfo,
                                             fields='name,title_dimension')
     collector_config = {
         collector.get('name'): collector.get('title_dimension')
         for collector in collectors
     }
     search_manager = EMSearchManager(EMCommon.get_server_uri(),
                                      handler.getSessionKey(),
                                      em_constants.APP_NAME)
     search_res = search_manager.get_avg_metric_val_by_entity(
         execute_search=execute_search,
         metric_name=query_params['metric_name'],
         entities=filtered_entities,
         collector_config=collector_config,
         count=count)
     confInfo['metric_data']['metric_data'] = \
         json.dumps({
             ret.get('key'): ret.get('value') for ret in search_res
         }) if isinstance(search_res, list) else search_res
Пример #10
0
def _construct_query_for(key, value, options):
    """
    If values is a list it would return
        {"$or": [{"key":"a"}, {"key": "b"}]}

    else it would return
        {"key": "value"}
    :return:
    """
    if not (isinstance(value, list) or isinstance(value, basestring)):
        raise ArgValidationException(_('Value needs to be a string or list'))

    item = {}
    if isinstance(value, list):
        item['$or'] = [{
            key: get_regex_search_string(v, options)
        } for v in value]
    else:
        item[key] = get_regex_search_string(value, options)
    return item
Пример #11
0
def get_list_of_admin_managedby(query, app_name):
    """
    Converts UI query to a list of entities
    that are preceded by 'alert.managedBy:'
    :param query query string from UI
    :return
    """
    if not query:
        return []
    else:
        try:
            type_ids = []
            if type(query) is dict:
                type_ids = query.get('_key', [])
            # Getting a delete all call here, so take all entities
            else:
                type_ids = [entity_type.get('_key') for entity_type in query]
            return [
                'alert.managedBy="%s:%s"' % (app_name, type_id)
                for type_id in type_ids
            ]
        except ValueError:
            raise ArgValidationException(
                _('Invalid JSON supplied as part of query!'))
Пример #12
0
    def _load_valid_metric_metadata_query(self, query_param):
        # {metric_name:cpu.idle, dimensions:{os:["ubuntu"]}}
        message = (
            'Cannot parse query parameter: %s. ' % query_param +
            'Expected format is {metric_name: [metric_name], ' +
            'dimensions: {<dimension name>: [ <dimension values, wildcards>]}}'
        )
        # Check if it's a valid json string
        try:
            query_param = json.loads(query_param)
        except:
            raise ArgValidationException(message)
        if isinstance(query_param, dict):
            # Check if both metric_name and dimensions exist
            if 'metric_name' not in query_param:
                raise ArgValidationException(
                    'Missing required key: metric_name')
            metric_name = query_param['metric_name']
            dimensions = query_param.get('dimensions')
            # Check type for required key - metric_name
            if not isinstance(metric_name, basestring):
                raise ArgValidationException(
                    'Expected metric name to be a string.')
            if dimensions:
                # Check type for optional key - dimensions
                if not isinstance(dimensions, dict):
                    raise ArgValidationException(
                        'Expected dimensions to be a dict.')
                # Check if each key in dimensions is a string and each value is a list
                is_query_param_valid = all(
                    isinstance(key, basestring) and isinstance(value, list)
                    for key, value in dimensions.iteritems())
                if is_query_param_valid is False:
                    raise ArgValidationException(
                        'Expected each key in dimensions to be a string, each value to be a list'
                    )
        else:
            raise ArgValidationException('Expected query param to be a dict')

        return query_param
Пример #13
0
 def _validateDimensionsExist(self, dimensionsObj, dimensionList):
     for dimension in dimensionList:
         if dimension not in dimensionsObj:
             message = 'Dimension "%s" provided does not exist in dimensions object!' % dimension
             raise ArgValidationException(message)
Пример #14
0
 def _validateEntityState(self, entity_state):
     if entity_state not in self.VALID_ENTITY_STATES:
         raise ArgValidationException('Invalid entity state: must be %s' %
                                      self.VALID_ENTITY_STATES)