%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 1996-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at %% %% http://www.apache.org/licenses/LICENSE-2.0 %% %% Unless required by applicable law or agreed to in writing, software %% distributed under the License is distributed on an "AS IS" BASIS, %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. %% %% %CopyrightEnd% %% -module(snmpa_set). -behaviour(snmpa_set_mechanism). -define(VMODULE,"SET"). -include("snmp_verbosity.hrl"). %%%----------------------------------------------------------------- %%% This module implements a simple, basic atomic set mechanism. %%%----------------------------------------------------------------- %%% Table of contents %%% ================= %%% 1. SET REQUEST %%% 1.1 SET phase one %%% 1.2 SET phase two %%% 2. Misc functions %%%----------------------------------------------------------------- %% External exports -export([do_set/2, do_subagent_set/1]). %%%----------------------------------------------------------------- %%% 1. SET REQUEST %%% %%% 1) Perform set_phase_one for all own vars %%% 2) Perform set_phase_one for all SAs %%% IF nok THEN 2.1 ELSE 3 %%% 2.1) Perform set_phase_two(undo) for all SAs that have performed %%% set_phase_one. %%% 3) Perform set_phase_two for all own vars %%% 4) Perform set_phase_two(set) for all SAs %%% IF nok THEN 4.1 ELSE 5 %%% 4.1) Perform set_phase_two(undo) for all SAs that have performed %%% set_phase_one but not set_phase_two(set). %%% 5) noError %%%----------------------------------------------------------------- %%----------------------------------------------------------------- %% First of all - validate MibView for all varbinds. In this way %% we don't have to send the MibView to all SAs for validation. %%----------------------------------------------------------------- do_set(MibView, UnsortedVarbinds) -> ?vtrace("do set with" "~n MibView: ~p",[MibView]), case snmpa_acm:validate_all_mib_view(UnsortedVarbinds, MibView) of true -> {MyVarbinds , SubagentVarbinds} = sort_varbindlist(UnsortedVarbinds), case set_phase_one(MyVarbinds, SubagentVarbinds) of {noError, 0} -> set_phase_two(MyVarbinds, SubagentVarbinds); {Reason, Index} -> {Reason, Index} end; {false, Index} -> {noAccess, Index} end. %%----------------------------------------------------------------- %% This function is called when a subagents receives a message %% concerning some set_phase. %% Mandatory messages for all subagents: %% [phase_one, UnsortedVarbinds] %% [phase_two, set, UnsortedVarbinds] %% [phase_two, undo, UnsortedVarbinds] %%----------------------------------------------------------------- do_subagent_set([phase_one, UnsortedVarbinds]) -> ?vtrace("do subagent set, phase one",[]), {MyVarbinds, SubagentVarbinds} = sort_varbindlist(UnsortedVarbinds), set_phase_one(MyVarbinds, SubagentVarbinds); do_subagent_set([phase_two, State, UnsortedVarbinds]) -> ?vtrace("do subagent set, phase two",[]), {MyVarbinds, SubagentVarbinds} = sort_varbindlist(UnsortedVarbinds), set_phase_two(State, MyVarbinds, SubagentVarbinds). %%%----------------------------------------------------------------- %%% 1.1 SET phase one %%%----------------------------------------------------------------- %%----------------------------------------------------------------- %% Func: set_phase_one/3 %% Purpose: First, do set_phase_one for my own variables (i.e. %% variables handled by this agent). Then, do set_phase_one %% for all subagents. If any SA failed, do set_phase_two %% (undo) for all SA that have done set_phase_one. %% Returns: {noError, 0} | {ErrorStatus, Index} %%----------------------------------------------------------------- set_phase_one(MyVarbinds, SubagentVarbinds) -> ?vtrace("set phase one: " "~n MyVarbinds: ~p" "~n SubagentVarbinds: ~p", [MyVarbinds, SubagentVarbinds]), case set_phase_one_my_variables(MyVarbinds) of {noError, 0} -> case set_phase_one_subagents(SubagentVarbinds, []) of {noError, 0} -> {noError, 0}; {{ErrorStatus, Index}, PerformedSubagents} -> case set_phase_two_undo(MyVarbinds, PerformedSubagents) of {noError, 0} -> {ErrorStatus, Index}; {WorseErrorStatus, WorseIndex} -> {WorseErrorStatus, WorseIndex} end end; {ErrorStatus, Index} -> {ErrorStatus, Index} end. set_phase_one_my_variables(MyVarbinds) -> ?vtrace("my variables set, phase one:" "~n ~p",[MyVarbinds]), case snmpa_set_lib:is_varbinds_ok(MyVarbinds) of {noError, 0} -> snmpa_set_lib:consistency_check(MyVarbinds); {ErrorStatus, Index} -> {ErrorStatus, Index} end. %%----------------------------------------------------------------- %% Loop all subagents, and perform set_phase_one for them. %%----------------------------------------------------------------- set_phase_one_subagents([{SubAgentPid, SAVbs}|SubagentVarbinds], Done) -> {_SAOids, Vbs} = sa_split(SAVbs), case (catch snmpa_agent:subagent_set(SubAgentPid, [phase_one, Vbs])) of {noError, 0} -> set_phase_one_subagents(SubagentVarbinds, [{SubAgentPid, SAVbs} | Done]); {'EXIT', Reason} -> user_err("Lost contact with subagent (set phase_one)" "~n~w. Using genErr", [Reason]), {{genErr, 0}, Done}; {ErrorStatus, ErrorIndex} -> {{ErrorStatus, ErrorIndex}, Done} end; set_phase_one_subagents([], _Done) -> {noError, 0}. %%%----------------------------------------------------------------- %%% 1.2 SET phase two %%%----------------------------------------------------------------- %% returns: {ErrStatus, ErrIndex} set_phase_two(MyVarbinds, SubagentVarbinds) -> ?vtrace("set phase two: " "~n MyVarbinds: ~p" "~n SubagentVarbinds: ~p", [MyVarbinds, SubagentVarbinds]), case snmpa_set_lib:try_set(MyVarbinds) of {noError, 0} -> ?vtrace("set phase two: (local) varbinds set ok", []), set_phase_two_subagents(SubagentVarbinds); {ErrorStatus, ErrorIndex} -> ?vlog("set phase two: (local) varbinds set failed" "~n ErrorStatus: ~p" "~n ErrorIndex: ~p", [ErrorStatus, ErrorIndex]), set_phase_two_undo_subagents(SubagentVarbinds), {ErrorStatus, ErrorIndex} end. %%----------------------------------------------------------------- %% This function is called for each phase_two state in the %% subagents. The undo state just pass undo along to each of its %% subagents. %%----------------------------------------------------------------- set_phase_two(set, MyVarbinds, SubagentVarbinds) -> set_phase_two(MyVarbinds, SubagentVarbinds); set_phase_two(undo, MyVarbinds, SubagentVarbinds) -> set_phase_two_undo(MyVarbinds, SubagentVarbinds). %%----------------------------------------------------------------- %% Loop all subagents, and perform set_phase_two(set) for them. %% If any fails, perform set_phase_two(undo) for the not yet %% called SAs. %%----------------------------------------------------------------- set_phase_two_subagents([{SubAgentPid, SAVbs} | SubagentVarbinds]) -> {_SAOids, Vbs} = sa_split(SAVbs), case catch snmpa_agent:subagent_set(SubAgentPid, [phase_two, set, Vbs]) of {noError, 0} -> ?vtrace("set phase two: subagent ~p varbinds set ok", [SubAgentPid]), set_phase_two_subagents(SubagentVarbinds); {'EXIT', Reason} -> user_err("Lost contact with subagent (set)~n~w. Using genErr", [Reason]), set_phase_two_undo_subagents(SubagentVarbinds), {genErr, 0}; {ErrorStatus, ErrorIndex} -> ?vlog("set phase two: subagent ~p varbinds set failed" "~n ErrorStatus: ~p" "~n ErrorIndex: ~p", [SubAgentPid, ErrorStatus, ErrorIndex]), set_phase_two_undo_subagents(SubagentVarbinds), {ErrorStatus, ErrorIndex} end; set_phase_two_subagents([]) -> ?vtrace("set phase two: subagent(s) set ok", []), {noError, 0}. %%----------------------------------------------------------------- %% This function undos phase_one, own and subagent. %%----------------------------------------------------------------- set_phase_two_undo(MyVarbinds, SubagentVarbinds) -> case set_phase_two_undo_my_variables(MyVarbinds) of {noError, 0} -> set_phase_two_undo_subagents(SubagentVarbinds); {ErrorStatus, Index} -> set_phase_two_undo_subagents(SubagentVarbinds), {ErrorStatus, Index} end. set_phase_two_undo_my_variables(MyVarbinds) -> snmpa_set_lib:undo_varbinds(MyVarbinds). set_phase_two_undo_subagents([{SubAgentPid, SAVbs} | SubagentVarbinds]) -> {_SAOids, Vbs} = sa_split(SAVbs), case catch snmpa_agent:subagent_set(SubAgentPid, [phase_two, undo, Vbs]) of {noError, 0} -> set_phase_two_undo_subagents(SubagentVarbinds); {'EXIT', Reason} -> user_err("Lost contact with subagent (undo)~n~w. Using genErr", [Reason]), {genErr, 0}; {ErrorStatus, ErrorIndex} -> {ErrorStatus, ErrorIndex} end; set_phase_two_undo_subagents([]) -> {noError, 0}. %%%----------------------------------------------------------------- %%% 2. Misc functions %%%----------------------------------------------------------------- sort_varbindlist(Varbinds) -> snmpa_svbl:sort_varbindlist(get(mibserver), Varbinds). sa_split(SubagentVarbinds) -> snmpa_svbl:sa_split(SubagentVarbinds). user_err(F, A) -> snmpa_error:user_err(F, A).