aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/snmp/doc/src/notes.xml30
-rw-r--r--lib/snmp/doc/src/snmp_app.xml7
-rw-r--r--lib/snmp/doc/src/snmp_config.xml9
-rw-r--r--lib/snmp/doc/src/snmpm_user.xml187
-rw-r--r--lib/snmp/examples/ex2/snmp_ex2_manager.erl9
-rw-r--r--lib/snmp/src/agent/snmpa_local_db.erl8
-rw-r--r--lib/snmp/src/agent/snmpa_supervisor.erl2
-rw-r--r--lib/snmp/src/app/Makefile4
-rw-r--r--lib/snmp/src/app/snmp.erl55
-rw-r--r--lib/snmp/src/app/snmp_internal.hrl4
-rw-r--r--lib/snmp/src/manager/snmpm.erl25
-rw-r--r--lib/snmp/src/manager/snmpm_config.erl31
-rw-r--r--lib/snmp/src/manager/snmpm_server.erl184
-rw-r--r--lib/snmp/src/manager/snmpm_user.erl173
-rw-r--r--lib/snmp/src/misc/snmp_config.erl187
-rw-r--r--lib/snmp/test/snmp_agent_test.erl72
-rw-r--r--lib/snmp/test/snmp_manager_config_test.erl43
-rw-r--r--lib/snmp/test/snmp_manager_test.erl66
-rw-r--r--lib/snmp/test/snmp_manager_user.erl17
-rw-r--r--lib/snmp/test/snmp_test_manager.erl20
20 files changed, 779 insertions, 354 deletions
diff --git a/lib/snmp/doc/src/notes.xml b/lib/snmp/doc/src/notes.xml
index 1b954a5294..0da620e754 100644
--- a/lib/snmp/doc/src/notes.xml
+++ b/lib/snmp/doc/src/notes.xml
@@ -36,7 +36,7 @@
<section>
<title>SNMP Development Toolkit 4.25</title>
<p>Version 4.25 supports code replacement in runtime from/to
- version 2.24.2, 4.24.1, 4.24, 4.23.1 and 4.23. </p>
+ version 4.24.2, 4.24.1, 4.24, 4.23.1 and 4.23. </p>
<section>
<title>Improvements and new features</title>
@@ -46,6 +46,32 @@
<list type="bulleted">
<item>
+ <p>[agent] Enable SNMP to create missing database directories. </p>
+ <p>Add
+ <seealso marker="snmp_app#db_init_error">
+ {db_init_error, create_db_and_dir}</seealso> option to SNMP
+ <seealso marker="snmp_app#manager_opts_and_types">manager</seealso>
+ and
+ <seealso marker="snmp_app#agent_opts_and_types">agent</seealso>.
+ This allows them to create any missing parent directories for
+ <c>db_dir</c>, rather than treating any missing directories
+ as a fatal error.
+ The default for <c>db_init_error</c>, which is <c>terminate</c>,
+ is unchanged. </p>
+ <p>Steve Vinoski</p>
+ <p>Own Id: OTP-11352</p>
+ </item>
+
+ <item>
+ <p>[manager] Improved handling of unexpected return values from
+ <seealso marker="snmpm_user">snmpm_user</seealso>
+ callback functions. </p>
+ <p>Violations of the documented API (crashes or invalid return
+ values) will now result in an error message. </p>
+ <p>Own Id: OTP-11307</p>
+ </item>
+
+ <item>
<p>Add (atl) log conversion block option. </p>
<p>It is now possible to request that the Audit Trail Log should
be blocked during conversion (<c>log_to_txt</c> or <c>log_to_io</c>).
@@ -168,7 +194,7 @@
</list>
-->
</section>
-
+
</section> <!-- 4.24.2 -->
diff --git a/lib/snmp/doc/src/snmp_app.xml b/lib/snmp/doc/src/snmp_app.xml
index e5a05342c1..9ede75b943 100644
--- a/lib/snmp/doc/src/snmp_app.xml
+++ b/lib/snmp/doc/src/snmp_app.xml
@@ -763,12 +763,15 @@
</item>
<marker id="db_init_error"></marker>
- <tag><c>db_init_error() = terminate | create</c></tag>
+ <tag><c>db_init_error() = terminate | create | create_db_and_dir</c></tag>
<item>
<p>Defines what to do if the agent or manager is unable to open an
existing database file. <c>terminate</c> means that the
agent/manager will terminate and <c>create</c> means that the
- agent/manager will remove the faulty file(s) and create new ones.</p>
+ agent/manager will remove the faulty file(s) and create new ones,
+ and <c>create_db_and_dir</c> means that the agent/manager will
+ create the database file along with any missing parent directories
+ for the database file.</p>
<p>Default is <c>terminate</c>.</p>
</item>
diff --git a/lib/snmp/doc/src/snmp_config.xml b/lib/snmp/doc/src/snmp_config.xml
index 61ee7f00ee..30b46e6aa8 100644
--- a/lib/snmp/doc/src/snmp_config.xml
+++ b/lib/snmp/doc/src/snmp_config.xml
@@ -792,12 +792,15 @@ in so far as it will be converted to the new format if found.
</item>
<marker id="db_init_error"></marker>
- <tag><c>db_init_error() = terminate | create</c></tag>
+ <tag><c>db_init_error() = terminate | create | create_db_and_dir</c></tag>
<item>
<p>Defines what to do if the agent is unable to open an
existing database file. <c>terminate</c> means that the
- agent/manager will terminate and <c>create</c> means that the
- agent/manager will remove the faulty file(s) and create new ones.</p>
+ agent/manager will terminate, <c>create</c> means that the
+ agent/manager will remove the faulty file(s) and create new ones,
+ and <c>create_db_and_dir</c> means that the agent/manager will
+ create the database file along with any missing parent directories
+ for the database file.</p>
<p>Default is <c>terminate</c>.</p>
</item>
diff --git a/lib/snmp/doc/src/snmpm_user.xml b/lib/snmp/doc/src/snmpm_user.xml
index 1823e0c815..cb2deab976 100644
--- a/lib/snmp/doc/src/snmpm_user.xml
+++ b/lib/snmp/doc/src/snmpm_user.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
<header>
<copyright>
- <year>2004</year><year>2009</year>
+ <year>2004</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -56,40 +56,59 @@
<item>
<p>handle_report/3</p>
</item>
+ <item>
+ <p>handle_invalid_result/2</p>
+ </item>
</list>
<p>The semantics of them and their exact signatures are explained
- below. </p>
- <p>Note that if an agent is registered using the old, no longer
- documented, functions (using Addr and Port), the old variant of the
- callback functions, handle_pdu, handle_trap, handle_inform and
- handle_report, will be called. </p>
+ below. </p>
+ <p>Some of the function has no defined return value (<c>void()</c>),
+ they can ofcourse return anythyng. But the functions that do have
+ specified return value(s) <em>must</em> adhere to this. None of the
+ functions can use exit of throw to return. </p>
- <marker id="handle_error"></marker>
+ <marker id="types"></marker>
</description>
+
+ <section>
+ <title>DATA TYPES</title>
+ <code type="none"><![CDATA[
+snmp_gen_info() = {ErrorStatus :: atom(),
+ ErrorIndex :: pos_integer(),
+ Varbinds :: [snmp:varbind()]}
+snmp_v1_trap_info() :: {Enteprise :: snmp:oid(),
+ Generic :: integer(),
+ Spec :: integer(),
+ Timestamp :: integer(),
+ Varbinds :: [snmp:varbind()]}
+ ]]></code>
+ <marker id="handle_error"></marker>
+ </section>
+
<funcs>
<func>
- <name>handle_error(ReqId, Reason, UserData) -> Reply</name>
+ <name>handle_error(ReqId, Reason, UserData) -> void()</name>
<fsummary>Handle error</fsummary>
<type>
<v>ReqId = integer()</v>
<v>Reason = {unexpected_pdu, SnmpInfo} | {invalid_sec_info, SecInfo, SnmpInfo} | {empty_message, Addr, Port} | term()</v>
+ <v>SnmpInfo = snmp_gen_info()</v>
+ <v>SecInfo = term()</v>
<v>Addr = ip_address()</v>
<v>Port = integer()</v>
<v>UserData = term()</v>
- <v>Reply = ignore</v>
</type>
<desc>
<p>This function is called when the manager needs to
- communicate an "asynchronous" error, to the user:
- e.g. failure to send an asynchronous message (i.e. encoding
- error), a received message was discarded due to security
- error, the manager failed to generate a response message to
- a received inform-request, or when receiving an unexpected
- PDU from an agent (could be an expired async request). </p>
- <p>If <c>ReqId</c> is less then 0, it means that this
- information was not available to the manager (that info was
- never retrieved before the message was discarded).
- </p>
+ communicate an "asynchronous" error to the user:
+ e.g. failure to send an asynchronous message (i.e. encoding
+ error), a received message was discarded due to security
+ error, the manager failed to generate a response message to
+ a received inform-request, or when receiving an unexpected
+ PDU from an agent (could be an expired async request). </p>
+ <p>If <c>ReqId</c> is less then 0, it means that this
+ information was not available to the manager (that info was
+ never retrieved before the message was discarded). </p>
<p>For <c>SnmpInfo</c> see handle_agent below.</p>
<marker id="handle_agent"></marker>
@@ -104,22 +123,22 @@
<v>Port = integer()</v>
<v>Type = pdu | trap | report | inform</v>
<v>SnmpInfo = SnmpPduInfo | SnmpTrapInfo | SnmpReportInfo | SnmpInformInfo</v>
- <v>ErrorStatus = atom()</v>
- <v>ErrorIndex = integer()</v>
- <v>Varbinds = [varbind()]</v>
- <v>varbind() = #varbind</v>
+ <v>SnmpPduInfo = snmp_gen_info()</v>
+ <v>SnmpTrapInfo = snmp_v1_trap_info()</v>
+ <v>SnmpReportInfo = snmp_gen_info()</v>
+ <v>SnmpInformInfo = snmp_gen_info()</v>
<v>UserData = term()</v>
- <v>Reply = ignore | {register, UserId, TargetName, agent_info()}</v>
+ <v>Reply = ignore | {register, UserId, TargetName, AgentConfig}</v>
<v>UserId = term()</v>
<v>TargetName = target_name()</v>
- <v>agent_info() = [{agent_info_item(), agent_info_value()}]</v>
+ <v>AgentConfig = [agent_config()]</v>
</type>
<desc>
- <p>This function is called when a message is received from an
- unknown agent.</p>
+ <p>This function is called when a message is received from an
+ unknown agent.</p>
<p>Note that this will always be the default user that is called.</p>
- <p>For more info about the <c>agent_info()</c>, see
- <seealso marker="snmpm#register_agent">register_agent</seealso>.</p>
+ <p>For more info about the <c>agent_config()</c>, see
+ <seealso marker="snmpm#register_agent">register_agent</seealso>.</p>
<p>The arguments <c>Type</c> and <c>SnmpInfo</c> relates in the
following way: </p>
@@ -148,7 +167,7 @@
</list>
<p>The only user which would return
- <c>{register, UserId, TargetName, agent_info()}</c> is the
+ <c>{register, UserId, TargetName, AgentConfig}</c> is the
<em>default user</em>.</p>
<marker id="handle_pdu"></marker>
@@ -156,18 +175,13 @@
</func>
<func>
- <name>handle_pdu(TargetName, ReqId, SnmpPduInfo, UserData) -> Reply</name>
+ <name>handle_pdu(TargetName, ReqId, SnmpPduInfo, UserData) -> void()</name>
<fsummary>Handle the reply to an asynchronous request</fsummary>
<type>
<v>TargetName = target_name()</v>
<v>ReqId = term()</v>
- <v>SnmpPduInfo = {ErrorStatus, ErrorIndex, Varbinds}</v>
- <v>ErrorStatus = atom()</v>
- <v>ErrorIndex = integer()</v>
- <v>Varbinds = [varbind()]</v>
- <v>varbind() = #varbind</v>
+ <v>SnmpPduInfo = snmp_gen_info()</v>
<v>UserData = term()</v>
- <v>Reply = ignore</v>
</type>
<desc>
<p>Handle the reply to an asynchronous request, such as
@@ -186,27 +200,19 @@
<fsummary>Handle a trap/notification message</fsummary>
<type>
<v>TargetName = TargetName2 = target_name()</v>
- <v>SnmpTrapInfo = {Enteprise, Generic, Spec, Timestamp, Varbinds} | {ErrorStatus, ErrorIndex, Varbinds}</v>
- <v>Enterprise = oid()</v>
- <v>Generic = integer()</v>
- <v>Spec = integer()</v>
- <v>Timestamp = integer()</v>
- <v>ErrorStatus = atom()</v>
- <v>ErrorIndex = integer()</v>
- <v>Varbinds = [varbind()]</v>
- <v>varbind() = #varbind</v>
+ <v>SnmpTrapInfo = snmp_v1_trap_info() | snmp_gen_info()</v>
<v>UserData = term()</v>
- <v>Reply = ignore | unregister | {register, UserId, TargetName2, agent_info()}</v>
+ <v>Reply = ignore | unregister | {register, UserId, TargetName2, AgentConfig}</v>
<v>UserId = term()</v>
- <v>agent_info() = [{agent_info_item(), agent_info_value()}]</v>
+ <v>AgentConfig = [agent_config()]</v>
</type>
<desc>
<p>Handle a trap/notification message from an agent.</p>
- <p>For more info about the <c>agent_info()</c>, see
- <seealso marker="snmpm#register_agent">register_agent</seealso></p>
+ <p>For more info about the <c>agent_config()</c>, see
+ <seealso marker="snmpm#register_agent">register_agent</seealso></p>
<p>The only user which would return
- <c>{register, UserId, TargetName2, agent_info()}</c> is the
- <em>default user</em>.</p>
+ <c>{register, UserId, TargetName2, agent_info()}</c> is the
+ <em>default user</em>.</p>
<marker id="handle_inform"></marker>
</desc>
@@ -217,29 +223,25 @@
<fsummary>Handle a inform message</fsummary>
<type>
<v>TargetName = TargetName2 = target_name()</v>
- <v>SnmpInformInfo = {ErrorStatus, ErrorIndex, Varbinds}</v>
- <v>ErrorStatus = atom()</v>
- <v>ErrorIndex = integer()</v>
- <v>Varbinds = [varbind()]</v>
- <v>varbind() = #varbind</v>
+ <v>SnmpInformInfo = snmp_gen_info()</v>
<v>UserData = term()</v>
- <v>Reply = ignore | unregister | {register, UserId, TargetName2, agent_info()}</v>
+ <v>Reply = ignore | no_reply | unregister | {register, UserId, TargetName2, AgentConfig}</v>
<v>UserId = term()</v>
- <v>agent_info() = [{agent_info_item(), agent_info_value()}]</v>
+ <v>AgentConfig = [agent_config()]</v>
</type>
<desc>
<p>Handle a inform message.</p>
- <p>For more info about the <c>agent_info()</c>, see
- <seealso marker="snmpm#register_agent">register_agent</seealso></p>
+ <p>For more info about the <c>agent_config()</c>, see
+ <seealso marker="snmpm#register_agent">register_agent</seealso></p>
<p>The only user which would return
- <c>{register, UserId, TargetName2, agent_info()}</c> is the
- <em>default user</em>.</p>
- <p>If the
- <seealso marker="snmp_app">inform request behaviour</seealso>
- configuration option is set to <c>user</c> or
- <c>{user, integer()}</c>, the response (acknowledgment) to this
- inform-request will be sent when this function returns.</p>
-
+ <c>{register, UserId, TargetName2, AgentConfig}</c> is the
+ <em>default user</em>.</p>
+ <p>If the
+ <seealso marker="snmp_app">inform request behaviour</seealso>
+ configuration option is set to <c>user</c> or
+ <c>{user, integer()}</c>, the response (acknowledgment) to this
+ inform-request will be sent when this function returns.</p>
+
<marker id="handle_report"></marker>
</desc>
</func>
@@ -251,23 +253,46 @@
<v>TargetName = TargetName2 = target_name()</v>
<v>Addr = ip_address()</v>
<v>Port = integer()</v>
- <v>SnmpReportInfo = {ErrorStatus, ErrorIndex, Varbinds}</v>
- <v>ErrorStatus = atom()</v>
- <v>ErrorIndex = integer()</v>
- <v>Varbinds = [varbind()]</v>
- <v>varbind() = #varbind</v>
+ <v>SnmpReportInfo = snmp_gen_info()</v>
<v>UserData = term()</v>
- <v>Reply = ignore | unregister | {register, UserId, TargetName2, agent_info()}</v>
+ <v>Reply = ignore | unregister | {register, UserId, TargetName2, AgentConfig}</v>
<v>UserId = term()</v>
- <v>agent_info() = [{agent_info_item(), agent_info_value()}]</v>
+ <v>AgentConfig = [agent_config()]</v>
</type>
<desc>
<p>Handle a report message.</p>
- <p>For more info about the <c>agent_info()</c>, see
- <seealso marker="snmpm#register_agent">register_agent</seealso></p>
+ <p>For more info about the <c>agent_config()</c>, see
+ <seealso marker="snmpm#register_agent">register_agent</seealso></p>
<p>The only user which would return
- <c>{register, UserId, TargetName2, agent_info()}</c> is the
- <em>default user</em>.</p>
+ <c>{register, UserId, TargetName2, AgentConfig}</c> is the
+ <em>default user</em>.</p>
+
+ <marker id="handle_invalid_result"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>handle_invalid_result(IN, OUT) -> void()</name>
+ <fsummary>Handle a report message</fsummary>
+ <type>
+ <v>IN = {Func, Args}</v>
+ <v>Func = atom()</v>
+ <v>Args = list()</v>
+ <v>OUT = {crash, CrashInfo} | {result, InvalidResult}</v>
+ <v>CrashInfo = {ErrorType, Error, Stacktrace}</v>
+ <v>ErrorType = atom()</v>
+ <v>Error = term()</v>
+ <v>Stacktrace = list()</v>
+ <v>InvalidResult = term()</v>
+ </type>
+ <desc>
+ <p>If <em>any</em> of the <em>other</em> callback functions crashes
+ (exit, throw or a plain crash) or return an invalid result (if a valid
+ return has been specified), this function is called.
+ The purpose is to allow the user handle this
+ error (for instance to issue an error report).</p>
+ <p><c>IN</c> reprecents the function called (and its arguments).
+ <c>OUT</c> represents the unexpected/invalid result. </p>
</desc>
</func>
</funcs>
diff --git a/lib/snmp/examples/ex2/snmp_ex2_manager.erl b/lib/snmp/examples/ex2/snmp_ex2_manager.erl
index 1b247d713d..a9dcc09b77 100644
--- a/lib/snmp/examples/ex2/snmp_ex2_manager.erl
+++ b/lib/snmp/examples/ex2/snmp_ex2_manager.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -43,7 +43,8 @@
handle_pdu/4,
handle_trap/3,
handle_inform/3,
- handle_report/3]).
+ handle_report/3,
+ handle_invalid_result/3]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
@@ -406,5 +407,9 @@ handle_report(TargetName, SnmpReport, Server) when is_pid(Server) ->
report_callback(Server, handle_inform, {TargetName, SnmpReport}),
ok.
+handle_invalid_result(In, Out, Server) when is_pid(Server) ->
+ report_callback(Server, handle_invalid_result, {In, Out}),
+ ok.
+
report_callback(Pid, Tag, Info) ->
Pid ! {snmp_callback, Tag, Info}.
diff --git a/lib/snmp/src/agent/snmpa_local_db.erl b/lib/snmp/src/agent/snmpa_local_db.erl
index 5198c6ec4e..f991244287 100644
--- a/lib/snmp/src/agent/snmpa_local_db.erl
+++ b/lib/snmp/src/agent/snmpa_local_db.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -191,6 +191,12 @@ dets_open(DbDir, DbInitError, Opts) ->
end
end;
_ ->
+ case DbInitError of
+ create_db_and_dir ->
+ ok = filelib:ensure_dir(Filename);
+ _ ->
+ ok
+ end,
case do_dets_open(Name, Filename, Opts) of
{ok, Dets} ->
?vdebug("dets open done",[]),
diff --git a/lib/snmp/src/agent/snmpa_supervisor.erl b/lib/snmp/src/agent/snmpa_supervisor.erl
index aebcdbaa84..77ed54bee4 100644
--- a/lib/snmp/src/agent/snmpa_supervisor.erl
+++ b/lib/snmp/src/agent/snmpa_supervisor.erl
@@ -356,7 +356,7 @@ init([AgentType, Opts]) ->
SymStoreSpec =
worker_spec(snmpa_symbolic_store, SymStoreArgs, Restart, 2000),
- LdbArgs = [Prio, DbDir, LdbOpts],
+ LdbArgs = [Prio, DbDir, DbInitError, LdbOpts],
LocalDbSpec =
worker_spec(snmpa_local_db, LdbArgs, Restart, 5000),
diff --git a/lib/snmp/src/app/Makefile b/lib/snmp/src/app/Makefile
index 716add8b9e..b8cc4b8754 100644
--- a/lib/snmp/src/app/Makefile
+++ b/lib/snmp/src/app/Makefile
@@ -2,7 +2,7 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2003-2012. All Rights Reserved.
+# Copyright Ericsson AB 2003-2013. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -79,6 +79,8 @@ endif
# FLAGS
# ----------------------------------------------------
+ERL_COMPILE_FLAGS += -pa $(ERL_TOP)/lib/snmp/ebin
+
ifeq ($(WARN_UNUSED_VARS),true)
ERL_COMPILE_FLAGS += +warn_unused_vars
endif
diff --git a/lib/snmp/src/app/snmp.erl b/lib/snmp/src/app/snmp.erl
index 967afa0e08..c8d1ef28ef 100644
--- a/lib/snmp/src/app/snmp.erl
+++ b/lib/snmp/src/app/snmp.erl
@@ -92,8 +92,29 @@
-export_type([
dir/0,
-
+ snmp_timer/0,
+
+ engine_id/0,
+ tdomain/0,
+ community/0,
+ mms/0,
+ version/0,
+ sec_model/0,
+ sec_name/0,
+ sec_level/0,
+
oid/0,
+ varbind/0,
+ ivarbind/0,
+ asn1_type/0,
+ table_info/0,
+ variable_info/0,
+ me/0,
+ trap/0,
+ notification/0,
+ pdu/0,
+ trappdu/0,
+ mib/0,
mib_name/0,
void/0
@@ -152,16 +173,40 @@
-define(APPLICATION, snmp).
+-include_lib("snmp/include/snmp_types.hrl").
%%-----------------------------------------------------------------
%% Types
%%-----------------------------------------------------------------
--type oid() :: [non_neg_integer()].
--type void() :: term().
--type dir() :: string().
--type mib_name() :: string().
+-type dir() :: string().
+-type snmp_timer() :: #snmp_incr_timer{}.
+
+-type engine_id() :: string().
+-type tdomain() :: transportDomainUdpIpv4 | transportDomainUdpIpv6.
+-type community() :: string().
+-type mms() :: non_neg_integer().
+-type version() :: v1 | v2 | v3.
+-type sec_model() :: any | v1 | v2c | usm.
+-type sec_name() :: string().
+-type sec_level() :: noAuthNoPriv | authNoPriv | authPriv.
+
+-type oid() :: [non_neg_integer()].
+-type varbind() :: #varbind{}.
+-type ivarbind() :: #ivarbind{}.
+-type asn1_type() :: #asn1_type{}.
+-type table_info() :: #table_info{}.
+-type variable_info() :: #variable_info{}.
+-type me() :: #me{}.
+-type trap() :: #trap{}.
+-type notification() :: #notification{}.
+-type mib() :: #mib{}.
+-type mib_name() :: string().
+-type pdu() :: #pdu{}.
+-type trappdu() :: #trappdu{}.
+
+-type void() :: term().
%%-----------------------------------------------------------------
diff --git a/lib/snmp/src/app/snmp_internal.hrl b/lib/snmp/src/app/snmp_internal.hrl
index 5ff715e0b7..f04fa4dd53 100644
--- a/lib/snmp/src/app/snmp_internal.hrl
+++ b/lib/snmp/src/app/snmp_internal.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -24,6 +24,8 @@
-define(APPLICATION, snmp).
-endif.
+-define(STACK(), erlang:get_stacktrace()).
+
-define(snmp_info(C, F, A), ?snmp_msg(info_msg, C, F, A)).
-define(snmp_warning(C, F, A), ?snmp_msg(warning_msg, C, F, A)).
-define(snmp_error(C, F, A), ?snmp_msg(error_msg, C, F, A)).
diff --git a/lib/snmp/src/manager/snmpm.erl b/lib/snmp/src/manager/snmpm.erl
index a749153ece..a62379de97 100644
--- a/lib/snmp/src/manager/snmpm.erl
+++ b/lib/snmp/src/manager/snmpm.erl
@@ -110,6 +110,12 @@
-export([start_link/3, snmpm_start_verify/2, snmpm_start_verify/3]).
-export([target_name/1, target_name/2]).
+-export_type([
+ register_timeout/0,
+ agent_config/0,
+ target_name/0
+ ]).
+
-include_lib("snmp/src/misc/snmp_debug.hrl").
-include_lib("snmp/include/snmp_types.hrl").
@@ -120,6 +126,25 @@
-define(DEFAULT_AGENT_PORT, 161).
+%%-----------------------------------------------------------------
+%% Types
+%%-----------------------------------------------------------------
+
+-type register_timeout() :: pos_integer() | snmp:snmp_timer().
+-type agent_config() :: {engine_id, snmp:engine_id()} | % Mandatory
+ {address, inet:ip_address()} | % Mandatory
+ {port, inet:port_number()} | % Optional
+ {tdomain, snmp:tdomain()} | % Optional
+ {community, snmp:community()} | % Optional
+ {timeout, register_timeout()} | % Optional
+ {max_message_size, snmp:mms()} | % Optional
+ {version, snmp:version()} | % Optional
+ {sec_moduel, snmp:sec_model()} | % Optional
+ {sec_name, snmp:sec_name()} | % Optional
+ {sec_level, snmp:sec_level()}. % Optional
+-type target_name() :: string().
+
+
%% This function is called when the snmp application
%% starts.
start_link(Opts, normal, []) ->
diff --git a/lib/snmp/src/manager/snmpm_config.erl b/lib/snmp/src/manager/snmpm_config.erl
index 736debe544..2101ad46e1 100644
--- a/lib/snmp/src/manager/snmpm_config.erl
+++ b/lib/snmp/src/manager/snmpm_config.erl
@@ -1215,6 +1215,12 @@ dets_open(Dir, DbInitError, Repair, AutoSave) ->
end
end;
_ ->
+ case DbInitError of
+ create_db_and_dir ->
+ ok = filelib:ensure_dir(Filename);
+ _ ->
+ ok
+ end,
case do_dets_open(Name, Filename, Repair, AutoSave) of
{ok, _Dets} ->
ok;
@@ -1316,7 +1322,14 @@ verify_option({server, ServerOpts}) ->
verify_server_opts(ServerOpts);
verify_option({note_store, NoteStoreOpts}) ->
verify_note_store_opts(NoteStoreOpts);
-verify_option({config, ConfOpts}) ->
+verify_option({config, ConfOpts0}) ->
+ %% Make sure any db_dir option is first in the options list to make it
+ %% easier to check if the db_init_error option specifies that a missing
+ %% db_dir should be created.
+ ConfOpts = case lists:keytake(db_dir, 1, ConfOpts0) of
+ false -> ConfOpts0;
+ {value, Result, OtherOpts} -> [Result|OtherOpts]
+ end,
verify_config_opts(ConfOpts);
verify_option({versions, Vsns}) ->
verify_versions(Vsns);
@@ -1365,7 +1378,12 @@ verify_config_opts([{dir, Dir}|Opts]) ->
verify_conf_dir(Dir),
verify_config_opts(Opts);
verify_config_opts([{db_dir, Dir}|Opts]) ->
- verify_conf_db_dir(Dir),
+ case lists:keyfind(db_init_error, 1, Opts) of
+ {db_init_error, create_db_and_dir} ->
+ verify_conf_db_dir(Dir, false);
+ _ ->
+ verify_conf_db_dir(Dir, true)
+ end,
verify_config_opts(Opts);
verify_config_opts([{db_init_error, DbInitErr}|Opts]) ->
verify_conf_db_init_error(DbInitErr),
@@ -1443,7 +1461,7 @@ verify_conf_dir(Dir) ->
error({invalid_conf_dir, Dir})
end.
-verify_conf_db_dir(Dir) ->
+verify_conf_db_dir(Dir, true) ->
case (catch verify_dir(Dir)) of
ok ->
ok;
@@ -1451,13 +1469,16 @@ verify_conf_db_dir(Dir) ->
error({invalid_conf_db_dir, Dir, Reason});
_ ->
error({invalid_conf_db_dir, Dir})
- end.
-
+ end;
+verify_conf_db_dir(_Dir, false) ->
+ ok.
verify_conf_db_init_error(terminate) ->
ok;
verify_conf_db_init_error(create) ->
ok;
+verify_conf_db_init_error(create_db_and_dir) ->
+ ok;
verify_conf_db_init_error(InvalidDbInitError) ->
error({invalid_conf_db_init_error, InvalidDbInitError}).
diff --git a/lib/snmp/src/manager/snmpm_server.erl b/lib/snmp/src/manager/snmpm_server.erl
index 61d22362cc..9c79df2748 100644
--- a/lib/snmp/src/manager/snmpm_server.erl
+++ b/lib/snmp/src/manager/snmpm_server.erl
@@ -488,7 +488,7 @@ cancel_async_request(UserId, ReqId) ->
%% discovery(UserId, BAddr, Port, Config, Expire, ExtraInfo) ->
%% call({discovery, self(), UserId, BAddr, Port, Config, Expire, ExtraInfo}).
-
+
verbosity(Verbosity) ->
case ?vvalidate(Verbosity) of
Verbosity ->
@@ -1851,7 +1851,17 @@ handle_snmp_error(Addr, Port, ReqId, Reason, State) ->
handle_error(_UserId, Mod, Reason, ReqId, Data, _State) ->
?vtrace("handle_error -> entry when"
"~n Mod: ~p", [Mod]),
- F = fun() -> (catch Mod:handle_error(ReqId, Reason, Data)) end,
+ F = fun() ->
+ try
+ begin
+ Mod:handle_error(ReqId, Reason, Data)
+ end
+ catch
+ T:E ->
+ CallbackArgs = [ReqId, Reason, Data],
+ handle_invalid_result(handle_error, CallbackArgs, T, E)
+ end
+ end,
handle_callback(F),
ok.
@@ -2031,7 +2041,15 @@ handle_pdu(_UserId, Mod, target_name = _RegType, TargetName, _Addr, _Port,
?vtrace("handle_pdu(target_name) -> entry when"
"~n Mod: ~p", [Mod]),
F = fun() ->
- (catch Mod:handle_pdu(TargetName, ReqId, SnmpResponse, Data))
+ try
+ begin
+ Mod:handle_pdu(TargetName, ReqId, SnmpResponse, Data)
+ end
+ catch
+ T:E ->
+ CallbackArgs = [TargetName, ReqId, SnmpResponse, Data],
+ handle_invalid_result(handle_pdu, CallbackArgs, T, E)
+ end
end,
handle_callback(F),
ok;
@@ -2064,8 +2082,37 @@ do_handle_agent(DefUserId, DefMod,
SnmpInfo, DefData, State) ->
?vdebug("do_handle_agent -> entry when"
"~n DefUserId: ~p", [DefUserId]),
- case (catch DefMod:handle_agent(Addr, Port, Type, SnmpInfo, DefData)) of
- {'EXIT', {undef, _}} when Type =:= pdu ->
+ try DefMod:handle_agent(Addr, Port, Type, SnmpInfo, DefData) of
+ {register, UserId2, TargetName, Config} ->
+ ?vtrace("do_handle_agent -> register: "
+ "~n UserId2: ~p"
+ "~n TargetName: ~p"
+ "~n Config: ~p",
+ [UserId2, TargetName, Config]),
+ Config2 = ensure_present([{address, Addr}, {port, Port}], Config),
+ Config3 = [{reg_type, target_name} | Config2],
+ case snmpm_config:register_agent(UserId2,
+ TargetName, Config3) of
+ ok ->
+ ok;
+ {error, Reason} ->
+ error_msg("failed registering agent - "
+ "handling agent "
+ "~p <~p,~p>: ~n~w",
+ [TargetName, Addr, Port, Reason]),
+ ok
+ end;
+
+ ignore ->
+ ?vdebug("do_handle_agent -> ignore", []),
+ ok;
+
+ InvalidResult ->
+ CallbackArgs = [Addr, Port, Type, SnmpInfo, DefData],
+ handle_invalid_result(handle_agent, CallbackArgs, InvalidResult)
+
+ catch
+ error:{undef, _} when Type =:= pdu ->
%% Maybe, still on the old API
?vdebug("do_handle_agent -> maybe still on the old api", []),
case (catch DefMod:handle_agent(Addr, Port, SnmpInfo, DefData)) of
@@ -2113,10 +2160,10 @@ do_handle_agent(DefUserId, DefMod,
ok
end;
- {'EXIT', {undef, _}} ->
+ error:{undef, _} ->
%% If the user does not implement the new API (but the
%% old), then this clause catches all non-pdu handle_agent
- %% calls. These calls was previously never made,so we make
+ %% calls. These calls was previously never made, so we make
%% a best-effert call (using reg-type target_name) to the
%% various callback functions, and leave it to the user to
%% figure out
@@ -2148,31 +2195,11 @@ do_handle_agent(DefUserId, DefMod,
"regarding agent "
"<~p,~p>: ~n~w", [Type, Addr, Port, SnmpInfo])
end;
-
- {register, UserId2, TargetName, Config} ->
- ?vtrace("do_handle_agent -> register: "
- "~n UserId2: ~p"
- "~n TargetName: ~p"
- "~n Config: ~p",
- [UserId2, TargetName, Config]),
- Config2 = ensure_present([{address, Addr}, {port, Port}], Config),
- Config3 = [{reg_type, target_name} | Config2],
- case snmpm_config:register_agent(UserId2,
- TargetName, Config3) of
- ok ->
- ok;
- {error, Reason} ->
- error_msg("failed registering agent - "
- "handling agent "
- "~p <~p,~p>: ~n~w",
- [TargetName, Addr, Port, Reason]),
- ok
- end;
- _Ignore ->
- ?vdebug("do_handle_agent -> ignore", []),
- ok
-
+ T:E ->
+ CallbackArgs = [Addr, Port, Type, SnmpInfo, DefData],
+ handle_invalid_result(handle_agent, CallbackArgs, T, E)
+
end.
ensure_present([], Config) ->
@@ -2305,15 +2332,17 @@ do_handle_trap(UserId, Mod,
RegType, Target, Addr, Port, SnmpTrapInfo, Data, _State) ->
?vdebug("do_handle_trap -> entry with"
"~n UserId: ~p", [UserId]),
- HandleTrap =
+ {HandleTrap, CallbackArgs} =
case RegType of
target_name ->
- fun() -> Mod:handle_trap(Target, SnmpTrapInfo, Data) end;
+ {fun() -> Mod:handle_trap(Target, SnmpTrapInfo, Data) end,
+ [Target, SnmpTrapInfo, Data]};
addr_port ->
- fun() -> Mod:handle_trap(Addr, Port, SnmpTrapInfo, Data) end
+ {fun() -> Mod:handle_trap(Addr, Port, SnmpTrapInfo, Data) end,
+ [Addr, Port, SnmpTrapInfo, Data]}
end,
- case (catch HandleTrap()) of
+ try HandleTrap() of
{register, UserId2, Config} ->
?vtrace("do_handle_trap -> register: "
"~n UserId2: ~p"
@@ -2362,9 +2391,17 @@ do_handle_trap(UserId, Mod,
[Addr, Port, Reason]),
ok
end;
- _Ignore ->
+ ignore ->
?vtrace("do_handle_trap -> ignore", []),
- ok
+ ok;
+
+ InvalidResult ->
+ handle_invalid_result(handle_trap, CallbackArgs, InvalidResult)
+
+ catch
+ T:E ->
+ handle_invalid_result(handle_trap, CallbackArgs, T, E)
+
end.
@@ -2465,16 +2502,18 @@ do_handle_inform(UserId, Mod, Ref,
RegType, Target, Addr, Port, SnmpInform, Data, State) ->
?vdebug("do_handle_inform -> entry with"
"~n UserId: ~p", [UserId]),
- HandleInform =
+ {HandleInform, CallbackArgs} =
case RegType of
target_name ->
- fun() -> Mod:handle_inform(Target, SnmpInform, Data) end;
+ {fun() -> Mod:handle_inform(Target, SnmpInform, Data) end,
+ [Target, SnmpInform, Data]};
addr_port ->
- fun() -> Mod:handle_inform(Addr, Port, SnmpInform, Data) end
+ {fun() -> Mod:handle_inform(Addr, Port, SnmpInform, Data) end,
+ [Addr, Port, SnmpInform, Data]}
end,
Rep =
- case (catch HandleInform()) of
+ try HandleInform() of
{register, UserId2, Config} ->
?vtrace("do_handle_inform -> register: "
"~n UserId2: ~p"
@@ -2494,6 +2533,7 @@ do_handle_inform(UserId, Mod, Ref,
[Target2, Addr, Port, Reason]),
reply
end;
+
{register, UserId2, Target2, Config} ->
?vtrace("do_handle_inform -> register: "
"~n UserId2: ~p"
@@ -2512,6 +2552,7 @@ do_handle_inform(UserId, Mod, Ref,
[Target2, Addr, Port, Reason]),
reply
end;
+
unregister ->
?vtrace("do_handle_inform -> unregister", []),
case snmpm_config:unregister_agent(UserId,
@@ -2525,12 +2566,25 @@ do_handle_inform(UserId, Mod, Ref,
[Addr, Port, Reason]),
reply
end;
+
no_reply ->
?vtrace("do_handle_inform -> no_reply", []),
no_reply;
- _Ignore ->
+
+ ignore ->
?vtrace("do_handle_inform -> ignore", []),
+ reply;
+
+ InvalidResult ->
+ handle_invalid_result(handle_inform, CallbackArgs,
+ InvalidResult),
reply
+
+ catch
+ T:E ->
+ handle_invalid_result(handle_inform, CallbackArgs, T, E),
+ reply
+
end,
handle_inform_response(Rep, Ref, Addr, Port, State),
ok.
@@ -2760,15 +2814,17 @@ do_handle_report(UserId, Mod,
RegType, Target, Addr, Port, SnmpReport, Data, _State) ->
?vdebug("do_handle_report -> entry with"
"~n UserId: ~p", [UserId]),
- HandleReport =
+ {HandleReport, CallbackArgs} =
case RegType of
target_name ->
- fun() -> Mod:handle_report(Target, SnmpReport, Data) end;
+ {fun() -> Mod:handle_report(Target, SnmpReport, Data) end,
+ [Target, SnmpReport, Data]};
addr_port ->
- fun() -> Mod:handle_report(Addr, Port, SnmpReport, Data) end
+ {fun() -> Mod:handle_report(Addr, Port, SnmpReport, Data) end,
+ [Addr, Port, SnmpReport, Data]}
end,
- case (catch HandleReport()) of
+ try HandleReport() of
{register, UserId2, Config} ->
?vtrace("do_handle_report -> register: "
"~n UserId2: ~p"
@@ -2788,6 +2844,7 @@ do_handle_report(UserId, Mod,
[Addr, Port, Reason]),
ok
end;
+
{register, UserId2, Target2, Config} ->
?vtrace("do_handle_report -> register: "
"~n UserId2: ~p"
@@ -2806,6 +2863,7 @@ do_handle_report(UserId, Mod,
[Target2, Addr, Port, Reason]),
reply
end;
+
unregister ->
?vtrace("do_handle_trap -> unregister", []),
case snmpm_config:unregister_agent(UserId,
@@ -2819,9 +2877,20 @@ do_handle_report(UserId, Mod,
[Addr, Port, Reason]),
ok
end;
- _Ignore ->
+
+ ignore ->
?vtrace("do_handle_report -> ignore", []),
- ok
+ ok;
+
+ InvalidResult ->
+ handle_invalid_result(handle_report, CallbackArgs, InvalidResult),
+ reply
+
+ catch
+ T:E ->
+ handle_invalid_result(handle_report, CallbackArgs, T, E),
+ reply
+
end.
@@ -2835,6 +2904,25 @@ handle_callback(F) ->
end).
+
+handle_invalid_result(Func, Args, T, E) ->
+ Stacktrace = ?STACK(),
+ error_msg("Callback function failed: "
+ "~n Function: ~p"
+ "~n Args: ~p"
+ "~n Error Type: ~p"
+ "~n Error: ~p"
+ "~n Stacktrace: ~p",
+ [Func, Args, T, E, Stacktrace]).
+
+handle_invalid_result(Func, Args, InvalidResult) ->
+ error_msg("Callback function returned invalid result: "
+ "~n Function: ~p"
+ "~n Args: ~p"
+ "~n Invalid result: ~p",
+ [Func, Args, InvalidResult]).
+
+
handle_down(MonRef) ->
(catch do_handle_down(MonRef)).
diff --git a/lib/snmp/src/manager/snmpm_user.erl b/lib/snmp/src/manager/snmpm_user.erl
index 78aa560b2e..e6b0b6943e 100644
--- a/lib/snmp/src/manager/snmpm_user.erl
+++ b/lib/snmp/src/manager/snmpm_user.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -19,79 +19,100 @@
-module(snmpm_user).
--export([behaviour_info/1]).
-
-behaviour_info(callbacks) ->
- [{handle_error, 3},
- {handle_agent, 5},
- {handle_pdu, 4},
- {handle_trap, 3},
- {handle_inform, 3},
- {handle_report, 3}];
-behaviour_info(_) ->
- undefined.
-
-
-%% handle_error(ReqId, Reason, UserData) -> Reply
-%% ReqId -> integer()
-%% Reason -> term()
-%% UserData -> term() (supplied when the user register)
-%% Reply -> ignore
-
-%% handle_agent(Addr, Port, Type, SnmpInfo, UserData) -> Reply
-%% Addr -> term()
-%% Port -> integer()
-%% Type -> pdu | trap | inform | report
-%% SnmpInfo -> {ErrorStatus, ErrorIndex, Varbinds}
-%% UserId -> term()
-%% ErrorStatus -> atom()
-%% ErrorIndex -> integer()
-%% Varbinds -> [varbind()]
-%% UserData -> term() (supplied when the user register)
-%% Reply -> ignore | {register, UserId, agent_info()}
-%% agent_info() -> [{agent_info_item(), agent_info_value()}]
-%% This is the same info as in update_agent_info/4
-
-%% handle_pdu(TargetName, ReqId, SnmpResponse, UserData) -> Reply
-%% TargetName -> target_name()
-%% ReqId -> term() (returned when calling ag(...), ...)
-%% SnmpResponse -> {ErrorStatus, ErrorIndex, Varbinds}
-%% ErrorStatus -> atom()
-%% ErrorIndex -> integer()
-%% Varbinds -> [varbind()]
-%% UserData -> term() (supplied when the user register)
-%% Reply -> ignore
-
-%% handle_trap(TargetName, SnmpTrapInfo, UserData) -> Reply
-%% TargetName -> target_name()
-%% SnmpTrapInfo -> {Enteprise, Generic, Spec, Timestamp, Varbinds} |
-%% {ErrorStatus, ErrorIndex, Varbinds}
-%% Enteprise -> oid()
-%% Generic -> integer()
-%% Spec -> integer()
-%% Timestamp -> integer()
-%% ErrorStatus -> atom()
-%% ErrorIndex -> integer()
-%% Varbinds -> [varbind()]
-%% UserData -> term() (supplied when the user register)
-%% Reply -> ignore | unregister | {register, UserId, agent_info()}
-
-%% handle_inform(TargetName, SnmpInform, UserData) -> Reply
-%% TargetName -> target_name()
-%% SnmpInform -> {ErrorStatus, ErrorIndex, Varbinds}
-%% ErrorStatus -> atom()
-%% ErrorIndex -> integer()
-%% Varbinds -> [varbind()]
-%% UserData -> term() (supplied when the user register)
-%% Reply -> ignore | unregister | {register, UserId, agent_info()}
-%%
-
-%% handle_report(TargetName, SnmpReport, UserData) -> Reply
-%% TargetName -> target_name()
-%% SnmpReport -> {ErrorStatus, ErrorIndex, Varbinds}
-%% ErrorStatus -> integer()
-%% ErrorIndex -> integer()
-%% Varbinds -> [varbind()]
-%% UserData -> term() (supplied when the user register)
-%% Reply -> ignore | unregister | {register, UserId, agent_info()}
+-export_type([
+ snmp_gen_info/0,
+ snmp_v1_trap_info/0
+ ]).
+
+-type snmp_gen_info() :: {ErrorStatus :: atom(),
+ ErrorIndex :: pos_integer(),
+ Varbinds :: [snmp:varbind()]}.
+-type snmp_v1_trap_info() :: {Enteprise :: snmp:oid(),
+ Generic :: integer(),
+ Spec :: integer(),
+ Timestamp :: integer(),
+ Varbinds :: [snmp:varbind()]}.
+-type ip_address() :: inet:ip_address().
+-type port_number() :: inet:port_number().
+
+
+%% *** handle_error ***
+%% An "asynchronous" error has been detected
+
+-callback handle_error(ReqId :: integer(),
+ Reason :: {unexpected_pdu, SnmpInfo :: snmp_gen_info()} |
+ {invalid_sec_info, SecInfo :: term(), SnmpInfo :: snmp_gen_info()} |
+ {empty_message, Addr :: ip_address(), Port :: port_number()} |
+ term(),
+ UserData :: term()) ->
+ snmp:void().
+
+
+%% *** handle_agent ***
+%% A message was received from an unknown agent
+
+-callback handle_agent(Addr :: term(),
+ Port :: pos_integer(),
+ Type :: pdu | trap | inform | report,
+ SnmpInfo :: snmp_gen_info() | snmp_v1_trap_info(),
+ UserData :: term()) ->
+ Reply :: ignore |
+ {register,
+ UserId :: term(),
+ RTargetName :: snmpm:target_name(),
+ AgentConfig :: [snmpm:agent_config()]}.
+
+
+%% *** handle_pdu ***
+%% Handle the reply to an async request (such as get, get-next and set).
+
+-callback handle_pdu(TargetName :: snmpm:target_name(),
+ ReqId :: term(),
+ SnmpResponse :: snmp_gen_info(),
+ UserData :: term()) ->
+ snmp:void().
+
+
+%% *** handle_trap ***
+%% Handle a trap/notification message received from an agent
+
+-callback handle_trap(TargetName :: snmpm:target_name(),
+ SnmpTrapInfo :: snmp_gen_info() | snmp_v1_trap_info(),
+ UserData :: term()) ->
+ Reply :: ignore |
+ unregister |
+ {register,
+ UserId :: term(),
+ RTargetName :: snmpm:target_name(),
+ AgentConfig :: [snmpm:agent_config()]}.
+
+
+%% *** handle_inform ***
+%% Handle a inform message received from an agent
+
+-callback handle_inform(TargetName :: snmpm:target_name(),
+ SnmpInform :: snmp_gen_info(),
+ UserData :: term()) ->
+ Reply :: ignore | no_reply |
+ unregister |
+ {register,
+ UserId :: term(),
+ RTargetName :: snmpm:target_name(),
+ AgentConfig :: [snmpm:agent_config()]}.
+
+
+%% *** handle_report ***
+%% Handle a report message received from an agent
+
+-callback handle_report(TargetName :: snmpm:target_name(),
+ SnmpReport :: snmp_gen_info(),
+ UserData :: term()) ->
+ Reply :: ignore |
+ unregister |
+ {register,
+ UserId :: term(),
+ RTargetName :: snmpm:target_name(),
+ AgentConfig :: [snmpm:agent_config()]}.
+
+
diff --git a/lib/snmp/src/misc/snmp_config.erl b/lib/snmp/src/misc/snmp_config.erl
index 945b8719fc..a222f842e5 100644
--- a/lib/snmp/src/misc/snmp_config.erl
+++ b/lib/snmp/src/misc/snmp_config.erl
@@ -233,16 +233,18 @@ config_agent_sys() ->
fun verify_verbosity/1),
DbDir = ask("5. Database directory (absolute path)?", DefDir,
fun verify_dir/1),
- MibStorageType = ask("6. Mib storage type (ets/dets/mnesia)?", "ets",
+ DbInitError = ask("6. How to handle DB init error?",
+ "terminate", fun verify_db_init_error/1),
+ MibStorageType = ask("7. Mib storage type (ets/dets/mnesia)?", "ets",
fun verify_mib_storage_type/1),
MibStorage =
case MibStorageType of
ets ->
[{module, snmpa_mib_storage_ets}];
dets ->
- DetsDir = ask("6b. Mib storage directory (absolute path)?",
+ DetsDir = ask("7b. Mib storage directory (absolute path)?",
DbDir, fun verify_dir/1),
- DetsAction = ask("6c. Mib storage [dets] database start "
+ DetsAction = ask("7c. Mib storage [dets] database start "
"action "
"(default/clear/keep)?",
"default", fun verify_mib_storage_action/1),
@@ -257,7 +259,7 @@ config_agent_sys() ->
end;
mnesia ->
Nodes = [],
- MnesiaAction = ask("6b. Mib storage [mnesia] database start "
+ MnesiaAction = ask("7b. Mib storage [mnesia] database start "
"action "
"(default/clear/keep)?",
"default", fun verify_mib_storage_action/1),
@@ -275,80 +277,80 @@ config_agent_sys() ->
%% Here we should ask about mib-server data module,
%% but as we only have one at the moment...
- TargetCacheVerb = ask("7. Target cache verbosity "
+ TargetCacheVerb = ask("8. Target cache verbosity "
"(silence/info/log/debug/trace)?", "silence",
fun verify_verbosity/1),
- SymStoreVerb = ask("8. Symbolic store verbosity "
+ SymStoreVerb = ask("9. Symbolic store verbosity "
"(silence/info/log/debug/trace)?", "silence",
fun verify_verbosity/1),
- LocalDbVerb = ask("9. Local DB verbosity "
+ LocalDbVerb = ask("10. Local DB verbosity "
"(silence/info/log/debug/trace)?", "silence",
fun verify_verbosity/1),
- LocalDbRepair = ask("10. Local DB repair (true/false/force)?", "true",
+ LocalDbRepair = ask("11. Local DB repair (true/false/force)?", "true",
fun verify_dets_repair/1),
- LocalDbAutoSave = ask("11. Local DB auto save (infinity/milli seconds)?",
+ LocalDbAutoSave = ask("12. Local DB auto save (infinity/milli seconds)?",
"5000", fun verify_dets_auto_save/1),
- ErrorMod = ask("12. Error report module?", "snmpa_error_logger", fun verify_module/1),
- Type = ask("13. Agent type (master/sub)?", "master",
+ ErrorMod = ask("13. Error report module?", "snmpa_error_logger", fun verify_module/1),
+ Type = ask("14. Agent type (master/sub)?", "master",
fun verify_agent_type/1),
AgentConfig =
case Type of
master ->
- MasterAgentVerb = ask("14. Master-agent verbosity "
+ MasterAgentVerb = ask("15. Master-agent verbosity "
"(silence/info/log/debug/trace)?",
"silence",
fun verify_verbosity/1),
- ForceLoad = ask("15. Shall the agent re-read the "
+ ForceLoad = ask("16. Shall the agent re-read the "
"configuration files during startup ~n"
" (and ignore the configuration "
"database) (true/false)?", "true",
fun verify_bool/1),
- MultiThreaded = ask("16. Multi threaded agent (true/false)?",
+ MultiThreaded = ask("17. Multi threaded agent (true/false)?",
"false",
fun verify_bool/1),
- MeOverride = ask("17. Check for duplicate mib entries when "
+ MeOverride = ask("18. Check for duplicate mib entries when "
"installing a mib (true/false)?", "false",
fun verify_bool/1),
- TrapOverride = ask("18. Check for duplicate trap names when "
+ TrapOverride = ask("19. Check for duplicate trap names when "
"installing a mib (true/false)?", "false",
fun verify_bool/1),
- MibServerVerb = ask("19. Mib server verbosity "
+ MibServerVerb = ask("20. Mib server verbosity "
"(silence/info/log/debug/trace)?",
"silence",
fun verify_verbosity/1),
- MibServerCache = ask("20. Mib server cache "
+ MibServerCache = ask("21. Mib server cache "
"(true/false)?",
"true",
fun verify_bool/1),
- NoteStoreVerb = ask("21. Note store verbosity "
+ NoteStoreVerb = ask("22. Note store verbosity "
"(silence/info/log/debug/trace)?",
"silence",
fun verify_verbosity/1),
- NoteStoreTimeout = ask("22. Note store GC timeout?", "30000",
+ NoteStoreTimeout = ask("23. Note store GC timeout?", "30000",
fun verify_timeout/1),
ATL =
- case ask("23. Shall the agent use an audit trail log "
+ case ask("24. Shall the agent use an audit trail log "
"(y/n)?",
"n", fun verify_yes_or_no/1) of
yes ->
- ATLType = ask("23b. Audit trail log type "
+ ATLType = ask("24b. Audit trail log type "
"(write/read_write)?",
"read_write", fun verify_atl_type/1),
- ATLDir = ask("23c. Where to store the "
+ ATLDir = ask("24c. Where to store the "
"audit trail log?",
DefDir, fun verify_dir/1),
- ATLMaxFiles = ask("23d. Max number of files?",
+ ATLMaxFiles = ask("24d. Max number of files?",
"10",
fun verify_pos_integer/1),
- ATLMaxBytes = ask("23e. Max size (in bytes) "
+ ATLMaxBytes = ask("24e. Max size (in bytes) "
"of each file?",
"10240",
fun verify_pos_integer/1),
ATLSize = {ATLMaxBytes, ATLMaxFiles},
- ATLRepair = ask("23f. Audit trail log repair "
+ ATLRepair = ask("24f. Audit trail log repair "
"(true/false/truncate/snmp_repair)?", "true",
fun verify_atl_repair/1),
- ATLSeqNo = ask("23g. Audit trail log "
+ ATLSeqNo = ask("24g. Audit trail log "
"sequence-numbering (true/false)?",
"false",
fun verify_atl_seqno/1),
@@ -360,33 +362,33 @@ config_agent_sys() ->
no ->
[]
end,
- NetIfVerb = ask("24. Network interface verbosity "
+ NetIfVerb = ask("25. Network interface verbosity "
"(silence/info/log/debug/trace)?",
"silence",
fun verify_verbosity/1),
- NetIfMod = ask("25. Which network interface module shall be used?",
+ NetIfMod = ask("26. Which network interface module shall be used?",
"snmpa_net_if", fun verify_module/1),
NetIfOpts =
case NetIfMod of
snmpa_net_if ->
NetIfBindTo =
- ask("25a. Bind the agent IP address "
+ ask("26a. Bind the agent IP address "
"(true/false)?",
"false", fun verify_bool/1),
NetIfNoReuse =
- ask("25b. Shall the agents "
+ ask("26b. Shall the agents "
"IP address "
"and port be not reusable "
"(true/false)?",
"false", fun verify_bool/1),
NetIfReqLimit =
- ask("25c. Agent request limit "
+ ask("26c. Agent request limit "
"(used for flow control) "
"(infinity/pos integer)?",
"infinity",
fun verify_netif_req_limit/1),
NetIfRecbuf =
- case ask("25d. Receive buffer size of the "
+ case ask("26d. Receive buffer size of the "
"agent (in bytes) "
"(default/pos integer)?",
"default",
@@ -397,7 +399,7 @@ config_agent_sys() ->
[{recbuf, RecBufSz}]
end,
NetIfSndbuf =
- case ask("25e. Send buffer size of the agent "
+ case ask("26e. Send buffer size of the agent "
"(in bytes) (default/pos integer)?",
"default",
fun verify_netif_sndbuf/1) of
@@ -407,7 +409,7 @@ config_agent_sys() ->
[{sndbuf, SndBufSz}]
end,
NetIfFilter =
- case ask("25f. Do you wish to specify a "
+ case ask("26f. Do you wish to specify a "
"network interface filter module "
"(or use default)",
"default", fun verify_module/1) of
@@ -426,18 +428,18 @@ config_agent_sys() ->
NetIf = [{module, NetIfMod},
{verbosity, NetIfVerb},
{options, NetIfOpts}],
- TermDiscoEnable = ask("26a. Allow terminating discovery "
+ TermDiscoEnable = ask("27. Allow terminating discovery "
"(true/false)?", "true",
fun verify_bool/1),
TermDiscoConf =
case TermDiscoEnable of
true ->
TermDiscoStage2 =
- ask("26b. Second stage behaviour "
+ ask("27a. Second stage behaviour "
"(discovery/plain)?", "discovery",
fun verify_term_disco_behaviour/1),
TermDiscoTrigger =
- ask("26c. Trigger username "
+ ask("27b. Trigger username "
"(default/a string)?", "default",
fun verify_term_disco_trigger_username/1),
[{enable, TermDiscoEnable},
@@ -448,7 +450,7 @@ config_agent_sys() ->
{stage2, discovery},
{trigger_username, ""}]
end,
- OrigDiscoEnable = ask("27a. Allow originating discovery "
+ OrigDiscoEnable = ask("28. Allow originating discovery "
"(true/false)?", "true",
fun verify_bool/1),
OrigDiscoConf =
@@ -471,7 +473,7 @@ config_agent_sys() ->
{verbosity, NoteStoreVerb}]},
{net_if, NetIf}] ++ ATL;
sub ->
- SubAgentVerb = ask("14. Sub-agent verbosity "
+ SubAgentVerb = ask("15. Sub-agent verbosity "
"(silence/info/log/debug/trace)?",
"silence",
fun verify_verbosity/1),
@@ -480,11 +482,12 @@ config_agent_sys() ->
{config, [{dir, ConfigDir}]}]
end,
SysConfig =
- [{priority, Prio},
- {versions, Vsns},
- {db_dir, DbDir},
- {mib_storage, MibStorage},
- {target_cache, [{verbosity, TargetCacheVerb}]},
+ [{priority, Prio},
+ {versions, Vsns},
+ {db_dir, DbDir},
+ {db_init_error, DbInitError},
+ {mib_storage, MibStorage},
+ {target_cache, [{verbosity, TargetCacheVerb}]},
{symbolic_store, [{verbosity, SymStoreVerb}]},
{local_db, [{repair, LocalDbRepair},
{auto_save, LocalDbAutoSave},
@@ -630,19 +633,21 @@ config_manager_sys() ->
fun verify_verbosity/1),
ConfigDbDir = ask("5. Database directory (absolute path)?",
DefDir, fun verify_dir/1),
- ConfigDbRepair = ask("6. Database repair "
+ ConfigDbInitError = ask("6. How to handle DB init error?",
+ "terminate", fun verify_db_init_error/1),
+ ConfigDbRepair = ask("7. Database repair "
"(true/false/force)?", "true",
fun verify_dets_repair/1),
- ConfigDbAutoSave = ask("7. Database auto save "
+ ConfigDbAutoSave = ask("8. Database auto save "
"(infinity/milli seconds)?",
"5000", fun verify_dets_auto_save/1),
IRB =
- case ask("8. Inform request behaviour (auto/user)?",
+ case ask("9. Inform request behaviour (auto/user)?",
"auto", fun verify_irb/1) of
auto ->
auto;
user ->
- case ask("8b. Use default GC timeout"
+ case ask("9b. Use default GC timeout"
"(default/seconds)?",
"default", fun verify_irb_user/1) of
default ->
@@ -651,31 +656,31 @@ config_manager_sys() ->
{user, IrbGcTo}
end
end,
- ServerVerb = ask("9. Server verbosity "
+ ServerVerb = ask("10. Server verbosity "
"(silence/info/log/debug/trace)?",
"silence",
fun verify_verbosity/1),
- ServerTimeout = ask("10. Server GC timeout?", "30000",
+ ServerTimeout = ask("11. Server GC timeout?", "30000",
fun verify_timeout/1),
- NoteStoreVerb = ask("11. Note store verbosity "
+ NoteStoreVerb = ask("12. Note store verbosity "
"(silence/info/log/debug/trace)?",
"silence",
fun verify_verbosity/1),
- NoteStoreTimeout = ask("12. Note store GC timeout?", "30000",
+ NoteStoreTimeout = ask("13. Note store GC timeout?", "30000",
fun verify_timeout/1),
- NetIfMod = ask("13. Which network interface module shall be used?",
+ NetIfMod = ask("14. Which network interface module shall be used?",
"snmpm_net_if", fun verify_module/1),
- NetIfVerb = ask("14. Network interface verbosity "
+ NetIfVerb = ask("15. Network interface verbosity "
"(silence/info/log/debug/trace)?", "silence",
fun verify_verbosity/1),
- NetIfBindTo = ask("15. Bind the manager IP address "
+ NetIfBindTo = ask("16. Bind the manager IP address "
"(true/false)?",
"false", fun verify_bool/1),
- NetIfNoReuse = ask("16. Shall the manager IP address and port "
+ NetIfNoReuse = ask("17. Shall the manager IP address and port "
"be not reusable (true/false)?",
"false", fun verify_bool/1),
NetIfRecbuf =
- case ask("17. Receive buffer size of the manager (in bytes) "
+ case ask("18. Receive buffer size of the manager (in bytes) "
"(default/pos integer)?", "default",
fun verify_netif_recbuf/1) of
default ->
@@ -684,7 +689,7 @@ config_manager_sys() ->
[{recbuf, RecBufSz}]
end,
NetIfSndbuf =
- case ask("18. Send buffer size of the manager (in bytes) "
+ case ask("19. Send buffer size of the manager (in bytes) "
"(default/pos integer)?", "default",
fun verify_netif_sndbuf/1) of
default ->
@@ -700,28 +705,28 @@ config_manager_sys() ->
{verbosity, NetIfVerb},
{options, NetIfOpts}],
ATL =
- case ask("19. Shall the manager use an audit trail log "
+ case ask("20. Shall the manager use an audit trail log "
"(y/n)?",
"n", fun verify_yes_or_no/1) of
yes ->
- ATLType = ask("19b. Audit trail log type "
+ ATLType = ask("20b. Audit trail log type "
"(write/read_write)?",
"read_write", fun verify_atl_type/1),
- ATLDir = ask("19c. Where to store the "
+ ATLDir = ask("20c. Where to store the "
"audit trail log?",
DefDir, fun verify_dir/1),
- ATLMaxFiles = ask("19d. Max number of files?",
+ ATLMaxFiles = ask("20d. Max number of files?",
"10",
fun verify_pos_integer/1),
- ATLMaxBytes = ask("19e. Max size (in bytes) "
+ ATLMaxBytes = ask("20e. Max size (in bytes) "
"of each file?",
"10240",
fun verify_pos_integer/1),
ATLSize = {ATLMaxBytes, ATLMaxFiles},
- ATLRepair = ask("19f. Audit trail log repair "
+ ATLRepair = ask("20f. Audit trail log repair "
"(true/false/truncate/snmp_repair)?", "true",
fun verify_atl_repair/1),
- ATLSeqNo = ask("19g. Audit trail log sequence-numbering "
+ ATLSeqNo = ask("20g. Audit trail log sequence-numbering "
"(true/false)?", "false",
fun verify_atl_seqno/1),
[{audit_trail_log, [{type, ATLType},
@@ -733,14 +738,14 @@ config_manager_sys() ->
[]
end,
DefUser =
- case ask("20. Do you wish to assign a default user [yes] or use~n"
+ case ask("21. Do you wish to assign a default user [yes] or use~n"
" the default settings [no] (y/n)?", "n",
fun verify_yes_or_no/1) of
yes ->
- DefUserMod = ask("20b. Default user module?",
+ DefUserMod = ask("21b. Default user module?",
"snmpm_user_default",
fun verify_module/1),
- DefUserData = ask("20c. Default user data?", "undefined",
+ DefUserData = ask("21c. Default user data?", "undefined",
fun verify_user_data/1),
[{def_user_mod, DefUserMod},
{def_user_data, DefUserData}];
@@ -750,11 +755,12 @@ config_manager_sys() ->
SysConfig =
[{priority, Prio},
{versions, Vsns},
- {config, [{dir, ConfigDir},
- {verbosity, ConfigVerb},
- {db_dir, ConfigDbDir},
- {repair, ConfigDbRepair},
- {auto_save, ConfigDbAutoSave}]},
+ {config, [{dir, ConfigDir},
+ {db_dir, ConfigDbDir},
+ {db_init_error, ConfigDbInitError},
+ {repair, ConfigDbRepair},
+ {auto_save, ConfigDbAutoSave},
+ {verbosity, ConfigVerb}]},
{inform_request_behaviour, IRB},
{mibs, []},
{server, [{timeout, ServerTimeout},
@@ -1069,6 +1075,16 @@ verify_dir(Dir) ->
_E ->
{error, "invalid directory (not absolute): " ++ Dir}
end.
+
+
+verify_db_init_error("terminate") ->
+ {ok, true};
+verify_db_init_error("create") ->
+ {ok, create};
+verify_db_init_error("create_db_and_dir") ->
+ {ok, create_db_and_dir};
+verify_db_init_error(R) ->
+ {error, "invalid DB init error: " ++ R}.
verify_notif_type("trap") -> {ok, trap};
@@ -1164,13 +1180,20 @@ verify_dets_auto_save(I0) ->
%% I know that this is a little of the edge, but...
+verify_module(M) when is_atom(M) ->
+ {ok, M};
+verify_module(M0) when is_list(M0) ->
+ {ok, list_to_atom(M0)};
verify_module(M0) ->
- case (catch list_to_atom(M0)) of
- M when is_atom(M) ->
- {ok, M};
- _ ->
- {error, "invalid module: " ++ M0}
- end.
+ {error, lists:flatten(io_lib:format("invalid module: ~p", [M0]))}.
+
+%% verify_module(M0) ->
+%% case (catch list_to_atom(M0)) of
+%% M when is_atom(M) ->
+%% {ok, M};
+%% _ ->
+%% {error, "invalid module: " ++ M0}
+%% end.
verify_agent_type("master") ->
@@ -2168,6 +2191,8 @@ write_sys_config_file_agent_opt(Fid, {config, Opts}) ->
ok = io:format(Fid, "}", []);
write_sys_config_file_agent_opt(Fid, {db_dir, Dir}) ->
ok = io:format(Fid, " {db_dir, \"~s\"}", [Dir]);
+write_sys_config_file_agent_opt(Fid, {db_init_error, Action}) ->
+ ok = io:format(Fid, " {db_init_error, ~w}", [Action]);
write_sys_config_file_agent_opt(Fid, {mib_storage, ets}) ->
ok = io:format(Fid, " {mib_storage, ets}", []);
write_sys_config_file_agent_opt(Fid, {mib_storage, {dets, Dir}}) ->
@@ -2344,6 +2369,8 @@ write_sys_config_file_manager_config_opt(Fid, {dir, Dir}) ->
ok = io:format(Fid, "{dir, \"~s\"}", [Dir]);
write_sys_config_file_manager_config_opt(Fid, {db_dir, Dir}) ->
ok = io:format(Fid, "{db_dir, \"~s\"}", [Dir]);
+write_sys_config_file_manager_config_opt(Fid, {db_init_error, Action}) ->
+ ok = io:format(Fid, "{db_init_error, ~w}", [Action]);
write_sys_config_file_manager_config_opt(Fid, {repair, Rep}) ->
ok = io:format(Fid, "{repair, ~w}", [Rep]);
write_sys_config_file_manager_config_opt(Fid, {auto_save, As}) ->
diff --git a/lib/snmp/test/snmp_agent_test.erl b/lib/snmp/test/snmp_agent_test.erl
index 7e683e315a..b7d34eb198 100644
--- a/lib/snmp/test/snmp_agent_test.erl
+++ b/lib/snmp/test/snmp_agent_test.erl
@@ -34,6 +34,7 @@
%% all_tcs - misc
app_info/1,
info_test/1,
+ create_local_db_dir/1,
%% all_tcs - test_v1
simple/1,
@@ -1506,7 +1507,8 @@ finish_misc(Config) ->
misc_cases() ->
[
app_info,
- info_test
+ info_test,
+ create_local_db_dir
].
app_info(suite) -> [];
@@ -1539,7 +1541,75 @@ app_dir(App) ->
"undefined"
end.
+create_local_db_dir(Config) when is_list(Config) ->
+ ?P(create_local_db_dir),
+ DataDir = snmp_test_lib:lookup(data_dir, Config),
+ T = erlang:now(),
+ [As,Bs,Cs] = [integer_to_list(I) || I <- tuple_to_list(T)],
+ DbDir = filename:join([DataDir, As, Bs, Cs]),
+ ok = del_dir(DbDir, 3),
+ Name = list_to_atom(atom_to_list(create_local_db_dir)
+ ++"-"++As++"-"++Bs++"-"++Cs),
+ Pa = filename:dirname(code:which(?MODULE)),
+ {ok,Node} = ?t:start_node(Name, slave, [{args, "-pa "++Pa}]),
+
+ %% first start with a nonexisting DbDir
+ Fun1 = fun() ->
+ false = filelib:is_dir(DbDir),
+ process_flag(trap_exit,true),
+ {error, {error, {failed_open_dets, {file_error, _, _}}}} =
+ snmpa_local_db:start_link(normal, DbDir, [{verbosity,trace}]),
+ false = filelib:is_dir(DbDir),
+ {ok, not_found}
+ end,
+ {ok, not_found} = nodecall(Node, Fun1),
+ %% now start with a nonexisting DbDir but pass the
+ %% create_local_db_dir option as well
+ Fun2 = fun() ->
+ false = filelib:is_dir(DbDir),
+ process_flag(trap_exit,true),
+ {ok, _Pid} =
+ snmpa_local_db:start_link(normal, DbDir,
+ create_db_and_dir, [{verbosity,trace}]),
+ snmpa_local_db:stop(),
+ true = filelib:is_dir(DbDir),
+ {ok, found}
+ end,
+ {ok, found} = nodecall(Node, Fun2),
+ %% cleanup
+ ?t:stop_node(Node),
+ ok = del_dir(DbDir, 3),
+ ok.
+
+nodecall(Node, Fun) ->
+ Parent = self(),
+ Ref = make_ref(),
+ spawn_link(Node,
+ fun() ->
+ Res = Fun(),
+ unlink(Parent),
+ Parent ! {Ref, Res}
+ end),
+ receive
+ {Ref, Res} ->
+ Res
+ end.
+del_dir(_Dir, 0) ->
+ ok;
+del_dir(Dir, Depth) ->
+ case filelib:is_dir(Dir) of
+ true ->
+ {ok, Files} = file:list_dir(Dir),
+ lists:map(fun(F) ->
+ Nm = filename:join(Dir,F),
+ ok = file:delete(Nm)
+ end, Files),
+ ok = file:del_dir(Dir),
+ del_dir(filename:dirname(Dir), Depth-1);
+ false ->
+ ok
+ end.
%v1_cases() -> [loop_mib];
v1_cases() ->
diff --git a/lib/snmp/test/snmp_manager_config_test.erl b/lib/snmp/test/snmp_manager_config_test.erl
index 3192fe1b40..7b9924b83c 100644
--- a/lib/snmp/test/snmp_manager_config_test.erl
+++ b/lib/snmp/test/snmp_manager_config_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -57,6 +57,7 @@
start_with_invalid_users_conf_file1/1,
start_with_invalid_agents_conf_file1/1,
start_with_invalid_usm_conf_file1/1,
+ start_with_create_db_and_dir_opt/1,
@@ -139,8 +140,13 @@ init_per_testcase(Case, Config) when is_list(Config) ->
file:make_dir(MgrTopDir = filename:join(CaseTopDir, "manager/")),
?line ok =
file:make_dir(MgrConfDir = filename:join(MgrTopDir, "conf/")),
- ?line ok =
- file:make_dir(MgrDbDir = filename:join(MgrTopDir, "db/")),
+ MgrDbDir = filename:join(MgrTopDir, "db/"),
+ case Case of
+ start_with_create_db_and_dir_opt ->
+ ok;
+ _ ->
+ ?line ok = file:make_dir(MgrDbDir)
+ end,
?line ok =
file:make_dir(MgrLogDir = filename:join(MgrTopDir, "log/")),
[{case_top_dir, CaseTopDir},
@@ -174,6 +180,7 @@ groups() ->
start_without_mandatory_opts2,
start_with_all_valid_opts, start_with_unknown_opts,
start_with_incorrect_opts,
+ start_with_create_db_and_dir_opt,
start_with_invalid_manager_conf_file1,
start_with_invalid_users_conf_file1,
start_with_invalid_agents_conf_file1,
@@ -332,7 +339,8 @@ start_with_all_valid_opts(Conf) when is_list(Conf) ->
{no_reuse, false}]}],
ServerOpts = [{timeout, 10000}, {verbosity, trace}],
NoteStoreOpts = [{timeout, 20000}, {verbosity, trace}],
- ConfigOpts = [{dir, ConfDir}, {verbosity, trace}, {db_dir, DbDir}],
+ ConfigOpts = [{dir, ConfDir}, {verbosity, trace},
+ {db_dir, DbDir}, {db_init_error, create}],
Mibs = [join(StdMibDir, "SNMP-NOTIFICATION-MIB"),
join(StdMibDir, "SNMP-USER-BASED-SM-MIB")],
Prio = normal,
@@ -1674,7 +1682,34 @@ start_with_invalid_usm_conf_file1(Conf) when is_list(Conf) ->
%% ---
%%
+start_with_create_db_and_dir_opt(suite) -> [];
+start_with_create_db_and_dir_opt(doc) ->
+ "Start the snmp manager config process with the\n"
+ "create_db_and_dir option.";
+start_with_create_db_and_dir_opt(Conf) when is_list(Conf) ->
+ put(tname, swcdado),
+ p("start"),
+ process_flag(trap_exit, true),
+ ConfDir = ?config(manager_conf_dir, Conf),
+ DbDir = ?config(manager_db_dir, Conf),
+ true = not filelib:is_dir(DbDir) and not filelib:is_file(DbDir),
+ write_manager_conf(ConfDir),
+
+ p("verify nonexistent db_dir"),
+ ConfigOpts01 = [{verbosity,trace}, {dir, ConfDir}, {db_dir, DbDir}],
+ {error, Reason01} = config_start([{config, ConfigOpts01}]),
+ p("nonexistent db_dir res: ~p", [Reason01]),
+ {invalid_conf_db_dir, _, not_found} = Reason01,
+ p("verify nonexistent db_dir gets created"),
+ ConfigOpts02 = [{db_init_error, create_db_and_dir} | ConfigOpts01],
+ {ok, _Pid} = config_start([{config, ConfigOpts02}]),
+ true = filelib:is_dir(DbDir),
+ p("verified: nonexistent db_dir was correctly created"),
+ ok = config_stop(),
+
+ p("done"),
+ ok.
%%
%% ---
diff --git a/lib/snmp/test/snmp_manager_test.erl b/lib/snmp/test/snmp_manager_test.erl
index dedbae5ce4..5fe18980bc 100644
--- a/lib/snmp/test/snmp_manager_test.erl
+++ b/lib/snmp/test/snmp_manager_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -1615,10 +1615,10 @@ simple_sync_get1(Config) when is_list(Config) ->
ok.
do_simple_sync_get(Node, Addr, Port, Oids) ->
- ?line {ok, Reply, Rem} = mgr_user_sync_get(Node, Addr, Port, Oids),
+ ?line {ok, Reply, _Rem} = mgr_user_sync_get(Node, Addr, Port, Oids),
?DBG("~n Reply: ~p"
- "~n Rem: ~w", [Reply, Rem]),
+ "~n Rem: ~w", [Reply, _Rem]),
%% verify that the operation actually worked:
%% The order should be the same, so no need to seach
@@ -1682,10 +1682,10 @@ do_simple_sync_get2(Config, Get, PostVerify) ->
do_simple_sync_get2(Node, TargetName, Oids, Get, PostVerify)
when is_function(Get, 3) andalso is_function(PostVerify, 0) ->
- ?line {ok, Reply, Rem} = Get(Node, TargetName, Oids),
+ ?line {ok, Reply, _Rem} = Get(Node, TargetName, Oids),
?DBG("~n Reply: ~p"
- "~n Rem: ~w", [Reply, Rem]),
+ "~n Rem: ~w", [Reply, _Rem]),
%% verify that the operation actually worked:
%% The order should be the same, so no need to seach
@@ -2061,10 +2061,10 @@ simple_sync_get_next1(Config) when is_list(Config) ->
do_simple_get_next(N, Node, Addr, Port, Oids, Verify) ->
p("issue get-next command ~w", [N]),
case mgr_user_sync_get_next(Node, Addr, Port, Oids) of
- {ok, Reply, Rem} ->
+ {ok, Reply, _Rem} ->
?DBG("get-next ok:"
"~n Reply: ~p"
- "~n Rem: ~w", [Reply, Rem]),
+ "~n Rem: ~w", [Reply, _Rem]),
Verify(Reply);
Error ->
@@ -2217,10 +2217,10 @@ do_simple_sync_get_next2(Config, GetNext, PostVerify)
do_simple_get_next(N, Node, TargetName, Oids, Verify, GetNext, PostVerify) ->
p("issue get-next command ~w", [N]),
case GetNext(Node, TargetName, Oids) of
- {ok, Reply, Rem} ->
+ {ok, Reply, _Rem} ->
?DBG("get-next ok:"
"~n Reply: ~p"
- "~n Rem: ~w", [Reply, Rem]),
+ "~n Rem: ~w", [Reply, _Rem]),
PostVerify(Verify(Reply));
Error ->
@@ -2551,10 +2551,10 @@ simple_sync_set1(Config) when is_list(Config) ->
do_simple_set1(Node, Addr, Port, VAVs) ->
[SysName, SysLoc] = value_of_vavs(VAVs),
- ?line {ok, Reply, Rem} = mgr_user_sync_set(Node, Addr, Port, VAVs),
+ ?line {ok, Reply, _Rem} = mgr_user_sync_set(Node, Addr, Port, VAVs),
?DBG("~n Reply: ~p"
- "~n Rem: ~w", [Reply, Rem]),
+ "~n Rem: ~w", [Reply, _Rem]),
%% verify that the operation actually worked:
%% The order should be the same, so no need to seach
@@ -2631,10 +2631,10 @@ do_simple_sync_set2(Config, Set, PostVerify)
do_simple_set2(Node, TargetName, VAVs, Set, PostVerify) ->
[SysName, SysLoc] = value_of_vavs(VAVs),
- ?line {ok, Reply, Rem} = Set(Node, TargetName, VAVs),
+ ?line {ok, Reply, _Rem} = Set(Node, TargetName, VAVs),
?DBG("~n Reply: ~p"
- "~n Rem: ~w", [Reply, Rem]),
+ "~n Rem: ~w", [Reply, _Rem]),
%% verify that the operation actually worked:
%% The order should be the same, so no need to seach
@@ -3026,10 +3026,10 @@ fl(L) ->
do_simple_get_bulk1(N, Node, Addr, Port, NonRep, MaxRep, Oids, Verify) ->
p("issue get-bulk command ~w", [N]),
case mgr_user_sync_get_bulk(Node, Addr, Port, NonRep, MaxRep, Oids) of
- {ok, Reply, Rem} ->
+ {ok, Reply, _Rem} ->
?DBG("get-bulk ok:"
"~n Reply: ~p"
- "~n Rem: ~w", [Reply, Rem]),
+ "~n Rem: ~w", [Reply, _Rem]),
Verify(Reply);
Error ->
@@ -3213,10 +3213,10 @@ do_simple_get_bulk2(N,
is_function(PostVerify) ->
p("issue get-bulk command ~w", [N]),
case GetBulk(NonRep, MaxRep, Oids) of
- {ok, Reply, Rem} ->
+ {ok, Reply, _Rem} ->
?DBG("get-bulk ok:"
"~n Reply: ~p"
- "~n Rem: ~w", [Reply, Rem]),
+ "~n Rem: ~w", [Reply, _Rem]),
PostVerify(Verify(Reply));
Error ->
@@ -5609,11 +5609,11 @@ init_mgr_user_data1(Conf) ->
[{address, Addr},
{port, Port},
{engine_id, "agentEngine"}]),
- Agents = mgr_user_which_own_agents(Node),
- ?DBG("Own agents: ~p", [Agents]),
+ _Agents = mgr_user_which_own_agents(Node),
+ ?DBG("Own agents: ~p", [_Agents]),
- ?line {ok, DefAgentConf} = mgr_user_agent_info(Node, TargetName, all),
- ?DBG("Default agent config: ~n~p", [DefAgentConf]),
+ ?line {ok, _DefAgentConf} = mgr_user_agent_info(Node, TargetName, all),
+ ?DBG("Default agent config: ~n~p", [_DefAgentConf]),
?line ok = mgr_user_update_agent_info(Node, TargetName,
community, "all-rights"),
@@ -5624,8 +5624,8 @@ init_mgr_user_data1(Conf) ->
?line ok = mgr_user_update_agent_info(Node, TargetName,
max_message_size, 1024),
- ?line {ok, AgentConf} = mgr_user_agent_info(Node, TargetName, all),
- ?DBG("Updated agent config: ~n~p", [AgentConf]),
+ ?line {ok, _AgentConf} = mgr_user_agent_info(Node, TargetName, all),
+ ?DBG("Updated agent config: ~n~p", [_AgentConf]),
Conf.
init_mgr_user_data2(Conf) ->
@@ -5639,11 +5639,11 @@ init_mgr_user_data2(Conf) ->
[{address, Addr},
{port, Port},
{engine_id, "agentEngine"}]),
- Agents = mgr_user_which_own_agents(Node),
- ?DBG("Own agents: ~p", [Agents]),
+ _Agents = mgr_user_which_own_agents(Node),
+ ?DBG("Own agents: ~p", [_Agents]),
- ?line {ok, DefAgentConf} = mgr_user_agent_info(Node, TargetName, all),
- ?DBG("Default agent config: ~n~p", [DefAgentConf]),
+ ?line {ok, _DefAgentConf} = mgr_user_agent_info(Node, TargetName, all),
+ ?DBG("Default agent config: ~n~p", [_DefAgentConf]),
?line ok = mgr_user_update_agent_info(Node, TargetName,
community, "all-rights"),
@@ -5652,8 +5652,8 @@ init_mgr_user_data2(Conf) ->
?line ok = mgr_user_update_agent_info(Node, TargetName,
max_message_size, 1024),
- ?line {ok, AgentConf} = mgr_user_agent_info(Node, TargetName, all),
- ?DBG("Updated agent config: ~n~p", [AgentConf]),
+ ?line {ok, _AgentConf} = mgr_user_agent_info(Node, TargetName, all),
+ ?DBG("Updated agent config: ~n~p", [_AgentConf]),
Conf.
fin_mgr_user_data1(Conf) ->
@@ -5853,12 +5853,12 @@ mgr_user_name_to_oid(Node, Name) ->
start_manager(Node, Vsns, Config) ->
start_manager(Node, Vsns, Config, []).
-start_manager(Node, Vsns, Conf0, Opts) ->
+start_manager(Node, Vsns, Conf0, _Opts) ->
?DBG("start_manager -> entry with"
"~n Node: ~p"
"~n Vsns: ~p"
"~n Conf0: ~p"
- "~n Opts: ~p", [Node, Vsns, Conf0, Opts]),
+ "~n Opts: ~p", [Node, Vsns, Conf0, _Opts]),
AtlDir = ?config(manager_log_dir, Conf0),
ConfDir = ?config(manager_conf_dir, Conf0),
@@ -5908,12 +5908,12 @@ stop_manager(Node, Conf) ->
start_agent(Node, Vsns, Config) ->
start_agent(Node, Vsns, Config, []).
-start_agent(Node, Vsns, Conf0, Opts) ->
+start_agent(Node, Vsns, Conf0, _Opts) ->
?DBG("start_agent -> entry with"
"~n Node: ~p"
"~n Vsns: ~p"
"~n Conf0: ~p"
- "~n Opts: ~p", [Node, Vsns, Conf0, Opts]),
+ "~n Opts: ~p", [Node, Vsns, Conf0, _Opts]),
AtlDir = ?config(agent_log_dir, Conf0),
ConfDir = ?config(agent_conf_dir, Conf0),
diff --git a/lib/snmp/test/snmp_manager_user.erl b/lib/snmp/test/snmp_manager_user.erl
index 4e789bbaec..ddbe156130 100644
--- a/lib/snmp/test/snmp_manager_user.erl
+++ b/lib/snmp/test/snmp_manager_user.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -681,6 +681,15 @@ loop(#state{parent = Parent, id = Id} = S) ->
Parent ! {async_event, TargetName, {report, SnmpReport}},
loop(S);
+ {handle_invalid_result, _Pid, In, Out} ->
+ d("loop -> received invalid result callback from manager for "
+ "~n In: ~p",
+ "~n Out: ~p", [In, Out]),
+ info("received invalid result message: "
+ "~n In: ~p"
+ "~n Out: ~p", [In, Out]),
+ loop(S);
+
{'EXIT', Parent, Reason} ->
d("received exit signal from parent: ~n~p", [Reason]),
info("received exit signal from parent: ~n~p", [Reason]),
@@ -770,7 +779,7 @@ handle_pdu(TargetName, ReqId, SnmpResponse, UserPid) ->
handle_trap(TargetName, SnmpTrap, UserPid) ->
UserPid ! {handle_trap, self(), TargetName, SnmpTrap},
- ok.
+ ignore.
handle_inform(TargetName, SnmpInform, UserPid) ->
UserPid ! {handle_inform, self(), TargetName, SnmpInform},
@@ -778,12 +787,12 @@ handle_inform(TargetName, SnmpInform, UserPid) ->
{handle_inform_no_response, TargetName} ->
no_reply;
{handle_inform_response, TargetName} ->
- ok
+ ignore
end.
handle_report(TargetName, SnmpReport, UserPid) ->
UserPid ! {handle_report, self(), TargetName, SnmpReport},
- ok.
+ ignore.
%%----------------------------------------------------------------------
diff --git a/lib/snmp/test/snmp_test_manager.erl b/lib/snmp/test/snmp_test_manager.erl
index 1f3383a7a8..925ae77ab5 100644
--- a/lib/snmp/test/snmp_test_manager.erl
+++ b/lib/snmp/test/snmp_test_manager.erl
@@ -47,7 +47,8 @@
handle_pdu/4,
handle_trap/3,
handle_inform/3,
- handle_report/3
+ handle_report/3,
+ handle_invalid_result/3
]).
@@ -279,12 +280,18 @@ handle_info({snmp_inform, TargetName, Info, Pid},
handle_info({snmp_report, TargetName, Info, Pid},
#state{parent = P} = State) ->
info_msg("received snmp report: "
- "~n TargetName: ~p"
- "~n Info: ~p", [TargetName, Info]),
+ "~n TargetName: ~p"
+ "~n Info: ~p", [TargetName, Info]),
Pid ! {snmp_report_reply, ignore, self()},
P ! {snmp_report, TargetName, Info},
{noreply, State};
+handle_info({snmp_invalid_result, In, Out}, State) ->
+ error_msg("Callback failure: "
+ "~n In: ~p"
+ "~n Out: ~p", [In, Out]),
+ {noreply, State};
+
handle_info(Info, State) ->
error_msg("received unknown info: "
"~n Info: ~p", [Info]),
@@ -369,7 +376,12 @@ handle_report(TargetName, SnmpInfo, Pid) ->
after 10000 ->
ignore
end.
-
+
+
+handle_invalid_result(In, Out, Pid) ->
+ Pid ! {snmp_invalid_result, In, Out},
+ ignore.
+
%%----------------------------------------------------------------------