~ubuntu-branches/ubuntu/raring/tsung/raring

« back to all changes in this revision

Viewing changes to src/tsung_controller/ts_config.erl

  • Committer: Package Import Robot
  • Author(s): Ignace Mouzannar
  • Date: 2012-01-08 10:32:48 UTC
  • mfrom: (1.1.1)
  • Revision ID: package-import@ubuntu.com-20120108103248-86e6zanu8dt5358j
Tags: 1.4.2-1
* New upstream version. (Closes: 653211)
* debian/patches:
  - 01_spelling_corrections.diff: refreshed patch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
57
57
%%% @doc:  read and parse the xml config file
58
58
%%% @end
59
59
%%%----------------------------------------------------------------------
 
60
read(Filename=standard_io, LogDir) ->
 
61
    ?LOG("Reading config file from stdin~n", ?NOTICE),
 
62
    XML = read_stdio(),
 
63
    handle_read(catch xmerl_scan:string(XML,
 
64
                                      [{fetch_path,["/usr/share/tsung/","./"]},
 
65
                                       {validation,true}]),Filename,LogDir);
60
66
read(Filename, LogDir) ->
61
 
    case catch xmerl_scan:file(Filename,
62
 
                               [{fetch_path,["/usr/share/tsung/","./"]},
63
 
                                {validation,true}]) of
64
 
        {ok, Root = #xmlElement{}} ->  % xmerl-0.15
65
 
            ?LOGF("Reading config file: ~s~n", [Filename], ?NOTICE),
66
 
            Table = ets:new(sessiontable, [ordered_set, protected]),
67
 
            {ok, parse(Root, #config{session_tab = Table})};
68
 
        {Root = #xmlElement{}, _Tail} ->  % xmerl-0.19 and up
69
 
            ?LOGF("Reading config file: ~s~n", [Filename], ?NOTICE),
70
 
            Table = ets:new(sessiontable, [ordered_set, protected]),
71
 
            backup_config(LogDir, Filename, Root),
72
 
            {ok, parse(Root, #config{session_tab = Table, proto_opts=#proto_opts{}})};
73
 
        {error,Reason} ->
74
 
            {error, Reason};
75
 
        {'EXIT',Reason} ->
76
 
            {error, Reason}
77
 
    end.
 
67
    ?LOGF("Reading config file: ~s~n", [Filename], ?NOTICE),
 
68
    handle_read(catch xmerl_scan:file(Filename,
 
69
                                      [{fetch_path,["/usr/share/tsung/","./"]},
 
70
                                       {validation,true}]),Filename,LogDir).
 
71
 
 
72
handle_read( {Root = #xmlElement{}, _Tail}, Filename, LogDir) ->
 
73
    Table = ets:new(sessiontable, [ordered_set, protected]),
 
74
    backup_config(LogDir, Filename, Root),
 
75
    {ok, parse(Root, #config{session_tab = Table, proto_opts=#proto_opts{}})};
 
76
handle_read({error,Reason},_,_) ->
 
77
    {error, Reason};
 
78
handle_read({'EXIT',Reason},_,_) ->
 
79
    {error, Reason}.
78
80
 
79
81
%%%----------------------------------------------------------------------
80
82
%%% Function: parse/2
100
102
parse(Element = #xmlElement{name=server, attributes=Attrs}, Conf=#config{servers=ServerList}) ->
101
103
    Server = getAttr(Attrs, host),
102
104
    Port   = getAttr(integer, Attrs, port),
103
 
    Type = case getAttr(Attrs, type) of
104
 
               "ssl" -> ssl;
105
 
               "tcp" -> gen_tcp;
106
 
               "udp" -> gen_udp;
107
 
               "erlang" -> erlang
108
 
           end,
 
105
    Type = set_net_type(getAttr(Attrs, type)),
109
106
 
110
107
    lists:foldl(fun parse/2,
111
108
        Conf#config{servers = [#server{host=Server,
114
111
                                     }|ServerList]},
115
112
        Element#xmlElement.content);
116
113
 
 
114
 
 
115
 
117
116
%% Parsing the cluster monitoring element (monitor)
118
117
parse(Element = #xmlElement{name=monitor, attributes=Attrs},
119
118
      Conf = #config{monitor_hosts=MHList}) ->
131
130
                                                         community, ?config(snmp_community)),
132
131
                           Version = getAttr(atom,SnmpEl#xmlElement.attributes,
133
132
                                                       version, ?config(snmp_version)),
134
 
                           {snmp, {Port, Community, Version}};
 
133
                           %% parse OIDS def
 
134
                           TmpConf = lists:foldl(fun parse/2, Conf#config{oids=[]}, SnmpEl#xmlElement.content),
 
135
                           {snmp, {Port, Community, Version,TmpConf#config.oids}};
135
136
                       _ ->
136
137
                           {snmp, {?config(snmp_port),
137
 
                            ?config(snmp_community),
138
 
                            ?config(snmp_version)}}
 
138
                                   ?config(snmp_community),
 
139
                                   ?config(snmp_version),[]}}
139
140
                   end;
140
141
               munin ->
141
142
                   case lists:keysearch(munin,#xmlElement.name,
159
160
        Conf#config{monitor_hosts = lists:append(MHList, NewMon)},
160
161
        Element#xmlElement.content);
161
162
 
 
163
 
 
164
parse(#xmlElement{name=oid, attributes=Attrs}, Conf=#config{oids=OIDS}) ->
 
165
    OIDStr  = getAttr(Attrs, value),
 
166
    OID  = lists:map(fun erlang:list_to_integer/1, string:tokens(OIDStr,".")),
 
167
    Name = getAttr(atom, Attrs, name),
 
168
    Type = case getAttr(atom, Attrs, type, sample) of
 
169
               sample  -> sample;
 
170
               counter -> sample_counter;
 
171
               sum     -> sum
 
172
           end,
 
173
    Snippet = getAttr(string, Attrs, eval, "fun(X)-> X end."),
 
174
    Fun= ts_utils:eval(Snippet),
 
175
    true = is_function(Fun, 1),
 
176
    Conf#config{oids=[{OID,Name,Type,Fun}| OIDS]};
 
177
 
162
178
%%
163
179
parse(Element = #xmlElement{name=load, attributes=Attrs}, Conf) ->
164
180
    Loop     = getAttr(integer, Attrs, loop, 0),
206
222
                                               {unix, linux} ->
207
223
                                                   {scan, Interface};
208
224
                                               OS ->
209
 
                                                   ?LOGF("Scan interface is not supported on OS ~p, abort~n",[OS],?ERR),
 
225
                                                   io:format(standard_error,"Scan interface is not supported on OS ~p, abort~n",[OS]),
210
226
                                                   exit({error, scan_interface_not_supported_on_os})
211
227
                                           end
212
228
                                   end,
223
239
                %% must be hostname and not ip:
224
240
                case ts_utils:is_ip(Host) of
225
241
                    true ->
226
 
                        ?LOGF("ERROR: client config: 'host' attribute must be a hostname, "++
227
 
                              "not an IP ! (was ~p)~n",[Host],?EMERG),
 
242
                        io:format(standard_error,"ERROR: client config: 'host' attribute must be a hostname, "++ "not an IP ! (was ~p)~n",[Host]),
228
243
                        exit({error, badhostname});
229
244
                    false ->
230
245
                        %% add a new client for each CPU
253
268
                                     StrIP
254
269
                             end,
255
270
                 ?LOGF("resolving host ~p~n",[ToResolve],?WARN),
256
 
                 {ok,IPtmp} = inet:getaddr(ToResolve,inet),
 
271
                 {ok,IPtmp} = case inet:getaddr(ToResolve,inet) of
 
272
                                  {error,nxdomain} -> % retry with IPv6
 
273
                                      inet:getaddr(ToResolve,inet6);
 
274
                                  Val ->
 
275
                                      Val
 
276
                              end,
257
277
                 IPtmp
258
278
         end,
259
279
    ?LOGF("resolved host ~p~n",[IP],?WARN),
269
289
    Phase     = getAttr(integer,Attrs, phase),
270
290
    IDuration  = getAttr(integer, Attrs, duration),
271
291
    Unit  = getAttr(string,Attrs, unit, "second"),
272
 
    D = 1000 * to_seconds(Unit, IDuration),
 
292
    D = to_milliseconds(Unit, IDuration),
273
293
    case lists:keysearch(Phase,#arrivalphase.phase,AList) of
274
294
        false ->
275
295
            lists:foldl(fun parse/2,
279
299
                                                     |AList]},
280
300
                        Element#xmlElement.content);
281
301
        _ -> % already existing phase, wrong configuration.
282
 
            ?LOGF("Client config error: phase ~p already defined, abort !~n",[Phase],?EMERG),
 
302
            io:format(standard_error,"Client config error: phase ~p already defined, abort !~n",[Phase]),
283
303
            exit({error, already_defined_phase})
284
304
    end;
285
305
 
290
310
    Start   = getAttr(float_or_integer,Attrs, start_time),
291
311
    Unit    = getAttr(string,Attrs, unit, "second"),
292
312
    Session = getAttr(string,Attrs, session),
293
 
    Delay   = to_seconds(Unit,Start)*1000,
 
313
    Delay   = to_milliseconds(Unit,Start),
294
314
    NewUsers= Users++[{Delay,Session}],
295
315
    lists:foldl(fun parse/2, Conf#config{static_users = NewUsers},
296
316
                Element#xmlElement.content);
308
328
                    {[],[]} ->
309
329
                        exit({invalid_xml,"arrival or interarrival must be specified"});
310
330
                    {[], Rate}  when Rate > 0 ->
311
 
                        to_seconds(Unit,Rate) / 1000;
 
331
                        Rate / to_milliseconds(Unit,1);
312
332
                    {InterArrival,[]} when InterArrival > 0 ->
313
 
                        1/(1000 * to_seconds(Unit,InterArrival));
 
333
                        1/to_milliseconds(Unit,InterArrival);
314
334
                    {_Value, _Value2} ->
315
335
                        exit({invalid_xml,"arrivalrate and interarrival can't be defined simultaneously"})
316
336
                end,
383
403
%%%% Parsing the 'if' element
384
404
parse(_Element = #xmlElement{name='if', attributes=Attrs,content=Content},
385
405
      Conf = #config{session_tab = Tab, sessions=[CurS|_], curid=Id}) ->
386
 
    VarName = getAttr(atom,Attrs,var),
 
406
    VarName=get_dynvar_name(getAttr(string,Attrs,var)),
387
407
    {Rel,Value} = case getAttr(string,Attrs,eq,none) of
388
408
                none -> {neq,getAttr(string,Attrs,neq)};
389
409
                X ->  {eq,X}
393
413
    NewConf = lists:foldl(fun parse/2, Conf#config{curid=Id+1}, Content),
394
414
    NewId = NewConf#config.curid,
395
415
    ?LOGF("endif in session ~p as id ~p",[CurS#session.id,NewId+1],?INFO),
396
 
    InitialAction = {ctrl_struct, {if_start, Rel, VarName, Value , NewId+1}},
 
416
    InitialAction = {ctrl_struct, {if_start, Rel, VarName, list_to_binary(Value) , NewId+1}},
397
417
    %%NewId+1 -> id of the first action after the if
398
418
    ets:insert(Tab,{{CurS#session.id,Id+1},InitialAction}),
399
419
    NewConf;
457
477
parse(_Element = #xmlElement{name=repeat,attributes=Attrs,content=Content},
458
478
    Conf = #config{session_tab = Tab, sessions=[CurS|_], curid=Id}) ->
459
479
    MaxRepeat = getAttr(integer,Attrs,max_repeat,20),
460
 
    RepeatName = getAttr(atom,Attrs,name),
 
480
    RepeatName = get_dynvar_name(getAttr(string,Attrs,name)),
 
481
 
461
482
    [LastElement|_] = lists:reverse([E || E=#xmlElement{} <- Content]),
462
483
    case LastElement of
463
484
        #xmlElement{name=While,attributes=WhileAttrs}
470
491
            Var = getAttr(atom,WhileAttrs,var),
471
492
            NewConf = lists:foldl(fun parse/2, Conf#config{curid=Id}, Content),
472
493
            NewId = NewConf#config.curid,
473
 
            EndAction = {ctrl_struct,{repeat,RepeatName, While,Rel,Var,Value,Id+1, MaxRepeat}},
 
494
            EndAction = {ctrl_struct,{repeat,RepeatName, While,Rel,Var,list_to_binary(Value),Id+1, MaxRepeat}},
474
495
                                 %Id+1 -> id of the first action inside the loop
475
496
            ?LOGF("Add repeat action in session ~p as id ~p, Jump to: ~p",
476
497
                  [CurS#session.id,NewId+1,Id+1],?INFO),
535
556
    Port    = getAttr(integer, Attrs, port),
536
557
    Store   = getAttr(atom, Attrs, store, false),
537
558
    Restore = getAttr(atom, Attrs, restore, false),
538
 
    PType = case getAttr(Attrs, server_type) of
539
 
               "ssl" -> ssl;
540
 
               "tcp" -> gen_tcp;
541
 
               "udp" -> gen_udp;
542
 
               "erlang" -> erlang
543
 
           end,
 
559
    PType   = set_net_type(getAttr(Attrs, server_type)),
544
560
    SessType=case Conf#config.main_sess_type == CType of
545
561
                 false -> CurS#session.type;
546
562
                 true  -> CType % back to the main type
793
809
                             Delimiter = getAttr(string,Attrs,delimiter,";"),
794
810
                             {setdynvars,file,{Order,FileId,Delimiter},Vars};
795
811
                         false ->
796
 
                             ?LOGF("Unknown_file_id ~p in file setdynvars declaration: you forgot to add a file_server option~n",[FileId],?EMERG),
 
812
                             io:format(standard_error, "Unknown_file_id ~p in file setdynvars declaration: you forgot to add a file_server option~n",[FileId]),
797
813
                             exit({error, unknown_file_id})
798
814
                     end;
799
815
                 "random_string" ->
881
897
to_seconds("hour",   Val)-> Val*3600;
882
898
to_seconds("millisecond", Val)-> Val/1000.
883
899
 
 
900
to_milliseconds("second", Val)-> Val*1000;
 
901
to_milliseconds("minute", Val)-> Val*60000;
 
902
to_milliseconds("hour",   Val)-> Val*3600000;
 
903
to_milliseconds("millisecond", Val)-> Val.
 
904
 
884
905
%%%----------------------------------------------------------------------
885
906
%%% Function: get_default/2
886
907
%%%----------------------------------------------------------------------
948
969
%%   Use parsed config file to expand all ENTITY
949
970
%% @end
950
971
%%----------------------------------------------------------------------
 
972
backup_config(Dir,standard_io, Config) ->
 
973
    backup_config(Dir, "tsung_stdin.xml", Config);
951
974
backup_config(Dir, Name, Config) ->
952
975
    BaseName = filename:basename(Name),
953
976
    {ok,IOF}=file:open(filename:join(Dir,BaseName),[write]),
959
982
            ok
960
983
    end,
961
984
    file:close(IOF).
 
985
 
 
986
%% @spec read_stdio()-> string()
 
987
%% @doc Read config from standard input
 
988
%% @end
 
989
read_stdio()->
 
990
    read_stdio(io:get_line(""),[]).
 
991
 
 
992
read_stdio(eof, Data)->
 
993
    lists:flatten(Data);
 
994
read_stdio(Data,Acc) ->
 
995
    read_stdio(io:get_line(""),[Acc,Data]).
 
996
 
 
997
set_net_type("tcp")  -> gen_tcp;
 
998
set_net_type("tcp6") -> gen_tcp6;
 
999
set_net_type("udp")  -> gen_udp;
 
1000
set_net_type("udp6") -> gen_udp6;
 
1001
set_net_type("ssl")  -> ssl;
 
1002
set_net_type("ssl6") -> ssl6.
 
1003
 
 
1004
get_dynvar_name(VarNameStr) ->
 
1005
    %% check if the var name is for an array (myvar[N])
 
1006
    case re:run(VarNameStr,"(.+)\[(\d+)\]",[{capture,all_but_first,list},dotall]) of
 
1007
        {match,[Name,Index]} -> {list_to_atom(Name),Index};
 
1008
        _                    -> list_to_atom(VarNameStr)
 
1009
    end.