Skip to content
Browse files

add option to scan ip aliases on a given interface at runtime on clients

  • Loading branch information...
1 parent 14e863c commit bd5d6fa10376ad479ce48319a5ea91cb312132b6 @nniclausse nniclausse committed Aug 9, 2010
Showing with 238 additions and 14 deletions.
  1. +4 −0 src/test/ts_test_config.erl
  2. +11 −2 src/tsung/ts_client.erl
  3. +186 −0 src/tsung/ts_ip_scan.erl
  4. +3 −1 src/tsung/ts_sup.erl
  5. +29 −10 src/tsung_controller/ts_config.erl
  6. +5 −1 tsung-1.0.dtd
View
4 src/test/ts_test_config.erl
@@ -125,6 +125,10 @@ cport_list_node_test() ->
?assertEqual(['tsung1@toto', 'tsung3@titi', 'tsung4@tutu'], lists:sort(Rep)).
+ifalias_test() ->
+ Res=ts_ip_scan:get_intf_aliases("lo"),
+ ?assertEqual([{127,0,0,1}],Res).
+
myset_env()->
myset_env(0).
myset_env(Level)->
View
13 src/tsung/ts_client.erl
@@ -89,7 +89,7 @@ init({#session{id = SessionId,
size = Count,
type = CType}, IP, Server,Id}) ->
?DebugF("Init ... started with count = ~p~n",[Count]),
- ts_utils:init_seed(),
+ ts_utils:init_seed(),
?DebugF("Get dynparams for ~p~n",[CType]),
DynData = CType:init_dynparams(),
@@ -98,10 +98,19 @@ init({#session{id = SessionId,
NewDynData = DynData#dyndata{dynvars=NewDynVars},
StartTime= now(),
set_thinktime(?short_timeout),
+ ?DebugF("IP param: ~p~n",[IP]),
NewIP = case IP of
- { RealIP, -1 } ->
+ { TmpIP, -1 } ->
{ok, MyHostName} = ts_utils:node_to_hostname(node()),
+ RealIP = case TmpIP of
+ {scan, Interface} ->
+ ts_ip_scan:get_ip(Interface);
+ _ -> TmpIP
+ end,
{RealIP, "cport-" ++ MyHostName};
+ {{scan, Interface}, PortVal } ->
+ ?DebugF("Must scan interface: ~p~n",[Interface]),
+ { ts_ip_scan:get_ip(Interface), PortVal };
Val ->
Val
end,
View
186 src/tsung/ts_ip_scan.erl
@@ -0,0 +1,186 @@
+%%% This program is free software; you can redistribute it and/or modify
+%%% it under the terms of the GNU General Public License as published by
+%%% the Free Software Foundation; either version 2 of the License, or
+%%% (at your option) any later version.
+%%%
+%%% This program is distributed in the hope that it will be useful,
+%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
+%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+%%% GNU General Public License for more details.
+%%%
+%%% You should have received a copy of the GNU General Public License
+%%% along with this program; if not, write to the Free Software
+%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+%%%
+%%% Created : 9 Aug 2010 by Nicolas Niclausse <nicolas@niclux.org>
+
+%%% In addition, as a special exception, you have the permission to
+%%% link the code of this program with any library released under
+%%% the EPL license and distribute linked combinations including
+%%% the two.
+
+%%%-------------------------------------------------------------------
+%%% @author Nicolas Niclausse <nicolas@niclux.org>
+%%% @copyright (C) 2010, Nicolas Niclausse
+%%% @doc
+%%%
+%%% @end
+%%% Created : 9 Aug 2010 by Nicolas Niclausse <>
+%%%-------------------------------------------------------------------
+-module(ts_ip_scan).
+
+-behaviour(gen_server).
+
+-include("ts_profile.hrl").
+-include("ts_config.hrl").
+
+%% API
+-export([start_link/0, get_ip/1]).
+
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+ terminate/2, code_change/3]).
+
+-define(SERVER, ?MODULE).
+
+-record(state, {ips}).
+
+%%%===================================================================
+%%% API
+%%%===================================================================
+get_ip(Interface) ->
+ gen_server:call(?MODULE, {get_ip, Interface}).
+
+%%--------------------------------------------------------------------
+%% @doc
+%% Starts the server
+%%
+%% @spec start_link() -> {ok, Pid} | ignore | {error, Error}
+%% @end
+%%--------------------------------------------------------------------
+start_link() ->
+ gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
+
+%%%===================================================================
+%%% gen_server callbacks
+%%%===================================================================
+
+%%--------------------------------------------------------------------
+%% @private
+%% @doc
+%% Initializes the server
+%%
+%% @spec init(Args) -> {ok, State} |
+%% {ok, State, Timeout} |
+%% ignore |
+%% {stop, Reason}
+%% @end
+%%--------------------------------------------------------------------
+init([]) ->
+ ?LOG("Starting ~n",?INFO),
+ {ok, #state{}}.
+
+%%--------------------------------------------------------------------
+%% @private
+%% @doc
+%% Handling call messages
+%%
+%% @spec handle_call(Request, From, State) ->
+%% {reply, Reply, State} |
+%% {reply, Reply, State, Timeout} |
+%% {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, Reply, State} |
+%% {stop, Reason, State}
+%% @end
+%%--------------------------------------------------------------------
+handle_call({get_ip, Interface}, _From, State=#state{ips=undefined}) ->
+ [Val|Rest] = get_intf_aliases(Interface),
+ {reply, Val, State#state{ips=Rest ++ [Val]}};
+handle_call({get_ip, _}, _From, State=#state{ips=[Val|Rest]}) ->
+ {reply, Val, State#state{ips=Rest ++ [Val]}}.
+
+%%--------------------------------------------------------------------
+%% @private
+%% @doc
+%% Handling cast messages
+%%
+%% @spec handle_cast(Msg, State) -> {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State}
+%% @end
+%%--------------------------------------------------------------------
+handle_cast(_Msg, State) ->
+ {noreply, State}.
+
+%%--------------------------------------------------------------------
+%% @private
+%% @doc
+%% Handling all non call/cast messages
+%%
+%% @spec handle_info(Info, State) -> {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State}
+%% @end
+%%--------------------------------------------------------------------
+handle_info(_Info, State) ->
+ {noreply, State}.
+
+%%--------------------------------------------------------------------
+%% @private
+%% @doc
+%% This function is called by a gen_server when it is about to
+%% terminate. It should be the opposite of Module:init/1 and do any
+%% necessary cleaning up. When it returns, the gen_server terminates
+%% with Reason. The return value is ignored.
+%%
+%% @spec terminate(Reason, State) -> void()
+%% @end
+%%--------------------------------------------------------------------
+terminate(_Reason, _State) ->
+ ok.
+
+%%--------------------------------------------------------------------
+%% @private
+%% @doc
+%% Convert process state when code is changed
+%%
+%% @spec code_change(OldVsn, State, Extra) -> {ok, NewState}
+%% @end
+%%--------------------------------------------------------------------
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
+%%%===================================================================
+%%% Internal functions
+%%%===================================================================
+
+%%
+get_intf_aliases(Interface) ->
+ Res=os:cmd("LANG=C /sbin/ifconfig "),
+ get_intf_aliases(string:tokens(Res,"\n"), Interface,[],[]).
+
+get_intf_aliases([], _, _, Res) ->
+ Res;
+get_intf_aliases([" inet addr:"++Line|Tail], Interface, Interface, Res) ->
+ [TmpIP|_] =string:tokens(Line," "),
+ ?LOGF("found IP: ~p~n",[TmpIP],?DEB),
+ {ok, IP } = inet:getaddr(TmpIP,inet),
+ get_intf_aliases(Tail, Interface, Interface, lists:append([IP],Res));
+get_intf_aliases([" "++_Line|Tail], Interface, Current, Res) ->
+ get_intf_aliases(Tail, Interface, Current, Res);
+get_intf_aliases([Line|Tail], Interface, Old, Res) ->
+ ?DebugF("scan line : ~p~n",[Line]),
+ case string:str(Line,Interface) of
+ 1 ->
+ [Current|_] =string:tokens(Line," "),
+ ?LOGF("found interface (old is ~p): ~p~n",[Old,Current],?DEB),
+ case string:str(Current, Old++":") of
+ 1 -> % subinterface, don't change current
+ get_intf_aliases(Tail, Interface, Old, Res);
+ _ ->
+ get_intf_aliases(Tail, Interface, Current, Res)
+ end;
+ _ ->
+ get_intf_aliases(Tail, Interface, "", Res)
+ end.
View
4 src/tsung/ts_sup.erl
@@ -76,7 +76,9 @@ init([]) ->
transient, 2000, worker, [ts_session_cache]},
MonCache = {ts_mon_cache, {ts_mon_cache, start, []},
transient, 2000, worker, [ts_mon_cache]},
- {ok,{{one_for_one,?retries,10}, [LauncherManager, SessionCache, MonCache,ClientsSup, StaticLauncher,Launcher ]}}.
+ IPScan = {ts_ip_scan, {ts_ip_scan, start_link, []},
+ transient, 2000, worker, [ts_ip_scan]},
+ {ok,{{one_for_one,?retries,10}, [IPScan, LauncherManager, SessionCache, MonCache,ClientsSup, StaticLauncher,Launcher ]}}.
%%%----------------------------------------------------------------------
%%% Internal functions
View
39 src/tsung_controller/ts_config.erl
@@ -180,6 +180,7 @@ parse(Element = #xmlElement{name=client, attributes=Attrs},
batch ->
?LOG("Get client nodes from batch scheduler~n",?DEB),
Batch = getAttr(atom, Attrs, batch),
+ Scan_Intf = getAttr(Attrs, scan_intf),
NodesTmp = get_batch_nodes(Batch),
case NodesTmp of
[]->
@@ -192,8 +193,20 @@ parse(Element = #xmlElement{name=client, attributes=Attrs},
{ok, ControllerHost} = ts_utils:node_to_hostname(node()),
Nodes = lists:delete(ControllerHost, NodesTmp),
Fun = fun(N)->
- {ok, IP } = inet:getaddr(N,inet),
- #client{host=N,weight=Weight,ip=[IP],maxusers=MaxUsers}
+ IP = case Scan_Intf of
+ "" ->
+ {ok, TmpIP } = inet:getaddr(N,inet),
+ TmpIP;
+ Interface ->
+ case os:type() of
+ {unix, linux} ->
+ {scan, Interface};
+ OS ->
+ ?LOGF("Scan interface is not supported on OS ~p, abort~n",[OS],?ERR),
+ exit({error, scan_interface_not_supported_on_os})
+ end
+ end,
+ #client{host=N,weight=Weight,ip=[IP],maxusers=MaxUsers}
end,
lists:map(Fun, Nodes);
_ ->
@@ -225,15 +238,21 @@ parse(Element = #xmlElement{name=client, attributes=Attrs},
parse(Element = #xmlElement{name=ip, attributes=Attrs},
Conf = #config{clients=[CurClient|CList]}) ->
IPList = CurClient#client.ip,
- ToResolve = case getAttr(Attrs, value) of
- "resolve" ->
- CurClient#client.host;
- StrIP ->
- StrIP
+ IP = case getAttr(atom, Attrs, scan, false) of
+ true ->
+ {scan, getAttr(string,Attrs, value, "eth0")};
+ _ ->
+ ToResolve = case getAttr(Attrs, value) of
+ "resolve" ->
+ CurClient#client.host;
+ StrIP ->
+ StrIP
+ end,
+ ?LOGF("resolving host ~p~n",[ToResolve],?WARN),
+ {ok,IPtmp} = inet:getaddr(ToResolve,inet),
+ IPtmp
end,
- ?LOGF("resolving host ~p~n",[ToResolve],?WARN),
- {ok, IP } = inet:getaddr(ToResolve,inet),
- ?LOGF("resolved host ~p~n",[IP],?WARN),
+ ?LOGF("resolved host ~p~n",[IP],?WARN),
lists:foldl(fun parse/2,
Conf#config{clients = [CurClient#client{ip = [IP|IPList]}
|CList]},
View
6 tsung-1.0.dtd
@@ -29,12 +29,16 @@
type (machine | batch) "machine"
host NMTOKEN #IMPLIED
batch (torque | pbs | lsf | oar) #IMPLIED
+ scan_intf NMTOKEN #IMPLIED
maxusers NMTOKEN "800"
use_controller_vm (true | false) "false"
weight NMTOKEN "1">
<!ELEMENT ip EMPTY>
-<!ATTLIST ip value NMTOKEN #REQUIRED>
+<!ATTLIST ip
+ value NMTOKEN #REQUIRED
+ scan (true| false) "false"
+>
<!ELEMENT monitoring ( monitor+ )>
<!ELEMENT monitor ( snmp? | munin?)>

0 comments on commit bd5d6fa

Please sign in to comment.
Something went wrong with that request. Please try again.