From 9eefebadc2e2563b6d044f2f2e230294b9d00053 Mon Sep 17 00:00:00 2001 From: Mark Tran Date: Sat, 2 Jul 2016 00:03:53 +0700 Subject: [PATCH 1/8] rename to README.txt --- ejabberd_auth_http/{README.md => README.txt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename ejabberd_auth_http/{README.md => README.txt} (100%) diff --git a/ejabberd_auth_http/README.md b/ejabberd_auth_http/README.txt similarity index 100% rename from ejabberd_auth_http/README.md rename to ejabberd_auth_http/README.txt From f806442b9cd7a4c62703005e0c45f74df631bc07 Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 6 Jul 2016 12:48:53 +0200 Subject: [PATCH 2/8] Add mod_opt_type callback function desired by gen_mod (#163) --- mod_rest/src/mod_rest.erl | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/mod_rest/src/mod_rest.erl b/mod_rest/src/mod_rest.erl index a950fd9..49736a0 100644 --- a/mod_rest/src/mod_rest.erl +++ b/mod_rest/src/mod_rest.erl @@ -29,8 +29,8 @@ -export([start/2, stop/1, split_line/1, - process/2 - ]). + process/2, + mod_opt_type/1]). -include("ejabberd.hrl"). -include("logger.hrl"). @@ -179,3 +179,14 @@ splitend([92, 34], Res) -> {"", Res}; splitend([34, 32 | Line], Res) -> {Line, Res}; splitend([92, 34, 32 | Line], Res) -> {Line, Res}; splitend([Char | Line], Res) -> splitend(Line, [Char | Res]). + +mod_opt_type(allowed_ips) -> + fun (all) -> all; (A) when is_list(A) -> A end; +mod_opt_type(allowed_destinations) -> + fun (all) -> all; (A) when is_list(A) -> A end; +mod_opt_type(allowed_stanza_types) -> + fun (all) -> all; (A) when is_list(A) -> A end; +mod_opt_type(access_commands) -> + fun (A) when is_list(A) -> A end; +mod_opt_type(_) -> + [allowed_ips, allowed_destinations, allowed_stanza_types, access_commands]. From e2ebd1a405613d52526e3d8ad9871d89883ea109 Mon Sep 17 00:00:00 2001 From: xmppjingle Date: Thu, 14 Jul 2016 10:30:17 -0300 Subject: [PATCH 3/8] mod_grafite Initial Commit --- mod_grafite/mod_grafite.erl | 183 ++++++++++++++++++++++++++++++++++++ 1 file changed, 183 insertions(+) create mode 100644 mod_grafite/mod_grafite.erl diff --git a/mod_grafite/mod_grafite.erl b/mod_grafite/mod_grafite.erl new file mode 100644 index 0000000..d7dee68 --- /dev/null +++ b/mod_grafite/mod_grafite.erl @@ -0,0 +1,183 @@ +%%%---------------------------------------------------------------------- +%%% File : mod_grafite.erl +%%% Author : Thiago Rocha Camargo +%%% Purpose : Calculates and gathers statistics actively +%%% Created : +%%% Id : $Id: mod_grafite.erl 0000 2016-07-11 16:42:30Z xmppjingle $ +%%%---------------------------------------------------------------------- + +%%%% Definitions + +-module(mod_grafite). +-author('rochacamargothiago@gmail.com'). +-behaviour(gen_mod). + +-include("ejabberd.hrl"). +-include("logger.hrl"). +-include("jlib.hrl"). + +-define(HOOKS, [offline_message_hook, + sm_register_connection_hook, sm_remove_connection_hook, + user_send_packet, user_receive_packet, + s2s_send_packet, s2s_receive_packet, + remove_user, register_user, component_register]). + +-export([start/2, stop/1, mod_opt_type/1, + depends/2, udp_loop_start/1]). + +-export([offline_message_hook/3, + sm_register_connection_hook/3, sm_remove_connection_hook/3, + user_send_packet/4, user_receive_packet/5, + s2s_send_packet/3, s2s_receive_packet/3, + remove_user/2, register_user/2, component_register/1]). + +-record(state, {socket, host, port}). + +-define(PROCNAME, ejabberd_mod_grafite). + +%%==================================================================== +%% API +%%==================================================================== + +start(Host, Opts) -> + [ejabberd_hooks:add(Hook, Host, ?MODULE, Hook, 20) + || Hook <- ?HOOKS], + StatsDHost = gen_mod:get_opt(statsdhost, Opts, fun(X) -> X end, "localhost"), + StatsDPort = gen_mod:get_opt(statsdport, Opts, fun(X) -> X end, 5002), + register(?PROCNAME, spawn(?MODULE, udp_loop_start, [#state{host = getaddrs(StatsDHost), port = StatsDPort}])). + +stop(Host) -> + [ejabberd_hooks:delete(Hook, Host, ?MODULE, Hook, 20) + || Hook <- ?HOOKS]. + +depends(_Host, _Opts) -> + []. + +%%==================================================================== +%% Hooks handlers +%%==================================================================== + +offline_message_hook(_From, #jid{lserver=LServer}, _Packet) -> + push(LServer, offline_message). + +sm_register_connection_hook(_SID, #jid{lserver=LServer}, _Info) -> + push(LServer, sm_register_connection). +sm_remove_connection_hook(_SID, #jid{lserver=LServer}, _Info) -> + push(LServer, sm_remove_connection). + +user_send_packet(Packet, _C2SState, #jid{lserver=LServer}, _To) -> + push(LServer, user_send_packet), + Packet. +user_receive_packet(Packet, _C2SState, _JID, _From, #jid{lserver=LServer}) -> + push(LServer, user_receive_packet), + Packet. + +s2s_send_packet(#jid{lserver=LServer}, _To, _Packet) -> + push(LServer, s2s_send_packet). +s2s_receive_packet(_From, #jid{lserver=LServer}, _Packet) -> + push(LServer, s2s_receive_packet). + +remove_user(_User, Server) -> + push(jid:nameprep(Server), remove_user). +register_user(_User, Server) -> + push(jid:nameprep(Server), register_user). + +component_register(Host) -> + push(Host, component_register). + +%%==================================================================== +%% metrics push handler +%%==================================================================== + +push(Host, Probe) -> + Payload = encode_metrics(Host, Probe), + whereis(?PROCNAME) ! {send, Payload}. + +encode_metrics(Host, Probe) -> + [_, NodeId] = str:tokens(jlib:atom_to_binary(node()), <<"@">>), + [Node | _] = str:tokens(NodeId, <<".">>), + BaseId = <>, + DateTime = erlang:universaltime(), + UnixTime = calendar:datetime_to_gregorian_seconds(DateTime) - 62167219200, + TS = integer_to_binary(UnixTime), + Data = case Probe of + {Key, Val} -> + BVal = integer_to_binary(Val), + <>; + Key -> + <> + end, + ?INFO_MSG("Stats: ~p ~p ~n", [Data, encode(gauge, Key, 1, undefined)]), + Data. + +%%==================================================================== +%% Grafite/StatsD +%%==================================================================== + +encode(gauge, Key, Value, _SampleRate) -> + [Key, ":", format_value(Value), "|g"]. + +format_value(Value) when is_integer(Value) -> + integer_to_list(Value); +format_value(Value) when is_float(Value) -> + float_to_list(Value, [{decimals, 2}]). + +%%==================================================================== +%% UDP Utils +%%==================================================================== + +udp_loop_start(#state{}=S) -> + LocalPort = 44444, + case gen_udp:open(LocalPort) of + {ok, Socket} -> + ?INFO_MSG("UDP Stats Socket Open: [~p]~n", [LocalPort]), + udp_loop(S#state{socket = Socket}); + _ -> + ?INFO_MSG("Could not start UDP Socket [~p]~n", [LocalPort]) + end. + +udp_loop(#state{} = S) -> + receive + {send, Packet} -> + send_udp(Packet, S), + udp_loop(S); + _ -> + ok + end. + +send_udp(Payload, #state{socket = Socket, host = Host, port = Port} = State) -> + gen_udp:send(Socket, Host, Port, Payload), + {ok, State}. + +getaddrs({_, _, _, _} = Address) -> + {ok, Address}; +getaddrs(Hostname) when is_binary(Hostname) -> + getaddrs(binary_to_list(Hostname)); +getaddrs(Hostname) -> + case inet:getaddrs(Hostname, inet) of + {ok, Addrs} -> + {ok, random_element(Addrs)}; + {error, Reason} -> + ?ERROR_MSG("getaddrs error: ~p~n", [Reason]), + {error, Reason} + end. + +random_element([Element]) -> + Element; +random_element([_|_] = List) -> + T = list_to_tuple(List), + Index = random(tuple_size(T)), + element(Index, T). + +random(N) -> + erlang:phash2({self(), timestamp()}, N) + 1. + +timestamp() -> + os:timestamp(). + +mod_opt_type(statsdhost) -> fun(X) -> X end; +mod_opt_type(statsdport) -> fun(X) when is_integer(X) -> X end; +mod_opt_type(_) -> + [statsdhost, statsdport]. From 098a810843a11ccfd7476cf55a799694172ebd15 Mon Sep 17 00:00:00 2001 From: xmppjingle Date: Mon, 18 Jul 2016 15:45:54 -0300 Subject: [PATCH 4/8] First Working Version --- mod_grafite/mod_grafite.erl | 64 +++++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 24 deletions(-) diff --git a/mod_grafite/mod_grafite.erl b/mod_grafite/mod_grafite.erl index d7dee68..dbcca79 100644 --- a/mod_grafite/mod_grafite.erl +++ b/mod_grafite/mod_grafite.erl @@ -1,7 +1,7 @@ %%%---------------------------------------------------------------------- %%% File : mod_grafite.erl %%% Author : Thiago Rocha Camargo -%%% Purpose : Calculates and gathers statistics actively +%%% Purpose : Gathers statistics and publishes via statsd/grafite %%% Created : %%% Id : $Id: mod_grafite.erl 0000 2016-07-11 16:42:30Z xmppjingle $ %%%---------------------------------------------------------------------- @@ -20,20 +20,27 @@ sm_register_connection_hook, sm_remove_connection_hook, user_send_packet, user_receive_packet, s2s_send_packet, s2s_receive_packet, - remove_user, register_user, component_register]). + remove_user, register_user]). + +-define(GLOBAL_HOOKS, [component_connected, component_disconnected]). -export([start/2, stop/1, mod_opt_type/1, - depends/2, udp_loop_start/1]). + depends/2, udp_loop_start/1, push/2]). -export([offline_message_hook/3, sm_register_connection_hook/3, sm_remove_connection_hook/3, user_send_packet/4, user_receive_packet/5, s2s_send_packet/3, s2s_receive_packet/3, - remove_user/2, register_user/2, component_register/1]). + remove_user/2, register_user/2, component_connected/1, + component_disconnected/1]). -record(state, {socket, host, port}). -define(PROCNAME, ejabberd_mod_grafite). +-define(GRAFITE_KEY(Node, Host, Probe), "mod_grafite.ejabberd." ++ + erlang:binary_to_list(Node) ++ "_" ++ + erlang:binary_to_list(Host) ++ "." ++ + erlang:atom_to_list(Probe)). %%==================================================================== %% API @@ -42,9 +49,12 @@ start(Host, Opts) -> [ejabberd_hooks:add(Hook, Host, ?MODULE, Hook, 20) || Hook <- ?HOOKS], - StatsDHost = gen_mod:get_opt(statsdhost, Opts, fun(X) -> X end, "localhost"), - StatsDPort = gen_mod:get_opt(statsdport, Opts, fun(X) -> X end, 5002), - register(?PROCNAME, spawn(?MODULE, udp_loop_start, [#state{host = getaddrs(StatsDHost), port = StatsDPort}])). + [ejabberd_hooks:add(Hook, ?MODULE, Hook, 18) + || Hook <- ?GLOBAL_HOOKS], + StatsDH = gen_mod:get_opt(statsdhost, Opts, fun(X) -> X end, "localhost"), + {ok, StatsDHost} = getaddrs(StatsDH), + StatsDPort = gen_mod:get_opt(statsdport, Opts, fun(X) -> X end, 8125), + register(?PROCNAME, spawn(?MODULE, udp_loop_start, [#state{host = StatsDHost, port = StatsDPort}])). stop(Host) -> [ejabberd_hooks:delete(Hook, Host, ?MODULE, Hook, 20) @@ -82,8 +92,12 @@ remove_user(_User, Server) -> register_user(_User, Server) -> push(jid:nameprep(Server), register_user). -component_register(Host) -> - push(Host, component_register). +component_connected(Host) -> + push(Host, component_connected). + +component_disconnected(Host) -> + push(Host, component_disconnected). + %%==================================================================== %% metrics push handler @@ -96,18 +110,11 @@ push(Host, Probe) -> encode_metrics(Host, Probe) -> [_, NodeId] = str:tokens(jlib:atom_to_binary(node()), <<"@">>), [Node | _] = str:tokens(NodeId, <<".">>), - BaseId = <>, - DateTime = erlang:universaltime(), - UnixTime = calendar:datetime_to_gregorian_seconds(DateTime) - 62167219200, - TS = integer_to_binary(UnixTime), Data = case Probe of {Key, Val} -> - BVal = integer_to_binary(Val), - <>; + encode(gauge, ?GRAFITE_KEY(Node, Host, Probe), Val, 1.0); Key -> - <> + encode(gauge, ?GRAFITE_KEY(Node, Host, Probe), 1, 1.0) end, ?INFO_MSG("Stats: ~p ~p ~n", [Data, encode(gauge, Key, 1, undefined)]), Data. @@ -124,6 +131,7 @@ format_value(Value) when is_integer(Value) -> format_value(Value) when is_float(Value) -> float_to_list(Value, [{decimals, 2}]). + %%==================================================================== %% UDP Utils %%==================================================================== @@ -140,16 +148,20 @@ udp_loop_start(#state{}=S) -> udp_loop(#state{} = S) -> receive - {send, Packet} -> - send_udp(Packet, S), - udp_loop(S); + {send, Packet} -> + send_udp(Packet, S), + udp_loop(S); _ -> - ok + udp_loop(S) end. send_udp(Payload, #state{socket = Socket, host = Host, port = Port} = State) -> - gen_udp:send(Socket, Host, Port, Payload), - {ok, State}. + case gen_udp:send(Socket, Host, Port, Payload) of + ok -> + ok; + _Error -> + ?INFO_MSG("UDP Send Failed: [~p] (~p)~n", [State, Payload]) + end. getaddrs({_, _, _, _} = Address) -> {ok, Address}; @@ -177,6 +189,10 @@ random(N) -> timestamp() -> os:timestamp(). +%%==================================================================== +%% mod Options +%%==================================================================== + mod_opt_type(statsdhost) -> fun(X) -> X end; mod_opt_type(statsdport) -> fun(X) when is_integer(X) -> X end; mod_opt_type(_) -> From ed3853ccf941cb17c6fdcf4e9f125173d767d8eb Mon Sep 17 00:00:00 2001 From: xmppjingle Date: Mon, 18 Jul 2016 16:01:52 -0300 Subject: [PATCH 5/8] Complete Module Skeleton --- mod_grafite/README.md | 35 +++++++++++++++++++++++++++ mod_grafite/conf/mod_grafite.yml | 5 ++++ mod_grafite/mod_grafite.spec | 5 ++++ mod_grafite/{ => src}/mod_grafite.erl | 0 4 files changed, 45 insertions(+) create mode 100644 mod_grafite/README.md create mode 100644 mod_grafite/conf/mod_grafite.yml create mode 100644 mod_grafite/mod_grafite.spec rename mod_grafite/{ => src}/mod_grafite.erl (100%) diff --git a/mod_grafite/README.md b/mod_grafite/README.md new file mode 100644 index 0000000..6153198 --- /dev/null +++ b/mod_grafite/README.md @@ -0,0 +1,35 @@ + +mod_grafite - Gathers statistics and publishes via statsd/grafite +author: Thiago Rocha Camargo (rochacamargothiago@gmail.com) + + mod_grafite + ============== + +Gathers statistics and publishes via statsd/grafite + + CONFIGURE + --------- + +Enable the module in ejabberd.yml for example with a basic configuration: +modules: + mod_grafite: + statsdhost: "carbonr.xmpp.com.br" + statsdport: 8125 + +Configurable options: + statsdhost: Host of the statsd server + statsdport: Port of the statsd server + + EXAMPLE CONFIGURATION + --------------------- + +modules: + mod_grafite: + statsdhost: "carbonr.xmpp.com.br" + statsdport: 8125 + + FEATURE REQUESTS + ---------------- + + - Add support for configurable Hooks + diff --git a/mod_grafite/conf/mod_grafite.yml b/mod_grafite/conf/mod_grafite.yml new file mode 100644 index 0000000..6c47a33 --- /dev/null +++ b/mod_grafite/conf/mod_grafite.yml @@ -0,0 +1,5 @@ +modules: + mod_grafite: + statsdhost: "carbonr.xmpp.com.br" + statsdport: 8125 + \ No newline at end of file diff --git a/mod_grafite/mod_grafite.spec b/mod_grafite/mod_grafite.spec new file mode 100644 index 0000000..1cb670a --- /dev/null +++ b/mod_grafite/mod_grafite.spec @@ -0,0 +1,5 @@ +author: "Thiago Rocha Camargo " +category: "statistics" +summary: "Publishes Statistics via statsd/grafite" +home: "https://github.com/processone/ejabberd-contrib/tree/master/" +url: "git@github.com:processone/ejabberd-contrib.git" diff --git a/mod_grafite/mod_grafite.erl b/mod_grafite/src/mod_grafite.erl similarity index 100% rename from mod_grafite/mod_grafite.erl rename to mod_grafite/src/mod_grafite.erl From 0aa5516e04af7189bb4d2f9297e095ffca3bf9ff Mon Sep 17 00:00:00 2001 From: xmppjingle Date: Fri, 22 Jul 2016 15:00:38 -0300 Subject: [PATCH 6/8] Remove Global Hooks upon module stop --- mod_grafite/src/mod_grafite.erl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mod_grafite/src/mod_grafite.erl b/mod_grafite/src/mod_grafite.erl index dbcca79..e707b39 100644 --- a/mod_grafite/src/mod_grafite.erl +++ b/mod_grafite/src/mod_grafite.erl @@ -58,7 +58,9 @@ start(Host, Opts) -> stop(Host) -> [ejabberd_hooks:delete(Hook, Host, ?MODULE, Hook, 20) - || Hook <- ?HOOKS]. + || Hook <- ?HOOKS], + [ejabberd_hooks:delete(Hook, Host, ?MODULE, Hook, 20) + || Hook <- ?GLOBAL_HOOKS]. depends(_Host, _Opts) -> []. From 065ab085924e96ca0eedc287c5aa5018f766859a Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 25 Jul 2016 16:57:34 +0200 Subject: [PATCH 7/8] mod_rest allowing ip range (#175) --- mod_rest/src/mod_rest.erl | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/mod_rest/src/mod_rest.erl b/mod_rest/src/mod_rest.erl index 49736a0..9239025 100644 --- a/mod_rest/src/mod_rest.erl +++ b/mod_rest/src/mod_rest.erl @@ -127,17 +127,7 @@ check_stanza(Stanza, _From, To, Host) -> check_member_option(Host, ClientIp, allowed_ips) -> true = case try_get_option(Host, allowed_ips, all) of all -> true; - AllowedValues -> - case lists:all(fun(El) -> is_binary(El) end, AllowedValues) of - true -> - AllowedIps = lists:map(fun(El) -> - binary_to_ip_tuple(El) - end, - AllowedValues), - lists:member(ClientIp, AllowedIps); - false -> - lists:member(ClientIp, AllowedValues) - end + AllowedValues -> ip_matches(ClientIp, AllowedValues) end; check_member_option(Host, Element, Option) -> true = case try_get_option(Host, Option, all) of @@ -145,9 +135,12 @@ check_member_option(Host, Element, Option) -> AllowedValues -> lists:member(Element, AllowedValues) end. -binary_to_ip_tuple(IpAddress) when is_binary(IpAddress) -> - {ok, IpTuple} = inet_parse:address(binary_to_list(IpAddress)), - IpTuple. +ip_matches(ClientIp, AllowedValues) -> + lists:any(fun(El) -> + {ok, Net, Mask} = acl:parse_ip_netmask(El), + acl:acl_rule_matches({ip,{Net,Mask}}, #{ip => {ClientIp,port}}, host) + end, + AllowedValues). post_request(Stanza, From, To) -> case ejabberd_router:route(From, To, Stanza) of From 41371cf7fed4e4a53a24e8e27e75d409171d4e11 Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 1 Aug 2016 21:18:20 +0200 Subject: [PATCH 8/8] Update mod_rest documentation to reflect module_install (#177)) --- mod_rest/README.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mod_rest/README.txt b/mod_rest/README.txt index d3a8fa8..92a74a9 100644 --- a/mod_rest/README.txt +++ b/mod_rest/README.txt @@ -17,16 +17,16 @@ This module can also be used as a frontend to execute ejabberd commands. CONFIGURATION ============= -To use this module, follow the general build instructions, and configure -in ejabberd.yml as described. +To use this module, follow the general build instructions. +You can modify the default module configuration file like this: -Enable the module: +To enable the module: modules: mod_rest: allowed_ips: - "127.0.0.1" -And enable the HTTP request handler in the listen section: +To enable the HTTP request handler in the listen section: listen: - port: 5285 @@ -40,7 +40,7 @@ With that configuration, you can send HTTP POST requests to the URL: Configurable options: allowed_ips: IP addresses that can use the rest service. - Allowed values: 'all' or a list of Erlang tuples. + Allowed values: 'all' or a list of Erlang strings. Default value: all Notice that the IP address is checked after the connection is established. If you want to restrict the IP address that listens connections, and