Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scenario descr rest api #130

Merged
merged 9 commits into from
Aug 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 5 additions & 7 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
FROM phusion/baseimage as amoc-build
FROM phusion/baseimage:18.04-1.0.0 as amoc-build
NelsonVides marked this conversation as resolved.
Show resolved Hide resolved

ARG otp_vsn=22.3.4-1

RUN apt-get update && \
apt-get install -y --no-install-recommends \
git \
make \
wget && \
wget https://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb && \
dpkg -i erlang-solutions_1.0_all.deb && \
git make wget gnupg && \
wget https://packages.erlang-solutions.com/erlang-solutions_2.0_all.deb && \
dpkg -i erlang-solutions_2.0_all.deb && \
apt-get update && \
apt-get install -y esl-erlang=1:${otp_vsn}

Expand All @@ -18,7 +16,7 @@ RUN cd amoc_build && \
git clean -ffxd && \
make rel

FROM phusion/baseimage
FROM phusion/baseimage:18.04-1.0.0
MAINTAINER Erlang Solutions <mongoose-im@erlang-solutions.com>

RUN useradd -ms /bin/bash amoc
Expand Down
2 changes: 1 addition & 1 deletion doc/http-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@ With default options API will be running on port 4000. You can set other port by
In Amoc we use Swagger so if you want the current documentation in a nice format you can find it under `/api-docs/` path.
Just open it in your browser (e.g. http://localhost:4000/api-docs/)

Also you can find the current documentation [here](https://esl.github.io/amoc_rest/?v=1.0.0)
Also you can find the current documentation [here](https://esl.github.io/amoc_rest/?v=7a46d9f)
(without possibility to execute requests)
5 changes: 3 additions & 2 deletions rebar.config
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
{exometer_core, {git, "https://github.com/esl/exometer_core.git", {branch, "master"}}},
{exometer_report_graphite, {git, "https://github.com/esl/exometer_report_graphite.git", {branch, "master"}}},
%% when updating amoc_rest version, don't forget to update it at ./doc/http-api.md as well.
{amoc_rest, {git, "https://github.com/esl/amoc_rest.git", {tag, "1.0.0"}}}
{amoc_rest, {git, "https://github.com/esl/amoc_rest.git", {ref, "7a46d9f"}}},
{docsh, "0.7.2"}
]}.

{ profiles, [
Expand All @@ -22,7 +23,7 @@
{prod, [
{erl_opts, [{src_dirs, ["src", "scenarios"]}]},
{relx, [
{release, {amoc, git}, [amoc, runtime_tools, compiler]},
{release, {amoc, git}, [amoc, runtime_tools, compiler, docsh]},
{dev_mode, false},
{include_erts, true},
{include_src, false},
Expand Down
8 changes: 7 additions & 1 deletion rebar.lock
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
{"1.1.0",
[{<<"amoc_rest">>,
{git,"https://github.com/esl/amoc_rest.git",
{ref,"59ccffad8fa3662bde44f54772a01c60192f8b04"}},
{ref,"7a46d9f083692427fcbd2e4a83a01f6ca2d735da"}},
0},
{<<"cowboy">>,{pkg,<<"cowboy">>,<<"2.8.0">>},1},
{<<"cowlib">>,{pkg,<<"cowlib">>,<<"2.9.1">>},2},
{<<"docsh">>,{pkg,<<"docsh">>,<<"0.7.2">>},0},
{<<"exometer_core">>,
{git,"https://github.com/esl/exometer_core.git",
{ref,"979ff04bcabc276c122b47fb7e6b54fbded62576"}},
Expand All @@ -13,10 +14,12 @@
{git,"https://github.com/esl/exometer_report_graphite.git",
{ref,"264dd7bcbadbd7febcd43917302251286c88b681"}},
0},
{<<"getopt">>,{pkg,<<"getopt">>,<<"1.0.1">>},2},
{<<"hut">>,{pkg,<<"hut">>,<<"1.2.1">>},1},
{<<"jesse">>,{pkg,<<"jesse">>,<<"1.5.5">>},1},
{<<"jsx">>,{pkg,<<"jsx">>,<<"2.11.0">>},1},
{<<"parse_trans">>,{pkg,<<"parse_trans">>,<<"3.3.0">>},1},
{<<"providers">>,{pkg,<<"providers">>,<<"1.8.1">>},1},
{<<"ranch">>,{pkg,<<"ranch">>,<<"1.7.1">>},2},
{<<"rfc3339">>,
{git,"https://github.com/talentdeficit/rfc3339.git",
Expand All @@ -26,9 +29,12 @@
{pkg_hash,[
{<<"cowboy">>, <<"F3DC62E35797ECD9AC1B50DB74611193C29815401E53BAC9A5C0577BD7BC667D">>},
{<<"cowlib">>, <<"61A6C7C50CF07FDD24B2F45B89500BB93B6686579B069A89F88CB211E1125C78">>},
{<<"docsh">>, <<"F893D5317A0E14269DD7FE79CF95FB6B9BA23513DA0480EC6E77C73221CAE4F2">>},
{<<"getopt">>, <<"C73A9FA687B217F2FF79F68A3B637711BB1936E712B521D8CE466B29CBF7808A">>},
{<<"hut">>, <<"08D46679523043424870723923971889E8A34D63B2F946A35B46CF921D1236E7">>},
{<<"jesse">>, <<"ECFD2C1634C49052CA907B4DFDE1D1F44B7FD7862D933F4590807E42759B8072">>},
{<<"jsx">>, <<"08154624050333919B4AC1B789667D5F4DB166DC50E190C4D778D1587F102EE0">>},
{<<"parse_trans">>, <<"09765507A3C7590A784615CFD421D101AEC25098D50B89D7AA1D66646BC571C1">>},
{<<"providers">>, <<"70B4197869514344A8A60E2B2A4EF41CA03DEF43CFB1712ECF076A0F3C62F083">>},
{<<"ranch">>, <<"6B1FAB51B49196860B733A49C07604465A47BDB78AA10C1C16A3D199F7F8C881">>}]}
].
1 change: 1 addition & 0 deletions src/amoc_config/amoc_config.hrl
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
-record(module_parameter, {name :: name(),
mod :: module(),
value :: value(),
description :: string(),
verification_fn :: maybe_verification_fun(),
update_fn = read_only :: maybe_update_fun() | read_only}).

Expand Down
7 changes: 4 additions & 3 deletions src/amoc_config/amoc_config_attributes.erl
Original file line number Diff line number Diff line change
Expand Up @@ -111,15 +111,16 @@ check_update_method(Attr) ->
end.

-spec make_module_parameter(#{name := name(),
description := string(),
default_value := value(),
verification := maybe_verification_fun(),
update := maybe_update_fun(),
any() => any()},
module()) ->
{ok, module_parameter()}.
make_module_parameter(#{name := Name, default_value := Value, update := UpdateFn,
verification := VerificationFn}, Module) ->
{ok, #module_parameter{name = Name, mod = Module, value = Value,
make_module_parameter(#{name := Name, description := Description, default_value := Value,
verification := VerificationFn, update := UpdateFn}, Module) ->
{ok, #module_parameter{name = Name, mod = Module, description = Description, value = Value,
verification_fn = VerificationFn, update_fn = UpdateFn}}.

-spec verification_fn(maybe_verification_method()) ->
Expand Down
36 changes: 35 additions & 1 deletion src/amoc_config/amoc_config_scenario.erl
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,15 @@

%% API
-export([parse_scenario_settings/2,
update_settings/1]).
update_settings/1,
get_default_configuration/1,
get_current_configuration/0]).

-include_lib("kernel/include/logger.hrl").
-include("amoc_config.hrl").

-type module_configuration_map() :: #{name() => #{value := any(),
any() => any()}}.
%% ------------------------------------------------------------------
%% API
%% ------------------------------------------------------------------
Expand Down Expand Up @@ -43,6 +47,20 @@ update_settings(Settings) ->
{error, invalid_return_value, UnexpectedReturnValue}
end.

-spec get_default_configuration(module()) -> {ok, module_configuration_map()} | error().
get_default_configuration(Module) ->
PipelineActions = [
{fun get_configuration/1, []},
{fun convert_to_config_map/1, []}],
amoc_config_utils:pipeline(PipelineActions, {ok, Module}).

-spec get_current_configuration() -> {ok, module_configuration_map()}.
get_current_configuration() ->
PipelineActions = [
{fun get_existing_configuration/0, []},
{fun convert_to_config_map/1, []}],
amoc_config_utils:pipeline(PipelineActions, ok).

%% ------------------------------------------------------------------
%% Internal Function Definitions
%% ------------------------------------------------------------------
Expand Down Expand Up @@ -121,3 +139,19 @@ store_scenario_config(Config) ->
[spawn(fun() -> apply(Fn, [Name, Value]) end)
|| #module_parameter{name = Name, value = Value, update_fn = Fn} <- Config],
ok.

convert_to_config_map(Config) ->
PropList = [{Name, parameter_to_map(P)}
|| #module_parameter{name = Name} = P <- Config],
{ok, maps:from_list(PropList)}.

parameter_to_map(#module_parameter{} = Param) ->
RecordFields = record_info(fields, module_parameter),
RecordSize = record_info(size, module_parameter),
FieldsWithPosition = lists:zip(lists:seq(2, RecordSize), RecordFields),
PropList = [{Field, element(Pos, Param)} || {Pos, Field} <- FieldsWithPosition,
filter_parameter_fields(Field)],
maps:from_list(PropList).

filter_parameter_fields(name) -> false;
filter_parameter_fields(_) -> true.
16 changes: 14 additions & 2 deletions src/rest_api/amoc_api_logic_handler.erl
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,21 @@ handle_request('ScenariosIdGet', _Req, #{id := ScenarioName}) ->
case amoc_api_scenario_status:test_status(ScenarioName) of
{doesnt_exist, _} ->
{404, #{}, #{}};
{Status, _Scenario} ->
{Status, Scenario} ->
BinStatus = atom_to_binary(Status, utf8),
{200, #{}, [{<<"scenario_status">>, BinStatus}]}
MaybeSettings =
amoc_api_scenario_status:maybe_scenario_settings(Status, Scenario),
{200, #{}, [{<<"scenario_status">>, BinStatus} | MaybeSettings]}
end;
handle_request('ScenariosIdInfoGet', _Req, #{id := ScenarioName}) ->
case amoc_api_scenario_status:test_status(ScenarioName) of
{doesnt_exist, _} ->
{404, #{}, #{}};
{_Status, Scenario} ->
EDoc = amoc_api_scenario_status:get_edoc(Scenario),
MaybeParams =
amoc_api_scenario_status:maybe_scenario_params(Scenario),
{200, #{}, [{<<"doc">>, EDoc} | MaybeParams]}
end;
handle_request('ScenariosIdPatch', _Req, #{'ScenarioExecution' := Body,
id := ScenarioName}) ->
Expand Down
60 changes: 59 additions & 1 deletion src/rest_api/amoc_api_scenario_status.erl
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,29 @@
%%==============================================================================
-module(amoc_api_scenario_status).
%% API
-export([test_status/1]).
-export([test_status/1,
maybe_scenario_settings/2,
maybe_scenario_params/1,
get_edoc/1]).

-type status() :: error | running | finished | loaded | doesnt_exist.
-type scenario_status() :: {status(), amoc:scenario()}.

get_edoc(Scenario) ->
case docsh_lib:get_docs(Scenario) of
{error, _} ->
ScenarioName = atom_to_binary(Scenario, utf8),
<<"cannot extract documentation for ", ScenarioName/binary>>;
{ok, Docs} ->
case docsh_format:lookup(Docs, Scenario, [moduledoc]) of
{not_found, Message} ->
<<"no documentation found">>;
{ok, [DocItem]} ->
Doc = maps:get(<<"en">>, DocItem),
iolist_to_binary(docsh_edoc:format_edoc(Doc, #{}))
end
end.

-spec test_status(binary()) -> scenario_status().
test_status(ScenarioName) ->
case get_scenario(ScenarioName) of
Expand All @@ -22,6 +40,46 @@ test_status(ScenarioName) ->
{doesnt_exist, invalid_scenario_name}
end.

maybe_scenario_settings(Status, Scenario)->
case scenario_settings(Status, Scenario) of
[] -> [];
Settings ->
FormattedSettings = [{format(K), format(V)} || {K, V} <- Settings],
[{<<"settings">>, FormattedSettings}]
end.

maybe_scenario_params(Scenario)->
case scenario_parameters(Scenario) of
[] -> [];
Parameters ->
FormattedParameters = [{format(K), format_kv_list(V)}
|| {K, V} <- Parameters],
[{<<"parameters">>, FormattedParameters}]
end.

format_kv_list(PropList)->
[{change_and_format(K), format(V)} || {K, V} <- PropList].

change_and_format(mod)-> format(module);
change_and_format(value)-> format(default_value);
change_and_format(X) -> format(X).

format(Value) ->
list_to_binary(lists:flatten(io_lib:format("~tp", [Value]))).

-spec scenario_settings(status(), amoc:scenario()) -> amoc_config:settings().
scenario_settings(loaded, Scenario) ->
{ok, ConfigMap} = amoc_config_scenario:get_default_configuration(Scenario),
[{Name, Value} || {Name, #{value := Value}} <- maps:to_list(ConfigMap)];
scenario_settings(running, _Scenario) ->
{ok, ConfigMap} = amoc_config_scenario:get_current_configuration(),
[{Name, Value} || {Name, #{value := Value}} <- maps:to_list(ConfigMap)];
scenario_settings(_, _Scenario) -> [].

scenario_parameters(Scenario) ->
{ok, ConfigMap} = amoc_config_scenario:get_default_configuration(Scenario),
[{Name, maps:to_list(Info)} || {Name, Info} <- maps:to_list(ConfigMap)].

-spec get_scenario(binary()) -> {ok, amoc:scenario()} | doesnt_exist.
get_scenario(ScenarioName) ->
try
Expand Down
14 changes: 9 additions & 5 deletions test/amoc_api_scenario_handler_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ all() ->
patch_scenario_returns_200_when_request_ok_and_module_exists_w_settings
].

init_per_testcase(Mod, Config)
when Mod =:= patch_scenario_returns_200_when_request_ok_and_module_exists;
Mod =:= patch_scenario_returns_200_when_request_ok_and_module_exists_w_settings ->
init_per_testcase(TC, Config)
when TC =:= patch_scenario_returns_200_when_request_ok_and_module_exists;
TC =:= patch_scenario_returns_200_when_request_ok_and_module_exists_w_settings ->
mock_amoc_dist_do(),
create_env(Config),
Config;
Expand All @@ -48,7 +48,9 @@ init_per_testcase(_, Config) ->
create_env(Config),
Config.

end_per_testcase(patch_scenario_returns_200_when_request_ok_and_module_exists, _Config) ->
end_per_testcase(TC, _Config)
when TC =:= patch_scenario_returns_200_when_request_ok_and_module_exists;
TC =:= patch_scenario_returns_200_when_request_ok_and_module_exists_w_settings ->
ok = meck:unload(amoc_dist),
destroy_env();
end_per_testcase(_, _Config) ->
Expand Down Expand Up @@ -178,7 +180,9 @@ destroy_env() ->
-spec given_test_status_mocked(atom()) -> ok.
given_test_status_mocked(Value) ->
meck:new(amoc_api_scenario_status, []),
meck:expect(amoc_api_scenario_status, test_status, fun(_) -> Value end).
meck:expect(amoc_api_scenario_status, test_status, fun(_) -> Value end),
meck:expect(amoc_api_scenario_status, maybe_scenario_settings,
fun(_, _) -> [] end).

-spec mock_amoc_dist_do() -> ok.
mock_amoc_dist_do() ->
Expand Down
Loading