1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
|
%% This Source Code Form is subject to the terms of the Mozilla Public
%% License, v. 2.0. If a copy of the MPL was not distributed with this
%% file, You can obtain one at https://mozilla.org/MPL/2.0/.
%%
%% Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
%%
-module(rabbit_boot_steps).
-export([run_boot_steps/0, run_boot_steps/1, run_cleanup_steps/1]).
-export([find_steps/0, find_steps/1]).
run_boot_steps() ->
run_boot_steps(loaded_applications()).
run_boot_steps(Apps) ->
[begin
rabbit_log:info("Running boot step ~s defined by app ~s", [Step, App]),
ok = run_step(Attrs, mfa)
end || {App, Step, Attrs} <- find_steps(Apps)],
ok.
run_cleanup_steps(Apps) ->
[run_step(Attrs, cleanup) || {_, _, Attrs} <- find_steps(Apps)],
ok.
loaded_applications() ->
[App || {App, _, _} <- application:loaded_applications()].
find_steps() ->
find_steps(loaded_applications()).
find_steps(Apps) ->
All = sort_boot_steps(rabbit_misc:all_module_attributes(rabbit_boot_step)),
[Step || {App, _, _} = Step <- All, lists:member(App, Apps)].
run_step(Attributes, AttributeName) ->
[begin
rabbit_log:debug("Applying MFA: M = ~s, F = ~s, A = ~p",
[M, F, A]),
case apply(M,F,A) of
ok -> ok;
{error, Reason} -> exit({error, Reason})
end
end
|| {Key, {M,F,A}} <- Attributes,
Key =:= AttributeName],
ok.
vertices({AppName, _Module, Steps}) ->
[{StepName, {AppName, StepName, Atts}} || {StepName, Atts} <- Steps].
edges({_AppName, _Module, Steps}) ->
EnsureList = fun (L) when is_list(L) -> L;
(T) -> [T]
end,
[case Key of
requires -> {StepName, OtherStep};
enables -> {OtherStep, StepName}
end || {StepName, Atts} <- Steps,
{Key, OtherStepOrSteps} <- Atts,
OtherStep <- EnsureList(OtherStepOrSteps),
Key =:= requires orelse Key =:= enables].
sort_boot_steps(UnsortedSteps) ->
case rabbit_misc:build_acyclic_graph(fun vertices/1, fun edges/1,
UnsortedSteps) of
{ok, G} ->
%% Use topological sort to find a consistent ordering (if
%% there is one, otherwise fail).
SortedSteps = lists:reverse(
[begin
{StepName, Step} = digraph:vertex(G,
StepName),
Step
end || StepName <- digraph_utils:topsort(G)]),
digraph:delete(G),
%% Check that all mentioned {M,F,A} triples are exported.
case [{StepName, {M,F,A}} ||
{_App, StepName, Attributes} <- SortedSteps,
{mfa, {M,F,A}} <- Attributes,
code:ensure_loaded(M) =/= {module, M} orelse
not erlang:function_exported(M, F, length(A))] of
[] -> SortedSteps;
MissingFns -> exit({boot_functions_not_exported, MissingFns})
end;
{error, {vertex, duplicate, StepName}} ->
exit({duplicate_boot_step, StepName});
{error, {edge, Reason, From, To}} ->
exit({invalid_boot_step_dependency, From, To, Reason})
end.
|