diff --git a/guides/configuration.md b/guides/configuration.md index ccf1c8b0..209c484f 100644 --- a/guides/configuration.md +++ b/guides/configuration.md @@ -1,7 +1,7 @@ ## Configuration Amoc is configured through environment variables (uppercase with prefix ``AMOC_``). -Note that the environment variables are evaluated as Erlang code. +Note that by default, environment variables values are deserialized as Erlang terms. This behavior can be customized by providing an alternative parsing module in the `config_parser_mod` configuration parameter for the amoc application. It can be done using the [application:set_env/4](https://www.erlang.org/doc/man/application#set_env-4) interface or via a [config file](https://www.erlang.org/doc/man/config). The custom parsing module must implement the `amoc_config_env` behavior. Amoc supports the following generic configuration parameters: @@ -12,7 +12,7 @@ Amoc supports the following generic configuration parameters: * ``api_port`` - a port for the amoc REST interfaces: * default value - 4000 * example: `AMOC_API_PORT="4000"` - + * ``interarrival`` - a delay (in ms, for each node in the cluster independently) between creating the processes for two consecutive users: * default value - 50 ms. @@ -61,7 +61,7 @@ where * **Default:** this field is mandatory ### `description` -* **Syntax:** A string describing how this variable is used, can be extracted by APIs to document the behaviour +* **Syntax:** A string describing how this variable is used, can be extracted by APIs to document the behavior * **Example:** `description = "a description of this variable"` * **Default:** this field is mandatory @@ -91,9 +91,9 @@ An action to take when the value of this variable is updated. It is triggered at - If it is set to `none`, all updates are allowed. - If it is an `mfa`, the given function will be called on the old and new value. -## Reasonale +## Rationale -The reason why the `-required_variable(...)` is preferred over the usual behaviour +The reason why the `-required_variable(...)` is preferred over the usual behavior callback is because the orchestration tools can easily extract the attributes even without the compilation, while configuring via a callback, requires a successful compilation of the module. As an example, a module: @@ -101,7 +101,7 @@ compilation of the module. As an example, a module: -module(example). -include("some_unavailable_header.hrl"). -some_attr({"some", value}). --some_attr([{another, "value"}, +-some_attr([{another, "value"}, {yet, <<"another">>, "value"}]). ``` cannot be compiled without the ``some_unavailable_header.hrl`` file, but we still @@ -115,9 +115,9 @@ error {ok,[{attribute,1,file,{"example.erl",1}}, {attribute,1,module,example}, {error,{2,epp,{include,file,"some_unavailable_header.hrl"}}}, - {attribute,3,some_attr,{"some",value}}, + {attribute,3,some_attr,{"some",value}}, {attribute,4,some_attr, - [{another,"value"},{yet,<<"another">>,"value"}]}, + [{another,"value"},{yet,<<"another">>,"value"}]}, {eof,6}]} 3> lists:flatten([Value || {attribute, _, some_attr, Value} <- AbstractForm]). [{"some",value}, diff --git a/src/amoc_config/amoc_config_env.erl b/src/amoc_config/amoc_config_env.erl index f3512d2f..df326ffa 100644 --- a/src/amoc_config/amoc_config_env.erl +++ b/src/amoc_config/amoc_config_env.erl @@ -12,7 +12,7 @@ %% @end -module(amoc_config_env). --export([get/1, get/2]). +-export([get/2]). -define(DEFAULT_PARSER_MODULE, amoc_config_parser). @@ -21,19 +21,8 @@ %% ------------------------------------------------------------------ %% API %% ------------------------------------------------------------------ --spec get(amoc_config:name()) -> amoc_config:value(). -get(Name) -> - get(Name, undefined). - -spec get(amoc_config:name(), amoc_config:value()) -> amoc_config:value(). get(Name, Default) when is_atom(Name) -> - get_os_env(Name, Default). - -%% ------------------------------------------------------------------ -%% Internal Function Definitions -%% ------------------------------------------------------------------ --spec get_os_env(amoc_config:name(), amoc_config:value()) -> amoc_config:value(). -get_os_env(Name, Default) -> EnvName = os_env_name(Name), Value = os:getenv(EnvName), case parse_value(Value, Default) of @@ -47,6 +36,9 @@ get_os_env(Name, Default) -> Default end. +%% ------------------------------------------------------------------ +%% Internal Function Definitions +%% ------------------------------------------------------------------ -spec os_env_name(amoc_config:name()) -> string(). os_env_name(Name) when is_atom(Name) -> "AMOC_" ++ string:uppercase(erlang:atom_to_list(Name)). @@ -55,8 +47,7 @@ os_env_name(Name) when is_atom(Name) -> parse_value(false, Default) -> {ok, Default}; parse_value("", Default) -> {ok, Default}; parse_value(String, _) -> - App = application:get_application(?MODULE), - Mod = application:get_env(App, config_parser_mod, ?DEFAULT_PARSER_MODULE), + Mod = application:get_env(amoc, config_parser_mod, ?DEFAULT_PARSER_MODULE), try Mod:parse_value(String) of {ok, Value} -> {ok, Value}; {error, Error} -> {error, Error}; diff --git a/src/amoc_config/amoc_config_utils.erl b/src/amoc_config/amoc_config_utils.erl index ca801a26..230ed12c 100644 --- a/src/amoc_config/amoc_config_utils.erl +++ b/src/amoc_config/amoc_config_utils.erl @@ -11,8 +11,7 @@ merge_config/2, override_config/2, store_scenario_config/1, - create_amoc_config_ets/0, - find_all_vars/1]). + create_amoc_config_ets/0]). -spec maybe_error(error_type(), [{error, reason()} | {ok, any()}]) -> error() | {ok, [any()]}. @@ -71,9 +70,3 @@ create_amoc_config_ets() -> protected, {keypos, #module_parameter.name}, {read_concurrency, true}]). - --spec find_all_vars(atom()) -> [any()]. -find_all_vars(Name) -> - AllValues = [application:get_env(App, Name) - || {App, _, _} <- application:loaded_applications()], - [Value || {ok, Value} <- AllValues]. diff --git a/test/amoc_config_env_SUITE.erl b/test/amoc_config_env_SUITE.erl index 454b7658..dfa0cced 100644 --- a/test/amoc_config_env_SUITE.erl +++ b/test/amoc_config_env_SUITE.erl @@ -35,27 +35,22 @@ end_per_suite(_) -> init_per_testcase(valid_custom_parser_test, Config) -> meck:new(?MOCK_MOD, [non_strict, no_link]), - App = application:get_application(amoc_config_env), - application:set_env(App, config_parser_mod, ?MOCK_MOD), - ct:pal("amoc_config_env module belongs to '~p' application", [App]), + set_config_parser_module(?MOCK_MOD), ct:pal("AMOC_* OS env. variables:~n ~p", [[AmocEnv || "AMOC_" ++ _ = AmocEnv <- os:getenv()]]), Config; init_per_testcase(invalid_custom_parser_test, Config) -> - App = application:get_application(amoc_config_env), %% setting non-existing config parser module - application:set_env(App, config_parser_mod, invalid_parser_module), + set_config_parser_module(invalid_parser_module), Config; init_per_testcase(_, Config) -> Config. end_per_testcase(valid_custom_parser_test, _Config) -> - App = application:get_application(amoc_config_env), - application:unset_env(App, config_parser_mod), + unset_config_parser_module(), meck:unload(); end_per_testcase(invalid_custom_parser_test, _Config) -> - App = application:get_application(amoc_config_env), - application:unset_env(App, config_parser_mod); + unset_config_parser_module(); end_per_testcase(_, _Config) -> ok. %%----------------------------------------------------------------------------------- @@ -130,3 +125,13 @@ invalid_custom_parser_test(_) -> ?assertEqual(default_value, get_env(unset_var, default_value)), ?assertEqual(undefined, get_env(empty_var)), ?assertEqual(default_value, get_env(empty_var, default_value)). + +%%----------------------------------------------------------------------------------- +%% helper functions +%%----------------------------------------------------------------------------------- + +set_config_parser_module(Mod) -> + application:set_env(amoc, config_parser_mod, Mod). + +unset_config_parser_module() -> + application:unset_env(amoc, config_parser_mod). diff --git a/test/amoc_config_helper.erl b/test/amoc_config_helper.erl index 6c85bc51..c5274ca6 100644 --- a/test/amoc_config_helper.erl +++ b/test/amoc_config_helper.erl @@ -15,7 +15,7 @@ env_name(Name) -> "AMOC_" ++ string:uppercase(erlang:atom_to_list(Name)). get_env(Name) -> - amoc_config_env:get(Name). + get_env(Name, undefined). get_env(Name, Default) -> amoc_config_env:get(Name, Default).