def test_missing_hsp_in_list(self): # get a 404 if one out of two records is missing with self.test_flask_app.app_context(): db_interface.create_profile("eca1c5c4-ab27-11ea-958a-98fa9b07d419", {}, "1234", "5678") self.addInventoryRecord("eca1c5c4-ab27-11ea-958a-98fa9b07d419", "test_name") response = self.client.get( "/api/historical-system-profiles/v1/systems/eca1c5c4-ab27-11ea-958a-98fa9b07d419", headers=fixtures.AUTH_HEADER, ) data = json.loads(response.data) valid_profile_id = data["data"][0]["profiles"][0]["id"] # NB: we are fetching individual profiles now, not the list of profiles for the system response = self.client.get( f"/api/historical-system-profiles/v1/profiles/{valid_profile_id}", headers=fixtures.AUTH_HEADER, ) self.assertEqual(response.status_code, 200) response = self.client.get( f"/api/historical-system-profiles/v1/profiles/{valid_profile_id}" ",9db484bc-ab2a-11ea-9a15-98fa9b07d419", headers=fixtures.AUTH_HEADER, ) self.assertEqual(response.status_code, 404) self.assertEqual( response.json["message"], "ids [9db484bc-ab2a-11ea-9a15-98fa9b07d419] not available to display", )
def test_save_model(self): # confirm there are zero records associated with an inventory ID response = self.client.get( "/api/historical-system-profiles/v1/systems/29dbe6ce-897f-11ea-8f75-98fa9b07d419", headers=fixtures.AUTH_HEADER, ) data = json.loads(response.data) self.assertEqual(response.status_code, 404) # add one record, confirm count with self.test_flask_app.app_context(): # NB: this is an INVENTORY id, not HSP id! HSP ids are generated at creation time. db_interface.create_profile("29dbe6ce-897f-11ea-8f75-98fa9b07d419", {}, "1234", "5678") response = self.client.get( "/api/historical-system-profiles/v1/systems/29dbe6ce-897f-11ea-8f75-98fa9b07d419", headers=fixtures.AUTH_HEADER, ) data = json.loads(response.data) self.assertEquals(1, len(data["data"][0]["profiles"])) # delete all records, confirm count with self.test_flask_app.app_context(): # inventory ID is the only way to reference records to delete db_interface.delete_hsps_by_inventory_id( "29dbe6ce-897f-11ea-8f75-98fa9b07d419") response = self.client.get( "/api/historical-system-profiles/v1/systems/29dbe6ce-897f-11ea-8f75-98fa9b07d419", headers=fixtures.AUTH_HEADER, ) data = json.loads(response.data) self.assertEqual(response.status_code, 404)
def test_create_delete_hsp(self): # this test requires accessing some data via the DB interface. We don't # expose create or delete via the API. # confirm there are zero records to start response = self.client.get( "/api/historical-system-profiles/v1/systems/6887d404-ab27-11ea-b3ae-98fa9b07d419", headers=fixtures.AUTH_HEADER, ) data = json.loads(response.data) self.assertEqual(response.status_code, 404) # add one record, confirm count with self.test_flask_app.app_context(): db_interface.create_profile("6887d404-ab27-11ea-b3ae-98fa9b07d419", {}, "1234", "5678") response = self.client.get( "/api/historical-system-profiles/v1/systems/6887d404-ab27-11ea-b3ae-98fa9b07d419", headers=fixtures.AUTH_HEADER, ) data = json.loads(response.data) self.assertEquals(1, len(data["data"][0]["profiles"])) # delete all records, confirm count with self.test_flask_app.app_context(): db_interface.delete_hsps_by_inventory_id( "6887d404-ab27-11ea-b3ae-98fa9b07d419") response = self.client.get( "/api/historical-system-profiles/v1/systems/6887d404-ab27-11ea-b3ae-98fa9b07d419", headers=fixtures.AUTH_HEADER, ) data = json.loads(response.data) self.assertEqual(response.status_code, 404)
def test_pagination(self): # create inventory record self.addInventoryRecord( "16c1b34a-bf78-494e-ba3d-fe7dc1b18459", "pagination_test_system_display_name", ) # create four profiles, iterating "some_fact" to simulate check-ins for this host # 1234 is the account number # 5678 is the org id with self.test_flask_app.app_context(): for i in range(4): db_interface.create_profile( "16c1b34a-bf78-494e-ba3d-fe7dc1b18459", {"some_fact": f"some_value_{i}"}, "1234", "5678", ) # fetch the system profiles providing limit and offset response = self.client.get( "/api/historical-system-profiles/v1/systems/16c1b34a-bf78-494e-ba3d-fe7dc1b18459" "?limit=2&offset=1", headers=fixtures.AUTH_HEADER, ) returned_profiles = response.json["data"][0]["profiles"] # assert that the limit works self.assertEqual(len(returned_profiles), 2) # get the fact from a particular profile profile_id = returned_profiles[1]["id"] profile_response = self.client.get( f"/api/historical-system-profiles/v1/profiles/{profile_id}", headers=fixtures.AUTH_HEADER, ) some_value = profile_response.json["data"][0]["system_profile"][ "some_fact"] # assert that the offset works by comparing the fact for the profile in that position self.assertEqual(some_value, "some_value_1")
def archiver_event_loop(flask_app, logger): consumer = init_consumer("platform.inventory.host-egress") with flask_app.app_context(): while True: for data in consumer: try: host = data.value["host"] profile = host["system_profile"] # fqdn is on the host but we need it in the profile as well profile["fqdn"] = host["fqdn"] db_interface.create_profile( inventory_id=host["id"], profile=profile, account_number=host["account"], ) logger.info( "wrote inventory_id %s's profile to historical database" % host["id"] ) except Exception: logger.exception("An error occurred during message processing")
def _archive_profile(data, ptc, logger): """ given an event, archive a profile and emit a success message """ if data.value["type"] not in ("created", "updated"): logger.info("skipping message that is not created or updated type") return host = data.value["host"] request_id = _get_request_id(data) _record_recv_message(host, request_id, ptc) profile = host["system_profile"] # fqdn is on the host but we need it in the profile as well profile["fqdn"] = host["fqdn"] # tags is on the host but we need it in the profile as well profile["tags"] = host["tags"] captured_date = profile.get("captured_date") account = host["account"] # Historical profiles have a "captured_date" which is when the data was # taken from the system by insights-client. However, some reporters to # inventory service run in a batch mode and do not update the # captured_date. The logic below will only save a profile if the # captured_date is one that we don't already have for the system in # question. This works for our purposes since users differentiate between # profiles in the app via captured_date. if captured_date and db_interface.is_profile_recorded( captured_date, host["id"], account ): logger.info( "profile with date %s is already recorded for %s" % (captured_date, host["id"]) ) _record_duplicate_message(host, request_id, ptc) else: hsp = db_interface.create_profile( inventory_id=host["id"], profile=profile, account_number=host["account"], ) _record_success_message(hsp.id, host, request_id, ptc) logger.info( "wrote %s to historical database (inv id: %s, captured_on: %s)" % (hsp.id, hsp.inventory_id, hsp.captured_on) )
def _archive_profile(data, ptc, logger, notification_service): """ given an event, archive a profile and emit a success message """ if not data.value or not isinstance(data.value, dict): logger.info("skipping message where data.value is empty or not a dict") return if "type" not in data.value: logger.info("skipping message that does not have a type") return if data.value["type"] not in ("created", "updated"): logger.info("skipping message that is not created or updated type") return service_auth_key = None if "platform_metadata" in data.value and isinstance(data.value["platform_metadata"], dict): service_auth_key = data.value["platform_metadata"].get("b64_identity", None) host = data.value["host"] request_id = _get_request_id(data) _record_recv_message(host, request_id, ptc) profile = host["system_profile"] # fqdn is on the host but we need it in the profile as well profile["fqdn"] = host["fqdn"] # tags is on the host but we need it in the profile as well profile["tags"] = host["tags"] captured_date = profile.get("captured_date") account = host["account"] org_id = host["org_id"] # Historical profiles have a "captured_date" which is when the data was # taken from the system by insights-client. However, some reporters to # inventory service run in a batch mode and do not update the # captured_date. The logic below will only save a profile if the # captured_date is one that we don't already have for the system in # question. This works for our purposes since users differentiate between # profiles in the app via captured_date. if captured_date and db_interface.is_profile_recorded( captured_date, host["id"], account, org_id ): logger.info( "profile with date %s is already recorded for %s, using account id: %s, org_id: %s" % (captured_date, host["id"], account, org_id) ) _record_duplicate_message(host, request_id, ptc) else: hsp = db_interface.create_profile( inventory_id=host["id"], profile=profile, account_number=host["account"], org_id=org_id, ) _record_success_message(hsp.id, host, request_id, ptc) logger.info( "wrote %s to historical database (inv id: %s, captured_on: %s, account id: %s," " org_id: %s)" % (hsp.id, hsp.inventory_id, hsp.captured_on, account, org_id) ) # After the new hsp is saved, we need to check for any reason to alert via # triggering a notification, i.e. if drift from any associated baselines has # occurred. _check_and_send_notifications( host["id"], host["account"], host["org_id"], host["updated"], host["display_name"], host["tags"], notification_service, service_auth_key, logger, )