aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorSteve Vinoski <[email protected]>2013-09-20 14:23:35 -0400
committerMicael Karlberg <[email protected]>2013-10-09 11:21:04 +0200
commitc83c236f6a0a1a5299376e40db57e7b7527cbac7 (patch)
tree61253108c10682e359d7260ea6547a1a7ac4e10d /lib
parent50e91bde3403c788bb1cabe644534f351d6dc1c1 (diff)
downloadotp-c83c236f6a0a1a5299376e40db57e7b7527cbac7.tar.gz
otp-c83c236f6a0a1a5299376e40db57e7b7527cbac7.tar.bz2
otp-c83c236f6a0a1a5299376e40db57e7b7527cbac7.zip
[snmp/agent] enable SNMP to create missing database directories
Add {db_init_error, create_db_and_dir} option to SNMP manager and agent. This allows them to create any missing parent directories for db_dir, rather than treating any missing directories as a fatal error. The default for db_init_error, which is terminate, is unchanged. Add create_db_and_dir to the documentation. Add new tests to verify that using create_db_and_dir results in missing parent directories being created.
Diffstat (limited to 'lib')
-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/src/agent/snmpa_local_db.erl6
-rw-r--r--lib/snmp/src/agent/snmpa_supervisor.erl2
-rw-r--r--lib/snmp/src/manager/snmpm_config.erl31
-rw-r--r--lib/snmp/test/snmp_agent_test.erl72
-rw-r--r--lib/snmp/test/snmp_manager_config_test.erl41
7 files changed, 153 insertions, 15 deletions
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/src/agent/snmpa_local_db.erl b/lib/snmp/src/agent/snmpa_local_db.erl
index 5198c6ec4e..a1e41257ce 100644
--- a/lib/snmp/src/agent/snmpa_local_db.erl
+++ b/lib/snmp/src/agent/snmpa_local_db.erl
@@ -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/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/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..a2733cd043 100644
--- a/lib/snmp/test/snmp_manager_config_test.erl
+++ b/lib/snmp/test/snmp_manager_config_test.erl
@@ -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.
%%
%% ---