1%% This Source Code Form is subject to the terms of the Mozilla Public
2%% License, v. 2.0. If a copy of the MPL was not distributed with this
3%% file, You can obtain one at https://mozilla.org/MPL/2.0/.
4%%
5%% Copyright (c) 2007-2021 VMware, Inc. or its affiliates.  All rights reserved.
6%%
7
8-module(rabbit_shovel_sup).
9-behaviour(supervisor2).
10
11-export([start_link/0, init/1]).
12
13-import(rabbit_shovel_config, []).
14
15-include("rabbit_shovel.hrl").
16
17start_link() ->
18    case parse_configuration(application:get_env(shovels)) of
19        {ok, Configurations} ->
20            supervisor2:start_link({local, ?MODULE}, ?MODULE, [Configurations]);
21        {error, Reason} ->
22            {error, Reason}
23    end.
24
25init([Configurations]) ->
26    Len = dict:size(Configurations),
27    ChildSpecs = [{rabbit_shovel_status,
28                   {rabbit_shovel_status, start_link, []},
29                   transient, 16#ffffffff, worker,
30                   [rabbit_shovel_status]},
31                  {rabbit_shovel_dyn_worker_sup_sup,
32                   {rabbit_shovel_dyn_worker_sup_sup, start_link, []},
33                   transient, 16#ffffffff, supervisor,
34                   [rabbit_shovel_dyn_worker_sup_sup]} |
35                  make_child_specs(Configurations)],
36    {ok, {{one_for_one, 2*Len, 2}, ChildSpecs}}.
37
38make_child_specs(Configurations) ->
39    dict:fold(
40      fun (ShovelName, ShovelConfig, Acc) ->
41              [{ShovelName,
42                {rabbit_shovel_worker_sup, start_link,
43                    [ShovelName, ShovelConfig]},
44                permanent,
45                16#ffffffff,
46                supervisor,
47                [rabbit_shovel_worker_sup]} | Acc]
48      end, [], Configurations).
49
50parse_configuration(undefined) ->
51    {ok, dict:new()};
52parse_configuration({ok, Env}) ->
53    {ok, Defaults} = application:get_env(defaults),
54    parse_configuration(Defaults, Env, dict:new()).
55
56parse_configuration(_Defaults, [], Acc) ->
57    {ok, Acc};
58parse_configuration(Defaults, [{ShovelName, ShovelConfig} | Env], Acc)
59  when is_atom(ShovelName) andalso is_list(ShovelConfig) ->
60    case dict:is_key(ShovelName, Acc) of
61        true  -> {error, {duplicate_shovel_definition, ShovelName}};
62        false -> case validate_shovel_config(ShovelName, ShovelConfig) of
63                     {ok, Shovel} ->
64                         %% make sure the config we accumulate has any
65                         %% relevant default values (discovered during
66                         %% validation), applied back to it
67                         Acc2 = dict:store(ShovelName, Shovel, Acc),
68                         parse_configuration(Defaults, Env, Acc2);
69                     Error ->
70                         Error
71                 end
72    end;
73parse_configuration(_Defaults, _, _Acc) ->
74    {error, require_list_of_shovel_configurations}.
75
76validate_shovel_config(ShovelName, ShovelConfig) ->
77    rabbit_shovel_config:parse(ShovelName, ShovelConfig).
78