%%
%% %CopyrightBegin%
%%
%% 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
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
%%
%% %CopyrightEnd%
%%
%%----------------------------------------------------------------------
%% This module implements an SNMP manager used in the test suite
%%----------------------------------------------------------------------
%%
-module(snmp_test_manager).
-behaviour(gen_server).
-behaviour(snmpm_user).
%% External exports
-export([
start_link/0, start_link/1,
stop/0,
sync_get/1, sync_get/2,
sync_get_next/1, sync_get_next/2,
sync_get_bulk/3,
sync_set/1, sync_set/2
]).
%% Manager callback API:
-export([
handle_error/3,
handle_agent/5,
handle_pdu/4,
handle_trap/3,
handle_inform/3,
handle_report/3,
handle_invalid_result/3
]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
code_change/3, terminate/2]).
-record(state, {parent, req, agent_target_name}).
-define(SERVER, ?MODULE).
-define(USER, ?MODULE).
%%%-------------------------------------------------------------------
%%% API
%%%-------------------------------------------------------------------
start_link() ->
start_link([]).
start_link(Opts) ->
gen_server:start_link({local, ?SERVER}, ?MODULE, [self(), Opts], []).
stop() ->
call(stop).
sync_get(Oids) ->
sync_get(Oids, fun(X) -> {ok, X} end).
sync_get(Oids, Verify) when is_list(Oids) and is_function(Verify) ->
Verify(call({sync_get, Oids})).
sync_get_next(Oids) ->
sync_get_next(Oids, fun(X) -> {ok, X} end).
sync_get_next(Oids, Verify) when is_list(Oids) and is_function(Verify) ->
Verify(call({sync_get_next, Oids})).
sync_get_bulk(NR, MR, Oids) ->
sync_get_bulk(NR, MR, Oids, fun(X) -> {ok, X} end).
sync_get_bulk(NR, MR, Oids, Verify)
when is_integer(NR) and is_integer(MR) and
is_list(Oids) and is_function(Verify) ->
Verify(call({sync_get_bulk, NR, MR, Oids})).
sync_set(VarsAndVals) ->
sync_set(VarsAndVals, fun(X) -> {ok, X} end).
sync_set(VarsAndVals, Verify)
when is_list(VarsAndVals) and is_function(Verify) ->
Verify(call({sync_set, VarsAndVals})).
%%%-------------------------------------------------------------------
%%% Callback functions from gen_server
%%%-------------------------------------------------------------------
%%--------------------------------------------------------------------
%% Func: init/1
%% Returns: {ok, State} |
%% {ok, State, Timeout} |
%% ignore |
%% {stop, Reason}
%%--------------------------------------------------------------------
init([Parent, Opts]) ->
process_flag(trap_exit, true),
case (catch do_init(Opts)) of
{ok, State} ->
{ok, State#state{parent = Parent}};
{error, Reason} ->
{stop, Reason}
end.
do_init(Opts) ->
{MgrDir, MgrConf, MgrOpts, AgentTargetName, AgentConf} = parse_opts(Opts),
ok = snmp_config:write_manager_config(MgrDir, "", MgrConf),
ok = snmpm:start_link(MgrOpts),
ok = snmpm:register_user(?USER, ?MODULE, self()),
ok = snmpm:register_agent(?USER, AgentTargetName, AgentConf),
{ok, #state{agent_target_name = AgentTargetName}}.
parse_opts(Opts) ->
%% Manager config (written to the manager.conf file)
%% Addr = get_opt(addr, Opts, ?HOSTNAME()),
Port = get_opt(port, Opts, 5000),
EngineId = get_opt(engine_id, Opts, "mgrEngine"),
MMS = get_opt(max_message_size, Opts, 484),
MgrConf = [%% {address, Addr},
{port, Port},
{engine_id, EngineId},
{max_message_size, MMS}],
%% Manager options
MgrOpts = get_opt(options, Opts),
MgrDir = get_opt(dir, get_opt(config, MgrOpts, [])),
%% Retreive the agent configuration
AgentConf = get_opt(agent_config, Opts),
AgentTarget = get_opt(agent_target, Opts),
{MgrDir, MgrConf, MgrOpts, AgentTarget, AgentConf}.
get_opt(Key, Opts) ->
case lists:keysearch(Key, 1, Opts) of
{value, {Key, Val}} ->
Val;
false ->
throw({error, {missing_mandatory, Key}})
end.
get_opt(Key, Opts, Def) ->
case lists:keysearch(Key, 1, Opts) of
{value, {Key, Val}} ->
Val;
false ->
Def
end.
%%--------------------------------------------------------------------
%% Func: handle_call/3
%% Returns: {reply, Reply, State} |
%% {reply, Reply, State, Timeout} |
%% {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, Reply, State} | (terminate/2 is called)
%% {stop, Reason, State} (terminate/2 is called)
%%--------------------------------------------------------------------
handle_call(stop, _From, S) ->
(catch snmpm:stop()),
{stop, normal, S};
handle_call({sync_get, Oids}, _From,
#state{agent_target_name = TargetName} = S) ->
Reply = (catch snmpm:sync_get(?USER, TargetName, Oids)),
{reply, Reply, S};
handle_call({sync_get_next, Oids}, _From,
#state{agent_target_name = TargetName} = S) ->
Reply = (catch snmpm:sync_get_next(?USER, TargetName, Oids)),
{reply, Reply, S};
handle_call({sync_get_bulk, NR, MR, Oids}, _From,
#state{agent_target_name = TargetName} = S) ->
Reply = (catch snmpm:sync_get_bulk(?USER, TargetName, NR, MR, Oids)),
{reply, Reply, S};
handle_call({sync_set, VarsAndVals}, _From,
#state{agent_target_name = TargetName} = S) ->
Reply = (catch snmpm:sync_set(?USER, TargetName, VarsAndVals)),
{reply, Reply, S};
handle_call(Req, From, State) ->
error_msg("received unknown request ~n~p~nFrom ~p", [Req, From]),
{reply, {error, unknown_request}, State}.
%%--------------------------------------------------------------------
%% Func: handle_cast/2
%% Returns: {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, State} (terminate/2 is called)
%%--------------------------------------------------------------------
handle_cast(Msg, State) ->
error_msg("received unknown message ~n~p", [Msg]),
{noreply, State}.
%%--------------------------------------------------------------------
%% Func: handle_info/2
%% Returns: {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, State} (terminate/2 is called)
%%--------------------------------------------------------------------
handle_info({snmp_error, ReqId, Reason},
#state{parent = P} = State) ->
info_msg("received snmp error: "
"~n ReqId: ~w"
"~n Reason: ~p", [ReqId, Reason]),
P ! {snmp_error, ReqId, Reason},
{noreply, State};
handle_info({snmp_agent, Addr, Port, Info, Pid, _UserData},
#state{parent = P} = State) ->
error_msg("detected new agent: "
"~n Addr: ~w"
"~n Port: ~p"
"~n Info: ~p", [Addr, Port, Info]),
Pid ! {snmp_agent_reply, ignore, self()},
P ! {snmp_agent, Addr, Port, Info},
{noreply, State};
handle_info({snmp_pdu, TargetName, ReqId, Resp},
#state{parent = P} = State) ->
info_msg("received snmp pdu: "
"~n TargetName: ~p"
"~n ReqId: ~w"
"~n Resp: ~p", [TargetName, ReqId, Resp]),
P ! {snmp_pdu, TargetName, ReqId, Resp},
{noreply, State};
handle_info({snmp_trap, TargetName, Info, Pid},
#state{parent = P} = State) ->
info_msg("received snmp trap: "
"~n TargetName: ~p"
"~n Info: ~p", [TargetName, Info]),
Pid ! {snmp_trap_reply, ignore, self()},
P ! {snmp_trap, TargetName, Info},
{noreply, State};
handle_info({snmp_inform, TargetName, Info, Pid},
#state{parent = P} = State) ->
info_msg("received snmp inform: "
"~n TargetName: ~p"
"~n Info: ~p", [TargetName, Info]),
Pid ! {snmp_inform_reply, ignore, self()},
P ! {snmp_inform, TargetName, Info},
{noreply, State};
handle_info({snmp_report, TargetName, Info, Pid},
#state{parent = P} = State) ->
info_msg("received snmp report: "
"~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]),
{noreply, State}.
%%--------------------------------------------------------------------
%% Func: terminate/2
%% Purpose: Shutdown the server
%% Returns: any (ignored by gen_server)
%%--------------------------------------------------------------------
terminate(_Reason, _State) ->
ok.
code_change({down, _Vsn}, State, _Extra) ->
{ok, State};
% upgrade
code_change(_Vsn, State, _Extra) ->
{ok, State}.
%%%-------------------------------------------------------------------
%%% Internal functions
%%%-------------------------------------------------------------------
%% --------------------------------------------------------------------------
%%
%% SNMP manager callback functions
%%
%% --------------------------------------------------------------------------
handle_error(ReqId, Reason, Pid) ->
Pid ! {snmp_error, ReqId, Reason},
ignore.
handle_agent(Addr, Port, SnmpInfo, Pid, UserData) ->
Pid ! {snmp_agent, Addr, Port, SnmpInfo, self(), UserData},
receive
{snmp_agent_reply, Reply, Pid} ->
Reply
after 10000 ->
ignore
end.
handle_pdu(TargetName, ReqId, SnmpResponse, Pid) ->
Pid ! {snmp_pdu, TargetName, ReqId, SnmpResponse},
ignore.
handle_trap(TargetName, SnmpTrapInfo, Pid) ->
Pid ! {snmp_trap, TargetName, SnmpTrapInfo, self()},
receive
{snmp_trap_reply, Reply, Pid} ->
Reply
after 10000 ->
ignore
end.
handle_inform(TargetName, SnmpInfo, Pid) ->
Pid ! {snmp_inform, TargetName, SnmpInfo, self()},
receive
{snmp_inform_reply, Reply, Pid} ->
Reply
after 10000 ->
ignore
end.
handle_report(TargetName, SnmpInfo, Pid) ->
Pid ! {snmp_report, TargetName, SnmpInfo, self()},
receive
{snmp_report_reply, Reply, Pid} ->
Reply
after 10000 ->
ignore
end.
handle_invalid_result(In, Out, Pid) ->
Pid ! {snmp_invalid_result, In, Out},
ignore.
%%----------------------------------------------------------------------
call(Req) ->
gen_server:call(?SERVER, Req, infinity).
% cast(Msg) ->
% gen_server:cast(?SERVER, Msg).
info_msg(F, A) ->
catch error_logger:info_msg("*** TEST-MANAGER: " ++ F ++ "~n", A).
error_msg(F, A) ->
catch error_logger:error_msg("*** TEST-MANAGER: " ++ F ++ "~n", A).