File 3487-snmp-agent-Improved-agent-config-validation.patch of Package erlang

From 4fac786630a1b0dfe0ea1e86b28b6c25b6bff985 Mon Sep 17 00:00:00 2001
From: Micael Karlberg <bmk@erlang.org>
Date: Tue, 6 Oct 2020 17:22:09 +0200
Subject: [PATCH 17/21] [snmp|agent] Improved agent config validation

Attempt to ensure that invalid config can be detected.
Specifically with regard to transports.

OTP-16649
---
 lib/snmp/src/agent/snmp_framework_mib.erl | 85 +++++++++++++++++------
 1 file changed, 62 insertions(+), 23 deletions(-)

diff --git a/lib/snmp/src/agent/snmp_framework_mib.erl b/lib/snmp/src/agent/snmp_framework_mib.erl
index fa0464c077..9f5caae8e2 100644
--- a/lib/snmp/src/agent/snmp_framework_mib.erl
+++ b/lib/snmp/src/agent/snmp_framework_mib.erl
@@ -192,39 +192,77 @@ check_context(Context) ->
 %%  {Name, Value}.
 %%-----------------------------------------------------------------
 check_agent(Entry, undefined) ->
-    check_agent(Entry, {snmp_target_mib:default_domain(), undefined});
-check_agent({intAgentTransportDomain, Domain}, {_, Port}) ->
+    check_agent(Entry, #{domain => snmp_target_mib:default_domain(),
+                         port   => undefined});
+
+%% <BACKWARD-COMPAT>
+check_agent({intAgentTransportDomain, Domain},
+            #{transports := T} = State) when is_list(T) andalso (T =/= []) ->
+    ?vinfo("check_agent(intAgentTransportDomain) -> entry with"
+           "~n      Domain: ~p"
+           "~n   when"
+           "~n      State:  ~p", [Domain, State]),
+    error({transports_already_defined, T});
+check_agent({intAgentTransportDomain, Domain}, State) ->
     ?vtrace("check_agent(intAgentTransportDomain) -> entry with"
-            "~n      Domain: ~p"
-            "~n   when"
-            "~n      Port:   ~p", [Domain, Port]),
-    {snmp_conf:check_domain(Domain), {Domain, Port}};
-check_agent({intAgentUDPPort, Port}, {Domain, _}) ->
+            "~n      Domain: ~p", [Domain]),
+    {snmp_conf:check_domain(Domain), State#{domain => Domain}};
+%% </BACKWARD-COMPAT>
+
+check_agent({intAgentUDPPort, NewPort}, #{port := OldPort})
+  when is_integer(OldPort) ->
+    ?vinfo("check_agent(intAgentUDPPort) -> entry with"
+          "~n      New Port: ~p"
+          "~n   when"
+          "~n      Old Port: ~p", [NewPort, OldPort]),
+    error({port_already_defined, OldPort});
+check_agent({intAgentUDPPort, Port}, State) ->
     ?vtrace("check_agent(intAgentUDPPort) -> entry with"
-            "~n      Port:   ~p"
+            "~n      Port:  ~p"
             "~n   when"
-            "~n      Domain: ~p", [Port, Domain]),
+            "~n      State: ~p", [Port, State]),
     ok = snmp_conf:check_port(Port),
-    {ok, {Domain, Port}};
-check_agent({intAgentIpAddress, _}, {_, undefined}) ->
+    {ok, State#{port => Port}};
+
+%% <BACKWARD-COMPAT>
+check_agent({intAgentIpAddress, Ip}, #{port := undefined}) ->
+    ?vinfo("check_agent(intAgentIpAddress) -> "
+           "entry when port not defined with"
+           "~n      Ip: ~p", [Ip]),
     error({missing_mandatory, intAgentUDPPort});
-check_agent({intAgentIpAddress = Tag, Ip} = Entry, {Domain, Port} = State) ->
+check_agent({intAgentIpAddress = _Tag, Ip} = _Entry, 
+            #{transports := T} = _State) when (T =/= []) ->
+    ?vinfo("check_agent(intAgentIpAddress) -> "
+           "entry when transports already defined with"
+           "~n      Ip:         ~p"
+           "~n   when"
+           "~n      Transports: ~p", [Ip, T]),
+    error({transports_already_defined, T});
+check_agent({intAgentIpAddress = Tag, Ip} = _Entry,
+            #{domain := Domain, port := Port} = State) ->
     ?vtrace("check_agent(intAgentIpAddress) -> entry with"
             "~n      Ip:     ~p"
             "~n   when"
             "~n      Domain: ~p"
             "~n      Port:   ~p", [Ip, Domain, Port]),
-    {case snmp_conf:check_ip(Domain, Ip) of
-	 ok ->
-	     [Entry,
-	      {intAgentTransports, [{Domain, {Ip, Port}, all, []}]}];
-	 {ok, FixedIp} ->
-             ?vtrace("check_agent(intAgentIpAddress) -> Fixed IP:"
-                     "~n      ~p", [FixedIp]),
-	     [{Tag, FixedIp},
-	      {intAgentTransports, [{Domain, {FixedIp, Port}, all, []}]}]
-     end, State};
-check_agent({intAgentTransports = Tag, Transports}, {_, Port} = State)
+    FixedIp = case snmp_conf:check_ip(Domain, Ip) of
+                  ok ->
+                      Ip;
+                  {ok, FIp} ->
+                      FIp
+              end,
+    T       = [{Domain, {FixedIp, Port}, all, []}],
+    Rows    = [{Tag, FixedIp}, {intAgentTransports, T}],
+    {Rows, State#{transports => T}};
+%% </BACKWARD-COMPAT>
+
+check_agent({intAgentTransports = _Tag, _Transports},
+            #{transports := T} = _State) when (T =/= []) -> 
+    ?vinfo("check_agent(intAgentTransports) -> "
+           "entry when transports already defined with"
+           "~n      T: ~p", [T]),
+    error({transports_already_defined, T});   
+check_agent({intAgentTransports = Tag, Transports}, #{port := Port} = State)
   when is_list(Transports) ->
     ?vtrace("check_agent(intAgentTransports) -> entry when"
             "~n      Port: ~p", [Port]),
@@ -337,6 +375,7 @@ check_agent(X) ->
 
 %% Ordering function to sort intAgentTransportDomain first
 %% hence before intAgentIpAddress.  Sort other entries on the key.
+%% Note that neither of these are required!
 -dialyzer({nowarn_function, order_agent/2}).
 order_agent(EntryA, EntryB) ->
     snmp_conf:keyorder(
-- 
2.26.2

openSUSE Build Service is sponsored by