Example #1
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 #2
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()
    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)
    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 #5
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 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 #7
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
Example #8
0
    def table_data(self, plugin_table):
        # Because there are many locals needed :)
        # pylint: disable=too-many-locals
        """Return elements data in json format as of Datatables SSP protocol

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

        Example URL::

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

        Request parameters are Json formatted

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

        - draw, index parameter to be returned in the response

            Pagination:
            - start / length, for pagination

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

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

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

        Response data:
        - draw

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

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

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

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

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

        parameters = {}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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