def test_2_delete_exceptions(self):
        """
        Test delete a timeperiod with errors (so exceptions)

        :return: None
        """
        backend = Backend(self.backend_address)
        backend.login("admin", "admin")

        # Create a new timeperiod
        data = {
            "name": "Testing TP",
            "alias": "Test TP",
            "dateranges": [
                {u"monday": u"09:00-17:00"},
                {u"tuesday": u"09:00-17:00"},
                {u"wednesday": u"09:00-17:00"},
                {u"thursday": u"09:00-17:00"},
                {u"friday": u"09:00-17:00"},
            ],
            "_realm": self.realmAll_id,
        }
        response = backend.post("timeperiod", data=data)
        assert_true(response["_status"] == "OK")
        timeperiod_id = response["_id"]
        timeperiod_etag = response["_etag"]

        with assert_raises(BackendException) as cm:
            headers = {"If-Match": timeperiod_etag}
            response = backend.delete("/".join(["timeperiod", "5" + timeperiod_id]), headers)
        ex = cm.exception
        print("exception:", str(ex.code))
        assert_true(ex.code == 1003, str(ex))
Beispiel #2
0
    def test_1_patch_successful_inception(self):
        """
        Test patch a user successfully with inception

        :return: None
        """
        backend = Backend(self.backend_address)
        backend.login('admin', 'admin')

        # get user admin
        params = {"where": {"name": "admin"}}
        response = requests.get(self.backend_address + '/user',
                                json=params,
                                auth=self.auth)
        resp = response.json()
        user_id = resp['_items'][0]['_id']
        # user_etag = resp['_items'][0]['_etag']

        data = {'alias': 'modified test'}
        headers = {'If-Match': 'foo'}
        response = backend.patch('/'.join(['user', user_id]),
                                 data=data,
                                 headers=headers,
                                 inception=True)
        assert_true(response['_status'] == 'OK')
    def test_1_delete_successful(self):
        """
        Test delete a timeperiod successfully

        :return: None
        """
        backend = Backend(self.backend_address)
        backend.login("admin", "admin")

        # Create a new timeperiod
        data = {
            "name": "Testing TP",
            "alias": "Test TP",
            "dateranges": [
                {u"monday": u"09:00-17:00"},
                {u"tuesday": u"09:00-17:00"},
                {u"wednesday": u"09:00-17:00"},
                {u"thursday": u"09:00-17:00"},
                {u"friday": u"09:00-17:00"},
            ],
            "_realm": self.realmAll_id,
        }
        response = backend.post("timeperiod", data=data)
        assert_true(response["_status"] == "OK")
        timeperiod_id = response["_id"]
        timeperiod_etag = response["_etag"]

        headers = {"If-Match": timeperiod_etag}
        response = backend.delete("/".join(["timeperiod", timeperiod_id]), headers=headers)
        assert_true(response["_status"] == "OK")
    def test_1_post_successful(self):
        """
        Test post a timeperiod successfully

        :return: None
        """
        backend = Backend(self.backend_address)
        backend.login('admin', 'admin')

        # Create a new timeperiod
        print('create a timeperiod')
        data = {
            "name": "Testing TP",
            "alias": "Test TP",
            "dateranges": [
                {u'monday': u'09:00-17:00'},
                {u'tuesday': u'09:00-17:00'},
                {u'wednesday': u'09:00-17:00'},
                {u'thursday': u'09:00-17:00'},
                {u'friday': u'09:00-17:00'}
            ],
            "_realm": self.realmAll_id
        }
        response = backend.post('timeperiod', data=data)
        assert_true('_created' in response)
        assert_true('_updated' in response)
        assert_true(response['_created'] == response['_updated'])
Beispiel #5
0
    def test_1_put_successful(self):
        """
        Test put an alignakretention successfully

        :return: None
        """
        backend = Backend(self.backend_address)
        backend.login('admin', 'admin')

        # get alignakretention
        params = {}
        response = requests.get(self.backend_address + '/alignakretention', json=params,
                                auth=self.auth)
        resp = response.json()
        ar_id = resp['_items'][0]['_id']
        ar_etag = resp['_items'][0]['_etag']

        data = {
            'host': 'srv001',
            'latency': 2,
            'last_state_type': 'HARD',
            'state': 'UP',
            'last_chk': 0,
        }
        headers = {'If-Match': ar_etag}
        response = backend.put('/'.join(['alignakretention', ar_id]), data=data, headers=headers)
        assert_true(response['_status'] == 'OK')

        response = requests.get(self.backend_address + '/alignakretention', json=params,
                                auth=self.auth)
        resp = response.json()
        self.assertEqual('srv001', resp['_items'][0]['host'])
        self.assertEqual(2, resp['_items'][0]['latency'])
    def test_2_post_exceptions(self):
        """
        Test post a user with errors (so exceptions)

        :return: None
        """
        backend = Backend(self.backend_address)
        backend.login('admin', 'admin')

        # Create a new user, bad parameters
        # Mandatory field user_name is missing ...
        data = {
            "name": "Testing user",
            "alias": "Fred",
            "back_role_super_admin": False,
            "back_role_admin": [],
            "min_business_impact": 0,
        }
        with assert_raises(BackendException) as cm:
            backend.post('user', data=data)
        ex = cm.exception
        print('exception:', str(ex.code), ex.message, ex.response)
        if "_issues" in ex.response:
            for issue in ex.response["_issues"]:
                print("Issue: %s - %s" % (issue, ex.response["_issues"][issue]))
        assert_true(ex.code == 422)
        assert_true(ex.response["_issues"])
    def test_01_creation(self):
        """
        Create connection with the backend

        :return: None
        """
        print('')
        print('test creation')

        print('Create client API for URL:', self.backend_address)
        backend = Backend(self.backend_address)

        print('object:', backend)
        print('authenticated:', backend.authenticated)
        print('endpoint:', backend.url_endpoint_root)
        print('token:', backend.token)
        assert_false(backend.authenticated)
        assert_true(backend.url_endpoint_root == self.backend_address)
        assert_equal(backend.token, None)

        print('Create client API (trailing slash is removed)')
        backend = Backend(self.backend_address + '/')

        print('object:', backend)
        print('authenticated:', backend.authenticated)
        print('endpoint:', backend.url_endpoint_root)
        print('token:', backend.token)
        assert_false(backend.authenticated)
        assert_true(backend.url_endpoint_root == self.backend_address)
        assert_equal(backend.token, None)
class TestRecalculateLivestate(unittest2.TestCase):
    @classmethod
    def setUpClass(cls):
        cls.p = subprocess.Popen(
            ["uwsgi", "-w", "alignakbackend:app", "--socket", "0.0.0.0:5000", "--protocol=http", "--enable-threads"]
        )
        time.sleep(3)
        cls.backend = Backend("http://127.0.0.1:5000")
        cls.backend.login("admin", "admin", "force")
        cls.backend.delete("host", {})
        cls.backend.delete("service", {})
        cls.backend.delete("command", {})
        cls.backend.delete("livestate", {})
        cls.backend.delete("livesynthesis", {})

    def test_recalculate(self):
        # add host
        data = json.loads(open("cfg/host_srv001.json").read())
        self.backend.post("host", data)
        rh = self.backend.get("host")

        # Add command
        data = json.loads(open("cfg/command_ping.json").read())
        self.backend.post("command", data)
        # Check if command right in backend
        rc = self.backend.get("command")
        self.assertEqual(rc["_items"][0]["command_name"], "ping")

        # Add service
        data = json.loads(open("cfg/service_srv001_ping.json").read())
        data["host_name"] = rh["_items"][0]["_id"]
        data["check_command"] = rc["_items"][0]["_id"]
        self.backend.post("service", data)
        # Check if service right in backend
        rs = self.backend.get("service")
        self.assertEqual(rs["_items"][0]["service_description"], "ping")

        self.backend.delete("livestate", {})
        self.p.kill()
        time.sleep(3)
        self.p = subprocess.Popen(
            ["uwsgi", "-w", "alignakbackend:app", "--socket", "0.0.0.0:5000", "--protocol=http", "--enable-threads"]
        )
        time.sleep(3)

        # Check if livestate right recalculate
        self.backend = Backend("http://127.0.0.1:5000")
        self.backend.login("admin", "admin", "force")
        r = self.backend.get("livestate")
        self.assertEqual(len(r["_items"]), 2)
        self.assertEqual(r["_items"][1]["last_state"], "OK")
        self.assertEqual(r["_items"][1]["last_state_type"], "HARD")
        self.assertEqual(r["_items"][1]["last_check"], 0)
        self.assertEqual(r["_items"][1]["state_type"], "HARD")
        self.assertEqual(r["_items"][1]["state"], "OK")
        self.assertEqual(r["_items"][1]["host_name"], rh["_items"][0]["_id"])
        self.assertEqual(r["_items"][1]["service_description"], rs["_items"][0]["_id"])

        self.backend.delete("contact", {})
        self.p.kill()
Beispiel #9
0
    def test_3_patch_connection_error(self):
        """
        Backend connection error when updating an object...

        :return: None
        """
        print('test connection error when updating an object')

        # Create client API
        backend = Backend(self.backend_address)
        backend.login('admin', 'admin')

        # get user admin
        params = {"where": {"name": "admin"}}
        response = requests.get(self.backend_address + '/user',
                                json=params,
                                auth=self.auth)
        resp = response.json()
        user_id = resp['_items'][0]['_id']
        user_etag = resp['_items'][0]['_etag']

        print("stop the alignak backend")
        self.pid.kill()

        with assert_raises(BackendException) as cm:
            data = {'alias': 'modified test'}
            headers = {'If-Match': user_etag}
            response = backend.patch('/'.join(['user', user_id]),
                                     data=data,
                                     headers=headers)
            assert_true(response['_status'] == 'OK')
        ex = cm.exception
        self.assertEqual(ex.code, 1000)
Beispiel #10
0
    def __init__(self, mod_conf):
        """Module initialization

        mod_conf is a dictionary that contains:
        - all the variables declared in the module configuration file
        - a 'properties' value that is the module properties as defined globally in this file

        :param mod_conf: module configuration file as a dictionary
        """
        BaseModule.__init__(self, mod_conf)

        # pylint: disable=global-statement
        global logger
        logger = logging.getLogger('alignak.module.%s' % self.alias)
        logger.setLevel(getattr(mod_conf, 'log_level', logging.INFO))

        logger.debug("inner properties: %s", self.__dict__)
        logger.debug("received configuration: %s", mod_conf.__dict__)

        self.client_processes = int(getattr(mod_conf, 'client_processes', 1))
        logger.info("Number of processes used by backend client: %s",
                    self.client_processes)

        self.backend_count = int(getattr(mod_conf, 'backend_count', '50'))
        logger.info("backend pagination count: %d items", self.backend_count)

        logger.info("StatsD configuration: %s:%s, prefix: %s, enabled: %s",
                    getattr(mod_conf, 'statsd_host', 'localhost'),
                    int(getattr(mod_conf, 'statsd_port', '8125')),
                    getattr(mod_conf, 'statsd_prefix', 'alignak'),
                    (getattr(mod_conf, 'statsd_enabled', '0') != '0'))
        self.statsmgr = Stats()
        self.statsmgr.register(
            self.alias,
            'module',
            statsd_host=getattr(mod_conf, 'statsd_host', 'localhost'),
            statsd_port=int(getattr(mod_conf, 'statsd_port', '8125')),
            statsd_prefix=getattr(mod_conf, 'statsd_prefix', 'alignak'),
            statsd_enabled=(getattr(mod_conf, 'statsd_enabled', '0') != '0'))

        self.url = getattr(mod_conf, 'api_url', 'http://localhost:5000')
        logger.info("Alignak backend endpoint: %s", self.url)
        self.backend = Backend(self.url, self.client_processes)
        self.backend.token = getattr(mod_conf, 'token', '')
        self.backend_connected = False
        self.backend_errors_count = 0
        self.backend_username = getattr(mod_conf, 'username', '')
        self.backend_password = getattr(mod_conf, 'password', '')
        self.backend_generate = getattr(mod_conf, 'allowgeneratetoken', False)

        if not self.backend.token:
            logger.warning(
                "no user token configured. "
                "It is recommended to set a user token rather than a user login "
                "in the configuration. Trying to get a token from the provided "
                "user login information...")
            self.getToken()
        else:
            self.backend_connected = True
Beispiel #11
0
    def login(self, username=None, password=None):
        """
        Connect to app_backend with credentials in settings.cfg.

        :return: True if connected or False if not
        :rtype: bool
        """

        connect = False
        # Credentials
        if not username and not password:
            if self.user:
                username = self.user['token']
            else:
                username = get_app_config('Alignak', 'username')
                password = get_app_config('Alignak', 'password')

        # Create Backend object
        backend_url = get_app_config('Alignak', 'backend')
        processes = int(get_app_config('Alignak', 'processes'))

        self.backend = Backend(backend_url, processes=processes)

        logger.debug('Backend URL : %s', backend_url)
        logger.info('Try to connect to app_backend...')

        if username and password:
            # Username & password : not recommended, without "widgets.login.py" form.
            try:
                connect = self.backend.login(username, password)
                if connect:
                    self.user['username'] = username
                    self.user['token'] = self.backend.token
                logger.info('Connection by password: %s', str(connect))
            except BackendException as e:  # pragma: no cover
                logger.error('Connection to Backend has failed: %s', str(e))
        elif username and not password:
            # Username as token : recommended
            self.backend.authenticated = True
            if self.user:
                self.backend.token = self.user['token']
            else:
                self.backend.token = username
                self.user['token'] = username

            # Test to check token
            self.connected = True
            connect = bool(self.get('livesynthesis'))
            logger.info('Connection by token: %s', str(connect))
        else:
            # Else exit
            logger.error(
                'Connection to Backend has failed.\nCheck [Backend] section in configuration file.'
            )
            connect = False

        self.connected = connect

        return connect
class TestRecalculateLivestate(unittest2.TestCase):

    @classmethod
    def setUpClass(cls):
        cls.p = subprocess.Popen(['uwsgi', '-w', 'alignakbackend:app', '--socket', '0.0.0.0:5000', '--protocol=http', '--enable-threads'])
        time.sleep(3)
        cls.backend = Backend('http://127.0.0.1:5000')
        cls.backend.login("admin", "admin", "force")
        cls.backend.delete("host", {})
        cls.backend.delete("service", {})
        cls.backend.delete("command", {})
        cls.backend.delete("livestate", {})
        cls.backend.delete("livesynthesis", {})

    def test_recalculate(self):
        # add host
        data = json.loads(open('cfg/host_srv001.json').read())
        self.backend.post("host", data)
        rh = self.backend.get('host')

        # Add command
        data = json.loads(open('cfg/command_ping.json').read())
        self.backend.post("command", data)
        # Check if command right in backend
        rc = self.backend.get('command')
        self.assertEqual(rc['_items'][0]['command_name'], "ping")

        # Add service
        data = json.loads(open('cfg/service_srv001_ping.json').read())
        data['host_name'] = rh['_items'][0]['_id']
        data['check_command'] = rc['_items'][0]['_id']
        self.backend.post("service", data)
        # Check if service right in backend
        rs = self.backend.get('service')
        self.assertEqual(rs['_items'][0]['service_description'], "ping")

        self.backend.delete("livestate", {})
        self.p.kill()
        time.sleep(3)
        self.p = subprocess.Popen(['uwsgi', '-w', 'alignakbackend:app', '--socket', '0.0.0.0:5000', '--protocol=http', '--enable-threads'])
        time.sleep(3)

        # Check if livestate right recalculate
        self.backend = Backend('http://127.0.0.1:5000')
        self.backend.login("admin", "admin", "force")
        r = self.backend.get('livestate')
        self.assertEqual(len(r['_items']), 2)
        self.assertEqual(r['_items'][1]['last_state'], 'OK')
        self.assertEqual(r['_items'][1]['last_state_type'], 'HARD')
        self.assertEqual(r['_items'][1]['last_check'], 0)
        self.assertEqual(r['_items'][1]['state_type'], 'HARD')
        self.assertEqual(r['_items'][1]['state'], 'OK')
        self.assertEqual(r['_items'][1]['host_name'], rh['_items'][0]['_id'])
        self.assertEqual(r['_items'][1]['service_description'], rs['_items'][0]['_id'])
        self.assertEqual(r['_items'][1]['type'], 'service')

        self.backend.delete("contact", {})
        self.p.kill()
Beispiel #13
0
    def test_0(self):
        print ""

        # Login and delete defined contacts ...
        self.backend.login("admin", "admin")
        self.backend.delete("contact", {})

        # No login possible ...
        assert not self.backend.login("admin", "admin")

        # Stop and restart backend ...
        print ("")
        print ("stop backend")
        self.p.kill()
        print ("")
        print ("start backend")
        self.p = subprocess.Popen(['uwsgi', '-w', 'alignakbackend:app', '--socket', '0.0.0.0:5000', '--protocol=http', '--enable-threads'])
        time.sleep(1)
        self.backend = Backend('http://127.0.0.1:5000')

        # Login is now possible because backend recreated super admin user
        assert self.backend.login("admin", "admin")
        print "Super admin is now defined in backend ..."
        token = self.backend.token
        assert token

        print ("")
        print ("stop backend")
        self.p.kill()
    def test_05_login(self):
        """
        Test with right username / password

        :return: None
        """
        print('test connection error when login')

        # Create client API
        backend = Backend(self.backend_address)

        print('Login ... must be refused!')
        with assert_raises(BackendException) as cm:
            backend.login('admin', 'admin')
        ex = cm.exception
        self.assertEqual(ex.code, 1000)
    def __init__(self, mod_conf):
        """
        Module initialization

        mod_conf is a dictionary that contains:
        - all the variables declared in the module configuration file
        - a 'properties' value that is the module properties as defined globally in this file

        :param mod_conf: module configuration file as a dictionary
        """
        BaseModule.__init__(self, mod_conf)

        # pylint: disable=global-statement
        global logger
        logger = logging.getLogger("alignak.module.%s" % self.alias)

        logger.debug("inner properties: %s", self.__dict__)
        logger.debug("received configuration: %s", mod_conf.__dict__)

        self.url = getattr(mod_conf, "api_url", "http://localhost:5000")
        self.backend = Backend(self.url)
        self.backend.token = getattr(mod_conf, "token", "")
        self.backend_connected = False
        if self.backend.token == "":
            self.getToken(
                getattr(mod_conf, "username", ""),
                getattr(mod_conf, "password", ""),
                getattr(mod_conf, "allowgeneratetoken", False),
            )
    def setUpClass(cls):
        # Set test mode for applications backend
        os.environ['TEST_ALIGNAK_BACKEND'] = '1'
        os.environ['ALIGNAK_BACKEND_MONGO_DBNAME'] = 'alignak-backend-import-test'
        os.environ['ALIGNAK_BACKEND_CONFIGURATION_FILE'] = './cfg/settings/settings.json'

        cls.maxDiff = None

        # Delete used mongo DBs
        exit_code = subprocess.call(
            shlex.split('mongo %s --eval "db.dropDatabase()"'
                        % os.environ['ALIGNAK_BACKEND_MONGO_DBNAME'])
        )
        assert exit_code == 0
        time.sleep(1)

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

        print("Starting Alignak backend...")
        cls.p = subprocess.Popen(['uwsgi', '--plugin', 'python', '-w', 'alignak_backend.app:app',
                                  '--socket', '0.0.0.0:5000',
                                  '--protocol=http', '--enable-threads', '--pidfile',
                                  '/tmp/uwsgi.pid'])
        time.sleep(1)
        print("Started as %s" % cls.p.pid)

        cls.backend = Backend('http://127.0.0.1:5000')
        cls.backend.login("admin", "admin", "force")

        cls.backend.delete("host", {})
        cls.backend.delete("service", {})
        cls.backend.delete("command", {})
        cls.backend.delete("livesynthesis", {})
Beispiel #17
0
    def test_2_put_exception_method_not_allowed(self):
        """
        Test put a user with errors (so exceptions) because PUT method not allowed on this endpoint

        :return: None
        """
        backend = Backend(self.backend_address)
        backend.login('admin', 'admin')

        # get user admin
        params = {"where": {"name": "admin"}}
        response = requests.get(self.backend_address + '/user', json=params, auth=self.auth)
        resp = response.json()
        user_id = resp['_items'][0]['_id']

        with assert_raises(BackendException) as cm:
            data = {'alias': 'modified with no header'}
            backend.put('/'.join(['user', user_id]), data=data)
        ex = cm.exception
        print('exception:', str(ex.code))
        assert_true(ex.code == 1000, str(ex))

        with assert_raises(BackendException) as cm:
            data = {'alias': 'modified test again and again'}
            headers = {'If-Match': "567890987678"}
            response = backend.put('/'.join(['user', user_id]), data=data, headers=headers)
        ex = cm.exception
        print('exception:', str(ex.code))
        assert_true(ex.code == 405, str(ex))
    def test_2_all_pages(self):
        """
        Get all items (so all pages) of a resource

        :return: None
        """
        print('')
        print('get all elements on an endpoint')

        # Create client API
        backend = Backend(self.backend_address)
        backend.login('admin', 'admin')

        # Get all elements
        print('get all hostgroups at once')
        params = {'max_results': 3}
        items = backend.get_all('hostgroup', params=params)
        hosts = items['_items']
        self.assertEqual(len(hosts), 101)
    def test_recalculate(self):
        # add host
        data = json.loads(open("cfg/host_srv001.json").read())
        self.backend.post("host", data)
        rh = self.backend.get("host")

        # Add command
        data = json.loads(open("cfg/command_ping.json").read())
        self.backend.post("command", data)
        # Check if command right in backend
        rc = self.backend.get("command")
        self.assertEqual(rc["_items"][0]["command_name"], "ping")

        # Add service
        data = json.loads(open("cfg/service_srv001_ping.json").read())
        data["host_name"] = rh["_items"][0]["_id"]
        data["check_command"] = rc["_items"][0]["_id"]
        self.backend.post("service", data)
        # Check if service right in backend
        rs = self.backend.get("service")
        self.assertEqual(rs["_items"][0]["service_description"], "ping")

        self.backend.delete("livesynthesis", {})
        self.p.kill()
        time.sleep(3)
        self.p = subprocess.Popen(
            ["uwsgi", "-w", "alignakbackend:app", "--socket", "0.0.0.0:5000", "--protocol=http", "--enable-threads"]
        )
        time.sleep(3)

        # Check if livestate right recalculate
        self.backend = Backend("http://127.0.0.1:5000")
        self.backend.login("admin", "admin", "force")
        r = self.backend.get("livesynthesis")
        self.assertEqual(len(r["_items"]), 1)
        self.assertEqual(r["_items"][0]["hosts_total"], 1)
        self.assertEqual(r["_items"][0]["hosts_up_hard"], 0)
        self.assertEqual(r["_items"][0]["hosts_up_soft"], 0)
        self.assertEqual(r["_items"][0]["hosts_down_hard"], 0)
        self.assertEqual(r["_items"][0]["hosts_down_soft"], 0)
        self.assertEqual(r["_items"][0]["hosts_unreachable_hard"], 1)
        self.assertEqual(r["_items"][0]["hosts_unreachable_soft"], 0)
        self.assertEqual(r["_items"][0]["hosts_acknowledged"], 0)
        self.assertEqual(r["_items"][0]["services_total"], 1)
        self.assertEqual(r["_items"][0]["services_ok_hard"], 1)
        self.assertEqual(r["_items"][0]["services_ok_soft"], 0)
        self.assertEqual(r["_items"][0]["services_warning_hard"], 0)
        self.assertEqual(r["_items"][0]["services_warning_soft"], 0)
        self.assertEqual(r["_items"][0]["services_critical_hard"], 0)
        self.assertEqual(r["_items"][0]["services_critical_soft"], 0)
        self.assertEqual(r["_items"][0]["services_unknown_hard"], 0)
        self.assertEqual(r["_items"][0]["services_unknown_soft"], 0)

        self.backend.delete("contact", {})
        self.p.kill()
    def test_02_bad_parameters(self):
        global backend_address

        print ''
        print 'test refused connection with username/password'

        # Create client API
        backend = Backend(backend_address)

        print "no username or no password, login refused - exception 1001"
        with assert_raises(BackendException) as cm:
            result = backend.login(None, None)
        ex = cm.exception # raised exception is available through exception property of context
        print 'exception:', str(ex.code)
        assert_true(ex.code == 1001, str(ex))
        print 'authenticated:', backend.authenticated

        print "invalid username/password, login refused - returns false"
        result = backend.login('admin', 'bad_password')
        assert_false(backend.authenticated)
Beispiel #21
0
    def test_2_all_pages(self):
        """
        Get all items (so all pages) of a resource

        :return: None
        """
        print('get all elements on an endpoint')

        # Create client API
        backend = Backend(self.backend_address)
        backend.login('admin', 'admin')

        # Get all elements
        print('get all hostgroups at once')
        params = {'max_results': 3}
        items = backend.get_all('hostgroup', params=params)
        hostgroups = items['_items']
        for hostgroup in hostgroups:
            print("Group: %s" % hostgroup['name'])
        self.assertEqual(len(hostgroups), 101)
    def test_1_patch_successful(self):
        """
        Test patch a user successfully

        :return: None
        """
        backend = Backend(self.backend_address)
        backend.login('admin', 'admin')

        # get user admin
        params = {"where": {"name": "admin"}}
        response = requests.get(self.backend_address + '/user', json=params, auth=self.auth)
        resp = response.json()
        user_id = resp['_items'][0]['_id']
        user_etag = resp['_items'][0]['_etag']

        data = {'alias': 'modified test'}
        headers = {'If-Match': user_etag}
        response = backend.patch('/'.join(['user', user_id]), data=data, headers=headers)
        assert_true(response['_status'] == 'OK')
    def test_1_domains(self):
        """
        Test get domains (= all resource/enpoints available)

        :return: None
        """
        # Create client API
        backend = Backend(self.backend_address)
        backend.login('admin', 'admin')

        # Get all available endpoints
        print('get all domains')
        # Filter the templates ...
        items = backend.get_domains()
        print("Got %d elements: %s" % (len(items), items))
        assert_true('_items' not in items)
        # assert_true(len(items) == 26)
        for item in items:
            assert_true('href' in item)
            assert_true('title' in item)
            print("Domain: ", item)
    def test_03_token_generate(self):
        global backend_address

        print ''
        print 'force authentication token generation'

        # Create client API
        backend = Backend(backend_address)

        print 'request new token generation'
        result = backend.login('admin', 'admin', 'force')
        assert_true(backend.authenticated)
        token1 = backend.token
        print 'token1:', token1
        print 'request new token generation'
        result = backend.login('admin', 'admin', 'force')
        print 'authenticated:', backend.authenticated
        assert_true(backend.authenticated)
        token2 = backend.token
        print 'token2:', token2
        assert_true(token1 != token2)
Beispiel #25
0
    def configure(self, endpoint):
        """
        Initialize backend connection ...
        """
        # Backend API start point
        if endpoint.endswith('/'):  # pragma: no cover - test url is complying ...
            self.url_endpoint_root = endpoint[0:-1]
        else:
            self.url_endpoint_root = endpoint

        logger.info("backend endpoint: %s", self.url_endpoint_root)
        self.backend = Backend(self.url_endpoint_root)
Beispiel #26
0
    def test_1_put_successful_inception(self):
        """
        Test put an alignakretention successfully with inception

        :return: None
        """
        backend = Backend(self.backend_address)
        backend.login('admin', 'admin')

        # get alignakretention
        params = {}
        response = requests.get(self.backend_address + '/alignakretention', json=params,
                                auth=self.auth)
        resp = response.json()
        ar_id = resp['_items'][0]['_id']

        data = {'alias': 'modified test'}
        headers = {'If-Match': 'foo'}
        response = backend.put('/'.join(['alignakretention', ar_id]), data=data, headers=headers,
                               inception=True)
        assert_true(response['_status'] == 'OK')
Beispiel #27
0
    def test_1_domains(self):
        """
        Test get domains (= all resource/enpoints available)

        :return: None
        """
        # Create client API
        backend = Backend(self.backend_address)
        backend.login('admin', 'admin')

        # Get all available endpoints
        print('get all domains')
        # Filter the templates ...
        items = backend.get_domains()
        print("Got %d elements: %s" % (len(items), items))
        assert_true('_items' not in items)
        # assert_true(len(items) == 26)
        for item in items:
            assert_true('href' in item)
            assert_true('title' in item)
            print("Domain: ", item)
Beispiel #28
0
    def test_2_patch_exception(self):
        """
        Test patch a user with errors (so exceptions)

        :return: None
        """
        backend = Backend(self.backend_address)
        backend.login('admin', 'admin')

        # get user admin
        params = {"where": {"name": "admin"}}
        response = requests.get(self.backend_address + '/user',
                                json=params,
                                auth=self.auth)
        resp = response.json()
        user_id = resp['_items'][0]['_id']
        user_etag = resp['_items'][0]['_etag']

        with assert_raises(BackendException) as cm:
            data = {'alias': 'modified with no header'}
            backend.patch('/'.join(['user', user_id]), data=data)
        ex = cm.exception
        print('exception:', str(ex.code))
        assert_true(ex.code == 1000, str(ex))

        with assert_raises(BackendException) as cm:
            data = {'bad_field': 'bad field name ... unknown in data model'}
            headers = {'If-Match': user_etag}
            backend.patch('/'.join(['user', user_id]),
                          data=data,
                          headers=headers,
                          inception=True)
        ex = cm.exception
        assert_true(ex.code == 422)

        with assert_raises(BackendException) as cm:
            data = {'alias': 'modified test again and again'}
            headers = {'If-Match': "567890987678"}
            response = backend.patch('/'.join(['user', user_id]),
                                     data=data,
                                     headers=headers)
        ex = cm.exception
        print('exception:', str(ex.code))
        assert_true(ex.code == 412, str(ex))
Beispiel #29
0
    def test_3_delete_connection_error(self):
        """
        Backend connection error when deleting an object...

        :return: None
        """
        print('test connection error when deleting an object')

        # Create client API
        backend = Backend(self.backend_address)
        backend.login('admin', 'admin')

        # Create a new timeperiod
        data = {
            "name":
            "Testing TP 2",
            "alias":
            "Test TP 2",
            "dateranges": [{
                u'monday': u'09:00-17:00'
            }, {
                u'tuesday': u'09:00-17:00'
            }, {
                u'wednesday': u'09:00-17:00'
            }, {
                u'thursday': u'09:00-17:00'
            }, {
                u'friday': u'09:00-17:00'
            }],
            "_realm":
            self.realmAll_id
        }
        response = backend.post('timeperiod', data=data)
        assert_true(response['_status'] == 'OK')
        timeperiod_id = response['_id']
        timeperiod_etag = response['_etag']

        headers = {'If-Match': timeperiod_etag}
        response = backend.delete('/'.join(['timeperiod', timeperiod_id]),
                                  headers=headers)
        assert_true(response['_status'] == 'OK')

        print("stop the alignak backend")
        self.pid.kill()

        with assert_raises(BackendException) as cm:
            headers = {'If-Match': timeperiod_etag}
            response = backend.delete('/'.join(['timeperiod', timeperiod_id]),
                                      headers=headers)
            assert_true(response['_status'] == 'OK')
        ex = cm.exception
        self.assertEqual(ex.code, 1000)
Beispiel #30
0
    def test_4_put_connection_error(self):
        """
        Backend connection error when replacing an object...

        :return: None
        """
        print('test connection error when replacing an object')

        # Create client API
        backend = Backend(self.backend_address)
        backend.login('admin', 'admin')

        # get alignakretention
        params = {}
        response = requests.get(self.backend_address + '/alignakretention', json=params,
                                auth=self.auth)
        resp = response.json()
        ar_id = resp['_items'][0]['_id']
        ar_etag = resp['_items'][0]['_etag']

        print("stop the alignak backend")
        self.pid.kill()

        with assert_raises(BackendException) as cm:
            data = {
                'host': 'srv001',
                'latency': 2,
                'last_state_type': 'HARD',
                'state': 'UP',
                'last_chk': 0,
            }
            headers = {'If-Match': ar_etag}
            response = backend.put('/'.join(['alignakretention', ar_id]), data=data,
                                   headers=headers)
            assert_true(response['_status'] == 'OK')
        ex = cm.exception
        self.assertEqual(ex.code, 1000)
    def test_03_token_generate(self):
        """
        Test token generation

        :return: None
        """
        print('')
        print('force authentication token generation')

        # Create client API
        backend = Backend(self.backend_address)

        print('request new token generation')
        backend.login('admin', 'admin', 'force')
        assert_true(backend.authenticated)
        token1 = backend.token
        print('token1:', token1)
        print('request new token generation')
        backend.login('admin', 'admin', 'force')
        print('authenticated:', backend.authenticated)
        assert_true(backend.authenticated)
        token2 = backend.token
        print('token2:', token2)
        assert_true(token1 != token2)
    def test_02_bad_parameters(self):
        """
        Test with bad username/password

        :return: None
        """
        print('')
        print('test refused connection with username/password')

        # Create client API
        backend = Backend(self.backend_address)

        print('Login - missing credentials ...')
        with assert_raises(BackendException) as cm:
            backend.login(None, None)
        ex = cm.exception
        print('exception:', str(ex.code))
        assert_true(ex.code == 1000, str(ex))
        assert_true("Missing mandatory parameters" in str(ex))

        print('Login - missing credentials ...')
        with assert_raises(BackendException) as cm:
            backend.login('', '')
        ex = cm.exception
        print('exception:', str(ex.code))
        assert_true(ex.code == 1000, str(ex))
        assert_true("Missing mandatory parameters" in str(ex))

        print('Login - missing credentials ...')
        with assert_raises(BackendException) as cm:
            backend.login('admin', '')
        ex = cm.exception
        print('exception:', str(ex.code))
        assert_true(ex.code == 1000, str(ex))

        print("invalid username/password, login refused")
        result = backend.login('admin', 'bad_password')
        assert_false(result)
        assert_false(backend.authenticated)
    def test_2_patch_exception(self):
        """
        Test patch a user with errors (so exceptions)

        :return: None
        """
        backend = Backend(self.backend_address)
        backend.login('admin', 'admin')

        # get user admin
        params = {"where": {"name": "admin"}}
        response = requests.get(self.backend_address + '/user', json=params, auth=self.auth)
        resp = response.json()
        user_id = resp['_items'][0]['_id']
        user_etag = resp['_items'][0]['_etag']

        with assert_raises(BackendException) as cm:
            data = {'alias': 'modified with no header'}
            backend.patch('/'.join(['user', user_id]), data=data)
        ex = cm.exception
        print('exception:', str(ex.code))
        assert_true(ex.code == 1005, str(ex))

        with assert_raises(BackendException) as cm:
            data = {'bad_field': 'bad field name ... unknown in data model'}
            headers = {'If-Match': user_etag}
            backend.patch('/'.join(['user', user_id]), data=data, headers=headers, inception=True)
        ex = cm.exception
        print('exception:', str(ex.code), ex.message, ex.response)
        if "_issues" in ex.response:
            for issue in ex.response["_issues"]:
                print("Issue: %s - %s" % (issue, ex.response["_issues"][issue]))
        assert_true(ex.code == 422)
        assert_true(ex.response["_issues"])

        with assert_raises(BackendException) as cm:
            data = {'alias': 'modified test again and again'}
            headers = {'If-Match': "567890987678"}
            response = backend.patch('/'.join(['user', user_id]), data=data, headers=headers)
        ex = cm.exception
        print('exception:', str(ex.code))
        assert_true(ex.code == 412, str(ex))
Beispiel #34
0
    def __init__(self, backend_endpoint='http://127.0.0.1:5000', glpi=None):
        """
        Create an instance
        """
        # Set a unique id for each DM object
        self.__class__.id += 1

        # Associated backend object
        self.backend_endpoint = backend_endpoint
        self.backend = Backend(backend_endpoint)

        # Associated Glpi backend object
        self.glpi = None
        if glpi:
            self.glpi = Glpi(glpi.get('glpi_ws_backend', None))
            self.glpi_ws_login = glpi.get('glpi_ws_login', None)
            self.glpi_ws_password = glpi.get('glpi_ws_password', None)

        # Backend available objects (filled with objects received from backend)
        # self.backend_available_objets = []

        # Get known objects type from the imported modules
        # Search for classes including an _type attribute
        self.known_classes = []
        for k, v in globals().items():
            if isinstance(globals()[k], type) and '_type' in globals()[k].__dict__:
                self.known_classes.append(globals()[k])
                logger.debug(
                    "Known class %s for object type: %s",
                    globals()[k], globals()[k].getType()
                )

        self.connected = False
        self.logged_in_user = None
        self.connection_message = None
        self.loading = 0
        self.loaded = False

        self.refresh_required = False
        self.refresh_done = False

        self.updated = datetime.utcnow()
    def test_02_bad_parameters(self):
        """
        Test with bad username/password

        :return: None
        """
        print('')
        print('test refused connection with username/password')

        # Create client API
        backend = Backend(self.backend_address)

        print('Login - missing credentials ...')
        with assert_raises(BackendException) as cm:
            backend.login(None, None)
        ex = cm.exception
        print('exception:', str(ex.code))
        assert_true(ex.code == 1001, str(ex))
        assert_true("Missing mandatory parameters" in str(ex))

        print('Login - missing credentials ...')
        with assert_raises(BackendException) as cm:
            backend.login('', '')
        ex = cm.exception
        print('exception:', str(ex.code))
        assert_true(ex.code == 1001, str(ex))
        assert_true("Missing mandatory parameters" in str(ex))

        print('Login - missing credentials ...')
        with assert_raises(BackendException) as cm:
            backend.login('admin', '')
        ex = cm.exception
        print('exception:', str(ex.code))
        assert_true(ex.code == 1001, str(ex))

        print("invalid username/password, login refused - returns false")
        result = backend.login('admin', 'bad_password')
        assert_false(result)
        assert_false(backend.authenticated)
    def __init__(self, mod_conf):
        """
        Module initialization

        mod_conf is a dictionary that contains:
        - all the variables declared in the module configuration file
        - a 'properties' value that is the module properties as defined globally in this file

        :param mod_conf: module configuration file as a dictionary
        """
        BaseModule.__init__(self, mod_conf)

        # pylint: disable=global-statement
        global logger
        logger = logging.getLogger('alignak.module.%s' % self.alias)

        logger.debug("inner properties: %s", self.__dict__)
        logger.debug("received configuration: %s", mod_conf.__dict__)

        self.url = getattr(mod_conf, 'api_url', 'http://localhost:5000')
        self.backend = Backend(self.url)
        self.backend.token = getattr(mod_conf, 'token', '')
        self.backend_connected = False
        if self.backend.token == '':
            self.getToken(getattr(mod_conf, 'username', ''), getattr(mod_conf, 'password', ''),
                          getattr(mod_conf, 'allowgeneratetoken', False))

        self.logged_in = self.backendConnection()

        self.ref_live = {
            'host': {},
            'service': {}
        }
        self.mapping = {
            'host': {},
            'service': {}
        }
        self.hosts = {}
        self.services = {}
        self.loaded_hosts = False
        self.loaded_services = False
Beispiel #37
0
    def test_3_put_exception_method_allowed(self):
        """
        Test put a user with errors (so exceptions) because PUT method not allowed on this endpoint

        :return: None
        """
        backend = Backend(self.backend_address)
        backend.login('admin', 'admin')

        # get alignakretention
        params = {}
        response = requests.get(self.backend_address + '/alignakretention', json=params,
                                auth=self.auth)
        resp = response.json()
        ar_id = resp['_items'][0]['_id']

        with assert_raises(BackendException) as cm:
            data = {
                'host': 'srv001',
                'latency': 2,
                'last_state_type': 'HARD',
                'state': 'UP',
                'last_chk': 0,
            }
            backend.put('/'.join(['alignakretention', ar_id]), data=data)
        ex = cm.exception
        print('exception:', str(ex.code))
        assert_true(ex.code == 1000, str(ex))

        with assert_raises(BackendException) as cm:
            data = {
                'host': 'srv001',
                'latency': 2,
                'last_state_type': 'HARD',
                'state': 'UP',
                'last_chk': 0,
            }
            headers = {'If-Match': "567890987678"}
            response = backend.put('/'.join(['alignakretention', ar_id]), data=data,
                                   headers=headers)
        ex = cm.exception
        print('exception:', str(ex.code))
        assert_true(ex.code == 412, str(ex))
Beispiel #38
0
    def test_2_delete_exceptions(self):
        """
        Test delete a timeperiod with errors (so exceptions)

        :return: None
        """
        backend = Backend(self.backend_address)
        backend.login('admin', 'admin')

        # Create a new timeperiod
        data = {
            "name":
            "Testing TP",
            "alias":
            "Test TP",
            "dateranges": [{
                u'monday': u'09:00-17:00'
            }, {
                u'tuesday': u'09:00-17:00'
            }, {
                u'wednesday': u'09:00-17:00'
            }, {
                u'thursday': u'09:00-17:00'
            }, {
                u'friday': u'09:00-17:00'
            }],
            "_realm":
            self.realmAll_id
        }
        response = backend.post('timeperiod', data=data)
        assert_true(response['_status'] == 'OK')
        timeperiod_id = response['_id']
        timeperiod_etag = response['_etag']

        with assert_raises(BackendException) as cm:
            headers = {'If-Match': timeperiod_etag}
            response = backend.delete(
                '/'.join(['timeperiod', '5' + timeperiod_id]), headers)
        ex = cm.exception
        print('exception:', str(ex.code))
        assert_true(ex.code == 404, str(ex))
Beispiel #39
0
    def test_4_connection_error(self):
        """
        Backend connection error when getting an object...

        :return: None
        """
        print('test connection error when getting an object')

        # Create client API
        backend = Backend(self.backend_address)
        backend.login('admin', 'admin')

        print("stop the alignak backend")
        self.pid.kill()

        with assert_raises(BackendException) as cm:
            print('get all hostgroups at once')
            params = {'max_results': 3}
            backend.get_all('hostgroup', params=params)
        ex = cm.exception
        self.assertEqual(ex.code, 1000)
Beispiel #40
0
    def test_1_delete_successful(self):
        """
        Test delete a timeperiod successfully

        :return: None
        """
        backend = Backend(self.backend_address)
        backend.login('admin', 'admin')

        # Create a new timeperiod
        data = {
            "name":
            "Testing TP",
            "alias":
            "Test TP",
            "dateranges": [{
                u'monday': u'09:00-17:00'
            }, {
                u'tuesday': u'09:00-17:00'
            }, {
                u'wednesday': u'09:00-17:00'
            }, {
                u'thursday': u'09:00-17:00'
            }, {
                u'friday': u'09:00-17:00'
            }],
            "_realm":
            self.realmAll_id
        }
        response = backend.post('timeperiod', data=data)
        assert_true(response['_status'] == 'OK')
        timeperiod_id = response['_id']
        timeperiod_etag = response['_etag']

        headers = {'If-Match': timeperiod_etag}
        response = backend.delete('/'.join(['timeperiod', timeperiod_id]),
                                  headers=headers)
        assert_true(response['_status'] == 'OK')
    def test_03_token_generate(self):
        """
        Test token generation

        :return: None
        """
        print('')
        print('force authentication token generation')

        # Create client API
        backend = Backend(self.backend_address)

        print('request new token generation')
        backend.login('admin', 'admin', 'force')
        assert_true(backend.authenticated)
        token1 = backend.token
        print('token1:', token1)
        print('request new token generation')
        backend.login('admin', 'admin', 'force')
        print('authenticated:', backend.authenticated)
        assert_true(backend.authenticated)
        token2 = backend.token
        print('token2:', token2)
        assert_true(token1 != token2)
    def test_12_all_pages(self):
        global backend_address

        print ''
        print 'get all elements on an endpoint'

        # Create client API
        backend = Backend(backend_address)

        print 'Login ...'
        print 'authenticated:', backend.authenticated
        result = backend.login('admin', 'admin')
        print 'authenticated:', backend.authenticated
        print 'token:', backend.token
        assert_true(backend.authenticated)

        # Get all available endpoints
        print 'get all domains'
        items = backend.get_domains()
        print "Got %d elements:" % len(items)
        assert_true('_items' not in items)
        assert_true(len(items) > 0)
        for item in items:
            if item['href'] in ['loghost', 'logservice']:
                continue
            assert_true('href' in item)
            assert_true('title' in item)
            print "Domain: ", item

            # Get all elements
            print 'get all %s at once' % item['href']
            items = backend.get_all(item['href'])
            print "Got %d elements:" % len(items)
            assert_true('_items' not in items)
            # assert_true(len(items) > 0)
            for item in items:
                assert_true('_etag' in item)
                print "etag: ", item['_etag']

        # Get all available endpoints
        print 'get all domains'
        items = backend.get_domains()
        print "Got %d elements:" % len(items)
        assert_true('_items' not in items)
        assert_true(len(items) > 0)
        for item in items:
            if item['href'] in ['loghost', 'logservice']:
                continue
            assert_true('href' in item)
            assert_true('title' in item)
            print "Domain: ", item

            # Get all elements
            print 'get all %s at once' % item['href']
            params = {'max_results': 2}
            items = backend.get_all(item['href'], params=params)
            print "Got %d elements:" % len(items)
            assert_true('_items' not in items)
            # assert_true(len(items) > 0)
            for item in items:
                assert_true('_etag' in item)
                print "etag: ", item['_etag']

        # Get all hosts
        print 'get all hosts at once, 1 item per page'
        params = {'max_results':1}
        items = backend.get_all(item['href'], params=params)
        print "Got %d elements:" % len(items)
        assert_true('_items' not in items)
        # assert_true(len(items) > 0)
        for item in items:
            assert_true('_etag' in item)
            print "etag: ", item['_etag']
    def test_04_connection_username(self):
        global backend_address

        print ''
        print 'test accepted connection with username/password'

        # Create client API
        backend = Backend(backend_address)

        print 'Login ...'
        result = backend.login('admin', 'admin')
        print 'authenticated:', backend.authenticated
        print 'token:', backend.token
        assert_true(backend.authenticated)

        print 'Logout ...'
        result = backend.logout()
        print 'authenticated:', backend.authenticated
        print 'token:', backend.token
        assert_false(backend.authenticated)

        print 'Login ...'
        print 'authenticated:', backend.authenticated
        result = backend.login('admin', 'admin')
        print 'authenticated:', backend.authenticated
        print 'token:', backend.token
        assert_true(backend.authenticated)

        print 'Logout ...'
        result = backend.logout()
        print 'authenticated:', backend.authenticated
        print 'token:', backend.token
        assert_false(backend.authenticated)

        print 'Logout ...'
        result = backend.logout()
        print 'authenticated:', backend.authenticated
        print 'token:', backend.token
        assert_false(backend.authenticated)

        print 'get object ... must be refused!'
        with assert_raises(BackendException) as cm:
            items = backend.get('host')
        ex = cm.exception
        print 'exception:', str(ex.code)
        assert_true(ex.code == 1001, str(ex))

        print 'get_all object ... must be refused!'
        with assert_raises(BackendException) as cm:
            items = backend.get_all('host')
        ex = cm.exception
        print 'exception:', str(ex.code)
        assert_true(ex.code == 1001, str(ex))

        print 'get all domains ... must be refused!'
        with assert_raises(BackendException) as cm:
            items = backend.get_domains()
        ex = cm.exception
        print 'exception:', str(ex.code)
        assert_true(ex.code == 1001, str(ex))

        print 'post data ... must be refused!'
        with assert_raises(BackendException) as cm:
            data = { 'fake': 'fake' }
            response = backend.post('contact', data=data)
        ex = cm.exception
        print 'exception:', str(ex.code)
        assert_true(ex.code == 1001, str(ex))

        print 'patch data ... must be refused!'
        with assert_raises(BackendException) as cm:
            data = { 'fake': 'fake' }
            headers = { 'If-Match': '' }
            response = backend.patch('contact', data=data, headers=headers)
        ex = cm.exception
        print 'exception:', str(ex.code)
        assert_true(ex.code == 1001, str(ex))

        print 'delete data ... must be refused!'
        with assert_raises(BackendException) as cm:
            data = { 'fake': 'fake' }
            headers = { 'If-Match': '' }
            response = backend.delete('contact', headers=headers)
        ex = cm.exception
        print 'exception:', str(ex.code)
        assert_true(ex.code == 1001, str(ex))
Beispiel #44
0
    def __init__(self, mod_conf):
        """Module initialization

        mod_conf is a dictionary that contains:
        - all the variables declared in the module configuration file
        - a 'properties' value that is the module properties as defined globally in this file

        :param mod_conf: module configuration file as a dictionary
        """
        BaseModule.__init__(self, mod_conf)

        # pylint: disable=global-statement
        global logger
        logger = logging.getLogger('alignak.module.%s' % self.alias)
        logger.setLevel(getattr(mod_conf, 'log_level', logging.INFO))

        logger.debug("inner properties: %s", self.__dict__)
        logger.debug("received configuration: %s", mod_conf.__dict__)

        self.client_processes = int(getattr(mod_conf, 'client_processes', 1))
        logger.info("Number of processes used by backend client: %s",
                    self.client_processes)

        self.default_realm = None

        logger.info("StatsD configuration: %s:%s, prefix: %s, enabled: %s",
                    getattr(mod_conf, 'statsd_host', 'localhost'),
                    int(getattr(mod_conf, 'statsd_port', '8125')),
                    getattr(mod_conf, 'statsd_prefix', 'alignak'),
                    (getattr(mod_conf, 'statsd_enabled', '0') != '0'))
        self.statsmgr = Stats()
        self.statsmgr.register(
            self.alias,
            'module',
            statsd_host=getattr(mod_conf, 'statsd_host', 'localhost'),
            statsd_port=int(getattr(mod_conf, 'statsd_port', '8125')),
            statsd_prefix=getattr(mod_conf, 'statsd_prefix', 'alignak'),
            statsd_enabled=(getattr(mod_conf, 'statsd_enabled', '0') != '0'))

        self.url = getattr(mod_conf, 'api_url', 'http://localhost:5000')
        logger.info("Alignak backend endpoint: %s", self.url)
        self.backend_connected = False
        self.backend_connection_retry_planned = 0
        try:
            self.backend_connection_retry_delay = int(
                getattr(mod_conf, 'backend_connection_retry_delay', '10'))
        except ValueError:
            self.backend_connection_retry_delay = 10
        logger.info("backend connection retry delay: %.2f seconds",
                    self.backend_connection_retry_delay)

        self.backend_errors_count = 0
        self.backend_username = getattr(mod_conf, 'username', '')
        self.backend_password = getattr(mod_conf, 'password', '')
        self.backend_generate = getattr(mod_conf, 'allowgeneratetoken', False)

        self.backend_count = int(getattr(mod_conf, 'backend_count', '50'))
        logger.info("backend pagination count: %d items", self.backend_count)

        self.backend_token = getattr(mod_conf, 'token', '')
        self.backend = Backend(self.url, self.client_processes)

        self.manage_update_program_status = getattr(mod_conf,
                                                    'update_program_status',
                                                    '0') == '1'
        logger.info("manage update_program_status broks: %s",
                    self.manage_update_program_status)

        # Log in to the backend
        self.logged_in = False
        self.backend_connected = self.backend_connection()

        # Get the default realm
        self.default_realm = self.get_default_realm()

        self.ref_live = {'host': {}, 'service': {}, 'user': {}}
        self.mapping = {'host': {}, 'service': {}, 'user': {}}

        # Objects reference
        self.load_protect_delay = int(
            getattr(mod_conf, 'load_protect_delay', '300'))
        self.last_load = 0

        # Backend to be posted data
        self.logcheckresults = []
Beispiel #45
0
class AlignakBackendScheduler(BaseModule):
    """
    This class is used to send live states to alignak-backend
    """
    def __init__(self, mod_conf):
        """Module initialization

        mod_conf is a dictionary that contains:
        - all the variables declared in the module configuration file
        - a 'properties' value that is the module properties as defined globally in this file

        :param mod_conf: module configuration file as a dictionary
        """
        BaseModule.__init__(self, mod_conf)

        # pylint: disable=global-statement
        global logger
        logger = logging.getLogger('alignak.module.%s' % self.alias)
        logger.setLevel(getattr(mod_conf, 'log_level', logging.INFO))

        logger.debug("inner properties: %s", self.__dict__)
        logger.debug("received configuration: %s", mod_conf.__dict__)

        self.client_processes = int(getattr(mod_conf, 'client_processes', 1))
        logger.info("Number of processes used by backend client: %s",
                    self.client_processes)

        self.backend_count = int(getattr(mod_conf, 'backend_count', '50'))
        logger.info("backend pagination count: %d items", self.backend_count)

        logger.info("StatsD configuration: %s:%s, prefix: %s, enabled: %s",
                    getattr(mod_conf, 'statsd_host', 'localhost'),
                    int(getattr(mod_conf, 'statsd_port', '8125')),
                    getattr(mod_conf, 'statsd_prefix', 'alignak'),
                    (getattr(mod_conf, 'statsd_enabled', '0') != '0'))
        self.statsmgr = Stats()
        self.statsmgr.register(
            self.alias,
            'module',
            statsd_host=getattr(mod_conf, 'statsd_host', 'localhost'),
            statsd_port=int(getattr(mod_conf, 'statsd_port', '8125')),
            statsd_prefix=getattr(mod_conf, 'statsd_prefix', 'alignak'),
            statsd_enabled=(getattr(mod_conf, 'statsd_enabled', '0') != '0'))

        self.url = getattr(mod_conf, 'api_url', 'http://localhost:5000')
        logger.info("Alignak backend endpoint: %s", self.url)
        self.backend = Backend(self.url, self.client_processes)
        self.backend.token = getattr(mod_conf, 'token', '')
        self.backend_connected = False
        self.backend_errors_count = 0
        self.backend_username = getattr(mod_conf, 'username', '')
        self.backend_password = getattr(mod_conf, 'password', '')
        self.backend_generate = getattr(mod_conf, 'allowgeneratetoken', False)

        if not self.backend.token:
            logger.warning(
                "no user token configured. "
                "It is recommended to set a user token rather than a user login "
                "in the configuration. Trying to get a token from the provided "
                "user login information...")
            self.getToken()
        else:
            self.backend_connected = True

    # Common functions
    def do_loop_turn(self):
        """This function is called/used when you need a module with
        a loop function (and use the parameter 'external': True)
        """
        logger.info("[Backend Scheduler] In loop")
        time.sleep(1)

    def getToken(self):
        """Authenticate and get the token

        :return: None
        """
        generate = 'enabled'
        if not self.backend_generate:
            generate = 'disabled'

        try:
            start = time.time()
            self.backend_connected = self.backend.login(
                self.backend_username, self.backend_password, generate)
            self.statsmgr.counter('backend-login', 1)
            self.statsmgr.timer('backend-login-time', time.time() - start)
            if not self.backend_connected:
                logger.warning("Backend login failed")
            self.token = self.backend.token
            self.backend_errors_count = 0
        except BackendException as exp:  # pragma: no cover - should not happen
            self.backend_connected = False
            self.backend_errors_count += 1
            logger.warning(
                "Alignak backend is not available for login. "
                "No backend connection, attempt: %d",
                self.backend_errors_count)
            logger.debug("Exception: %s", exp)

    def raise_backend_alert(self, errors_count=10):
        """Raise a backend alert

        :return: True if the backend is not connected and the error count
        is greater than a defined threshold
        """
        logger.debug(
            "Check backend connection, connected: %s, errors count: %d",
            self.backend_connected, self.backend_errors_count)
        if not self.backend_connected and self.backend_errors_count >= errors_count:
            return True

        return False

    def hook_load_retention(self, scheduler):
        """Load retention data from alignak-backend

        :param scheduler: scheduler instance of alignak
        :type scheduler: object
        :return: None
        """

        all_data = {'hosts': {}, 'services': {}}

        if not self.backend_connected:
            self.getToken()
            if self.raise_backend_alert(errors_count=1):
                logger.warning("Alignak backend connection is not available. "
                               "Loading retention data is not possible.")
                return None

        if not self.backend_connected:
            return None

        # Get data from the backend
        try:
            start = time.time()
            params = {"max_results": self.backend_count}
            response = self.backend.get_all('alignakretention', params)
            for host in response['_items']:
                # clean unusable keys
                hostname = host['host']
                if 'retention_services' in host:
                    for service in host['retention_services']:
                        all_data['services'][(host['host'], service)] = \
                            host['retention_services'][service]
                for key in [
                        '_created', '_etag', '_id', '_links', '_updated',
                        'host', 'retention_services', '_user', 'schema_version'
                ]:
                    if key in host:
                        del host[key]
                all_data['hosts'][hostname] = host

            logger.info('%d hosts loaded from retention',
                        len(all_data['hosts']))
            self.statsmgr.counter('retention-load.hosts',
                                  len(all_data['hosts']))
            logger.info('%d services loaded from retention',
                        len(all_data['services']))
            self.statsmgr.counter('retention-load.services',
                                  len(all_data['services']))
            self.statsmgr.timer('retention-load.time', time.time() - start)

            scheduler.restore_retention_data(all_data)
        except BackendException:
            self.backend_connected = False
            self.backend_errors_count += 1
            logger.warning(
                "Alignak backend connection fails. Check and fix your configuration"
            )
            return False

        return True

    def hook_save_retention(self, scheduler):
        """Save retention data to alignak-backend

        :param scheduler: scheduler instance of alignak
        :type scheduler: object
        :return: None
        """
        if not self.backend_connected:
            self.getToken()
            if self.raise_backend_alert(errors_count=1):
                logger.warning("Alignak backend connection is not available. "
                               "Saving objects is not possible.")
                return None

        if not self.backend_connected:
            return None

        try:
            data_to_save = scheduler.get_retention_data()
            start_time = time.time()

            # get list of retention_data
            params = {"max_results": self.backend_count}
            response = self.backend.get_all('alignakretention', params)
            db_hosts = {}
            for host in response['_items']:
                db_hosts[host['host']] = host

            # add services in the hosts
            for host in data_to_save['hosts']:
                data_to_save['hosts'][host]['retention_services'] = {}
                data_to_save['hosts'][host]['host'] = host
            if 'services' in data_to_save:
                # Scheduler old-school: two separate dictionaries!
                for service in data_to_save['services']:
                    data_to_save['hosts'][service[0]]['retention_services'][service[1]] = \
                        data_to_save['services'][service]

            for host in data_to_save['hosts']:
                if host in db_hosts:
                    # if host in retention_data, PUT
                    headers = {'Content-Type': 'application/json'}
                    headers['If-Match'] = db_hosts[host]['_etag']
                    try:
                        logger.debug('Host retention data: %s',
                                     data_to_save['hosts'][host])
                        self.backend.put(
                            'alignakretention/%s' % (db_hosts[host]['_id']),
                            data_to_save['hosts'][host], headers, True)
                    except BackendException as exp:  # pragma: no cover - should not happen
                        logger.error('Put alignakretention error')
                        logger.error('Response: %s', exp.response)
                        logger.exception("Exception: %s", exp)
                        self.backend_connected = False
                        return False
                else:
                    # if not host in retention_data, POST
                    try:
                        logger.debug('Host retention data: %s',
                                     data_to_save['hosts'][host])
                        self.backend.post('alignakretention',
                                          data=data_to_save['hosts'][host])
                    except BackendException as exp:  # pragma: no cover - should not happen
                        logger.error('Post alignakretention error')
                        logger.error('Response: %s', exp.response)
                        logger.exception("Exception: %s", exp)
                        self.backend_connected = False
                        return False
            logger.info('%d hosts saved in retention',
                        len(data_to_save['hosts']))
            self.statsmgr.counter('retention-save.hosts',
                                  len(data_to_save['hosts']))
            logger.info('%d services saved in retention',
                        len(data_to_save['services']))
            self.statsmgr.counter('retention-save.services',
                                  len(data_to_save['services']))
            self.statsmgr.timer('retention-save.time',
                                time.time() - start_time)

            now = time.time()
            logger.info("Retention saved in %s seconds", (now - start_time))
        except BackendException:
            self.backend_connected = False
            self.backend_errors_count += 1
            logger.warning(
                "Alignak backend connection fails. Check and fix your configuration"
            )
            return False

        return True
    def test_multiprocess(self):
        """
        Test multiprocess get right all elements

        :return: None
        """
        print('')
        print('test creation')

        print('Create client API for URL:', self.backend_address)
        backend = Backend(self.backend_address, 8)
        backend.login('admin', 'admin')

        items = backend.get('realm')
        realm_id = items['_items'][0]['_id']

        # add 2000 commands
        backend.delete("command", {})
        data = {'command_line': 'check_ping', '_realm': realm_id}
        for i in range(1, 2001):
            data['name'] = "cmd %d" % i
            backend.post('command', data)

        # get without multiprocess
        backend_yannsolo = Backend(self.backend_address)
        backend_yannsolo.login('admin', 'admin')
        start_time = time.time()
        resp = backend_yannsolo.get_all('command', {'max_results': 20})
        threads_1 = time.time() - start_time
        self.assertEqual(len(resp['_items']), 2002,
                         "Number of commands in non multiprocess mode")

        # get with multiprocess (8 processes)
        start_time = time.time()
        resp = backend.get_all('command', {'max_results': 20})
        threads_8 = time.time() - start_time
        self.assertEqual(len(resp['_items']), 2002,
                         "Number of commands in multiprocess mode")
        ids = []
        for dat in resp['_items']:
            ids.append(dat['_id'])
        self.assertEqual(len(ids), 2002, "Number of id")
        # remove duplicates
        ids_final = set(ids)
        self.assertEqual(len(ids_final), 2002, "Number of id unique")

        print(threads_1)
        print(threads_8)
Beispiel #47
0
class AppBackend(object):
    """
        Class who collect informations with Backend-Client and returns data for
        Alignak-App.
    """
    def __init__(self):
        self.backend = None
        self.user = {}
        self.connected = False
        self.app = None

    def login(self, username=None, password=None):
        """
        Connect to app_backend with credentials in settings.cfg.

        :return: True if connected or False if not
        :rtype: bool
        """

        connect = False
        # Credentials
        if not username and not password:
            if self.user:
                username = self.user['token']
            else:
                username = get_app_config('Alignak', 'username')
                password = get_app_config('Alignak', 'password')

        # Create Backend object
        backend_url = get_app_config('Alignak', 'backend')
        processes = int(get_app_config('Alignak', 'processes'))

        self.backend = Backend(backend_url, processes=processes)

        logger.debug('Backend URL : %s', backend_url)
        logger.info('Try to connect to app_backend...')

        if username and password:
            # Username & password : not recommended, without "widgets.login.py" form.
            try:
                connect = self.backend.login(username, password)
                if connect:
                    self.user['username'] = username
                    self.user['token'] = self.backend.token
                logger.info('Connection by password: %s', str(connect))
            except BackendException as e:  # pragma: no cover
                logger.error('Connection to Backend has failed: %s', str(e))
        elif username and not password:
            # Username as token : recommended
            self.backend.authenticated = True
            if self.user:
                self.backend.token = self.user['token']
            else:
                self.backend.token = username
                self.user['token'] = username

            # Test to check token
            self.connected = True
            connect = bool(self.get('livesynthesis'))
            logger.info('Connection by token: %s', str(connect))
        else:
            # Else exit
            logger.error(
                'Connection to Backend has failed.\nCheck [Backend] section in configuration file.'
            )
            connect = False

        self.connected = connect

        return connect

    def get(self, endpoint, params=None, projection=None):
        """
        GET on alignak Backend REST API.

        :param endpoint: endpoint (API URL)
        :type endpoint: str
        :param params: dict of parameters for the app_backend API
        :type params: dict|None
        :param projection: list of field to get, if None, get all
        :type projection: list|None
        :return desired request of app_backend
        :rtype: dict
        """

        request = None

        if params is None:
            params = {'max_results': 50}
        if projection is not None:
            generate_proj = {}
            for field in projection:
                generate_proj[field] = 1
            params['projection'] = json.dumps(generate_proj)

        if self.connected:
            # Request
            try:
                request = self.backend.get_all(endpoint, params)
                logger.debug('GET: %s', endpoint)
                logger.debug('..with params: %s', str(params))
                logger.debug('...Response > %s', str(request['_status']))
            except BackendException as e:
                logger.error('GET failed: %s', str(e))
                logger.warning(
                    'Application will check the connection with Backend...')
                self.connected = False
                if not self.app.reconnect_mode:
                    self.app.reconnecting.emit(self, str(e))
                return request

        return request

    def post(self,
             endpoint,
             data,
             headers=None):  # pragma: no cover - Post already test by client
        """
        POST on alignak Backend REST API

        :param endpoint: endpoint (API URL)
        :type endpoint: str
        :param data: properties of item to create | add
        :type data: dict
        :param headers: headers (example: Content-Type)
        :type headers: dict|None
        :return: response (creation information)
        :rtype: dict
        """

        resp = None

        if self.connected:
            try:
                resp = self.backend.post(endpoint, data, headers=headers)
                logger.debug('POST on %s', endpoint)
                logger.debug('..with data: %s', str(data))
                logger.debug('...Response > %s', str(resp))
            except BackendException as e:
                logger.error('POST failed: %s', str(e))
                logger.warning(
                    'Application will check the connection with Backend...')
                self.connected = False
                if not self.app.reconnect_mode:
                    self.app.reconnecting.emit(self, str(e))
                return resp

        return resp

    def get_host(self, key, value, projection=None):
        """
        Return the host corresponding to "key"/"value" pair

        :param key: key corresponding to value
        :type key: str
        :param value: value of key
        :type value: str
        :param projection: list of field to get, if None, get all
        :type projection: list|None
        :return: None if not found or item dict
        :rtype: dict|None
        """

        params = {'where': json.dumps({'_is_template': False, key: value})}

        hosts = self.get('host', params, projection=projection)

        if hosts and len(hosts['_items']) > 0:  # pylint: disable=len-as-condition
            wanted_host = hosts['_items'][0]
        else:
            wanted_host = None

        return wanted_host

    def get_service(self, host_id, service_id, projection=None):
        """
        Returns the desired service of the specified host

        :param host_id: "_id" of host
        :type host_id: str
        :param service_id: "_id" of wanted service
        :type service_id: str
        :param projection: list of field to get, if None, get all
        :type projection: list|None
        :return: wanted service
        :rtype: dict
        """

        params = {
            'where': json.dumps({
                '_is_template': False,
                'host': host_id
            })
        }

        services = self.get('service', params=params, projection=projection)

        wanted_service = None
        if services:
            if len(services['_items']) > 0:  # pylint: disable=len-as-condition
                wanted_service = services['_items'][0]
            for service in services['_items']:
                if service['_id'] == service_id:
                    wanted_service = service

        return wanted_service

    def get_host_with_services(self, host_name):
        """
        Returns the desired host and all its services

        :param host_name: desired host
        :type host_name: str
        :return dict with host data and its associated services
        :rtype: dict
        """

        host_data = None

        host_projection = [
            'name', 'alias', 'ls_state', '_id', 'ls_acknowledged',
            'ls_downtimed', 'ls_last_check', 'ls_output', 'address',
            'business_impact', 'parents', 'ls_last_state_changed'
        ]
        host = self.get_host('name', host_name, projection=host_projection)

        if host:
            params = {
                'where': json.dumps({
                    '_is_template': False,
                    'host': host['_id']
                })
            }
            service_projection = [
                'name', 'alias', 'display_name', 'ls_state', 'ls_acknowledged',
                'ls_downtimed', 'ls_last_check', 'ls_output',
                'business_impact', 'customs', '_overall_state_id',
                'aggregation', 'ls_last_state_changed'
            ]
            services = self.get('service',
                                params=params,
                                projection=service_projection)

            services_host = services['_items']

            host_data = {'host': host, 'services': services_host}

        return host_data

    def get_user(self, projection=None):
        """
        Get current user. The token must already be acquired

        :param projection: list of field to get, if None, get all
        :type projection: list|None
        :return user items
        :rtype dict|None
        """

        params = {'where': json.dumps({'token': self.user['token']})}

        if projection is not None:
            generate_proj = {}
            for field in projection:
                generate_proj[field] = 1
            params['projection'] = json.dumps(generate_proj)

        user = self.get('user', params, projection=projection)

        if user:
            return user['_items'][0]

        return None

    def synthesis_count(self):
        """
        Get on "synthesis" endpoint and return the states of hosts and services

        :return: states of hosts and services.
        :rtype: dict
        """

        states = {
            'hosts': {
                'up': 0,
                'down': 0,
                'unreachable': 0,
                'acknowledge': 0,
                'downtime': 0
            },
            'services': {
                'ok': 0,
                'critical': 0,
                'unknown': 0,
                'warning': 0,
                'unreachable': 0,
                'acknowledge': 0,
                'downtime': 0
            }
        }
        live_synthesis = self.get('livesynthesis')

        if live_synthesis:
            for realm in live_synthesis['_items']:
                states['hosts']['up'] += realm['hosts_up_soft']
                states['hosts']['up'] += realm['hosts_up_hard']

                states['hosts']['unreachable'] += realm[
                    'hosts_unreachable_soft']
                states['hosts']['unreachable'] += realm[
                    'hosts_unreachable_hard']

                states['hosts']['down'] += realm['hosts_down_soft']
                states['hosts']['down'] += realm['hosts_down_hard']

                states['hosts']['acknowledge'] += realm['hosts_acknowledged']
                states['hosts']['downtime'] += realm['hosts_in_downtime']

                states['services']['ok'] += realm['services_ok_soft']
                states['services']['ok'] += realm['services_ok_hard']

                states['services']['warning'] += realm['services_warning_soft']
                states['services']['warning'] += realm['services_warning_hard']

                states['services']['critical'] += realm[
                    'services_critical_soft']
                states['services']['critical'] += realm[
                    'services_critical_hard']

                states['services']['unknown'] += realm['services_unknown_soft']
                states['services']['unknown'] += realm['services_unknown_hard']

                states['services']['unreachable'] += realm[
                    'services_unreachable_soft']
                states['services']['unreachable'] += realm[
                    'services_unreachable_hard']

                states['services']['acknowledge'] += realm[
                    'services_acknowledged']
                states['services']['downtime'] += realm['services_in_downtime']

        logger.info('Store current states...')

        return states
Beispiel #48
0
    def test_3_page_after_page(self):
        """
        Get page after page manually

        :return: None
        """
        print('backend connection with username/password')

        # Create client API
        backend = Backend(self.backend_address)
        backend.login('admin', 'admin')

        # Start with first page ... max_results=3
        last_page = False
        parameters = {'max_results': 3, 'page': 1}
        items = []
        while not last_page:
            resp = backend.get('hostgroup', params=parameters)
            assert_true('_items' in resp)
            assert_true('_links' in resp)
            assert_true('_meta' in resp)
            page_number = int(resp['_meta']['page'])
            total = int(resp['_meta']['total'])
            max_results = int(resp['_meta']['max_results'])
            assert_equal(total, 101)
            assert_equal(max_results, 3)
            if 'next' in resp['_links']:
                # It has pagination, so get items of all pages
                parameters['page'] = page_number + 1
            else:
                last_page = True
                assert_equal(page_number, 34)
            items.extend(resp['_items'])

        print("----------")
        print("Got %d elements:" % len(items))
        assert_equal(len(items), 101)

        # Start with first page ... max_results=10
        last_page = False
        parameters = {'max_results': 10, 'page': 1}
        items = []
        while not last_page:
            resp = backend.get('hostgroup', params=parameters)
            assert_true('_items' in resp)
            assert_true('_links' in resp)
            assert_true('_meta' in resp)
            page_number = int(resp['_meta']['page'])
            total = int(resp['_meta']['total'])
            max_results = int(resp['_meta']['max_results'])
            assert_equal(total, 101)
            assert_equal(max_results, 10)
            if 'next' in resp['_links']:
                # It has pagination, so get items of all pages
                parameters['page'] = page_number + 1
            else:
                last_page = True
                assert_equal(page_number, 11)
            items.extend(resp['_items'])

        # Start with first page ... no max_results
        last_page = False
        parameters = {'page': 1}
        items = []
        while not last_page:
            resp = backend.get('hostgroup', params=parameters)
            assert_true('_items' in resp)
            assert_true('_links' in resp)
            assert_true('_meta' in resp)
            page_number = int(resp['_meta']['page'])
            total = int(resp['_meta']['total'])
            max_results = int(resp['_meta']['max_results'])
            assert_equal(total, 101)
            assert_equal(max_results, 25)
            if 'next' in resp['_links']:
                # It has pagination, so get items of all pages
                parameters['page'] = page_number + 1
            else:
                last_page = True
                assert_equal(page_number, 5)
            items.extend(resp['_items'])

        print("----------")
        print("Got %d elements:" % len(items))
        assert_equal(len(items), 101)
    def test_13_page_after_page(self):
        global backend_address

        print ''
        print 'backend connection with username/password'


        # Create client API
        backend = Backend(backend_address)

        print 'Login ...'
        print 'authenticated:', backend.authenticated
        result = backend.login('admin', 'admin')
        print 'authenticated:', backend.authenticated
        print 'token:', backend.token
        assert_true(backend.authenticated)

        # Start with first page ...
        last_page = False
        parameters = { 'where': '{"register":true}', 'max_results': 2, 'page': 1 }
        items = []
        while not last_page:
            resp = backend.get('host', params=parameters)
            assert_true('_items' in resp)
            assert_true('_links' in resp)
            assert_true('_meta' in resp)
            print resp['_meta']
            page_number = int(resp['_meta']['page'])
            total = int(resp['_meta']['total'])
            max_results = int(resp['_meta']['max_results'])
            print "Got %d elements out of %d (page %d):" % (max_results, total, page_number)
            for item in resp['_items']:
                assert_true('host_name' in item)
                print "Host: ", item['host_name']

            if 'next' in resp['_links']:
                # It has pagination, so get items of all pages
                parameters['page'] = page_number + 1
                parameters['max_results'] = max_results
            else:
                last_page = True
            items.extend(resp['_items'])

        print "----------"
        print "Got %d elements:" % len(items)
        assert_true('_items' not in items)
        # assert_true(len(items) > 0)
        for item in items:
            assert_true('host_name' in item)
            print "Host: ", item['host_name']

        # Start with first page ...
        last_page = False
        parameters = { 'where': '{"register":true}', 'max_results': 10, 'page': 1 }
        items = []
        while not last_page:
            resp = backend.get('service', params=parameters)
            assert_true('_items' in resp)
            assert_true('_links' in resp)
            assert_true('_meta' in resp)
            print resp['_meta']
            page_number = int(resp['_meta']['page'])
            total = int(resp['_meta']['total'])
            max_results = int(resp['_meta']['max_results'])
            print "Got %d elements out of %d (page %d):" % (max_results, total, page_number)
            for item in resp['_items']:
                assert_true('host_name' in item)
                assert_true('service_description' in item)
                print "Service: %s/%s" % (item['host_name'], item['service_description'])

            if 'next' in resp['_links']:
                # It has pagination, so get items of all pages
                parameters['page'] = page_number + 1
                parameters['max_results'] = max_results
            else:
                last_page = True
            items.extend(resp['_items'])

        print "----------"
        print "Got %d elements:" % len(items)
        assert_true('_items' not in items)
        # assert_true(len(items) > 0)
        for item in items:
            assert_true('host_name' in item)
            assert_true('service_description' in item)
            print "Service: %s/%s" % (item['host_name'], item['service_description'])
    def test_21_post_patch_delete(self):
        global backend_address

        print ''
        print 'post/delete/patch some elements'

        # Create client API
        backend = Backend(backend_address)

        print 'Login ...'
        print 'authenticated:', backend.authenticated
        result = backend.login('admin', 'admin')
        print 'authenticated:', backend.authenticated
        print 'token:', backend.token
        assert_true(backend.authenticated)

        # Get all contacts
        print 'get all contacts at once'
        parameters = { 'where': '{"register":true}' }
        items = backend.get_all('contact', params=parameters)
        print "Got %d elements:" % len(items)
        assert_true('_items' not in items)
        for item in items:
            assert_true('contact_name' in item)
            assert_true('_id' in item)
            assert_true('_etag' in item)
            print "Contact: ", item['contact_name'], item['_id']
            # Test contact still exists ... delete him!
            if item['contact_name'] == 'test':
                headers = { 'If-Match': item['_etag'] }
                response = backend.delete('/'.join(['contact', item['_id']]), headers)
                print "Response:", response

        # Get all timeperiods
        print 'get all timeperiods at once'
        parameters = { 'where': '{"register":true}' }
        items = backend.get_all('timeperiod', params=parameters)
        print "Got %d elements:" % len(items)
        assert_true('_items' not in items)
        tp_id = ''
        for item in items:
            assert_true('timeperiod_name' in item)
            assert_true('_id' in item)
            tp_id = item['_id']
            print item
            print "TP: %s (%s), id=%s" % (item['timeperiod_name'], item['name'], item['_id'])

        if not tp_id:
            # Create a new timeperiod
            print 'create a timeperiod'
            data = {
                "timeperiod_name": "test",
                "name": "Testing TP",
                "alias": "Test TP",
                "dateranges": [
                    {u'monday': u'09:00-17:00'},
                    {u'tuesday': u'09:00-17:00'},
                    {u'wednesday': u'09:00-17:00'},
                    {u'thursday': u'09:00-17:00'},
                    {u'friday': u'09:00-17:00'}
                ],
                "register": True
            }
            response = backend.post('timeperiod', data=data)
            print "Response:", response
            assert_true('_created' in response)
            assert_true('_updated' in response)
            assert_true(response['_created'] == response['_updated'])

            # Get all timeperiods
            print 'get all timeperiods at once'
            parameters = { 'where': '{"register":true}' }
            items = backend.get_all('timeperiod', params=parameters)
            print "Got %d elements:" % len(items)
            assert_true('_items' not in items)
            tp_id = ''
            for item in items:
                assert_true('timeperiod_name' in item)
                assert_true('_id' in item)
                tp_id = item['_id']
                print "TP: %s (%s), id=%s" % (item['timeperiod_name'], item['name'], item['_id'])

        assert_true(tp_id != '')

        # Create a new contact, bad parameters
        print 'create a contact, missing fields'
        # Mandatory field contact_name is missing ...
        data = {
            "name": "Testing contact",
            "alias": "Fred",
            "back_role_super_admin": False,
            "back_role_admin": [],
            "min_business_impact": 0,
        }
        with assert_raises(BackendException) as cm:
            response = backend.post('contact', data=data)
        ex = cm.exception
        print 'exception:', str(ex.code), ex.message, ex.response
        if "_issues" in ex.response:
            for issue in ex.response["_issues"]:
                print "Issue: %s - %s" %(issue, ex.response["_issues"][issue])
        assert_true(ex.code == 422)
        assert_true(ex.response["_issues"])

        # Create a new contact
        print 'create a contact'
        data = {
            "contact_name": "test",
            "name": "Testing contact",
            "alias": "Fred",
            "back_role_super_admin": False,
            "back_role_admin": [],
            "min_business_impact": 0,
            "email": "*****@*****.**",

            "is_admin": False,
            "expert": False,
            "can_submit_commands": False,

            "host_notifications_enabled": True,
            "host_notification_period": tp_id,
            "host_notification_commands": [
            ],
            "host_notification_options": [
                "d",
                "u",
                "r"
            ],

            "service_notifications_enabled": True,
            "service_notification_period": tp_id,
            "service_notification_commands": [ ],
            "service_notification_options": [
                "w",
                "u",
                "c",
                "r"
            ],
            "retain_status_information": False,
            "note": "Monitoring template : default",
            "retain_nonstatus_information": False,
            "definition_order": 100,
            "address1": "",
            "address2": "",
            "address3": "",
            "address4": "",
            "address5": "",
            "address6": "",
            "pager": "",
            "notificationways": [],
            "register": True
        }
        response = backend.post('contact', data=data)
        print "Response:", response
        assert_true('_created' in response)
        assert_true('_updated' in response)
        assert_true(response['_created'] == response['_updated'])

        # Get all contacts
        print 'get all contacts at once'
        # Filter the templates ...
        parameters = { 'where': '{"register":true}' }
        items = backend.get_all('contact', params=parameters)
        print "Got %d elements:" % len(items)
        assert_true('_items' not in items)
        assert_true(len(items) > 0)
        # Search test contact
        contact_id = ''
        contact_etag = ''
        for item in items:
            assert_true('contact_name' in item)
            print "Contact: ", item['contact_name']
            if item['contact_name'] == 'test':
                contact_id = item['_id']
                contact_etag = item['_etag']
        assert_true(contact_id != '')
        assert_true(contact_etag != '')

        print 'changing contact alias ... no _etag'
        print 'id:', contact_id
        print 'etag:', contact_etag
        with assert_raises(BackendException) as cm:
            data = {'alias': 'modified with no header'}
            # headers['If-Match'] = contact_etag
            response = backend.patch('/'.join(['contact', contact_id]), data=data)
        ex = cm.exception
        print 'exception:', str(ex.code)
        assert_true(ex.code == 1005, str(ex))

        print 'changing contact alias ...'
        print 'id:', contact_id
        print 'etag:', contact_etag
        data = {'alias': 'modified test'}
        headers = {'If-Match': contact_etag}
        response = backend.patch('/'.join(['contact', contact_id]), data=data, headers=headers)
        print 'response:', response
        assert_true(response['_status'] == 'OK')

        response = backend.get('/'.join(['contact', contact_id]))
        print 'response:', response
        assert_true(response['alias'] == 'modified test')

        print 'changing contact alias ... bad _etag (inception = True)'
        print 'id:', contact_id
        print 'etag:', contact_etag
        data = {'alias': 'modified test again'}
        headers = {'If-Match': contact_etag}
        response = backend.patch('/'.join(['contact', contact_id]), data=data, headers=headers, inception=True)
        print 'response:', response
        assert_true(response['_status'] == 'OK')

        response = backend.get('/'.join(['contact', contact_id]))
        print 'response:', response
        assert_true(response['alias'] == 'modified test again')

        print 'changing contact unknown field ... must be refused'
        print 'id:', contact_id
        print 'etag:', contact_etag
        with assert_raises(BackendException) as cm:
            data = {'bad_field': 'bad field name ... unknown in data model'}
            headers = {'If-Match': contact_etag}
            response = backend.patch('/'.join(['contact', contact_id]), data=data, headers=headers, inception=True)
        ex = cm.exception
        print 'exception:', str(ex.code), ex.message, ex.response
        if "_issues" in ex.response:
            for issue in ex.response["_issues"]:
                print "Issue: %s - %s" %(issue, ex.response["_issues"][issue])
        assert_true(ex.code == 422)
        assert_true(ex.response["_issues"])

        print 'changing contact alias ... bad _etag (inception = False)'
        print 'id:', contact_id
        print 'etag:', contact_etag
        with assert_raises(BackendException) as cm:
            data = {'alias': 'modified test again and again'}
            headers = {'If-Match': contact_etag}
            response = backend.patch('/'.join(['contact', contact_id]), data=data, headers=headers)
        ex = cm.exception
        print 'exception:', str(ex.code)
        assert_true(ex.code == 412, str(ex))

        response = backend.get('/'.join(['contact', contact_id]))
        print 'response:', response
        # Not changed !
        assert_true(response['alias'] == 'modified test again')

        response = backend.get('/'.join(['contact', contact_id]))
        print 'response:', response
        # Not changed !
        assert_true(response['alias'] == 'modified test again')

        print 'deleting contact ... bad href'
        with assert_raises(BackendException) as cm:
            headers = { 'If-Match': item['_etag'] }
            response = backend.delete('/'.join(['contact', '5'+item['_id']]), headers)
            print "Response:", response
        ex = cm.exception
        print 'exception:', str(ex.code)
        assert_true(ex.code == 1003, str(ex))
Beispiel #51
0
    class __BackendConnection(object):
        """
        Base class for all objects state management (displayed icon, ...)
        """

        def __init__(self, backend_endpoint='http://127.0.0.1:5002'):
            self.backend_endpoint = backend_endpoint
            self.backend = Backend(backend_endpoint)
            self.connected = False

        def login(self, username, password=None):
            """
            Log into the backend

            If password is provided, use the backend login function to authenticate the user

            If no password is provided, the username is assumed to be an authentication token and we
            use the backend connect function.
            """
            logger.info("login, connection requested, login: %s", username)

            self.connected = False

            if not username:  # pragma: no cover, should not happen
                # Refuse backend login without username
                logger.warning("No login without username!")
                return self.connected

            if not password:  # pragma: no cover, should not happen
                # Set backend token (no login request).
                logger.debug("Update backend token")
                self.backend.token = username
                self.connected = True
                return self.connected

            try:
                # Backend real login
                logger.info("Requesting backend authentication, username: %s", username)
                self.connected = self.backend.login(username, password)
            except BackendException:  # pragma: no cover, should not happen
                logger.warning("configured backend is not available!")
            except Exception as e:  # pragma: no cover, should not happen
                logger.warning("User login exception: %s", str(e))
                logger.error("traceback: %s", traceback.format_exc())

            logger.info("login result: %s", self.connected)
            return self.connected

        def logout(self):
            """
            Log out from the backend

            Do nothing except setting 'connected' attribute to False
            """
            logger.info("logout")

            self.connected = False

        def count(self, object_type, params=None):
            """
            If params is a string, it is considered to be an object id and params
            is modified to {'_id': params}.

            Else, params is used to 'get' objects from the backend.
            """
            logger.debug("count, %s, params: %s", object_type, params)

            if isinstance(params, basestring):
                params = {'where': {'_id': params}}

            # Update backend search parameters
            if params is None:
                params = {'page': 0, 'max_results': 1}
            if 'where' in params:
                params['where'] = json.dumps(params['where'])
            if 'max_results' not in params:
                params['max_results'] = 1
            logger.debug(
                "count, search in the backend for %s: parameters=%s", object_type, params
            )

            try:
                result = self.backend.get(object_type, params=params)
            except BackendException as e:  # pragma: no cover, simple protection
                logger.warning("count, backend exception for %s: %s", object_type, str(e))
                return 0

            logger.debug("count, search result for %s: result=%s", object_type, result)
            if not result['_status'] == 'OK':  # pragma: no cover, should not happen
                error = []
                if "content" in result:
                    error.append(result['content'])
                if "_issues" in result:
                    error.append(result['_issues'])
                logger.warning("count, %s: %s, not found: %s", object_type, params, error)
                return 0

            # If more than one element is found, we get an _items list
            if '_items' in result:
                logger.debug("count, found in the backend: %s: %s", object_type, result['_items'])
                return result['_meta']['total']

            return 0  # pragma: no cover, simple protection

        def get(self, object_type, params=None, all_elements=False):
            """
            If params is a string, it is considered to be an object id and params
            is modified to {'_id': params}.

            Else, params is used to 'get' objects from the backend.

            Returns an object or an array of matching objects. All extra attributes
            (_links, _status, _meta, ...) are not returned but an '_total' attribute is added
            in each element to get the total count of elements stored in the backend.

            Returns None if the search failed. Do not raise any exception to the caller.

            If all_elements is True, it calls the get_all function of the backend client to
            get all the elements without any pagination activated.
            """
            logger.debug("get, %s, params: %s", object_type, params)

            if isinstance(params, basestring):
                params = {'where': {'_id': params}}
                logger.debug("get, %s, params: %s", object_type, params)

            # Update backend search parameters
            if params is None:
                params = {'page': 0, 'max_results': BACKEND_PAGINATION_LIMIT}
            if 'where' in params:
                params['where'] = json.dumps(params['where'])
            if 'embedded' in params:
                params['embedded'] = json.dumps(params['embedded'])
            if 'where' not in params:
                params['where'] = {}
            if 'page' not in params:
                params['page'] = 0
            if 'max_results' not in params:
                params['max_results'] = BACKEND_PAGINATION_LIMIT
            logger.debug(
                "get, search in the backend for %s: parameters=%s", object_type, params
            )

            try:
                if all_elements:
                    result = self.backend.get_all(object_type, params=params)
                else:
                    result = self.backend.get(object_type, params=params)
            except BackendException as e:  # pragma: no cover, simple protection
                logger.warning("get, backend exception for %s: %s", object_type, str(e))
                return None

            logger.debug(
                "search, search result for %s: result=%s", object_type, result
            )
            if result['_status'] != 'OK':  # pragma: no cover, should not happen
                error = []
                if "content" in result:
                    error.append(result['content'])
                if "_issues" in result:
                    error.append(result['_issues'])
                logger.warning("get, %s: %s, not found: %s", object_type, params, error)
                raise ValueError(
                    '%s, search: %s was not found in the backend, error: %s' % (
                        object_type, params, error
                    )
                )

            # If more than one element is found, we get an _items list
            if '_items' in result:
                if '_meta' in result:
                    for item in result['_items']:
                        item.update({'_total': result['_meta']['total']})
                logger.debug("get, found in the backend: %s: %s", object_type, result['_items'])
                return result['_items']

            if '_status' in result:
                result.pop('_status')
            if '_meta' in result:
                # result.update({'_total': result['_meta']['total']})
                result['_total'] = result['_meta']['total']
            logger.debug("get, found one in the backend: %s: %s", object_type, result)
            return result

        def post(self, object_type, data=None, files=None):
            """ Add an element """
            logger.info("post, request to add a %s: data: %s", object_type, data)

            # Do not set header to use the client default behavior:
            # - set headers as {'Content-Type': 'application/json'}
            # - encode provided data to JSON
            headers = None
            if files:
                logger.info("post, request to add a %s with files: %s", object_type, files)
                # Set header to disable client default behavior
                headers = {'Content-type': 'multipart/form-data'}

            try:
                result = self.backend.post(object_type, data=data, files=files, headers=headers)
                logger.debug("post, response: %s", result)
                if result['_status'] != 'OK':
                    logger.warning("post, error: %s", result)
                    return None
            except BackendException as e:  # pragma: no cover, simple protection
                logger.error("post, backend exception: %s", str(e))
                logger.error("- response: %s", e.response)
                return None
            except Exception as e:  # pragma: no cover, simple protection
                logger.warning("post, error: %s", str(e))
                return None

            return result['_id']

        def delete(self, object_type, object_id):
            """
            Delete an element
            - object_type is the element type
            - object_id is the element identifier
            """
            logger.info("delete, request to delete the %s: %s", object_type, object_id)

            try:
                # Get most recent version of the element
                element = self.get('/'.join([object_type, object_id]))
                logger.debug("delete, element: %s", element)
            except ValueError:  # pragma: no cover, simple protection
                logger.warning("delete, object %s, _id=%s not found", object_type, object_id)
                return False

            try:
                # Request deletion
                headers = {'If-Match': element['_etag']}
                endpoint = '/'.join([object_type, object_id])
                logger.info("delete, endpoint: %s", endpoint)
                result = self.backend.delete(endpoint, headers)
                logger.debug("delete, response: %s", result)
                if result['_status'] != 'OK':  # pragma: no cover, should never happen
                    error = []
                    if "content" in result:
                        error.append(result["content"])
                    if "_issues" in result:
                        error.append(result["_issues"])
                        for issue in result["_issues"]:
                            error.append(result["_issues"][issue])
                    logger.warning("delete, error: %s", error)
                    return False
            except BackendException as e:  # pragma: no cover, should never happen
                logger.error("delete, backend exception: %s", str(e))
                return False
            except ValueError:  # pragma: no cover, should never happen
                logger.warning("delete, not found %s: %s", object_type, element)
                return False

            return True

        def update(self, object_type, object_id, data):
            """
            Update an element
            - object_type is the element type
            - object_id is the element identifier
            """
            logger.info("update, request to update the %s: %s", object_type, object_id)

            try:
                # Get most recent version of the element
                element = self.get('/'.join([object_type, object_id]))
                logger.debug("update, element: %s", element)
            except ValueError:  # pragma: no cover, simple protection
                logger.warning("update, object %s, _id=%s not found", object_type, object_id)
                return False

            try:
                # Request update
                headers = {'If-Match': element['_etag']}
                endpoint = '/'.join([object_type, object_id])
                logger.info("update, endpoint: %s, data: %s", endpoint, data)
                result = self.backend.patch(endpoint, data, headers)
                logger.debug("update, response: %s", result)
                if result['_status'] != 'OK':  # pragma: no cover, should never happen
                    error = []
                    if "content" in result:
                        error.append(result["content"])
                    if "_issues" in result:
                        error.append(result["_issues"])
                        for issue in result["_issues"]:
                            error.append(result["_issues"][issue])
                    logger.warning("update, error: %s", error)
                    return False
            except BackendException as e:  # pragma: no cover, should never happen
                logger.error("update, backend exception: %s", str(e))
                return False
            except ValueError:  # pragma: no cover, should never happen
                logger.warning("update, not found %s: %s", object_type, element)
                return False

            return True
    def test_11_domains_and_some_elements(self):
        global backend_address

        print ''
        print 'get all domains and some elements'

        # Create client API
        backend = Backend(backend_address)

        print 'Login ...'
        print 'authenticated:', backend.authenticated
        result = backend.login('admin', 'admin')
        print 'authenticated:', backend.authenticated
        print 'token:', backend.token
        assert_true(backend.authenticated)

        # Get all available endpoints
        print 'get all domains'
        # Filter the templates ...
        items = backend.get_domains()
        print "Got %d elements:" % len(items)
        assert_true('_items2' not in items)
        assert_true(len(items) > 0)
        for item in items:
            assert_true('href' in item)
            assert_true('title' in item)
            print "Domain: ", item

        # Get all hosts
        print 'get all hosts at once'
        # Filter the templates ...
        parameters = { 'where': '{"register":true}', 'max_results': 1 }
        items = backend.get_all('host', params=parameters)
        print "Got %d elements:" % len(items)
        assert_true('_items' not in items)
        # assert_true(len(items) > 0)
        for item in items:
            assert_true('host_name' in item)
            print "Host: ", item['host_name']

        # Get all services
        print 'get all services at once'
        # Filter the templates ...
        parameters = { 'where': '{"register":true}' }
        items = backend.get_all('service', params=parameters)
        print "Got %d elements:" % len(items)
        assert_true('_items' not in items)
        # assert_true(len(items) > 0)
        for item in items:
            assert_true('host_name' in item)
            assert_true('service_description' in item)
            print "Service: %s/%s" % (item['host_name'], item['service_description'])

        # Get all contacts
        print 'get all contacts at once'
        # Filter the templates ...
        parameters = { 'where': '{"register":true}' }
        items = backend.get_all('contact', params=parameters)
        print "Got %d elements:" % len(items)
        assert_true('_items' not in items)
        # assert_true(len(items) > 0)
        for item in items:
            assert_true('contact_name' in item)
            print "Contact: ", item['contact_name']
    def test_04_login(self):
        """
        Test with right username / password

        :return: None
        """
        print('')
        print('test accepted connection with username/password')

        # Create client API
        backend = Backend(self.backend_address)

        print('Login ...')
        assert backend.login('admin', 'admin')
        print('authenticated:', backend.authenticated)
        print('token:', backend.token)
        assert_true(backend.authenticated)

        print('Logout ...')
        backend.logout()
        print('authenticated:', backend.authenticated)
        print('token:', backend.token)
        assert_false(backend.authenticated)

        print('Login ...')
        print('authenticated:', backend.authenticated)
        assert backend.login('admin', 'admin')
        print('authenticated:', backend.authenticated)
        print('token:', backend.token)
        assert_true(backend.authenticated)

        print('Logout ...')
        backend.logout()
        print('authenticated:', backend.authenticated)
        print('token:', backend.token)
        assert_false(backend.authenticated)

        print('Logout ...')
        backend.logout()
        print('authenticated:', backend.authenticated)
        print('token:', backend.token)
        assert_false(backend.authenticated)

        print('get object ... must be refused!')
        with assert_raises(BackendException) as cm:
            backend.get('host')
        ex = cm.exception
        print('exception:', str(ex.code))
        assert_true(ex.code == 401, str(ex))

        print('get_all object ... must be refused!')
        with assert_raises(BackendException) as cm:
            backend.get_all('host')
        ex = cm.exception
        print('exception:', str(ex.code))
        assert_true(ex.code == 401, str(ex))

        print('get all domains ... must be refused!')
        with assert_raises(BackendException) as cm:
            backend.get_domains()
        ex = cm.exception
        print('exception:', str(ex.code))
        assert_true(ex.code == 401, str(ex))

        print('post data ... must be refused!')
        with assert_raises(BackendException) as cm:
            data = {'fake': 'fake'}
            backend.post('user', data=data)
        ex = cm.exception
        print('exception:', str(ex.code))
        assert_true(ex.code == 401, str(ex))

        print('patch data ... must be refused!')
        with assert_raises(BackendException) as cm:
            data = {'fake': 'fake'}
            headers = {'If-Match': ''}
            backend.patch('user', data=data, headers=headers)
        ex = cm.exception
        print('exception:', str(ex.code))
        assert_true(ex.code == 405, str(ex))

        print('delete data ... must be refused!')
        with assert_raises(BackendException) as cm:
            headers = {'If-Match': ''}
            backend.delete('user', headers=headers)
        ex = cm.exception
        print('exception:', str(ex.code))
        assert_true(ex.code == 401, str(ex))
    def test_04_login(self):
        """
        Test with right username / password

        :return: None
        """
        print('')
        print('test accepted connection with username/password')

        # Create client API
        backend = Backend(self.backend_address)

        print('Login ...')
        assert backend.login('admin', 'admin')
        print('authenticated:', backend.authenticated)
        print('token:', backend.token)
        assert_true(backend.authenticated)

        print('Logout ...')
        backend.logout()
        print('authenticated:', backend.authenticated)
        print('token:', backend.token)
        assert_false(backend.authenticated)

        print('Login ...')
        print('authenticated:', backend.authenticated)
        assert backend.login('admin', 'admin')
        print('authenticated:', backend.authenticated)
        print('token:', backend.token)
        assert_true(backend.authenticated)

        print('Logout ...')
        backend.logout()
        print('authenticated:', backend.authenticated)
        print('token:', backend.token)
        assert_false(backend.authenticated)

        print('Logout ...')
        backend.logout()
        print('authenticated:', backend.authenticated)
        print('token:', backend.token)
        assert_false(backend.authenticated)

        print('get object ... must be refused!')
        with assert_raises(BackendException) as cm:
            backend.get('host')
        ex = cm.exception
        print('exception:', str(ex.code))
        assert_true(ex.code == 1001, str(ex))

        print('get_all object ... must be refused!')
        with assert_raises(BackendException) as cm:
            backend.get_all('host')
        ex = cm.exception
        print('exception:', str(ex.code))
        assert_true(ex.code == 1001, str(ex))

        print('get all domains ... must be refused!')
        with assert_raises(BackendException) as cm:
            backend.get_domains()
        ex = cm.exception
        print('exception:', str(ex.code))
        assert_true(ex.code == 1001, str(ex))

        print('post data ... must be refused!')
        with assert_raises(BackendException) as cm:
            data = {'fake': 'fake'}
            backend.post('user', data=data)
        ex = cm.exception
        print('exception:', str(ex.code))
        assert_true(ex.code == 1001, str(ex))

        print('patch data ... must be refused!')
        with assert_raises(BackendException) as cm:
            data = {'fake': 'fake'}
            headers = {'If-Match': ''}
            backend.patch('user', data=data, headers=headers)
        ex = cm.exception
        print('exception:', str(ex.code))
        assert_true(ex.code == 1001, str(ex))

        print('delete data ... must be refused!')
        with assert_raises(BackendException) as cm:
            headers = {'If-Match': ''}
            backend.delete('user', headers=headers)
        ex = cm.exception
        print('exception:', str(ex.code))
        assert_true(ex.code == 1001, str(ex))
    def setUpClass(cls):
        # Set test mode for alignak backend
        # Uncomment to log the bakend REST API
        # os.environ['TEST_ALIGNAK_BACKEND'] = '1'
        os.environ[
            'ALIGNAK_BACKEND_MONGO_DBNAME'] = 'alignak-module-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.backend = Backend('http://127.0.0.1:5000')
        cls.backend.login("admin", "admin", "force")
        realms = cls.backend.get_all('realm')
        for cont in realms['_items']:
            cls.realm_all = cont['_id']

        # Get admin user
        users = cls.backend.get_all('user')
        for user in users['_items']:
            if user['name'] == 'admin':
                cls.user_admin = user

        # add commands
        data = json.loads(open('cfg/command_ping.json').read())
        data['_realm'] = cls.realm_all
        data_cmd_ping = cls.backend.post("command", data)
        data = json.loads(open('cfg/command_http.json').read())
        data['_realm'] = cls.realm_all
        data_cmd_http = cls.backend.post("command", data)
        cls.ping_cmd = data_cmd_http['_id']

        # add 1 host
        data = json.loads(open('cfg/host_srv001.json').read())
        data['check_command'] = data_cmd_ping['_id']
        del data['realm']
        data['_realm'] = cls.realm_all
        cls.data_host = cls.backend.post("host", data)

        # add 2 services
        data = json.loads(open('cfg/service_srv001_ping.json').read())
        data['host'] = cls.data_host['_id']
        data['check_command'] = data_cmd_ping['_id']
        data['_realm'] = cls.realm_all
        cls.data_srv_ping = cls.backend.post("service", data)

        data = json.loads(open('cfg/service_srv001_http.json').read())
        data['host'] = cls.data_host['_id']
        data['check_command'] = data_cmd_http['_id']
        data['_realm'] = cls.realm_all
        cls.data_srv_http = cls.backend.post("service", data)

        # Start arbiter module
        modconf = Module()
        modconf.module_alias = "backend_arbiter"
        modconf.username = "******"
        modconf.password = "******"
        modconf.api_url = 'http://127.0.0.1:5000'

        # Update default check timers
        # check every x min if config in backend changed, if yes it will reload it
        # Default, every 5 minutes
        modconf.verify_modification = 1
        # verify_modification     5

        cls.arbmodule = AlignakBackendArbiter(modconf)
        cls.objects = cls.arbmodule.get_objects()
    def test_22_post_patch_delete(self):
        global backend_address

        print ''
        print 'post/delete/patch some hostgroups'

        # Create client API
        backend = Backend(backend_address)

        print 'Login ...'
        print 'authenticated:', backend.authenticated
        result = backend.login('admin', 'admin')
        print 'authenticated:', backend.authenticated
        print 'token:', backend.token
        assert_true(backend.authenticated)

        # Get all hostgroups
        print 'get all hostgroups at once'
        items = backend.get_all('hostgroup')
        print "Got %d elements:" % len(items)
        assert_true('_items' not in items)
        for item in items:
            assert_true('hostgroup_name' in item)
            assert_true('_id' in item)
            assert_true('_etag' in item)
            print "Group: ", item['hostgroup_name'], item['_id']
            # Test contact still exists ... delete him!
            if item['hostgroup_name'] == 'test':
                headers = { 'If-Match': item['_etag'] }
                response = backend.delete('/'.join(['hostgroup', item['_id']]), headers)
                print "Response:", response

        # Create a new hostgroup, bad parameters
        print 'create a hostgroup, missing fields'
        # Mandatory field hostgroup_name is missing ...
        data = {
            "name": "Testing hostgroup",
            "alias": "Fred",
            "back_role_super_admin": False,
            "back_role_admin": [],
            "min_business_impact": 0,
        }
        with assert_raises(BackendException) as cm:
            response = backend.post('hostgroup', data=data)
        ex = cm.exception
        print 'exception:', str(ex.code), ex.message, ex.response
        if "_issues" in ex.response:
            for issue in ex.response["_issues"]:
                print "Issue: %s - %s" %(issue, ex.response["_issues"][issue])
        assert_true(ex.code == 422)
        assert_true(ex.response["_issues"])

        # Create a new hostgroup
        print 'create a hostgroup'
        data = {
            "hostgroup_name": "test",
            "name": "Testing hostgroup",
            "alias": "Fred",
            "note": "Hostgroup note ...",
            "realm": "all"
        }
        response = backend.post('hostgroup', data=data)
        print "Response:", response
        assert_true('_created' in response)
        assert_true('_updated' in response)
        assert_true(response['_created'] == response['_updated'])

        # Get all hostgroups
        print 'get all hostgroups at once'
        # Filter the templates ...
        items = backend.get_all('hostgroup')
        print "Got %d elements:" % len(items)
        assert_true('_items' not in items)
        assert_true(len(items) > 0)
        # Search test hostgroup
        hostgroup_id = ''
        hostgroup_etag = ''
        for item in items:
            assert_true('hostgroup_name' in item)
            print "hostgroup: ", item['hostgroup_name']
            if item['hostgroup_name'] == 'test':
                hostgroup_id = item['_id']
                hostgroup_etag = item['_etag']
        assert_true(hostgroup_id != '')
        assert_true(hostgroup_etag != '')

        print 'changing hostgroup alias ... no _etag'
        print 'id:', hostgroup_id
        print 'etag:', hostgroup_etag
        with assert_raises(BackendException) as cm:
            data = {'alias': 'modified with no header'}
            # headers['If-Match'] = hostgroup_etag
            response = backend.patch('/'.join(['hostgroup', hostgroup_id]), data=data)
        ex = cm.exception
        print 'exception:', str(ex.code)
        assert_true(ex.code == 1005, str(ex))

        print 'changing hostgroup alias ...'
        print 'id:', hostgroup_id
        print 'etag:', hostgroup_etag
        data = {'alias': 'modified test'}
        headers = {'If-Match': hostgroup_etag}
        response = backend.patch('/'.join(['hostgroup', hostgroup_id]), data=data, headers=headers)
        print 'response:', response
        assert_true(response['_status'] == 'OK')

        response = backend.get('/'.join(['hostgroup', hostgroup_id]))
        print 'response:', response
        assert_true(response['alias'] == 'modified test')

        print 'changing hostgroup alias ... bad _etag (inception = True)'
        print 'id:', hostgroup_id
        print 'etag:', hostgroup_etag
        data = {'alias': 'modified test again'}
        headers = {'If-Match': hostgroup_etag}
        response = backend.patch('/'.join(['hostgroup', hostgroup_id]), data=data, headers=headers, inception=True)
        print 'response:', response
        assert_true(response['_status'] == 'OK')

        response = backend.get('/'.join(['hostgroup', hostgroup_id]))
        print 'response:', response
        assert_true(response['alias'] == 'modified test again')

        print 'changing hostgroup alias ... bad _etag (inception = False)'
        print 'id:', hostgroup_id
        print 'etag:', hostgroup_etag
        with assert_raises(BackendException) as cm:
            data = {'alias': 'modified test again and again'}
            headers = {'If-Match': hostgroup_etag}
            response = backend.patch('/'.join(['hostgroup', hostgroup_id]), data=data, headers=headers)
        ex = cm.exception
        print 'exception:', str(ex.code)
        assert_true(ex.code == 412, str(ex))

        response = backend.get('/'.join(['hostgroup', hostgroup_id]))
        print 'response:', response
        # Not changed !
        assert_true(response['alias'] == 'modified test again')

        response = backend.get('/'.join(['hostgroup', hostgroup_id]))
        print 'response:', response
        # Not changed !
        assert_true(response['alias'] == 'modified test again')

        print 'deleting hostgroup ... bad href'
        with assert_raises(BackendException) as cm:
            headers = { 'If-Match': item['_etag'] }
            response = backend.delete('/'.join(['hostgroup', '5'+item['_id']]), headers)
            print "Response:", response
        ex = cm.exception
        print 'exception:', str(ex.code)
        assert_true(ex.code == 1003, str(ex))
class AlignakBackendArbiter(BaseModule):
    # pylint: disable=too-many-public-methods
    """ This class is used to get configuration from alignak-backend
    """

    def __init__(self, mod_conf):
        """
        Module initialization

        mod_conf is a dictionary that contains:
        - all the variables declared in the module configuration file
        - a 'properties' value that is the module properties as defined globally in this file

        :param mod_conf: module configuration file as a dictionary
        """
        BaseModule.__init__(self, mod_conf)

        # pylint: disable=global-statement
        global logger
        logger = logging.getLogger('alignak.module.%s' % self.alias)

        logger.debug("inner properties: %s", self.__dict__)
        logger.debug("received configuration: %s", mod_conf.__dict__)

        self.my_arbiter = None

        # Alignak backend importation script is running
        self.backend_import = False
        if 'ALIGNAK_BACKEND_IMPORT_RUN' in os.environ and os.environ['ALIGNAK_BACKEND_IMPORT_RUN']:
            logger.info("Alignak backend importation script is active.")
            self.backend_import = True

        self.url = getattr(mod_conf, 'api_url', 'http://localhost:5000')
        self.backend = Backend(self.url)
        self.backend.token = getattr(mod_conf, 'token', '')
        self.backend_connected = False
        if self.backend.token == '':
            self.getToken(getattr(mod_conf, 'username', ''), getattr(mod_conf, 'password', ''),
                          getattr(mod_conf, 'allowgeneratetoken', False))
        self.bypass_verify_mode = int(getattr(mod_conf, 'bypass_verify_mode', 0)) == 1
        logger.info(
            "bypass objects loading when Arbiter is in verify mode: %s",
            self.bypass_verify_mode
        )
        self.verify_modification = int(getattr(mod_conf, 'verify_modification', 5))
        logger.info(
            "configuration reload check period: %s minutes",
            self.verify_modification
        )
        self.action_check = int(getattr(mod_conf, 'action_check', 15))
        logger.info(
            "actions check period: %s seconds", self.action_check
        )
        self.next_check = 0
        self.next_action_check = 0
        self.time_loaded_conf = datetime.utcnow().strftime("%a, %d %b %Y %H:%M:%S GMT")
        self.configraw = {}
        self.config = {'commands': [],
                       'timeperiods': [],
                       'hosts': [],
                       'hostgroups': [],
                       'services': [],
                       'contacts': [],
                       'contactgroups': [],
                       'servicegroups': [],
                       'realms': [],
                       'hostdependencies': [],
                       'hostescalations': [],
                       'servicedependencies': [],
                       'serviceescalations': [],
                       'triggers': []}

    # Common functions
    def do_loop_turn(self):
        """This function is called/used when you need a module with
        a loop function (and use the parameter 'external': True)
        """
        logger.info("In loop")
        time.sleep(1)

    def hook_read_configuration(self, arbiter):
        """
        Hook in arbiter used on configuration parsing start. This is useful to get our arbiter
        object and its parameters.

        :param arbiter: alignak.daemons.arbiterdaemon.Arbiter
        :type arbiter: object
        :return: None
        """
        self.my_arbiter = arbiter

    def getToken(self, username, password, generatetoken):
        """
        Authenticate and get the token

        :param username: login name
        :type username: str
        :param password: password
        :type password: str
        :param generatetoken: if True allow generate token, otherwise not generate
        :type generatetoken: bool
        :return: None
        """
        if self.backend_import:
            # Do no try to login when importing a configuration into the backend
            logger.info("Alignak backend importation script is active. "
                        "No backend connection.")
            return

        generate = 'enabled'
        if not generatetoken:
            generate = 'disabled'

        try:
            self.backend.login(username, password, generate)
            self.backend_connected = True
        except BackendException as exp:
            logger.warning("Alignak backend is not available for login. "
                           "No backend connection.")
            logger.exception("Exception: %s", exp)
            self.backend_connected = False

    def single_relation(self, resource, mapping, ctype):
        """
        Convert single embedded data to name of relation_data
        Example:
        {'contacts': {'_id': a3659204fe,'name':'admin'}}
        converted to:
        {'contacts': 'admin'}

        :param resource: dictionary got from alignak-backend
        :type resource: dict
        :param mapping: key value of resource
        :type mapping: str
        :param ctype: type of configraw (hosts, services, commands...)
        :type ctype: str
        """
        if mapping in resource:
            if resource[mapping] is not None:
                if resource[mapping] in self.configraw[ctype]:
                    resource[mapping] = self.configraw[ctype][resource[mapping]]

    def multiple_relation(self, resource, mapping, ctype):
        """
        Convert multiple embedded data to name of relation_data
        Example:
        {'contacts': [{'_id': a3659204fe,'contact_name':'admin'},
                      {'_id': a3659204ff,'contact_name':'admin2'}]}
        converted to:
        {'contacts': 'admin,admin2'}

        :param resource: dictionary got from alignak-backend
        :type resource: dict
        :param mapping: key value of resource
        :type mapping: str
        :param ctype: type of configraw (hosts, services, commands...)
        :type ctype: str
        """
        if mapping in resource:
            members = []
            for member in resource[mapping]:
                if member in self.configraw[ctype]:
                    members.append(self.configraw[ctype][member])
            resource[mapping] = ','.join(members)

    @classmethod
    def clean_unusable_keys(cls, resource):
        """
        Delete keys of dictionary not used

        :param resource: dictionary got from alignak-backend
        :type resource: dict
        :return:
        """
        fields = [
            '_links', '_updated', '_created', '_etag', '_id', 'name', 'ui', '_realm',
            '_sub_realm', '_users_read', '_users_update', '_users_delete', '_parent',
            '_tree_parents', '_all_children', '_level', 'customs', 'host', 'service',
            'back_role_super_admin', 'token', '_templates', '_template_fields', 'note',
            '_is_template', '_templates_with_services', '_templates_from_host_template',
            'merge_host_users', 'hosts_critical_threshold', 'hosts_warning_threshold',
            'services_critical_threshold', 'services_warning_threshold',
            'global_critical_threshold', 'global_warning_threshold', '_children',
            'hostgroups', 'hosts', 'dependent_hostgroups', 'dependent_hosts',
            'servicegroups', 'services', 'dependent_servicegroups', 'dependent_services',
            'usergroups', 'users',
            'location',
            'duplicate_foreach', 'tags',
            'ls_acknowledged', 'ls_current_attempt', 'ls_downtimed', 'ls_execution_time',
            'ls_grafana', 'ls_grafana_panelid', 'ls_impact', 'ls_last_check', 'ls_last_state',
            'ls_last_state_changed', 'ls_last_state_type', 'ls_latency', 'ls_long_output',
            'ls_max_attempts', 'ls_next_check', 'ls_output', 'ls_perf_data',
            'ls_state', 'ls_state_id', 'ls_state_type'
        ]
        for field in fields:
            if field in resource:
                del resource[field]

    @classmethod
    def convert_lists(cls, resource):
        """
        Convert lists into string with values separated with comma

        :param resource: ressource
        :type resource: dict
        :return: None
        """
        for prop in resource:
            if isinstance(resource[prop], list):
                resource[prop] = u','.join(str(e) for e in resource[prop])
            # Is it really useful ... considered as not useful!
            # elif isinstance(resource[prop], dict):
            # logger.warning("=====> %s", prop)
            # logger.warning(resource[prop])

    def get_realms(self):
        """
        Get realms from alignak_backend

        :return: None
        """
        self.configraw['realms'] = {}
        all_realms = self.backend.get_all('realm')
        logger.info("Got %d realms",
                    len(all_realms['_items']))
        for realm in all_realms['_items']:
            logger.info("- %s", realm['name'])
            self.configraw['realms'][realm['_id']] = realm['name']
            realm['imported_from'] = u'alignakbackend'
            realm['realm_name'] = realm['name']
            realm['realm_members'] = []
            self.clean_unusable_keys(realm)
            del realm['notes']
            del realm['alias']
            # self.convert_lists(realm)

            logger.debug("- realm: %s", realm)
            self.config['realms'].append(realm)

    def get_commands(self):
        """
        Get commands from alignak_backend

        :return: None
        """
        self.configraw['commands'] = {}
        all_commands = self.backend.get_all('command')
        logger.info("Got %d commands",
                    len(all_commands['_items']))
        for command in all_commands['_items']:
            logger.info("- %s", command['name'])
            self.configraw['commands'][command['_id']] = command['name']
            command['imported_from'] = u'alignakbackend'
            command['command_name'] = command['name']
            self.clean_unusable_keys(command)
            del command['alias']
            del command['notes']
            self.convert_lists(command)

            logger.debug("- command: %s", command)
            self.config['commands'].append(command)

    def get_timeperiods(self):
        """
        Get timeperiods from alignak_backend

        :return: None
        """
        self.configraw['timeperiods'] = {}
        all_timeperiods = self.backend.get_all('timeperiod')
        logger.info("Got %d timeperiods",
                    len(all_timeperiods['_items']))
        for timeperiod in all_timeperiods['_items']:
            logger.info("- %s", timeperiod['name'])
            self.configraw['timeperiods'][timeperiod['_id']] = timeperiod['name']
            timeperiod['imported_from'] = u'alignakbackend'
            timeperiod['timeperiod_name'] = timeperiod['name']
            for daterange in timeperiod['dateranges']:
                timeperiod.update(daterange)
            del timeperiod['dateranges']
            self.clean_unusable_keys(timeperiod)
            del timeperiod['notes']
            self.convert_lists(timeperiod)

            logger.debug("- timeperiod: %s", timeperiod)
            self.config['timeperiods'].append(timeperiod)

    def get_contactgroups(self):
        """
        Get contactgroups from alignak_backend

        :return: None
        """
        self.configraw['contactgroups'] = {}
        all_contactgroups = self.backend.get_all('usergroup')
        logger.info("Got %d contactgroups",
                    len(all_contactgroups['_items']))
        for contactgroup in all_contactgroups['_items']:
            logger.info("- %s", contactgroup['name'])
            self.configraw['contactgroups'][contactgroup['_id']] = contactgroup['name']

        for contactgroup in all_contactgroups['_items']:
            contactgroup[u'imported_from'] = u'alignakbackend'
            contactgroup[u'contactgroup_name'] = contactgroup['name']
            contactgroup[u'contactgroup_members'] = contactgroup['usergroups']
            contactgroup[u'members'] = contactgroup['users']
            # members
            self.multiple_relation(contactgroup, 'members', 'contacts')
            # contactgroup_members
            self.multiple_relation(contactgroup, 'contactgroup_members', 'contactgroups')
            self.clean_unusable_keys(contactgroup)
            del contactgroup['notes']
            self.convert_lists(contactgroup)

            logger.debug("- contacts group: %s", contactgroup)
            self.config['contactgroups'].append(contactgroup)

    def get_contacts(self):
        """
        Get contacts from alignak_backend

        :return: None
        """
        self.configraw['contacts'] = {}
        all_contacts = self.backend.get_all('user')
        logger.info("Got %d contacts",
                    len(all_contacts['_items']))
        for contact in all_contacts['_items']:
            logger.info("- %s", contact['name'])
            self.configraw['contacts'][contact['_id']] = contact['name']
            contact['imported_from'] = u'alignakbackend'
            contact['contact_name'] = contact['name']

            # host_notification_period
            self.single_relation(contact, 'host_notification_period', 'timeperiods')
            # service_notification_period
            self.single_relation(contact, 'service_notification_period', 'timeperiods')
            # host_notification_commands
            self.multiple_relation(contact, 'host_notification_commands', 'commands')
            # service_notification_commands
            self.multiple_relation(contact, 'service_notification_commands', 'commands')
            # contactgroups
            self.multiple_relation(contact, 'contactgroups', 'contactgroups')

            if 'host_notification_commands' not in contact:
                contact['host_notification_commands'] = ''
            if 'service_notification_commands' not in contact:
                contact['service_notification_commands'] = ''
            if 'host_notification_period' not in contact:
                contact['host_notification_period'] = \
                    self.config['timeperiods'][0]['timeperiod_name']
                contact['host_notifications_enabled'] = False
            if 'service_notification_period' not in contact:
                contact['service_notification_period'] = \
                    self.config['timeperiods'][0]['timeperiod_name']
                contact['service_notifications_enabled'] = False
            for key, value in contact['customs'].iteritems():
                contact[key] = value
            self.clean_unusable_keys(contact)
            del contact['notes']
            del contact['ui_preferences']
            self.convert_lists(contact)

            logger.debug("- contact: %s", contact)
            self.config['contacts'].append(contact)

    def get_hostgroups(self):
        """
        Get hostgroups from alignak_backend

        :return: None
        """
        self.configraw['hostgroups'] = {}
        all_hostgroups = self.backend.get_all('hostgroup')
        logger.info("Got %d hostgroups",
                    len(all_hostgroups['_items']))
        for hostgroup in all_hostgroups['_items']:
            logger.info("- %s", hostgroup['name'])
            self.configraw['hostgroups'][hostgroup['_id']] = hostgroup['name']

        for hostgroup in all_hostgroups['_items']:
            self.configraw['hostgroups'][hostgroup['_id']] = hostgroup['name']
            hostgroup[u'imported_from'] = u'alignakbackend'
            hostgroup[u'hostgroup_name'] = hostgroup['name']
            hostgroup[u'hostgroup_members'] = hostgroup['hostgroups']
            hostgroup[u'members'] = hostgroup['hosts']
            # members
            self.multiple_relation(hostgroup, 'members', 'hosts')
            # hostgroup_members
            self.multiple_relation(hostgroup, 'hostgroup_members', 'hostgroups')
            self.clean_unusable_keys(hostgroup)
            self.convert_lists(hostgroup)

            logger.debug("- hosts group: %s", hostgroup)
            self.config['hostgroups'].append(hostgroup)

    def get_hosts(self):
        """
        Get hosts from alignak_backend

        :return: None
        """
        self.configraw['hosts'] = {}
        all_hosts = self.backend.get_all('host', {"where": '{"_is_template": false}'})
        logger.info("Got %d hosts",
                    len(all_hosts['_items']))
        for host in all_hosts['_items']:
            logger.info("- %s", host['name'])
            self.configraw['hosts'][host['_id']] = host['name']
            host[u'host_name'] = host['name']
            host[u'imported_from'] = u'alignakbackend'
            # check_command
            if 'check_command' in host:
                if host['check_command'] is None:
                    host['check_command'] = ''
                elif host['check_command'] in self.configraw['commands']:
                    host['check_command'] = self.configraw['commands'][host['check_command']]
                else:
                    host['check_command'] = ''
            if 'check_command_args' in host:
                if 'check_command' not in host:
                    host['check_command'] = ''
                elif host['check_command_args'] != '':
                    host['check_command'] += '!'
                    host['check_command'] += host['check_command_args']
                del host['check_command_args']
            host[u'contacts'] = []
            if 'users' in host:
                host[u'contacts'] = host['users']
            host[u'contact_groups'] = []
            if 'usergroups' in host:
                host[u'contact_groups'] = host['usergroups']
            # check_period
            self.single_relation(host, 'check_period', 'timeperiods')
            # realm
            self.single_relation(host, '_realm', 'realms')
            host['realm'] = host['_realm']
            # notification_period
            self.single_relation(host, 'notification_period', 'timeperiods')
            # maintenance_period
            self.single_relation(host, 'maintenance_period', 'timeperiods')
            # snapshot_period
            self.single_relation(host, 'snapshot_period', 'timeperiods')
            # event_handler
            self.single_relation(host, 'event_handler', 'commands')
            # parents
            # ## self.multiple_relation(host, 'parents', 'host_name')
            host[u'parents'] = ''
            # hostgroups
            self.multiple_relation(host, 'hostgroup_name', 'hostgroups')
            # contacts
            self.multiple_relation(host, 'contacts', 'contacts')
            # contact_groups
            self.multiple_relation(host, 'contact_groups', 'contactgroups')
            # escalations
            # ## self.multiple_relation(host, 'escalations', 'escalation_name')
            del host['escalations']
            if 'alias' in host and host['alias'] == '':
                del host['alias']
            if 'realm' in host:
                if host['realm'] is None:
                    del host['realm']
            for key, value in host['customs'].iteritems():
                host[key] = value
            # Fix #9: inconsistent state when no retention module exists
            if 'ls_last_state' in host:
                if host['ls_state'] == 'UNREACHABLE':
                    host['initial_state'] = 'u'
                if host['ls_state'] == 'DOWN':
                    host['initial_state'] = 'd'
                if host['ls_state'] == 'UP':
                    host['initial_state'] = 'o'

                logger.debug(
                    "- host current live state is %s, "
                    "set initial_state as '%s'", host['ls_state'], host['initial_state']
                )
            self.clean_unusable_keys(host)
            self.convert_lists(host)

            logger.debug("- host: %s", host)
            self.config['hosts'].append(host)

    def get_servicegroups(self):
        """
        Get servicegroups from alignak_backend

        :return: None
        """
        self.configraw['servicegroups'] = {}
        all_servicegroups = self.backend.get_all('servicegroup')
        logger.info("Got %d servicegroups",
                    len(all_servicegroups['_items']))
        for servicegroup in all_servicegroups['_items']:
            logger.info("- %s", servicegroup['name'])
            self.configraw['servicegroups'][servicegroup['_id']] = servicegroup['name']

        for servicegroup in all_servicegroups['_items']:
            self.configraw['servicegroups'][servicegroup['_id']] = servicegroup['name']
            servicegroup['imported_from'] = u'alignakbackend'
            servicegroup['servicegroup_name'] = servicegroup['name']
            servicegroup[u'servicegroup_members'] = servicegroup['servicegroups']
            # members
            members = []
            for service in servicegroup['services']:
                if service not in self.configraw['services']:
                    continue
                for svc in self.config['services']:
                    if self.configraw['services'][service] == svc['service_description']:
                        members.append("%s,%s" % (svc['host_name'], svc['service_description']))
            servicegroup['members'] = ','.join(members)
            # servicegroup_members
            self.multiple_relation(servicegroup, 'servicegroup_members', 'servicegroups')
            self.clean_unusable_keys(servicegroup)
            self.convert_lists(servicegroup)

            logger.debug("- services group: %s", servicegroup)
            self.config['servicegroups'].append(servicegroup)

    def get_services(self):
        """
        Get services from alignak_backend

        :return: None
        """
        self.configraw['services'] = {}
        params = {'embedded': '{"escalations":1,"service_dependencies":1}',
                  "where": '{"_is_template": false}'}
        all_services = self.backend.get_all('service', params)
        logger.info("Got %d services",
                    len(all_services['_items']))
        for service in all_services['_items']:
            logger.info("- %s", service['name'])
            self.configraw['services'][service['_id']] = service['name']
            service['imported_from'] = u'alignakbackend'
            service['service_description'] = service['name']
            service['host_name'] = service['host']
            service['merge_host_contacts'] = service['merge_host_users']
            service['hostgroup_name'] = service['hostgroups']
            service[u'contacts'] = []
            if 'users' in service:
                service[u'contacts'] = service['users']
            service[u'contact_groups'] = []
            if 'usergroups' in service:
                service[u'contact_groups'] = service['usergroups']
            # check_command
            if 'check_command' in service:
                if service['check_command'] is None:
                    del service['check_command']
                elif service['check_command'] in self.configraw['commands']:
                    service['check_command'] = self.configraw['commands'][service['check_command']]
                else:
                    del service['check_command']
            if 'check_command_args' in service:
                if 'check_command' not in service:
                    service['check_command'] = ''
                else:
                    service['check_command'] += '!'
                service['check_command'] += service['check_command_args']
                del service['check_command_args']
            # host_name
            self.single_relation(service, 'host_name', 'hosts')
            # check_period
            self.single_relation(service, 'check_period', 'timeperiods')
            # notification_period
            self.single_relation(service, 'notification_period', 'timeperiods')
            # maintenance_period
            self.single_relation(service, 'maintenance_period', 'timeperiods')
            # snapshot_period
            self.single_relation(service, 'snapshot_period', 'timeperiods')
            # event_handler
            self.single_relation(service, 'event_handler', 'commands')
            # servicegroups
            self.multiple_relation(service, 'servicegroups', 'servicegroups')
            # contacts
            self.multiple_relation(service, 'contacts', 'contacts')
            # contact_groups
            self.multiple_relation(service, 'contact_groups', 'contactgroups')
            # escalations
            # ## self.multiple_relation(service, 'escalations', 'escalation_name')
            if 'escalation' in service and service['escalation'] == '':
                del service['escalation']
            # service_dependencies
            # ## self.multiple_relation(service, 'service_dependencies', 'service_name')
            service['service_dependencies'] = ''
            if 'alias' in service and service['alias'] == '':
                del service['alias']
            for key, value in service['customs'].iteritems():
                service[key] = value
            # Fix #9: inconsistent state when no retention module exists
            if 'ls_last_state' in service:
                if service['ls_state'] == 'UNKNOWN':
                    service['initial_state'] = 'u'
                if service['ls_state'] == 'CRITICAL':
                    service['initial_state'] = 'c'
                if service['ls_state'] == 'WARNING':
                    service['initial_state'] = 'w'
                if service['ls_state'] == 'UP':
                    service['initial_state'] = 'o'

                logger.debug(
                    "- service current live state is %s, "
                    "set initial_state as '%s'", service['ls_state'], service['initial_state']
                )

            self.clean_unusable_keys(service)
            self.convert_lists(service)

            logger.debug("- service: %s", service)
            self.config['services'].append(service)

    def get_hostdependencies(self):
        """
        Get hostdependencies from alignak_backend

        :return: None
        """
        self.configraw['hostdependencies'] = {}
        all_hostdependencies = self.backend.get_all('hostdependency')
        logger.info("Got %d hostdependencies",
                    len(all_hostdependencies['_items']))
        for hostdependency in all_hostdependencies['_items']:
            logger.info("- %s", hostdependency['name'])
            self.configraw['hostdependencies'][hostdependency['_id']] = hostdependency['name']
            hostdependency['imported_from'] = u'alignakbackend'
            # Do not exist in Alignak
            # hostdependency['hostdependency_name'] = hostdependency['name']

            hostdependency['dependent_hostgroup_name'] = hostdependency['dependent_hostgroups']
            hostdependency['dependent_host_name'] = hostdependency['dependent_hosts']
            hostdependency['hostgroup_name'] = hostdependency['hostgroups']
            hostdependency['host_name'] = hostdependency['hosts']

            # dependent_host_name
            self.multiple_relation(hostdependency, 'dependent_host_name', 'hosts')
            # dependent_hostgroup_name
            self.multiple_relation(hostdependency, 'dependent_hostgroup_name', 'hostgroups')
            # host_name
            self.multiple_relation(hostdependency, 'host_name', 'hosts')
            # hostgroup_name
            self.multiple_relation(hostdependency, 'hostgroup_name', 'hostgroups')
            self.clean_unusable_keys(hostdependency)
            self.convert_lists(hostdependency)

            logger.debug("- hosts dependency: %s", hostdependency)
            self.config['hostdependencies'].append(hostdependency)

    def get_hostescalations(self):
        """
        Get hostescalations from alignak_backend

        :return: None
        """
        self.configraw['hostescalations'] = {}
        all_hostescalations = self.backend.get_all('hostescalation')
        logger.info("Got %d hostescalations",
                    len(all_hostescalations['_items']))
        for hostescalation in all_hostescalations['_items']:
            logger.info("- %s", hostescalation['name'])
            self.configraw['hostescalations'][hostescalation['_id']] = hostescalation['name']
            hostescalation['hostescalation_name'] = hostescalation['name']
            hostescalation['imported_from'] = u'alignakbackend'
            # host_name
            self.single_relation(hostescalation, 'host_name', 'hosts')
            # hostgroup_name
            self.multiple_relation(hostescalation, 'hostgroup_name', 'hostgroups')
            # contacts
            self.multiple_relation(hostescalation, 'contacts', 'contacts')
            # contact_groups
            self.multiple_relation(hostescalation, 'contact_groups', 'contactgroups')
            self.clean_unusable_keys(hostescalation)
            self.convert_lists(hostescalation)

            logger.debug("- host escalation: %s", hostescalation)
            self.config['hostescalations'].append(hostescalation)

    def get_servicedependencies(self):
        """
        Get servicedependencies from alignak_backend

        :return: None
        """
        self.configraw['servicedependencies'] = {}
        all_servicedependencies = self.backend.get_all('servicedependency')
        logger.info("Got %d servicedependencies",
                    len(all_servicedependencies['_items']))
        for servicedependency in all_servicedependencies['_items']:
            logger.info("- %s", servicedependency['name'])
            self.configraw['servicedependencies'][servicedependency['_id']] = \
                servicedependency['name']
            servicedependency['imported_from'] = u'alignakbackend'
            # Do not exist in Alignak
            # servicedependency['servicedependency_name'] = servicedependency['name']

            servicedependency['dependent_hostgroup_name'] = \
                servicedependency['dependent_hostgroups']
            servicedependency['dependent_host_name'] = \
                servicedependency['dependent_hosts']
            servicedependency['dependent_service_description'] = \
                servicedependency['dependent_services']
            servicedependency['hostgroup_name'] = servicedependency['hostgroups']
            servicedependency['host_name'] = servicedependency['hosts']
            servicedependency['service_description'] = servicedependency['services']

            # dependent_host_name
            self.multiple_relation(servicedependency, 'dependent_host_name', 'hosts')
            # dependent_hostgroup_name
            self.multiple_relation(servicedependency, 'dependent_hostgroup_name', 'hostgroups')
            # service_description
            self.multiple_relation(servicedependency, 'service_description', 'services')
            # dependent_service_description
            self.multiple_relation(servicedependency, 'dependent_service_description', 'services')
            # host_name
            self.multiple_relation(servicedependency, 'host_name', 'hosts')
            # hostgroup_name
            self.multiple_relation(servicedependency, 'hostgroup_name', 'hostgroups')
            self.clean_unusable_keys(servicedependency)
            self.convert_lists(servicedependency)

            if not servicedependency['hostgroup_name']:
                del servicedependency['hostgroup_name']
            if not servicedependency['dependent_hostgroup_name']:
                del servicedependency['dependent_hostgroup_name']

            logger.debug("- services dependency: %s", servicedependency)
            self.config['servicedependencies'].append(servicedependency)

    def get_serviceescalations(self):
        """
        Get serviceescalations from alignak_backend

        :return: None
        """
        self.configraw['serviceescalations'] = {}
        all_serviceescalations = self.backend.get_all('serviceescalation')
        logger.info("Got %d serviceescalations",
                    len(all_serviceescalations['_items']))
        for serviceescalation in all_serviceescalations['_items']:
            logger.info("- %s", serviceescalation['name'])
            self.configraw['serviceescalations'][serviceescalation['_id']] = \
                serviceescalation['name']
            serviceescalation['serviceescalation_name'] = serviceescalation['name']
            serviceescalation['imported_from'] = u'alignakbackend'
            # host_name
            self.single_relation(serviceescalation, 'host_name', 'hosts')
            # hostgroup_name
            self.multiple_relation(serviceescalation, 'hostgroup_name', 'hostgroups')
            # service_description
            self.single_relation(serviceescalation, 'service_description', 'services')
            # contacts
            self.multiple_relation(serviceescalation, 'contacts', 'contacts')
            # contact_groups
            self.multiple_relation(serviceescalation, 'contact_groups', 'contactgroups')
            self.clean_unusable_keys(serviceescalation)
            self.convert_lists(serviceescalation)

            logger.debug("- service escalation: %s", serviceescalation)
            self.config['serviceescalations'].append(serviceescalation)

    def get_objects(self):
        """
        Get objects from alignak-backend

        :return: configuration objects
        :rtype: dict
        """
        if not self.backend_connected:
            logger.error("Alignak backend connection is not available. "
                         "Skipping objects load and provide an empty list to the Arbiter.")
            return self.config

        if self.my_arbiter and self.my_arbiter.verify_only:
            logger.info("my Arbiter is in verify only mode")
            if self.bypass_verify_mode:
                logger.info("configured to bypass the objects loading. "
                            "Skipping objects load and provide an empty list to the Arbiter.")
                return self.config

        if self.backend_import:
            logger.info("Alignak backend importation script is active. "
                        "Provide an empty objects list to the Arbiter.")
            return self.config

        start_time = time.time()
        try:
            self.get_realms()
            self.get_commands()
            self.get_timeperiods()
            self.get_contacts()
            self.get_contactgroups()
            self.get_hosts()
            self.get_hostgroups()
            self.get_services()
            self.get_servicegroups()
            self.get_hostdependencies()
            self.get_hostescalations()
            self.get_servicedependencies()
            self.get_serviceescalations()
        except BackendException as exp:
            logger.warning("Alignak backend is not available for reading. "
                           "Backend communication error.")
            logger.exception("Exception: %s", exp)
            self.backend_connected = False

        self.time_loaded_conf = datetime.utcnow().strftime("%a, %d %b %Y %H:%M:%S GMT")

        now = time.time()
        logger.info(
            "backend configuration loaded in %s seconds",
            (now - start_time)
        )

        # Schedule next configuration reload check in 10 minutes (need time to finish load config)
        self.next_check = int(now) + (60 * self.verify_modification)
        self.next_action_check = int(now) + self.action_check

        logger.info(
            "next configuration reload check in %s seconds ---",
            (self.next_check - int(now))
        )
        logger.info(
            "next actions check in %s seconds ---",
            (self.next_action_check - int(now))
        )
        return self.config

    def hook_tick(self, arbiter):
        """
        Hook in arbiter used to check if configuration has changed in the backend since
        last configuration loaded

        :param arbiter: alignak.daemons.arbiterdaemon.Arbiter
        :type arbiter: object
        :return: None
        """
        try:
            now = int(time.time())
            if now > self.next_check:
                logger.info(
                    "Check if system configuration changed in the backend..."
                )
                resources = [
                    'realm', 'command', 'timeperiod',
                    'usergroup', 'user',
                    'hostgroup', 'host', 'hostdependency', 'hostescalation',
                    'servicegroup', 'service', 'servicedependency', 'serviceescalation'
                ]
                reload_conf = False
                for resource in resources:
                    ret = self.backend.get(resource, {'where': '{"_updated":{"$gte": "' +
                                                               self.time_loaded_conf + '"}}'})
                    logger.info(
                        " - backend updated resource: %s, count: %d",
                        resource, ret['_meta']['total']
                    )
                    if ret['_meta']['total'] > 0:
                        reload_conf = True
                if reload_conf:
                    logger.warning(
                        "Hey, we must reload configuration from the backend!"
                    )
                    with open(arbiter.pidfile, 'r') as f:
                        arbiterpid = f.readline()
                    os.kill(int(arbiterpid), signal.SIGHUP)
                self.next_check = now + (60 * self.verify_modification)
                logger.debug(
                    "next configuration reload check in %s seconds ---",
                    (self.next_check - now)
                )

            if now > self.next_action_check:
                logger.debug("Check if acknowledgements are required...")
                self.get_acknowledge(arbiter)
                logger.debug("Check if downtime scheduling are required...")
                self.get_downtime(arbiter)
                logger.debug("Check if re-checks are required...")
                self.get_forcecheck(arbiter)

                self.next_action_check = now + self.action_check
                logger.debug(
                    "next actions check in %s seconds ---",
                    (self.next_action_check - int(now))
                )
        except Exception as exp:
            logger.warning("hook_tick exception: %s", str(exp))
            logger.exception("Exception: %s", exp)

    @staticmethod
    def convert_date_timestamp(mydate):
        """
        Convert date/time of backend into timestamp

        :param mydate: the date
        :type mydate: str
        :return: the timestamp
        :rtype: int
        """
        return int(time.mktime(datetime.strptime(mydate, "%a, %d %b %Y %H:%M:%S %Z").
                               timetuple()))

    def get_acknowledge(self, arbiter):
        """
        Get acknowledge from backend

        :return: None
        """
        all_ack = self.backend.get_all('actionacknowledge',
                                       {'where': '{"processed": false}',
                                        'embedded': '{"host": 1, "service": 1, "user": 1}'})
        for ack in all_ack['_items']:
            sticky = 1
            if ack['sticky']:
                sticky = 2
            if ack['action'] == 'add':
                if ack['service']:
                    command = '[{}] ACKNOWLEDGE_SVC_PROBLEM;{};{};{};{};{};{};{}\n'.\
                        format(self.convert_date_timestamp(ack['_created']), ack['host']['name'],
                               ack['service']['name'], sticky, int(ack['notify']),
                               int(ack['persistent']), ack['user']['name'], ack['comment'])
                else:
                    # logger.warning(time.time())
                    # logger.warning(self.convert_date_timestamp(ack['_created']))
                    command = '[{}] ACKNOWLEDGE_HOST_PROBLEM;{};{};{};{};{};{}\n'. \
                        format(self.convert_date_timestamp(ack['_created']), ack['host']['name'],
                               sticky, int(ack['notify']), int(ack['persistent']),
                               ack['user']['name'], ack['comment'])
            elif ack['action'] == 'delete':
                if ack['service']:
                    command = '[{}] REMOVE_SVC_ACKNOWLEDGEMENT;{};{}\n'.\
                        format(self.convert_date_timestamp(ack['_created']), ack['host']['name'],
                               ack['service']['name'])
                else:
                    command = '[{}] REMOVE_HOST_ACKNOWLEDGEMENT;{}\n'. \
                        format(self.convert_date_timestamp(ack['_created']), ack['host']['name'])

            headers = {'Content-Type': 'application/json', 'If-Match': ack['_etag']}
            data = {'processed': True}
            self.backend.patch('actionacknowledge/' + ack['_id'], data, headers)

            logger.info("build external command: %s", str(command))
            ext = ExternalCommand(command)
            arbiter.external_commands.append(ext)

    def get_downtime(self, arbiter):
        """
        Get downtime from backend

        :return: None
        """
        all_downt = self.backend.get_all('actiondowntime',
                                         {'where': '{"processed": false}',
                                          'embedded': '{"host": 1, "service": 1, '
                                                      '"user": 1}'})
        # pylint: disable=too-many-format-args
        for downt in all_downt['_items']:
            if downt['action'] == 'add':
                if downt['service']:
                    command = '[{}] SCHEDULE_SVC_DOWNTIME;{};{};{};{};{};{};{};{};{}\n'.\
                        format(self.convert_date_timestamp(downt['_created']),
                               downt['host']['name'], downt['service']['name'],
                               downt['start_time'], downt['end_time'], int(downt['fixed']),
                               0, downt['duration'], downt['user']['name'],
                               downt['comment'])
                elif downt['host'] and 'name' in downt['host']:
                    command = '[{}] SCHEDULE_HOST_DOWNTIME;{};{};{};{};{};{};{};{}\n'.\
                        format(self.convert_date_timestamp(downt['_created']),
                               downt['host']['name'], downt['start_time'], downt['end_time'],
                               int(downt['fixed']), 0, downt['duration'],
                               downt['user']['name'], downt['comment'])
            elif downt['action'] == 'delete':
                if downt['service']:
                    command = '[{}] DEL_ALL_SVC_DOWNTIMES;{};{}\n'.\
                        format(self.convert_date_timestamp(downt['_created']),
                               downt['host']['name'], downt['service']['name'])
                else:
                    command = '[{}] DEL_ALL_HOST_DOWNTIMES;{}\n'. \
                        format(self.convert_date_timestamp(downt['_created']),
                               downt['host']['name'])

            headers = {'Content-Type': 'application/json', 'If-Match': downt['_etag']}
            data = {'processed': True}
            self.backend.patch('actiondowntime/' + downt['_id'], data, headers)

            logger.info("build external command: %s", str(command))
            ext = ExternalCommand(command)
            arbiter.external_commands.append(ext)

    def get_forcecheck(self, arbiter):
        """
        Get forcecheck from backend

        :return: None
        """
        all_fcheck = self.backend.get_all('actionforcecheck',
                                          {'where': '{"processed": false}',
                                           'embedded': '{"host": 1, "service": 1}'})
        for fcheck in all_fcheck['_items']:
            timestamp = self.convert_date_timestamp(fcheck['_created'])
            if fcheck['service']:
                command = '[{}] SCHEDULE_FORCED_SVC_CHECK;{};{};{}\n'.\
                    format(timestamp, fcheck['host']['name'], fcheck['service']['name'], timestamp)
            else:
                command = '[{}] SCHEDULE_FORCED_HOST_CHECK;{};{}\n'.\
                    format(timestamp, fcheck['host']['name'], timestamp)

            headers = {'Content-Type': 'application/json', 'If-Match': fcheck['_etag']}
            data = {'processed': True}
            self.backend.patch('actionforcecheck/' + fcheck['_id'], data, headers)

            logger.info("build external command: %s", str(command))
            ext = ExternalCommand(command)
            arbiter.external_commands.append(ext)
    def __init__(self, mod_conf):
        """
        Module initialization

        mod_conf is a dictionary that contains:
        - all the variables declared in the module configuration file
        - a 'properties' value that is the module properties as defined globally in this file

        :param mod_conf: module configuration file as a dictionary
        """
        BaseModule.__init__(self, mod_conf)

        # pylint: disable=global-statement
        global logger
        logger = logging.getLogger('alignak.module.%s' % self.alias)

        logger.debug("inner properties: %s", self.__dict__)
        logger.debug("received configuration: %s", mod_conf.__dict__)

        self.my_arbiter = None

        # Alignak backend importation script is running
        self.backend_import = False
        if 'ALIGNAK_BACKEND_IMPORT_RUN' in os.environ and os.environ['ALIGNAK_BACKEND_IMPORT_RUN']:
            logger.info("Alignak backend importation script is active.")
            self.backend_import = True

        self.url = getattr(mod_conf, 'api_url', 'http://localhost:5000')
        self.backend = Backend(self.url)
        self.backend.token = getattr(mod_conf, 'token', '')
        self.backend_connected = False
        if self.backend.token == '':
            self.getToken(getattr(mod_conf, 'username', ''), getattr(mod_conf, 'password', ''),
                          getattr(mod_conf, 'allowgeneratetoken', False))
        self.bypass_verify_mode = int(getattr(mod_conf, 'bypass_verify_mode', 0)) == 1
        logger.info(
            "bypass objects loading when Arbiter is in verify mode: %s",
            self.bypass_verify_mode
        )
        self.verify_modification = int(getattr(mod_conf, 'verify_modification', 5))
        logger.info(
            "configuration reload check period: %s minutes",
            self.verify_modification
        )
        self.action_check = int(getattr(mod_conf, 'action_check', 15))
        logger.info(
            "actions check period: %s seconds", self.action_check
        )
        self.next_check = 0
        self.next_action_check = 0
        self.time_loaded_conf = datetime.utcnow().strftime("%a, %d %b %Y %H:%M:%S GMT")
        self.configraw = {}
        self.config = {'commands': [],
                       'timeperiods': [],
                       'hosts': [],
                       'hostgroups': [],
                       'services': [],
                       'contacts': [],
                       'contactgroups': [],
                       'servicegroups': [],
                       'realms': [],
                       'hostdependencies': [],
                       'hostescalations': [],
                       'servicedependencies': [],
                       'serviceescalations': [],
                       'triggers': []}
Beispiel #59
0
 def __init__(self, backend_endpoint='http://127.0.0.1:5002'):
     self.backend_endpoint = backend_endpoint
     self.backend = Backend(backend_endpoint)
     self.connected = False
    def test_3_page_after_page(self):
        """
        Get page after page manually

        :return: None
        """
        print('')
        print('backend connection with username/password')

        # Create client API
        backend = Backend(self.backend_address)
        backend.login('admin', 'admin')

        # Start with first page ...
        last_page = False
        parameters = {'max_results': 3, 'page': 1}
        items = []
        while not last_page:
            resp = backend.get('hostgroup', params=parameters)
            assert_true('_items' in resp)
            assert_true('_links' in resp)
            assert_true('_meta' in resp)
            page_number = int(resp['_meta']['page'])
            total = int(resp['_meta']['total'])
            max_results = int(resp['_meta']['max_results'])
            assert_equal(total, 101)
            assert_equal(max_results, 3)
            if 'next' in resp['_links']:
                # It has pagination, so get items of all pages
                parameters['page'] = page_number + 1
            else:
                last_page = True
                assert_equal(page_number, 34)
            items.extend(resp['_items'])

        print("----------")
        print("Got %d elements:" % len(items))
        assert_equal(len(items), 101)

        # Start with first page ...
        last_page = False
        parameters = {'max_results': 10, 'page': 1}
        items = []
        while not last_page:
            resp = backend.get('hostgroup', params=parameters)
            assert_true('_items' in resp)
            assert_true('_links' in resp)
            assert_true('_meta' in resp)
            page_number = int(resp['_meta']['page'])
            total = int(resp['_meta']['total'])
            max_results = int(resp['_meta']['max_results'])
            assert_equal(total, 101)
            assert_equal(max_results, 10)
            if 'next' in resp['_links']:
                # It has pagination, so get items of all pages
                parameters['page'] = page_number + 1
            else:
                last_page = True
                assert_equal(page_number, 11)
            items.extend(resp['_items'])

        print("----------")
        print("Got %d elements:" % len(items))
        assert_equal(len(items), 101)