コード例 #1
0
def get_table(object_type,
              schema,
              embedded=False,
              identifier=None,
              credentials=None):
    """
    Build the object_type table and get data to populate the table
    """
    datamgr = request.environ['beaker.session']['datamanager']

    # Pagination and search
    where = {'saved_filters': True}
    if request.query.get('search') is not None:
        where = Helper.decode_search(request.query.get('search', ''))

    # Get total elements count
    # total = datamgr.get_objects_count(object_type, search=where, refresh=True)

    # Build table structure
    dt = Datatable(object_type, datamgr, schema)

    # Build page title
    title = dt.title
    if '%d' in title:
        title = title % dt.records_total

    return {
        'object_type': object_type,
        'dt': dt,
        'where': where,
        'title': request.query.get('title', title),
        'embedded': embedded,
        'identifier': identifier,
        'credentials': credentials
    }
コード例 #2
0
ファイル: worldmap.py プロジェクト: fpeyre/alignak-webui
def get_worldmap():
    """
    Get the hosts list to build a worldmap
    """
    user = request.environ['beaker.session']['current_user']
    datamgr = request.environ['beaker.session']['datamanager']
    target_user = request.environ['beaker.session']['target_user']

    username = user.get_username()
    if not target_user.is_anonymous():
        username = target_user.get_username()

    # Fetch elements per page preference for user, default is 25
    elts_per_page = datamgr.get_user_preferences(username, 'elts_per_page', 25)
    elts_per_page = elts_per_page['value']

    # Pagination and search
    start = int(request.query.get('start', '0'))
    count = int(request.query.get('count', elts_per_page))
    where = Helper.decode_search(request.query.get('search', ''))
    search = {
        'page': start // (count + 1),
        'max_results': count,
        'sort': '-_id',
        'where': where
    }

    # Get valid hosts
    valid_hosts = get_valid_elements(search)

    # Get last total elements count
    total = len(valid_hosts)
    count = min(len(valid_hosts), total)

    return {
        'mapId': 'hostsMap',
        'params': worldmap_parameters,
        'hosts': valid_hosts,
        'pagination': webui.helper.get_pagination_control('/worldmap', total, start, count),
        'title': request.query.get('title', _('Hosts worldmap'))
    }
コード例 #3
0
ファイル: services.py プロジェクト: jgmel/alignak-webui
    def get_service_timeline(self,
                             element_id,
                             widget_id='timeline',
                             embedded=False,
                             identifier=None,
                             credentials=None):
        # pylint: disable=unused-argument, too-many-locals
        """Display a service timeline widget"""
        user = request.environ['beaker.session']['current_user']
        datamgr = request.app.datamgr

        # Get service
        service = datamgr.get_service(element_id)
        if not service:
            return self.webui.response_invalid_parameters(
                _('Service does not exist'))

        # Search the required widget
        widget_place = request.params.get('widget_place', 'service')
        widget_template = request.params.get('widget_template',
                                             'service_widget')
        # Search in the application widgets (all plugins widgets)
        for widget in self.webui.get_widgets_for(widget_place):
            if widget_id.startswith(widget['id']):
                widget_template = widget['template']
                logger.info("Widget found, template: %s", widget_template)
                break
        else:
            logger.info(
                "Widget identifier not found: using default template and no options"
            )

        logger.debug("get_service_timeline: found template: %s",
                     widget_template)

        # Fetch elements per page preference for user, default is 25
        elts_per_page = datamgr.get_user_preferences(user, 'elts_per_page', 25)

        # service history pagination and search parameters
        start = int(request.params.get('start', '0'))
        count = int(request.params.get('count', elts_per_page))
        where = {'service': service.id}

        # Find known history types
        history_plugin = self.webui.find_plugin('Histories')
        if history_plugin:
            decoded_search = Helper.decode_search(
                request.params.get('search', ''), history_plugin.table)
            logger.info("Decoded search: %s", decoded_search)
            if decoded_search:
                where.update(decoded_search)

        search = {
            'page': (start // count) + 1,
            'max_results': count,
            'where': where
        }

        # Get service history
        history = datamgr.get_history(search=search)
        if history is None:
            history = []
        total = 0
        if history:
            total = history[0]['_total']

        # Search filters used for the timeline widget
        events_search_filters = {
            '01': (_('Web UI comments'), 'type:webui.comment'),
            '02': (_('Check results'), 'type:check.'),
            '03': (_('Alerts'), 'type:monitoring.alert'),
            '04': (_('Acknowledges'), 'type:monitoring.ack'),
            '05': (_('Downtimes'), 'type:monitoring.downtime'),
            '06': (_('Notifications'), 'type:monitoring.notification'),
            '07': ('', ''),
        }

        # Render the widget
        return template(
            '_widget', {
                'widget_id':
                widget_id,
                'widget_name':
                widget_template,
                'widget_place':
                'user',
                'widget_template':
                widget_template,
                'widget_uri':
                request.urlparts.path,
                'options': {},
                'plugin_parameters':
                self.plugin_parameters,
                'search_engine':
                True,
                'search_filters':
                events_search_filters,
                'service':
                service,
                'history':
                history,
                'pagination':
                self.webui.helper.get_pagination_control(
                    '/service/%s#service_%s' %
                    (service.id, widget_id), total, start, count),
                'title':
                None,
                'embedded':
                embedded,
                'identifier':
                identifier,
                'credentials':
                credentials
            })
コード例 #4
0
    def show_minemap(self):
        # Yes, but that's how it is made, and it suits ;)
        # pylint: disable=too-many-locals
        """Get the hosts / services list to build a minemap"""
        user = request.environ['beaker.session']['current_user']
        datamgr = request.app.datamgr

        # Fetch elements per page preference for user, default is 25
        elts_per_page = datamgr.get_user_preferences(user, 'elts_per_page', 25)

        # Minemap search engine is based upon host table
        plugin = self.webui.find_plugin('host')

        # Pagination and search
        start = int(request.params.get('start', '0'))
        count = int(request.params.get('count', elts_per_page))
        if count < 1:
            count = elts_per_page
        search = Helper.decode_search(request.params.get('search', ''), plugin.table)
        logger.info("Decoded search pattern: %s", search)
        for key, pattern in search.items():
            logger.info("global search pattern '%s' / '%s'", key, pattern)

        search = {
            'page': (start // count) + 1,
            'max_results': count,
            'where': search,
            'sort': '-_overall_state_id'
        }

        # Get elements from the data manager
        # Do not include the embedded fields to improve the loading time...
        hosts = datamgr.get_hosts(search, embedded=False)

        minemap = []
        columns = []
        for host in hosts:
            # Each item contains the total number of records matching the search filter
            total = host['_total']
            minemap_row = {'host_check': host}

            # Get all host services
            # Do not include the embedded fields to improve the loading time...
            services = datamgr.get_services(
                search={
                    'where': {'host': host.id},
                    'sort': '-_overall_state_id'
                },
                all_elements=True, embedded=False
            )
            for service in services:
                columns.append(service.name)
                minemap_row.update({service.name: service})

            minemap.append(minemap_row)

        # Sort column names by most frequent ...
        count_columns = collections.Counter(columns)
        columns = [c for c, dummy in count_columns.most_common()]

        return {
            'search_engine': self.search_engine,
            'search_filters': self.search_filters,
            'params': self.plugin_parameters,
            'minemap': minemap,
            'columns': columns,
            'pagination': self.webui.helper.get_pagination_control('/minemap', total, start, count),
            'title': request.query.get('title', _('Hosts minemap'))
        }
コード例 #5
0
    def get_host_timeline(self, element_id, widget_id='timeline',
                          embedded=False, identifier=None, credentials=None):
        # pylint: disable=unused-argument, too-many-locals
        """Display an host timeline widget"""
        user = request.environ['beaker.session']['current_user']
        datamgr = request.app.datamgr

        # Get the host
        host = datamgr.get_host(element_id)
        if not host:
            # Test if we got a name instead of an id
            host = datamgr.get_host(search={'max_results': 1, 'where': {'name': element_id}})
            if not host:
                return self.webui.response_invalid_parameters(_('Host does not exist'))

        # Search the required widget
        widget_place = request.params.get('widget_place', 'host')
        widget_template = request.params.get('widget_template', 'host_widget')
        # Search in the application widgets (all plugins widgets)
        for widget in self.webui.get_widgets_for(widget_place):
            if widget_id.startswith(widget['id']):
                widget_template = widget['template']
                logger.debug("Widget found, template: %s", widget_template)
                break
        else:
            logger.info("Widget identifier not found: using default template and no options")

        logger.debug("get_host_timeline: found template: %s", widget_template)

        # Fetch elements per page preference for user, default is 25
        elts_per_page = datamgr.get_user_preferences(user, 'elts_per_page', 25)

        # Host history pagination and search parameters
        start = int(request.params.get('start', '0'))
        count = int(request.params.get('count', elts_per_page))
        where = {'host': host.id}

        # Find known history types
        history_plugin = self.webui.find_plugin('Histories')
        if history_plugin:
            decoded_search = Helper.decode_search(request.params.get('search', ''),
                                                  history_plugin.table)
            logger.info("Decoded search: %s", decoded_search)
            if decoded_search:
                where.update(decoded_search)

        search = {
            'page': (start // count) + 1,
            'max_results': count,
            'where': where
        }

        # Get host history
        history = datamgr.get_history(search=search)
        if history is None:
            history = []
        total = 0
        if history:
            total = history[0]['_total']

        # Search filters used for the timeline widget
        events_search_filters = {
            '01': (_('Web UI comments'), 'type:webui.comment'),
            '02': (_('Check results'), 'type:check.'),
            '03': (_('Alerts'), 'type:monitoring.alert'),
            '04': (_('Acknowledges'), 'type:monitoring.ack'),
            '05': (_('Downtimes'), 'type:monitoring.downtime'),
            '06': (_('Notifications'), 'type:monitoring.notification'),
            '07': ('', ''),
        }

        # Render the widget
        return template('_widget', {
            'widget_id': widget_id,
            'widget_name': widget_template,
            'widget_place': 'user',
            'widget_template': widget_template,
            'widget_uri': request.urlparts.path,
            'options': {},

            'plugin_parameters': self.plugin_parameters,
            'search_engine': True,
            'search_filters': events_search_filters,

            'host': host,

            'history': history,
            'pagination': self.webui.helper.get_pagination_control(
                '/host/%s#host_%s' % (host.id, widget_id), total, start, count
            ),

            'title': None,
            'embedded': embedded,
            'identifier': identifier,
            'credentials': credentials
        })
コード例 #6
0
    def show_worldmap(self, for_my_widget=False):
        """Get the hosts list to build a worldmap

        Get the list of the valid hosts t display onthe map

         If `for_my_widget` is True this function returns the list of the concerned hosts
         else it returns the worldmap view.

        :param for_my_widget: defaults to False
        :return:
        """
        user = request.environ['beaker.session']['current_user']
        datamgr = request.app.datamgr

        # Fetch elements per page preference for user, default is 25
        elts_per_page = datamgr.get_user_preferences(user, 'elts_per_page', 25)

        # Pagination and search
        start = int(request.query.get('start', '0'))
        count = int(request.query.get('count', elts_per_page))
        where = Helper.decode_search(request.query.get('search', ''), self.table)
        search = {
            'page': (start // count) + 1,
            'max_results': count,
            'sort': '-_id',
            'where': where
        }
        if self.plugin_parameters.get('hosts_business_impacts'):
            # Only get hosts which business impact is configured...
            logger.debug("worldmap, only hosts with BI in: %s",
                         self.plugin_parameters['hosts_business_impacts'])
            search['where'].update(
                {'business_impact': {'$in': self.plugin_parameters['hosts_business_impacts']}})
        if self.plugin_parameters.get('hosts_included'):
            # Include some hosts...
            logger.debug("worldmap, included hosts: %s", self.plugin_parameters['hosts_included'])
            search['where'].update({'name': {
                "$regex": self.plugin_parameters['hosts_included']}})
        if self.plugin_parameters.get('hosts_excluded'):
            # Exclude some hosts...
            logger.debug("worldmap, excluded hosts: %s", self.plugin_parameters['hosts_excluded'])
            search['where'].update({'name': {
                "$regex": "^((?!%s).)*$" % self.plugin_parameters['hosts_excluded']}})

        # Do not include the embedded fields to improve the loading time...
        hosts = datamgr.get_hosts(search, embedded=False)

        # Get positioned and not-positioned hosts
        positioned_hosts = self.get_map_elements(hosts)

        # Get last total elements count
        total = len(hosts)
        if hosts:
            total = hosts[0]['_total']
            logger.info("worldmap, total %d hosts", total)

        if for_my_widget:
            return [h for h in positioned_hosts if h['positioned']]

        map_style = "width: %s; height: %s;" % (self.plugin_parameters.get('map_width', "100%"),
                                                self.plugin_parameters.get('map_height', "100%"))

        return {
            'search_engine': self.search_engine,
            'search_filters': self.search_filters,
            'mapId': 'hostsMap',
            'mapStyle': map_style,
            'params': self.plugin_parameters,
            'hosts': positioned_hosts,
            'pagination': self.webui.helper.get_pagination_control(
                '/worldmap', total, start, count),
            'title': request.query.get('title', _('Hosts worldmap'))
        }
コード例 #7
0
ファイル: minemap.py プロジェクト: jgmel/alignak-webui
    def show_minemap(self):
        # Yes, but that's how it is made, and it suits ;)
        # pylint: disable=too-many-locals
        """Get the hosts / services list to build a minemap"""
        user = request.environ['beaker.session']['current_user']
        datamgr = request.app.datamgr

        # Fetch elements per page preference for user, default is 25
        elts_per_page = datamgr.get_user_preferences(user, 'elts_per_page', 25)

        # Minemap search engine is based upon host table
        plugin = self.webui.find_plugin('host')

        # Pagination and search
        start = int(request.params.get('start', '0'))
        count = int(request.params.get('count', elts_per_page))
        if count < 1:
            count = elts_per_page
        search = Helper.decode_search(request.params.get('search', ''),
                                      plugin.table)
        logger.info("Decoded search pattern: %s", search)
        for key, pattern in search.items():
            logger.info("global search pattern '%s' / '%s'", key, pattern)

        search = {
            'page': (start // count) + 1,
            'max_results': count,
            'where': search,
            'sort': '-_overall_state_id'
        }

        # Get elements from the data manager
        # Do not include the embedded fields to improve the loading time...
        hosts = datamgr.get_hosts(search, embedded=False)

        minemap = []
        columns = []
        for host in hosts:
            # Each item contains the total number of records matching the search filter
            total = host['_total']
            minemap_row = {'host_check': host}

            # Get all host services
            # Do not include the embedded fields to improve the loading time...
            services = datamgr.get_services(search={
                'where': {
                    'host': host.id
                },
                'sort': '-_overall_state_id'
            },
                                            all_elements=True,
                                            embedded=False)
            for service in services:
                columns.append(service.name)
                minemap_row.update({service.name: service})

            minemap.append(minemap_row)

        # Sort column names by most frequent ...
        count_columns = collections.Counter(columns)
        columns = [c for c, dummy in count_columns.most_common()]

        return {
            'search_engine':
            self.search_engine,
            'search_filters':
            self.search_filters,
            'params':
            self.plugin_parameters,
            'minemap':
            minemap,
            'columns':
            columns,
            'pagination':
            self.webui.helper.get_pagination_control('/minemap', total, start,
                                                     count),
            'title':
            request.query.get('title', _('Hosts minemap'))
        }
コード例 #8
0
    def table_data(self, plugin_table):
        # Because there are many locals needed :)
        # pylint: disable=too-many-locals
        """Return elements data in json format as of Datatables SSP protocol

        More info: https://datatables.net/manual/server-side

        Example URL::

            POST /?
            draw=1&
            columns[0][data]=alias&
            columns[0][name]=&
            columns[0][searchable]=true&
            columns[0][orderable]=true&
            columns[0][search][value]=&
            columns[0][search][regex]=false&
             ...
            order[0][column]=0&
            order[0][dir]=asc&
            start=0&
            length=10&
            search[value]=&
            search[regex]=false&

        Request parameters are Json formatted

        Request Parameters:
        - object_type: object type managed by the datatable
        - links: url prefix to be used by the links in the table
        - embedded: true / false whether the table is embedded by an external application
            **Note**: those three first parameters are not datatable specific parameters :)

        - draw, index parameter to be returned in the response

            Pagination:
            - start / length, for pagination

            Searching:
            - search (value or regexp)
            search[value]: Global search value. To be applied to all columns which are searchable
            search[regex]: true if search[value] is a regex

            Sorting:
            - order[i][column] / order[i][dir]
            index of the columns to order and sort direction (asc/desc)

            Columns:
            - columns[i][data]: Column's data source, as defined by columns.data.
            - columns[i][name]: Column's name, as defined by columns.name.
            - columns[i][searchable]: Flag to indicate if this column is searchable (true).
            - columns[i][orderable]: Flag to indicate if this column is orderable (true).
            - columns[i][search][value]: Search value to apply to this specific column.
            - columns[i][search][regex]: Flag to indicate if the search term for this column is a
            regex.

        Response data:
        - draw

        - recordsTotal: total records, before filtering
            (i.e. total number of records in the database)

        - recordsFiltered: Total records, after filtering
            (i.e. total number of records after filtering has been applied -
            not just the number of records being returned for this page of data).

        - data: The data to be displayed in the table.
            an array of data source objects, one for each row, which will be used by DataTables.

        - error (optional): Error message if an error occurs
            Not included if there is no error.
        """
        # Manage request parameters ...
        logger.info("request data for table: %s, templates: %s",
                    request.forms.get('object_type'), self.templates)

        # Because of specific datatables parameters name (eg. columns[0] ...)
        # ... some parameters have been json.stringify on client side !
        params = {}
        for key in list(request.params.keys()):
            if key in ['columns', 'order', 'search']:
                params[key] = json.loads(request.params.get(key))
            else:
                params[key] = request.params.get(key)
        # params now contains 'valid' query parameters as we should have found them ...
        logger.debug("table request parameters: %s", params)

        parameters = {}

        # Manage page number ...
        # start is the first requested row and we must transform to a page count ...
        first_row = int(params.get('start', '0'))
        # length is the number of requested rows
        rows_count = int(params.get('length', '25'))

        parameters['page'] = (first_row // rows_count) + 1
        parameters['max_results'] = rows_count
        logger.debug("get %d rows from row #%d -> page: %d",
                     rows_count, first_row, parameters['page'])

        # Columns ordering
        # order:[{"column":2,"dir":"desc"}]
        if 'order' in params and 'columns' in params and params['order']:
            sorted_columns = []
            for order in params['order']:
                idx = int(order['column'])
                if params['columns'][idx] and params['columns'][idx]['data']:
                    logger.debug(
                        "sort by column %d (%s), order: %s ",
                        idx, params['columns'][idx]['data'], order['dir']
                    )
                    if order['dir'] == 'desc':
                        sorted_columns.append('-' + params['columns'][idx]['data'])
                    else:
                        sorted_columns.append(params['columns'][idx]['data'])
            if sorted_columns:
                parameters['sort'] = ','.join(sorted_columns)

            logger.info("backend order request parameters: %s", parameters)

        # Individual column search parameter
        s_columns = []
        if 'columns' in params and params['columns']:
            for column in params['columns']:
                if 'searchable' not in column or 'search' not in column:  # pragma: no cover
                    continue
                if 'value' not in column['search'] or not column['search']['value']:
                    continue
                logger.debug("search column '%s' for '%s'",
                             column['data'], column['search']['value'])

                for field in self.table_columns:
                    if field['data'] != column['data']:
                        continue

                    # Some specific types...
                    if field['type'] == 'boolean':
                        s_columns.append(
                            {column['data']: column['search']['value'] == 'true'}
                        )
                    elif field['type'] == 'integer':
                        s_columns.append(
                            {column['data']: int(column['search']['value'])}
                        )
                    elif field['format'] == 'select':
                        values = column['search']['value'].split(',')
                        if len(values) > 1:
                            s_columns.append(
                                {
                                    column['data']: {
                                        "$in": values
                                    }
                                }
                            )
                        else:
                            s_columns.append(
                                {column['data']: values[0]}
                            )
                    # ... the other fields :)
                    else:
                        # Do not care about 'smart' and 'caseInsensitive' boolean parameters ...
                        if column['search']['regex']:
                            s_columns.append(
                                {
                                    column['data']: {
                                        "$regex": ".*" + column['search']['value'] + ".*"
                                    }
                                }
                            )
                        else:
                            s_columns.append(
                                {column['data']: column['search']['value']}
                            )
                    break

            logger.info("backend search individual columns parameters: %s", s_columns)

        # Global search parameter
        # search:{"value":"test","regex":false}
        s_global = {}
        # pylint: disable=too-many-nested-blocks
        # Will be too complex else ...
        if 'search' in params and 'columns' in params and params['search']:
            # params['search'] contains something like: {u'regex': False, u'value': u'name:pi1'}
            # global regex is always ignored ... in favor of the column declared regex
            logger.info("global search requested: %s ", params['search'])
            if 'value' in params['search'] and params['search']['value']:
                # There is something to search for...
                logger.debug("search requested, value: %s ", params['search']['value'])

                # New strategy: decode search patterns...
                search = Helper.decode_search(params['search']['value'], plugin_table)
                logger.info("decoded search pattern: %s", search)

                # Old strategy: search for the value in all the searchable columns...
                # if not search:
                #     logger.info("applying datatable search pattern...")
                #     for column in params['columns']:
                #         if not column['searchable']:
                #             continue
                #         logger.debug("search global '%s' for '%s'",
                #                      column['data'], params['search']['value'])
                #         if 'regex' in params['search']:
                #             if params['search']['regex']:
                #                 s_global.update(
                #                     {column['data']: {
                #                         "$regex": ".*" + params['search']['value'] + ".*"}})
                #             else:
                #                 s_global.update({column['data']: params['search']['value']})
                s_global = search

            logger.info("backend search global parameters: %s", s_global)

        # Specific hack to filter the log check results that are not dated!
        if self.object_type == 'logcheckresult':
            s_columns.append({"last_check": {"$ne": 0}})

        if s_columns and s_global:
            parameters['where'] = {"$and": [{"$and": s_columns}, s_global]}
        elif s_columns:
            parameters['where'] = {"$and": s_columns}
        elif s_global:
            parameters['where'] = s_global

        # Embed linked resources / manage templated resources
        parameters['embedded'] = {}
        for field in self.embedded:
            parameters['embedded'].update({field: 1})

        logger.debug("backend embedded parameters: %s", parameters['embedded'])

        # Count total elements excluding templates if necessary
        if self.is_templated:
            if self.ui_visibility:
                self.records_total = self.datamgr.my_backend.count(
                    self.object_type, params={'where': {'_is_template': self.templates,
                                                        'webui_visible': True}}
                )
            else:
                self.records_total = self.datamgr.my_backend.count(
                    self.object_type, params={'where': {'_is_template': self.templates}}
                )
            if 'where' in parameters:
                parameters['where'].update({'_is_template': self.templates})
            else:
                parameters['where'] = {'_is_template': self.templates}
        else:
            if self.ui_visibility:
                self.records_total = self.datamgr.my_backend.count(
                    self.object_type, params={'where': {'webui_visible': True}}
                )
            else:
                self.records_total = self.datamgr.my_backend.count(self.object_type)

        if self.ui_visibility:
            if 'where' in parameters:
                parameters['where'].update({'webui_visible': True})
            else:
                parameters['where'] = {'webui_visible': True}

        # Request objects from the backend ...
        logger.info("table data get parameters: %s", parameters)
        items = self.datamgr.my_backend.get(self.object_type, params=parameters)
        logger.info("table data got %d items", len(items))
        if not items:
            logger.info("No backend elements match search criteria: %s", parameters)
            # Empty response
            return json.dumps({
                # draw is the request number ...
                "draw": int(params.get('draw', '0')),
                "recordsTotal": 0,
                "recordsFiltered": 0,
                "data": []
            })

        # Create an object ...
        object_class = [kc for kc in self.datamgr.known_classes
                        if kc.get_type() == self.object_type]
        if not object_class:  # pragma: no cover, should never happen!
            logger.warning("datatable, unknown object type: %s", self.object_type)
            # Empty response
            return json.dumps({
                # draw is the request number ...
                "draw": int(params.get('draw', '0')),
                "recordsTotal": 0,
                "recordsFiltered": 0,
                "data": []
            })

        # Update table inner properties with the object class defined properties
        object_class = object_class[0]

        self.id_property = '_id'
        if hasattr(object_class, 'id_property'):
            self.id_property = object_class.id_property
        self.name_property = 'name'
        if hasattr(object_class, 'name_property'):
            self.name_property = object_class.name_property
        self.status_property = 'status'
        if hasattr(object_class, 'status_property'):
            self.status_property = object_class.status_property
        logger.debug("datatable, object type: '%s' and properties: %s / %s / %s",
                     object_class, self.id_property, self.name_property, self.status_property)

        # Change item content...
        rows = []
        # Total number of filtered records
        self.records_filtered = self.records_total
        for item in items:
            bo_object = object_class(item)
            if not bo_object.ui_visible:
                logger.debug("Not UI visible object: %s", bo_object)
                continue

            logger.info("table data object: %s", bo_object)
            logger.debug("table data object: %s", bo_object)
            # This is an awful hack that allows to update the objects filtered for a table.
            # Two main interests:
            # - update the backend because some massive modifications are necessary for testing
            # - prepare a massive update feature in the Web UI :)
            # -----
            # if self.is_templated and self.templates and self.object_type == 'service':
            #     logger.warning("service template: %s for host: %s",
            #                    bo_object.name, bo_object['host'])
            #     if bo_object['host'].name.startswith('fdj'):
            #         logger.info("To be updated...")
            #         data = {
            #             "check_freshness": True,
            #             "freshness_threshold": 86400,
            #             "passive_checks_enabled": True,
            #             "active_checks_enabled": False
            #         }
            #         result = self.datamgr.update_object(element=bo_object, data=data)
            #         if result is True:
            #             logger.info("updated.")
            #         else:
            #             logger.error("update failed!")
            # -----

            # Each item contains the total number of records matching the search filter
            self.records_filtered = item['_total']

            row = {}
            row['DT_RowData'] = {}
            row['_id'] = bo_object.id
            for field in self.table_columns:
                logger.debug(" - field: %s", field)
                # Specific fields
                if field['data'] == self.name_property:
                    # Create a link to navigate to the item page
                    row[self.name_property] = bo_object.html_link
                    # Store the item name in a specific field of the row.
                    # The value will be retrieved by the table actions (ack, recheck, ...)
                    row['DT_RowData'].update({"object_%s" % self.object_type: bo_object.name})
                    continue

                if field['data'] == self.status_property:
                    # Replace the text status with the specific item HTML state
                    row[self.status_property] = bo_object.get_html_state(text=None,
                                                                         title=bo_object.status)
                    # Use the item status to specify the table row class
                    # row['DT_RowClass'] = "table-row-%s" % (bo_object.status.lower())
                    continue

                if field['data'] in ['_overall_state_id', 'overall_state', 'overall_status']:
                    # Get the item overall state from the data manager
                    f_get_overall_state = getattr(self.datamgr,
                                                  'get_%s_overall_state' % self.object_type)
                    if f_get_overall_state:
                        (dummy, overall_status) = f_get_overall_state(bo_object)

                        # Get element state configuration
                        row[field['data']] = ElementState().get_html_state(
                            self.object_type, bo_object,
                            text=None,
                            title=bo_object.overall_state_to_title[bo_object.overall_state],
                            use_status=overall_status
                        )
                        # Use the item overall state to specify the table row class
                        row['DT_RowClass'] = "table-row-%s" % (overall_status)
                    else:  # pragma: no cover, should never happen!
                        logger.warning("Missing get_overall_state method for: %s", self.object_type)
                        row[field['data']] = 'XxX'
                    continue

                if "business_impact" in field['data']:
                    # Replace the BI count with the specific item HTML formatting
                    row[field['data']] = Helper.get_html_business_impact(bo_object.business_impact)
                    continue

                # Specific fields type
                if field['type'] == 'datetime' or field['format'] == 'datetime':
                    # Replace the timestamp with the formatted date
                    row[field['data']] = bo_object.get_date(bo_object[field['data']])
                    continue

                if field['type'] == 'boolean':
                    # Replace the boolean vaue with the specific item HTML formatting
                    row[field['data']] = Helper.get_on_off(bo_object[field['data']])
                    continue

                if field['type'] == 'list':
                    # Replace the list with the specific list HTML formatting
                    if hasattr(bo_object, field['data']):
                        row[field['data']] = Helper.get_html_item_list(
                            bo_object.id, field['data'],
                            getattr(bo_object, field['data']), title=field['title']
                        )
                    else:
                        row[field['data']] = 'Unknown'
                    continue

                if field['type'] == 'dict':
                    # Replace the dictionary with the specific dict HTML formatting
                    row[field['data']] = Helper.get_html_item_list(
                        bo_object.id, field['data'],
                        getattr(bo_object, field['data']), title=field['title']
                    )
                    continue

                if field['type'] == 'objectid':
                    if isinstance(bo_object[field['data']], BackendElement):
                        row[field['data']] = bo_object[field['data']].get_html_link(
                            prefix=request.params.get('links')
                        )
                        # row['DT_RowData'].update({
                        #     "object_%s" % field['data']: bo_object[field['data']].name
                        # })
                    else:
                        logger.warning("Table field is supposed to be an object: %s, %s = %s",
                                       bo_object.name, field['data'],
                                       getattr(bo_object, field['data']))
                        row[field['data']] = getattr(bo_object, field['data'])
                        if row[field['data']] == field['resource']:
                            row[field['data']] = '...'
                    continue

                # For any non-specific fields, send the field value to the table
                row[field['data']] = getattr(bo_object, field['data'], 'unset')
                logger.debug(" -> field: %s", field)
            logger.debug("table data row: %s", row)

            # logger.debug("Table row: %s", row)
            rows.append(row)

        logger.debug("filtered records: %d out of total: %d",
                     self.records_filtered, self.records_total)

        # Send response
        return json.dumps({
            "draw": int(float(params.get('draw', '0'))),
            "recordsTotal": self.records_total,
            "recordsFiltered": self.records_filtered,
            "data": rows
        })
コード例 #9
0
    def show_worldmap(self, for_my_widget=False):
        """Get the hosts list to build a worldmap

        Get the list of the valid hosts t display onthe map

         If `for_my_widget` is True this function returns the list of the concerned hosts
         else it returns the worldmap view.

        :param for_my_widget: defaults to False
        :return:
        """
        user = request.environ['beaker.session']['current_user']
        datamgr = request.app.datamgr

        # Fetch elements per page preference for user, default is 25
        elts_per_page = datamgr.get_user_preferences(user, 'elts_per_page', 25)

        # Pagination and search
        start = int(request.query.get('start', '0'))
        count = int(request.query.get('count', elts_per_page))
        where = Helper.decode_search(request.query.get('search', ''),
                                     self.table)
        search = {
            'page': (start // count) + 1,
            'max_results': count,
            'sort': '-_id',
            'where': where
        }
        if self.plugin_parameters.get('hosts_business_impacts'):
            # Only get hosts which business impact is configured...
            logger.debug("worldmap, only hosts with BI in: %s",
                         self.plugin_parameters['hosts_business_impacts'])
            search['where'].update({
                'business_impact': {
                    '$in': self.plugin_parameters['hosts_business_impacts']
                }
            })
        if self.plugin_parameters.get('hosts_included'):
            # Include some hosts...
            logger.debug("worldmap, included hosts: %s",
                         self.plugin_parameters['hosts_included'])
            search['where'].update(
                {'name': {
                    "$regex": self.plugin_parameters['hosts_included']
                }})
        if self.plugin_parameters.get('hosts_excluded'):
            # Exclude some hosts...
            logger.debug("worldmap, excluded hosts: %s",
                         self.plugin_parameters['hosts_excluded'])
            search['where'].update({
                'name': {
                    "$regex":
                    "^((?!%s).)*$" % self.plugin_parameters['hosts_excluded']
                }
            })

        # Do not include the embedded fields to improve the loading time...
        hosts = datamgr.get_hosts(search, embedded=False)

        # Get positioned and not-positioned hosts
        positioned_hosts = self.get_map_elements(hosts)

        # Get last total elements count
        total = len(hosts)
        if hosts:
            total = hosts[0]['_total']
            logger.info("worldmap, total %d hosts", total)

        if for_my_widget:
            return [h for h in positioned_hosts if h['positioned']]

        map_style = "width: %s; height: %s;" % (self.plugin_parameters.get(
            'map_width',
            "100%"), self.plugin_parameters.get('map_height', "100%"))

        return {
            'search_engine':
            self.search_engine,
            'search_filters':
            self.search_filters,
            'mapId':
            'hostsMap',
            'mapStyle':
            map_style,
            'params':
            self.plugin_parameters,
            'hosts':
            positioned_hosts,
            'pagination':
            self.webui.helper.get_pagination_control('/worldmap', total, start,
                                                     count),
            'title':
            request.query.get('title', _('Hosts worldmap'))
        }
コード例 #10
0
    def table_data(self, plugin_table):
        # Because there are many locals needed :)
        # pylint: disable=too-many-locals
        """Return elements data in json format as of Datatables SSP protocol

        More info: https://datatables.net/manual/server-side

        Example URL::

            POST /?
            draw=1&
            columns[0][data]=alias&
            columns[0][name]=&
            columns[0][searchable]=true&
            columns[0][orderable]=true&
            columns[0][search][value]=&
            columns[0][search][regex]=false&
             ...
            order[0][column]=0&
            order[0][dir]=asc&
            start=0&
            length=10&
            search[value]=&
            search[regex]=false&

        Request parameters are Json formatted

        Request Parameters:
        - object_type: object type managed by the datatable
        - links: url prefix to be used by the links in the table
        - embedded: true / false whether the table is embedded by an external application
            **Note**: those three first parameters are not datatable specific parameters :)

        - draw, index parameter to be returned in the response

            Pagination:
            - start / length, for pagination

            Searching:
            - search (value or regexp)
            search[value]: Global search value. To be applied to all columns which are searchable
            search[regex]: true if search[value] is a regex

            Sorting:
            - order[i][column] / order[i][dir]
            index of the columns to order and sort direction (asc/desc)

            Columns:
            - columns[i][data]: Column's data source, as defined by columns.data.
            - columns[i][name]: Column's name, as defined by columns.name.
            - columns[i][searchable]: Flag to indicate if this column is searchable (true).
            - columns[i][orderable]: Flag to indicate if this column is orderable (true).
            - columns[i][search][value]: Search value to apply to this specific column.
            - columns[i][search][regex]: Flag to indicate if the search term for this column is a
            regex.

        Response data:
        - draw

        - recordsTotal: total records, before filtering
            (i.e. total number of records in the database)

        - recordsFiltered: Total records, after filtering
            (i.e. total number of records after filtering has been applied -
            not just the number of records being returned for this page of data).

        - data: The data to be displayed in the table.
            an array of data source objects, one for each row, which will be used by DataTables.

        - error (optional): Error message if an error occurs
            Not included if there is no error.
        """
        # Manage request parameters ...
        logger.info("request data for table: %s, templates: %s",
                    request.forms.get('object_type'), self.templates)

        # Because of specific datatables parameters name (eg. columns[0] ...)
        # ... some parameters have been json.stringify on client side !
        params = {}
        for key in list(request.params.keys()):
            if key in ['columns', 'order', 'search']:
                params[key] = json.loads(request.params.get(key))
            else:
                params[key] = request.params.get(key)
        # params now contains 'valid' query parameters as we should have found them ...
        logger.debug("table request parameters: %s", params)

        parameters = {}

        # Manage page number ...
        # start is the first requested row and we must transform to a page count ...
        first_row = int(params.get('start', '0'))
        # length is the number of requested rows
        rows_count = int(params.get('length', '25'))

        parameters['page'] = (first_row // rows_count) + 1
        parameters['max_results'] = rows_count
        logger.debug("get %d rows from row #%d -> page: %d", rows_count,
                     first_row, parameters['page'])

        # Columns ordering
        # order:[{"column":2,"dir":"desc"}]
        if 'order' in params and 'columns' in params and params['order']:
            sorted_columns = []
            for order in params['order']:
                idx = int(order['column'])
                if params['columns'][idx] and params['columns'][idx]['data']:
                    logger.debug("sort by column %d (%s), order: %s ", idx,
                                 params['columns'][idx]['data'], order['dir'])
                    if order['dir'] == 'desc':
                        sorted_columns.append('-' +
                                              params['columns'][idx]['data'])
                    else:
                        sorted_columns.append(params['columns'][idx]['data'])
            if sorted_columns:
                parameters['sort'] = ','.join(sorted_columns)

            logger.info("backend order request parameters: %s", parameters)

        # Individual column search parameter
        s_columns = []
        if 'columns' in params and params['columns']:
            for column in params['columns']:
                if 'searchable' not in column or 'search' not in column:  # pragma: no cover
                    continue
                if 'value' not in column[
                        'search'] or not column['search']['value']:
                    continue
                logger.debug("search column '%s' for '%s'", column['data'],
                             column['search']['value'])

                for field in self.table_columns:
                    if field['data'] != column['data']:
                        continue

                    # Some specific types...
                    if field['type'] == 'boolean':
                        s_columns.append({
                            column['data']:
                            column['search']['value'] == 'true'
                        })
                    elif field['type'] == 'integer':
                        s_columns.append(
                            {column['data']: int(column['search']['value'])})
                    elif field['format'] == 'select':
                        values = column['search']['value'].split(',')
                        if len(values) > 1:
                            s_columns.append({column['data']: {"$in": values}})
                        else:
                            s_columns.append({column['data']: values[0]})
                    # ... the other fields :)
                    else:
                        # Do not care about 'smart' and 'caseInsensitive' boolean parameters ...
                        if column['search']['regex']:
                            s_columns.append({
                                column['data']: {
                                    "$regex":
                                    ".*" + column['search']['value'] + ".*"
                                }
                            })
                        else:
                            s_columns.append(
                                {column['data']: column['search']['value']})
                    break

            logger.info("backend search individual columns parameters: %s",
                        s_columns)

        # Global search parameter
        # search:{"value":"test","regex":false}
        s_global = {}
        # pylint: disable=too-many-nested-blocks
        # Will be too complex else ...
        if 'search' in params and 'columns' in params and params['search']:
            # params['search'] contains something like: {u'regex': False, u'value': u'name:pi1'}
            # global regex is always ignored ... in favor of the column declared regex
            logger.info("global search requested: %s ", params['search'])
            if 'value' in params['search'] and params['search']['value']:
                # There is something to search for...
                logger.debug("search requested, value: %s ",
                             params['search']['value'])

                # New strategy: decode search patterns...
                search = Helper.decode_search(params['search']['value'],
                                              plugin_table)
                logger.info("decoded search pattern: %s", search)

                # Old strategy: search for the value in all the searchable columns...
                # if not search:
                #     logger.info("applying datatable search pattern...")
                #     for column in params['columns']:
                #         if not column['searchable']:
                #             continue
                #         logger.debug("search global '%s' for '%s'",
                #                      column['data'], params['search']['value'])
                #         if 'regex' in params['search']:
                #             if params['search']['regex']:
                #                 s_global.update(
                #                     {column['data']: {
                #                         "$regex": ".*" + params['search']['value'] + ".*"}})
                #             else:
                #                 s_global.update({column['data']: params['search']['value']})
                s_global = search

            logger.info("backend search global parameters: %s", s_global)

        # Specific hack to filter the log check results that are not dated!
        if self.object_type == 'logcheckresult':
            s_columns.append({"last_check": {"$ne": 0}})

        if s_columns and s_global:
            parameters['where'] = {"$and": [{"$and": s_columns}, s_global]}
        elif s_columns:
            parameters['where'] = {"$and": s_columns}
        elif s_global:
            parameters['where'] = s_global

        # Embed linked resources / manage templated resources
        parameters['embedded'] = {}
        for field in self.embedded:
            parameters['embedded'].update({field: 1})

        logger.debug("backend embedded parameters: %s", parameters['embedded'])

        # Count total elements excluding templates if necessary
        if self.is_templated:
            if self.ui_visibility:
                self.records_total = self.datamgr.my_backend.count(
                    self.object_type,
                    params={
                        'where': {
                            '_is_template': self.templates,
                            'webui_visible': True
                        }
                    })
            else:
                self.records_total = self.datamgr.my_backend.count(
                    self.object_type,
                    params={'where': {
                        '_is_template': self.templates
                    }})
            if 'where' in parameters:
                parameters['where'].update({'_is_template': self.templates})
            else:
                parameters['where'] = {'_is_template': self.templates}
        else:
            if self.ui_visibility:
                self.records_total = self.datamgr.my_backend.count(
                    self.object_type,
                    params={'where': {
                        'webui_visible': True
                    }})
            else:
                self.records_total = self.datamgr.my_backend.count(
                    self.object_type)

        if self.ui_visibility:
            if 'where' in parameters:
                parameters['where'].update({'webui_visible': True})
            else:
                parameters['where'] = {'webui_visible': True}

        # Request objects from the backend ...
        logger.info("table data get parameters: %s", parameters)
        items = self.datamgr.my_backend.get(self.object_type,
                                            params=parameters)
        logger.info("table data got %d items", len(items))
        if not items:
            logger.info("No backend elements match search criteria: %s",
                        parameters)
            # Empty response
            return json.dumps({
                # draw is the request number ...
                "draw": int(params.get('draw', '0')),
                "recordsTotal": 0,
                "recordsFiltered": 0,
                "data": []
            })

        # Create an object ...
        object_class = [
            kc for kc in self.datamgr.known_classes
            if kc.get_type() == self.object_type
        ]
        if not object_class:  # pragma: no cover, should never happen!
            logger.warning("datatable, unknown object type: %s",
                           self.object_type)
            # Empty response
            return json.dumps({
                # draw is the request number ...
                "draw": int(params.get('draw', '0')),
                "recordsTotal": 0,
                "recordsFiltered": 0,
                "data": []
            })

        # Update table inner properties with the object class defined properties
        object_class = object_class[0]

        self.id_property = '_id'
        if hasattr(object_class, 'id_property'):
            self.id_property = object_class.id_property
        self.name_property = 'name'
        if hasattr(object_class, 'name_property'):
            self.name_property = object_class.name_property
        self.status_property = 'status'
        if hasattr(object_class, 'status_property'):
            self.status_property = object_class.status_property
        logger.debug(
            "datatable, object type: '%s' and properties: %s / %s / %s",
            object_class, self.id_property, self.name_property,
            self.status_property)

        # Change item content...
        rows = []
        # Total number of filtered records
        self.records_filtered = self.records_total
        for item in items:
            bo_object = object_class(item)
            if not bo_object.ui_visible:
                logger.debug("Not UI visible object: %s", bo_object)
                continue

            logger.info("table data object: %s", bo_object)
            logger.debug("table data object: %s", bo_object)
            # This is an awful hack that allows to update the objects filtered for a table.
            # Two main interests:
            # - update the backend because some massive modifications are necessary for testing
            # - prepare a massive update feature in the Web UI :)
            # -----
            # if self.is_templated and self.templates and self.object_type == 'service':
            #     logger.warning("service template: %s for host: %s",
            #                    bo_object.name, bo_object['host'])
            #     if bo_object['host'].name.startswith('fdj'):
            #         logger.info("To be updated...")
            #         data = {
            #             "check_freshness": True,
            #             "freshness_threshold": 86400,
            #             "passive_checks_enabled": True,
            #             "active_checks_enabled": False
            #         }
            #         result = self.datamgr.update_object(element=bo_object, data=data)
            #         if result is True:
            #             logger.info("updated.")
            #         else:
            #             logger.error("update failed!")
            # -----

            # Each item contains the total number of records matching the search filter
            self.records_filtered = item['_total']

            row = {}
            row['DT_RowData'] = {}
            row['_id'] = bo_object.id
            for field in self.table_columns:
                logger.debug(" - field: %s", field)
                # Specific fields
                if field['data'] == self.name_property:
                    # Create a link to navigate to the item page
                    row[self.name_property] = bo_object.html_link
                    # Store the item name in a specific field of the row.
                    # The value will be retrieved by the table actions (ack, recheck, ...)
                    row['DT_RowData'].update(
                        {"object_%s" % self.object_type: bo_object.name})
                    continue

                if field['data'] == self.status_property:
                    # Replace the text status with the specific item HTML state
                    row[self.status_property] = bo_object.get_html_state(
                        text=None, title=bo_object.status)
                    # Use the item status to specify the table row class
                    # row['DT_RowClass'] = "table-row-%s" % (bo_object.status.lower())
                    continue

                if field['data'] in [
                        '_overall_state_id', 'overall_state', 'overall_status'
                ]:
                    # Get the item overall state from the data manager
                    f_get_overall_state = getattr(
                        self.datamgr,
                        'get_%s_overall_state' % self.object_type)
                    if f_get_overall_state:
                        (dummy,
                         overall_status) = f_get_overall_state(bo_object)

                        # Get element state configuration
                        row[field['data']] = ElementState().get_html_state(
                            self.object_type,
                            bo_object,
                            text=None,
                            title=bo_object.overall_state_to_title[
                                bo_object.overall_state],
                            use_status=overall_status)
                        # Use the item overall state to specify the table row class
                        row['DT_RowClass'] = "table-row-%s" % (overall_status)
                    else:  # pragma: no cover, should never happen!
                        logger.warning(
                            "Missing get_overall_state method for: %s",
                            self.object_type)
                        row[field['data']] = 'XxX'
                    continue

                if "business_impact" in field['data']:
                    # Replace the BI count with the specific item HTML formatting
                    row[field['data']] = Helper.get_html_business_impact(
                        bo_object.business_impact)
                    continue

                # Specific fields type
                if field['type'] == 'datetime' or field['format'] == 'datetime':
                    # Replace the timestamp with the formatted date
                    row[field['data']] = bo_object.get_date(
                        bo_object[field['data']])
                    continue

                if field['type'] == 'boolean':
                    # Replace the boolean vaue with the specific item HTML formatting
                    row[field['data']] = Helper.get_on_off(
                        bo_object[field['data']])
                    continue

                if field['type'] == 'list':
                    # Replace the list with the specific list HTML formatting
                    if hasattr(bo_object, field['data']):
                        row[field['data']] = Helper.get_html_item_list(
                            bo_object.id,
                            field['data'],
                            getattr(bo_object, field['data']),
                            title=field['title'])
                    else:
                        row[field['data']] = 'Unknown'
                    continue

                if field['type'] == 'dict':
                    # Replace the dictionary with the specific dict HTML formatting
                    row[field['data']] = Helper.get_html_item_list(
                        bo_object.id,
                        field['data'],
                        getattr(bo_object, field['data']),
                        title=field['title'])
                    continue

                if field['type'] == 'objectid':
                    if isinstance(bo_object[field['data']], BackendElement):
                        row[field['data']] = bo_object[
                            field['data']].get_html_link(
                                prefix=request.params.get('links'))
                        # row['DT_RowData'].update({
                        #     "object_%s" % field['data']: bo_object[field['data']].name
                        # })
                    else:
                        logger.warning(
                            "Table field is supposed to be an object: %s, %s = %s",
                            bo_object.name, field['data'],
                            getattr(bo_object, field['data']))
                        row[field['data']] = getattr(bo_object, field['data'])
                        if row[field['data']] == field['resource']:
                            row[field['data']] = '...'
                    continue

                # For any non-specific fields, send the field value to the table
                row[field['data']] = getattr(bo_object, field['data'], 'unset')
                logger.debug(" -> field: %s", field)
            logger.debug("table data row: %s", row)

            # logger.debug("Table row: %s", row)
            rows.append(row)

        logger.debug("filtered records: %d out of total: %d",
                     self.records_filtered, self.records_total)

        # Send response
        return json.dumps({
            "draw": int(float(params.get('draw', '0'))),
            "recordsTotal": self.records_total,
            "recordsFiltered": self.records_filtered,
            "data": rows
        })