Ejemplo n.º 1
0
class TestModules(AlignakTest):
    """
    This class contains the tests for the module
    """

    def test_module_loading(self):
        """
        Test arbiter, broker, ... auto-generated modules

        Alignak module loading

        :return:
        """
        self.print_header()
        self.setup_with_file('./cfg/cfg_default.cfg')
        self.assertTrue(self.conf_is_correct)
        self.show_configuration_logs()

        # No arbiter modules created
        modules = [m.module_alias for m in self.arbiter.myself.modules]
        self.assertListEqual(modules, [])

        # The only existing broker module is logs declared in the configuration
        modules = [m.module_alias for m in self.brokers['broker-master'].modules]
        self.assertListEqual(modules, [])

        # No poller module
        modules = [m.module_alias for m in self.pollers['poller-master'].modules]
        self.assertListEqual(modules, [])

        # No receiver module
        modules = [m.module_alias for m in self.receivers['receiver-master'].modules]
        self.assertListEqual(modules, ['web-services'])

        # No reactionner module
        modules = [m.module_alias for m in self.reactionners['reactionner-master'].modules]
        self.assertListEqual(modules, [])

        # No scheduler modules
        modules = [m.module_alias for m in self.schedulers['scheduler-master'].modules]
        self.assertListEqual(modules, [])

    def test_module_manager(self):
        """
        Test if the module manager manages correctly all the modules
        :return:
        """
        self.print_header()
        self.setup_with_file('cfg/cfg_default.cfg')
        self.assertTrue(self.conf_is_correct)

        time_hacker.set_real_time()

        # Create an Alignak module
        mod = Module({
            'module_alias': 'web-services',
            'module_types': 'web-services',
            'python_name': 'alignak_module_ws',
            # Set Arbiter address as empty to not poll the Arbiter else the test will fail!
            'alignak_host': '',
            'alignak_port': 7770,
        })

        # Create the modules manager for a daemon type
        self.modulemanager = ModulesManager('receiver', None)

        # Load and initialize the modules:
        #  - load python module
        #  - get module properties and instances
        self.modulemanager.load_and_init([mod])

        # Loading module logs
        self.assert_any_log_match(re.escape(
            "Importing Python module 'alignak_module_ws' for web-services..."
        ))
        self.assert_any_log_match(re.escape(
            "Module properties: {'daemons': ['receiver'], 'phases': ['running'], "
            "'type': 'web-services', 'external': True}"
        ))
        self.assert_any_log_match(re.escape(
            "Imported 'alignak_module_ws' for web-services"
        ))
        self.assert_any_log_match(re.escape(
            "Loaded Python module 'alignak_module_ws' (web-services)"
        ))
        self.assert_any_log_match(re.escape(
            "Give an instance of alignak_module_ws for alias: web-services"
        ))

        my_module = self.modulemanager.instances[0]

        # Get list of not external modules
        self.assertListEqual([], self.modulemanager.get_internal_instances())
        for phase in ['configuration', 'late_configuration', 'running', 'retention']:
            self.assertListEqual([], self.modulemanager.get_internal_instances(phase))

        # Get list of external modules
        self.assertListEqual([my_module], self.modulemanager.get_external_instances())
        for phase in ['configuration', 'late_configuration', 'retention']:
            self.assertListEqual([], self.modulemanager.get_external_instances(phase))
        for phase in ['running']:
            self.assertListEqual([my_module], self.modulemanager.get_external_instances(phase))

        # Clear logs
        self.clear_logs()

        # Start external modules
        self.modulemanager.start_external_instances()

        # Starting external module logs
        self.assert_log_match("Trying to initialize module: web-services", 0)
        self.assert_log_match("Starting external module web-services", 1)
        self.assert_log_match("Starting external process for module web-services", 2)
        self.assert_log_match("web-services is now started", 3)

        # Check alive
        self.assertIsNotNone(my_module.process)
        self.assertTrue(my_module.process.is_alive())

        # Clear logs
        self.clear_logs()

        # Kill the external module (normal stop is .stop_process)
        my_module.kill()
        time.sleep(0.1)
        self.assert_log_match("Killing external module", 0)
        self.assert_log_match("External module killed", 1)

        # Should be dead (not normally stopped...) but we still know a process for this module!
        self.assertIsNotNone(my_module.process)

        # Nothing special ...
        self.modulemanager.check_alive_instances()
        self.assert_log_match("The external module web-services died unexpectedly!", 2)
        self.assert_log_match("Setting the module web-services to restart", 3)

        # Try to restart the dead modules
        self.modulemanager.try_to_restart_deads()
        self.assert_log_match("Trying to initialize module: web-services", 4)

        # In fact it's too early, so it won't do it
        # The module instance is still dead
        self.assertFalse(my_module.process.is_alive())

        # So we lie, on the restart tries ...
        my_module.last_init_try = -5
        self.modulemanager.check_alive_instances()
        self.modulemanager.try_to_restart_deads()
        self.assert_log_match("Trying to initialize module: web-services", 5)

        # The module instance is now alive again
        self.assertTrue(my_module.process.is_alive())
        self.assert_log_match("I'm stopping module 'web-services'", 6)
        self.assert_log_match("Starting external process for module web-services", 7)
        self.assert_log_match("web-services is now started", 8)

        # There is nothing else to restart in the module manager
        self.assertEqual([], self.modulemanager.to_restart)

        # Clear logs
        self.clear_logs()

        # Now we look for time restart so we kill it again
        my_module.kill()
        time.sleep(0.2)
        self.assertFalse(my_module.process.is_alive())
        self.assert_log_match("Killing external module", 0)
        self.assert_log_match("External module killed", 1)

        # Should be too early
        self.modulemanager.check_alive_instances()
        self.assert_log_match("The external module web-services died unexpectedly!", 2)
        self.assert_log_match("Setting the module web-services to restart", 3)

        self.modulemanager.try_to_restart_deads()
        self.assert_log_match("Trying to initialize module: web-services", 4)

        # In fact it's too early, so it won't do it
        # The module instance is still dead
        self.assertFalse(my_module.process.is_alive())

        # So we lie, on the restart tries ...
        my_module.last_init_try = -5
        self.modulemanager.check_alive_instances()
        self.modulemanager.try_to_restart_deads()
        self.assert_log_match("Trying to initialize module: web-services", 5)

        # The module instance is now alive again
        self.assertTrue(my_module.process.is_alive())
        self.assert_log_match("I'm stopping module 'web-services'", 6)
        self.assert_log_match("Starting external process for module web-services", 7)
        self.assert_log_match("web-services is now started", 8)

        # And we clear all now
        self.modulemanager.stop_all()
        # Stopping module logs

        self.assert_log_match("Request external process to stop for web-services", 9)
        self.assert_log_match(re.escape("I'm stopping module 'web-services' (pid="), 10)
        self.assert_log_match(
            re.escape("'web-services' is still alive after normal kill, I help it to die"), 11
        )
        self.assert_log_match("Killing external module ", 12)
        self.assert_log_match("External module killed", 13)
        self.assert_log_match("External process stopped.", 14)

    def test_module_start_default(self):
        """
        Test the module initialization function, no parameters, using default
        :return:
        """
        self.print_header()
        # Obliged to call to get a self.logger...
        self.setup_with_file('cfg/cfg_default.cfg')
        self.assertTrue(self.conf_is_correct)

        # -----
        # Default initialization
        # -----
        # Clear logs
        self.clear_logs()

        # Create an Alignak module
        mod = Module({
            'module_alias': 'web-services',
            'module_types': 'web-services',
            'python_name': 'alignak_module_ws'
        })

        instance = alignak_module_ws.get_instance(mod)
        self.assertIsInstance(instance, BaseModule)

        self.assert_log_match(
            re.escape("Give an instance of alignak_module_ws for "
                      "alias: web-services"), 0)
        self.assert_log_match(
            re.escape("configuration, Alignak Arbiter: 127.0.0.1:7770"), 1)
        self.assert_log_match(
            re.escape("configuration, listening on: 0.0.0.0:8888"), 2)
        self.assert_log_match(
            re.escape("SSL is not enabled, this is not recommended. "
                      "You should consider enabling SSL!"), 3)

    def test_module_start_parameters(self):
        """
        Test the module initialization function, no parameters, provide parameters
        :return:
        """
        self.print_header()
        # Obliged to call to get a self.logger...
        self.setup_with_file('cfg/cfg_default.cfg')
        self.assertTrue(self.conf_is_correct)

        # -----
        # Provide parameters
        # -----
        # Clear logs
        self.clear_logs()

        # Create an Alignak module
        mod = Module({
            'module_alias': 'web-services',
            'module_types': 'web-services',
            'python_name': 'alignak_module_ws',
            'use_ssl': '1',
            'alignak_host': 'my_host',
            'alignak_port': 80,
            'host': 'me',
            'port': 8080,
        })

        instance = alignak_module_ws.get_instance(mod)
        self.assertIsInstance(instance, BaseModule)

        self.assert_log_match(
            re.escape("Give an instance of alignak_module_ws for "
                      "alias: web-services"), 0)
        self.assert_log_match(
            re.escape("configuration, Alignak Arbiter: my_host:80"), 1)
        self.assert_log_match(
            re.escape("configuration, listening on: me:8080"), 2)
        self.assert_log_match(
            re.escape("Error : the CA certificate /usr/local/etc/alignak/certs/ca.pem is "
                      "missing (ca_cert).Please fix it in your configuration"), 3)
        self.assert_log_match(
            re.escape("SSL is not enabled, this is not recommended. "
                      "You should consider enabling SSL!"), 4)

    def test_module_zzz_run(self):
        """
        Test the module API
        :return:
        """
        self.print_header()
        # Obliged to call to get a self.logger...
        self.setup_with_file('cfg/cfg_default.cfg')
        self.assertTrue(self.conf_is_correct)

        # -----
        # Provide parameters - logger configuration file (exists)
        # -----
        # Clear logs
        self.clear_logs()

        # Create an Alignak module
        mod = Module({
            'module_alias': 'web-services',
            'module_types': 'web-services',
            'python_name': 'alignak_module_ws',
            # Set Arbiter address as empty to not poll the Arbiter else the test will fail!
            'alignak_host': '',
            'alignak_port': 7770,
        })

        # Create the modules manager for a daemon type
        self.modulemanager = ModulesManager('receiver', None)

        # Load an initialize the modules:
        #  - load python module
        #  - get module properties and instances
        self.modulemanager.load_and_init([mod])

        my_module = self.modulemanager.instances[0]

        # Clear logs
        self.clear_logs()

        # Start external modules
        self.modulemanager.start_external_instances()

        # Starting external module logs
        self.assert_log_match("Trying to initialize module: web-services", 0)
        self.assert_log_match("Starting external module web-services", 1)
        self.assert_log_match("Starting external process for module web-services", 2)
        self.assert_log_match("web-services is now started", 3)

        # Check alive
        self.assertIsNotNone(my_module.process)
        self.assertTrue(my_module.process.is_alive())

        time.sleep(1)

        # Get the module API list and request on each endpoint
        response = requests.get('http://127.0.0.1:8888')
        api_list = response.json()
        for endpoint in api_list:
            print("Trying %s" % (endpoint))
            response = requests.get('http://127.0.0.1:8888/' + endpoint)
            print("Response %d: %s" % (response.status_code, response.content))
            self.assertEqual(response.status_code, 200)
            if response.status_code == 200:
                print("Got %s: %s" % (endpoint, response.json()))
            else:
                print("Error %s: %s" % (response.status_code, response.content))

        time.sleep(1)

        # Do not allow GET request on /command
        response = requests.get('http://127.0.0.1:8888/command')
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result['_status'], 'ko')
        self.assertEqual(result['_result'], 'You must only POST on this endpoint.')

        self.assertEqual(my_module.received_commands, 0)

        # You must have parameters when POSTing on /command
        headers = {'Content-Type': 'application/json'}
        data = {}
        response = requests.post('http://127.0.0.1:8888/command', json=data, headers=headers)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result['_status'], 'ko')
        self.assertEqual(result['_result'], 'You must POST parameters on this endpoint.')

        self.assertEqual(my_module.received_commands, 0)

        # Request to execute an external command
        headers = {'Content-Type': 'application/json'}
        data = {
            "command": "Command",
            "element": "test_host",
            "parameters": "abc;1"
        }
        self.assertEqual(my_module.received_commands, 0)
        response = requests.post('http://127.0.0.1:8888/command', json=data, headers=headers)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result['_status'], 'ok')
        # Result is uppercase command, parameters are ordered
        self.assertEqual(result['_result'], 'COMMAND;test_host;abc;1')

        # Not during unit tests ... because module queues are not functional!
        # time.sleep(1)
        # self.assertEqual(my_module.received_commands, 1)

        # Request to execute an external command
        headers = {'Content-Type': 'application/json'}
        data = {
            "command": "command_command",
            "element": "test_host;test_service",
            "parameters": "1;abc;2"
        }
        response = requests.post('http://127.0.0.1:8888/command', json=data, headers=headers)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result['_status'], 'ok')
        # Result is uppercase command, parameters are ordered
        self.assertEqual(result['_result'], 'COMMAND_COMMAND;test_host;test_service;1;abc;2')

        # Request to execute an external command
        headers = {'Content-Type': 'application/json'}
        data = {
            "command": "command_command",
            "element": "test_host/test_service",    # Accept / as an host/service separator
            "parameters": "1;abc;2"
        }
        response = requests.post('http://127.0.0.1:8888/command', json=data, headers=headers)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result['_status'], 'ok')
        # Result is uppercase command, parameters are ordered
        self.assertEqual(result['_result'], 'COMMAND_COMMAND;test_host;test_service;1;abc;2')

        # Request to execute an external command (Alignak modern syntax)
        headers = {'Content-Type': 'application/json'}
        data = {
            "command": "command_command",
            "host": "test_host",
            "service": "test_service",
            "parameters": "1;abc;2"
        }
        response = requests.post('http://127.0.0.1:8888/command', json=data, headers=headers)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result['_status'], 'ok')
        # Result is uppercase command, parameters are ordered
        self.assertEqual(result['_result'], 'COMMAND_COMMAND;test_host;test_service;1;abc;2')

        # Request to execute an external command (Alignak modern syntax)
        headers = {'Content-Type': 'application/json'}
        data = {
            "command": "command_command",
            "host": "test_host",
            "service": "test_service",
            "user": "******",
            "parameters": "1;abc;2"
        }
        response = requests.post('http://127.0.0.1:8888/command', json=data, headers=headers)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result['_status'], 'ok')
        # Result is uppercase command, parameters are ordered
        self.assertEqual(result['_result'],
                         'COMMAND_COMMAND;test_host;test_service;test_user;1;abc;2')

        self.modulemanager.stop_all()
Ejemplo n.º 2
0
class TestModuleNoBackend(AlignakTest):
    """This class contains the tests for the module"""
    @classmethod
    def setUpClass(cls):
        # Simulate an Alignak receiver daemon
        cls.ws_endpoint = 'http://127.0.0.1:7773/ws'
        import cherrypy

        class ReceiverItf(object):
            @cherrypy.expose
            def index(self):
                return "I am the Receiver daemon!"

        from alignak.http.daemon import HTTPDaemon as AlignakDaemon
        http_daemon1 = AlignakDaemon('0.0.0.0', 7773, ReceiverItf(), False,
                                     None, None, None, None, 10,
                                     '/tmp/alignak-cherrypy.log')

        def run_http_server():
            http_daemon1.run()

        import threading
        cls.http_thread1 = threading.Thread(target=run_http_server,
                                            name='http_server_receiver')
        cls.http_thread1.daemon = True
        cls.http_thread1.start()
        print("Thread started")

        cls.modulemanager = None

    def setUp(self):
        super(TestModuleNoBackend, self).setUp()

    def tearDown(self):
        """Delete resources in backend

        :return: None
        """
        super(TestModuleNoBackend, self).tearDown()
        if self.modulemanager:
            self.modulemanager.stop_all()

    def test_module_host_livestate_unauthorized(self):
        """Test the module /host API - host livestate - unauthorized access
        :return:
        """
        # Create an Alignak module
        mod = Module({
            'module_alias': 'web-services',
            'module_types': 'web-services',
            'python_name': 'alignak_module_ws',
            # Alignak backend
            'alignak_backend': '',
            'username': '',
            'password': '',
            # Do not set a timestamp in the built external commands
            'set_timestamp': '0',
            # Do not give feedback data
            'give_feedback': '0',
            'give_result': '1',
            # Set Arbiter address as empty to not poll the Arbiter else the test will fail!
            'alignak_host': '',
            'alignak_port': 7770,
            # Set module to listen on all interfaces
            'host': '0.0.0.0',
            'port': 8888,

            # Allow host/service creation
            'allow_host_creation': '1',
            'allow_service_creation': '1',
            # Force Alignak backend update by the module (default is not force!)
            'alignak_backend_livestate_update': '0',

            # Disable authorization
            'authorization': '0'
        })

        # Create a receiver daemon
        args = {'env_file': '', 'daemon_name': 'receiver-master'}
        self._receiver_daemon = Receiver(**args)

        # Create the modules manager for the daemon
        self.modulemanager = ModulesManager(self._receiver_daemon)

        # Load an initialize the modules:
        #  - load python module
        #  - get module properties and instances
        self.modulemanager.load_and_init([mod])

        my_module = self.modulemanager.instances[0]

        # Clear logs
        self.clear_logs()

        # Start external modules
        self.modulemanager.start_external_instances()

        # Starting external module logs
        self.assert_log_match("Trying to initialize module: web-services", 0)
        self.assert_log_match("Starting external module web-services", 1)
        self.assert_log_match(
            "Starting external process for module web-services", 2)
        self.assert_log_match("web-services is now started", 3)

        # Check alive
        self.assertIsNotNone(my_module.process)
        self.assertTrue(my_module.process.is_alive())

        time.sleep(1)

        session = requests.Session()

        headers = {'Content-Type': 'application/json'}
        params = {'username': '******', 'password': '******'}
        response = session.post(self.ws_endpoint + '/login',
                                json=params,
                                headers=headers)
        assert response.status_code == 200
        resp = response.json()

        # -----
        # Update an host with an host livestate (heartbeat / host is alive): livestate
        # Because there is no backend configured, only an external command is raised
        # to Alignak for the host
        data = {
            "name": "new_host_0",
            "livestate": {
                # No timestamp in the livestate
                "state": "UP",
                "output": "Output...",
                "long_output": "Long output...",
                "perf_data": "'counter'=1",
            }
        }
        self.assertEqual(my_module.received_commands, 0)
        response = session.patch(self.ws_endpoint + '/host',
                                 json=data,
                                 headers=headers)
        print(response)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(
            result, {
                '_status':
                'OK',
                '_result': [
                    'new_host_0 is alive :)',
                    "PROCESS_HOST_CHECK_RESULT;new_host_0;0;Output...|'counter'=1\nLong output...",
                ]
            })
        # No errors - an extrenal command was raised for the host livestate

        # -----
        # Update an host with an host livestate (heartbeat / host is alive): livestate
        # Because there is no backend configured, only an external command is raised
        # to Alignak for the host
        data = {
            "name":
            "new_host_0",
            "livestate": {
                # No timestamp in the livestate
                "state": "UP",
                "output": "Output...",
                "long_output": "Long output...",
                "perf_data": "'counter'=1",
            },
            "services": [{
                "name": "test_svc_0",
                "livestate": {
                    "state": "OK",
                    "output": "Output...",
                    "long_output": "Long output...",
                    "perf_data": "'counter'=1",
                }
            }]
        }
        self.assertEqual(my_module.received_commands, 1)
        response = session.patch(self.ws_endpoint + '/host',
                                 json=data,
                                 headers=headers)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(
            result, {
                '_status':
                'OK',
                '_result': [
                    'new_host_0 is alive :)',
                    "PROCESS_HOST_CHECK_RESULT;new_host_0;0;Output...|'counter'=1\nLong output...",
                    "PROCESS_SERVICE_CHECK_RESULT;new_host_0;test_svc_0;0;Output...|'counter'=1\nLong output..."
                ]
            })
        # No errors - an extrenal command was raised for the host livestate

        self.modulemanager.stop_all()
Ejemplo n.º 3
0
class TestModuleWsHostGet(AlignakTest):
    """This class contains the tests for the module"""
    @classmethod
    def setUpClass(cls):

        # Set test mode for alignak backend
        os.environ['TEST_ALIGNAK_BACKEND'] = '1'
        os.environ[
            'ALIGNAK_BACKEND_MONGO_DBNAME'] = 'alignak-module-ws-backend-test'

        # Delete used mongo DBs
        print("Deleting Alignak backend DB...")
        exit_code = subprocess.call(
            shlex.split('mongo %s --eval "db.dropDatabase()"' %
                        os.environ['ALIGNAK_BACKEND_MONGO_DBNAME']))
        assert exit_code == 0

        fnull = open(os.devnull, 'w')
        cls.p = subprocess.Popen([
            'uwsgi', '--plugin', 'python', '-w', 'alignakbackend:app',
            '--socket', '0.0.0.0:5000', '--protocol=http', '--enable-threads',
            '--pidfile', '/tmp/uwsgi.pid'
        ],
                                 stdout=fnull,
                                 stderr=fnull)
        time.sleep(3)

        endpoint = 'http://127.0.0.1:5000'

        test_dir = os.path.dirname(os.path.realpath(__file__))
        print("Current test directory: %s" % test_dir)

        print("Feeding Alignak backend... %s" % test_dir)
        exit_code = subprocess.call(shlex.split(
            'alignak-backend-import --delete %s/cfg/cfg_default.cfg' %
            test_dir),
                                    stdout=fnull,
                                    stderr=fnull)
        assert exit_code == 0
        print("Fed")

        # Backend authentication
        headers = {'Content-Type': 'application/json'}
        params = {'username': '******', 'password': '******'}
        # Get admin user token (force regenerate)
        response = requests.post(endpoint + '/login',
                                 json=params,
                                 headers=headers)
        resp = response.json()
        cls.token = resp['token']
        cls.auth = requests.auth.HTTPBasicAuth(cls.token, '')

        # Get admin user
        response = requests.get(endpoint + '/user', auth=cls.auth)
        resp = response.json()
        cls.user_admin = resp['_items'][0]

        # Get realms
        response = requests.get(endpoint + '/realm', auth=cls.auth)
        resp = response.json()
        cls.realmAll_id = resp['_items'][0]['_id']

        # Add a user
        data = {
            'name':
            'test',
            'password':
            '******',
            'back_role_super_admin':
            False,
            'host_notification_period':
            cls.user_admin['host_notification_period'],
            'service_notification_period':
            cls.user_admin['service_notification_period'],
            '_realm':
            cls.realmAll_id
        }
        response = requests.post(endpoint + '/user',
                                 json=data,
                                 headers=headers,
                                 auth=cls.auth)
        resp = response.json()
        print("Created a new user: %s" % resp)

        # Get new user restrict role
        params = {'where': json.dumps({'user': resp['_id']})}
        response = requests.get(endpoint + '/userrestrictrole',
                                params=params,
                                auth=cls.auth)
        resp = response.json()

        # Update user's rights - set full CRUD rights
        headers = {
            'Content-Type': 'application/json',
            'If-Match': resp['_items'][0]['_etag']
        }
        data = {'crud': ['create', 'read', 'update', 'delete', 'custom']}
        resp = requests.patch(endpoint + '/userrestrictrole/' +
                              resp['_items'][0]['_id'],
                              json=data,
                              headers=headers,
                              auth=cls.auth)
        resp = resp.json()
        assert resp['_status'] == 'OK'

    @classmethod
    def tearDownClass(cls):
        cls.p.kill()

    def test_module_zzz_host_get(self):
        """Test the module /host API - host creation and get information
        :return:
        """
        self.print_header()
        # Obliged to call to get a self.logger...
        self.setup_with_file('cfg/cfg_default.cfg')
        self.assertTrue(self.conf_is_correct)

        # -----
        # Provide parameters - logger configuration file (exists)
        # -----
        # Clear logs
        self.clear_logs()

        # Create an Alignak module
        mod = Module({
            'module_alias': 'web-services',
            'module_types': 'web-services',
            'python_name': 'alignak_module_ws',
            # Alignak backend
            'alignak_backend': 'http://127.0.0.1:5000',
            'username': '******',
            'password': '******',
            # Do not set a timestamp in the built external commands
            'set_timestamp': '0',
            'give_result': '1',
            'give_feedback': '1',
            # Set Arbiter address as empty to not poll the Arbiter else the test will fail!
            'alignak_host': '',
            'alignak_port': 7770,
            # Allow host/service creation
            'allow_host_creation': '1',
            'allow_service_creation': '1',
            # Errors for unknown host/service
            'ignore_unknown_host': '0',
            'ignore_unknown_service': '0',
        })

        # Create the modules manager for a daemon type
        self.modulemanager = ModulesManager('receiver', None)

        # Load an initialize the modules:
        #  - load python module
        #  - get module properties and instances
        self.modulemanager.load_and_init([mod])

        my_module = self.modulemanager.instances[0]

        # Clear logs
        self.clear_logs()

        # Start external modules
        self.modulemanager.start_external_instances()

        # Starting external module logs
        self.assert_log_match("Trying to initialize module: web-services", 0)
        self.assert_log_match("Starting external module web-services", 1)
        self.assert_log_match(
            "Starting external process for module web-services", 2)
        self.assert_log_match("web-services is now started", 3)

        # Check alive
        self.assertIsNotNone(my_module.process)
        self.assertTrue(my_module.process.is_alive())

        time.sleep(1)

        # Do not allow GET request on /host - not yet authorized!
        response = requests.get('http://127.0.0.1:8888/host')
        self.assertEqual(response.status_code, 401)

        session = requests.Session()

        # Login with username/password (real backend login)
        headers = {'Content-Type': 'application/json'}
        params = {'username': '******', 'password': '******'}
        response = session.post('http://127.0.0.1:8888/login',
                                json=params,
                                headers=headers)
        assert response.status_code == 200
        resp = response.json()

        # -----
        # Get a non-existing host - 1st: use parameters in the request
        response = session.get('http://127.0.0.1:8888/host',
                               auth=self.auth,
                               params={'name': 'new_host_2'})
        result = response.json()
        self.assertEqual(
            result, {
                u'_status': u'ERR',
                u'_result': [],
                u'_issues': ["Requested host 'new_host_2' does not exist"]
            })

        # Get a non-existing host - 2nd: use host name in the URI
        response = session.get('http://127.0.0.1:8888/host/new_host_2',
                               auth=self.auth)
        result = response.json()
        self.assertEqual(
            result, {
                u'_status': u'ERR',
                u'_result': [],
                u'_issues': ["Requested host 'new_host_2' does not exist"]
            })

        # -----
        # Request to create an host - no provided data (default)
        headers = {'Content-Type': 'application/json'}
        data = {
            "name": "new_host_0",
        }
        self.assertEqual(my_module.received_commands, 0)
        response = session.patch('http://127.0.0.1:8888/host',
                                 json=data,
                                 headers=headers)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(
            result, {
                u'_status':
                u'OK',
                u'_result': [
                    u'new_host_0 is alive :)',
                    u"Requested host 'new_host_0' does not exist.",
                    u"Requested host 'new_host_0' created."
                ],
                u'_feedback': {
                    u'name': u'new_host_0'
                }
            })
        # Host created with default check_command and in default user realm

        # -----
        # Get new host to confirm creation - 1st: use parameters in the request
        response = session.get('http://127.0.0.1:8888/host',
                               auth=self.auth,
                               params={'name': 'new_host_0'})
        result = response.json()
        self.assertEqual(result['_status'], 'OK')
        self.assertIsNot(result['_result'], {})
        self.assertEqual(result['_result'][0]['name'], 'new_host_0')

        # Get new host to confirm creation - 2nd: use host name in the URI
        response = session.get('http://127.0.0.1:8888/host/new_host_0',
                               auth=self.auth)
        result = response.json()
        from pprint import pprint
        pprint(result['_result'])
        # [{u'2d_coords': u'',
        # u'3d_coords': u'',
        # u'_created': u'Thu, 01 Jun 2017 10:58:30 GMT',
        # u'_etag': u'691c3f4a7cc8996c1d047932421759c020d00857',
        # u'_id': u'592ff35606fd4b7eec395625',
        # u'_is_template': False,
        # u'_links': {u'self': {u'href': u'host/592ff35606fd4b7eec395625',
        #                       u'title': u'Host'}},
        # u'_overall_state_id': 3,
        # u'_realm': {u'_all_children': [],
        #             u'_children': [],
        #             u'_created': u'Thu, 01 Jun 2017 10:58:24 GMT',
        #             u'_etag': u'26b3830c017b4fca8553365246f21267aece46a7',
        #             u'_id': u'592ff35006fd4b7eec3955eb',
        #             u'_level': 0,
        #             u'_parent': None,
        #             u'_tree_parents': [],
        #             u'_updated': u'Thu, 01 Jun 2017 10:58:27 GMT',
        #             u'alias': u'',
        #             u'default': True,
        #             u'definition_order': 100,
        #             u'global_critical_threshold': 5,
        #             u'global_warning_threshold': 3,
        #             u'hosts_critical_threshold': 5,
        #             u'hosts_warning_threshold': 3,
        #             u'imported_from': u'unknown',
        #             u'name': u'All',
        #             u'notes': u'',
        #             u'services_critical_threshold': 5,
        #             u'services_warning_threshold': 3},
        # u'_sub_realm': True,
        # u'_template_fields': {},
        # u'_templates': [],
        # u'_templates_with_services': True,
        # u'_updated': u'Thu, 01 Jun 2017 10:58:30 GMT',
        # u'action_url': u'',
        # u'active_checks_enabled': True,
        # u'address': u'',
        # u'address6': u'',
        # u'alias': u'',
        # u'business_impact': 2,
        # u'business_impact_modulations': [],
        # u'business_rule_downtime_as_ack': False,
        # u'business_rule_host_notification_options': [u'd', u'u', u'r', u'f', u's'],
        # u'business_rule_output_template': u'',
        # u'business_rule_service_notification_options': [u'w',
        #                                                 u'u',
        #                                                 u'c',
        #                                                 u'r',
        #                                                 u'f',
        #                                                 u's'],
        # u'business_rule_smart_notifications': False,
        # u'check_command': {u'_created': u'Thu, 01 Jun 2017 10:58:24 GMT',
        #                    u'_etag': u'356d02479ca7dbebe85e22b9b43e95dc9d5d037c',
        #                    u'_id': u'592ff35006fd4b7eec3955f1',
        #                    u'_realm': u'592ff35006fd4b7eec3955eb',
        #                    u'_sub_realm': True,
        #                    u'_updated': u'Thu, 01 Jun 2017 10:58:24 GMT',
        #                    u'alias': u'Host/service is always UP/OK',
        #                    u'command_line': u'_internal_host_up',
        #                    u'definition_order': 100,
        #                    u'enable_environment_macros': False,
        #                    u'imported_from': u'unknown',
        #                    u'module_type': u'fork',
        #                    u'name': u'_internal_host_up',
        #                    u'notes': u'',
        #                    u'poller_tag': u'',
        #                    u'reactionner_tag': u'',
        #                    u'timeout': -1},
        # u'check_command_args': u'',
        # u'check_freshness': False,
        # u'check_interval': 5,
        # u'checkmodulations': [],
        # u'custom_views': [],
        # u'customs': {},
        # u'definition_order': 100,
        # u'display_name': u'',
        # u'escalations': [],
        # u'event_handler': None,
        # u'event_handler_args': u'',
        # u'event_handler_enabled': False,
        # u'failure_prediction_enabled': False,
        # u'first_notification_delay': 0,
        # u'flap_detection_enabled': True,
        # u'flap_detection_options': [u'o', u'd', u'x'],
        # u'freshness_state': u'x',
        # u'freshness_threshold': 0,
        # u'high_flap_threshold': 50,
        # u'icon_image': u'',
        # u'icon_image_alt': u'',
        # u'icon_set': u'',
        # u'imported_from': u'unknown',
        # u'initial_state': u'x',
        # u'labels': [],
        # u'location': {u'coordinates': [48.858293, 2.294601], u'type': u'Point'},
        # u'low_flap_threshold': 25,
        # u'ls_acknowledged': False,
        # u'ls_acknowledgement_type': 1,
        # u'ls_attempt': 0,
        # u'ls_current_attempt': 0,
        # u'ls_downtimed': False,
        # u'ls_execution_time': 0.0,
        # u'ls_grafana': False,
        # u'ls_grafana_panelid': 0,
        # u'ls_impact': False,
        # u'ls_last_check': 0,
        # u'ls_last_hard_state_changed': 0,
        # u'ls_last_notification': 0,
        # u'ls_last_state': u'OK',
        # u'ls_last_state_changed': 0,
        # u'ls_last_state_type': u'HARD',
        # u'ls_last_time_down': 0,
        # u'ls_last_time_unknown': 0,
        # u'ls_last_time_unreachable': 0,
        # u'ls_last_time_up': 0,
        # u'ls_latency': 0.0,
        # u'ls_long_output': u'',
        # u'ls_max_attempts': 0,
        # u'ls_next_check': 0,
        # u'ls_output': u'',
        # u'ls_passive_check': False,
        # u'ls_perf_data': u'',
        # u'ls_state': u'UNREACHABLE',
        # u'ls_state_id': 3,
        # u'ls_state_type': u'HARD',
        # u'macromodulations': [],
        # u'max_check_attempts': 1,
        # u'name': u'new_host_0',
        # u'notes': u'',
        # u'notes_url': u'',
        # u'notification_interval': 60,
        # u'notification_options': [u'd', u'x', u'r', u'f', u's'],
        # u'notifications_enabled': True,
        # u'obsess_over_host': False,
        # u'parents': [],
        # u'passive_checks_enabled': True,
        # u'poller_tag': u'',
        # u'process_perf_data': True,
        # u'reactionner_tag': u'',
        # u'resultmodulations': [],
        # u'retry_interval': 0,
        # u'service_excludes': [],
        # u'service_includes': [],
        # u'service_overrides': [],
        # u'snapshot_criteria': [u'd', u'x'],
        # u'snapshot_enabled': False,
        # u'snapshot_interval': 5,
        # u'stalking_options': [],
        # u'statusmap_image': u'',
        # u'tags': [],
        # u'time_to_orphanage': 300,
        # u'trending_policies': [],
        # u'trigger_broker_raise_enabled': False,
        # u'trigger_name': u'',
        # u'usergroups': [],
        # u'users': [],
        # u'vrml_image': u''}]
        #
        self.assertEqual(result['_status'], 'OK')
        self.assertIsNot(result['_result'], {})
        self.assertEqual(result['_result'][0]['name'], 'new_host_0')

        # -----
        # Logout
        response = session.get('http://127.0.0.1:8888/logout')
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result['_status'], 'OK')
        self.assertEqual(result['_result'], 'Logged out')

        self.modulemanager.stop_all()
Ejemplo n.º 4
0
class TestModules(AlignakTest):
    """
    This class contains the tests for the modules
    """
    def setUp(self):
        super(TestModules, self).setUp()
        self.set_unit_tests_logger_level('INFO')

    def test_module_loading(self):
        """ Test arbiter, broker, ... detecting configured modules

        :return:
        """
        self.setup_with_file('cfg/cfg_default_with_modules.cfg',
                             'cfg/default_with_modules/alignak.ini')
        assert self.conf_is_correct
        self.show_configuration_logs()
        self.show_logs()

        # arbiter modules
        modules = [m.module_alias for m in self._arbiter.link_to_myself.modules]
        assert modules == ['Example']
        modules = [m.name for m in self._arbiter.link_to_myself.modules]
        assert modules == ['Example']

        # broker modules
        modules = [m.module_alias for m in self._broker_daemon.modules]
        assert modules == ['Example']
        modules = [m.name for m in self._broker_daemon.modules]
        assert modules == ['Example']

        # # The only existing poller module is Example declared in the configuration
        # modules = [m.module_alias for m in self.pollers['poller-master'].modules]
        # assert modules == ['Example']
        #
        # # The only existing receiver module is Example declared in the configuration
        # modules = [m.module_alias for m in self.receivers['receiver-master'].modules]
        # assert modules == ['Example']
        #
        # # The only existing reactionner module is Example declared in the configuration
        # modules = [m.module_alias for m in self.reactionners['reactionner-master'].modules]
        # assert modules == ['Example']

        # No scheduler modules created
        modules = [m.module_alias for m in self._scheduler_daemon.modules]
        assert modules == ['Example']
        modules = [m.name for m in self._scheduler_daemon.modules]
        assert modules == ['Example']

        self.show_logs()

        # Loading module logs
        self.assert_any_log_match(re.escape(
            u"Importing Python module 'alignak_module_example' for Example..."
        ))
        self.assert_any_log_match(re.escape(
            u"Imported 'alignak_module_example' for Example"
        ))
        self.assert_any_log_match(re.escape(
            u"Give an instance of alignak_module_example for alias: Example"
        ))
        self.assert_any_log_match(re.escape(
            u"I correctly loaded my modules: [Example]"
        ))

    def test_arbiter_configuration_module(self):
        """ Test arbiter configuration loading

        :return:
        """
        self.setup_with_file('./cfg/modules/arbiter_modules.cfg')
        assert self.conf_is_correct
        self.show_configuration_logs()
        self.show_logs()

        # The arbiter module is 'backend_arbiter' declared in the configuration
        modules = [m.module_alias for m in self._arbiter.link_to_myself.modules]
        assert modules == ['Example']

    def test_module_on_module(self):
        """ No module configuration for modules

        Check that the feature is detected as disabled
        :return:
        """
        self.setup_with_file('cfg/modules/alignak_module_with_submodules.cfg')
        assert self.conf_is_correct
        self.show_configuration_logs()

        # arbiter modules
        modules = [m.module_alias for m in self._arbiter.link_to_myself.modules]
        assert modules == ['Example']
        modules = [m.name for m in self._arbiter.link_to_myself.modules]
        assert modules == ['Example']

        # broker modules
        modules = [m.module_alias for m in self._broker_daemon.modules]
        assert modules == ['Example']
        modules = [m.name for m in self._broker_daemon.modules]
        assert modules == ['Example']

        # # The only existing poller module is Example declared in the configuration
        # modules = [m.module_alias for m in self.pollers['poller-master'].modules]
        # assert modules == ['Example']
        #
        # # The only existing receiver module is Example declared in the configuration
        # modules = [m.module_alias for m in self.receivers['receiver-master'].modules]
        # assert modules == ['Example']
        #
        # # The only existing reactionner module is Example declared in the configuration
        # modules = [m.module_alias for m in self.reactionners['reactionner-master'].modules]
        # assert modules == ['Example']

        # No scheduler modules created
        modules = [m.module_alias for m in self._scheduler_daemon.modules]
        assert modules == ['Example', 'inner-retention']
        modules = [m.name for m in self._scheduler_daemon.modules]
        assert modules == ['Example', 'inner-retention']

    def test_modulemanager_1(self):
        """ Module manager manages its modules - old form

        Test if the module manager manages correctly all the modules
        :return:
        """
        self.setup_with_file('cfg/cfg_default_with_modules.cfg',
                             'cfg/default_with_modules/alignak.ini')
        assert self.conf_is_correct

        # Create an Alignak module
        mod = Module({
            'module_alias': 'mod-example',
            'module_types': 'example',
            'python_name': 'alignak_module_example'
        })
        self.run_modulemanager(mod)

    def test_modulemanager_2(self):
        """ Module manager manages its modules - new form

        Test if the module manager manages correctly all the modules
        :return:
        """
        self.setup_with_file('cfg/cfg_default_with_modules.cfg',
                             'cfg/default_with_modules/alignak.ini')
        assert self.conf_is_correct

        # Create an Alignak module
        mod = Module({
            'name': 'mod-example',
            'type': 'example',
            'python_name': 'alignak_module_example'
        })
        self.run_modulemanager(mod)

    def run_modulemanager(self, mod):
        # Force the daemon SyncManager to None for unit tests!
        self._broker_daemon.sync_manager = None

        # Create the modules manager for a daemon type
        self.modules_manager = ModulesManager(self._broker_daemon)

        # Load an initialize the modules:
        #  - load python module
        #  - get module properties and instances
        self.modules_manager.load_and_init([mod])

        # Loading module logs
        self.assert_any_log_match(re.escape(
            "Importing Python module 'alignak_module_example' for mod-example..."
        ))
        self.assert_any_log_match(re.escape(
            "Imported 'alignak_module_example' for mod-example"
        ))
        self.assert_any_log_match(re.escape(
            "Give an instance of alignak_module_example for alias: mod-example"
        ))

        self.clear_logs()

        my_module = self.modules_manager.instances[0]
        assert my_module.is_external

        # Get list of not external modules
        assert [] == self.modules_manager.get_internal_instances()
        for phase in ['configuration', 'late_configuration', 'running', 'retention']:
            assert [] == self.modules_manager.get_internal_instances(phase)

        # Get list of external modules
        assert [my_module] == self.modules_manager.get_external_instances()
        for phase in ['configuration', 'late_configuration', 'running', 'retention']:
            assert [my_module] == self.modules_manager.get_external_instances(phase)

        # Start external modules
        self.modules_manager.start_external_instances()

        self.show_logs()

        # Starting external module logs
        idx = 0
        self.assert_log_match(re.escape(
            "Trying to initialize module: mod-example"
        ), idx)
        idx += 1
        self.assert_log_match(re.escape(
            "Test - Example in init"
        ), idx)
        idx += 1
        self.assert_log_match(re.escape(
            "Initialization of the example module"
        ), idx)
        idx += 1
        self.assert_log_match(re.escape(
            "Module mod-example is initialized"
        ), idx)
        idx += 1
        self.assert_log_match(re.escape(
            "Starting external module mod-example"
        ), idx)
        idx += 1
        self.assert_log_match(re.escape(
            "Starting external process for module mod-example"
        ), idx)
        idx += 1
        self.assert_log_match(re.escape(
            "mod-example is now started (pid="
        ), idx)
        idx += 1
        self.assert_log_count(7)

        # Check alive
        assert my_module.process is not None
        assert my_module.process.is_alive()

        self.clear_logs()
        # Check the alive module instances...
        self.modules_manager.check_alive_instances()
        # Try to restart the dead modules, if any
        self.modules_manager.try_to_restart_deads()
        self.assert_log_count(0)

        # Kill the external module (normal stop is .stop_process)
        self.clear_logs()
        my_module.kill()
        idx = 0
        self.assert_log_match(re.escape(
            "Killing external module "
        ), idx)
        idx += 1
        self.show_logs()

        # self.assert_log_match(re.escape(
        #     "mod-example is still living "
        # ), idx)
        # idx += 1
        # Specific case because sometimes the module is not killed within the expected 10s time
        normal_kill = True
        logger_ = logging.getLogger(ALIGNAK_LOGGER_NAME)
        for handler in logger_.handlers:
            if not isinstance(handler, CollectorHandler):
                continue
            regex = re.compile('mod-example is still living')

            log_num = 0
            found = False
            for log in handler.collector:
                if idx == log_num:
                    if regex.search(log):
                        idx += 1
                        normal_kill = False
                        break
                log_num += 1
            break

        self.assert_log_match(re.escape(
            "External module killed"
        ), idx)
        idx += 1
        self.assert_log_count(idx)

        # The module is dead (not normally stopped...) so this module inner
        # process reference is not None!
        assert my_module.process is not None

        # Check the alive module instances...
        self.clear_logs()
        idx = 0
        self.modules_manager.check_alive_instances()
        self.show_logs()
        self.assert_log_match(re.escape(
            "The external module mod-example died unexpectedly!"
        ), idx)
        idx += 1
        self.assert_log_match(re.escape(
            "Setting the module mod-example to restart"
        ), idx)
        self.assert_log_count(2)
        idx += 1

        if normal_kill:
            # Try to restart the dead modules, if any
            # Indeed, it's too early, so it won't do it
            self.clear_logs()
            idx = 0
            print("try init: %d" % my_module.init_try)
            self.modules_manager.try_to_restart_deads()
            self.show_logs()

            self.assert_log_match(re.escape(
                "Trying to restart module: mod-example"
            ), idx)
            idx += 1
            self.assert_log_match(re.escape(
                "Too early to retry initialization, retry period is %d seconds" % MODULE_INIT_PERIOD
            ), idx)
            idx += 1
            self.assert_log_count(2)

            # Here the module instance is still dead
            assert not my_module.process.is_alive()

            # Wait for a minimum delay
            time.sleep(MODULE_INIT_PERIOD + 1)

        # my_module.last_init_try = -5
        self.clear_logs()
        self.modules_manager.check_alive_instances()
        self.show_logs()
        self.assert_log_count(0)

        # Try to restart the dead modules, if any
        # Now it is time...
        self.clear_logs()
        idx = 0
        self.modules_manager.try_to_restart_deads()
        self.show_logs()
        self.assert_log_match(re.escape(
            "Trying to restart module: mod-example"
        ), idx)
        idx += 1
        self.assert_log_match(re.escape(
            "Trying to initialize module: mod-example"
        ), idx)
        idx += 1
        self.assert_log_match(re.escape(
            "Test - Example in init"
        ), idx)
        idx += 1
        self.assert_log_match(re.escape(
            "Initialization of the example module"
        ), idx)
        idx += 1
        self.assert_log_match(re.escape(
            "Module mod-example is initialized"
        ), idx)
        idx += 1
        self.assert_log_match(re.escape(
            "Restarting mod-example..."
        ), idx)
        idx += 1
        self.assert_log_match(re.escape(
            "Starting external process for module mod-example"
        ), idx)
        idx += 1
        self.assert_log_match(re.escape(
            "mod-example is now started (pid="
        ), idx)
        idx += 1
        self.assert_log_count(8)

        # Here the module instance should be alive again
        assert my_module.process.is_alive()

        # No more module to restart...
        assert [] == self.modules_manager.to_restart

        # And we clear all now
        self.clear_logs()
        idx = 0
        self.modules_manager.stop_all()
        self.show_logs()
        self.assert_log_match(re.escape(
            "Shutting down modules..."
        ), idx)
        idx += 1
        self.assert_log_match(re.escape(
            "Request external process to stop for mod-example"
        ), idx)
        idx += 1
        self.assert_log_match(re.escape(
            "I'm stopping module 'mod-example'"
        ), idx)
        idx += 1
        self.assert_log_match(re.escape(
            "Killing external module "
        ), idx)
        idx += 1

        # Specific case because sometimes the module is not killed within the expected 10s time
        logger_ = logging.getLogger(ALIGNAK_LOGGER_NAME)
        for handler in logger_.handlers:
            if not isinstance(handler, CollectorHandler):
                continue
            regex = re.compile('mod-example is still living')

            log_num = 0
            found = False
            for log in handler.collector:
                if idx == log_num:
                    if regex.search(log):
                        idx += 1
                        break
                log_num += 1
            break

        self.assert_log_match(re.escape(
            "External module killed"
        ), idx)
        idx += 1
        self.assert_log_match(re.escape(
            "External process stopped."
        ), idx)
        idx += 1
        # self.assert_log_count(6)

    def test_modulemanager_several_modules(self):
        """ Module manager manages its modules

        Test if the module manager manages correctly all the modules

        Configured with several modules
        :return:
        """
        self.setup_with_file('cfg/cfg_default_with_modules.cfg',
                             'cfg/default_with_modules/alignak.ini')
        assert self.conf_is_correct

        # for mod in self._arbiter.conf.modules:
        #     print (mod.__dict__)

        # Create an Alignak module
        mod = Module({
            'module_alias': 'mod-example',
            'module_types': 'example',
            'python_name': 'alignak_module_example',
            'option1': 'foo',
            'option2': 'bar',
            'option3': 1
        })
        mod2 = Module({
            'module_alias': 'mod-example-2',
            'module_types': 'example',
            'python_name': 'alignak_module_example',
            'option1': 'faa',
            'option2': 'bor',
            'option3': 1
        })

        # Force the daemon SyncManager to None for unit tests!
        self._broker_daemon.sync_manager = None
        # Create the modules manager for a daemon type
        self.modules_manager = ModulesManager(self._broker_daemon)
        print("Modules: %s" % self._broker_daemon.modules)

        # Load an initialize the modules:
        #  - load python module
        #  - get module properties and instances
        assert self.modules_manager.load_and_init([mod, mod2])
        print("I correctly loaded my modules: [%s]" % ','.join([inst.name for inst in
                                                                self.modules_manager.instances]))
        self.show_logs()

        self.assert_any_log_match(re.escape(
            "Importing Python module 'alignak_module_example' for mod-example..."
        ))
        self.assert_any_log_match(re.escape(
            "Imported 'alignak_module_example' for mod-example"
        ))
        self.assert_any_log_match(re.escape(
            "Loaded Python module 'alignak_module_example' (mod-example)"
        ))
        self.assert_any_log_match(re.escape(
            "Importing Python module 'alignak_module_example' for mod-example-2..."
        ))
        self.assert_any_log_match(re.escape(
            "Imported 'alignak_module_example' for mod-example-2"
        ))
        self.assert_any_log_match(re.escape(
            "Loaded Python module 'alignak_module_example' (mod-example-2)"
        ))
        self.assert_any_log_match(re.escape(
            "Give an instance of alignak_module_example for alias: mod-example"
        ))
        self.assert_any_log_match(re.escape(
            "configuration, foo, bar, 1"
        ))
        self.assert_any_log_match(re.escape(
            "Give an instance of alignak_module_example for alias: mod-example-2"
        ))
        self.assert_any_log_match(re.escape(
            "configuration, faa, bor, 1"
        ))
        # Loading module logs
        self.assert_any_log_match(re.escape(
            "Importing Python module 'alignak_module_example' for mod-example..."
        ))

        my_module = self.modules_manager.instances[0]
        my_module2 = self.modules_manager.instances[1]
        assert my_module.is_external
        assert my_module2.is_external

        # Get list of not external modules
        assert [] == self.modules_manager.get_internal_instances()
        for phase in ['configuration', 'late_configuration', 'running', 'retention']:
            assert [] == self.modules_manager.get_internal_instances(phase)

        # Get list of external modules
        assert [my_module, my_module2] == self.modules_manager.get_external_instances()
        for phase in ['configuration', 'late_configuration', 'running', 'retention']:
            assert [my_module, my_module2] == self.modules_manager.get_external_instances(phase)

        # Start external modules
        self.modules_manager.start_external_instances()
        self.modules_manager.start_external_instances()

        # Starting external module logs
        self.assert_any_log_match(re.escape(
            "Starting external module mod-example"
        ))
        self.assert_any_log_match(re.escape(
            "Starting external process for module mod-example"
        ))
        self.assert_any_log_match(re.escape(
            "mod-example is now started (pid="
        ))

        # Check alive
        assert my_module.process is not None
        assert my_module.process.is_alive()

        assert my_module2.process is not None
        assert my_module2.process.is_alive()

        # Kill the external module (normal stop is .stop_process)
        self.clear_logs()
        print("Killing a module")
        my_module.kill()
        time.sleep(0.1)
        self.show_logs()
        # Stopping module logs
        self.assert_any_log_match(re.escape(
            "Killing external module "
        ))
        self.assert_any_log_match(re.escape(
            "External module killed"
        ))
        # Should be dead (not normally stopped...) but we still know a process for this module!
        assert my_module.process is not None

        self.clear_logs()
        print("Killing another module")
        my_module2.kill()
        time.sleep(0.1)
        self.show_logs()
        # Stopping module logs
        self.assert_any_log_match(re.escape(
            "Killing external module "
        ))
        self.assert_any_log_match(re.escape(
            "External module killed"
        ))
        # Should be dead (not normally stopped...) but we still know a process for this module!
        assert my_module.process is not None

        # Nothing special ...
        self.clear_logs()
        self.modules_manager.check_alive_instances()

        # Try to restart the dead modules
        print("Trying to restart dead modules")
        # We lie on the last restart try time
        my_module.last_init_try = time.time()
        my_module2.last_init_try = time.time()
        self.modules_manager.try_to_restart_deads()
        self.show_logs()
        # In fact it's too early, so it won't do it

        # Here the module instances should still be dead
        assert not my_module.process.is_alive()
        assert not my_module2.process.is_alive()

        # We lie on the last restart try time
        my_module.last_init_try = 0
        my_module2.last_init_try = 0
        self.modules_manager.check_alive_instances()
        self.modules_manager.try_to_restart_deads()

        # Here the module instances should be alive again
        assert my_module.process.is_alive()
        assert my_module2.process.is_alive()

        # Kill the module again
        self.clear_logs()
        my_module.kill()
        self.show_logs()
        time.sleep(0.2)
        assert not my_module.process.is_alive()

        # And we clear all now
        self.modules_manager.stop_all()
        # Stopping module logs
        self.assert_any_log_match(re.escape(
            "I'm stopping module "
        ))
Ejemplo n.º 5
0
class TestModuleManager(AlignakTest):

    def setUp(self):
        self.setup_with_file([])
        time_hacker.set_real_time()

    # Try to see if the module manager can manage modules
    def test_modulemanager(self):
        mod = Module({'module_alias': 'mod-example', 'python_name': 'alignak_module_example'})
        self.modulemanager = ModulesManager('broker', None)
        self.modulemanager.load_and_init([mod])
        # And start external ones, like our LiveStatus
        self.modulemanager.start_external_instances()
        print "I correctly loaded the modules: %s " % ([inst.get_name() for inst in self.modulemanager.instances])

        print "*** First kill ****"
        # Now I will try to kill the livestatus module
        ls = self.modulemanager.instances[0]
        " :type: alignak.basemodule.BaseModule "
        ls.kill()
        time.sleep(0.1)
        print "Check alive?"
        print "Is alive?", ls.process.is_alive()
        # Should be dead
        self.assertFalse(ls.process.is_alive())
        self.modulemanager.check_alive_instances()
        self.modulemanager.try_to_restart_deads()

        # In fact it's too early, so it won't do it

        # Here the inst should still be dead
        print "Is alive?", ls.process.is_alive()
        self.assertFalse(ls.process.is_alive())

        # So we lie
        ls.last_init_try = -5
        self.modulemanager.check_alive_instances()
        self.modulemanager.try_to_restart_deads()

        # In fact it's too early, so it won't do it

        # Here the inst should be alive again
        print "Is alive?", ls.process.is_alive()
        self.assertTrue(ls.process.is_alive())

        # should be nothing more in to_restart of
        # the module manager
        self.assertEqual([], self.modulemanager.to_restart)

        # Now we look for time restart so we kill it again
        ls.kill()
        time.sleep(0.2)
        self.assertFalse(ls.process.is_alive())

        # Should be too early
        self.modulemanager.check_alive_instances()
        self.modulemanager.try_to_restart_deads()
        print "Is alive or not", ls.process.is_alive()
        self.assertFalse(ls.process.is_alive())
        # We lie for the test again
        ls.last_init_try = -5
        self.modulemanager.check_alive_instances()
        self.modulemanager.try_to_restart_deads()

        # Here the inst should be alive again
        print "Is alive?", ls.process.is_alive()
        self.assertTrue(ls.process.is_alive())

        # And we clear all now
        print "Ask to die"
        self.modulemanager.stop_all()
        print "Died"
Ejemplo n.º 6
0
class TestModules(AlignakTest):
    """
    This class contains the tests for the modules
    """
    def setUp(self):
        super(TestModules, self).setUp()
        self.set_unit_tests_logger_level('INFO')

    def test_module_loading(self):
        """ Test arbiter, broker, ... detecting configured modules

        :return:
        """
        self.setup_with_file('cfg/cfg_default_with_modules.cfg',
                             'cfg/default_with_modules/alignak.ini')
        assert self.conf_is_correct
        self.show_configuration_logs()
        self.show_logs()

        # arbiter modules
        modules = [
            m.module_alias for m in self._arbiter.link_to_myself.modules
        ]
        assert modules == ['Example']
        modules = [m.name for m in self._arbiter.link_to_myself.modules]
        assert modules == ['Example']

        # broker modules
        modules = [m.module_alias for m in self._broker_daemon.modules]
        assert modules == ['Example']
        modules = [m.name for m in self._broker_daemon.modules]
        assert modules == ['Example']

        # # The only existing poller module is Example declared in the configuration
        # modules = [m.module_alias for m in self.pollers['poller-master'].modules]
        # assert modules == ['Example']
        #
        # # The only existing receiver module is Example declared in the configuration
        # modules = [m.module_alias for m in self.receivers['receiver-master'].modules]
        # assert modules == ['Example']
        #
        # # The only existing reactionner module is Example declared in the configuration
        # modules = [m.module_alias for m in self.reactionners['reactionner-master'].modules]
        # assert modules == ['Example']

        # No scheduler modules created
        modules = [m.module_alias for m in self._scheduler_daemon.modules]
        assert modules == ['Example']
        modules = [m.name for m in self._scheduler_daemon.modules]
        assert modules == ['Example']

        self.show_logs()

        # Loading module logs
        self.assert_any_log_match(
            re.escape(
                u"Importing Python module 'alignak_module_example' for Example..."
            ))
        self.assert_any_log_match(
            re.escape(u"Imported 'alignak_module_example' for Example"))
        self.assert_any_log_match(
            re.escape(
                u"Give an instance of alignak_module_example for alias: Example"
            ))
        self.assert_any_log_match(
            re.escape(u"I correctly loaded my modules: [Example]"))

    def test_arbiter_configuration_module(self):
        """ Test arbiter configuration loading

        :return:
        """
        self.setup_with_file('./cfg/modules/arbiter_modules.cfg')
        assert self.conf_is_correct
        self.show_configuration_logs()
        self.show_logs()

        # The arbiter module is 'backend_arbiter' declared in the configuration
        modules = [
            m.module_alias for m in self._arbiter.link_to_myself.modules
        ]
        assert modules == ['Example']

    def test_module_on_module(self):
        """ No module configuration for modules

        Check that the feature is detected as disabled
        :return:
        """
        self.setup_with_file('cfg/modules/alignak_module_with_submodules.cfg')
        assert self.conf_is_correct
        self.show_configuration_logs()

        # arbiter modules
        modules = [
            m.module_alias for m in self._arbiter.link_to_myself.modules
        ]
        assert modules == ['Example']
        modules = [m.name for m in self._arbiter.link_to_myself.modules]
        assert modules == ['Example']

        # broker modules
        modules = [m.module_alias for m in self._broker_daemon.modules]
        assert modules == ['Example']
        modules = [m.name for m in self._broker_daemon.modules]
        assert modules == ['Example']

        # # The only existing poller module is Example declared in the configuration
        # modules = [m.module_alias for m in self.pollers['poller-master'].modules]
        # assert modules == ['Example']
        #
        # # The only existing receiver module is Example declared in the configuration
        # modules = [m.module_alias for m in self.receivers['receiver-master'].modules]
        # assert modules == ['Example']
        #
        # # The only existing reactionner module is Example declared in the configuration
        # modules = [m.module_alias for m in self.reactionners['reactionner-master'].modules]
        # assert modules == ['Example']

        # No scheduler modules created
        modules = [m.module_alias for m in self._scheduler_daemon.modules]
        assert modules == ['Example', 'inner-retention']
        modules = [m.name for m in self._scheduler_daemon.modules]
        assert modules == ['Example', 'inner-retention']

    def test_modulemanager_1(self):
        """ Module manager manages its modules - old form

        Test if the module manager manages correctly all the modules
        :return:
        """
        self.setup_with_file('cfg/cfg_default_with_modules.cfg',
                             'cfg/default_with_modules/alignak.ini')
        assert self.conf_is_correct

        # Create an Alignak module
        mod = Module({
            'module_alias': 'mod-example',
            'module_types': 'example',
            'python_name': 'alignak_module_example'
        })
        self.run_modulemanager(mod)

    def test_modulemanager_2(self):
        """ Module manager manages its modules - new form

        Test if the module manager manages correctly all the modules
        :return:
        """
        self.setup_with_file('cfg/cfg_default_with_modules.cfg',
                             'cfg/default_with_modules/alignak.ini')
        assert self.conf_is_correct

        # Create an Alignak module
        mod = Module({
            'name': 'mod-example',
            'type': 'example',
            'python_name': 'alignak_module_example'
        })
        self.run_modulemanager(mod)

    def run_modulemanager(self, mod):
        # Force the daemon SyncManager to None for unit tests!
        self._broker_daemon.sync_manager = None

        # Create the modules manager for a daemon type
        self.modules_manager = ModulesManager(self._broker_daemon)

        # Load an initialize the modules:
        #  - load python module
        #  - get module properties and instances
        self.modules_manager.load_and_init([mod])

        # Loading module logs
        self.assert_any_log_match(
            re.escape(
                "Importing Python module 'alignak_module_example' for mod-example..."
            ))
        self.assert_any_log_match(
            re.escape("Imported 'alignak_module_example' for mod-example"))
        self.assert_any_log_match(
            re.escape(
                "Give an instance of alignak_module_example for alias: mod-example"
            ))

        self.clear_logs()

        my_module = self.modules_manager.instances[0]
        assert my_module.is_external

        # Get list of not external modules
        assert [] == self.modules_manager.get_internal_instances()
        for phase in [
                'configuration', 'late_configuration', 'running', 'retention'
        ]:
            assert [] == self.modules_manager.get_internal_instances(phase)

        # Get list of external modules
        assert [my_module] == self.modules_manager.get_external_instances()
        for phase in [
                'configuration', 'late_configuration', 'running', 'retention'
        ]:
            assert [my_module
                    ] == self.modules_manager.get_external_instances(phase)

        # Start external modules
        self.modules_manager.start_external_instances()

        self.show_logs()

        # Starting external module logs
        idx = 0
        self.assert_log_match(
            re.escape("Trying to initialize module: mod-example"), idx)
        idx += 1
        self.assert_log_match(re.escape("Test - Example in init"), idx)
        idx += 1
        self.assert_log_match(
            re.escape("Initialization of the example module"), idx)
        idx += 1
        self.assert_log_match(re.escape("Module mod-example is initialized"),
                              idx)
        idx += 1
        self.assert_log_match(
            re.escape("Starting external module mod-example"), idx)
        idx += 1
        self.assert_log_match(
            re.escape("Starting external process for module mod-example"), idx)
        idx += 1
        self.assert_log_match(re.escape("mod-example is now started (pid="),
                              idx)
        idx += 1
        self.assert_log_count(7)

        # Check alive
        assert my_module.process is not None
        assert my_module.process.is_alive()

        self.clear_logs()
        # Check the alive module instances...
        self.modules_manager.check_alive_instances()
        # Try to restart the dead modules, if any
        self.modules_manager.try_to_restart_deads()
        self.assert_log_count(0)

        # Kill the external module (normal stop is .stop_process)
        self.clear_logs()
        my_module.kill()
        idx = 0
        self.assert_log_match(re.escape("Killing external module "), idx)
        idx += 1
        self.show_logs()

        # self.assert_log_match(re.escape(
        #     "mod-example is still living "
        # ), idx)
        # idx += 1
        # Specific case because sometimes the module is not killed within the expected 10s time
        normal_kill = True
        logger_ = logging.getLogger(ALIGNAK_LOGGER_NAME)
        for handler in logger_.handlers:
            if not isinstance(handler, CollectorHandler):
                continue
            regex = re.compile('mod-example is still living')

            log_num = 0
            found = False
            for log in handler.collector:
                if idx == log_num:
                    if regex.search(log):
                        idx += 1
                        normal_kill = False
                        break
                log_num += 1
            break

        self.assert_log_match(re.escape("External module killed"), idx)
        idx += 1
        self.assert_log_count(idx)

        # The module is dead (not normally stopped...) so this module inner
        # process reference is not None!
        assert my_module.process is not None

        # Check the alive module instances...
        self.clear_logs()
        idx = 0
        self.modules_manager.check_alive_instances()
        self.show_logs()
        self.assert_log_match(
            re.escape("The external module mod-example died unexpectedly!"),
            idx)
        idx += 1
        self.assert_log_match(
            re.escape("Setting the module mod-example to restart"), idx)
        self.assert_log_count(2)
        idx += 1

        if normal_kill:
            # Try to restart the dead modules, if any
            # Indeed, it's too early, so it won't do it
            self.clear_logs()
            idx = 0
            print("try init: %d" % my_module.init_try)
            self.modules_manager.try_to_restart_deads()
            self.show_logs()

            self.assert_log_match(
                re.escape("Trying to restart module: mod-example"), idx)
            idx += 1
            self.assert_log_match(
                re.escape(
                    "Too early to retry initialization, retry period is %d seconds"
                    % MODULE_INIT_PERIOD), idx)
            idx += 1
            self.assert_log_count(2)

            # Here the module instance is still dead
            assert not my_module.process.is_alive()

            # Wait for a minimum delay
            time.sleep(MODULE_INIT_PERIOD + 1)

        # my_module.last_init_try = -5
        self.clear_logs()
        self.modules_manager.check_alive_instances()
        self.show_logs()
        self.assert_log_count(0)

        # Try to restart the dead modules, if any
        # Now it is time...
        self.clear_logs()
        idx = 0
        self.modules_manager.try_to_restart_deads()
        self.show_logs()
        self.assert_log_match(
            re.escape("Trying to restart module: mod-example"), idx)
        idx += 1
        self.assert_log_match(
            re.escape("Trying to initialize module: mod-example"), idx)
        idx += 1
        self.assert_log_match(re.escape("Test - Example in init"), idx)
        idx += 1
        self.assert_log_match(
            re.escape("Initialization of the example module"), idx)
        idx += 1
        self.assert_log_match(re.escape("Module mod-example is initialized"),
                              idx)
        idx += 1
        self.assert_log_match(re.escape("Restarting mod-example..."), idx)
        idx += 1
        self.assert_log_match(
            re.escape("Starting external process for module mod-example"), idx)
        idx += 1
        self.assert_log_match(re.escape("mod-example is now started (pid="),
                              idx)
        idx += 1
        self.assert_log_count(8)

        # Here the module instance should be alive again
        assert my_module.process.is_alive()

        # No more module to restart...
        assert [] == self.modules_manager.to_restart

        # And we clear all now
        self.clear_logs()
        idx = 0
        self.modules_manager.stop_all()
        self.show_logs()
        self.assert_log_match(re.escape("Shutting down modules..."), idx)
        idx += 1
        self.assert_log_match(
            re.escape("Request external process to stop for mod-example"), idx)
        idx += 1
        self.assert_log_match(re.escape("I'm stopping module 'mod-example'"),
                              idx)
        idx += 1
        self.assert_log_match(re.escape("Killing external module "), idx)
        idx += 1

        # Specific case because sometimes the module is not killed within the expected 10s time
        logger_ = logging.getLogger(ALIGNAK_LOGGER_NAME)
        for handler in logger_.handlers:
            if not isinstance(handler, CollectorHandler):
                continue
            regex = re.compile('mod-example is still living')

            log_num = 0
            found = False
            for log in handler.collector:
                if idx == log_num:
                    if regex.search(log):
                        idx += 1
                        break
                log_num += 1
            break

        self.assert_log_match(re.escape("External module killed"), idx)
        idx += 1
        self.assert_log_match(re.escape("External process stopped."), idx)
        idx += 1
        # self.assert_log_count(6)

    def test_modulemanager_several_modules(self):
        """ Module manager manages its modules

        Test if the module manager manages correctly all the modules

        Configured with several modules
        :return:
        """
        self.setup_with_file('cfg/cfg_default_with_modules.cfg',
                             'cfg/default_with_modules/alignak.ini')
        assert self.conf_is_correct

        # for mod in self._arbiter.conf.modules:
        #     print (mod.__dict__)

        # Create an Alignak module
        mod = Module({
            'module_alias': 'mod-example',
            'module_types': 'example',
            'python_name': 'alignak_module_example',
            'option1': 'foo',
            'option2': 'bar',
            'option3': 1
        })
        mod2 = Module({
            'module_alias': 'mod-example-2',
            'module_types': 'example',
            'python_name': 'alignak_module_example',
            'option1': 'faa',
            'option2': 'bor',
            'option3': 1
        })

        # Force the daemon SyncManager to None for unit tests!
        self._broker_daemon.sync_manager = None
        # Create the modules manager for a daemon type
        self.modules_manager = ModulesManager(self._broker_daemon)
        print("Modules: %s" % self._broker_daemon.modules)

        # Load an initialize the modules:
        #  - load python module
        #  - get module properties and instances
        assert self.modules_manager.load_and_init([mod, mod2])
        print("I correctly loaded my modules: [%s]" %
              ','.join([inst.name for inst in self.modules_manager.instances]))
        self.show_logs()

        self.assert_any_log_match(
            re.escape(
                "Importing Python module 'alignak_module_example' for mod-example..."
            ))
        self.assert_any_log_match(
            re.escape("Imported 'alignak_module_example' for mod-example"))
        self.assert_any_log_match(
            re.escape(
                "Loaded Python module 'alignak_module_example' (mod-example)"))
        self.assert_any_log_match(
            re.escape(
                "Importing Python module 'alignak_module_example' for mod-example-2..."
            ))
        self.assert_any_log_match(
            re.escape("Imported 'alignak_module_example' for mod-example-2"))
        self.assert_any_log_match(
            re.escape(
                "Loaded Python module 'alignak_module_example' (mod-example-2)"
            ))
        self.assert_any_log_match(
            re.escape(
                "Give an instance of alignak_module_example for alias: mod-example"
            ))
        self.assert_any_log_match(re.escape("configuration, foo, bar, 1"))
        self.assert_any_log_match(
            re.escape(
                "Give an instance of alignak_module_example for alias: mod-example-2"
            ))
        self.assert_any_log_match(re.escape("configuration, faa, bor, 1"))
        # Loading module logs
        self.assert_any_log_match(
            re.escape(
                "Importing Python module 'alignak_module_example' for mod-example..."
            ))

        my_module = self.modules_manager.instances[0]
        my_module2 = self.modules_manager.instances[1]
        assert my_module.is_external
        assert my_module2.is_external

        # Get list of not external modules
        assert [] == self.modules_manager.get_internal_instances()
        for phase in [
                'configuration', 'late_configuration', 'running', 'retention'
        ]:
            assert [] == self.modules_manager.get_internal_instances(phase)

        # Get list of external modules
        assert [my_module,
                my_module2] == self.modules_manager.get_external_instances()
        for phase in [
                'configuration', 'late_configuration', 'running', 'retention'
        ]:
            assert [my_module, my_module2
                    ] == self.modules_manager.get_external_instances(phase)

        # Start external modules
        self.modules_manager.start_external_instances()
        self.modules_manager.start_external_instances()

        # Starting external module logs
        self.assert_any_log_match(
            re.escape("Starting external module mod-example"))
        self.assert_any_log_match(
            re.escape("Starting external process for module mod-example"))
        self.assert_any_log_match(
            re.escape("mod-example is now started (pid="))

        # Check alive
        assert my_module.process is not None
        assert my_module.process.is_alive()

        assert my_module2.process is not None
        assert my_module2.process.is_alive()

        # Kill the external module (normal stop is .stop_process)
        self.clear_logs()
        print("Killing a module")
        my_module.kill()
        time.sleep(0.1)
        self.show_logs()
        # Stopping module logs
        self.assert_any_log_match(re.escape("Killing external module "))
        self.assert_any_log_match(re.escape("External module killed"))
        # Should be dead (not normally stopped...) but we still know a process for this module!
        assert my_module.process is not None

        self.clear_logs()
        print("Killing another module")
        my_module2.kill()
        time.sleep(0.1)
        self.show_logs()
        # Stopping module logs
        self.assert_any_log_match(re.escape("Killing external module "))
        self.assert_any_log_match(re.escape("External module killed"))
        # Should be dead (not normally stopped...) but we still know a process for this module!
        assert my_module.process is not None

        # Nothing special ...
        self.clear_logs()
        self.modules_manager.check_alive_instances()

        # Try to restart the dead modules
        print("Trying to restart dead modules")
        # We lie on the last restart try time
        my_module.last_init_try = time.time()
        my_module2.last_init_try = time.time()
        self.modules_manager.try_to_restart_deads()
        self.show_logs()
        # In fact it's too early, so it won't do it

        # Here the module instances should still be dead
        assert not my_module.process.is_alive()
        assert not my_module2.process.is_alive()

        # We lie on the last restart try time
        my_module.last_init_try = 0
        my_module2.last_init_try = 0
        self.modules_manager.check_alive_instances()
        self.modules_manager.try_to_restart_deads()

        # Here the module instances should be alive again
        assert my_module.process.is_alive()
        assert my_module2.process.is_alive()

        # Kill the module again
        self.clear_logs()
        my_module.kill()
        self.show_logs()
        time.sleep(0.2)
        assert not my_module.process.is_alive()

        # And we clear all now
        self.modules_manager.stop_all()
        # Stopping module logs
        self.assert_any_log_match(re.escape("I'm stopping module "))
Ejemplo n.º 7
0
class TestModules(AlignakTest):
    """
    This class contains the tests for the module
    """
    def test_module_loading(self):
        """
        Test module loading

        Alignak module loading

        :return:
        """
        self.setup_with_file('./cfg/alignak.cfg')
        self.assertTrue(self.conf_is_correct)
        self.show_configuration_logs()

        # No arbiter modules created
        modules = [
            m.module_alias for m in self._arbiter.link_to_myself.modules
        ]
        self.assertListEqual(modules, [])

        # No broker modules
        modules = [m.module_alias for m in self._broker_daemon.modules]
        self.assertListEqual(modules, [])

        # No scheduler modules
        modules = [m.module_alias for m in self._scheduler_daemon.modules]
        self.assertListEqual(modules, ['inner-retention'])

        # A receiver module
        modules = [m.module_alias for m in self._receiver.modules]
        self.assertListEqual(modules, ['nsca'])

    def test_module_manager(self):
        """
        Test if the module manager manages correctly all the modules
        :return:
        """
        self.setup_with_file('./cfg/alignak.cfg')
        self.assertTrue(self.conf_is_correct)
        self.clear_logs()

        # Create an Alignak module
        mod = Module({
            'module_alias': 'nsca',
            'module_types': 'nsca',
            'python_name': 'alignak_module_nsca'
        })

        # Create the modules manager for a daemon type
        self.modulemanager = ModulesManager(self._broker_daemon)

        # Load an initialize the modules:
        #  - load python module
        #  - get module properties and instances
        self.modulemanager.load_and_init([mod])

        # Loading module nsca
        print("Load and init")
        self.show_logs()
        i = 0
        self.assert_log_match(
            re.escape(
                "Importing Python module 'alignak_module_nsca' for nsca..."),
            i)
        i += 1
        # Dict order is problematic :/
        # self.assert_log_match(re.escape(
        #     "Module properties: {'daemons': ['broker'], 'phases': ['running'], "
        #     "'type': 'nsca', 'external': True}"
        # ), i)
        i += 1
        self.assert_log_match(
            re.escape("Imported 'alignak_module_nsca' for nsca"), i)
        i += 1
        self.assert_log_match(
            re.escape("Loaded Python module 'alignak_module_nsca' (nsca)"), i)
        i += 1
        self.assert_log_match(re.escape("Alignak starting module 'nsca'"), i)
        i += 1
        self.assert_log_match(
            re.escape(
                "Give an instance of alignak_module_nsca for alias: nsca"), i)
        i += 1
        self.assert_log_match(
            re.escape(
                "configuration, allowed hosts : '127.0.0.1'(5667), buffer length: 4096, "
                "payload length: -1, encryption: 0, max packet age: 30, "
                "check future packet: True, backlog: 10"), i)

        time.sleep(1)
        # Reload the module
        print("Reload")
        self.modulemanager.load([mod])
        self.modulemanager.get_instances()
        #
        # Loading module nsca
        self.show_logs()
        i = 0
        self.assert_log_match(
            re.escape(
                "Importing Python module 'alignak_module_nsca' for nsca..."),
            i)
        i += 1
        # self.assert_log_match(re.escape(
        #     "Module properties: {'daemons': ['broker'], 'phases': ['running'], "
        #     "'type': 'nsca', 'external': True}"
        # ), i)
        i += 1
        self.assert_log_match(
            re.escape("Imported 'alignak_module_nsca' for nsca"), i)
        i += 1
        self.assert_log_match(
            re.escape("Loaded Python module 'alignak_module_nsca' (nsca)"), i)
        i += 1
        self.assert_log_match(re.escape("Alignak starting module 'nsca'"), i)
        i += 1
        self.assert_log_match(
            re.escape(
                "Give an instance of alignak_module_nsca for alias: nsca"), i)
        i += 1
        self.assert_log_match(
            re.escape(
                "configuration, allowed hosts : '127.0.0.1'(5667), buffer length: 4096, "
                "payload length: -1, encryption: 0, max packet age: 30, "
                "check future packet: True, backlog: 10"), i)
        i += 1
        self.assert_log_match(
            re.escape(
                "Importing Python module 'alignak_module_nsca' for nsca..."),
            i)
        i += 1
        # self.assert_log_match(re.escape(
        #     "Module properties: {'daemons': ['broker'], 'phases': ['running'], "
        #     "'type': 'nsca', 'external': True}"
        # ), i)
        i += 1
        self.assert_log_match(
            re.escape("Imported 'alignak_module_nsca' for nsca"), i)
        i += 1
        self.assert_log_match(
            re.escape("Loaded Python module 'alignak_module_nsca' (nsca)"), i)
        i += 1
        self.assert_log_match(
            re.escape("Request external process to stop for nsca"), i)
        i += 1
        self.assert_log_match(re.escape("External process stopped."), i)
        i += 1
        self.assert_log_match(re.escape("Alignak starting module 'nsca'"), i)
        i += 1
        # self.assert_log_match(re.escape(
        #     "Give an instance of alignak_module_nsca for alias: nsca"
        # ), i)
        # i += 1
        self.assert_log_match(
            re.escape(
                "Give an instance of alignak_module_nsca for alias: nsca"), i)
        i += 1
        self.assert_log_match(
            re.escape(
                "configuration, allowed hosts : '127.0.0.1'(5667), buffer length: 4096, "
                "payload length: -1, encryption: 0, max packet age: 30, "
                "check future packet: True, backlog: 10"), i)

        my_module = self.modulemanager.instances[0]

        # Get list of not external modules
        self.assertListEqual([], self.modulemanager.get_internal_instances())
        for phase in [
                'configuration', 'late_configuration', 'running', 'retention'
        ]:
            self.assertListEqual(
                [], self.modulemanager.get_internal_instances(phase))

        # Get list of external modules
        self.assertListEqual([my_module],
                             self.modulemanager.get_external_instances())
        for phase in ['configuration', 'late_configuration', 'retention']:
            self.assertListEqual(
                [], self.modulemanager.get_external_instances(phase))
        for phase in ['running']:
            self.assertListEqual(
                [my_module], self.modulemanager.get_external_instances(phase))

        # Clear nsca
        self.clear_logs()

        # Start external modules
        self.modulemanager.start_external_instances()

        # Starting external module nsca
        self.assert_log_match("Trying to initialize module: nsca", 0)
        self.assert_log_match("Starting external module nsca", 1)
        self.assert_log_match("Starting external process for module nsca", 2)
        self.assert_log_match("nsca is now started", 3)

        # Check alive
        self.assertIsNotNone(my_module.process)
        self.assertTrue(my_module.process.is_alive())

        # Clear nsca
        self.clear_logs()

        # Kill the external module (normal stop is .stop_process)
        my_module.kill()
        time.sleep(0.1)
        index = 0
        self.assert_log_match("Killing external module", index)
        index = index + 1
        # todo: This log is not expected! But it is probably because of the py.test ...
        # Indeed the receiver daemon that the module is attached to is receiving a SIGTERM !!!
        self.assert_log_match(
            re.escape(
                "nsca is still living 10 seconds after a normal kill, I help it to die"
            ), index)
        index = index + 1
        self.assert_log_match("External module killed", index)
        index = index + 1

        # Should be dead (not normally stopped...) but we still know a process for this module!
        self.assertIsNotNone(my_module.process)

        # Nothing special ...
        self.modulemanager.check_alive_instances()
        self.assert_log_match("The external module nsca died unexpectedly!",
                              index)
        index = index + 1
        self.assert_log_match("Setting the module nsca to restart", index)
        index = index + 1

        # # Try to restart the dead modules
        # self.modulemanager.try_to_restart_deads()
        # self.assert_log_match("Trying to restart module: nsca", index)
        # index = index +1
        # self.assert_log_match("Too early to retry initialization, retry period is 5 seconds", index)
        # index = index +1
        #
        # # In fact it's too early, so it won't do it
        # # The module instance is still dead
        # self.assertFalse(my_module.process.is_alive())

        # So we lie, on the restart tries ...
        my_module.last_init_try = -5
        self.modulemanager.check_alive_instances()
        self.modulemanager.try_to_restart_deads()
        self.assert_log_match("Trying to restart module: nsca", index)
        index = index + 1
        self.assert_log_match("Trying to initialize module: nsca", index)
        index = index + 1
        self.assert_log_match("Restarting nsca...", index)
        index = index + 1

        # The module instance is now alive again
        self.assertTrue(my_module.process.is_alive())
        self.assert_log_match("Starting external process for module nsca",
                              index)
        index = index + 1
        self.assert_log_match("nsca is now started", index)
        index = index + 1

        # There is nothing else to restart in the module manager
        self.assertEqual([], self.modulemanager.to_restart)

        # Clear nsca
        self.clear_logs()

        # Let the module start and then kill it again
        time.sleep(3.0)
        my_module.kill()
        # time.sleep(5.0)
        self.show_logs()
        print("My module PID 2: %s" % my_module.process.pid)
        time.sleep(0.2)
        self.assertFalse(my_module.process.is_alive())
        index = 0
        self.assert_log_match("Killing external module", index)
        index = index + 1
        # # todo: This log is not expected! But it is probably because of the py.test ...
        # # Indeed the receiver daemon that the module is attached to is receiving a SIGTERM !!!
        # self.assert_log_match(re.escape("'web-services' is still living 10 seconds after a normal kill, I help it to die"), index)
        # index = index +1
        self.assert_log_match("External module killed", index)
        index = index + 1

        # The module is dead but the modules manager do not know yet!
        self.modulemanager.check_alive_instances()
        self.assert_log_match("The external module nsca died unexpectedly!",
                              index)
        index = index + 1
        self.assert_log_match("Setting the module nsca to restart", index)
        index = index + 1

        self.modulemanager.try_to_restart_deads()
        self.assert_log_match("Trying to restart module: nsca", index)
        index = index + 1
        self.assert_log_match(
            "Too early to retry initialization, retry period is 5 seconds",
            index)
        index = index + 1

        # In fact it's too early, so it won't do it
        # The module instance is still dead
        self.assertFalse(my_module.process.is_alive())

        # So we lie, on the restart tries ...
        my_module.last_init_try = -5
        self.modulemanager.check_alive_instances()
        self.modulemanager.try_to_restart_deads()
        self.assert_log_match("Trying to restart module: nsca", index)
        index = index + 1
        self.assert_log_match("Trying to initialize module: nsca", index)
        index = index + 1
        self.assert_log_match("Restarting nsca...", index)
        index = index + 1

        # The module instance is now alive again
        self.assertTrue(my_module.process.is_alive())
        self.assert_log_match("Starting external process for module nsca",
                              index)
        index = index + 1
        self.assert_log_match("nsca is now started", index)
        index = index + 1
        time.sleep(1.0)
        print("My module PID: %s" % my_module.process.pid)

        # Clear nsca
        self.clear_logs()

        # And we clear all now
        self.modulemanager.stop_all()
        # Stopping module nsca

        index = 0
        self.assert_log_match("Shutting down modules...", index)
        index = index + 1
        self.assert_log_match("Request external process to stop for nsca",
                              index)
        index = index + 1
        self.assert_log_match(re.escape("I'm stopping module 'nsca' (pid="),
                              index)
        index = index + 1
        # self.assert_log_match(re.escape("'nsca' is still living after a normal kill, I help it to die"), index)
        # index = index +1
        self.assert_log_match(re.escape("Killing external module (pid"), index)
        index = index + 1
        self.assert_log_match(re.escape("External module killed"), index)
        index = index + 1
        self.assert_log_match("External process stopped.", index)
        index = index + 1

    def test_module_start_default(self):
        """Test the module initialization function, no parameters, using default
        :return:
        """
        # Obliged to call to get a self.logger...
        self.setup_with_file('./cfg/alignak.cfg')
        self.assertTrue(self.conf_is_correct)

        # Clear nsca
        self.clear_logs()

        # -----
        # Default initialization
        # -----
        # Create an Alignak module
        mod = Module({
            'module_alias': 'nsca',
            'module_types': 'passive',
            'python_name': 'alignak_module_nsca'
        })

        instance = alignak_module_nsca.get_instance(mod)
        self.assertIsInstance(instance, BaseModule)
        self.show_logs()

        # self.assert_log_match(
        #     re.escape("Give an instance of alignak_module_nsca for alias: nsca"), 0)
        self.assert_log_match(
            re.escape(
                "Give an instance of alignak_module_nsca for alias: nsca"), 0)
        self.assert_log_match(
            re.escape(
                "configuration, allowed hosts : '127.0.0.1'(5667), buffer length: 4096, "
                "payload length: -1, encryption: 0, max packet age: 30, "
                "check future packet: True, backlog: 10"), 1)
Ejemplo n.º 8
0
class TestModuleWsEvent(AlignakTest):
    """This class contains the tests for the module"""

    @classmethod
    def setUpClass(cls):

        # Simulate an Alignak receiver daemon
        cls.ws_endpoint = 'http://127.0.0.1:7773/ws'
        import cherrypy
        class ReceiverItf(object):
            @cherrypy.expose
            def index(self):
                return "I am the Receiver daemon!"
        from alignak.http.daemon import HTTPDaemon as AlignakDaemon
        http_daemon1 = AlignakDaemon('0.0.0.0', 7773, ReceiverItf(),
                                     False, None, None, None, None, 10, '/tmp/alignak-cherrypy.log')
        def run_http_server():
            http_daemon1.run()
        import threading
        cls.http_thread1 = threading.Thread(target=run_http_server, name='http_server_receiver')
        cls.http_thread1.daemon = True
        cls.http_thread1.start()
        print("Thread started")

        # Set test mode for alignak backend
        os.environ['TEST_ALIGNAK_BACKEND'] = '1'
        os.environ['ALIGNAK_BACKEND_MONGO_DBNAME'] = 'alignak-module-ws-event'

        # Delete used mongo DBs
        print ("Deleting Alignak backend DB...")
        exit_code = subprocess.call(
            shlex.split(
                'mongo %s --eval "db.dropDatabase()"' % os.environ['ALIGNAK_BACKEND_MONGO_DBNAME'])
        )
        assert exit_code == 0

        fnull = open(os.devnull, 'w')
        cls.p = subprocess.Popen(['uwsgi', '--plugin', 'python', '-w', 'alignakbackend:app',
                                  '--socket', '0.0.0.0:5000',
                                  '--protocol=http', '--enable-threads', '--pidfile',
                                  '/tmp/uwsgi.pid', '--logto', '/tmp/uwsgi.log'],
                                 # stdout=fnull, stderr=fnull
                                 )
        time.sleep(3)

        endpoint = 'http://127.0.0.1:5000'

        test_dir = os.path.dirname(os.path.realpath(__file__))
        print("Current test directory: %s" % test_dir)

        print("Feeding Alignak backend... %s" % test_dir)
        exit_code = subprocess.call(
            shlex.split('alignak-backend-import --delete %s/cfg/cfg_default.cfg' % test_dir),
            # stdout=fnull, stderr=fnull
        )
        assert exit_code == 0
        print("Fed")

        # Backend authentication
        headers = {'Content-Type': 'application/json'}
        params = {'username': '******', 'password': '******'}
        # Get admin user token (force regenerate)
        response = requests.post(endpoint + '/login', json=params, headers=headers)
        resp = response.json()
        cls.token = resp['token']
        cls.auth = requests.auth.HTTPBasicAuth(cls.token, '')

        # Get admin user
        response = requests.get(endpoint + '/user', auth=cls.auth)
        resp = response.json()
        cls.user_admin = resp['_items'][0]

        # Get realms
        response = requests.get(endpoint + '/realm', auth=cls.auth)
        resp = response.json()
        cls.realmAll_id = resp['_items'][0]['_id']

        # Add a user
        data = {'name': 'test', 'password': '******', 'back_role_super_admin': False,
                'host_notification_period': cls.user_admin['host_notification_period'],
                'service_notification_period': cls.user_admin['service_notification_period'],
                '_realm': cls.realmAll_id}
        response = requests.post(endpoint + '/user', json=data, headers=headers,
                                 auth=cls.auth)
        resp = response.json()
        print(("Created a new user: %s" % resp))

        # Get new user restrict role
        params = {'where': json.dumps({'user': resp['_id']})}
        response = requests.get(endpoint + '/userrestrictrole', params=params, auth=cls.auth)
        resp = response.json()

        # Update user's rights - set full CRUD rights
        headers = {'Content-Type': 'application/json', 'If-Match': resp['_items'][0]['_etag']}
        data = {'crud': ['create', 'read', 'update', 'delete', 'custom']}
        resp = requests.patch(endpoint + '/userrestrictrole/' + resp['_items'][0]['_id'],
                              json=data, headers=headers, auth=cls.auth)
        resp = resp.json()
        assert resp['_status'] == 'OK'

    @classmethod
    def tearDownClass(cls):
        cls.p.kill()

    def setUp(self):
        super(TestModuleWsEvent, self).setUp()

    def tearDown(self):
        super(TestModuleWsEvent, self).tearDown()
        if self.modulemanager:
            time.sleep(1)
            self.modulemanager.stop_all()

    def test_module_zzz_event(self):
        """Test the module /event endpoint
        :return:
        """
        # Create an Alignak module
        mod = Module({
            'module_alias': 'web-services',
            'module_types': 'web-services',
            'python_name': 'alignak_module_ws',
            # Alignak backend
            'alignak_backend': 'http://127.0.0.1:5000',
            'username': '******',
            'password': '******',
            # Set Arbiter address as empty to not poll the Arbiter else the test will fail!
            'alignak_host': '',
            'alignak_port': 7770,
            'authorization': '1',
        })

        # Create a receiver daemon
        args = {'env_file': '', 'daemon_name': 'receiver-master'}
        self._receiver_daemon = Receiver(**args)

        # Create the modules manager for the daemon
        self.modulemanager = ModulesManager(self._receiver_daemon)

        # Load an initialize the modules:
        #  - load python module
        #  - get module properties and instances
        self.modulemanager.load_and_init([mod])

        my_module = self.modulemanager.instances[0]

        # Clear logs
        self.clear_logs()

        # Start external modules
        self.modulemanager.start_external_instances()

        # Starting external module logs
        self.assert_log_match("Trying to initialize module: web-services", 0)
        self.assert_log_match("Starting external module web-services", 1)
        self.assert_log_match("Starting external process for module web-services", 2)
        self.assert_log_match("web-services is now started", 3)

        # Check alive
        self.assertIsNotNone(my_module.process)
        self.assertTrue(my_module.process.is_alive())

        time.sleep(1)

        # ---
        # Prepare the backend content...
        self.endpoint = 'http://127.0.0.1:5000'

        headers = {'Content-Type': 'application/json'}
        params = {'username': '******', 'password': '******'}
        # get token
        response = requests.post(self.endpoint + '/login', json=params, headers=headers)
        resp = response.json()
        self.token = resp['token']
        self.auth = requests.auth.HTTPBasicAuth(self.token, '')

        # Get default realm
        response = requests.get(self.endpoint + '/realm', auth=self.auth)
        resp = response.json()
        self.realm_all = resp['_items'][0]['_id']
        # ---

        # Do not allow GET request on /event - not yet authorized
        response = requests.get(self.ws_endpoint + '/event')
        self.assertEqual(response.status_code, 401)

        session = requests.Session()

        # Login with username/password (real backend login)
        headers = {'Content-Type': 'application/json'}
        params = {'username': '******', 'password': '******'}
        response = session.post(self.ws_endpoint + '/login', json=params, headers=headers)
        assert response.status_code == 200
        resp = response.json()

        # Do not allow GET request on /event
        response = session.get(self.ws_endpoint + '/event')
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result['_status'], 'ERR')
        self.assertEqual(result['_issues'], ['You must only POST on this endpoint.'])

        self.assertEqual(my_module.received_commands, 0)

        # You must have parameters when POSTing on /event
        headers = {'Content-Type': 'application/json'}
        data = {}
        response = session.post(self.ws_endpoint + '/event', json=data, headers=headers)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result['_status'], 'ERR')
        self.assertEqual(result['_issues'], ['You must POST parameters on this endpoint.'])

        self.assertEqual(my_module.received_commands, 0)

        # Notify an host event - missing host or service
        headers = {'Content-Type': 'application/json'}
        data = {
            "fake": ""
        }
        self.assertEqual(my_module.received_commands, 0)
        response = session.post(self.ws_endpoint + '/event', json=data, headers=headers)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result, {'_status': 'ERR', '_issues': ['Missing host and/or service parameter.']})

        # Notify an host event - missing comment
        headers = {'Content-Type': 'application/json'}
        data = {
            "host": "test_host",
        }
        response = session.post(self.ws_endpoint + '/event', json=data, headers=headers)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result, {'_status': 'ERR',
                                  '_issues': ['Missing comment. If you do not have any comment, '
                                              'do not comment ;)']})

        # Notify an host event - default author
        headers = {'Content-Type': 'application/json'}
        data = {
            "host": "test_host",
            "comment": "My comment"
        }
        response = session.post(self.ws_endpoint + '/event', json=data, headers=headers)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result, {'_status': 'OK',
                                  '_result': ['ADD_HOST_COMMENT;test_host;1;'
                                              'Alignak WS;My comment']})

        # Notify an host event - default author and timestamp
        headers = {'Content-Type': 'application/json'}
        data = {
            "timestamp": 1234567890,
            "host": "test_host",
            "author": "Me",
            "comment": "My comment"
        }
        response = session.post(self.ws_endpoint + '/event', json=data, headers=headers)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result, {'_status': 'OK',
                                  '_result': ['[1234567890] ADD_HOST_COMMENT;test_host;1;'
                                              'Me;My comment']})

        # Notify a service event - default author
        headers = {'Content-Type': 'application/json'}
        data = {
            "host": "test_host",
            "service": "test_service",
            "comment": "My comment"
        }
        response = session.post(self.ws_endpoint + '/event', json=data, headers=headers)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result, {'_status': 'OK',
                                  '_result': ['ADD_SVC_COMMENT;test_host;test_service;1;'
                                              'Alignak WS;My comment']})

        # Notify a service event - default author and timestamp
        headers = {'Content-Type': 'application/json'}
        data = {
            "timestamp": 1234567890,
            "host": "test_host",
            "service": "test_service",
            "author": "Me",
            "comment": "My comment"
        }
        response = session.post(self.ws_endpoint + '/event', json=data, headers=headers)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result, {'_status': 'OK',
                                  '_result': ['[1234567890] ADD_SVC_COMMENT;test_host;test_service;'
                                              '1;Me;My comment']})

        # Get history to confirm that backend is ready
        # ---
        response = session.get(self.endpoint + '/history', auth=self.auth,
                                params={"sort": "-_id", "max_results": 25, "page": 1})
        resp = response.json()
        print(("Response: %s" % resp))
        for item in resp['_items']:
            assert item['type'] in ['webui.comment']
        # Got 4 notified events, so we get 4 comments in the backend
        self.assertEqual(len(resp['_items']), 4)
        # ---

        # Logout
        response = session.get(self.ws_endpoint + '/logout')
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result['_status'], 'OK')
        self.assertEqual(result['_result'], 'Logged out')

        self.modulemanager.stop_all()

    def test_module_zzz_event(self):
        """Test the module /event endpoint
        :return:
        """
        # Create an Alignak module
        mod = Module({
            'module_alias': 'web-services',
            'module_types': 'web-services',
            'python_name': 'alignak_module_ws',
            # Alignak backend
            'alignak_backend': 'http://127.0.0.1:5000',
            'username': '******',
            'password': '******',
            # Set Arbiter address as empty to not poll the Arbiter else the test will fail!
            'alignak_host': '',
            'alignak_port': 7770,
            'authorization': '1',
        })

        # Create a receiver daemon
        args = {'env_file': '', 'daemon_name': 'receiver-master'}
        self._receiver_daemon = Receiver(**args)

        # Create the modules manager for the daemon
        self.modulemanager = ModulesManager(self._receiver_daemon)

        # Load an initialize the modules:
        #  - load python module
        #  - get module properties and instances
        self.modulemanager.load_and_init([mod])

        my_module = self.modulemanager.instances[0]

        # Clear logs
        self.clear_logs()

        # Start external modules
        self.modulemanager.start_external_instances()

        # Starting external module logs
        self.assert_log_match("Trying to initialize module: web-services", 0)
        self.assert_log_match("Starting external module web-services", 1)
        self.assert_log_match("Starting external process for module web-services", 2)
        self.assert_log_match("web-services is now started", 3)

        # Check alive
        self.assertIsNotNone(my_module.process)
        self.assertTrue(my_module.process.is_alive())

        time.sleep(1)

        # ---
        # Prepare the backend content...
        self.endpoint = 'http://127.0.0.1:5000'

        headers = {'Content-Type': 'application/json'}
        params = {'username': '******', 'password': '******'}
        # get token
        response = requests.post(self.endpoint + '/login', json=params, headers=headers)
        resp = response.json()
        self.token = resp['token']
        self.auth = requests.auth.HTTPBasicAuth(self.token, '')

        # Get default realm
        response = requests.get(self.endpoint + '/realm', auth=self.auth)
        resp = response.json()
        self.realm_all = resp['_items'][0]['_id']
        # ---

        # Do not allow GET request on /event - not yet authorized
        response = requests.get(self.ws_endpoint + '/event')
        self.assertEqual(response.status_code, 401)

        session = requests.Session()

        # Login with username/password (real backend login)
        headers = {'Content-Type': 'application/json'}
        params = {'username': '******', 'password': '******'}
        response = session.post(self.ws_endpoint + '/login', json=params, headers=headers)
        assert response.status_code == 200
        resp = response.json()

        # Do not allow GET request on /event
        response = session.get(self.ws_endpoint + '/event')
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result['_status'], 'ERR')
        self.assertEqual(result['_issues'], ['You must only POST on this endpoint.'])

        self.assertEqual(my_module.received_commands, 0)

        # You must have parameters when POSTing on /event
        headers = {'Content-Type': 'application/json'}
        data = {}
        response = session.post(self.ws_endpoint + '/event', json=data, headers=headers)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result['_status'], 'ERR')
        self.assertEqual(result['_issues'], ['You must POST parameters on this endpoint.'])

        self.assertEqual(my_module.received_commands, 0)

        # Notify an host event - missing host or service
        headers = {'Content-Type': 'application/json'}
        data = {
            "fake": ""
        }
        self.assertEqual(my_module.received_commands, 0)
        response = session.post(self.ws_endpoint + '/event', json=data, headers=headers)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result, {'_status': 'ERR', '_issues': ['Missing host and/or service parameter.']})

        # Notify an host event - missing comment
        headers = {'Content-Type': 'application/json'}
        data = {
            "host": "test_host",
        }
        response = session.post(self.ws_endpoint + '/event', json=data, headers=headers)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result, {'_status': 'ERR',
                                  '_issues': ['Missing comment. If you do not have any comment, '
                                              'do not comment ;)']})

        # Notify an host event - default author
        headers = {'Content-Type': 'application/json'}
        data = {
            "host": "test_host",
            "comment": "My comment"
        }
        response = session.post(self.ws_endpoint + '/event', json=data, headers=headers)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result, {'_status': 'OK',
                                  '_result': ['ADD_HOST_COMMENT;test_host;1;'
                                              'Alignak WS;My comment']})

        # Notify an host event - default author and timestamp
        headers = {'Content-Type': 'application/json'}
        data = {
            "timestamp": 1234567890,
            "host": "test_host",
            "author": "Me",
            "comment": "My comment"
        }
        response = session.post(self.ws_endpoint + '/event', json=data, headers=headers)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result, {'_status': 'OK',
                                  '_result': ['[1234567890] ADD_HOST_COMMENT;test_host;1;'
                                              'Me;My comment']})

        # Notify a service event - default author
        headers = {'Content-Type': 'application/json'}
        data = {
            "host": "test_host",
            "service": "test_service",
            "comment": "My comment"
        }
        response = session.post(self.ws_endpoint + '/event', json=data, headers=headers)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result, {'_status': 'OK',
                                  '_result': ['ADD_SVC_COMMENT;test_host;test_service;1;'
                                              'Alignak WS;My comment']})

        # Notify a service event - default author and timestamp
        headers = {'Content-Type': 'application/json'}
        data = {
            "timestamp": 1234567890,
            "host": "test_host",
            "service": "test_service",
            "author": "Me",
            "comment": "My comment"
        }
        response = session.post(self.ws_endpoint + '/event', json=data, headers=headers)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result, {'_status': 'OK',
                                  '_result': ['[1234567890] ADD_SVC_COMMENT;test_host;test_service;'
                                              '1;Me;My comment']})

        # Get history to confirm that backend is ready
        # ---
        response = session.get(self.endpoint + '/history', auth=self.auth,
                               params={"sort": "-_id", "max_results": 25, "page": 1})
        resp = response.json()
        print(("Response: %s" % resp))
        for item in resp['_items']:
            assert item['type'] in ['webui.comment']
        # Got 4 notified events, so we get 4 comments in the backend
        self.assertEqual(len(resp['_items']), 4)
        # ---

        # Logout
        response = session.get(self.ws_endpoint + '/logout')
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result['_status'], 'OK')
        self.assertEqual(result['_result'], 'Logged out')

        self.modulemanager.stop_all()
class TestModuleWsHistory(AlignakTest):

    @classmethod
    def setUpClass(cls):

        # Set test mode for alignak backend
        os.environ['TEST_ALIGNAK_BACKEND'] = '1'
        os.environ['ALIGNAK_BACKEND_MONGO_DBNAME'] = 'alignak-module-ws-backend-test'

        # Delete used mongo DBs
        print ("Deleting Alignak backend DB...")
        exit_code = subprocess.call(
            shlex.split(
                'mongo %s --eval "db.dropDatabase()"' % os.environ['ALIGNAK_BACKEND_MONGO_DBNAME'])
        )
        assert exit_code == 0

        cls.p = subprocess.Popen(['uwsgi', '--plugin', 'python', '-w', 'alignakbackend:app',
                                  '--socket', '0.0.0.0:5000',
                                  '--protocol=http', '--enable-threads', '--pidfile',
                                  '/tmp/uwsgi.pid'])
        time.sleep(3)

        cls.endpoint = 'http://127.0.0.1:5000'

        # Backend authentication
        headers = {'Content-Type': 'application/json'}
        params = {'username': '******', 'password': '******'}
        # Get admin user token (force regenerate)
        response = requests.post(cls.endpoint + '/login', json=params, headers=headers)
        resp = response.json()
        cls.token = resp['token']
        cls.auth = requests.auth.HTTPBasicAuth(cls.token, '')

        # Get admin user
        response = requests.get(cls.endpoint + '/user', auth=cls.auth)
        resp = response.json()
        cls.user_admin = resp['_items'][0]

        # Get realms
        response = requests.get(cls.endpoint + '/realm', auth=cls.auth)
        resp = response.json()
        cls.realmAll_id = resp['_items'][0]['_id']

        # Add a user
        data = {'name': 'test', 'password': '******', 'back_role_super_admin': False,
                'host_notification_period': cls.user_admin['host_notification_period'],
                'service_notification_period': cls.user_admin['service_notification_period'],
                '_realm': cls.realmAll_id}
        response = requests.post(cls.endpoint + '/user', json=data, headers=headers,
                                 auth=cls.auth)
        resp = response.json()
        print("Created a new user: %s" % resp)

        # Get new user restrict role
        params = {'where': json.dumps({'user': resp['_id']})}
        response = requests.get(cls.endpoint + '/userrestrictrole', params=params, auth=cls.auth)
        resp = response.json()

        # Update user's rights - set full CRUD rights
        headers = {'Content-Type': 'application/json', 'If-Match': resp['_items'][0]['_etag']}
        data = {'crud': ['create', 'read', 'update', 'delete', 'custom']}
        resp = requests.patch(cls.endpoint + '/userrestrictrole/' + resp['_items'][0]['_id'],
                              json=data, headers=headers, auth=cls.auth)
        resp = resp.json()
        assert resp['_status'] == 'OK'

        # Add command
        data = {
            "name": "ping",
            "command_line": "check_ping -H $HOSTADDRESS$",
            "_realm": cls.realmAll_id
        }
        requests.post(cls.endpoint + '/command', json=data, headers=headers, auth=cls.auth)
        response = requests.get(cls.endpoint + '/command', auth=cls.auth)
        resp = response.json()
        cls.rc = resp['_items']

        # Add an host
        data = {
            "name": "srv001",
            "address": "192.168.0.2",
            "business_impact": 5,
            "check_command": cls.rc[0]['_id'],
            "_realm": cls.realmAll_id
        }
        response = requests.post(cls.endpoint + '/host', json=data, headers=headers, auth=cls.auth)
        response = requests.get(cls.endpoint + '/host?where={"name":"srv001"}', auth=cls.auth)
        resp = response.json()
        cls.rh = resp['_items']

        # Add a service
        data = {
            "name": "ping",
            "host": cls.rh[0]['_id'],
            "check_command": cls.rc[0]['_id'],
            "business_impact": 4,
            "_realm": cls.realmAll_id
        }
        response = requests.post(cls.endpoint + '/service', json=data, headers=headers, auth=cls.auth)
        response = requests.get(cls.endpoint + '/service', auth=cls.auth)
        resp = response.json()
        cls.rs = resp['_items']

        cls.modulemanager = None

    @classmethod
    def tearDownClass(cls):
        cls.p.kill()

    def setUp(self):
        """Create resources in backend

        :return: None
        """

    def tearDown(self):
        for resource in ['logcheckresult', 'history']:
            requests.delete('http://127.0.0.1:5000/' + resource, auth=self.auth)
        if self.modulemanager:
            time.sleep(1)
            self.modulemanager.stop_all()

    def file_dump(self, data, filename):  # pylint: disable=no-self-use
        """Dump the data to a JSON formatted file
        :param data: data to be dumped
        :param filename: name of the file to use. Only the file name, not the full path!
        :return: dumped file absolute file name
        """
        dump = json.dumps(data, indent=4,
                          separators=(',', ': '), sort_keys=True)
        path = os.path.join(self.folder or os.getcwd(), filename)
        try:
            dfile = open(path, "wt")
            dfile.write(dump)
            dfile.close()
            return path
        except (OSError, IndexError) as exp:  # pragma: no cover, should never happen
            print("Error when writing the list dump file %s : %s" % (path, str(exp)))
            assert False
        return None

    def test_module_zzz_get_history_admin(self):
        """Test the module log collection functions
        :return:
        """
        self.print_header()
        self._get_history("admin", "admin")

    def test_module_zzz_get_history_test(self):
        """Test the module log collection functions
        :return:
        """
        self.print_header()
        self._get_history("test", "test")

    def _get_history(self, username, password):

        # Obliged to call to get a self.logger...
        self.setup_with_file('cfg/cfg_default.cfg')
        self.assertTrue(self.conf_is_correct)

        # -----
        # Provide parameters - logger configuration file (exists)
        # -----
        # Clear logs
        self.clear_logs()

        # Create an Alignak module
        mod = Module({
            'module_alias': 'web-services',
            'module_types': 'web-services',
            'python_name': 'alignak_module_ws',
            # Set Arbiter address as empty to not poll the Arbiter else the test will fail!
            'alignak_host': '',
            'alignak_port': 7770,
            # Alignak backend URL
            'alignak_backend': 'http://127.0.0.1:5000',
            'username': '******',
            'password': '******',
            # Activate CherryPy file logs
            'log_access': '/tmp/alignak-module-ws-access.log',
            'log_error': '/tmp/alignak-module-ws-error.log',
        })

        # Create the modules manager for a daemon type
        self.modulemanager = ModulesManager('receiver', None)

        # Load an initialize the modules:
        #  - load python module
        #  - get module properties and instances
        self.modulemanager.load_and_init([mod])

        my_module = self.modulemanager.instances[0]

        # Clear logs
        self.clear_logs()

        # Start external modules
        self.modulemanager.start_external_instances()

        # Starting external module logs
        self.assert_log_match("Trying to initialize module: web-services", 0)
        self.assert_log_match("Starting external module web-services", 1)
        self.assert_log_match("Starting external process for module web-services", 2)
        self.assert_log_match("web-services is now started", 3)

        time.sleep(1)

        # Check alive
        self.assertIsNotNone(my_module.process)
        self.assertTrue(my_module.process.is_alive())

        time.sleep(1)

        # ---
        # Prepare the backend content...
        self.endpoint = 'http://127.0.0.1:5000'

        headers = {'Content-Type': 'application/json'}
        params = {'username': '******', 'password': '******'}
        # get token
        response = requests.post(self.endpoint + '/login', json=params, headers=headers)
        resp = response.json()
        self.token = resp['token']
        self.auth = requests.auth.HTTPBasicAuth(self.token, '')

        # Get default realm
        response = requests.get(self.endpoint + '/realm', auth=self.auth)
        resp = response.json()
        self.realm_all = resp['_items'][0]['_id']
        # ---

        # -------------------------------------------
        # Add a check result for an host
        data = {
            "last_check": 1496332753,
            "host": self.rh[0]['_id'],
            "service": None,
            'acknowledged': False,
            'state_id': 0,
            'state': 'UP',
            'state_type': 'HARD',
            'last_state_id': 0,
            'last_state': 'UP',
            'last_state_type': 'HARD',
            'state_changed': False,
            'latency': 0,
            'execution_time': 0.12,
            'output': 'Check output',
            'long_output': 'Check long_output',
            'perf_data': 'perf_data',
            "_realm": self.realm_all
        }
        response = requests.post(
            self.endpoint + '/logcheckresult', json=data, headers=headers, auth=self.auth
        )
        resp = response.json()
        self.assertEqual(resp['_status'], 'OK')

        # -------------------------------------------
        # Add a check result for a service
        data = {
            "last_check": 1496332754,
            "host": self.rh[0]['_id'],
            "service": self.rs[0]['_id'],
            'acknowledged': False,
            'state_id': 0,
            'state': 'UP',
            'state_type': 'HARD',
            'last_state_id': 0,
            'last_state': 'UP',
            'last_state_type': 'HARD',
            'state_changed': False,
            'latency': 0,
            'execution_time': 0.12,
            'output': 'Check output',
            'long_output': 'Check long_output',
            'perf_data': 'perf_data',
            "_realm": self.realm_all
        }
        response = requests.post(
            self.endpoint + '/logcheckresult', json=data, headers=headers, auth=self.auth
        )
        resp = response.json()
        self.assertEqual(resp['_status'], 'OK')
        # Add an history event
        data = {
            "host_name": "chazay",
            "service_name": "Processus",
            "user_name": "Alignak",
            "type": "check.result",
            "message": "OK[HARD] (False,False): All is ok",
            "_realm": self.realm_all,
            "_sub_realm": True
        }
        time.sleep(1)
        requests.post(self.endpoint + '/history', json=data, headers=headers, auth=self.auth)

        # Add an history event
        time.sleep(1)
        data = {
            "host_name": "denice",
            "service_name": "Zombies",
            "user_name": "Alignak",
            "type": "check.result",
            "message": "OK[HARD] (False,False): All is ok",
            "_realm": self.realm_all,
            "_sub_realm": True
        }
        requests.post(self.endpoint + '/history', json=data, headers=headers, auth=self.auth)

        # Add an history event
        time.sleep(1)
        data = {
            "host_name": "denice",
            "user_name": "Me",
            "type": "monitoring.alert",
            "message": "HOST ALERT ....",
            "_realm": self.realm_all,
            "_sub_realm": True
        }
        requests.post(self.endpoint + '/history', json=data, headers=headers, auth=self.auth)
        # ---

        # ---
        # Get history to confirm that backend is ready
        # ---
        response = requests.get(self.endpoint + '/history', auth=self.auth,
                                params={"sort": "-_id", "max_results": 25, "page": 1, 'embedded': json.dumps({"logcheckresult": 1})})
        resp = response.json()
        pprint(resp['_items'])
        self.assertEqual(len(resp['_items']), 5)

        # Backend real history
        # The commented fields are the one existing in the backend but filtered by the WS
        backend_real_history = [
            {
                u'_created': u'Thu, 01 Jun 2017 15:59:16 GMT',
                # u'_etag': u'9f07c7285b37bb3d336a96ede3d3fd2a774c4c4c',
                u'_id': u'593039d406fd4b3bf0e27d9f',
                # u'_links': {u'self': {u'href': u'history/593039d406fd4b3bf0e27d9f',
                #                       u'title': u'History'}},
                # u'_realm': u'593039cc06fd4b3bf0e27d88',
                # u'_sub_realm': True,
                # u'_updated': u'Thu, 01 Jun 2017 15:59:16 GMT',
                u'host_name': u'denice',
                u'message': u'HOST ALERT ....',
                u'type': u'monitoring.alert',
                u'user_name': u'Me'
            },
            {
                u'_created': u'Thu, 01 Jun 2017 15:59:15 GMT',
                # u'_etag': u'24cd486a1a28859a0177fbe15d1ead61f78f7b2c',
                u'_id': u'593039d306fd4b3bf0e27d9e',
                # u'_links': {u'self': {u'href': u'history/593039d306fd4b3bf0e27d9e',
                #                       u'title': u'History'}},
                # u'_realm': u'593039cc06fd4b3bf0e27d88',
                # u'_sub_realm': True,
                # u'_updated': u'Thu, 01 Jun 2017 15:59:15 GMT',
                u'host_name': u'denice',
                u'message': u'OK[HARD] (False,False): All is ok',
                u'service_name': u'Zombies',
                u'type': u'check.result',
                u'user_name': u'Alignak'
            },
            {
                u'_created': u'Thu, 01 Jun 2017 15:59:14 GMT',
                # u'_etag': u'4c4ee43a4fac0b91dcfddb011619007dedb1cd95',
                u'_id': u'593039d206fd4b3bf0e27d9d',
                # u'_links': {u'self': {u'href': u'history/593039d206fd4b3bf0e27d9d',
                #                       u'title': u'History'}},
                # u'_realm': u'593039cc06fd4b3bf0e27d88',
                # u'_sub_realm': True,
                # u'_updated': u'Thu, 01 Jun 2017 15:59:14 GMT',
                u'host_name': u'chazay',
                u'message': u'OK[HARD] (False,False): All is ok',
                u'service_name': u'Processus',
                u'type': u'check.result',
                u'user_name': u'Alignak'
            },
            {u'_created': u'Thu, 01 Jun 2017 15:59:13 GMT',
             # u'_etag': u'76dd35f575244848dd41f67ad3109cf6f1f9a33c',
             u'_id': u'593039d106fd4b3bf0e27d9c',
             # u'_links': {u'self': {u'href': u'history/593039d106fd4b3bf0e27d9c',
             #                       u'title': u'History'}},
             # u'_realm': u'593039cc06fd4b3bf0e27d88',
             # u'_sub_realm': True,
             # u'_updated': u'Thu, 01 Jun 2017 15:59:13 GMT',
             # u'host': u'593039cc06fd4b3bf0e27d90',
             u'host_name': u'srv001',
             u'logcheckresult': {
                 u'_created': u'Thu, 01 Jun 2017 15:59:13 GMT',
                 # u'_etag': u'10a3935b1158fe4c8f62962a14b1050fef32df4b',
                 # u'_id': u'593039d106fd4b3bf0e27d9b',
                 # u'_realm': u'593039cc06fd4b3bf0e27d88',
                 # u'_sub_realm': True,
                 # u'_updated': u'Thu, 01 Jun 2017 15:59:13 GMT',
                 u'acknowledged': False,
                 u'acknowledgement_type': 1,
                 u'downtimed': False,
                 u'execution_time': 0.12,
                 # u'host': u'593039cc06fd4b3bf0e27d90',
                 # u'host_name': u'srv001',
                 u'last_check': 1496332753,
                 u'last_state': u'UP',
                 u'last_state_changed': 0,
                 u'last_state_id': 0,
                 u'last_state_type': u'HARD',
                 u'latency': 0.0,
                 u'long_output': u'Check long_output',
                 u'output': u'Check output',
                 u'passive_check': False,
                 u'perf_data': u'perf_data',
                 # u'service': u'593039cf06fd4b3bf0e27d98',
                 # u'service_name': u'ping',
                 u'state': u'UP',
                 u'state_changed': False,
                 u'state_id': 0,
                 u'state_type': u'HARD'
             },
             u'message': u'UP[HARD] (False/False): Check output',
             # u'service': u'593039cf06fd4b3bf0e27d98',
             u'service_name': u'ping',
             u'type': u'check.result',
             # u'user': None,
             u'user_name': u'Alignak'
             },
            {u'_created': u'Thu, 01 Jun 2017 15:59:13 GMT',
             # u'_etag': u'c3cd29587ad328325dc48af677b3a36157361a84',
             u'_id': u'593039d106fd4b3bf0e27d9a',
             # u'_links': {u'self': {u'href': u'history/593039d106fd4b3bf0e27d9a',
             #                       u'title': u'History'}},
             # u'_realm': u'593039cc06fd4b3bf0e27d88',
             # u'_sub_realm': True,
             # u'_updated': u'Thu, 01 Jun 2017 15:59:13 GMT',
             # u'host': u'593039cc06fd4b3bf0e27d90',
             u'host_name': u'srv001',
             u'logcheckresult': {
                 u'_created': u'Thu, 01 Jun 2017 15:59:13 GMT',
                 # u'_etag': u'0ea4c16f1e651a02772aa2bfa83070b47e7f6531',
                 # u'_id': u'593039d106fd4b3bf0e27d99',
                 # u'_realm': u'593039cc06fd4b3bf0e27d88',
                 # u'_sub_realm': True,
                 # u'_updated': u'Thu, 01 Jun 2017 15:59:13 GMT',
                 u'acknowledged': False,
                 u'acknowledgement_type': 1,
                 u'downtimed': False,
                 u'execution_time': 0.12,
                 # u'host': u'593039cc06fd4b3bf0e27d90',
                 # u'host_name': u'srv001',
                 u'last_check': 1496332754,
                 u'last_state': u'UP',
                 u'last_state_changed': 0,
                 u'last_state_id': 0,
                 u'last_state_type': u'HARD',
                 u'latency': 0.0,
                 u'long_output': u'Check long_output',
                 u'output': u'Check output',
                 u'passive_check': False,
                 u'perf_data': u'perf_data',
                 # u'service': None,
                 # u'service_name': u'',
                 u'state': u'UP',
                 u'state_changed': False,
                 u'state_id': 0,
                 u'state_type': u'HARD'
             },
             u'message': u'UP[HARD] (False/False): Check output',
             # u'service': None,
             u'service_name': u'',
             u'type': u'check.result',
             # u'user': None,
             u'user_name': u'Alignak'
             }
        ]
        # ---

        # ---
        # # Directly call the module function
        # search = {
        #     'page': 1,
        #     'max_results': 25
        # }
        # result = my_module.getBackendHistory(search)
        # print(result)
        # print("Page: %d, got: %d items" % (search["page"], len(result['items'])))
        # for item in result['items']:
        #     print(item)
        # assert len(result['items']) == 5

        # ---
        # Do not allow GET request on /alignak_logs - not yet authorized!
        response = requests.get('http://127.0.0.1:8888/alignak_logs')
        self.assertEqual(response.status_code, 401)

        session = requests.Session()

        # Login with username/password (real backend login)
        headers = {'Content-Type': 'application/json'}
        params = {'username': username, 'password': password}
        response = session.post('http://127.0.0.1:8888/login', json=params, headers=headers)
        assert response.status_code == 200
        resp = response.json()

        # ---
        # Get the alignak default history
        response = session.get('http://127.0.0.1:8888/alignak_logs')
        self.assertEqual(response.status_code, 200)
        result = response.json()
        # Remove fields that will obviously be different!
        for item in result['items']:
            del(item['_id'])
            del(item['_created'])
            # if 'logcheckresult' in item:
            #     del (item['logcheckresult']['_created'])
        for item in backend_real_history:
            del(item['_id'])
            del(item['_created'])
            if 'logcheckresult' in item:
                del (item['logcheckresult']['_created'])
        self.assertEqual(len(result['items']), 5)
        # Too complex comparison!!!
        # self.assertEqual(backend_real_history, result['items'])
        # assert cmp(backend_real_history, result['items']) == 0
        # ---

        # ---
        # Get the alignak default history, filter to get only check.result
        response = session.get('http://127.0.0.1:8888/alignak_logs?search=type:check.result')
        self.assertEqual(response.status_code, 200)
        result = response.json()
        for item in result['items']:
            print(item)
        self.assertEqual(len(result['items']), 4)
        # ---

        # ---
        # Get the alignak default history, filter to get only for a user
        response = session.get('http://127.0.0.1:8888/alignak_logs?search=user_name:Alignak')
        self.assertEqual(response.status_code, 200)
        result = response.json()
        for item in result['items']:
            print(item)
        self.assertEqual(len(result['items']), 4)
        response = session.get('http://127.0.0.1:8888/alignak_logs?search=user_name:Me')
        self.assertEqual(response.status_code, 200)
        result = response.json()
        for item in result['items']:
            print(item)
        self.assertEqual(len(result['items']), 1)
        # ---

        # ---
        # Get the alignak default history, filter to get only for an host
        response = session.get('http://127.0.0.1:8888/alignak_logs?search=host_name:chazay')
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(len(result['items']), 1)
        # Implicit host_name
        response = session.get('http://127.0.0.1:8888/alignak_logs?search=chazay')
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(len(result['items']), 1)
        # Unknown search field
        response = session.get('http://127.0.0.1:8888/alignak_logs?search=name:chazay')
        self.assertEqual(response.status_code, 200)
        result = response.json()
        # All history items because name is not aknown search field! So we get all items...
        self.assertEqual(len(result['items']), 5)

        # Some other hosts...
        response = session.get('http://127.0.0.1:8888/alignak_logs?search=host_name:denice')
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(len(result['items']), 2)
        response = session.get('http://127.0.0.1:8888/alignak_logs?search=host_name:srv001')
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(len(result['items']), 2)

        # Several hosts...
        response = session.get('http://127.0.0.1:8888/alignak_logs?search=host_name:denice host_name:srv001')
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(len(result['items']), 4)   # 2 for each host

        # Not an host...
        # TODO: looks that ths criteria is not correctly implemented :(
        # response = session.get('http://127.0.0.1:8888/alignak_logs?search=host_name:!denice')
        # self.assertEqual(response.status_code, 200)
        # result = response.json()
        # self.assertEqual(len(result['items']), 3)
        # ---

        # ---
        # Get the alignak default history, NOT for an host
        # todo: temporarily skipped
        # response = requests.get('http://127.0.0.1:8888/alignak_logs?search=host_name:!Chazay')
        # self.assertEqual(response.status_code, 200)
        # result = response.json()
        # for item in result['items']:
        #     print(item)
        # self.assertEqual(len(result['items']), 2)
        # ---

        # ---
        # Get the alignak default history, only for a service
        response = session.get('http://127.0.0.1:8888/alignak_logs?search=service_name:Processus')
        self.assertEqual(response.status_code, 200)
        result = response.json()
        for item in result['items']:
            print(item)
        self.assertEqual(len(result['items']), 1)
        # ---

        # ---
        # Get the alignak default history, for an host and a service
        # todo multi search query to be improved!
        # response = session.get('http://127.0.0.1:8888/alignak_logs?search="host_name:chazay service_name=Processus"')
        # self.assertEqual(response.status_code, 200)
        # result = response.json()
        # for item in result['items']:
        #     print(item)
        # self.assertEqual(len(result['items']), 3)
        # ---

        # ---
        # Get the alignak default history, unknown event type
        response = session.get('http://127.0.0.1:8888/alignak_logs?search=type:XXX')
        self.assertEqual(response.status_code, 200)
        result = response.json()
        for item in result['items']:
            print(item)
        self.assertEqual(len(result['items']), 0)
        # ---

        # ---
        # Get the alignak default history, page count
        response = session.get('http://127.0.0.1:8888/alignak_logs?start=0&count=1')
        self.assertEqual(response.status_code, 200)
        result = response.json()
        for item in result['items']:
            print(item)
        self.assertEqual(len(result['items']), 1)
        response = session.get('http://127.0.0.1:8888/alignak_logs?start=1&count=1')
        self.assertEqual(response.status_code, 200)
        result = response.json()
        for item in result['items']:
            print(item)
        self.assertEqual(len(result['items']), 1)
        response = session.get('http://127.0.0.1:8888/alignak_logs?start=2&count=1')
        self.assertEqual(response.status_code, 200)
        result = response.json()
        for item in result['items']:
            print(item)
        self.assertEqual(len(result['items']), 1)
        response = session.get('http://127.0.0.1:8888/alignak_logs?start=3&count=1')
        self.assertEqual(response.status_code, 200)
        result = response.json()
        for item in result['items']:
            print(item)
        self.assertEqual(len(result['items']), 1)
        response = session.get('http://127.0.0.1:8888/alignak_logs?start=4&count=1')
        self.assertEqual(response.status_code, 200)
        result = response.json()
        for item in result['items']:
            print(item)
        self.assertEqual(len(result['items']), 1)
        # Over the limits !
        response = session.get('http://127.0.0.1:8888/alignak_logs?start=5&count=1')
        self.assertEqual(response.status_code, 200)
        result = response.json()
        for item in result['items']:
            print(item)
        self.assertEqual(len(result['items']), 0)
        response = session.get('http://127.0.0.1:8888/alignak_logs?start=50&count=50')
        self.assertEqual(response.status_code, 200)
        result = response.json()
        for item in result['items']:
            print(item)
        self.assertEqual(len(result['items']), 0)
        # ---

        # ---
        # Get the alignak history, page count greater than the number of items
        response = session.get('http://127.0.0.1:8888/alignak_logs?start=1&count=25')
        self.assertEqual(response.status_code, 200)
        result = response.json()
        pprint(result)
        self.assertEqual(len(result['items']), 5)   # Got 5 items
        self.assertEqual(result['_meta']['max_results'], 25)
        self.assertEqual(result['_meta']['page'], 1)
        self.assertEqual(result['_meta']['total'], 5)

        response = session.get('http://127.0.0.1:8888/alignak_logs?start=0&count=50')
        self.assertEqual(response.status_code, 200)
        result = response.json()
        pprint(result)
        self.assertEqual(len(result['items']), 5)   # Got 5 items
        self.assertEqual(result['_meta']['max_results'], 50)
        self.assertEqual(result['_meta']['page'], 1)
        self.assertEqual(result['_meta']['total'], 5)

        # ---

        # Logout
        response = session.get('http://127.0.0.1:8888/logout')
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result['_status'], 'OK')
        self.assertEqual(result['_result'], 'Logged out')

    @pytest.mark.skip("Internal function to get from an existing backend")
    def _get_from_backend(self, backend_url='http://127.0.01:5000',
                          host_name='test', file_name='history.json'):
        """Get the all history for an host in an existing backend.
        Dumps the resulting information as a JSON array to a file

        :return:
        """
        self.print_header()
        # Obliged to call to get a self.logger...
        self.setup_with_file('cfg/cfg_default.cfg')
        self.assertTrue(self.conf_is_correct)

        # -----
        # Provide parameters - logger configuration file (exists)
        # -----
        # Clear logs
        self.clear_logs()

        # Create an Alignak module
        mod = Module({
            'module_alias': 'web-services',
            'module_types': 'web-services',
            'python_name': 'alignak_module_ws',
            # Set Arbiter address as empty to not poll the Arbiter else the test will fail!
            'alignak_host': '',
            'alignak_port': 7770,
            # Alignak backend URL
            'alignak_backend': backend_url,
            'username': '******',
            'password': '******',
        })

        # Create the modules manager for a daemon type
        self.modulemanager = ModulesManager('receiver', None)

        # Load an initialize the modules:
        #  - load python module
        #  - get module properties and instances
        self.modulemanager.load_and_init([mod])

        my_module = self.modulemanager.instances[0]

        # Clear logs
        self.clear_logs()

        # Start external modules
        self.modulemanager.start_external_instances()

        # Starting external module logs
        self.assert_log_match("Trying to initialize module: web-services", 0)
        self.assert_log_match("Starting external module web-services", 1)
        self.assert_log_match("Starting external process for module web-services", 2)
        self.assert_log_match("web-services is now started", 3)

        time.sleep(2)

        # Check alive
        self.assertIsNotNone(my_module.process)
        self.assertTrue(my_module.process.is_alive())

        time.sleep(1)

        # ---

        # Start with first page ... max_results=3
        page = 1
        count = 25
        items = []
        search = {
            'page': page,
            'max_results': count
        }
        where = Helper.decode_search(host_name)
        if where:
            search.update({'where': json.dumps(where)})

        while count > 0:
            result = my_module.getBackendHistory(search)
            count = len(result['items'])
            print("Page: %d, got: %d items" % (search["page"], count))
            for item in result['items']:
                sys.stdout.write('.')
                # print(item)
            items.extend(result['items'])
            search["page"] += 1
        print("Got: %d items" % len(items))

        self.folder = '/tmp'
        self.file_dump(items, file_name)
Ejemplo n.º 10
0
class TestModuleWsCommand(AlignakTest):
    """This class contains the tests for the module"""
    @classmethod
    def setUpClass(cls):

        # Simulate an Alignak receiver daemon
        cls.ws_endpoint = 'http://127.0.0.1:7773/ws'
        import cherrypy

        class ReceiverItf(object):
            @cherrypy.expose
            def index(self):
                return "I am the Receiver daemon!"

        from alignak.http.daemon import HTTPDaemon as AlignakDaemon
        http_daemon1 = AlignakDaemon('0.0.0.0', 7773, ReceiverItf(), False,
                                     None, None, None, None, 10,
                                     '/tmp/alignak-cherrypy.log')

        def run_http_server():
            http_daemon1.run()

        import threading
        cls.http_thread1 = threading.Thread(target=run_http_server,
                                            name='http_server_receiver')
        cls.http_thread1.daemon = True
        cls.http_thread1.start()
        print("Thread started")

        # Set test mode for alignak backend
        os.environ['TEST_ALIGNAK_BACKEND'] = '1'
        os.environ[
            'ALIGNAK_BACKEND_MONGO_DBNAME'] = 'alignak-module-ws-command'

        # Delete used mongo DBs
        print("Deleting Alignak backend DB...")
        exit_code = subprocess.call(
            shlex.split('mongo %s --eval "db.dropDatabase()"' %
                        os.environ['ALIGNAK_BACKEND_MONGO_DBNAME']))
        assert exit_code == 0

        fnull = open(os.devnull, 'w')
        cls.p = subprocess.Popen([
            'uwsgi', '--plugin', 'python', '-w', 'alignakbackend:app',
            '--socket', '0.0.0.0:5000', '--protocol=http', '--enable-threads',
            '--pidfile', '/tmp/uwsgi.pid'
        ],
                                 stdout=fnull,
                                 stderr=fnull)
        time.sleep(3)

        endpoint = 'http://127.0.0.1:5000'

        test_dir = os.path.dirname(os.path.realpath(__file__))
        print(("Current test directory: %s" % test_dir))

        print(("Feeding Alignak backend... %s" % test_dir))
        exit_code = subprocess.call(
            shlex.split(
                'alignak-backend-import --delete %s/cfg/cfg_default.cfg' %
                test_dir),
            # stdout=fnull, stderr=fnull
        )
        assert exit_code == 0
        print("Fed")

        # Backend authentication
        headers = {'Content-Type': 'application/json'}
        params = {'username': '******', 'password': '******'}
        # Get admin user token (force regenerate)
        response = requests.post(endpoint + '/login',
                                 json=params,
                                 headers=headers)
        resp = response.json()
        cls.token = resp['token']
        cls.auth = requests.auth.HTTPBasicAuth(cls.token, '')

        # Get admin user
        response = requests.get(endpoint + '/user', auth=cls.auth)
        resp = response.json()
        cls.user_admin = resp['_items'][0]

        # Get realms
        response = requests.get(endpoint + '/realm', auth=cls.auth)
        resp = response.json()
        cls.realmAll_id = resp['_items'][0]['_id']

        # Add a user
        data = {
            'name':
            'test',
            'password':
            '******',
            'back_role_super_admin':
            False,
            'host_notification_period':
            cls.user_admin['host_notification_period'],
            'service_notification_period':
            cls.user_admin['service_notification_period'],
            '_realm':
            cls.realmAll_id
        }
        response = requests.post(endpoint + '/user',
                                 json=data,
                                 headers=headers,
                                 auth=cls.auth)
        resp = response.json()
        print(("Created a new user: %s" % resp))

        # Get new user restrict role
        params = {'where': json.dumps({'user': resp['_id']})}
        response = requests.get(endpoint + '/userrestrictrole',
                                params=params,
                                auth=cls.auth)
        resp = response.json()

        # Update user's rights - set full CRUD rights
        headers = {
            'Content-Type': 'application/json',
            'If-Match': resp['_items'][0]['_etag']
        }
        data = {'crud': ['create', 'read', 'update', 'delete', 'custom']}
        resp = requests.patch(endpoint + '/userrestrictrole/' +
                              resp['_items'][0]['_id'],
                              json=data,
                              headers=headers,
                              auth=cls.auth)
        resp = resp.json()
        assert resp['_status'] == 'OK'

    @classmethod
    def tearDownClass(cls):
        cls.p.kill()

    def setUp(self):
        super(TestModuleWsCommand, self).setUp()

    def tearDown(self):
        super(TestModuleWsCommand, self).tearDown()
        if self.modulemanager:
            time.sleep(1)
            self.modulemanager.stop_all()

    def test_module_zzz_command(self):
        """ Test the WS /command endpoint
        :return:
        """
        # Create an Alignak module
        mod = Module({
            'module_alias': 'web-services',
            'module_types': 'web-services',
            'python_name': 'alignak_module_ws',
            # Alignak backend
            'alignak_backend': 'http://127.0.0.1:5000',
            'username': '******',
            'password': '******',
            # Set Arbiter address as empty to not poll the Arbiter else the test will fail!
            'alignak_host': '',
            'alignak_port': 7770,
            'authorization': '1'
        })

        # Create a receiver daemon
        args = {'env_file': '', 'daemon_name': 'receiver-master'}
        self._receiver_daemon = Receiver(**args)

        # Create the modules manager for the daemon
        self.modulemanager = ModulesManager(self._receiver_daemon)

        # Load an initialize the modules:
        #  - load python module
        #  - get module properties and instances
        self.modulemanager.load_and_init([mod])

        my_module = self.modulemanager.instances[0]

        # Clear logs
        self.clear_logs()

        # Start external modules
        self.modulemanager.start_external_instances()

        # Starting external module logs
        self.assert_log_match("Trying to initialize module: web-services", 0)
        self.assert_log_match("Starting external module web-services", 1)
        self.assert_log_match(
            "Starting external process for module web-services", 2)
        self.assert_log_match("web-services is now started", 3)

        # Check alive
        self.assertIsNotNone(my_module.process)
        self.assertTrue(my_module.process.is_alive())

        time.sleep(1)

        # Do not allow GET request on /command - not yet authorized
        response = requests.get(self.ws_endpoint + '/command')
        self.assertEqual(response.status_code, 401)

        session = requests.Session()

        # Login with username/password (real backend login)
        headers = {'Content-Type': 'application/json'}
        params = {'username': '******', 'password': '******'}
        response = session.post(self.ws_endpoint + '/login',
                                json=params,
                                headers=headers)
        assert response.status_code == 200
        resp = response.json()

        # Allowed request on /command
        response = session.get(self.ws_endpoint + '/command')
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result['_status'], 'ERR')
        self.assertEqual(result['_error'],
                         'You must only POST on this endpoint.')

        self.assertEqual(my_module.received_commands, 0)

        # You must have parameters when POSTing on /command
        headers = {'Content-Type': 'application/json'}
        data = {}
        response = session.post(self.ws_endpoint + '/command',
                                json=data,
                                headers=headers)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result['_status'], 'ERR')
        self.assertEqual(result['_error'],
                         'You must POST parameters on this endpoint.')

        self.assertEqual(my_module.received_commands, 0)

        # You must have a command parameter when POSTing on /command
        headers = {'Content-Type': 'application/json'}
        data = {
            # "command": "Command",
            "element": "test_host",
            "parameters": "abc;1"
        }
        self.assertEqual(my_module.received_commands, 0)
        response = session.post(self.ws_endpoint + '/command',
                                json=data,
                                headers=headers)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result['_status'], 'ERR')
        # Result error message
        self.assertEqual(result['_error'], 'Missing command parameter')

        # Request to execute an external command
        headers = {'Content-Type': 'application/json'}
        data = {
            "command": "Command",
            "element": "test_host",
            "parameters": "abc;1"
        }
        self.assertEqual(my_module.received_commands, 0)
        response = session.post(self.ws_endpoint + '/command',
                                json=data,
                                headers=headers)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result['_status'], 'OK')
        # Result is uppercase command, parameters are ordered
        self.assertEqual(result['_command'], 'COMMAND;test_host;abc;1')

        # Request to execute an external command with timestamp - bad value
        headers = {'Content-Type': 'application/json'}
        data = {
            "command": "Command",
            "timestamp": "text",
            "element": "test_host",
            "parameters": "abc;1"
        }
        self.assertEqual(my_module.received_commands, 1)
        response = session.post(self.ws_endpoint + '/command',
                                json=data,
                                headers=headers)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result, {
            '_status': 'ERR',
            '_error': 'Timestamp must be an integer value'
        })

        # Request to execute an external command with timestamp
        headers = {'Content-Type': 'application/json'}
        data = {
            "command": "command_command",
            "timestamp": "1234",
            "element": "test_host;test_service",
            "parameters": "1;abc;2"
        }
        self.assertEqual(my_module.received_commands, 1)
        response = session.post(self.ws_endpoint + '/command',
                                json=data,
                                headers=headers)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result['_status'], 'OK')
        # Result is uppercase command, parameters are ordered
        self.assertEqual(
            result['_command'],
            '[1234] COMMAND_COMMAND;test_host;test_service;1;abc;2')

        # Request to execute an external command
        headers = {'Content-Type': 'application/json'}
        data = {
            "command": "command_command",
            "element": "test_host;test_service",
            "parameters": "1;abc;2"
        }
        response = session.post(self.ws_endpoint + '/command',
                                json=data,
                                headers=headers)
        self.assertEqual(my_module.received_commands, 3)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result['_status'], 'OK')
        # Result is uppercase command, parameters are ordered
        self.assertEqual(result['_command'],
                         'COMMAND_COMMAND;test_host;test_service;1;abc;2')

        # Request to execute an external command
        headers = {'Content-Type': 'application/json'}
        data = {
            "command": "command_command",
            "element":
            "test_host/test_service",  # Accept / as an host/service separator
            "parameters": "1;abc;2"
        }
        response = session.post(self.ws_endpoint + '/command',
                                json=data,
                                headers=headers)
        self.assertEqual(my_module.received_commands, 4)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result['_status'], 'OK')
        # Result is uppercase command, parameters are ordered
        self.assertEqual(result['_command'],
                         'COMMAND_COMMAND;test_host;test_service;1;abc;2')

        # Request to execute an external command (Alignak modern syntax)
        headers = {'Content-Type': 'application/json'}
        data = {
            "command": "command_command",
            "host": "test_host",
            "service": "test_service",
            "parameters": "1;abc;2"
        }
        response = session.post(self.ws_endpoint + '/command',
                                json=data,
                                headers=headers)
        self.assertEqual(my_module.received_commands, 5)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result['_status'], 'OK')
        # Result is uppercase command, parameters are ordered
        self.assertEqual(result['_command'],
                         'COMMAND_COMMAND;test_host;test_service;1;abc;2')

        # Request to execute an external command (Alignak modern syntax)
        headers = {'Content-Type': 'application/json'}
        data = {
            "command": "command_command",
            "host": "test_host",
            "service": "test_service",
            "user": "******",
            "parameters": "1;abc;2"
        }
        response = session.post(self.ws_endpoint + '/command',
                                json=data,
                                headers=headers)
        self.assertEqual(my_module.received_commands, 6)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result['_status'], 'OK')
        # Result is uppercase command, parameters are ordered
        self.assertEqual(
            result['_command'],
            'COMMAND_COMMAND;test_host;test_service;test_user;1;abc;2')

        # Logout
        response = session.get(self.ws_endpoint + '/logout')
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result['_status'], 'OK')
        self.assertEqual(result['_result'], 'Logged out')

        self.modulemanager.stop_all()

    def test_module_zzz_command_unauthorized(self):
        """ Test the WS /command endpoint - unauthorized access mode
        :return:
        """
        # Create an Alignak module
        mod = Module({
            'module_alias': 'web-services',
            'module_types': 'web-services',
            'python_name': 'alignak_module_ws',
            # Alignak backend - not configured
            'alignak_backend': '',
            'username': '',
            'password': '',
            # Set Arbiter address as empty to not poll the Arbiter else the test will fail!
            'alignak_host': '',
            'alignak_port': 7770,
            # Disable authorization
            'authorization': '0'
        })

        # Create a receiver daemon
        args = {'env_file': '', 'daemon_name': 'receiver-master'}
        self._receiver_daemon = Receiver(**args)

        # Create the modules manager for the daemon
        self.modulemanager = ModulesManager(self._receiver_daemon)

        # Load an initialize the modules:
        #  - load python module
        #  - get module properties and instances
        self.modulemanager.load_and_init([mod])

        my_module = self.modulemanager.instances[0]

        # Clear logs
        self.clear_logs()

        # Start external modules
        self.modulemanager.start_external_instances()

        # Starting external module logs
        self.assert_log_match("Trying to initialize module: web-services", 0)
        self.assert_log_match("Starting external module web-services", 1)
        self.assert_log_match(
            "Starting external process for module web-services", 2)
        self.assert_log_match("web-services is now started", 3)

        # Check alive
        self.assertIsNotNone(my_module.process)
        self.assertTrue(my_module.process.is_alive())

        time.sleep(1)

        session = requests.Session()

        # You must have parameters when POSTing on /command
        headers = {'Content-Type': 'application/json'}
        data = {}
        response = session.post(self.ws_endpoint + '/command',
                                json=data,
                                headers=headers)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result['_status'], 'ERR')
        self.assertEqual(result['_error'],
                         'You must POST parameters on this endpoint.')

        self.assertEqual(my_module.received_commands, 0)

        # You must have a command parameter when POSTing on /command
        headers = {'Content-Type': 'application/json'}
        data = {
            # "command": "Command",
            "element": "test_host",
            "parameters": "abc;1"
        }
        self.assertEqual(my_module.received_commands, 0)
        response = session.post(self.ws_endpoint + '/command',
                                json=data,
                                headers=headers)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result['_status'], 'ERR')
        # Result error message
        self.assertEqual(result['_error'], 'Missing command parameter')

        # Request to execute an external command
        headers = {'Content-Type': 'application/json'}
        data = {
            "command": "Command",
            "element": "test_host",
            "parameters": "abc;1"
        }
        self.assertEqual(my_module.received_commands, 0)
        response = session.post(self.ws_endpoint + '/command',
                                json=data,
                                headers=headers)
        self.assertEqual(my_module.received_commands, 1)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result['_status'], 'OK')
        # Result is uppercase command, parameters are ordered
        self.assertEqual(result['_command'], 'COMMAND;test_host;abc;1')

        # Request to execute an external command with timestamp - bad value
        headers = {'Content-Type': 'application/json'}
        data = {
            "command": "Command",
            "timestamp": "text",
            "element": "test_host",
            "parameters": "abc;1"
        }
        response = session.post(self.ws_endpoint + '/command',
                                json=data,
                                headers=headers)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result, {
            '_status': 'ERR',
            '_error': 'Timestamp must be an integer value'
        })
        self.assertEqual(my_module.received_commands, 1)

        # Request to execute an external command with timestamp
        headers = {'Content-Type': 'application/json'}
        data = {
            "command": "command_command",
            "timestamp": "1234",
            "element": "test_host;test_service",
            "parameters": "1;abc;2"
        }
        response = session.post(self.ws_endpoint + '/command',
                                json=data,
                                headers=headers)
        self.assertEqual(my_module.received_commands, 2)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result['_status'], 'OK')
        # Result is uppercase command, parameters are ordered
        self.assertEqual(
            result['_command'],
            '[1234] COMMAND_COMMAND;test_host;test_service;1;abc;2')

        # Request to execute an external command
        headers = {'Content-Type': 'application/json'}
        data = {
            "command": "command_command",
            "element": "test_host;test_service",
            "parameters": "1;abc;2"
        }
        response = session.post(self.ws_endpoint + '/command',
                                json=data,
                                headers=headers)
        self.assertEqual(my_module.received_commands, 3)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result['_status'], 'OK')
        # Result is uppercase command, parameters are ordered
        self.assertEqual(result['_command'],
                         'COMMAND_COMMAND;test_host;test_service;1;abc;2')

        # Request to execute an external command
        headers = {'Content-Type': 'application/json'}
        data = {
            "command": "command_command",
            "element":
            "test_host/test_service",  # Accept / as an host/service separator
            "parameters": "1;abc;2"
        }
        response = session.post(self.ws_endpoint + '/command',
                                json=data,
                                headers=headers)
        self.assertEqual(my_module.received_commands, 4)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result['_status'], 'OK')
        # Result is uppercase command, parameters are ordered
        self.assertEqual(result['_command'],
                         'COMMAND_COMMAND;test_host;test_service;1;abc;2')

        # Request to execute an external command (Alignak modern syntax)
        headers = {'Content-Type': 'application/json'}
        data = {
            "command": "command_command",
            "host": "test_host",
            "service": "test_service",
            "parameters": "1;abc;2"
        }
        response = session.post(self.ws_endpoint + '/command',
                                json=data,
                                headers=headers)
        self.assertEqual(my_module.received_commands, 5)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result['_status'], 'OK')
        # Result is uppercase command, parameters are ordered
        self.assertEqual(result['_command'],
                         'COMMAND_COMMAND;test_host;test_service;1;abc;2')

        # Request to execute an external command (Alignak modern syntax)
        headers = {'Content-Type': 'application/json'}
        data = {
            "command": "command_command",
            "host": "test_host",
            "service": "test_service",
            "user": "******",
            "parameters": "1;abc;2"
        }
        response = session.post(self.ws_endpoint + '/command',
                                json=data,
                                headers=headers)
        self.assertEqual(my_module.received_commands, 6)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result['_status'], 'OK')
        # Result is uppercase command, parameters are ordered
        self.assertEqual(
            result['_command'],
            'COMMAND_COMMAND;test_host;test_service;test_user;1;abc;2')

        self.modulemanager.stop_all()
Ejemplo n.º 11
0
class TestModuleWsHostgroup(AlignakTest):
    """This class contains the tests for the module"""
    @classmethod
    def setUpClass(cls):

        # Set test mode for alignak backend
        os.environ['TEST_ALIGNAK_BACKEND'] = '1'
        os.environ[
            'ALIGNAK_BACKEND_MONGO_DBNAME'] = 'alignak-module-ws-backend-test'

        # Delete used mongo DBs
        print("Deleting Alignak backend DB...")
        exit_code = subprocess.call(
            shlex.split('mongo %s --eval "db.dropDatabase()"' %
                        os.environ['ALIGNAK_BACKEND_MONGO_DBNAME']))
        assert exit_code == 0

        fnull = open(os.devnull, 'w')
        cls.p = subprocess.Popen([
            'uwsgi', '--plugin', 'python', '-w', 'alignakbackend:app',
            '--socket', '0.0.0.0:5000', '--protocol=http', '--enable-threads',
            '--pidfile', '/tmp/uwsgi.pid'
        ],
                                 stdout=fnull,
                                 stderr=fnull)
        time.sleep(3)

        endpoint = 'http://127.0.0.1:5000'

        test_dir = os.path.dirname(os.path.realpath(__file__))
        print("Current test directory: %s" % test_dir)

        print("Feeding Alignak backend... %s" % test_dir)
        exit_code = subprocess.call(shlex.split(
            'alignak-backend-import --delete %s/cfg/cfg_default.cfg' %
            test_dir),
                                    stdout=fnull,
                                    stderr=fnull)
        assert exit_code == 0
        print("Fed")

        # Backend authentication
        headers = {'Content-Type': 'application/json'}
        params = {'username': '******', 'password': '******'}
        # Get admin user token (force regenerate)
        response = requests.post(endpoint + '/login',
                                 json=params,
                                 headers=headers)
        resp = response.json()
        cls.token = resp['token']
        cls.auth = requests.auth.HTTPBasicAuth(cls.token, '')

        # Get admin user
        response = requests.get(endpoint + '/user', auth=cls.auth)
        resp = response.json()
        cls.user_admin = resp['_items'][0]

        # Get realms
        response = requests.get(endpoint + '/realm', auth=cls.auth)
        resp = response.json()
        cls.realmAll_id = resp['_items'][0]['_id']

        # Add a user
        data = {
            'name':
            'test',
            'password':
            '******',
            'back_role_super_admin':
            False,
            'host_notification_period':
            cls.user_admin['host_notification_period'],
            'service_notification_period':
            cls.user_admin['service_notification_period'],
            '_realm':
            cls.realmAll_id
        }
        response = requests.post(endpoint + '/user',
                                 json=data,
                                 headers=headers,
                                 auth=cls.auth)
        resp = response.json()
        print("Created a new user: %s" % resp)

        # Get new user restrict role
        params = {'where': json.dumps({'user': resp['_id']})}
        response = requests.get(endpoint + '/userrestrictrole',
                                params=params,
                                auth=cls.auth)
        resp = response.json()

        # Update user's rights - set full CRUD rights
        headers = {
            'Content-Type': 'application/json',
            'If-Match': resp['_items'][0]['_etag']
        }
        data = {'crud': ['create', 'read', 'update', 'delete', 'custom']}
        resp = requests.patch(endpoint + '/userrestrictrole/' +
                              resp['_items'][0]['_id'],
                              json=data,
                              headers=headers,
                              auth=cls.auth)
        resp = resp.json()
        assert resp['_status'] == 'OK'

    @classmethod
    def tearDownClass(cls):
        cls.p.kill()

    def setUp(self):
        """Create resources in backend

        :return: None
        """
        self.print_header()
        # Obliged to call to get a self.logger...
        self.setup_with_file('cfg/cfg_default.cfg')
        self.assertTrue(self.conf_is_correct)

        # -----
        # Provide parameters - logger configuration file (exists)
        # -----
        # Clear logs
        self.clear_logs()

        # Create an Alignak module
        mod = Module({
            'module_alias': 'web-services',
            'module_types': 'web-services',
            'python_name': 'alignak_module_ws',
            # Alignak backend
            'alignak_backend': 'http://127.0.0.1:5000',
            'username': '******',
            'password': '******',
            # Do not set a timestamp in the built external commands
            'set_timestamp': '0',
            # Set Arbiter address as empty to not poll the Arbiter else the test will fail!
            'alignak_host': '',
            'alignak_port': 7770,
            # Allow host/service creation
            'allow_host_creation': '1',
            'allow_service_creation': '1'
        })

        # Create the modules manager for a daemon type
        self.modulemanager = ModulesManager('receiver', None)

        # Load an initialize the modules:
        #  - load python module
        #  - get module properties and instances
        self.modulemanager.load_and_init([mod])

        self.my_module = self.modulemanager.instances[0]

        # Clear logs
        self.clear_logs()

        # Start external modules
        self.modulemanager.start_external_instances()

        # Starting external module logs
        self.assert_log_match("Trying to initialize module: web-services", 0)
        self.assert_log_match("Starting external module web-services", 1)
        self.assert_log_match(
            "Starting external process for module web-services", 2)
        self.assert_log_match("web-services is now started", 3)

        # Check alive
        self.assertIsNotNone(self.my_module.process)
        self.assertTrue(self.my_module.process.is_alive())

        time.sleep(1)

    def tearDown(self):
        if self.modulemanager:
            time.sleep(1)
            self.modulemanager.stop_all()

    def test_module_zzz_hostgroup_get(self):
        """Test the module /hostgroup API - hostgroup get information
        :return:
        """
        # Do not allow GET request on /hostgroup - not yet authorized!
        response = requests.get('http://127.0.0.1:8888/hostgroup')
        self.assertEqual(response.status_code, 401)

        session = requests.Session()

        # Login with username/password (real backend login)
        headers = {'Content-Type': 'application/json'}
        params = {'username': '******', 'password': '******'}
        response = session.post('http://127.0.0.1:8888/login',
                                json=params,
                                headers=headers)
        assert response.status_code == 200
        resp = response.json()

        # -----
        # Get a non-existing host - 1st: use parameters in the request
        response = session.get('http://127.0.0.1:8888/hostgroup',
                               auth=self.auth,
                               params={'name': 'fake-hostgroup'})
        result = response.json()
        self.assertEqual(
            result, {
                u'_status': u'ERR',
                u'_result': [],
                u'_issues':
                ["Requested hostgroup 'fake-hostgroup' does not exist"]
            })

        # Get a non-existing host - 2nd: use hostgroup name in the URI
        response = session.get(
            'http://127.0.0.1:8888/hostgroup/fake-hostgroup', auth=self.auth)
        result = response.json()
        self.assertEqual(
            result, {
                u'_status': u'ERR',
                u'_result': [],
                u'_issues':
                ["Requested hostgroup 'fake-hostgroup' does not exist"]
            })

        # -----
        # Get all hostgroups ... no parameters!
        response = session.get('http://127.0.0.1:8888/hostgroup',
                               auth=self.auth)
        result = response.json()
        # from pprint import pprint
        # pprint(result)
        self.assertEqual(result['_status'], 'OK')
        self.assertIsNot(result['_result'], {})
        self.assertEqual(len(result['_result']), 13)

        # -----
        # Get a specific hostgroup - 1st: use parameters in the request
        response = session.get('http://127.0.0.1:8888/hostgroup',
                               auth=self.auth,
                               params={'name': 'hostgroup_01'})
        result = response.json()
        self.assertEqual(result['_status'], 'OK')
        self.assertIsNot(result['_result'], {})
        self.assertEqual(result['_result'][0]['name'], 'hostgroup_01')

        # Get a specific hostgroup - 2nd: use hostgroup name in the URI
        response = session.get('http://127.0.0.1:8888/hostgroup/hostgroup_01',
                               auth=self.auth)
        result = response.json()
        self.assertEqual(result['_status'], 'OK')
        self.assertIsNot(result['_result'], {})
        # Comparing is tricky because of the changing objects _id ...
        # self.assertEqual(result['_result'][0], {
        #     u'_level': 1, u'name': u'hostgroup_01', u'notes': u'', u'hostgroups': [],
        #     u'_parent': {u'alias': u'All hosts', u'name': u'All'}, u'alias': u'hostgroup_alias_01',
        #     u'hosts': [{u'alias': u'up_0', u'name': u'test_host_0'}],
        #     u'_tree_parents': [{u'alias': u'All hosts', u'name': u'All'}],
        #     u'_realm': {u'alias': u'All', u'name': u'All'}
        # })

        # Get a specific hostgroup - embed related items
        response = session.get('http://127.0.0.1:8888/hostgroup/hostgroup_01',
                               auth=self.auth,
                               params={'embedded': True})
        result = response.json()
        self.assertEqual(result['_status'], 'OK')
        self.assertIsNot(result['_result'], {})
        print(result['_result'][0])
        result['_result'][0].pop('_id')
        result['_result'][0].pop('_created')
        result['_result'][0].pop('_updated')
        self.assertEqual(
            result['_result'][0], {
                u'_level': 1,
                u'name': u'hostgroup_01',
                u'notes': u'',
                u'hostgroups': [],
                u'_parent': {
                    u'alias': u'All hosts',
                    u'name': u'All'
                },
                u'alias': u'hostgroup_alias_01',
                u'hosts': [{
                    u'alias': u'up_0',
                    u'name': u'test_host_0'
                }],
                u'_tree_parents': [{
                    u'alias': u'All hosts',
                    u'name': u'All'
                }],
                u'_realm': {
                    u'alias': u'All',
                    u'name': u'All'
                }
            })

        # -----
        # Logout
        response = session.get('http://127.0.0.1:8888/logout')
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result['_status'], 'OK')
        self.assertEqual(result['_result'], 'Logged out')
class TestModuleWsHostLivestate(AlignakTest):
    """This class contains the tests for the module"""
    @classmethod
    def setUpClass(cls):

        # Set test mode for alignak backend
        os.environ['TEST_ALIGNAK_BACKEND'] = '1'
        os.environ[
            'ALIGNAK_BACKEND_MONGO_DBNAME'] = 'alignak-module-ws-backend-test'

        # Delete used mongo DBs
        print("Deleting Alignak backend DB...")
        exit_code = subprocess.call(
            shlex.split('mongo %s --eval "db.dropDatabase()"' %
                        os.environ['ALIGNAK_BACKEND_MONGO_DBNAME']))
        assert exit_code == 0

        fnull = open(os.devnull, 'w')
        cls.p = subprocess.Popen([
            'uwsgi', '--plugin', 'python', '-w', 'alignakbackend:app',
            '--socket', '0.0.0.0:5000', '--protocol=http', '--enable-threads',
            '--pidfile', '/tmp/uwsgi.pid'
        ],
                                 stdout=fnull,
                                 stderr=fnull)
        time.sleep(3)

        endpoint = 'http://127.0.0.1:5000'

        test_dir = os.path.dirname(os.path.realpath(__file__))
        print("Current test directory: %s" % test_dir)

        print("Feeding Alignak backend...")
        print('alignak-backend-import --delete %s/cfg/cfg_default.cfg' %
              test_dir)
        exit_code = subprocess.call(shlex.split(
            'alignak-backend-import --delete %s/cfg/cfg_default.cfg' %
            test_dir),
                                    stdout=fnull,
                                    stderr=fnull)
        assert exit_code == 0
        print("Fed")

        # Backend authentication
        headers = {'Content-Type': 'application/json'}
        params = {'username': '******', 'password': '******'}
        # Get admin user token (force regenerate)
        response = requests.post(endpoint + '/login',
                                 json=params,
                                 headers=headers)
        resp = response.json()
        cls.token = resp['token']
        cls.auth = requests.auth.HTTPBasicAuth(cls.token, '')

        # Get admin user
        response = requests.get(endpoint + '/user', auth=cls.auth)
        resp = response.json()
        cls.user_admin = resp['_items'][0]

        # Get realms
        response = requests.get(endpoint + '/realm', auth=cls.auth)
        resp = response.json()
        cls.realmAll_id = resp['_items'][0]['_id']

        # Add a user
        data = {
            'name':
            'test',
            'password':
            '******',
            'back_role_super_admin':
            False,
            'host_notification_period':
            cls.user_admin['host_notification_period'],
            'service_notification_period':
            cls.user_admin['service_notification_period'],
            '_realm':
            cls.realmAll_id
        }
        response = requests.post(endpoint + '/user',
                                 json=data,
                                 headers=headers,
                                 auth=cls.auth)
        resp = response.json()
        print("Created a new user: %s" % resp)

        # Get new user restrict role
        params = {'where': json.dumps({'user': resp['_id']})}
        response = requests.get(endpoint + '/userrestrictrole',
                                params=params,
                                auth=cls.auth)
        resp = response.json()

        # Update user's rights - set full CRUD rights
        headers = {
            'Content-Type': 'application/json',
            'If-Match': resp['_items'][0]['_etag']
        }
        data = {'crud': ['create', 'read', 'update', 'delete', 'custom']}
        resp = requests.patch(endpoint + '/userrestrictrole/' +
                              resp['_items'][0]['_id'],
                              json=data,
                              headers=headers,
                              auth=cls.auth)
        resp = resp.json()
        assert resp['_status'] == 'OK'

        cls.modulemanager = None

    @classmethod
    def tearDownClass(cls):
        if cls.modulemanager:
            cls.modulemanager.stop_all()
        cls.p.kill()

    @classmethod
    def tearDown(cls):
        """Delete resources in backend

        :return: None
        """
        for resource in ['logcheckresult']:
            requests.delete('http://127.0.0.1:5000/' + resource, auth=cls.auth)

    def test_module_zzz_host_livestate(self):
        """Test the module /host API - host creation and livestate
        :return:
        """
        self.print_header()
        # Obliged to call to get a self.logger...
        self.setup_with_file('cfg/cfg_default.cfg')
        self.assertTrue(self.conf_is_correct)

        # -----
        # Provide parameters - logger configuration file (exists)
        # -----
        # Clear logs
        self.clear_logs()

        # Create an Alignak module
        mod = Module({
            'module_alias': 'web-services',
            'module_types': 'web-services',
            'python_name': 'alignak_module_ws',
            # Alignak backend
            'alignak_backend': 'http://127.0.0.1:5000',
            'username': '******',
            'password': '******',
            # Do not set a timestamp in the built external commands
            'set_timestamp': '0',
            # Send a log_check_result to the alignak backend
            'alignak_backend_old_lcr': '1',
            # Do not give feedback data
            'give_feedback': '0',
            'give_result': '1',
            # Set Arbiter address as empty to not poll the Arbiter else the test will fail!
            'alignak_host': '',
            'alignak_port': 7770,
            # Allow host/service creation
            'allow_host_creation': '1',
            'allow_service_creation': '1'
        })

        # Create the modules manager for a daemon type
        self.modulemanager = ModulesManager('receiver', None)

        # Load an initialize the modules:
        #  - load python module
        #  - get module properties and instances
        self.modulemanager.load_and_init([mod])

        my_module = self.modulemanager.instances[0]

        # Clear logs
        self.clear_logs()

        # Start external modules
        self.modulemanager.start_external_instances()

        # Starting external module logs
        self.assert_log_match("Trying to initialize module: web-services", 0)
        self.assert_log_match("Starting external module web-services", 1)
        self.assert_log_match(
            "Starting external process for module web-services", 2)
        self.assert_log_match("web-services is now started", 3)

        # Check alive
        self.assertIsNotNone(my_module.process)
        self.assertTrue(my_module.process.is_alive())

        time.sleep(1)

        # Alignak backend
        # ---
        self.endpoint = 'http://127.0.0.1:5000'
        headers = {'Content-Type': 'application/json'}
        params = {'username': '******', 'password': '******'}
        # get token
        response = requests.post(self.endpoint + '/login',
                                 json=params,
                                 headers=headers)
        resp = response.json()
        self.token = resp['token']
        self.auth = requests.auth.HTTPBasicAuth(self.token, '')

        # Do not allow GET request on /host - not authorized
        response = requests.get('http://127.0.0.1:8888/host')
        self.assertEqual(response.status_code, 401)

        session = requests.Session()

        # Login with username/password (real backend login)
        headers = {'Content-Type': 'application/json'}
        params = {'username': '******', 'password': '******'}
        response = session.post('http://127.0.0.1:8888/login',
                                json=params,
                                headers=headers)
        assert response.status_code == 200
        resp = response.json()

        # -----
        # Create a new host with an host livestate (heartbeat / host is alive): livestate
        data = {
            "name": "new_host_0",
            "livestate": {
                # No timestamp in the livestate
                "state": "UP",
                "output": "Output...",
                "long_output": "Long output...",
                "perf_data": "'counter'=1",
            }
        }
        self.assertEqual(my_module.received_commands, 0)
        response = session.patch('http://127.0.0.1:8888/host',
                                 json=data,
                                 headers=headers)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(
            result, {
                u'_status':
                u'OK',
                u'_result': [
                    u'new_host_0 is alive :)',
                    u"Requested host 'new_host_0' does not exist.",
                    u"Requested host 'new_host_0' created.",
                    u"PROCESS_HOST_CHECK_RESULT;new_host_0;0;Output...|'counter'=1\nLong output...",
                ]
            })
        # No errors!

        # Get new host in the backend
        response = requests.get(
            self.endpoint + '/host',
            auth=self.auth,
            params={'where': json.dumps({'name': 'new_host_0'})})
        resp = response.json()
        new_host_0 = resp['_items'][0]
        self.assertEqual('new_host_0', new_host_0['name'])

        # Get backend check results - no check result sent to the backend
        response = requests.get(self.endpoint + '/logcheckresult',
                                auth=self.auth)
        resp = response.json()
        rl = resp['_items']
        self.assertEqual(len(rl), 0)

        # -----
        # Send an host livestate
        data = {
            "name": "new_host_0",
            "livestate": {
                # No timestamp in the livestate
                "state": "UP",
                "output": "Output...",
                "long_output": "Long output...",
                "perf_data": "'counter'=1",
            }
        }
        self.assertEqual(my_module.received_commands, 0)
        response = session.patch('http://127.0.0.1:8888/host',
                                 json=data,
                                 headers=headers)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(
            result, {
                u'_status':
                u'OK',
                u'_result': [
                    u'new_host_0 is alive :)',
                    u"PROCESS_HOST_CHECK_RESULT;new_host_0;0;Output...|'counter'=1\nLong output...",
                ]
            })
        # No errors!

        # Get backend check results - no check result sent to the backend
        response = requests.get(self.endpoint + '/logcheckresult',
                                auth=self.auth)
        resp = response.json()
        rl = resp['_items']
        self.assertEqual(len(rl), 0)

        # -----
        # Send an host livestate with a timestamp in the past
        now = int(time.time()) - 3600
        data = {
            "name": "new_host_0",
            "livestate": {
                # Timestamp in the past
                "timestamp": now,
                "state": "UP",
                "output": "Output...",
                "long_output": "Long output...",
                "perf_data": "'counter'=1",
            }
        }
        self.assertEqual(my_module.received_commands, 0)
        response = session.patch('http://127.0.0.1:8888/host',
                                 json=data,
                                 headers=headers)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(
            result, {
                u'_status':
                u'OK',
                u'_result': [
                    u'new_host_0 is alive :)',
                    u"[%d] PROCESS_HOST_CHECK_RESULT;new_host_0;0;Output...|'counter'=1\nLong output..."
                    % now,
                ]
            })
        # No errors!

        # Get backend check results - a check result was recorded in the backend
        response = requests.get(self.endpoint + '/logcheckresult',
                                auth=self.auth)
        resp = response.json()
        rl = resp['_items']
        # A log check result was recorded...
        self.assertEqual(len(rl), 1)
        rl = resp['_items'][0]
        print("LCR: %s" % rl)
        # ...with the correct timestamp
        self.assertEqual(rl['host_name'], "new_host_0")
        self.assertEqual(rl['last_check'], now)

        # -----
        # Send an host livestate with a timestamp in the past but sooner than the former one
        now = now + 1800
        data = {
            "name": "new_host_0",
            "livestate": {
                # Timestamp in the past
                "timestamp": now,
                "state": "UP",
                "output": "Output...",
                "long_output": "Long output...",
                "perf_data": "'counter'=1",
            }
        }
        self.assertEqual(my_module.received_commands, 0)
        response = session.patch('http://127.0.0.1:8888/host',
                                 json=data,
                                 headers=headers)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(
            result, {
                u'_status':
                u'OK',
                u'_result': [
                    u'new_host_0 is alive :)',
                    u"[%d] PROCESS_HOST_CHECK_RESULT;new_host_0;0;Output...|'counter'=1\nLong output..."
                    % now,
                ]
            })
        # No errors!

        # Get backend check results - one more check result was recorded in the backend
        response = requests.get(self.endpoint + '/logcheckresult',
                                auth=self.auth)
        resp = response.json()
        rl = resp['_items']
        # A log check result was recorded...
        self.assertEqual(len(rl), 2)
        # Get the second LCR
        rl = resp['_items'][1]
        print("LCR: %s" % rl)
        # ...with the correct timestamp
        self.assertEqual(rl['host_name'], "new_host_0")
        self.assertEqual(rl['last_check'], now)

        # Logout
        response = session.get('http://127.0.0.1:8888/logout')
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result['_status'], 'OK')
        self.assertEqual(result['_result'], 'Logged out')

        self.modulemanager.stop_all()

    def test_module_zzz_service_livestate(self):
        """Test the module /host API - service creation and livestate
        :return:
        """
        self.print_header()
        # Obliged to call to get a self.logger...
        self.setup_with_file('cfg/cfg_default.cfg')
        self.assertTrue(self.conf_is_correct)

        # -----
        # Provide parameters - logger configuration file (exists)
        # -----
        # Clear logs
        self.clear_logs()

        # Create an Alignak module
        mod = Module({
            'module_alias': 'web-services',
            'module_types': 'web-services',
            'python_name': 'alignak_module_ws',
            # Alignak backend
            'alignak_backend': 'http://127.0.0.1:5000',
            'username': '******',
            'password': '******',
            # Do not set a timestamp in the built external commands
            'set_timestamp': '0',
            # Send a log_check_result to the alignak backend
            'alignak_backend_old_lcr': '1',
            # Do not give feedback data
            'give_feedback': '0',
            'give_result': '1',
            # Set Arbiter address as empty to not poll the Arbiter else the test will fail!
            'alignak_host': '',
            'alignak_port': 7770,
            # Allow host/service creation
            'allow_host_creation': '1',
            'allow_service_creation': '1'
        })

        # Create the modules manager for a daemon type
        self.modulemanager = ModulesManager('receiver', None)

        # Load an initialize the modules:
        #  - load python module
        #  - get module properties and instances
        self.modulemanager.load_and_init([mod])

        my_module = self.modulemanager.instances[0]

        # Clear logs
        self.clear_logs()

        # Start external modules
        self.modulemanager.start_external_instances()

        # Starting external module logs
        self.assert_log_match("Trying to initialize module: web-services", 0)
        self.assert_log_match("Starting external module web-services", 1)
        self.assert_log_match(
            "Starting external process for module web-services", 2)
        self.assert_log_match("web-services is now started", 3)

        # Check alive
        self.assertIsNotNone(my_module.process)
        self.assertTrue(my_module.process.is_alive())

        time.sleep(1)

        # Alignak backend
        # ---
        self.endpoint = 'http://127.0.0.1:5000'
        headers = {'Content-Type': 'application/json'}
        params = {'username': '******', 'password': '******'}
        # get token
        response = requests.post(self.endpoint + '/login',
                                 json=params,
                                 headers=headers)
        resp = response.json()
        self.token = resp['token']
        self.auth = requests.auth.HTTPBasicAuth(self.token, '')

        # Do not allow GET request on /host - not authorized
        response = requests.get('http://127.0.0.1:8888/host')
        self.assertEqual(response.status_code, 401)

        session = requests.Session()

        # Login with username/password (real backend login)
        headers = {'Content-Type': 'application/json'}
        params = {'username': '******', 'password': '******'}
        response = session.post('http://127.0.0.1:8888/login',
                                json=params,
                                headers=headers)
        assert response.status_code == 200
        resp = response.json()

        # Request to create an host - create a new host
        headers = {'Content-Type': 'application/json'}
        data = {
            "name": "new_host_for_services_0",
            "template": {
                "_realm": 'All',
                "check_command": "_internal_host_up"
            }
        }
        self.assertEqual(my_module.received_commands, 0)
        response = session.patch('http://127.0.0.1:8888/host',
                                 json=data,
                                 headers=headers)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(
            result, {
                u'_status':
                u'OK',
                u'_result': [
                    u'new_host_for_services_0 is alive :)',
                    u"Requested host 'new_host_for_services_0' does not exist.",
                    u"Requested host 'new_host_for_services_0' created."
                ]
            })
        # No errors!

        # Get new host in the backend
        response = requests.get(
            self.endpoint + '/host',
            auth=self.auth,
            params={'where': json.dumps({'name': 'new_host_for_services_0'})})
        resp = response.json()
        new_host_for_services_0 = resp['_items'][0]
        self.assertEqual('new_host_for_services_0',
                         new_host_for_services_0['name'])

        # Get backend check results - no check result sent to the backend
        response = requests.get(self.endpoint + '/logcheckresult',
                                auth=self.auth)
        resp = response.json()
        rl = resp['_items']
        self.assertEqual(len(rl), 0)

        # Request to create an host - create a new service without any template data
        headers = {'Content-Type': 'application/json'}
        data = {
            "name":
            "new_host_for_services_0",
            "services": [{
                "name": "test_empty_0",
                # "template": {
                #     "_realm": 'All',
                #     "check_command": "_echo"
                # },
                "livestate": {
                    "state": "OK",
                    "output": "Output...",
                    "long_output": "Long output...",
                    "perf_data": "'counter'=1",
                },
                "variables": {
                    'test1': 'string',
                    'test2': 1,
                    'test3': 5.0
                },
            }]
        }
        self.assertEqual(my_module.received_commands, 0)
        response = session.patch('http://127.0.0.1:8888/host',
                                 json=data,
                                 headers=headers)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(
            result, {
                u'_status':
                u'OK',
                u'_result': [
                    u'new_host_for_services_0 is alive :)',
                    u"Requested service 'new_host_for_services_0/test_empty_0' does not exist.",
                    u"Requested service 'new_host_for_services_0/test_empty_0' created.",
                    u"PROCESS_SERVICE_CHECK_RESULT;new_host_for_services_0;test_empty_0;0;Output...|'counter'=1\nLong output...",
                    u"Service 'new_host_for_services_0/test_empty_0' updated",
                ]
            })
        # No errors!

        # Get new host to confirm creation
        response = requests.get(
            self.endpoint + '/host',
            auth=self.auth,
            params={'where': json.dumps({'name': 'new_host_for_services_0'})})
        resp = response.json()
        new_host_for_services_0 = resp['_items'][0]
        self.assertEqual('new_host_for_services_0',
                         new_host_for_services_0['name'])

        # Get services data to confirm update
        response = requests.get(self.endpoint + '/service',
                                auth=self.auth,
                                params={
                                    'where':
                                    json.dumps({
                                        'host':
                                        new_host_for_services_0['_id'],
                                        'name':
                                        'test_empty_0'
                                    })
                                })
        resp = response.json()
        service = resp['_items'][0]
        expected = {u'_TEST3': 5.0, u'_TEST2': 1, u'_TEST1': u'string'}
        self.assertEqual(expected, service['customs'])

        # Send a service livestate, no timestamp
        headers = {'Content-Type': 'application/json'}
        data = {
            "name":
            "new_host_for_services_0",
            "services": [{
                "name": "test_empty_0",
                "livestate": {
                    # No timestamp in the livestate
                    "state": "OK",
                    "output": "Output...",
                    "long_output": "Long output...",
                    "perf_data": "'counter'=1",
                }
            }]
        }
        self.assertEqual(my_module.received_commands, 0)
        response = session.patch('http://127.0.0.1:8888/host',
                                 json=data,
                                 headers=headers)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(
            result, {
                u'_status':
                u'OK',
                u'_result': [
                    u'new_host_for_services_0 is alive :)',
                    u"PROCESS_SERVICE_CHECK_RESULT;new_host_for_services_0;test_empty_0;0;Output...|'counter'=1\nLong output...",
                ]
            })
        # No errors!

        # Get backend check results - no check result sent to the backend
        response = requests.get(self.endpoint + '/logcheckresult',
                                auth=self.auth)
        resp = response.json()
        rl = resp['_items']
        self.assertEqual(len(rl), 0)

        # Send a service livestate, timestamp in the past
        headers = {'Content-Type': 'application/json'}
        now = int(time.time()) - 3600
        data = {
            "name":
            "new_host_for_services_0",
            "services": [{
                "name": "test_empty_0",
                "livestate": {
                    # Timestamp in the past
                    "timestamp": now,
                    "state": "OK",
                    "output": "Output...",
                    "long_output": "Long output...",
                    "perf_data": "'counter'=1",
                }
            }]
        }
        self.assertEqual(my_module.received_commands, 0)
        response = session.patch('http://127.0.0.1:8888/host',
                                 json=data,
                                 headers=headers)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(
            result, {
                u'_status':
                u'OK',
                u'_result': [
                    u'new_host_for_services_0 is alive :)',
                    u"[%d] PROCESS_SERVICE_CHECK_RESULT;new_host_for_services_0;test_empty_0;0;Output...|'counter'=1\nLong output..."
                    % now,
                ]
            })
        # No errors!

        # Get backend check results - a check result was recorded in the backend
        response = requests.get(self.endpoint + '/logcheckresult',
                                auth=self.auth)
        resp = response.json()
        rl = resp['_items']
        # A log check result was recorded...
        self.assertEqual(len(rl), 1)
        rl = resp['_items'][0]
        print("LCR: %s" % rl)
        # ...with the correct timestamp
        self.assertEqual(rl['host_name'], "new_host_for_services_0")
        self.assertEqual(rl['service_name'], "test_empty_0")
        self.assertEqual(rl['last_check'], now)

        # Send a service livestate with a timestamp in the past but sooner than the former one
        now = now + 1800
        data = {
            "name":
            "new_host_for_services_0",
            "services": [{
                "name": "test_empty_0",
                "livestate": {
                    # Timestamp in the past
                    "timestamp": now,
                    "state": "OK",
                    "output": "Output...",
                    "long_output": "Long output...",
                    "perf_data": "'counter'=1",
                }
            }]
        }
        self.assertEqual(my_module.received_commands, 0)
        response = session.patch('http://127.0.0.1:8888/host',
                                 json=data,
                                 headers=headers)
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(
            result, {
                u'_status':
                u'OK',
                u'_result': [
                    u'new_host_for_services_0 is alive :)',
                    u"[%d] PROCESS_SERVICE_CHECK_RESULT;new_host_for_services_0;test_empty_0;0;Output...|'counter'=1\nLong output..."
                    % now,
                ]
            })
        # No errors!

        # Get backend check results - a check result was recorded in the backend
        response = requests.get(self.endpoint + '/logcheckresult',
                                auth=self.auth)
        resp = response.json()
        rl = resp['_items']
        # A log check result was recorded...
        self.assertEqual(len(rl), 2)
        rl = resp['_items'][1]
        print("LCR: %s" % rl)
        # ...with the correct timestamp
        self.assertEqual(rl['host_name'], "new_host_for_services_0")
        self.assertEqual(rl['service_name'], "test_empty_0")
        self.assertEqual(rl['last_check'], now)

        # Logout
        response = session.get('http://127.0.0.1:8888/logout')
        self.assertEqual(response.status_code, 200)
        result = response.json()
        self.assertEqual(result['_status'], 'OK')
        self.assertEqual(result['_result'], 'Logged out')

        self.modulemanager.stop_all()
Ejemplo n.º 13
0
class TestModules(AlignakTest):
    """
    This class contains the tests for the modules
    """
    def test_module_loading(self):
        """ Test arbiter, broker, ... detecting configured modules

        :return:
        """
        self.print_header()
        self.setup_with_file('./cfg/cfg_default_with_modules.cfg')
        assert self.conf_is_correct
        self.show_configuration_logs()

        # The only existing arbiter module is Example declared in the configuration
        modules = [m.module_alias for m in self.arbiter.myself.modules]
        assert modules == ['Example']

        # The only existing broker module is Example declared in the configuration
        modules = [
            m.module_alias for m in self.brokers['broker-master'].modules
        ]
        assert modules == ['Example']

        # The only existing poller module is Example declared in the configuration
        modules = [
            m.module_alias for m in self.pollers['poller-master'].modules
        ]
        assert modules == ['Example']

        # The only existing receiver module is Example declared in the configuration
        modules = [
            m.module_alias for m in self.receivers['receiver-master'].modules
        ]
        assert modules == ['Example']

        # The only existing reactionner module is Example declared in the configuration
        modules = [
            m.module_alias
            for m in self.reactionners['reactionner-master'].modules
        ]
        assert modules == ['Example']

        # No scheduler modules created
        modules = [
            m.module_alias for m in self.schedulers['scheduler-master'].modules
        ]
        assert modules == ['Example']

        # Loading module logs
        self.assert_any_log_match(
            re.escape(
                "Importing Python module 'alignak_module_example' for Example..."
            ))
        self.assert_any_log_match(
            re.escape(
                "Module properties: {'daemons': ['arbiter', 'broker', 'scheduler', 'poller', "
                "'receiver', 'reactionner'], 'phases': ['configuration', 'late_configuration', "
                "'running', 'retention'], 'type': 'example', 'external': True}"
            ))
        self.assert_any_log_match(
            re.escape("Imported 'alignak_module_example' for Example"))
        self.assert_any_log_match(
            re.escape(
                "Give an instance of alignak_module_example for alias: Example"
            ))
        self.assert_any_log_match(
            re.escape("I correctly loaded my modules: [Example]"))

    def test_arbiter_configuration_module(self):
        """ Test arbiter configuration loading

        :return:
        """
        self.print_header()
        self.setup_with_file('./cfg/cfg_arbiter_configuration_module.cfg')
        assert self.conf_is_correct
        self.show_configuration_logs()
        self.show_logs()

        # The arbiter module is 'backend_arbiter' declared in the configuration
        modules = [m.module_alias for m in self.arbiter.myself.modules]
        assert modules == ['backend_arbiter']

    def test_missing_module_detection(self):
        """ Detect missing module configuration

        Alignak configuration parser detects that some modules are required because some
        specific parameters are included in the configuration files. If the modules are not
        present in the configuration, it logs warning message to alert the user about this!

        :return:
        """
        self.print_header()
        with pytest.raises(SystemExit):
            self.setup_with_file(
                'cfg/modules/alignak_modules_nagios_parameters.cfg')
        assert not self.conf_is_correct
        self.show_configuration_logs()

        # Log missing module
        self.assert_any_log_match(
            re.escape(
                "Your configuration parameters 'status_file = /var/status.dat' and "
                "'object_cache_file = /var/status.dat' need to use an external module such "
                "as 'retention' but I did not found one!"))
        self.assert_any_log_match(
            re.escape(
                "Your configuration parameter 'log_file = /test/file' needs to use an external "
                "module such as 'logs' but I did not found one!"))
        self.assert_any_log_match(
            re.escape(
                "Your configuration parameter 'use_syslog = True' needs to use an external "
                "module such as 'logs' but I did not found one!"))
        self.assert_any_log_match(
            re.escape(
                "Your configuration parameters 'host_perfdata_file = /test/file' and "
                "'service_perfdata_file = /test/file' need to use an external module such as "
                "'retention' but I did not found one!"))
        self.assert_any_log_match(
            re.escape(
                "Your configuration parameters 'state_retention_file = /test/file' and "
                "'retention_update_interval = 100' need to use an external module such as "
                "'retention' but I did not found one!"))
        self.assert_any_log_match(
            re.escape(
                "Your configuration parameter 'command_file = /var/alignak.cmd' needs to use "
                "an external module such as 'logs' but I did not found one!"))

    def test_module_on_module(self):
        """ No module configuration for modules

        Check that the feature is detected as disabled
        :return:
        """
        self.print_header()
        self.setup_with_file('cfg/modules/alignak_module_with_submodules.cfg')
        assert self.conf_is_correct
        self.show_configuration_logs()

        # No arbiter modules created
        modules = [m.module_alias for m in self.arbiter.myself.modules]
        assert modules == ['Example']

        # The only existing broker module is Example declared in the configuration
        modules = [
            m.module_alias for m in self.brokers['broker-master'].modules
        ]
        assert modules == ['Example']

        # The only existing poller module is Example declared in the configuration
        modules = [
            m.module_alias for m in self.pollers['poller-master'].modules
        ]
        assert modules == ['Example']

        # The only existing receiver module is Example declared in the configuration
        modules = [
            m.module_alias for m in self.receivers['receiver-master'].modules
        ]
        assert modules == ['Example']

        # The only existing reactionner module is Example declared in the configuration
        modules = [
            m.module_alias
            for m in self.reactionners['reactionner-master'].modules
        ]
        assert modules == ['Example']

        # No scheduler modules created
        modules = [
            m.module_alias for m in self.schedulers['scheduler-master'].modules
        ]
        assert modules == ['Example']

    def test_modulemanager(self):
        """ Module manager manages its modules

        Test if the module manager manages correctly all the modules
        :return:
        """
        self.print_header()
        self.setup_with_file('cfg/cfg_default_with_modules.cfg')
        assert self.conf_is_correct

        time_hacker.set_real_time()

        # Create an Alignak module
        mod = Module({
            'module_alias': 'mod-example',
            'module_types': 'example',
            'python_name': 'alignak_module_example'
        })

        # Create the modules manager for a daemon type
        self.modulemanager = ModulesManager('receiver', None)

        # Load an initialize the modules:
        #  - load python module
        #  - get module properties and instances
        self.modulemanager.load_and_init([mod])

        # Loading module logs
        self.assert_any_log_match(
            re.escape(
                "Importing Python module 'alignak_module_example' for Example..."
            ))
        self.assert_any_log_match(
            re.escape(
                "Module properties: {'daemons': ['arbiter', 'broker', 'scheduler', 'poller', "
                "'receiver', 'reactionner'], 'phases': ['configuration', 'late_configuration', "
                "'running', 'retention'], 'type': 'example', 'external': True}"
            ))
        self.assert_any_log_match(
            re.escape("Imported 'alignak_module_example' for Example"))
        self.assert_any_log_match(
            re.escape(
                "Give an instance of alignak_module_example for alias: Example"
            ))
        self.assert_any_log_match(
            re.escape("I correctly loaded my modules: [Example]"))

        my_module = self.modulemanager.instances[0]
        assert my_module.is_external

        # Get list of not external modules
        assert [] == self.modulemanager.get_internal_instances()
        for phase in [
                'configuration', 'late_configuration', 'running', 'retention'
        ]:
            assert [] == self.modulemanager.get_internal_instances(phase)

        # Get list of external modules
        assert [my_module] == self.modulemanager.get_external_instances()
        for phase in [
                'configuration', 'late_configuration', 'running', 'retention'
        ]:
            assert [my_module
                    ] == self.modulemanager.get_external_instances(phase)

        # Start external modules
        self.modulemanager.start_external_instances()

        # Starting external module logs
        self.assert_any_log_match(
            re.escape("Starting external module mod-example"))
        self.assert_any_log_match(
            re.escape("Starting external process for module mod-example"))
        self.assert_any_log_match(
            re.escape("mod-example is now started (pid="))

        # Check alive
        assert my_module.process is not None
        assert my_module.process.is_alive()

        # Kill the external module (normal stop is .stop_process)
        my_module.kill()
        time.sleep(0.1)
        # Should be dead (not normally stopped...) but we still know a process for this module!
        assert my_module.process is not None

        # Stopping module logs
        self.assert_any_log_match(re.escape("Killing external module "))
        self.assert_any_log_match(re.escape("External module killed"))

        # Nothing special ...
        self.modulemanager.check_alive_instances()

        # Try to restart the dead modules
        self.modulemanager.try_to_restart_deads()

        # In fact it's too early, so it won't do it

        # Here the inst should still be dead
        assert not my_module.process.is_alive()

        # So we lie
        my_module.last_init_try = -5
        self.modulemanager.check_alive_instances()
        self.modulemanager.try_to_restart_deads()

        # In fact it's too early, so it won't do it

        # Here the inst should be alive again
        assert my_module.process.is_alive()

        # should be nothing more in to_restart of
        # the module manager
        assert [] == self.modulemanager.to_restart

        # Now we look for time restart so we kill it again
        my_module.kill()
        time.sleep(0.2)
        assert not my_module.process.is_alive()

        # Should be too early
        self.modulemanager.check_alive_instances()
        self.modulemanager.try_to_restart_deads()
        assert not my_module.process.is_alive()
        # We lie for the test again
        my_module.last_init_try = -5
        self.modulemanager.check_alive_instances()
        self.modulemanager.try_to_restart_deads()

        # Here the inst should be alive again
        assert my_module.process.is_alive()

        # And we clear all now
        self.modulemanager.stop_all()
        # Stopping module logs
        self.assert_any_log_match(re.escape("I'm stopping module "))
Ejemplo n.º 14
0
class TestModuleManager(AlignakTest):
    def setUp(self):
        self.setup_with_file([])
        time_hacker.set_real_time()

    # Try to see if the module manager can manage modules
    def test_modulemanager(self):
        mod = Module({
            'module_alias': 'mod-example',
            'python_name': 'alignak_module_example'
        })
        self.modulemanager = ModulesManager('broker', None)
        self.modulemanager.load_and_init([mod])
        # And start external ones, like our LiveStatus
        self.modulemanager.start_external_instances()
        print "I correctly loaded the modules: %s " % (
            [inst.get_name() for inst in self.modulemanager.instances])

        print "*** First kill ****"
        # Now I will try to kill the livestatus module
        ls = self.modulemanager.instances[0]
        " :type: alignak.basemodule.BaseModule "
        ls.kill()
        time.sleep(0.1)
        print "Check alive?"
        print "Is alive?", ls.process.is_alive()
        # Should be dead
        self.assertFalse(ls.process.is_alive())
        self.modulemanager.check_alive_instances()
        self.modulemanager.try_to_restart_deads()

        # In fact it's too early, so it won't do it

        # Here the inst should still be dead
        print "Is alive?", ls.process.is_alive()
        self.assertFalse(ls.process.is_alive())

        # So we lie
        ls.last_init_try = -5
        self.modulemanager.check_alive_instances()
        self.modulemanager.try_to_restart_deads()

        # In fact it's too early, so it won't do it

        # Here the inst should be alive again
        print "Is alive?", ls.process.is_alive()
        self.assertTrue(ls.process.is_alive())

        # should be nothing more in to_restart of
        # the module manager
        self.assertEqual([], self.modulemanager.to_restart)

        # Now we look for time restart so we kill it again
        ls.kill()
        time.sleep(0.2)
        self.assertFalse(ls.process.is_alive())

        # Should be too early
        self.modulemanager.check_alive_instances()
        self.modulemanager.try_to_restart_deads()
        print "Is alive or not", ls.process.is_alive()
        self.assertFalse(ls.process.is_alive())
        # We lie for the test again
        ls.last_init_try = -5
        self.modulemanager.check_alive_instances()
        self.modulemanager.try_to_restart_deads()

        # Here the inst should be alive again
        print "Is alive?", ls.process.is_alive()
        self.assertTrue(ls.process.is_alive())

        # And we clear all now
        print "Ask to die"
        self.modulemanager.stop_all()
        print "Died"