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()
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()
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)
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)
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_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))
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 700 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']), 2000, "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']), 2000, "Number of commands in multiprocess mode") ids = [] for dat in resp['_items']: ids.append(dat['_id']) self.assertEqual(len(ids), 2000, "Number of id") # remove doubles ids_final = set(ids) self.assertEqual(len(ids_final), 2000, "Number of id unique") print(threads_1) print(threads_8)
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))
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_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))
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
class DataManager(object): ''' Base class for all data manager objects ''' id = 1 """ Application data manager object """ 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 __repr__(self): return ("<DM, id: %s, objects count: %d, user: %s, updated: %s>") % ( self.id, self.get_objects_count(), self.get_logged_user().get_username() if self.get_logged_user() else 'Not logged in', self.updated ) ## # Connected user ## def user_login(self, username, password=None, load=True): """ Set the data manager user 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("user_login, connection requested: %s, load: %s", username, load) self.connection_message = _('Backend connecting...') if not password: # Set backend token (no login request). # Do not include the token in the application logs ! logger.debug("Update backend token") self.backend.token = username self.connected = True self.connection_message = _('Backend connected') # Load data if load required... if load: self.load(reset=True) return self.connected try: # Backend real login logger.info("Requesting backend authentication, username: %s", username) self.connected = self.backend.login(username, password) if self.connected: self.connection_message = _('Connection successful') # Fetch the logged-in user users = self.find_object( 'contact', {'where': {'token': self.backend.token}} ) # Tag user as authenticated users[0].authenticated = True self.logged_in_user = users[0] # Get total objects count from the backend objects_count = self.get_objects_count(refresh=True, log=True) # Load data if load required... if load: self.load(reset=True) else: self.connection_message = _('Backend connection refused...') except BackendException as e: # pragma: no cover, should not happen logger.warning("configured applications backend is not available!") self.connection_message = e.message self.connected = False 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("user_login, connection message: %s", self.connection_message) return self.connected def user_logout(self): """ Logout the data manager user. Do not log-out from the backend. Need to reset the datamanager to do it. """ self.logged_in_user = None def get_logged_user(self): """ Get the current logged in user """ return self.logged_in_user ## # Find objects and load objects cache ## def find_object(self, object_type, params=None, all_elements=False): """ Find an object ... Search in internal objects cache for an object matching the required parameters If params is a string, it is considered to be an object id and params is modified to {'_id': params}. Else, params is a dictionary of key/value to find a matching object in the objects cache If no objects are found in the cache, params is user to 'get' objects from the backend. Default behavior is to search in the backend if objects are not found in the cache. Call with backend=False to search only in local cache. If the backend search is successful, a new object is created if it exists a class in the imported modules (presumably alignak_webui.objects.item) which contains a 'bo_type' property and this property is valued as 'object_type'. Returns an array of matching objects """ logger.debug("find_object, self: %s, updated:%s", self, self.updated) logger.debug("find_object, %s, params: %s", object_type, params) # ----------------------------------------------------------------------------------------- # TODO: manage parameters like: # {'sort': '-opening_date', 'where': u'{"service_name": "userservice_1"}'} # -> ignore sort, ... but take car of 'where' to search in the cache! # ----------------------------------------------------------------------------------------- # if params is None: # params = {'page': 0, 'max_results': BACKEND_PAGINATION_LIMIT} unique_element = False if isinstance(params, basestring): params = {'where': {'_id': params}} unique_element = True logger.debug("find_object, %s, params: %s", object_type, params) items = [] # 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( "find_object, 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("find_object, backend exception: %s", str(e)) return items logger.debug( "find_object, 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("find_object, %s: %s, not found: %s", object_type, params, error) raise ValueError( '%s, where %s was not found in the backend, error: %s' % ( object_type, params, error ) ) if not result['_items']: # pragma: no cover, should occur rarely if items: logger.debug( "find_object, no data in backend, found in the cache: %s: %s", object_type, items ) return items logger.debug( "find_object, %s: %s: not found: %s", object_type, params, result ) raise ValueError( '%s, %s was not found in the cache nor in the backend' % ( object_type, params['where'] ) ) logger.debug("find_object, found in the backend: %s: %s", object_type, result['_items']) for item in result['_items']: # Find "Backend object type" classes in file imported modules ... for k, v in globals().items(): if isinstance(globals()[k], type) and '_type' in globals()[k].__dict__: if globals()[k].getType() == object_type: # Create a new object bo_object = globals()[k](item) items.append(bo_object) self.updated = datetime.utcnow() logger.debug("find_object, created: %s", bo_object) break else: # pragma: no cover, should not happen # No break, so not found a relative class! logger.error("find_object, %s class not found for: %s", object_type, item) return items def load(self, reset=False, refresh=False): """ Load data in the data manager objects If reset is set, then all the existing objects are deleted and then created from scratch (first load ...). Else, existing objects are updated and new objects are created. Get all the users (related to current logged-in user) Get all the user services (related to current logged-in user) Get all the relations between users and services Get the most recent sessions for each user service :returns: the number of newly created objects """ if not self.get_logged_user(): logger.error("load, must be logged-in before loading") return False if self.loading > 0: # pragma: no cover, protection if application shuts down ... logger.error("load, already loading: trial: %d", self.loading) if self.loading < 3: self.loading += 1 return False logger.error("load, already loading: reset counter") self.loading = 0 logger.debug("load, start loading: %s for %s", self, self.get_logged_user()) logger.debug( "load, start as administrator: %s", self.get_logged_user().is_administrator() ) start = time.time() if reset: logger.warning("Objects cache reset") self.reset(logout=False) self.loading += 1 self.loaded = False # Get internal objects count objects_count = self.get_objects_count() logger.debug("Load, start, objects in cache: %d", objects_count) # ----------------------------------------------------------------------------------------- # Get all users if current user is an administrator # ----------------------------------------------------------------------------------------- self.get_users() # ----------------------------------------------------------------------------------------- # Get all commands # ----------------------------------------------------------------------------------------- commands = self.get_commands() # ----------------------------------------------------------------------------------------- # Get all hosts # ----------------------------------------------------------------------------------------- hosts = self.get_hosts() # Get internal objects count new_objects_count = self.get_objects_count() logger.debug("Load, end, objects in cache: %d", new_objects_count) logger.warning( "Data manager load (%s), new objects: %d, duration: %s", refresh, new_objects_count - objects_count, (time.time() - start) ) if new_objects_count > objects_count: self.require_refresh() self.loaded = True self.loading = 0 return new_objects_count - objects_count def reset(self, logout=False): """ Reset data in the data manager objects """ logger.info("Data manager reset...") # Clean internal objects cache for known_class in self.known_classes: logger.info("Cleaning %s cache...", known_class.getType()) known_class.cleanCache() if logout: self.backend.logout() self.user_logout() self.loaded = False self.loading = 0 self.refresh_required = True def require_refresh(self): ''' Require an immediate refresh ''' self.refresh_required = True self.refresh_done = False def get_objects_count(self, object_type=None, refresh=False, log=False, search=None): ''' Get the count of the objects stored in the data manager cache If an object_type is specified, only returns the count for this object type If refresh is True, get the total count from the backend. This is only useful if total count is required... If log is set, an information log is made ''' log_function = logger.debug if log: log_function = logger.info if object_type: for known_class in self.known_classes: if object_type == known_class.getType(): objects_count = known_class.getCount() log_function( "get_objects_count, currently %d cached %ss", objects_count, object_type ) if refresh: if hasattr(known_class, '_total_count'): objects_count = known_class.getTotalCount() log_function( "get_objects_count, got _total_count attribute: %d", objects_count ) else: objects_count = self.count_objects(object_type, search=search) log_function( "get_objects_count, currently %d total %ss for %s", objects_count, object_type, search ) return objects_count else: # pragma: no cover, should not happen logger.warning("count_objects, unknown object type: %s", object_type) return 0 objects_count = 0 for known_class in self.known_classes: count = known_class.getCount() log_function( "get_objects_count, currently %d cached %ss", count, known_class.getType() ) if refresh: count = self.count_objects(known_class.getType(), search=search) log_function( "get_objects_count, currently %d total %ss for %s", count, known_class.getType(), search ) objects_count += count log_function("get_objects_count, currently %d elements", objects_count) return objects_count ## # # Elements add, delete, update, ... ## def count_objects(self, object_type, search=None): """ Request objects from the backend to pick-up total records count. Make a simple request for 1 element and we will get back the total count of elements search is a dictionary of key / value to search for If log is set, an information log is made """ total = 0 params = { 'page': 0, 'max_results': 1 } if search is not None: params['where'] = json.dumps(search) # Request objects from the backend ... try: resp = self.backend.get(object_type, params) logger.debug("count_objects %s: %s", object_type, resp) # Total number of records if '_meta' in resp: total = int(resp['_meta']['total']) except BackendException as e: logger.warning( "count_objects exception for object type: %s: %s", object_type, e.message ) return total def add_object(self, object_type, data=None, files=None): """ Add an element """ logger.info("add_object, 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("add_object, 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("add_object, response: %s", result) if result['_status'] != 'OK': logger.warning("add_object, error: %s", result) return None self.find_object(object_type, result['_id']) except BackendException as e: logger.error("add_object, backend exception: %s", str(e)) return None except ValueError as e: # pragma: no cover, should never happen logger.warning("add_object, error: %s", str(e)) return None return result['_id'] def delete_object(self, object_type, element): """ Delete an element - object_type is the element type - element may be a string. In this case it is considered to be the element id """ logger.info("delete_object, request to delete the %s: %s", object_type, element) if isinstance(element, basestring): object_id = element else: object_id = element.get_id() try: # Get most recent version of the element items = self.find_object(object_type, object_id) element = items[0] except ValueError: # pragma: no cover, should never happen logger.warning("delete_object, 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_object, endpoint: %s", endpoint) result = self.backend.delete(endpoint, headers) logger.debug("delete_object, 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_object, error: %s", error) return False except BackendException as e: # pragma: no cover, should never happen logger.error("delete_object, backend exception: %s", str(e)) return False except ValueError as e: # pragma: no cover, should never happen logger.warning("delete_object, not found %s: %s", object_type, element) return False try: # Try to get most recent version of the element items = self.find_object(object_type, object_id) except ValueError: logger.info("delete_object, object deleted: %s, _id=%s", object_type, object_id) # Object deletion element._delete() return True def update_object(self, object_type, element, data): """ Update an element - object_type is the element type - element may be a string. In this case it is considered to be the element id """ logger.info("update_object, request to update the %s: %s", object_type, element) if isinstance(element, basestring): object_id = element else: object_id = element.get_id() try: # Get most recent version of the element items = self.find_object(object_type, object_id) element = items[0] except ValueError: logger.warning("update_object, 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_object, endpoint: %s, data: %s", endpoint, data) result = self.backend.patch(endpoint, data, headers) logger.debug("update_object, 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_object, error: %s", error) return False items = self.find_object(object_type, object_id) logger.info("update_object, updated: %s", items[0]) except BackendException as e: # pragma: no cover, should never happen logger.error("update_object, backend exception: %s", str(e)) return False except ValueError: # pragma: no cover, should never happen logger.warning("update_object, not found %s: %s", object_type, element) return False return True ## # Hosts ## def get_hosts(self, search=None): """ Get a list of all hosts. """ if search is None: search = {} if 'embedded' not in search: search.update({'embedded': {'userservice_session': 1, 'user': 1}}) try: logger.info("get_hosts, search: %s", search) items = self.find_object('host', search) logger.info("get_hosts, got: %d elements, %s", len(items), items) return items except ValueError: logger.debug("get_hosts, none found") return [] def get_host(self, search): """ Get a host by its id (default). """ if isinstance(search, basestring): search = {'max_results': 1, 'where': {'_id': search}} elif 'max_results' not in search: search.update({'max_results': 1}) items = self.get_hosts(search=search) return items[0] if items else None def get_hosts_synthesis(self, elts=None): """ Hosts synthesis by status """ if elts: hosts = [item for item in elts if item.getType() == 'host'] else: # Use internal object list ... hosts = [item for _id, item in Host.getCache().items()] logger.debug("get_hosts_synthesis, %d hosts", len(hosts)) synthesis = dict() synthesis['nb_elts'] = len(hosts) synthesis['nb_problem'] = 0 if hosts: for state in 'up', 'unreachable', 'down', 'unknown': synthesis['nb_' + state] = sum( 1 for host in hosts if host.get_status().lower() == state ) synthesis['pct_' + state] = round( 100.0 * synthesis['nb_' + state] / synthesis['nb_elts'], 2 ) else: for state in 'up', 'unreachable', 'down', 'unknown': synthesis['nb_' + state] = 0 synthesis['pct_' + state] = 0 logger.debug("get_hosts_synthesis: %s", synthesis) return synthesis def add_host(self, data, files): """ Add a host. Update the concerned session internal objects. """ return self.add_object('host', data, files) ## # Commands ## def get_commands(self, search=None): """ Get a list of all commands. """ if search is None: search = {} if 'embedded' not in search: search.update({'embedded': {'userservice_session': 1, 'user': 1}}) try: logger.info("get_commands, search: %s", search) items = self.find_object('command', search) return items except ValueError: logger.debug("get_commands, none found") return [] def get_command(self, search): """ Get a command by its id. """ if isinstance(search, basestring): search = {'max_results': 1, 'where': {'_id': search}} elif 'max_results' not in search: search.update({'max_results': 1}) items = self.get_commands(search=search) return items[0] if items else None def get_commands_synthesis(self, elts=None): """ Documents synthesis by status """ if elts: commands = [item for item in elts if item.getType() == 'command'] else: # Use internal object list ... commands = [item for _id, item in Command.getCache().items()] logger.debug("get_commands_synthesis, %d commands", len(commands)) synthesis = dict() synthesis['nb_elts'] = len(commands) if commands: for state in 'attached', 'empty', 'problem', 'unknown': synthesis['nb_' + state] = sum( 1 for command in commands if command.get_status().lower() == state ) synthesis['pct_' + state] = round( 100.0 * synthesis['nb_' + state] / synthesis['nb_elts'], 2 ) else: for state in 'attached', 'empty', 'problem', 'unknown': synthesis['nb_' + state] = 0 synthesis['pct_' + state] = 0 logger.debug("get_commands_synthesis: %s", synthesis) return synthesis def add_command(self, data): # pragma: no cover, not yet implemented! """ Add a command. Update the concerned session internal objects. """ return self.add_object('command', data) ## # Users ## def get_users(self, search=None): """ Get a list of known users """ if not self.get_logged_user().is_administrator(): return [self.get_logged_user()] try: logger.info("get_users, search: %s", search) items = self.find_object('contact', search) return items except ValueError: logger.debug("get_users, none found") return [] def get_user(self, search): """ Get a user by its id or a search pattern """ if isinstance(search, basestring): search = {'max_results': 1, 'where': {'_id': search}} elif 'max_results' not in search: search.update({'max_results': 1}) items = self.get_users(search=search) return items[0] if items else None def add_user(self, data): """ Add a user. """ return self.add_object('user', data) def delete_user(self, user): """ Delete a user. Cannot delete the currently logged in user ... If user is a string it is assumed to be the User object id to be searched in the objects cache. :param user: User object instance :type user: User (or string) Returns True/False depending if user closed """ logger.info("delete_user, request to delete the user: %s", user) if isinstance(user, basestring): user = self.get_user(user) if not user: return False user_id = user.get_id() if user_id == self.get_logged_user().get_id(): logger.warning("delete_user, request to delete the current logged-in user: %s", user_id) return False return self.delete_object('user', user)
class BackendConnection(object): # pylint: disable=too-few-public-methods """Base class for Alignak backend connection""" def __init__(self, backend_endpoint='http://127.0.0.1:5000'): self.backend_endpoint = backend_endpoint self.alignak_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: # Refuse backend login without username logger.warning("No login without username!") return self.connected if not password: # Set backend token (no login request). logger.debug("Update backend token") self.alignak_backend.token = username self.connected = True return self.connected try: # Backend real login logger.info("Requesting backend (%s) authentication, username: %s", self.backend_endpoint, username) self.connected = self.alignak_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): """Count backend elements 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, string_types): params = {'where': {'_id': 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: del 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 # 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.alignak_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 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 logger.debug("count, search result for %s: status=%s", object_type, result['_status']) # If more than one element is found, we get an _items list if '_items' in result: logger.debug("count, found in the backend: %d %s", len(result['_items']), object_type) logger.debug("count, found in the backend: %d total %s", result['_meta']['total'], object_type) return result['_meta']['total'] return 0 # pragma: no cover, simple protection def get(self, object_type, params=None, all_elements=False): """Get backend elements 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 '/' not in object_type: # Do not Get a specific element, manage search parameters if isinstance(params, string_types): 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, all: %s", object_type, params, all_elements) try: if all_elements: result = self.alignak_backend.get_all(object_type, params=params) else: result = self.alignak_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)) raise BackendException(code=e.code, message=e.message) 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: total = len(result['_items']) if '_meta' in result: total = result['_meta']['total'] logger.debug("get %s %s, %d total elements found in the backend", object_type, ' (All required)' if all_elements else ' (filtered)', total) for item in result['_items']: item.update({'_total': total}) return result['_items'] if '_status' in result: result.pop('_status') if '_meta' in result: result['_total'] = result['_meta']['total'] result.pop('_meta') if all_elements: logger.info("get %s %s, %d total elements found in the backend", object_type, ' (All required)' if all_elements else ' (filtered)', len(result)) for item in result: item.update({'_total': len(result)}) 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.alignak_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 exp: # pragma: no cover, simple protection logger.exception("post, backend exception: %s", exp) error = [] if getattr(exp, "response", None) and "_issues" in exp.response: error = exp.response["_issues"] else: error.append(str(exp)) logger.warning("post, error(s): %s", error) return error 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.debug("delete, endpoint: %s", endpoint) result = self.alignak_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, element, data): """Update an element""" logger.info("update, request to update: %s", element) try: # Request update headers = {'If-Match': element['_etag']} endpoint = '/'.join([element.get_type(), element.id]) logger.debug("update, endpoint: %s, data: %s", endpoint, data) result = self.alignak_backend.patch(endpoint, data, headers, inception=True) 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): %s", error) return error except BackendException as e: # pragma: no cover, should never happen error = [] if e.response and "_issues" in e.response: error = e.response["_issues"] else: error.append(str(e)) logger.error("update, backend exception: %s", str(e)) return error except ValueError: # pragma: no cover, should never happen logger.warning("update, not found %s: %s", element.get_type(), element) return False return True
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 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))
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))
def main(): """ Main function """ # Store list of errors found errors_found = [] # Get command line parameters args = docopt(__doc__, version='0.1.0') # Define here the path of the cfg files cfg = args['<cfg_file>'] print ("Configuration to load: %s" % cfg) # Define here the url of the backend backend_url = args['--backend'] print ("Backend URL: %s", backend_url) # Delete all objects in backend ? destroy_backend_data = args['--delete'] print ("Delete existing backend data: %s" % destroy_backend_data) username = args['--username'] password = args['--password'] print ("Backend login with credentials: %s/%s" % (username, password)) def check_mapping(items, mapping): """ Check if elements are found ... """ response = { 'all_found': True, 'data': items } new_list = [] for item in items: if item in mapping: new_list.append(mapping[item]) else: response['all_found'] = False if response['all_found']: response['data'] = new_list return response # Get flat files configuration alconfig = Config() buf = alconfig.read_config(cfg) print ("Configuration: %s" % (buf)) conf = alconfig.read_config_buf(buf) print ("Configuration: %s" % (conf)) print("~~~~~~~~~~~~~~~~~~~~~~ First authentication to delete previous data ~~~~~~~~~~~~~~") # Backend authentication with token generation headers = {'Content-Type': 'application/json'} payload = {'username': username, 'password': password, 'action': 'generate'} backend = Backend(backend_url) backend.login(username, password) if backend.token is None: print("Can't authenticated") exit() print("~~~~~~~~~~~~~~~~~~~~~~ Authenticated ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") # Destroy data in backend if defined if destroy_backend_data: headers = {'Content-Type': 'application/json'} backend.delete('command', headers) backend.delete('timeperiod', headers) backend.delete('hostgroup', headers) backend.delete('hostdependency', headers) backend.delete('servicedependency', headers) backend.delete('serviceextinfo', headers) backend.delete('trigger', headers) # backend.delete('contact', headers) backend.delete('contactgroup', headers) backend.delete('contactrestrictrole', headers) backend.delete('escalation', headers) backend.delete('host', headers) backend.delete('hostextinfo', headers) backend.delete('hostescalation', headers) backend.delete('servicegroup', headers) backend.delete('service', headers) backend.delete('serviceescalation', headers) backend.delete('livestate', headers) backend.delete('livesynthesis', headers) print("~~~~~~~~~~~~~~~~~~~~~~ Data destroyed ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Order of objects + fields to update post add # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # # COMMAND # command.use # TIMEPERIOD # timeperiod.use # HOSTGROUP # hostgroup.hostgroup_members # HOSTDEPENDENCY # hostdependency.use # SERVICEDEPENDENCY # servicedependency.use # SERVICEEXTINFO # serviceextinfo.use # TRIGGER # trigger.use # CONTACT # contact.use # CONTACTGROUP # contact.contactgroups / contactgroup.contactgroup_members # CONTACTRESTRICTROLE # # ESCALATION # escalation.use # HOST # hostgroup.members / host.use / host.parents # HOSTEXTINFO # hostextinfo.use # HOSTESCALATION # hostescalation.use # SERVICEGROUP # servicegroup.servicegroup_members # SERVICE # service.use # SERVICEESCALATION # serviceescalation.use # def update_types(source, schema): """ Update elements types """ for prop in source: source[prop] = ''.join(source[prop]) if prop in schema: # get type if schema[prop]['type'] == 'boolean': if source[prop] == '1': source[prop] = True else: source[prop] = False elif schema[prop]['type'] == 'list': source[prop] = source[prop].split(',') elif schema[prop]['type'] == 'integer': source[prop] = int(source[prop]) return source def update_later(later, inserted, ressource, field, schema): """ Update field of ressource hav link with other ressources (objectid in backend) :param later: :type later: dict :param inserted: :type inserted: dict :param ressource: ressource name (command, contact, host...) :type ressource: str :param field: field of ressource to update :type field: str :return: None """ def get_template(ressource, value): """ :param ressource: :param value: value of use :return: """ if isinstance(value, basestring): value = value.split() for template_value in reversed(value): template_value = template_value.strip() if template_value not in template[ressource]: errors_found.append("# Undeclared template: %s for %s" % (template_value, ressource)) continue print ("Template: %s - %s" % (template_value, template[ressource][template_value])) if 'use' in template[ressource][template_value]: get_template(ressource, template[ressource][template_value]['use']) for key, val in iteritems(template[ressource][template_value]): if key not in ['register', 'name', 'use']: data[key] = val elif key == 'name': if val not in inserted[ressource]: errors_found.append("# Unknown resource %s for %s in %s" % (val, key, inserted[ressource])) else: data['use'].append(inserted[ressource][val]) headers = {'Content-Type': 'application/json'} for (index, item) in iteritems(later[ressource][field]): if field == 'use': data = {'use': []} get_template(ressource, item['value']) # data = update_types(data, schema) use_data = [] for template_id in reversed(data['use']): use_data.append(template_id) data['use'] = use_data else: if item['type'] == 'simple': data = {field: inserted[item['ressource']][item['value']]} elif item['type'] == 'list': data = {field: []} for val in item['value']: val = val.strip() if val not in inserted[item['ressource']]: errors_found.append("# Unknown %s: %s for %s" % (item['ressource'], val, ressource)) else: data[field].append(inserted[item['ressource']][val]) headers['If-Match'] = item['_etag'] resp = backend.patch(''.join([ressource, '/', index]), data, headers, True) if '_status' in resp: if resp['_status'] == 'ERR': raise ValueError(resp['_issues']) elif resp['_status'] == 'OK': for (ind, it) in iteritems(later[ressource]): if index in later[ressource][ind]: later[ressource][ind][index]['_etag'] = resp['_etag'] def manage_ressource(r_name, inserted, later, data_later, id_name, schema): """ data_later = [{'field': 'use', 'type': 'simple|list', 'ressource': 'command'}] :param r_name: :param inserted: :param later: :param data_later: :return: """ if r_name not in inserted: inserted[r_name] = {} if r_name not in template: template[r_name] = {} if r_name not in later: later[r_name] = {} for k, values in enumerate(data_later): if values['field'] not in later[r_name]: later[r_name][values['field']] = {} if r_name in conf: for item in conf[r_name]: later_tmp = {} headers = { 'Content-Type': 'application/json', } if 'imported_from' in item: del item['imported_from'] for p in item: item[p] = item[p][0] # Hack for check_command_args if r_name in ['host', 'service']: if 'check_command' in item: commands = item['check_command'].split('!', 1) item['check_command'] = commands[0] if len(commands) == 2: item['check_command_args'] = commands[1] # convert type (boolean, integer...) item = update_types(item, schema['schema']) for k, values in enumerate(data_later): # {'field': 'hostgroups', 'type': 'list', 'ressource': 'hostgroup'}, if values['field'] in item: if values['type'] == 'simple': if values['now'] \ and values['ressource'] in inserted \ and item[values['field']] in inserted[values['ressource']]: item[values['field']] = inserted[ values['ressource'] ][item[values['field']]] else: later_tmp[values['field']] = item[values['field']] del item[values['field']] elif values['type'] == 'list': add = True objectsid = [] if values['now']: if isinstance(item[values['field']], basestring): item[values['field']] = item[values['field']].split() for keylist, vallist in enumerate(item[values['field']]): vallist = vallist.strip() if values['ressource'] in inserted: if vallist in inserted[values['ressource']]: objectsid.append(inserted[values['ressource']][vallist]) else: add = False else: add = False if add: item[values['field']] = objectsid else: later_tmp[values['field']] = item[values['field']] del item[values['field']] # special case of timeperiod if r_name == 'timeperiod': fields = ['imported_from', 'use', 'name', 'definition_order', 'register', 'timeperiod_name', 'alias', 'dateranges', 'exclude', 'is_active'] item['dateranges'] = [] prop_to_del = [] for prop in item: if prop not in fields: item['dateranges'].append({prop: item[prop]}) prop_to_del.append(prop) for prop in prop_to_del: del item[prop] # if template add to template if 'register' in item: if not item['register']: if 'name' in item: template[r_name][item['name']] = item.copy() else: print("***** Missing name property in template: %s" % item) if 'service_description' in item: item['name'] = item['service_description'] template[r_name][item['name']] = item.copy() elif 'host_name' in item: item['name'] = item['host_name'] template[r_name][item['name']] = item.copy() print("before_post") print("%s : %s:" % (r_name, item)) try: response = backend.post(r_name, item, headers) except BackendException as e: print("***** Exception: %s" % str(e)) if "_issues" in e.response: print("ERROR: %s" % e.response['_issues']) else: print("POST response : %s:" % (response)) if id_name in item: inserted[r_name][item[id_name]] = response['_id'] else: inserted[r_name][item['name']] = response['_id'] for k, values in enumerate(data_later): if values['field'] in later_tmp: later[r_name][values['field']][response['_id']] = { 'type': values['type'], 'ressource': values['ressource'], 'value': later_tmp[values['field']], '_etag': response['_etag'] } later = {} inserted = {} template = {} print("~~~~~~~~~~~~~~~~~~~~~~ add commands ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") data_later = [{'field': 'use', 'type': 'list', 'ressource': 'command', 'now': False}] schema = command.get_schema() manage_ressource('command', inserted, later, data_later, 'command_name', schema) print("~~~~~~~~~~~~~~~~~~~~~~ post commands ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") update_later(later, inserted, 'command', 'use', schema) print("~~~~~~~~~~~~~~~~~~~~~~ add timeperiods ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") data_later = [{'field': 'use', 'type': 'list', 'ressource': 'timeperiod', 'now': False}] schema = timeperiod.get_schema() manage_ressource('timeperiod', inserted, later, data_later, 'timeperiod_name', schema) print("~~~~~~~~~~~~~~~~~~~~~~ post timeperiods ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") update_later(later, inserted, 'timeperiod', 'use', schema) print("~~~~~~~~~~~~~~~~~~~~~~ add hostgroups ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") data_later = [ { 'field': 'members', 'type': 'list', 'ressource': 'host', 'now': False }, { 'field': 'hostgroup_members', 'type': 'list', 'ressource': 'hostgroup', 'now': False } ] schema = hostgroup.get_schema() manage_ressource('hostgroup', inserted, later, data_later, 'hostgroup_name', schema) print("~~~~~~~~~~~~~~~~~~~~~~ post hostgroups ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") update_later(later, inserted, 'hostgroup', 'hostgroup_members', schema) print("~~~~~~~~~~~~~~~~~~~~~~ add hostdependency ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") data_later = [{'field': 'use', 'type': 'list', 'ressource': 'hostdependency', 'now': False}] schema = hostdependency.get_schema() manage_ressource('hostdependency', inserted, later, data_later, 'name', schema) print("~~~~~~~~~~~~~~~~~~~~~~ post hostdependency ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") update_later(later, inserted, 'hostdependency', 'use', schema) print("~~~~~~~~~~~~~~~~~~~~~~ add servicedependency ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") data_later = [{'field': 'use', 'type': 'list', 'ressource': 'servicedependency', 'now': False}] schema = servicedependency.get_schema() manage_ressource('servicedependency', inserted, later, data_later, 'name', schema) print("~~~~~~~~~~~~~~~~~~~~~~ post servicedependency ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") update_later(later, inserted, 'servicedependency', 'use', schema) print("~~~~~~~~~~~~~~~~~~~~~~ add serviceextinfo ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") data_later = [{'field': 'use', 'type': 'list', 'ressource': 'serviceextinfo', 'now': False}] schema = serviceextinfo.get_schema() manage_ressource('serviceextinfo', inserted, later, data_later, 'name', schema) print("~~~~~~~~~~~~~~~~~~~~~~ post serviceextinfo ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") update_later(later, inserted, 'serviceextinfo', 'use', schema) print("~~~~~~~~~~~~~~~~~~~~~~ add trigger ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") data_later = [{'field': 'use', 'type': 'list', 'ressource': 'trigger', 'now': False}] schema = trigger.get_schema() manage_ressource('trigger', inserted, later, data_later, 'trigger_name', schema) print("~~~~~~~~~~~~~~~~~~~~~~ post trigger ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") update_later(later, inserted, 'trigger', 'use', schema) # print("~~~~~~~~~~~~~~~~~~~~~~ add contact ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") # data_later = [ # {'field': 'use', 'type': 'simple', 'ressource': 'contact'}, # {'field': 'contactgroups', 'type': 'list', 'ressource': 'contactgroup'}, # {'field': 'host_notification_period', 'type': 'simple', 'ressource': 'timeperiod'}, # {'field': 'service_notification_period', 'type': 'simple', 'ressource': 'timeperiod'}, # {'field': 'host_notification_commands', 'type': 'list', 'ressource': 'command'}, # {'field': 'service_notification_commands', 'type': 'list', 'ressource': 'command'} # ] # schema = contact.get_schema() # manage_ressource('contact', inserted, later, data_later, 'contact_name', schema) # print("~~~~~~~~~~~~~~~~~~~~~~ post contact ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") # update_later(later, inserted, 'contact', 'use', schema) # update_later(later, inserted, 'contact', 'host_notification_period', schema) # update_later(later, inserted, 'contact', 'service_notification_period', schema) # update_later(later, inserted, 'contact', 'host_notification_commands', schema) # update_later(later, inserted, 'contact', 'service_notification_commands', schema) print("~~~~~~~~~~~~~~~~~~~~~~ add contactgroup ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") data_later = [ {'field': 'members', 'type': 'list', 'ressource': 'contact', 'now': False}, {'field': 'contactgroup_members', 'type': 'list', 'ressource': 'contactgroup', 'now': False} ] schema = contactgroup.get_schema() manage_ressource('contactgroup', inserted, later, data_later, 'contactgroup_name', schema) print("~~~~~~~~~~~~~~~~~~~~~~ post contactgroup ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") # update_later(later, inserted, 'contactgroup', 'members', schema) update_later(later, inserted, 'contactgroup', 'contactgroup_members', schema) # update_later(later, inserted, 'contact', 'contactgroups', schema) print("~~~~~~~~~~~~~~~~~~~~~~ add contactrestrictrole ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") data_later = [ {'field': 'contact', 'type': 'simple', 'ressource': 'contact', 'now': False} ] schema = contactrestrictrole.get_schema() manage_ressource('contactrestrictrole', inserted, later, data_later, 'contact', schema) print("~~~~~~~~~~~~~~~~~~~~~~ post contactrestrictrole ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") # update_later(later, inserted, 'contactrestrictrole', 'contact', schema) print("~~~~~~~~~~~~~~~~~~~~~~ add escalation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") data_later = [ {'field': 'use', 'type': 'list', 'ressource': 'escalation', 'now': False}, {'field': 'contacts', 'type': 'list', 'ressource': 'contact', 'now': False}, {'field': 'contact_groups', 'type': 'list', 'ressource': 'contactgroup', 'now': True} ] schema = escalation.get_schema() manage_ressource('escalation', inserted, later, data_later, 'escalation_name', schema) print("~~~~~~~~~~~~~~~~~~~~~~ post escalation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") update_later(later, inserted, 'escalation', 'use', schema) # update_later(later, inserted, 'escalation', 'contacts', schema) print("~~~~~~~~~~~~~~~~~~~~~~ add host ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") data_later = [ {'field': 'use', 'type': 'list', 'ressource': 'host', 'now': False}, {'field': 'parents', 'type': 'list', 'ressource': 'host', 'now': False}, {'field': 'hostgroups', 'type': 'list', 'ressource': 'hostgroup', 'now': True}, {'field': 'check_command', 'type': 'simple', 'ressource': 'command', 'now': True}, {'field': 'check_period', 'type': 'simple', 'ressource': 'timeperiod', 'now': True}, {'field': 'contacts', 'type': 'list', 'ressource': 'contact', 'now': False}, {'field': 'contact_groups', 'type': 'list', 'ressource': 'contactgroup', 'now': True}, {'field': 'notification_period', 'type': 'simple', 'ressource': 'timeperiod', 'now': True}, {'field': 'escalations', 'type': 'list', 'ressource': 'escalation', 'now': True} ] schema = host.get_schema() manage_ressource('host', inserted, later, data_later, 'host_name', schema) print("~~~~~~~~~~~~~~~~~~~~~~ post host ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") update_later(later, inserted, 'host', 'use', schema) update_later(later, inserted, 'host', 'parents', schema) # update_later(later, inserted, 'host', 'contacts', schema) update_later(later, inserted, 'hostgroup', 'members', schema) print("~~~~~~~~~~~~~~~~~~~~~~ add hostextinfo ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") data_later = [{'field': 'use', 'type': 'list', 'ressource': 'hostextinfo', 'now': False}] schema = hostextinfo.get_schema() manage_ressource('hostextinfo', inserted, later, data_later, 'host_name', schema) print("~~~~~~~~~~~~~~~~~~~~~~ post hostextinfo ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") update_later(later, inserted, 'hostextinfo', 'use', schema) print("~~~~~~~~~~~~~~~~~~~~~~ add hostescalation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") data_later = [{'field': 'use', 'type': 'list', 'ressource': 'hostescalation', 'now': False}, {'field': 'contacts', 'type': 'list', 'ressource': 'contact', 'now': False}, {'field': 'contact_groups', 'type': 'list', 'ressource': 'contactgroup', 'now': True}] schema = hostescalation.get_schema() manage_ressource('hostescalation', inserted, later, data_later, 'host_name', schema) print("~~~~~~~~~~~~~~~~~~~~~~ post hostescalation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") update_later(later, inserted, 'hostescalation', 'use', schema) # update_later(later, inserted, 'hostescalation', 'contacts', schema) print("~~~~~~~~~~~~~~~~~~~~~~ add servicegroups ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") data_later = [ {'field': 'members', 'type': 'list', 'ressource': 'service', 'now': False}, {'field': 'servicegroup_members', 'type': 'list', 'ressource': 'servicegroup', 'now': False} ] schema = servicegroup.get_schema() manage_ressource('servicegroup', inserted, later, data_later, 'servicegroup_name', schema) print("~~~~~~~~~~~~~~~~~~~~~~ post servicegroups ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") update_later(later, inserted, 'servicegroup', 'servicegroup_members', schema) print("~~~~~~~~~~~~~~~~~~~~~~ add service ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") data_later = [ {'field': 'use', 'type': 'list', 'ressource': 'service', 'now': False}, {'field': 'host_name', 'type': 'simple', 'ressource': 'host', 'now': True}, {'field': 'servicegroups', 'type': 'list', 'ressource': 'servicegroup', 'now': True}, {'field': 'check_command', 'type': 'simple', 'ressource': 'command', 'now': True}, {'field': 'check_period', 'type': 'simple', 'ressource': 'timeperiod', 'now': True}, {'field': 'notification_period', 'type': 'simple', 'ressource': 'timeperiod', 'now': True}, {'field': 'contacts', 'type': 'list', 'ressource': 'contact', 'now': False}, {'field': 'contact_groups', 'type': 'list', 'ressource': 'contactgroup', 'now': True}, {'field': 'escalations', 'type': 'list', 'ressource': 'escalation', 'now': True}, {'field': 'maintenance_period', 'type': 'simple', 'ressource': 'timeperiod', 'now': True}, {'field': 'service_dependencies', 'type': 'list', 'ressource': 'service', 'now': True} ] schema = service.get_schema() manage_ressource('service', inserted, later, data_later, 'service_description', schema) print("~~~~~~~~~~~~~~~~~~~~~~ post service ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") update_later(later, inserted, 'service', 'use', schema) # update_later(later, inserted, 'service', 'contacts', schema) update_later(later, inserted, 'servicegroup', 'members', schema) print("~~~~~~~~~~~~~~~~~~~~~~ add serviceescalation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") data_later = [ {'field': 'use', 'type': 'list', 'ressource': 'serviceescalation', 'now': False}, {'field': 'contacts', 'type': 'list', 'ressource': 'contact', 'now': False}, {'field': 'contact_groups', 'type': 'list', 'ressource': 'contactgroup', 'now': True} ] schema = serviceescalation.get_schema() manage_ressource('serviceescalation', inserted, later, data_later, 'host_name', schema) print("~~~~~~~~~~~~~~~~~~~~~~ post serviceescalation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") update_later(later, inserted, 'serviceescalation', 'use', schema) # update_later(later, inserted, 'serviceescalation', 'contacts', schema) # print all errors found print('################################## errors report ##################################') for error in errors_found: print(error) print('###################################################################################')
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))
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.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), ) # 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, 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 """ 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 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: logger.error( "[Backend Scheduler] Alignak backend connection is not available. " "Skipping objects retention load." ) else: # Get data from the backend response = self.backend.get_all("retentionhost") for host in response["_items"]: # clean unusable keys hostname = host["host"] for key in ["_created", "_etag", "_id", "_links", "_updated", "host"]: del host[key] all_data["hosts"][hostname] = host response = self.backend.get_all("retentionservice") for service in response["_items"]: # clean unusable keys servicename = (service["service"][0], service["service"][1]) for key in ["_created", "_etag", "_id", "_links", "_updated", "service"]: del service[key] all_data["services"][servicename] = service scheduler.restore_retention_data(all_data) def hook_save_retention(self, scheduler): """ Save retention data from alignak-backend :param scheduler: scheduler instance of alignak :type scheduler: object :return: None """ data_to_save = scheduler.get_retention_data() if not self.backend_connected: logger.error("Alignak backend connection is not available. " "Skipping objects retention save.") return # clean hosts we will re-upload the retention response = self.backend.get_all("retentionhost") for host in response["_items"]: if host["host"] in data_to_save["hosts"]: delheaders = {"If-Match": host["_etag"]} self.backend.delete("/".join(["retentionhost", host["_id"]]), headers=delheaders) # Add all hosts after for host in data_to_save["hosts"]: data_to_save["hosts"][host]["host"] = host try: self.backend.post("retentionhost", data=data_to_save["hosts"][host]) except BackendException as exp: logger.error("Post retentionhost for host error") logger.error("Response: %s", exp.response) logger.exception("Exception: %s", exp) return logger.info("%d hosts saved in retention", len(data_to_save["hosts"])) # clean services we will re-upload the retention response = self.backend.get_all("retentionservice") for service in response["_items"]: if (service["service"][0], service["service"][1]) in data_to_save["services"]: delheaders = {"If-Match": service["_etag"]} self.backend.delete("/".join(["retentionservice", service["_id"]]), headers=delheaders) # Add all services after for service in data_to_save["services"]: data_to_save["services"][service]["service"] = service try: self.backend.post("retentionservice", data=data_to_save["services"][service]) except BackendException as exp: logger.error("Post retentionservice for service error") logger.exception("Exception: %s", exp) return logger.info("%d services saved in retention", len(data_to_save["services"]))