def _select_applicable_info(systems_with_profiles, baselines, historical_sys_profiles, reference_id): """ Take a list of systems with profiles, and output a "pivoted" list of profile facts, where each fact key has a dict of systems and their values. This is useful when comparing facts across systems. """ # create dicts of id + info parsed_system_profiles = [] for system_with_profile in systems_with_profiles: system_name = profile_parser.get_name(system_with_profile) parsed_system_profile = profile_parser.parse_profile( system_with_profile["system_profile"], system_name, current_app.logger) parsed_system_profiles.append({ **parsed_system_profile, "is_baseline": False }) for historical_sys_profile in historical_sys_profiles: historical_sys_profile_name = historical_sys_profile["display_name"] parsed_historical_sys_profile = profile_parser.parse_profile( historical_sys_profile["system_profile"], historical_sys_profile_name, current_app.logger, ) parsed_system_profiles.append({ **parsed_historical_sys_profile, "is_baseline": False }) # add baselines into parsed_system_profiles for baseline in baselines: baseline_facts = { "id": baseline["id"], "name": baseline["display_name"] } for baseline_fact in baseline["baseline_facts"]: if "value" in baseline_fact: baseline_facts[baseline_fact["name"]] = baseline_fact["value"] elif "values" in baseline_fact: prefix = baseline_fact["name"] for nested_fact in baseline_fact["values"]: baseline_facts[prefix + "." + nested_fact["name"]] = nested_fact["value"] parsed_system_profiles.append({**baseline_facts, "is_baseline": True}) # find the set of all keys to iterate over all_keys = set() for parsed_system_profile in parsed_system_profiles: all_keys = all_keys.union(set(parsed_system_profile.keys())) info_comparisons = [ _create_comparison(parsed_system_profiles, key, reference_id) for key in all_keys ] return info_comparisons
def test_system_tags_parsing_multiple_tag_values(self): tests = { "id": "548f28c4-752d-11ea-b35c-54e1add9c7a0", "tags": [ { "namespace": "insights-client", "key": "Location", "value": "gray rack", }, { "namespace": "insights-client", "key": "Location", "value": "basement", }, { "namespace": "insights-client", "key": "Location", "value": "somewhere else", }, ], } parsed_profile = profile_parser.parse_profile(tests, "fake-name", None) self.assertEqual( parsed_profile["tags.insights-client.Location"], "basement, gray rack, somewhere else", )
def test_running_process_parsing(self): profile = {"id": "1234", "running_processes": ["vim", "vim", "doom.exe"]} fake_plastic_tree = MagicMock() result = profile_parser.parse_profile( profile, "some_display_name", fake_plastic_tree ) self.assertEqual(result["running_processes.vim"], "2") self.assertEqual(result["running_processes.doom.exe"], "1")
def _parse_from_sysprofile(system_profile, system_name, logger): parsed_profile = profile_parser.parse_profile(system_profile, system_name, current_app.logger) facts = [] for fact in parsed_profile: if fact not in ["id", "name"] and parsed_profile[fact] not in [ "N/A", "None", None, ]: facts.append({"name": fact, "value": parsed_profile[fact]}) return group_baselines(facts)
def test_system_tags_parsing(self): tests = { "id": "548f28c4-752d-11ea-b35c-54e1add9c7a0", "tags": [{ "namespace": "insights-client", "key": "Zone", "value": "eastern time zone", }], } parsed_profile = profile_parser.parse_profile(tests, "fake-name", None) self.assertEqual(parsed_profile["tags.insights-client.Zone"], "eastern time zone")
def test_network_interface_parsing(self): profile = { "id": "1234", "network_interfaces": [ {"mtu": 9876, "name": "fake-nic"}, {"name": "no_mtu"}, ], } fake_plastic_tree = MagicMock() result = profile_parser.parse_profile( profile, "some_display_name", fake_plastic_tree ) self.assertEqual(result["network_interfaces.fake-nic.mtu"], "9876") self.assertEqual(result["network_interfaces.no_mtu.mtu"], "N/A")
def test_gpg_pubkey_parsing(self): tests = { "id": "548f28c4-752d-11ea-b35c-54e1add9c7a0", "installed_packages": [ "gpg-pubkey-c481937a-5bc4662d", "bash-5.0.11-1.fc31.x86_64", ], } parsed_profiles = profile_parser.parse_profile(tests, "fake-name", None) self.assertIn("installed_packages.bash", parsed_profiles) self.assertNotIn("installed_packages.gpg-pubkey", parsed_profiles)
def test_system_tags_parsing_two_namespaces(self): tests = { "id": "548f28c4-752d-11ea-b35c-54e1add9c7a0", "tags": [ { "namespace": "insights-client", "key": "myTag", "value": "Insights Client Namespace Tag", }, { "namespace": "satellite", "key": "myTag", "value": "Satellite Namespace Tag", }, ], } parsed_profile = profile_parser.parse_profile(tests, "fake-name", None) self.assertEqual( parsed_profile["tags.insights-client.myTag"], "Insights Client Namespace Tag", self.assertEqual(parsed_profile["tags.satellite.myTag"], "Satellite Namespace Tag"), )
def _select_applicable_info( systems_with_profiles, baselines, historical_sys_profiles, reference_id, short_circuit, ): """ Take a list of systems with profiles, and output a "pivoted" list of profile facts, where each fact key has a dict of systems and their values. This is useful when comparing facts across systems. Unless short_circuit is True, then we don't need a full comparison report, only one for facts present on a single baseline that is being compared with a single system for notifications if a newly checked in hsp system has drifted from an associated baseline. If the key 'drifted_from_baseline' is True, the system has drifted, else False. """ # create dicts of id + info parsed_system_profiles = [] for system_with_profile in systems_with_profiles: system_name = profile_parser.get_name(system_with_profile) parsed_system_profile = profile_parser.parse_profile( system_with_profile["system_profile"], system_name, current_app.logger ) parsed_system_profiles.append({**parsed_system_profile, "is_baseline": False}) for historical_sys_profile in historical_sys_profiles: historical_sys_profile_name = historical_sys_profile["display_name"] parsed_historical_sys_profile = profile_parser.parse_profile( historical_sys_profile["system_profile"], historical_sys_profile_name, current_app.logger, ) parsed_system_profiles.append({**parsed_historical_sys_profile, "is_baseline": False}) # add baselines into parsed_system_profiles for baseline in baselines: baseline_facts = {"id": baseline["id"], "name": baseline["display_name"]} for baseline_fact in baseline["baseline_facts"]: if "value" in baseline_fact: baseline_facts[baseline_fact["name"]] = baseline_fact["value"] elif "values" in baseline_fact: prefix = baseline_fact["name"] for nested_fact in baseline_fact["values"]: baseline_facts[prefix + "." + nested_fact["name"]] = nested_fact["value"] parsed_system_profiles.append({**baseline_facts, "is_baseline": True}) # find the set of all keys to iterate over # if short_circuit is True, we only want the facts present in this baseline # since we are comparing one baseline to one system for notifications only all_keys = set() if short_circuit: for parsed_system_profile in parsed_system_profiles: if parsed_system_profile["is_baseline"]: all_keys = set(parsed_system_profile.keys()) else: for parsed_system_profile in parsed_system_profiles: all_keys = all_keys.union(set(parsed_system_profile.keys())) # prepare regexes for obfuscated values matching obfuscated_regexes = {} for key in OBFUSCATED_FACTS_PATTERNS.keys(): obfuscated_regexes[key] = re.compile(OBFUSCATED_FACTS_PATTERNS[key]) info_comparisons = [] for key in all_keys: # obfuscated information type - key for obfuscated_key in obfuscated_regexes.keys(): if obfuscated_key in key: for system in parsed_system_profiles: system["obfuscation"] = {} system["obfuscation"][key] = False obfuscated_regex = obfuscated_regexes[obfuscated_key] value = system.get(key) # only if value is present and matches with obfuscated pattern if value and obfuscated_regex.match(value): system["obfuscation"][key] = True current_comparison = _create_comparison( parsed_system_profiles, key, reference_id, len(systems_with_profiles), short_circuit, ) if current_comparison: # if short_circuit is True, and there was a change, i.e. this system # has drifted from this associated baseline, then set the key on the # comparison 'drifted_from_baseline' to True to trigger a notification # else set it to False. if short_circuit and current_comparison["state"] == COMPARISON_DIFFERENT: current_comparison["drifted_from_baseline"] = True else: current_comparison["drifted_from_baseline"] = False info_comparisons.append(current_comparison) return info_comparisons
def create_baseline(system_baseline_in): """ create a baseline """ account_number = view_helpers.get_account_number(request) if "values" in system_baseline_in and "value" in system_baseline_in: raise HTTPError( HTTPStatus.BAD_REQUEST, message= "'values' and 'value' cannot both be defined for system baseline", ) query = SystemBaseline.query.filter( SystemBaseline.account == account_number, SystemBaseline.display_name == system_baseline_in["display_name"], ) if query.count() > 0: raise HTTPError( HTTPStatus.BAD_REQUEST, message="display_name '%s' already used for this account" % system_baseline_in["display_name"], ) baseline_facts = [] if "baseline_facts" in system_baseline_in: baseline_facts = system_baseline_in["baseline_facts"] elif "inventory_uuid" in system_baseline_in: auth_key = get_key_from_headers(request.headers) system_with_profile = fetch_systems_with_profiles( [system_baseline_in["inventory_uuid"]], auth_key, current_app.logger, get_event_counters(), )[0] system_name = profile_parser.get_name(system_with_profile) parsed_profile = profile_parser.parse_profile( system_with_profile["system_profile"], system_name, current_app.logger) facts = [] for fact in parsed_profile: if fact not in ["id", "name"] and parsed_profile[fact] not in [ "N/A", "None", None, ]: facts.append({"name": fact, "value": parsed_profile[fact]}) baseline_facts = group_baselines(facts) baseline = SystemBaseline( account=account_number, display_name=system_baseline_in["display_name"], baseline_facts=baseline_facts, ) db.session.add(baseline) db.session.commit( ) # commit now so we get a created/updated time before json conversion return baseline.to_json()
def test_cores_per_socket_parsing(self): tests = {"id": "548f28c4-752d-11ea-b35c-54e1add9c7a0"} parsed_profiles = profile_parser.parse_profile(tests, "fake-name", None) self.assertEqual(parsed_profiles["cores_per_socket"], "N/A")
def create_baseline(system_baseline_in): """ create a baseline """ account_number = view_helpers.get_account_number(request) if "values" in system_baseline_in and "value" in system_baseline_in: raise HTTPError( HTTPStatus.BAD_REQUEST, message= "'values' and 'value' cannot both be defined for system baseline", ) _check_for_existing_display_name(system_baseline_in["display_name"], account_number) baseline_facts = [] if "baseline_facts" in system_baseline_in: baseline_facts = system_baseline_in["baseline_facts"] elif "inventory_uuid" in system_baseline_in: _validate_uuids([system_baseline_in["inventory_uuid"]]) auth_key = get_key_from_headers(request.headers) try: system_with_profile = fetch_systems_with_profiles( [system_baseline_in["inventory_uuid"]], auth_key, current_app.logger, get_event_counters(), )[0] except ItemNotReturned: raise HTTPError( HTTPStatus.BAD_REQUEST, message="inventory UUID %s not available" % system_baseline_in["inventory_uuid"], ) system_name = profile_parser.get_name(system_with_profile) parsed_profile = profile_parser.parse_profile( system_with_profile["system_profile"], system_name, current_app.logger) facts = [] for fact in parsed_profile: if fact not in ["id", "name"] and parsed_profile[fact] not in [ "N/A", "None", None, ]: facts.append({"name": fact, "value": parsed_profile[fact]}) baseline_facts = group_baselines(facts) try: _validate_facts(baseline_facts) except FactValidationError as e: raise HTTPError(HTTPStatus.BAD_REQUEST, message=e.message) baseline = SystemBaseline( account=account_number, display_name=system_baseline_in["display_name"], baseline_facts=baseline_facts, ) baseline.baseline_facts = _sort_baseline_facts(baseline.baseline_facts) db.session.add(baseline) db.session.commit( ) # commit now so we get a created/updated time before json conversion return baseline.to_json()