summaryrefslogtreecommitdiff
path: root/src/rabbit.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/rabbit.erl')
-rw-r--r--src/rabbit.erl282
1 files changed, 282 insertions, 0 deletions
diff --git a/src/rabbit.erl b/src/rabbit.erl
new file mode 100644
index 0000000000..e65d532b2a
--- /dev/null
+++ b/src/rabbit.erl
@@ -0,0 +1,282 @@
+%% The contents of this file are subject to the Mozilla Public License
+%% Version 1.1 (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.mozilla.org/MPL/
+%%
+%% 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.
+%%
+%% The Original Code is RabbitMQ.
+%%
+%% The Initial Developers of the Original Code are LShift Ltd.,
+%% Cohesive Financial Technologies LLC., and Rabbit Technologies Ltd.
+%%
+%% Portions created by LShift Ltd., Cohesive Financial Technologies
+%% LLC., and Rabbit Technologies Ltd. are Copyright (C) 2007-2008
+%% LShift Ltd., Cohesive Financial Technologies LLC., and Rabbit
+%% Technologies Ltd.;
+%%
+%% All Rights Reserved.
+%%
+%% Contributor(s): ______________________________________.
+%%
+
+-module(rabbit).
+
+-behaviour(application).
+
+-export([start/0, stop/0, stop_and_halt/0, status/0]).
+
+-export([start/2, stop/1]).
+
+-import(application).
+-import(mnesia).
+-import(lists).
+-import(inet).
+-import(gen_tcp).
+
+-include("rabbit_framing.hrl").
+-include("rabbit.hrl").
+
+-define(APPS, [os_mon, mnesia, rabbit]).
+
+%%----------------------------------------------------------------------------
+
+-ifdef(use_specs).
+
+-spec(start/0 :: () -> 'ok').
+-spec(stop/0 :: () -> 'ok').
+-spec(stop_and_halt/0 :: () -> 'ok').
+-spec(status/0 :: () ->
+ [{running_applications, [{atom(), string(), string()}]} |
+ {nodes, [node()]} |
+ {running_nodes, [node()]}]).
+
+-endif.
+
+%%----------------------------------------------------------------------------
+
+start() ->
+ try
+ ok = ensure_working_log_config(),
+ ok = rabbit_mnesia:ensure_mnesia_dir(),
+ ok = start_applications(?APPS)
+ after
+ %%give the error loggers some time to catch up
+ timer:sleep(100)
+ end.
+
+stop() ->
+ ok = stop_applications(?APPS).
+
+stop_and_halt() ->
+ spawn(fun () ->
+ SleepTime = 1000,
+ rabbit_log:info("Stop-and-halt request received; halting in ~p milliseconds~n",
+ [SleepTime]),
+ timer:sleep(SleepTime),
+ init:stop()
+ end),
+ case catch stop() of _ -> ok end.
+
+status() ->
+ [{running_applications, application:which_applications()}] ++
+ rabbit_mnesia:status().
+
+%%--------------------------------------------------------------------
+
+manage_applications(Iterate, Do, Undo, SkipError, ErrorTag, Apps) ->
+ Iterate(fun (App, Acc) ->
+ case Do(App) of
+ ok -> [App | Acc];
+ {error, {SkipError, _}} -> Acc;
+ {error, Reason} ->
+ lists:foreach(Undo, Acc),
+ throw({error, {ErrorTag, App, Reason}})
+ end
+ end, [], Apps),
+ ok.
+
+start_applications(Apps) ->
+ manage_applications(fun lists:foldl/3,
+ fun application:start/1,
+ fun application:stop/1,
+ already_started,
+ cannot_start_application,
+ Apps).
+
+stop_applications(Apps) ->
+ manage_applications(fun lists:foldr/3,
+ fun application:stop/1,
+ fun application:start/1,
+ not_started,
+ cannot_stop_application,
+ Apps).
+
+start(normal, []) ->
+
+ {ok, SupPid} = rabbit_sup:start_link(),
+
+ print_banner(),
+
+ {ok, ExtraSteps} = application:get_env(extra_startup_steps),
+
+ lists:foreach(
+ fun ({Msg, Thunk}) ->
+ io:format("starting ~-20s ...", [Msg]),
+ Thunk(),
+ io:format("done~n");
+ ({Msg, M, F, A}) ->
+ io:format("starting ~-20s ...", [Msg]),
+ apply(M, F, A),
+ io:format("done~n")
+ end,
+ [{"database",
+ fun () -> ok = rabbit_mnesia:init() end},
+ {"core processes",
+ fun () ->
+ ok = start_child(rabbit_log),
+
+ ok = rabbit_amqqueue:start(),
+
+ ok = rabbit_binary_generator:
+ check_empty_content_body_frame_size(),
+
+ ok = start_child(rabbit_router),
+ ok = start_child(rabbit_node_monitor)
+ end},
+ {"recovery",
+ fun () ->
+ ok = maybe_insert_default_data(),
+
+ ok = rabbit_exchange:recover(),
+ ok = rabbit_amqqueue:recover(),
+ ok = rabbit_realm:recover()
+ end},
+ {"persister",
+ fun () ->
+ ok = start_child(rabbit_persister)
+ end},
+ {"builtin applications",
+ fun () ->
+ {ok, DefaultVHost} = application:get_env(default_vhost),
+ ok = error_logger:add_report_handler(
+ rabbit_error_logger, [DefaultVHost]),
+ ok = start_builtin_amq_applications()
+ end},
+ {"TCP listeners",
+ fun () ->
+ ok = rabbit_networking:start(),
+ {ok, TCPListeners} = application:get_env(tcp_listeners),
+ lists:foreach(
+ fun ({Host, Port}) ->
+ ok = rabbit_networking:start_tcp_listener(Host, Port)
+ end,
+ TCPListeners)
+ end}]
+ ++ ExtraSteps),
+
+ io:format("~nbroker running~n"),
+
+ {ok, SupPid}.
+
+stop(_State) ->
+ terminated_ok = error_logger:delete_report_handler(rabbit_error_logger),
+ ok.
+
+%---------------------------------------------------------------------------
+
+print_banner() ->
+ {ok, Product} = application:get_key(id),
+ {ok, Version} = application:get_key(vsn),
+ io:format("~s ~s (AMQP ~p-~p)~n~s~n~s~n~n",
+ [Product, Version,
+ ?PROTOCOL_VERSION_MAJOR, ?PROTOCOL_VERSION_MINOR,
+ ?COPYRIGHT_MESSAGE, ?INFORMATION_MESSAGE]),
+ io:format("Logging to ~p~nSASL logging to ~p~n~n",
+ [error_log_location(), sasl_log_location()]).
+
+start_child(Mod) ->
+ {ok,_} = supervisor:start_child(rabbit_sup,
+ {Mod, {Mod, start_link, []},
+ transient, 100, worker, [Mod]}),
+ ok.
+
+maybe_insert_default_data() ->
+ case rabbit_mnesia:is_db_empty() of
+ true -> insert_default_data();
+ false -> ok
+ end.
+
+insert_default_data() ->
+ {ok, DefaultUser} = application:get_env(default_user),
+ {ok, DefaultPass} = application:get_env(default_pass),
+ {ok, DefaultVHost} = application:get_env(default_vhost),
+ ok = rabbit_access_control:add_vhost(DefaultVHost),
+ ok = insert_default_user(DefaultUser, DefaultPass,
+ [{DefaultVHost, [<<"/data">>, <<"/admin">>]}]),
+ ok.
+
+insert_default_user(Username, Password, VHostSpecs) ->
+ ok = rabbit_access_control:add_user(Username, Password),
+ lists:foreach(
+ fun ({VHostPath, Realms}) ->
+ ok = rabbit_access_control:map_user_vhost(
+ Username, VHostPath),
+ lists:foreach(
+ fun (Realm) ->
+ RealmFullName =
+ rabbit_misc:r(VHostPath, realm, Realm),
+ ok = rabbit_access_control:map_user_realm(
+ Username,
+ rabbit_access_control:full_ticket(
+ RealmFullName))
+ end, Realms)
+ end, VHostSpecs),
+ ok.
+
+start_builtin_amq_applications() ->
+ %%TODO: we may want to create a separate supervisor for these so
+ %%they don't bring down the entire app when they die and fail to
+ %%restart
+ ok.
+
+ensure_working_log_config() ->
+ case error_logger:logfile(filename) of
+ {error, no_log_file} ->
+ %% either no log file was configured or opening it failed.
+ case application:get_env(kernel, error_logger) of
+ {ok, {file, Filename}} ->
+ case filelib:ensure_dir(Filename) of
+ ok -> ok;
+ {error, Reason1} ->
+ throw({error, {cannot_log_to_file,
+ Filename, Reason1}})
+ end,
+ case error_logger:logfile({open, Filename}) of
+ ok -> ok;
+ {error, Reason2} ->
+ throw({error, {cannot_log_to_file,
+ Filename, Reason2}})
+ end;
+ _ -> ok
+ end;
+ _Filename -> ok
+ end.
+
+error_log_location() ->
+ case error_logger:logfile(filename) of
+ {error,no_log_file} -> tty;
+ File -> File
+ end.
+
+sasl_log_location() ->
+ case application:get_env(sasl, sasl_error_logger) of
+ {ok, {file, File}} -> File;
+ {ok, false} -> undefined;
+ {ok, tty} -> tty;
+ {ok, Bad} -> throw({error, {cannot_log_to_file, Bad}});
+ _ -> undefined
+ end.