From 7d424b59b1d095c0a43bab4f23d174c3c9430581 Mon Sep 17 00:00:00 2001 From: Rick Mouritzen <129233333+rmouritzen-splunk@users.noreply.github.com> Date: Tue, 28 Nov 2023 12:07:15 -0800 Subject: [PATCH] Issue #54: Explicitly set missing requirement attribute field (#56) * Issue #54: Explicitly set missing requirement field in attributes to "optional" during schema load. Log attributes with missing requirement field on a single line. Bump version. --------- Signed-off-by: Rick Mouritzen <129233333+rmouritzen-splunk@users.noreply.github.com> --- lib/schema/cache.ex | 73 +++++++++++++++++++++++++++++++++++++++++++++ mix.exs | 2 +- 2 files changed, 74 insertions(+), 1 deletion(-) diff --git a/lib/schema/cache.ex b/lib/schema/cache.ex index 3a289f7..4473b50 100644 --- a/lib/schema/cache.ex +++ b/lib/schema/cache.ex @@ -82,6 +82,21 @@ defmodule Schema.Cache do base_event = final_check(:base_event, base_event, attributes) + no_req_set = MapSet.new() + {profiles, no_req_set} = fix_entities(profiles, no_req_set) + {base_event, no_req_set} = fix_entity(base_event, no_req_set) + {classes, no_req_set} = fix_entities(classes, no_req_set) + {objects, no_req_set} = fix_entities(objects, no_req_set) + + if MapSet.size(no_req_set) > 0 do + no_reqs = no_req_set |> Enum.sort() |> Enum.join(", ") + + Logger.warning( + "The following attributes do not have a \"requirement\" field," <> + " a value of \"optional\" will be used: #{no_reqs}" + ) + end + new(version) |> set_profiles(profiles) |> set_categories(categories) @@ -593,6 +608,64 @@ defmodule Schema.Cache do end end + # Final fix up a map of many name -> entity key-value pairs. + # The term "entities" means to profiles, objects, or classes. + @spec fix_entities(map(), MapSet.t()) :: {map(), MapSet.t()} + defp fix_entities(entities, no_req_set) do + Enum.reduce( + entities, + {Map.new(), no_req_set}, + fn {entity_name, entity}, {entities, no_req_set} -> + {entity, no_req_set} = fix_entity(entity, no_req_set) + {Map.put(entities, entity_name, entity), no_req_set} + end + ) + end + + # Final fix up of an entity definition map. + # The term "entity" mean a single profile, object, class, or base_event (a special class). + @spec fix_entity(map(), MapSet.t()) :: {map(), MapSet.t()} + defp fix_entity(entity, no_req_set) do + {attributes, no_req_set} = fix_attributes(entity[:attributes], no_req_set) + {Map.put(entity, :attributes, attributes), no_req_set} + end + + # Final fix up an attributes map. + @spec fix_attributes(map(), MapSet.t()) :: {map(), MapSet.t()} + defp fix_attributes(attributes, no_req_set) do + Enum.reduce( + attributes, + {Map.new(), no_req_set}, + fn {attribute_name, attribute_details}, {attributes, no_req_set} -> + { + # The Map.put_new fixes the actual missing requirement problem + Map.put( + attributes, + attribute_name, + Map.put_new(attribute_details, :requirement, "optional") + ), + # This adds attributes with missing requirement to a set for later logging + track_missing_requirement(attribute_name, attribute_details, no_req_set) + } + end + ) + end + + @spec track_missing_requirement(String.t(), map(), MapSet.t()) :: MapSet.t() + defp track_missing_requirement(attribute_name, attribute_details, no_req_set) do + if Map.has_key?(attribute_details, :requirement) do + no_req_set + else + context = "#{attribute_details[:_source]}.#{attribute_name}" + + if MapSet.member?(no_req_set, context) do + no_req_set + else + MapSet.put(no_req_set, context) + end + end + end + defp set_profiles(%__MODULE__{} = schema, profiles) do struct(schema, profiles: profiles) end diff --git a/mix.exs b/mix.exs index b182d0e..31dff7c 100644 --- a/mix.exs +++ b/mix.exs @@ -10,7 +10,7 @@ defmodule Schema.MixProject do use Mix.Project - @version "2.62.0" + @version "2.63.0" def project do build = System.get_env("GITHUB_RUN_NUMBER") || "SNAPSHOT"