def test_fetch_objs_internal_error(self): """Test whether a log error message is thrown when an internal error occurs with the method fetch_objs""" saved_objs_error = read_file('data/objects_error') saved_objs_empty = read_file('data/objects_empty') httpretty.register_uri(httpretty.GET, SAVED_OBJECTS_URL + '?page=2', body=saved_objs_empty, status=200) httpretty.register_uri(httpretty.GET, SAVED_OBJECTS_URL + '?page=1', body=saved_objs_error, status=200) client = SavedObjects(KIBANA_URL) with self.assertLogs(logger, level='ERROR') as cm: _ = [ obj for page_objs in client.fetch_objs(SAVED_OBJECTS_URL) for obj in page_objs ] self.assertEqual( cm.output[0], 'ERROR:archimedes.clients.saved_objects:Impossible to retrieve objects at page 1, ' 'url http://example.com/api/saved_objects, An internal server error occurred' )
def test_fetch_objs_http_error_500(self): """Test whether a warning is logged when a 500 HTTP error occurs""" saved_objs_page_1 = read_file('data/objects_1') saved_objs_page_2 = read_file('data/objects_2') saved_objs_page_3 = read_file('data/objects_empty') httpretty.register_uri(httpretty.GET, SAVED_OBJECTS_URL + '?page=3', body=saved_objs_page_3, status=200) httpretty.register_uri(httpretty.GET, SAVED_OBJECTS_URL + '?page=2', body=saved_objs_page_2, status=500) httpretty.register_uri(httpretty.GET, SAVED_OBJECTS_URL + '?page=1', body=saved_objs_page_1, status=200) client = SavedObjects(KIBANA_URL) with self.assertLogs(logger) as cm: _ = [ obj for page_objs in client.fetch_objs(SAVED_OBJECTS_URL) for obj in page_objs ] self.assertEqual( cm.output[0], 'WARNING:archimedes.clients.saved_objects:Impossible to retrieve objects at page 2, ' 'url http://example.com/api/saved_objects')
def test_create_object_http_error(self): """Test whether an exception is thrown if create_object fails""" obj_data = read_file('data/object_index-pattern') attributes = json.loads(obj_data)['attributes'] httpretty.register_uri(httpretty.POST, OBJECT_URL, body=obj_data, status=500) client = SavedObjects(KIBANA_URL) with self.assertRaises(requests.exceptions.HTTPError): _ = client.create_object(OBJECT_TYPE, OBJECT_ID, attributes)
def test_delete_object_http_error(self): """Test whether an exception is thrown when the HTTP error is not 404""" obj_data = read_file('data/object_index-pattern') httpretty.register_uri(httpretty.DELETE, OBJECT_URL, body=obj_data, status=500) client = SavedObjects(KIBANA_URL) with self.assertRaises(requests.exceptions.HTTPError): _ = client.delete_object(OBJECT_TYPE, OBJECT_ID)
def test_get_object(self): """Test the method get_object""" obj_data = read_file('data/object_index-pattern') httpretty.register_uri(httpretty.GET, OBJECT_URL, body=obj_data, status=200) client = SavedObjects(KIBANA_URL) obj = client.get_object(OBJECT_TYPE, OBJECT_ID) self.assertDictEqual(obj, json.loads(obj_data))
def test_delete_object(self): """Test the method delete_object""" httpretty.register_uri(httpretty.DELETE, OBJECT_URL, body="{}", status=200) client = SavedObjects(KIBANA_URL) with self.assertLogs(logger, level='INFO') as cm: _ = client.delete_object(OBJECT_TYPE, OBJECT_ID) self.assertEqual( cm.output[0], 'INFO:archimedes.clients.saved_objects:' 'Object ' + OBJECT_TYPE + ' with id ' + OBJECT_ID + ' deleted')
def test_update_object_http_error(self): """Test whether an exception is thrown when the HTTP error is not 404 or 400""" obj_data = read_file('data/object_index-pattern') attributes = {"version": "2"} httpretty.register_uri(httpretty.PUT, OBJECT_URL, body=obj_data, status=500) client = SavedObjects(KIBANA_URL) with self.assertRaises(requests.exceptions.HTTPError): _ = client.update_object(OBJECT_TYPE, OBJECT_ID, attributes)
def test_fetch_objs(self): """Test whether objects are correctly returned by the method fetch_objs""" saved_objs_page_1 = read_file('data/objects_1') saved_objs_page_2 = read_file('data/objects_2') saved_objs_page_3 = read_file('data/objects_empty') httpretty.register_uri(httpretty.GET, SAVED_OBJECTS_URL + '?page=3', body=saved_objs_page_3, status=200) httpretty.register_uri(httpretty.GET, SAVED_OBJECTS_URL + '?page=2', body=saved_objs_page_2, status=200) httpretty.register_uri(httpretty.GET, SAVED_OBJECTS_URL + '?page=1', body=saved_objs_page_1, status=200) client = SavedObjects(KIBANA_URL) fetched_objs = [ obj for page_objs in client.fetch_objs(SAVED_OBJECTS_URL) for obj in page_objs ] self.assertEqual(len(fetched_objs), 4) obj = fetched_objs[0] self.assertEqual(obj['id'], "0b84fff0-b1b6-11e8-8aac-ef7fd4d8cbad") self.assertEqual(obj['type'], "visualization") self.assertEqual(obj["version"], 1) obj = fetched_objs[1] self.assertEqual(obj['id'], "00cf9cf0-d074-11e8-8aac-ef7fd4d8cbad") self.assertEqual(obj['type'], "visualization") self.assertEqual(obj["version"], 1) obj = fetched_objs[2] self.assertEqual(obj['id'], "1a23fbd0-bc0e-11e8-8aac-ef7fd4d8cbad") self.assertEqual(obj['type'], "visualization") self.assertEqual(obj["version"], 2) obj = fetched_objs[3] self.assertEqual(obj['id'], "00fee5a0-7eb7-11e8-a4e7-6b1c6a13c58d") self.assertEqual(obj['type'], "visualization") self.assertEqual(obj["version"], 1)
def test_fetch_objs_http_error(self): """Test whether an exception is thrown when the HTTP error is not 500""" saved_objs_page = read_file('data/objects_1') httpretty.register_uri(httpretty.GET, SAVED_OBJECTS_URL, body=saved_objs_page, status=404) client = SavedObjects(KIBANA_URL) with self.assertRaises(requests.exceptions.HTTPError): _ = [ obj for page_objs in client.fetch_objs(SAVED_OBJECTS_URL) for obj in page_objs ]
def test_fetch_objs_empty(self): """Test whether no objects are returned by the method fetch_objs""" saved_objs_empty = read_file('data/objects_empty') httpretty.register_uri(httpretty.GET, SAVED_OBJECTS_URL + '?page=1', body=saved_objs_empty, status=200) client = SavedObjects(KIBANA_URL) fetched_objs = [ obj for page_objs in client.fetch_objs(SAVED_OBJECTS_URL) for obj in page_objs ] self.assertEqual(len(fetched_objs), 0)
def test_delete_object_not_found(self): """Test whether a warning is logged when the object is not found""" obj_data = read_file('data/object_index-pattern') httpretty.register_uri(httpretty.DELETE, OBJECT_URL, body=obj_data, status=404) client = SavedObjects(KIBANA_URL) with self.assertLogs(logger, level='WARNING') as cm: obj = client.delete_object(OBJECT_TYPE, OBJECT_ID) self.assertEqual( cm.output[0], 'WARNING:archimedes.clients.saved_objects:' 'No ' + OBJECT_TYPE + ' found with id: ' + OBJECT_ID) self.assertIsNone(obj)
def test_create_object(self): """Test the method create_object""" obj_data = read_file('data/object_index-pattern') attributes = json.loads(obj_data)['attributes'] httpretty.register_uri(httpretty.POST, OBJECT_URL, body=obj_data, status=200) client = SavedObjects(KIBANA_URL) with self.assertLogs(logger, level='INFO') as cm: obj = client.create_object(OBJECT_TYPE, OBJECT_ID, attributes) self.assertEqual( cm.output[0], 'INFO:archimedes.clients.saved_objects:' 'Object ' + OBJECT_TYPE + ' with id ' + OBJECT_ID + ' create') self.assertDictEqual(obj, json.loads(obj_data))
def test_update_object_not_updated(self): """Test whether a warning is logged when the object is not updated""" obj_data = read_file('data/object_index-pattern') attributes = {"version": "2"} httpretty.register_uri(httpretty.PUT, OBJECT_URL, body=obj_data, status=400) client = SavedObjects(KIBANA_URL) with self.assertLogs(logger, level='WARNING') as cm: obj = client.update_object(OBJECT_TYPE, OBJECT_ID, attributes) self.assertEqual( cm.output[0], 'WARNING:archimedes.clients.saved_objects:Impossible to update ' 'the object ' + OBJECT_TYPE + ' with id ' + OBJECT_ID) self.assertIsNone(obj)
def test_initialization(self): """Test whether attributes are initialized""" client = SavedObjects(KIBANA_URL) self.assertEqual(client.base_url, KIBANA_URL) self.assertIsNotNone(client.session) self.assertEqual(client.session.headers['kbn-xsrf'], HEADERS.get('kbn-xsrf')) self.assertEqual(client.session.headers['Content-Type'], HEADERS.get('Content-Type'))
def test_update_object(self): """Test the method update_object""" obj_data = read_file('data/object_index-pattern') obj_attr = "version" obj_new_value = "2" httpretty.register_uri(httpretty.PUT, OBJECT_URL, body=obj_data, status=200) client = SavedObjects(KIBANA_URL) with self.assertLogs(logger, level='INFO') as cm: obj = client.update_object(OBJECT_TYPE, OBJECT_ID, obj_attr, obj_new_value) self.assertEqual( cm.output[0], 'INFO:archimedes.clients.saved_objects:' 'Object ' + OBJECT_TYPE + ' with id ' + OBJECT_ID + ' updated') self.assertDictEqual(obj, json.loads(obj_data))
def set_kibiter_config(kibiter_url, kibiter_time_from='now-90d', kibiter_index_pattern='git', kibiter_version='6.8.6', overwrite=True): """Set the configuration of the Kibiter instance via the Kibana API :param kibiter_url: Kibiter URL :param kibiter_time_from: The value of the time picker :param kibiter_index_pattern: The value of the default index pattern :param kibiter_version: The value of the Kibiter version :param overwrite: If True, force the overwrite of existing dashboards """ attributes = {} time_picker = {"from": kibiter_time_from, "to": "now", "mode": "quick"} attributes["timepicker:timeDefaults"] = json.dumps(time_picker) attributes["defaultIndex"] = kibiter_index_pattern saved_objects = SavedObjects(kibiter_url) saved_objects.create_object('config', kibiter_version, attributes, overwrite=overwrite)
def __init__(self, base_url): self.base_url = base_url self.dashboard = Dashboard(base_url) self.saved_objects = SavedObjects(base_url)
class Kibana: """Kibana class. This class defines operations performed against the Dashboard and the SavedObjects APIs, such as exporting and importing objects as well as searching objects by ID or title. :param base_url: the Kibana URL """ def __init__(self, base_url): self.base_url = base_url self.dashboard = Dashboard(base_url) self.saved_objects = SavedObjects(base_url) def export_by_id(self, obj_type, obj_id): """Export an object identified by its ID. This method returns an object saved in Kibana based on its type and ID. An `ObjectTypeError` is thrown if the type of the object is not one of the following: dashboard, index pattern, search, visualization. A `NotFoundError` is thrown if the object is not found in the Kibana instance. :param obj_type: type of the target object :param obj_id: ID of the target object :returns the target Kibana object """ if obj_type == DASHBOARD: obj = self.dashboard.export_dashboard(obj_id) elif obj_type in [INDEX_PATTERN, SEARCH, VISUALIZATION]: obj = self.saved_objects.get_object(obj_type, obj_id) else: cause = "Unknown type %s" % obj_type logger.error(cause) raise ObjectTypeError(cause=cause) if not obj: cause = "Impossible to export %s with id %s, not found" % ( obj_type, obj_id) logger.error(cause) raise NotFoundError(cause=cause) return obj def export_by_title(self, obj_type, obj_title): """Export an object identified by its title. This method returns an object saved in Kibana based on its type and title. An `ObjectTypeError` is thrown if the type of the object is not one of the following: dashboard, index pattern, search, visualization. A `NotFoundError` is thrown if the object is not found in the Kibana instance. :param obj_type: type of the target object :param obj_title: title of the target object :returns the target Kibana object """ if obj_type not in [DASHBOARD, INDEX_PATTERN, SEARCH, VISUALIZATION]: cause = "Unknown type %s" % obj_type logger.error(cause) raise ObjectTypeError(cause=cause) obj = self.find_by_title(obj_type, obj_title) if obj_type == DASHBOARD: obj_id = obj['id'] obj = self.dashboard.export_dashboard(obj_id) if not obj: cause = "Impossible to export %s with title %s, not found" % ( obj_type, obj_title) logger.error(cause) raise NotFoundError(cause=cause) return obj def import_objects(self, objects, force=False): """Import a list of objects to Kibana. This method imports a list of Kibana objects to Kibana by using the Dashboard API. :param objects: list of objects to import :param force: overwrite any existing objects on ID conflict """ self.dashboard.import_objects(objects, force=force) def find_by_title(self, obj_type, obj_title): """Find an object by its type and title. This methods returns a Kibana object based on its type and title. A `NotFoundError` is thrown if the object is not found in the Kibana instance. :param obj_type: type of the target object :param obj_title: title of the target object :returns the target object or None if not found """ url = urijoin(self.base_url, self.saved_objects.API_SAVED_OBJECTS_URL) found_obj = None for page_objs in self.saved_objects.fetch_objs(url): for obj in page_objs: if obj['type'] == obj_type and obj['attributes'][ 'title'] == obj_title: found_obj = obj break if not found_obj: cause = "No %s found with title: %s" % (obj_type, obj_title) logger.error(cause) raise NotFoundError(cause=cause) return found_obj def find_by_id(self, obj_type, obj_id): """Find an object by its type and ID. This methods returns a Kibana object based on its type and ID. A `NotFoundError` is thrown if the object is not found in the Kibana instance. :param obj_type: type of the target object :param obj_id: ID of the target object :returns the target object or None if not found """ url = urijoin(self.base_url, self.saved_objects.API_SAVED_OBJECTS_URL) found_obj = None for page_objs in self.saved_objects.fetch_objs(url): for obj in page_objs: if obj['type'] == obj_type and obj['id'] == obj_id: found_obj = obj break if not found_obj: cause = "No %s found with ID: %s" % (obj_type, obj_id) logger.error(cause) raise NotFoundError(cause=cause) return found_obj def find_all(self): """Find all objects stored in Kibana. This method returns all remote Kibana objects using the SavedObject API. :returns a generator of Kibana objects """ url = urijoin(self.base_url, self.saved_objects.API_SAVED_OBJECTS_URL) for page_objs in self.saved_objects.fetch_objs(url): for obj in page_objs: yield obj