Example #1
0
    def test_actions_url(self):
        """ Helper - get_element_notes_url """

        host = Host({
            '_id': '575a7dd74c988c170e857988',
            '_status': 'OK',
            'name': 'test',
            '_created': 1470995433,
            '_updated': 1470995450,
        })
        assert host

        html_actions = Helper.get_element_actions_url(host, default_title="Url", default_icon="globe")
        assert html_actions == []

        host = Host({
            '_id': '575a7dd74c988c170e857988',
            '_status': 'OK',
            'name': 'test',
            '_created': 1470995433,
            '_updated': 1470995450,
            'action_url': 'http://www.google.fr|url1::http://www.google.fr|My KB,,tag::http://www.my-KB.fr?host=$HOSTNAME$|Last URL,,tag::<strong>Lorem ipsum dolor sit amet</strong>, consectetur adipiscing elit. Proin et leo gravida, lobortis nunc nec, imperdiet odio. Vivamus quam velit, scelerisque nec egestas et, semper ut massa.,,http://www.my-KB.fr?host=$HOSTADDRESS$',
        })
        assert host

        html_actions = Helper.get_element_actions_url(host, default_title="Url", default_icon="globe")
        # 3 declared actions, with different parameters
        # Expecting 3 links
        assert html_actions == [
            '<a href="http://www.google.fr" target="_blank" role="button" data-toggle="popover urls" data-container="body" data-html="true" data-content="No description provided" data-trigger="hover focus" data-placement="bottom"><span class="fa fa-globe"></span>&nbsp;Url</a>', '<a href="http://www.google.fr" target="_blank" role="button" data-toggle="popover urls" data-container="body" data-html="true" data-content="No description provided" data-trigger="hover focus" data-placement="bottom"><span class="fa fa-globe"></span>&nbsp;url1</a>',
            '<a href="http://www.my-KB.fr?host=$HOSTNAME$" target="_blank" role="button" data-toggle="popover urls" data-container="body" data-html="true" data-content="No description provided" data-trigger="hover focus" data-placement="bottom"><span class="fa fa-tag"></span>&nbsp;My KB</a>',
            '<a href="http://www.my-KB.fr?host=$HOSTADDRESS$" target="_blank" role="button" data-toggle="popover urls" data-container="body" data-html="true" data-content="<strong>Lorem ipsum dolor sit amet</strong>, consectetur adipiscing elit. Proin et leo gravida, lobortis nunc nec, imperdiet odio. Vivamus quam velit, scelerisque nec egestas et, semper ut massa." data-trigger="hover focus" data-placement="bottom"><span class="fa fa-tag"></span>&nbsp;Last URL</a>'
        ]
Example #2
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
    }
Example #3
0
    def __init__(self, config=None):
        """
        Application configuration

        :param: config
        :type: dict
        """

        logger.info("Initializing...")

        # Store all the plugins
        self.plugins = []

        # Store all the widgets
        self.widgets = {}

        # Store all the tables
        self.tables = {}

        # Store all the lists
        self.lists = {}

        # Helper class
        self.helper = Helper()

        # Application configuration
        self.app_config = config
        logger.info("Configuration: %s", self.app_config)

        # Load plugins in the plugins directory ...
        self.plugins_count = self.load_plugins(
            bottle.app(),
            os.path.join(os.path.abspath(os.path.dirname(__file__)),
                         'plugins'))
Example #4
0
    def get_date(self, _date, fmt=None, duration=False):
        """Format the provided `_date` as a string according to the specified format.

        If no date format is specified, it uses the one defined in the ElementState object that is
        the date format defined in the application configuration.

        If duration is True, the date is displayed as a pretty date: 1 day 12 minutes ago ...
        """
        if _date == self.__class__._default_date:
            return _('Never dated!')

        if duration:
            return Helper.print_duration(_date, duration_only=False, x_elts=0)

        item_state = ElementState()
        if not fmt:
            if item_state.date_format:
                fmt = item_state.date_format

        # Make timestamp to datetime
        _date = datetime.utcfromtimestamp(_date)
        # Tell the datetime object that it's in UTC time zone since
        # datetime objects are 'naive' by default
        _date = _date.replace(tzinfo=item_state.tz_from)
        # Convert to required time zone
        _date = _date.astimezone(item_state.tz_to)

        if fmt:
            return _date.strftime(fmt)

        return _date.isoformat(' ')
    def get_date(self, _date, fmt=None, duration=False):
        """Format the provided `_date` as a string according to the specified format.

        If no date format is specified, it uses the one defined in the ElementState object that is
        the date format defined in the application configuration.

        If duration is True, the date is displayed as a pretty date: 1 day 12 minutes ago ...
        """
        if _date == self.__class__._default_date:
            return _('Never dated!')

        if duration:
            return Helper.print_duration(_date, duration_only=False, x_elts=0)

        item_state = ElementState()
        if not fmt:
            if item_state.date_format:
                fmt = item_state.date_format

        # Make timestamp to datetime
        _date = datetime.utcfromtimestamp(_date)
        # Tell the datetime object that it's in UTC time zone since
        # datetime objects are 'naive' by default
        _date = _date.replace(tzinfo=item_state.tz_from)
        # Convert to required time zone
        _date = _date.astimezone(item_state.tz_to)

        if fmt:
            return _date.strftime(fmt)

        return _date.isoformat(' ')
Example #6
0
    def test_notes_url(self):
        """ Helper - get_element_notes_url """

        host = Host({
            '_id': '575a7dd74c988c170e857988',
            '_status': 'OK',
            'name': 'test',
            '_created': 1470995433,
            '_updated': 1470995450,
        })
        assert host

        html_notes = Helper.get_element_notes_url(host, default_title="Note", default_icon="tag")
        # Empty list when no notes exist
        assert html_notes == []

        host = Host({
            '_id': '575a7dd74c988c170e857988',
            '_status': 'OK',
            'name': 'test',
            '_created': 1470995433,
            '_updated': 1470995450,
            'notes': 'note simple|Libellé::note avec un libellé|KB1023,,tag::<strong>Lorem ipsum dolor sit amet</strong>, consectetur adipiscing elit. Proin et leo gravida, lobortis nunc nec, imperdiet odio. Vivamus quam velit, scelerisque nec egestas et, semper ut massa. Vestibulum id tincidunt lacus. Ut in arcu at ex egestas vestibulum eu non sapien. Nulla facilisi. Aliquam non blandit tellus, non luctus tortor. Mauris tortor libero, egestas quis rhoncus in, sollicitudin et tortor.|note simple|Tag::tagged note ...',
            'notes_url': 'http://www.my-KB.fr?host=$HOSTADDRESS$|http://www.my-KB.fr?host=$HOSTNAME$',
        })
        assert host

        html_notes = Helper.get_element_notes_url(host, default_title="Note", default_icon="tag")
        # 5 declared notes, but only 2 URLs
        # Expecting 5 links
        assert html_notes == [
            '<a href="http://www.my-KB.fr?host=$HOSTADDRESS$" target="_blank" role="button" data-toggle="popover urls" data-container="body" data-html="true" data-content="note simple" data-trigger="hover focus" data-placement="bottom"><span class="fa fa-tag"></span>&nbsp;Note</a>',
            '<a href="http://www.my-KB.fr?host=$HOSTNAME$" target="_blank" role="button" data-toggle="popover urls" data-container="body" data-html="true" data-content="note avec un libellé" data-trigger="hover focus" data-placement="bottom"><span class="fa fa-tag"></span>&nbsp;Libellé</a>',
            '<a href="#" role="button" data-toggle="popover urls" data-container="body" data-html="true" data-content="<strong>Lorem ipsum dolor sit amet</strong>, consectetur adipiscing elit. Proin et leo gravida, lobortis nunc nec, imperdiet odio. Vivamus quam velit, scelerisque nec egestas et, semper ut massa. Vestibulum id tincidunt lacus. Ut in arcu at ex egestas vestibulum eu non sapien. Nulla facilisi. Aliquam non blandit tellus, non luctus tortor. Mauris tortor libero, egestas quis rhoncus in, sollicitudin et tortor." data-trigger="hover focus" data-placement="bottom"><span class="fa fa-tag"></span>&nbsp;KB1023</span></a>',
            '<a href="#" role="button" data-toggle="popover urls" data-container="body" data-html="true" data-content="note simple" data-trigger="hover focus" data-placement="bottom"><span class="fa fa-tag"></span>&nbsp;Note</span></a>',
            '<a href="#" role="button" data-toggle="popover urls" data-container="body" data-html="true" data-content="tagged note ..." data-trigger="hover focus" data-placement="bottom"><span class="fa fa-tag"></span>&nbsp;Tag</span></a>'
        ]
    def bi_livestate(self):  # pylint:disable=no-self-use
        """Returns the livestate for a specific business impact level

        Used by the view to update the live state page content
        """
        user = request.environ['beaker.session']['current_user']
        webui = request.app.config['webui']
        datamgr = webui.datamgr

        panels = datamgr.get_user_preferences(user, 'livestate', {})

        ls = Helper.get_html_livestate(datamgr, panels, int(request.query.get('bi', -1)),
                                       request.query.get('search', {}), actions=user.is_power())

        response.status = 200
        response.content_type = 'application/json'
        return json.dumps({'livestate': ls})
Example #8
0
    def bi_livestate(self):  # pylint:disable=no-self-use
        """Returns the livestate for a specific business impact level

        Used by the view to update the live state page content
        """
        user = request.environ['beaker.session']['current_user']
        webui = request.app.config['webui']
        datamgr = webui.datamgr

        panels = datamgr.get_user_preferences(user, 'livestate', {})

        ls = Helper.get_html_livestate(datamgr,
                                       panels,
                                       int(request.query.get('bi', -1)),
                                       request.query.get('search', {}),
                                       actions=user.is_power())

        response.status = 200
        response.content_type = 'application/json'
        return json.dumps({'livestate': ls})
Example #9
0
    def setUp(self):
        print ""
        print "setting up ..."

        alignak_webui.app.config['HOST'] = '127.0.0.1'
        alignak_webui.app.config['PORT'] = 80
        alignak_webui.app.config['DEBUG'] = False

        alignak_webui.app.config['TESTING'] = True

        cfg_file = "settings.cfg"
        print 'Required configuration file:', cfg_file
        sett = Settings(alignak_webui.app)
        found_cfg_files = sett.read(cfg_file, {})
        if not found_cfg_files:
            print "Required configuration file not found."
            sys.exit(1)
        print 'Found configuration file:', cfg_file

        self.helper = Helper(alignak_webui.app)
Example #10
0
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'))
    }
Example #11
0
    def __init__(self, app, name='alignak_webui', config=None):
        """
        Application initialization

        :param: config
        :type: dict
        """
        logger.info("Initializing application...")
        self.reduced_mode = os.environ.get('ALIGNAK_WEBUI_REDUCED', False)
        if self.reduced_mode:
            logger.warning("- reduced mode: %s!", self.reduced_mode)

        # Store all the plugins
        self.plugins = []

        # Store all the widgets
        self.widgets = {}

        # Store all the tables
        self.tables = {}

        # Store all the lists
        self.lists = {}

        # Helper class
        self.helper = Helper()

        # Application configuration
        self.app = app
        self.name = name
        self.config = config

        # Application data manager and connection
        self.datamgr = None
        self.current_user = None

        # Load plugins in the plugins directory ...
        self.plugins_dir = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'plugins')
        self.plugins_count = self.load_plugins(plugins_dir=self.plugins_dir)
        logger.info("loaded %d plugins from: %s", self.plugins_count, self.plugins_dir)
Example #12
0
def get_servicegroup_members(servicegroup_id):
    """
    Get the servicegroup services list
    """
    datamgr = request.environ['beaker.session']['datamanager']

    servicegroup = datamgr.get_servicegroup(servicegroup_id)
    if not servicegroup:  # pragma: no cover, should not happen
        return webui.response_invalid_parameters(
            _('Services group element does not exist'))

    # Not JSON serializable!
    # items = servicegroup.members

    items = []
    for service in servicegroup.members:
        lv_service = datamgr.get_livestate(
            {'where': {
                'type': 'service',
                'service': service.id
            }})
        lv_service = lv_service[0]
        title = "%s - %s (%s)" % (lv_service.status,
                                  Helper.print_duration(
                                      lv_service.last_check,
                                      duration_only=True,
                                      x_elts=0), lv_service.output)

        items.append({
            'id': service.id,
            'name': service.name,
            'alias': service.alias,
            'icon': lv_service.get_html_state(text=None, title=title),
            'url': lv_service.get_html_link()
        })

    response.status = 200
    response.content_type = 'application/json'
    return json.dumps(items)
    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'))
        }
Example #14
0
class test_helper(unittest.TestCase):

    def setUp(self):
        print ""
        print "setting up ..."

        alignak_webui.app.config['HOST'] = '127.0.0.1'
        alignak_webui.app.config['PORT'] = 80
        alignak_webui.app.config['DEBUG'] = False

        alignak_webui.app.config['TESTING'] = True

        cfg_file = "settings.cfg"
        print 'Required configuration file:', cfg_file
        sett = Settings(alignak_webui.app)
        found_cfg_files = sett.read(cfg_file, {})
        if not found_cfg_files:
            print "Required configuration file not found."
            sys.exit(1)
        print 'Found configuration file:', cfg_file

        self.helper = Helper(alignak_webui.app)

    def tearDown(self):
        print ""
        print "tearing down ..."


    def test_01_print_date(self):
        print "---"

        now = time.time()

        # Timestamp errors
        s = self.helper.print_date(None)
        print "Result:", s
        self.assert_(s == 'n/a')

        s = self.helper.print_date(0)
        print "Result:", s
        self.assert_(s == 'n/a')

        # Now, default format
        s = self.helper.print_date(now)
        print "Result:", s

        # Now, specified format
        s = self.helper.print_date(now, fmt='%Y-%m-%d')
        print "Result:", s

        s = self.helper.print_date(now, fmt='%H:%M:%S')
        print "Result:", s

    def test_02_print_duration(self):
        print "---"

        now = time.time()

        # Timestamp errors
        s = self.helper.print_duration(None)
        print "Result:", s
        self.assert_(s == 'n/a')
        s = self.helper.print_duration(0)
        print "Result:", s
        self.assert_(s == 'n/a')

        # Now, default format
        s = self.helper.print_duration(now)
        print "Result:", s
        self.assert_(s == 'Now')

        # In the past ...
        # 2s ago
        s = self.helper.print_duration(now - 2)
        print "Result:", s
        self.assert_(s == '2s ago')

        # Only the duration string
        s = self.helper.print_duration(now - 2, duration_only=True)
        print "Result:", s
        self.assert_(s == '2s')

        # Got 2minutes
        s = self.helper.print_duration(now - 120)
        print "Result:", s
        self.assert_(s == '2m ago')

        # Go 2hours ago
        s = self.helper.print_duration(now - 3600*2)
        print "Result:", s
        self.assert_(s == '2h ago')

        # Go 2 days ago
        s = self.helper.print_duration(now - 3600*24*2)
        print "Result:", s
        self.assert_(s == '2d ago')

        # Go 2 weeks ago
        s = self.helper.print_duration(now - 86400*14)
        print "Result:", s
        self.assert_(s == '2w ago')

        # Go 2 months ago
        s = self.helper.print_duration(now - 86400*56)
        print "Result:", s
        self.assert_(s == '2M ago')

        # Go 1 year ago
        s = self.helper.print_duration(now - 86400*365*2)
        print "Result:", s
        self.assert_(s == '2y ago')

        # Now a mix of all of this :)
        s = self.helper.print_duration(now - 2 - 120 - 3600*2 - 3600*24*2 - 86400*14 - 86400*56)
        print "Result:", s
        self.assert_(s == '2M 2w 2d 2h 2m 2s ago')

        # Now with a limit, because here it's just a nightmare to read
        s = self.helper.print_duration(now - 2 - 120 - 3600*2 - 3600*24*2 - 86400*14 - 86400*56, x_elts=2)
        print "Result:", s
        self.assert_(s == '2M 2w ago')

        # Return to the future
        # Get the 2s ago
        s = self.helper.print_duration(now + 2)
        print "Result:", s
        self.assert_(s == 'in 2s')

        # Got 2minutes
        s = self.helper.print_duration(now + 120)
        print "Result:", s
        self.assert_(s == 'in 2m')

        # Go 2hours ago
        s = self.helper.print_duration(now + 3600*2)
        print "Result:", s
        self.assert_(s == 'in 2h')

        # Go 2 days ago
        s = self.helper.print_duration(now + 3600*24*2)
        print "Result:", s
        self.assert_(s == 'in 2d')

        # Go 2 weeks ago
        s = self.helper.print_duration(now + 86400*14)
        print "Result:", s
        self.assert_(s == 'in 2w')

        # Go 2 months ago
        s = self.helper.print_duration(now + 86400*56)
        print "Result:", s
        self.assert_(s == 'in 2M')

        # Go 1 year ago
        s = self.helper.print_duration(now + 86400*365*2)
        print "Result:", s
        self.assert_(s == 'in 2y')

        # Now a mix of all of this :)
        s = self.helper.print_duration(now + 2 + 120 + 3600*2 + 3600*24*2 + 86400*14 + 86400*56)
        print "Result:", s
        self.assert_(s == 'in 2M 2w 2d 2h 2m 2s')

        # Now with a limit, because here it's just a nightmare to read
        s = self.helper.print_duration(now + 2 - 120 + 3600*2 + 3600*24*2 + 86400*14 + 86400*56, x_elts=2)
        print "Result:", s
        self.assert_(s == 'in 2M 2w')

    def test_03_get_business_impact_text(self):
        print "---"

        # Parameters errors
        s = self.helper.get_html_business_impact(10)
        print "Result:", s
        self.assert_(s == 'n/a')

        s = self.helper.get_html_business_impact(6, text=False)
        print "Result:", s
        self.assert_(s == 'n/a')

        s = self.helper.get_html_business_impact(-1)
        print "Result:", s
        self.assert_(s == 'n/a')

        s = self.helper.get_html_business_impact(1, False, False)
        print "Result:", s
        self.assert_(s == 'n/a')

        s = self.helper.get_html_business_impact(1, text=False, icon=False)
        print "Result:", s
        self.assert_(s == 'n/a')

        # Default ... text and stars
        s = self.helper.get_html_business_impact(0)
        print "Result:", s
        self.assert_(s == 'None')
        s = self.helper.get_html_business_impact(1)
        print "Result:", s
        self.assert_(s == 'Low')
        s = self.helper.get_html_business_impact(2)
        print "Result:", s
        self.assert_(s == 'Normal')
        s = self.helper.get_html_business_impact(3)
        print "Result:", s
        self.assert_(s == 'Important <i class="fa fa-star text-primary"></i>')
        s = self.helper.get_html_business_impact(4)
        print "Result:", s
        self.assert_(s == 'Very important <i class="fa fa-star text-primary"></i><i class="fa fa-star text-primary"></i>')
        s = self.helper.get_html_business_impact(5)
        print "Result:", s
        self.assert_(s == 'Business critical <i class="fa fa-star text-primary"></i><i class="fa fa-star text-primary"></i><i class="fa fa-star text-primary"></i>')

        # Stars only ...
        s = self.helper.get_html_business_impact(0, text=False)
        print "Result:", s
        self.assert_(s == '')
        s = self.helper.get_html_business_impact(1, text=False)
        print "Result:", s
        self.assert_(s == '')
        s = self.helper.get_html_business_impact(2, text=False)
        print "Result:", s
        self.assert_(s == '')
        s = self.helper.get_html_business_impact(3, text=False)
        print "Result:", s
        self.assert_(s == '<i class="fa fa-star text-primary"></i>')
        s = self.helper.get_html_business_impact(4, text=False)
        print "Result:", s
        self.assert_(s == '<i class="fa fa-star text-primary"></i><i class="fa fa-star text-primary"></i>')
        s = self.helper.get_html_business_impact(5, text=False)
        print "Result:", s
        self.assert_(s == '<i class="fa fa-star text-primary"></i><i class="fa fa-star text-primary"></i><i class="fa fa-star text-primary"></i>')

        # Text only ...
        s = self.helper.get_html_business_impact(0, icon=False)
        print "Result:", s
        self.assert_(s == 'None')
        s = self.helper.get_html_business_impact(1, icon=False)
        print "Result:", s
        self.assert_(s == 'Low')
        s = self.helper.get_html_business_impact(2, icon=False)
        print "Result:", s
        self.assert_(s == 'Normal')
        s = self.helper.get_html_business_impact(3, icon=False)
        print "Result:", s
        self.assert_(s == 'Important')
        s = self.helper.get_html_business_impact(4, icon=False)
        print "Result:", s
        self.assert_(s == 'Very important')
        s = self.helper.get_html_business_impact(5, icon=False)

    def test_04_get_state_text(self):
        print "---"

        print "Parameters errors:"
        s = self.helper.get_html_state('', '')
        print "Result:", s
        self.assert_(s == 'n/a')

        s = self.helper.get_html_state('host', 'bad state')
        print "Result:", s
        self.assert_(s == 'n/a')

        s = self.helper.get_html_state('service', 'bad state')
        print "Result:", s
        self.assert_(s == 'n/a')

        s = self.helper.get_html_state('host', 'UP', extra='bad state')
        print "Result:", s
        self.assert_(s == 'n/a')

        s = self.helper.get_html_state('service', 'OK', extra='bad state')
        print "Result:", s
        self.assert_(s == 'n/a')

        s = self.helper.get_html_state('host', 'UP', icon=False, text=False)
        print "Result:", s
        self.assert_(s == 'n/a')

        s = self.helper.get_html_state('service', 'OK', icon=False, text=False)
        print "Result:", s
        self.assert_(s == 'n/a')

    def test_05_get_host_state_text(self):
        print "---"

        # Host, icon only (default) ...
        s = self.helper.get_html_state('host', 'UP')
        print "Result:", s
        self.assert_(s == '<center class="font-up"><span class="fa-stack" title="host state is UP"><i class="fa fa-circle fa-stack-2x font-up"></i><i class="fa fa-server fa-stack-1x fa-inverse"></i></span><div></div></center>')
        s = self.helper.get_html_state('host', 'DOWN')
        print "Result:", s
        self.assert_(s == '<center class="font-down"><span class="fa-stack" title="host state is DOWN"><i class="fa fa-circle fa-stack-2x font-down"></i><i class="fa fa-server fa-stack-1x fa-inverse"></i></span><div></div></center>')
        s = self.helper.get_html_state('host', 'UNREACHABLE')
        print "Result:", s
        self.assert_(s == '<center class="font-unreachable"><span class="fa-stack" title="host state is UNREACHABLE"><i class="fa fa-circle fa-stack-2x font-unreachable"></i><i class="fa fa-server fa-stack-1x fa-inverse"></i></span><div></div></center>')
        s = self.helper.get_html_state('host', 'UP', extra='FLAPPING')
        print "Result:", s
        self.assert_(s == '<center class="font-up"><span class="fa-stack" title="host state is UP and flapping"><i class="fa fa-circle fa-stack-2x font-up"></i><i class="fa fa-server fa-stack-1x font-up"></i></span><div></div></center>')
        s = self.helper.get_html_state('host', 'DOWN', extra='FLAPPING')
        print "Result:", s
        self.assert_(s == '<center class="font-down"><span class="fa-stack" title="host state is DOWN and flapping"><i class="fa fa-circle fa-stack-2x font-down"></i><i class="fa fa-server fa-stack-1x font-down"></i></span><div></div></center>')
        s = self.helper.get_html_state('host', 'DOWN', extra='ACKNOWLEDGED')
        print "Result:", s
        self.assert_(s == '<center class="font-down"><span class="fa-stack" style="opacity: 0.5" title="host state is DOWN and acknowledged"><i class="fa fa-circle fa-stack-2x font-down"></i><i class="fa fa-server fa-stack-1x fa-inverse"></i></span><div></div></center>')
        s = self.helper.get_html_state('host', 'DOWN', extra='IN_DOWNTIME')
        print "Result:", s
        self.assert_(s == '<center class="font-down"><span class="fa-stack" style="opacity: 0.5" title="host state is DOWN but downtime is scheduled"><i class="fa fa-circle fa-stack-2x font-down"></i><i class="fa fa-server fa-stack-1x fa-inverse"></i></span><div></div></center>')
        # Host, text only ...
        s = self.helper.get_html_state('host', 'UP', text=True, icon=False)
        print "Result:", s
        self.assert_(s == 'host state is UP')
        s = self.helper.get_html_state('host', 'DOWN', text=True, icon=False)
        print "Result:", s
        self.assert_(s == 'host state is DOWN')
        s = self.helper.get_html_state('host', 'UNREACHABLE', text=True, icon=False)
        print "Result:", s
        self.assert_(s == 'host state is UNREACHABLE')
        s = self.helper.get_html_state('host', 'UP', extra='FLAPPING', text=True, icon=False)
        print "Result:", s
        self.assert_(s == 'host state is UP and flapping')
        s = self.helper.get_html_state('host', 'DOWN', extra='FLAPPING', text=True, icon=False)
        print "Result:", s
        self.assert_(s == 'host state is DOWN and flapping')
        s = self.helper.get_html_state('host', 'DOWN', extra='ACKNOWLEDGED', text=True, icon=False)
        print "Result:", s
        self.assert_(s == 'host state is DOWN and acknowledged')
        s = self.helper.get_html_state('host', 'DOWN', extra='IN_DOWNTIME', text=True, icon=False)
        print "Result:", s
        self.assert_(s == 'host state is DOWN but downtime is scheduled')

        # Host, icon and text ...
        s = self.helper.get_html_state('host', 'UP', text=True, icon=True)
        print "Result:", s
        self.assert_(s == '<center class="font-up"><span class="fa-stack" title="host state is UP"><i class="fa fa-circle fa-stack-2x font-up"></i><i class="fa fa-server fa-stack-1x fa-inverse"></i></span><div>host state is UP</div></center>')
        s = self.helper.get_html_state('host', 'DOWN', text=True, icon=True)
        print "Result:", s
        self.assert_(s == '<center class="font-down"><span class="fa-stack" title="host state is DOWN"><i class="fa fa-circle fa-stack-2x font-down"></i><i class="fa fa-server fa-stack-1x fa-inverse"></i></span><div>host state is DOWN</div></center>')
        s = self.helper.get_html_state('host', 'UNREACHABLE', text=True, icon=True)
        print "Result:", s
        self.assert_(s == '<center class="font-unreachable"><span class="fa-stack" title="host state is UNREACHABLE"><i class="fa fa-circle fa-stack-2x font-unreachable"></i><i class="fa fa-server fa-stack-1x fa-inverse"></i></span><div>host state is UNREACHABLE</div></center>')
        s = self.helper.get_html_state('host', 'UP', extra='FLAPPING', text=True, icon=True)
        print "Result:", s
        self.assert_(s == '<center class="font-up"><span class="fa-stack" title="host state is UP and flapping"><i class="fa fa-circle fa-stack-2x font-up"></i><i class="fa fa-server fa-stack-1x font-up"></i></span><div>host state is UP and flapping</div></center>')
        s = self.helper.get_html_state('host', 'DOWN', extra='FLAPPING', text=True, icon=True)
        print "Result:", s
        self.assert_(s == '<center class="font-down"><span class="fa-stack" title="host state is DOWN and flapping"><i class="fa fa-circle fa-stack-2x font-down"></i><i class="fa fa-server fa-stack-1x font-down"></i></span><div>host state is DOWN and flapping</div></center>')
        s = self.helper.get_html_state('host', 'DOWN', extra='ACKNOWLEDGED', text=True, icon=True)
        print "Result:", s
        self.assert_(s == '<center class="font-down"><span class="fa-stack" style="opacity: 0.5" title="host state is DOWN and acknowledged"><i class="fa fa-circle fa-stack-2x font-down"></i><i class="fa fa-server fa-stack-1x fa-inverse"></i></span><div>host state is DOWN and acknowledged</div></center>')
        s = self.helper.get_html_state('host', 'DOWN', extra='IN_DOWNTIME', text=True, icon=True)
        print "Result:", s
        self.assert_(s == '<center class="font-down"><span class="fa-stack" style="opacity: 0.5" title="host state is DOWN but downtime is scheduled"><i class="fa fa-circle fa-stack-2x font-down"></i><i class="fa fa-server fa-stack-1x fa-inverse"></i></span><div>host state is DOWN but downtime is scheduled</div></center>')

    def test_06_get_service_state_text(self):
        print "---"

        # service, icon only (default) ...
        s = self.helper.get_html_state('service', 'OK')
        print "Result:", s
        self.assert_(s == '<center class="font-ok"><span class="fa-stack" title="service state is OK"><i class="fa fa-circle fa-stack-2x font-ok"></i><i class="fa fa-arrow-up fa-stack-1x fa-inverse"></i></span><div></div></center>')
        s = self.helper.get_html_state('service', 'CRITICAL')
        print "Result:", s
        self.assert_(s == '<center class="font-critical"><span class="fa-stack" title="service state is CRITICAL"><i class="fa fa-circle fa-stack-2x font-critical"></i><i class="fa fa-arrow-down fa-stack-1x fa-inverse"></i></span><div></div></center>')
        s = self.helper.get_html_state('service', 'WARNING')
        print "Result:", s
        self.assert_(s == '<center class="font-warning"><span class="fa-stack" title="service state is WARNING"><i class="fa fa-circle fa-stack-2x font-warning"></i><i class="fa fa-exclamation fa-stack-1x fa-inverse"></i></span><div></div></center>')
        s = self.helper.get_html_state('service', 'UNKNOWN')
        print "Result:", s
        self.assert_(s == '<center class="font-unknown"><span class="fa-stack" title="service state is UNKNOWN"><i class="fa fa-circle fa-stack-2x font-unknown"></i><i class="fa fa-question fa-stack-1x fa-inverse"></i></span><div></div></center>')
        s = self.helper.get_html_state('service', 'ok', extra='FLAPPING')
        print "Result:", s
        self.assert_(s == '<center class="font-ok"><span class="fa-stack" title="service state is OK and flapping"><i class="fa fa-circle fa-stack-2x font-ok"></i><i class="fa fa-arrow-up fa-stack-1x font-ok"></i></span><div></div></center>')
        s = self.helper.get_html_state('service', 'CRITICAL', extra='FLAPPING')
        print "Result:", s
        self.assert_(s == '<center class="font-critical"><span class="fa-stack" title="service state is CRITICAL and flapping"><i class="fa fa-circle fa-stack-2x font-critical"></i><i class="fa fa-arrow-down fa-stack-1x font-critical"></i></span><div></div></center>')
        s = self.helper.get_html_state('service', 'CRITICAL', extra='ACKNOWLEDGED')
        print "Result:", s
        self.assert_(s == '<center class="font-critical"><span class="fa-stack" style="opacity: 0.5" title="service state is CRITICAL and acknowledged"><i class="fa fa-circle fa-stack-2x font-critical"></i><i class="fa fa-arrow-down fa-stack-1x fa-inverse"></i></span><div></div></center>')
        s = self.helper.get_html_state('service', 'CRITICAL', extra='IN_DOWNTIME')
        print "Result:", s
        self.assert_(s == '<center class="font-critical"><span class="fa-stack" style="opacity: 0.5" title="service state is CRITICAL but downtime is scheduled"><i class="fa fa-circle fa-stack-2x font-critical"></i><i class="fa fa-arrow-down fa-stack-1x fa-inverse"></i></span><div></div></center>')

        # service, text only ...
        s = self.helper.get_html_state('service', 'OK', text=True, icon=False)
        print "Result:", s
        self.assert_(s == 'service state is OK')
        s = self.helper.get_html_state('service', 'CRITICAL', text=True, icon=False)
        print "Result:", s
        self.assert_(s == 'service state is CRITICAL')
        s = self.helper.get_html_state('service', 'WARNING', text=True, icon=False)
        print "Result:", s
        self.assert_(s == 'service state is WARNING')
        s = self.helper.get_html_state('service', 'UNKNOWN', text=True, icon=False)
        print "Result:", s
        self.assert_(s == 'service state is UNKNOWN')
        s = self.helper.get_html_state('service', 'OK', extra='FLAPPING', text=True, icon=False)
        print "Result:", s
        self.assert_(s == 'service state is OK and flapping')
        s = self.helper.get_html_state('service', 'CRITICAL', extra='FLAPPING', text=True, icon=False)
        print "Result:", s
        self.assert_(s == 'service state is CRITICAL and flapping')
        s = self.helper.get_html_state('service', 'CRITICAL', extra='ACKNOWLEDGED', text=True, icon=False)
        print "Result:", s
        self.assert_(s == 'service state is CRITICAL and acknowledged')
        s = self.helper.get_html_state('service', 'CRITICAL', extra='IN_DOWNTIME', text=True, icon=False)
        print "Result:", s
        self.assert_(s == 'service state is CRITICAL but downtime is scheduled')

        # service, icon and text ...
        s = self.helper.get_html_state('service', 'OK', text=True, icon=True)
        print "Result:", s
        self.assert_(s == '<center class="font-ok"><span class="fa-stack" title="service state is OK"><i class="fa fa-circle fa-stack-2x font-ok"></i><i class="fa fa-arrow-up fa-stack-1x fa-inverse"></i></span><div>service state is OK</div></center>')
        s = self.helper.get_html_state('service', 'CRITICAL', text=True, icon=True)
        print "Result:", s
        self.assert_(s == '<center class="font-critical"><span class="fa-stack" title="service state is CRITICAL"><i class="fa fa-circle fa-stack-2x font-critical"></i><i class="fa fa-arrow-down fa-stack-1x fa-inverse"></i></span><div>service state is CRITICAL</div></center>')
        s = self.helper.get_html_state('service', 'WARNING', text=True, icon=True)
        print "Result:", s
        self.assert_(s == '<center class="font-warning"><span class="fa-stack" title="service state is WARNING"><i class="fa fa-circle fa-stack-2x font-warning"></i><i class="fa fa-exclamation fa-stack-1x fa-inverse"></i></span><div>service state is WARNING</div></center>')
        s = self.helper.get_html_state('service', 'UNKNOWN', text=True, icon=True)
        print "Result:", s
        self.assert_(s == '<center class="font-unknown"><span class="fa-stack" title="service state is UNKNOWN"><i class="fa fa-circle fa-stack-2x font-unknown"></i><i class="fa fa-question fa-stack-1x fa-inverse"></i></span><div>service state is UNKNOWN</div></center>')
        s = self.helper.get_html_state('service', 'ok', extra='FLAPPING', text=True, icon=True)
        print "Result:", s
        self.assert_(s == '<center class="font-ok"><span class="fa-stack" title="service state is OK and flapping"><i class="fa fa-circle fa-stack-2x font-ok"></i><i class="fa fa-arrow-up fa-stack-1x font-ok"></i></span><div>service state is OK and flapping</div></center>')
        s = self.helper.get_html_state('service', 'CRITICAL', extra='FLAPPING', text=True, icon=True)
        print "Result:", s
        self.assert_(s == '<center class="font-critical"><span class="fa-stack" title="service state is CRITICAL and flapping"><i class="fa fa-circle fa-stack-2x font-critical"></i><i class="fa fa-arrow-down fa-stack-1x font-critical"></i></span><div>service state is CRITICAL and flapping</div></center>')
        s = self.helper.get_html_state('service', 'CRITICAL', extra='ACKNOWLEDGED', text=True, icon=True)
        print "Result:", s
        self.assert_(s == '<center class="font-critical"><span class="fa-stack" style="opacity: 0.5" title="service state is CRITICAL and acknowledged"><i class="fa fa-circle fa-stack-2x font-critical"></i><i class="fa fa-arrow-down fa-stack-1x fa-inverse"></i></span><div>service state is CRITICAL and acknowledged</div></center>')
        s = self.helper.get_html_state('service', 'CRITICAL', extra='IN_DOWNTIME', text=True, icon=True)
        print "Result:", s
        self.assert_(s == '<center class="font-critical"><span class="fa-stack" style="opacity: 0.5" title="service state is CRITICAL but downtime is scheduled"><i class="fa fa-circle fa-stack-2x font-critical"></i><i class="fa fa-arrow-down fa-stack-1x fa-inverse"></i></span><div>service state is CRITICAL but downtime is scheduled</div></center>')

        # Use label instead of built text ...
        s = self.helper.get_html_state('service', 'OK', text=True, icon=True, label='My own label')
        print "Result:", s
        self.assert_(s == '<center class="font-ok"><span class="fa-stack" title="service state is OK"><i class="fa fa-circle fa-stack-2x font-ok"></i><i class="fa fa-arrow-up fa-stack-1x fa-inverse"></i></span><div>My own label</div></center>')

        # Specify disabled state ...
        s = self.helper.get_html_state('service', 'OK', text=True, icon=True, label='My own label', disabled=True)
        print "Result:", s
        self.assert_(s == '<center class="font-ok"><span class="fa-stack" title="service state is OK"><i class="fa fa-circle fa-stack-2x font-greyed"></i><i class="fa fa-arrow-up fa-stack-1x fa-inverse"></i></span><div>My own label</div></center>')

    def test_07_get_url(self):
        print "---"

        print "Parameters errors:"
        s = self.helper.get_html_url(None, None)
        print "Result:", s
        self.assert_(s == 'n/a')

        s = self.helper.get_html_url('', '')
        print "Result:", s
        self.assert_(s == 'n/a')

        s = self.helper.get_html_url('host', None)
        print "Result:", s
        self.assert_(s == 'n/a')

        s = self.helper.get_html_url('bad_type', 'bad')
        print "Result:", s
        self.assert_(s == '<a href="/bad_type/bad" title="bad">bad</a>')

        s = self.helper.get_html_url('host', 'host1')
        print "Result:", s
        self.assert_(s == '<a href="/host/host1" title="host1">host1</a>')

        s = self.helper.get_html_url('service', 'service1')
        print "Result:", s
        self.assert_(s == '<a href="/service/service1" title="service1">service1</a>')

        s = self.helper.get_html_url('host', 'test', 'My label ...')
        print "Result:", s
        self.assert_(s == '<a href="/host/test" title="test">My label ...</a>')

        s = self.helper.get_html_url('contact', 'bob', 'My label ...')
        print "Result:", s
        self.assert_(s == '<a href="/contact/bob" title="bob">My label ...</a>')

    def test_08_get_id(self):
        print "---"

        print "Parameters errors:"
        s = self.helper.get_html_id(None, None)
        print "Result:", s
        self.assert_(s == 'n/a')

        s = self.helper.get_html_id('', '')
        print "Result:", s
        self.assert_(s == 'n/a')

        s = self.helper.get_html_id('host', None)
        print "Result:", s
        self.assert_(s == 'n/a')

        s = self.helper.get_html_id('bad_type', 'bad')
        print "Result:", s
        self.assert_(s == 'bad_type-bad')

        s = self.helper.get_html_id('host', 'host1')
        print "Result:", s
        self.assert_(s == 'host-host1')

        s = self.helper.get_html_id('service', 'service1')
        print "Result:", s
        self.assert_(s == 'service-service1')

        s = self.helper.get_html_id('host', 'test*/-_+)')
        print "Result:", s
        self.assert_(s == 'host-test-_')

    def test_09_search(self):
        print "---"

        # Initialize backend communication ...
        frontend.configure(alignak_webui.app.config.get('ui.backend', 'http://localhost:5000'))
        print "Frontend: %s", frontend.url_endpoint_root

        # Configure users' management backend
        User.set_backend(frontend)

        # Force authentication ...
        connection = frontend.login('admin', 'admin', force=True)
        assert_true(frontend.authenticated)
        assert_true(frontend.token)

        connection = frontend.connect(username='******')
        assert_true(frontend.authenticated)
        assert_true(frontend.connected)

        ls = self.helper.get_livestate()

        print "Search on element type ..."
        search = self.helper.search_livestate(ls, "type:all")
        print "Result, found %d elements" % len(search)
        search = self.helper.search_livestate(ls, "type:host")
        print "Result, found %d elements" % len(search)
        search = self.helper.search_livestate(ls, "type:service")
        print "Result, found %d elements" % len(search)
        search = self.helper.search_livestate(ls, "host")
        print "Result, found %d elements" % len(search)
        search = self.helper.search_livestate(ls, "service")
        print "Result, found %d elements" % len(search)
        search = self.helper.search_livestate(ls, "type:unknown")
        print "Result, found %d elements" % len(search)

        print "---"
        print "Search on element name and content ... "
        print "found in name ..."
        search = self.helper.search_livestate(ls, "charnay")
        print "Result, found %d elements" % len(search)
        # assert len(search) > 0
        print "found in output ..."
        search = self.helper.search_livestate(ls, "time")
        print "Result, found %d elements" % len(search)
        # assert len(search) > 0
        print "not found ..."
        search = self.helper.search_livestate(ls, "test")
        print "Result, found %d elements" % len(search)

        print "---"
        print "Search on element business impact ... "
        search = self.helper.search_livestate(ls, "bi:0")
        print "Result, found %d elements" % len(search)
        # assert len(search) > 0
        search = self.helper.search_livestate(ls, "bi:=0")
        print "Result, found %d elements" % len(search)
        # assert len(search) > 0
        search = self.helper.search_livestate(ls, "bi:>0")
        print "Result, found %d elements" % len(search)
        # assert len(search) > 0
        search = self.helper.search_livestate(ls, "bi:>=0")
        print "Result, found %d elements" % len(search)
        # assert len(search) > 0
        search = self.helper.search_livestate(ls, "bi:<5")
        print "Result, found %d elements" % len(search)
        # assert len(search) > 0
        search = self.helper.search_livestate(ls, "bi:<=5")
        print "Result, found %d elements" % len(search)
        # assert len(search) > 0
        search = self.helper.search_livestate(ls, "bi:>3")
        print "Result, found %d elements" % len(search)
        # assert len(search) > 0

        print "---"
        print "Search on element state ... "
        search = self.helper.search_livestate(ls, "is:ack")
        print "Result, found %d elements" % len(search)
        search = self.helper.search_livestate(ls, "ack:true")
        print "Result, found %d elements" % len(search)
        search = self.helper.search_livestate(ls, "ack:yes")
        print "Result, found %d elements" % len(search)
        search = self.helper.search_livestate(ls, "ack:1")
        print "Result, found %d elements" % len(search)
        # assert len(search) > 0
        search = self.helper.search_livestate(ls, "isnot:ack")
        print "Result, found %d elements" % len(search)
        search = self.helper.search_livestate(ls, "ack:false")
        print "Result, found %d elements" % len(search)
        search = self.helper.search_livestate(ls, "ack:no")
        print "Result, found %d elements" % len(search)
        search = self.helper.search_livestate(ls, "ack:0")
        print "Result, found %d elements" % len(search)
        # assert len(search) > 0
        search = self.helper.search_livestate(ls, "is:downtime")
        print "Result, found %d elements" % len(search)
        search = self.helper.search_livestate(ls, "downtime:yes")
        print "Result, found %d elements" % len(search)
        search = self.helper.search_livestate(ls, "downtime:true")
        print "Result, found %d elements" % len(search)
        search = self.helper.search_livestate(ls, "downtime:1")
        print "Result, found %d elements" % len(search)
        search = self.helper.search_livestate(ls, "downtime:false")
        print "Result, found %d elements" % len(search)
        search = self.helper.search_livestate(ls, "downtime:no")
        print "Result, found %d elements" % len(search)
        search = self.helper.search_livestate(ls, "downtime:0")
        print "Result, found %d elements" % len(search)
        assert len(search) > 0
        search = self.helper.search_livestate(ls, "isnot:downtime")
        print "Result, found %d elements" % len(search)
        assert len(search) > 0
        search = self.helper.search_livestate(ls, "is:0")
        print "Result, found %d elements" % len(search)
        # assert len(search) > 0
        search = self.helper.search_livestate(ls, "is:1")
        print "Result, found %d elements" % len(search)
        # assert len(search) > 0
        search = self.helper.search_livestate(ls, "is:2")
        print "Result, found %d elements" % len(search)
        # assert len(search) > 0
        search = self.helper.search_livestate(ls, "is:3")
        print "Result, found %d elements" % len(search)
        # assert len(search) > 0
        search = self.helper.search_livestate(ls, "is:up")
        print "Result, found %d elements" % len(search)
        search = self.helper.search_livestate(ls, "up")
        print "Result, found %d elements" % len(search)
        # assert len(search) > 0
        search = self.helper.search_livestate(ls, "is:down")
        print "Result, found %d elements" % len(search)
        search = self.helper.search_livestate(ls, "down")
        print "Result, found %d elements" % len(search)
        # assert len(search) > 0
        search = self.helper.search_livestate(ls, "is:unreachable")
        print "Result, found %d elements" % len(search)
        search = self.helper.search_livestate(ls, "unreachable")
        print "Result, found %d elements" % len(search)
        # assert len(search) > 0
        search = self.helper.search_livestate(ls, "is:ok")
        print "Result, found %d elements" % len(search)
        search = self.helper.search_livestate(ls, "OK")
        print "Result, found %d elements" % len(search)
        # assert len(search) > 0
        search = self.helper.search_livestate(ls, "is:warning")
        print "Result, found %d elements" % len(search)
        search = self.helper.search_livestate(ls, "WARNING")
        print "Result, found %d elements" % len(search)
        # assert len(search) > 0
        search = self.helper.search_livestate(ls, "is:critical")
        print "Result, found %d elements" % len(search)
        search = self.helper.search_livestate(ls, "CRITICAL")
        print "Result, found %d elements" % len(search)
        # assert len(search) > 0
        search = self.helper.search_livestate(ls, "is:unknown")
        print "Result, found %d elements" % len(search)
        search = self.helper.search_livestate(ls, "UNKNOWN")
        print "Result, found %d elements" % len(search)
        # assert len(search) > 0
        search = self.helper.search_livestate(ls, "is:pending")
        print "Result, found %d elements" % len(search)
        search = self.helper.search_livestate(ls, "PENDING")
        print "Result, found %d elements" % len(search)
        # assert len(search) > 0
        search = self.helper.search_livestate(ls, "isnot:up")
        print "Result, found %d elements" % len(search)
        # assert len(search) > 0
        search = self.helper.search_livestate(ls, "isnot:down")
        print "Result, found %d elements" % len(search)
        # assert len(search) > 0
        search = self.helper.search_livestate(ls, "isnot:unreachable")
        print "Result, found %d elements" % len(search)
        # assert len(search) > 0
        search = self.helper.search_livestate(ls, "isnot:ok")
        print "Result, found %d elements" % len(search)
        # assert len(search) > 0
        search = self.helper.search_livestate(ls, "isnot:warning")
        print "Result, found %d elements" % len(search)
        # assert len(search) > 0
        search = self.helper.search_livestate(ls, "isnot:critical")
        print "Result, found %d elements" % len(search)
        # assert len(search) > 0
        search = self.helper.search_livestate(ls, "isnot:unknown")
        print "Result, found %d elements" % len(search)
        # assert len(search) > 0
        search = self.helper.search_livestate(ls, "isnot:pending")
        print "Result, found %d elements" % len(search)
        # assert len(search) > 0

        # Backend disconnection
        frontend.disconnect()

    def test_10_livesynthesis(self):
        print "---"

        # Initialize backend communication ...
        frontend.configure(alignak_webui.app.config.get('ui.backend', 'http://localhost:5000'))
        print "Frontend: %s", frontend.url_endpoint_root

        # Configure users' management backend
        User.set_backend(frontend)

        # Force authentication ...
        connection = frontend.login('admin', 'admin', force=True)
        assert_true(frontend.authenticated)
        assert_true(frontend.token)

        connection = frontend.connect(username='******')
        assert_true(frontend.authenticated)
        assert_true(frontend.connected)

        print "Get live synthesis ..."
        synthesis = self.helper.get_livesynthesis()
        print "Result:", synthesis
        assert_true('hosts_synthesis' in synthesis)
        assert_true('nb_elts' in synthesis['hosts_synthesis'])
        assert_true('services_synthesis' in synthesis)
        assert_true('nb_elts' in synthesis['services_synthesis'])

        print "Get HTML live synthesis ..."
        synthesis = self.helper.get_html_livesynthesis()
        print "Result:", synthesis
        assert 'hosts_states_popover' in synthesis
        assert 'host state is UP' in synthesis['hosts_states_popover']
        assert 'host state is DOWN' in synthesis['hosts_states_popover']
        assert 'host state is UNREACHABLE' in synthesis['hosts_states_popover']
        assert 'hosts_state' in synthesis
        # assert False

        assert 'services_states_popover' in synthesis
        assert 'service state is OK' in synthesis['services_states_popover']
        assert 'service state is WARNING' in synthesis['services_states_popover']
        assert 'service state is CRITICAL' in synthesis['services_states_popover']
        assert 'services_state' in synthesis

        # Backend disconnection
        frontend.disconnect()

    def test_11_livestate(self):
        print "---"

        # Initialize backend communication ...
        frontend.configure(alignak_webui.app.config.get('ui.backend', 'http://localhost:5000'))
        print "Frontend: %s", frontend.url_endpoint_root

        # Configure users' management backend
        User.set_backend(frontend)

        # Force authentication ...
        connection = frontend.login('admin', 'admin', force=True)
        assert_true(frontend.authenticated)
        assert_true(frontend.token)

        connection = frontend.connect(username='******')
        assert_true(frontend.authenticated)
        assert_true(frontend.connected)

        print "Get live state ..."
        print "Livestate_age: ", self.helper.livestate_age
        ls = self.helper.get_livestate()
        print "Livestate_age: ", self.helper.livestate_age
        print "Livestate: ", self.helper.livestate
        assert self.helper.livestate_age
        for item in ls:
            print "Item:", item
            assert_true('type' in item)
            assert_true('id' in item)
            assert_true('bi' in item)
            assert_true('name' in item)
            assert_true('friendly_name' in item)
        for item in self.helper.livestate:
            print "Item:", item
            assert_true('type' in item)
            assert_true('id' in item)
            assert_true('bi' in item)
            assert_true('name' in item)
            assert_true('friendly_name' in item)
        assert len(ls) == len(self.helper.livestate)

        print "Get HTML live state ..."
        print "Current user: "******"Items:", len(html['rows'])

        for bi in [0,1,2,3,4,5]:
            print "Get HTML live state (BI = %d) ..." % bi
            html = self.helper.get_html_livestate(bi=bi)
            assert 'bi' in html
            assert 'rows' in html
            assert 'panel_bi' in html
            print "Items:", len(html['rows']) / 2
            # for row in html['rows']:
                # print "Item:", row

        print "Get HTML live state ... filter"
        html = self.helper.get_html_livestate(search_filter="type:host")
        assert 'bi' in html
        assert 'rows' in html
        assert 'panel_bi' in html
        print "Items:", len(html['rows'])

        for bi in [0,1,2,3,4,5]:
            print "Get HTML live state (BI = %d) ...and filter" % bi
            html = self.helper.get_html_livestate(bi=bi, search_filter="type:host")
            assert 'bi' in html
            assert 'rows' in html
            assert 'panel_bi' in html
            print "Items:", len(html['rows'])

        # Backend disconnection
        frontend.disconnect()
Example #15
0
    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
            })
    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
        })
Example #17
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'))
        }
Example #18
0
    def get_livestate_widget(self,
                             embedded=False,
                             identifier=None,
                             credentials=None):
        # pylint: disable=too-many-locals
        """Get the livestate widget"""
        user = request.environ['beaker.session']['current_user']
        webui = request.app.config['webui']
        datamgr = webui.datamgr

        panels = datamgr.get_user_preferences(user, 'livestate', {})

        ls = Helper.get_html_livestate(datamgr,
                                       panels,
                                       int(request.query.get('bi', -1)),
                                       request.query.get('search', {}),
                                       actions=user.is_power())

        # Widget options
        widget_id = request.params.get('widget_id', '')
        if widget_id == '':
            return self.webui.response_invalid_parameters(
                _('Missing widget identifier'))

        widget_place = request.params.get('widget_place', 'dashboard')
        widget_template = request.params.get('widget_template',
                                             'elements_table_widget')
        widget_icon = request.params.get('widget_icon', 'plug')
        logger.debug("Searching a widget %s for: %s (%s)", widget_id,
                     widget_place, widget_template)

        # Search in the application widgets (all plugins widgets)
        options = {}
        for widget in self.webui.get_widgets_for(widget_place):
            logger.debug("found widget: %s (%s)", widget['name'], widget['id'])
            if widget_id.startswith(widget['id']):
                options = widget['options']
                widget_template = widget['template']
                widget_icon = widget['icon']
                logger.debug("Widget %s found, template: %s, options: %s",
                             widget_id, widget_template, options)
                break
        else:
            logger.warning("Widget identifier not found: %s", widget_id)
            return self.webui.response_invalid_parameters(
                _('Unknown widget identifier'))

        # Search in the saved dashboard widgets
        saved_widget = None
        saved_widgets = datamgr.get_user_preferences(user, 'dashboard_widgets',
                                                     [])
        for widget in saved_widgets:
            if widget_id == widget['id']:
                saved_widget = widget
                logger.info("Saved widget found: %s", saved_widget)
                break

        # Widget freshly created
        tmp_options = []
        if not saved_widget or 'options' not in saved_widget:
            for option in options:
                tmp_options.append("%s=%s" %
                                   (option, options[option]['value']))
            saved_options = '|'.join(tmp_options)
        else:
            saved_options = saved_widget['options']

        tmp_options = []
        logger.info("Saved widget options: %s", saved_options)
        for option in saved_options.split('|'):
            option = option.split('=')
            logger.info("- saved option: %s", option)
            if len(option) > 1:
                if request.params.get(option[0], option[1]) != option[1]:
                    tmp_options.append(
                        "%s=%s" % (option[0], request.params.get(option[0])))
                    options[option[0]]['value'] = request.params.get(option[0])
                else:
                    tmp_options.append("%s=%s" % (option[0], option[1]))
                    options[option[0]]['value'] = option[1]

        new_options = '|'.join(tmp_options)

        if saved_options != new_options:
            logger.info("Widget %s new options: %s", widget_id, new_options)

            # Search for the dashboard widgets
            saved_widgets = datamgr.get_user_preferences(
                user, 'dashboard_widgets', [])
            for widget in saved_widgets:
                if widget_id.startswith(widget['id']):
                    widget['options'] = new_options
                    datamgr.set_user_preferences(user, 'dashboard_widgets',
                                                 saved_widgets)
                    logger.info("Widget new options saved!")
                    break
        saved_options = new_options

        title = request.params.get('title', _('Elements'))

        # Use required template to render the widget
        logger.info("Rendering widget %s", widget_id)
        return template(
            '_widget', {
                'widget_id': widget_id,
                'widget_name': widget_template,
                'widget_place': widget_place,
                'widget_template': widget_template,
                'widget_icon': widget_icon,
                'widget_uri': request.urlparts.path,
                'plugin_parameters': self.plugin_parameters,
                'livestate': ls,
                'options': options,
                'title': title,
                'embedded': embedded,
                'identifier': identifier,
                'credentials': credentials
            })
    def get_realm_members(self, element_id):
        """Get the realm hosts list"""
        datamgr = request.app.datamgr

        realm = datamgr.get_realm(element_id)
        if not realm:
            realm = datamgr.get_realm(search={'max_results': 1, 'where': {'name': element_id}})
            if not realm:
                return self.webui.response_invalid_parameters(_('Element does not exist: %s')
                                                              % element_id)

        # Get elements from the data manager
        search = {
            'where': {'_realm': realm.id},
            'sort': '-business_impact, -ls_state_id, -ls_last_state_changed'
        }
        hosts = datamgr.get_hosts(search=search)
        logger.debug("get_realm_members, search: %s, found %d hosts", search, len(hosts))

        # Get element state configuration
        items_states = ElementState()

        items = []
        items.append({
            'id': -1,
            'type': 'host',
            'tr': """
                <table class="table table-invisible table-condensed">
                  <thead><tr>
                    <th></th>
                    <th>%s</th>
                    <th>%s</th>
                    <th>%s</th>
                    <th>%s</th>
                    <th>%s</th>
                  </tr></thead>

                  <tbody>
                  </tbody>
                </table>
            """ % (
                _("BI"), _("Element"),
                _("Since"), _("Last check"), _("Output")
            )
        })
        for member in hosts:
            logger.debug("Realm member: %s", member)
            cfg_state = items_states.get_icon_state('host', member.status)

            tr = """<tr>
                <td>%s</td>
                <td>%s</td>
                <td>%s</td>
                <td class="hidden-xs">%s</td>
                <td class="hidden-xs">%s</td>
                <td class="hidden-sm hidden-xs">%s: %s</td>
            </tr>""" % (
                member.get_html_state(text=None, title=member.alias),
                Helper.get_html_business_impact(member.business_impact, icon=True, text=False),
                member.get_html_link(),
                Helper.print_duration(member.last_state_changed, duration_only=True, x_elts=2),
                Helper.print_duration(member.last_check, duration_only=True, x_elts=2),
                Helper.print_date(member.last_check),
                member.output
            )
            items.append({
                'id': member.id,
                'type': 'host',
                'name': member.name,
                'alias': member.alias,
                'status': member.status,
                'icon': 'fa fa-%s item_%s' % (cfg_state['icon'], cfg_state['class']),
                'state': member.get_html_state(text=None, title=member.alias),
                'tr': tr
            })

        response.status = 200
        response.content_type = 'application/json'
        return json.dumps(items)
Example #20
0
    def get_realm_members(self, element_id):
        """Get the realm hosts list"""
        datamgr = request.app.datamgr

        realm = datamgr.get_realm(element_id)
        if not realm:
            realm = datamgr.get_realm(search={
                'max_results': 1,
                'where': {
                    'name': element_id
                }
            })
            if not realm:
                return self.webui.response_invalid_parameters(
                    _('Element does not exist: %s') % element_id)

        # Get elements from the data manager
        search = {
            'where': {
                '_realm': realm.id
            },
            'sort': '-business_impact, -ls_state_id, -ls_last_state_changed'
        }
        hosts = datamgr.get_hosts(search=search)
        logger.debug("get_realm_members, search: %s, found %d hosts", search,
                     len(hosts))

        # Get element state configuration
        items_states = ElementState()

        items = []
        items.append({
            'id':
            -1,
            'type':
            'host',
            'tr':
            """
                <table class="table table-invisible table-condensed">
                  <thead><tr>
                    <th></th>
                    <th>%s</th>
                    <th>%s</th>
                    <th>%s</th>
                    <th>%s</th>
                    <th>%s</th>
                  </tr></thead>

                  <tbody>
                  </tbody>
                </table>
            """ %
            (_("BI"), _("Element"), _("Since"), _("Last check"), _("Output"))
        })
        for member in hosts:
            logger.debug("Realm member: %s", member)
            cfg_state = items_states.get_icon_state('host', member.status)

            tr = """<tr>
                <td>%s</td>
                <td>%s</td>
                <td>%s</td>
                <td class="hidden-xs">%s</td>
                <td class="hidden-xs">%s</td>
                <td class="hidden-sm hidden-xs">%s: %s</td>
            </tr>""" % (member.get_html_state(text=None, title=member.alias),
                        Helper.get_html_business_impact(
                            member.business_impact, icon=True,
                            text=False), member.get_html_link(),
                        Helper.print_duration(member.last_state_changed,
                                              duration_only=True,
                                              x_elts=2),
                        Helper.print_duration(
                            member.last_check, duration_only=True, x_elts=2),
                        Helper.print_date(member.last_check), member.output)
            items.append({
                'id':
                member.id,
                'type':
                'host',
                'name':
                member.name,
                'alias':
                member.alias,
                'status':
                member.status,
                'icon':
                'fa fa-%s item_%s' % (cfg_state['icon'], cfg_state['class']),
                'state':
                member.get_html_state(text=None, title=member.alias),
                'tr':
                tr
            })

        response.status = 200
        response.content_type = 'application/json'
        return json.dumps(items)
Example #21
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
        })
    def get_livestate_widget(self, embedded=False, identifier=None, credentials=None):
        # pylint: disable=too-many-locals
        """Get the livestate widget"""
        user = request.environ['beaker.session']['current_user']
        webui = request.app.config['webui']
        datamgr = webui.datamgr

        panels = datamgr.get_user_preferences(user, 'livestate', {})

        ls = Helper.get_html_livestate(datamgr, panels, int(request.query.get('bi', -1)),
                                       request.query.get('search', {}), actions=user.is_power())

        # Widget options
        widget_id = request.params.get('widget_id', '')
        if widget_id == '':
            return self.webui.response_invalid_parameters(_('Missing widget identifier'))

        widget_place = request.params.get('widget_place', 'dashboard')
        widget_template = request.params.get('widget_template', 'elements_table_widget')
        widget_icon = request.params.get('widget_icon', 'plug')
        logger.debug("Searching a widget %s for: %s (%s)",
                     widget_id, widget_place, widget_template)

        # Search in the application widgets (all plugins widgets)
        options = {}
        for widget in self.webui.get_widgets_for(widget_place):
            logger.debug("found widget: %s (%s)", widget['name'], widget['id'])
            if widget_id.startswith(widget['id']):
                options = widget['options']
                widget_template = widget['template']
                widget_icon = widget['icon']
                logger.debug("Widget %s found, template: %s, options: %s",
                             widget_id, widget_template, options)
                break
        else:
            logger.warning("Widget identifier not found: %s", widget_id)
            return self.webui.response_invalid_parameters(_('Unknown widget identifier'))

        # Search in the saved dashboard widgets
        saved_widget = None
        saved_widgets = datamgr.get_user_preferences(user, 'dashboard_widgets', [])
        for widget in saved_widgets:
            if widget_id == widget['id']:
                saved_widget = widget
                logger.info("Saved widget found: %s", saved_widget)
                break

        # Widget freshly created
        tmp_options = []
        if not saved_widget or 'options' not in saved_widget:
            for option in options:
                tmp_options.append("%s=%s" % (option, options[option]['value']))
            saved_options = '|'.join(tmp_options)
        else:
            saved_options = saved_widget['options']

        tmp_options = []
        logger.info("Saved widget options: %s", saved_options)
        for option in saved_options.split('|'):
            option = option.split('=')
            logger.info("- saved option: %s", option)
            if len(option) > 1:
                if request.params.get(option[0], option[1]) != option[1]:
                    tmp_options.append("%s=%s" % (option[0], request.params.get(option[0])))
                    options[option[0]]['value'] = request.params.get(option[0])
                else:
                    tmp_options.append("%s=%s" % (option[0], option[1]))
                    options[option[0]]['value'] = option[1]

        new_options = '|'.join(tmp_options)

        if saved_options != new_options:
            logger.info("Widget %s new options: %s", widget_id, new_options)

            # Search for the dashboard widgets
            saved_widgets = datamgr.get_user_preferences(user, 'dashboard_widgets', [])
            for widget in saved_widgets:
                if widget_id.startswith(widget['id']):
                    widget['options'] = new_options
                    datamgr.set_user_preferences(user, 'dashboard_widgets', saved_widgets)
                    logger.info("Widget new options saved!")
                    break
        saved_options = new_options

        title = request.params.get('title', _('Elements'))

        # Use required template to render the widget
        logger.info("Rendering widget %s", widget_id)
        return template('_widget', {
            'widget_id': widget_id,
            'widget_name': widget_template,
            'widget_place': widget_place,
            'widget_template': widget_template,
            'widget_icon': widget_icon,
            'widget_uri': request.urlparts.path,

            'plugin_parameters': self.plugin_parameters,

            'livestate': ls,

            'options': options,
            'title': title,
            'embedded': embedded,
            'identifier': identifier,
            'credentials': credentials
        })
Example #23
0
    def get_currently(self):  # pylint:disable=no-self-use, too-many-locals
        """Display currently page"""
        user = request.environ['beaker.session']['current_user']
        webui = request.app.config['webui']
        datamgr = webui.datamgr

        # Default states
        hosts_states = ['up', 'down', 'unreachable']
        services_states = [
            'ok', 'warning', 'critical', 'unreachable', 'unknown'
        ]

        # Get the stored panels in user's preferences
        panels = datamgr.get_user_preferences(user, 'panels', None)
        if not panels:
            panels = {
                'panel_hosts': {
                    'collapsed': False
                },
                'panel_services': {
                    'collapsed': False
                },
                'panel_ls_history_hosts': {
                    'collapsed': False
                },
                'panel_ls_history_services': {
                    'collapsed': False
                }
            }

        # Get the stored graphs
        graphs = datamgr.get_user_preferences(user, 'currently_graphs', None)
        if not graphs:
            graphs = {
                'pie_graph_hosts': {
                    'legend': True,
                    'title': True,
                    'states': hosts_states
                },
                'pie_graph_services': {
                    'legend': True,
                    'title': True,
                    'states': services_states
                },
                'line_graph_hosts': {
                    'legend': True,
                    'title': True,
                    'states': hosts_states
                },
                'line_graph_services': {
                    'legend': True,
                    'title': True,
                    'states': services_states
                }
            }

        # Live state global and history
        (livesynthesis, ls_history) = datamgr.get_livesynthesis_history()
        hs = livesynthesis['hosts_synthesis']
        ss = livesynthesis['services_synthesis']
        ls_history = sorted(ls_history,
                            key=lambda x: x['_timestamp'],
                            reverse=False)

        collapsed = False
        if 'panel_hosts' in panels:
            collapsed = panels['panel_hosts']['collapsed']
        p_h = Helper.get_html_hosts_count_panel(
            hs, self.webui.get_url('Hosts table'), collapsed=collapsed)

        collapsed = False
        if 'panel_services' in panels:
            collapsed = panels['panel_services']['collapsed']
        p_s = Helper.get_html_services_count_panel(
            ss, self.webui.get_url('Services table'), collapsed=collapsed)

        collapsed = False
        if 'panel_ls_history_hosts' in panels:
            collapsed = panels['panel_ls_history_hosts']['collapsed']
        lsh = Helper.get_html_hosts_ls_history(hs,
                                               ls_history,
                                               collapsed=collapsed)

        collapsed = False
        if 'panel_ls_history_services' in panels:
            collapsed = panels['panel_ls_history_services']['collapsed']
        ssh = Helper.get_html_services_ls_history(ss,
                                                  ls_history,
                                                  collapsed=collapsed)

        return {
            'panels': panels,
            'panel_hosts': p_h,
            'panel_ls_history_hosts': lsh,
            'panel_services': p_s,
            'panel_ls_history_services': ssh,
            'title': request.query.get('title', _('Keep an eye'))
        }
Example #24
0
    def table_data(self):
        """
        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:
        - 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 searh[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 ...
        # Because of specific datatables parameters name (eg. columns[0] ...)
        # ... some parameters have been json.stringify on client side !
        params = {}
        logger.debug("table request parameters: %s", request.forms)
        for key in request.forms.keys():
            if key == 'columns' or key == 'order':
                params[key] = json.loads(request.forms.get(key))
            elif key == 'search':
                params[key] = json.loads(request.forms.get(key))
            else:
                params[key] = request.forms.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.info(
            "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)

        # Columns searching
        # Individual search parameter
        searched_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']
                )
                column_type = 'string'
                for field in self.table_columns:
                    if field['name'] == column['data']:
                        column_type = field['type']
                        break

                if 'regex' in column['search']:
                    if column['search']['regex']:
                        if column_type == 'integer':
                            searched_columns.append(
                                '{ "%s": { "$regex": .*%s.* } }' % (
                                    column['data'], column['search']['value']
                                )
                            )
                        else:
                            searched_columns.append(
                                '{ "%s": { "$regex": ".*%s.*" } }' % (
                                    column['data'], column['search']['value']
                                )
                            )
                    else:
                        if column_type == 'integer':
                            searched_columns.append(
                                '{ "%s": %s }' % (
                                    column['data'], column['search']['value']
                                )
                            )
                        else:
                            searched_columns.append(
                                '{ "%s": "%s" }' % (
                                    column['data'], column['search']['value']
                                )
                            )

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

        # Columns searching
        # Global search parameter
        # search:{"value":"test","regex":false}
        searched_global = []
        if 'search' in params and 'columns' in params and params['search']:
            if 'value' in params['search'] and params['search']['value']:
                logger.debug(
                    "search requested, value: %s ",
                    params['search']['value']
                )
                for column in params['columns']:
                    if 'searchable' in column and column['searchable']:
                        logger.debug(
                            "search global '%s' for '%s'",
                            column['data'], params['search']['value']
                        )
                        if 'regex' in params['search']:
                            if params['search']['regex']:
                                searched_global.append(
                                    '{ "%s": { "$regex": ".*%s.*" } }' % (
                                        column['data'], params['search']['value']
                                    )
                                )
                            else:
                                searched_global.append(
                                    '{ "%s": "%s" }' % (
                                        column['data'], params['search']['value']
                                    )
                                )

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

        if searched_columns and searched_global:
            parameters['where'] = '{"$and": [ %s, %s ] }' % (
                '{"$and": [' + ','.join(searched_columns) + '] }',
                '{"$or": [' + ','.join(searched_global) + '] }'
            )
        if searched_columns:
            parameters['where'] = '{"$and": [' + ','.join(searched_columns) + '] }'
        if searched_global:
            parameters['where'] = '{"$or": [' + ','.join(searched_global) + '] }'

        # Embed linked resources
        embedded = {}
        for field in self.table_columns:
            if field['type'] == 'objectid' and field['format'] != 'objectid':
                embedded.update({field['name']: 1})
        if embedded:
            parameters['embedded'] = json.dumps(embedded)
            logger.info("backend embedded parameters: %s", parameters['embedded'])

        # Request ALL objects from the backend
        recordsTotal = self.get_total_records()

        # Request objects from the backend ...
        logger.info("backend get parameters: %s", parameters)
        resp = self.backend.get(self.object_type, params=parameters)
        logger.debug("response _meta: %s", resp['_meta'])
        logger.debug("response _links: %s", resp['_links'])
        # logger.debug("response _items: %s", resp['_items'])

        # Total number of filtered records
        recordsFiltered = len(resp['_items'])
        if '_meta' in resp and (searched_columns or searched_global):
            recordsFiltered = int(resp['_meta']['total'])
        recordsFiltered = int(resp['_meta']['total'])

        # Create an object ...
        if resp['_items']:
            bo_object = None
            for k in globals().keys():
                if isinstance(globals()[k], type) and \
                   '_type' in globals()[k].__dict__ and \
                   globals()[k].getType() == self.object_type:
                    bo_object = globals()[k]()
                    logger.debug("created: %s", bo_object)
                    break

            # Change item content ...
            for item in resp['_items']:
                logger.debug("Object: %s", bo_object)
                bo_object._update(item)
                for key in item.keys():
                    for field in self.table_columns:
                        if field['name'] != key:
                            continue
                        # logger.debug("Setting field: %s", field)
                        if field['name'] == 'name':
                            item[key] = "%s %s" % (bo_object.get_html_state(), item[key])
                            break
                        if field['name'] == 'status':
                            item[key] = bo_object.get_html_state()
                            break
                        if field['type'] == 'datetime':
                            item[key] = bo_object.get_date()
                            break
                        if field['type'] == 'boolean':
                            item[key] = Helper.get_on_off(item[key])
                            break
                        if field['type'] == 'objectid' and key in embedded:
                            for k in globals().keys():
                                if isinstance(globals()[k], type) and \
                                   '_type' in globals()[k].__dict__ and \
                                   globals()[k]._type == field['format']:
                                    linked_object = globals()[k](item[key])
                                    logger.debug("created: %s", linked_object)
                                    item[key] = linked_object.get_html_state(
                                        label=linked_object.get_name()
                                    )
                                    break

        # Prepare response
        rsp = {
            # draw is the request number ...
            "draw": int(params.get('draw', '0')),
            "recordsTotal": recordsTotal,
            "recordsFiltered": recordsFiltered,
            "data": resp['_items']
        }
        return json.dumps(rsp)
Example #25
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'))
        }
Example #26
0
# You should have received a copy of the GNU Affero General Public License
# along with (WebUI).  If not, see <http://www.gnu.org/licenses/>.
# import the unit testing module

from __future__ import print_function

import time

import unittest2

from alignak_webui import set_app_config
from alignak_webui.objects.item_timeperiod import TimePeriod
from alignak_webui.utils.helper import Helper
from alignak_webui.utils.settings import Settings

helper = Helper()


def setup_module():
    print("")

    # Get configuration from only one file ...
    print("read configuration")
    cfg = Settings("settings.cfg")
    found_cfg_files = cfg.read('Alignak-WebUI')
    assert found_cfg_files
    set_app_config(cfg)


class TestDate(unittest2.TestCase):
    def test_01_print_date(self):
    def get_map_elements(self, hosts):
        # pylint:disable=no-self-use, too-many-locals
        """Get hosts valid for a map:

        :param hosts: list of hosts to search in
        :return: tuple with a list of positioned hosts and a list of not yet positioned hosts
        """
        user = request.environ['beaker.session']['current_user']
        datamgr = request.app.datamgr

        # Get elements from the data manager
        logger.info("worldmap, searching valid hosts...")

        default_lat = float(self.plugin_parameters['default_latitude'])
        default_lng = float(self.plugin_parameters['default_longitude'])

        positioned_hosts = []
        for host in hosts:
            map_host = {}
            logger.debug("worldmap, found host '%s'", host.name)

            map_host['positioned'] = True
            if 'type' not in host.position or host.position['type'] != 'Point':
                # logger.warning("worldmap, host '%s', invalid position: %s",
                #                host.name, host.position)
                # continue
                logger.warning("worldmap, host '%s' has an invalid position", host.name)
                continue
            else:
                logger.debug("worldmap, host '%s' located: %s", host.name, host.position)

                map_host['lat'] = host['position']['coordinates'][0]
                map_host['lng'] = host['position']['coordinates'][1]

            logger.debug("worldmap, host '%s' position: %s, %s",
                         host.name, map_host['lat'], map_host['lng'])
            if map_host['lat'] == default_lat and map_host['lng'] == default_lng:
                logger.debug("worldmap, host '%s' is not yet positioned", host.name)
                map_host['positioned'] = False

            for attr in ['id', 'name', 'alias', 'business_impact', 'tags',
                         'position', 'tags', 'notes', 'notes_url', 'action_url',
                         'overall_state', 'overall_status', 'state_id', 'state_type',
                         'acknowledged', 'downtimed',
                         'last_check', 'output', 'long_output']:
                map_host[attr] = host[attr]

            host_iw = self.plugin_parameters['host_info_content']
            host_iw = host_iw.replace("\n", '')
            host_iw = host_iw.replace("\r", '')
            host_iw = host_iw.replace("##id##", map_host['id'])
            host_iw = host_iw.replace("##name##", map_host['name'])
            host_iw = host_iw.replace("##state##", map_host['overall_status'])
            host_iw = host_iw.replace("##bi##", str(map_host['business_impact']))
            host_iw = host_iw.replace("##url##", host.get_html_link())
            host_iw = host_iw.replace("##html_bi##",
                                      Helper.get_html_business_impact(host.business_impact,
                                                                      icon=True, text=False))
            host_iw = host_iw.replace("##html_state##",
                                      host.get_html_state(text=None,
                                                          use_status=host.overall_status))
            if user.is_power():
                host_iw = host_iw.replace("##html_actions##", Helper.get_html_commands_buttons(
                    host, _('<span class="fa fa-bolt"></span>')
                ))
            else:
                host_iw = host_iw.replace("##html_actions##", "")

            # Get host services
            # todo: using a projection with selected fields may help to improve more?
            search = {
                'sort': '-_overall_state_id,name',
                'where': {}
            }
            if self.plugin_parameters.get('services_excluded'):
                search['where'].update({'name': {
                    "$regex": "^((?!%s).)*$" % self.plugin_parameters['services_excluded']}})
            if self.plugin_parameters.get('services_included'):
                search['where'].update({'name': {
                    "$regex": self.plugin_parameters['services_included']}})
            if self.plugin_parameters.get('services_overall_state'):
                allowed_states = self.plugin_parameters.get('services_overall_state').split(',')
                allowed_states = [int(value) for value in allowed_states]
                # {'_overall_state_id': {'$in': [0, 3], '$nin': [4]}}
                search['where'].update({'_overall_state_id': {"$in": allowed_states}})
            logger.info("worldmap, search services: %s", search)

            services = datamgr.get_host_services(host, search=search, embedded=False)
            services_iw = ""
            for service in services:
                svc_iw = self.plugin_parameters['service_info_content']
                svc_iw = svc_iw.replace("\n", '')
                svc_iw = svc_iw.replace("\r", '')
                svc_iw = svc_iw.replace("##id##", service['id'])
                svc_iw = svc_iw.replace("##name##", service['name'])
                svc_iw = svc_iw.replace("##state##", service['overall_status'])
                svc_iw = svc_iw.replace("##bi##", str(service['business_impact']))
                svc_iw = svc_iw.replace("##url##", service.get_html_link())
                svc_iw = svc_iw.replace("##html_bi##",
                                        Helper.get_html_business_impact(service.business_impact,
                                                                        icon=True, text=False))
                svc_iw = svc_iw.replace("##html_state##",
                                        service.get_html_state(text=None,
                                                               use_status=service.overall_status))
                if user.is_power():
                    svc_iw = svc_iw.replace("##html_actions##", Helper.get_html_commands_buttons(
                        service, _('<span class="fa fa-bolt"></span>')
                    ))
                else:
                    svc_iw = svc_iw.replace("##html_actions##", "")

                services_iw += svc_iw

            logger.debug("worldmap, host '%s' services: %s", host.name, services)
            map_host.update({'services': services})

            host_iw = host_iw.replace("##services##", services_iw)
            map_host.update({'content': host_iw})

            positioned_hosts.append(map_host)

        return positioned_hosts
Example #28
0
    def get_map_elements(self, hosts):
        # pylint:disable=no-self-use, too-many-locals
        """Get hosts valid for a map:

        :param hosts: list of hosts to search in
        :return: tuple with a list of positioned hosts and a list of not yet positioned hosts
        """
        user = request.environ['beaker.session']['current_user']
        datamgr = request.app.datamgr

        # Get elements from the data manager
        logger.info("worldmap, searching valid hosts...")

        default_lat = float(self.plugin_parameters['default_latitude'])
        default_lng = float(self.plugin_parameters['default_longitude'])

        positioned_hosts = []
        for host in hosts:
            map_host = {}
            logger.debug("worldmap, found host '%s'", host.name)

            map_host['positioned'] = True
            if 'type' not in host.position or host.position['type'] != 'Point':
                # logger.warning("worldmap, host '%s', invalid position: %s",
                #                host.name, host.position)
                # continue
                logger.warning("worldmap, host '%s' has an invalid position",
                               host.name)
                continue
            else:
                logger.debug("worldmap, host '%s' located: %s", host.name,
                             host.position)

                map_host['lat'] = host['position']['coordinates'][0]
                map_host['lng'] = host['position']['coordinates'][1]

            logger.debug("worldmap, host '%s' position: %s, %s", host.name,
                         map_host['lat'], map_host['lng'])
            if map_host['lat'] == default_lat and map_host[
                    'lng'] == default_lng:
                logger.debug("worldmap, host '%s' is not yet positioned",
                             host.name)
                map_host['positioned'] = False

            for attr in [
                    'id', 'name', 'alias', 'business_impact', 'tags',
                    'position', 'tags', 'notes', 'notes_url', 'action_url',
                    'overall_state', 'overall_status', 'state_id',
                    'state_type', 'acknowledged', 'downtimed', 'last_check',
                    'output', 'long_output'
            ]:
                map_host[attr] = host[attr]

            host_iw = self.plugin_parameters['host_info_content']
            host_iw = host_iw.replace("\n", '')
            host_iw = host_iw.replace("\r", '')
            host_iw = host_iw.replace("##id##", map_host['id'])
            host_iw = host_iw.replace("##name##", map_host['name'])
            host_iw = host_iw.replace("##state##", map_host['overall_status'])
            host_iw = host_iw.replace("##bi##",
                                      str(map_host['business_impact']))
            host_iw = host_iw.replace("##url##", host.get_html_link())
            host_iw = host_iw.replace(
                "##html_bi##",
                Helper.get_html_business_impact(host.business_impact,
                                                icon=True,
                                                text=False))
            host_iw = host_iw.replace(
                "##html_state##",
                host.get_html_state(text=None, use_status=host.overall_status))
            if user.is_power():
                host_iw = host_iw.replace(
                    "##html_actions##",
                    Helper.get_html_commands_buttons(
                        host, _('<span class="fa fa-bolt"></span>')))
            else:
                host_iw = host_iw.replace("##html_actions##", "")

            # Get host services
            # todo: using a projection with selected fields may help to improve more?
            search = {'sort': '-_overall_state_id,name', 'where': {}}
            if self.plugin_parameters.get('services_excluded'):
                search['where'].update({
                    'name': {
                        "$regex":
                        "^((?!%s).)*$" %
                        self.plugin_parameters['services_excluded']
                    }
                })
            if self.plugin_parameters.get('services_included'):
                search['where'].update({
                    'name': {
                        "$regex": self.plugin_parameters['services_included']
                    }
                })
            if self.plugin_parameters.get('services_overall_state'):
                allowed_states = self.plugin_parameters.get(
                    'services_overall_state').split(',')
                allowed_states = [int(value) for value in allowed_states]
                # {'_overall_state_id': {'$in': [0, 3], '$nin': [4]}}
                search['where'].update(
                    {'_overall_state_id': {
                        "$in": allowed_states
                    }})
            logger.info("worldmap, search services: %s", search)

            services = datamgr.get_host_services(host,
                                                 search=search,
                                                 embedded=False)
            services_iw = ""
            for service in services:
                svc_iw = self.plugin_parameters['service_info_content']
                svc_iw = svc_iw.replace("\n", '')
                svc_iw = svc_iw.replace("\r", '')
                svc_iw = svc_iw.replace("##id##", service['id'])
                svc_iw = svc_iw.replace("##name##", service['name'])
                svc_iw = svc_iw.replace("##state##", service['overall_status'])
                svc_iw = svc_iw.replace("##bi##",
                                        str(service['business_impact']))
                svc_iw = svc_iw.replace("##url##", service.get_html_link())
                svc_iw = svc_iw.replace(
                    "##html_bi##",
                    Helper.get_html_business_impact(service.business_impact,
                                                    icon=True,
                                                    text=False))
                svc_iw = svc_iw.replace(
                    "##html_state##",
                    service.get_html_state(text=None,
                                           use_status=service.overall_status))
                if user.is_power():
                    svc_iw = svc_iw.replace(
                        "##html_actions##",
                        Helper.get_html_commands_buttons(
                            service, _('<span class="fa fa-bolt"></span>')))
                else:
                    svc_iw = svc_iw.replace("##html_actions##", "")

                services_iw += svc_iw

            logger.debug("worldmap, host '%s' services: %s", host.name,
                         services)
            map_host.update({'services': services})

            host_iw = host_iw.replace("##services##", services_iw)
            map_host.update({'content': host_iw})

            positioned_hosts.append(map_host)

        return positioned_hosts
    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
        })
Example #30
0
    def table_data(self):
        # 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: urel 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",
                    request.params.get('object_type'))

        # Because of specific datatables parameters name (eg. columns[0] ...)
        # ... some parameters have been json.stringify on client side !
        params = {}
        for key in request.params.keys():
            if key == 'columns' or key == 'order' or key == '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.info("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
        searched_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':
                        searched_columns.append({
                            column['data']:
                            column['search']['value'] == 'true'
                        })
                    elif field['type'] == 'integer':
                        searched_columns.append(
                            {column['data']: int(column['search']['value'])})
                    elif field['format'] == 'select':
                        values = column['search']['value'].split(',')
                        if len(values) > 1:
                            searched_columns.append(
                                {column['data']: {
                                     "$in": values
                                 }})
                        else:
                            searched_columns.append(
                                {column['data']: values[0]})
                    # ... the other fields :)
                    else:
                        # Do not care about 'smart' and 'caseInsensitive' boolean parameters ...
                        if column['search']['regex']:
                            searched_columns.append({
                                column['data']: {
                                    "$regex":
                                    ".*" + column['search']['value'] + ".*"
                                }
                            })
                        else:
                            searched_columns.append(
                                {column['data']: column['search']['value']})
                    break

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

        # Global search parameter
        # search:{"value":"test","regex":false}
        searched_global = []
        # pylint: disable=too-many-nested-blocks
        # Will be too complex else ...
        if 'search' in params and 'columns' in params and params['search']:
            if 'value' in params['search'] and params['search']['value']:
                logger.debug("search requested, value: %s ",
                             params['search']['value'])
                for column in params['columns']:
                    if 'searchable' in column and column['searchable']:
                        logger.debug("search global '%s' for '%s'",
                                     column['data'], params['search']['value'])
                        if 'regex' in params['search']:
                            if params['search']['regex']:
                                searched_global.append({
                                    column['data']: {
                                        "$regex":
                                        ".*" + params['search']['value'] + ".*"
                                    }
                                })
                            else:
                                searched_global.append({
                                    column['data']:
                                    params['search']['value']
                                })

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

        if searched_columns and searched_global:
            parameters['where'] = {
                "$and": [{
                    "$and": searched_columns
                }, {
                    "$or": searched_global
                }]
            }
        if searched_columns:
            parameters['where'] = {"$and": searched_columns}
        if searched_global:
            parameters['where'] = {"$or": searched_global}

        # Embed linked resources
        parameters['embedded'] = {}
        for field in self.table_columns:
            if field['type'] == 'objectid' and field['format'] != 'objectid':
                parameters['embedded'].update({field['data']: 1})
        if parameters['embedded']:
            logger.info("backend embedded parameters: %s",
                        parameters['embedded'])

        # Update global table records count, require total count from backend
        self.records_total = self.backend.count(self.object_type)

        # Request objects from the backend ...
        logger.debug("table data get parameters: %s", parameters)
        items = self.backend.get(self.object_type, params=parameters)

        if not items:
            # 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
        ][0]
        bo_object = object_class()

        # Update inner properties
        self.id_property = '_id'
        if hasattr(bo_object.__class__, 'id_property'):
            self.id_property = bo_object.__class__.id_property
        self.name_property = 'name'
        if hasattr(bo_object.__class__, 'name_property'):
            self.name_property = bo_object.__class__.name_property
        self.status_property = 'status'
        if hasattr(bo_object.__class__, 'status_property'):
            self.status_property = bo_object.__class__.status_property

        # Change item content ...
        for item in items:
            bo_object = object_class(item)
            logger.debug("livestate object item: %s", bo_object)

            for key in item.keys():
                for field in self.table_columns:
                    if field['data'] != key:
                        continue

                    if field['data'] == self.name_property:
                        item[key] = bo_object.get_html_link(
                            prefix=request.params.get('links'))

                    if field['data'] == self.status_property:
                        item[key] = bo_object.get_html_state()

                    if field['data'] == "business_impact":
                        item[key] = Helper.get_html_business_impact(
                            bo_object.business_impact)

                    # Specific fields type
                    if field['type'] == 'datetime' or field['format'] == 'date':
                        item[key] = bo_object.get_date(item[key])

                    if field['type'] == 'boolean':
                        item[key] = Helper.get_on_off(item[key])

                    if field['type'] == 'list':
                        item[key] = Helper.get_html_item_list(
                            bo_object.id,
                            key,
                            getattr(bo_object, key),
                            title=field['title'])

                    if field['type'] == 'objectid' and \
                       key in parameters['embedded'] and item[key]:
                        related_object_class = [
                            kc for kc in self.datamgr.known_classes
                            if kc.get_type() == field['format']
                        ][0]
                        linked_object = related_object_class(item[key])
                        item[key] = linked_object.get_html_link(
                            prefix=request.params.get('links'))
                        break

            # Very specific fields...
            if self.responsive:
                item['#'] = ''

        # Total number of filtered records
        self.records_filtered = self.records_total
        if 'where' in parameters and parameters['where'] != {}:
            logger.debug("update filtered records: %s", parameters['where'])
            self.records_filtered = len(items)
        logger.info("filtered records: %d out of total: %d",
                    self.records_filtered, self.records_total)

        # Prepare response
        rsp = {
            # draw is the request number ...
            "draw": int(params.get('draw', '0')),
            "recordsTotal": self.records_total,
            "recordsFiltered": self.records_filtered,
            "data": items
        }
        return json.dumps(rsp)
    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'))
        }