diff --git a/src/dockerl_steps.erl b/src/dockerl_steps.erl new file mode 100644 index 0000000000000000000000000000000000000000..d4162c3e5a02e1dcea0e2c8bb0439a7491998d33 --- /dev/null +++ b/src/dockerl_steps.erl @@ -0,0 +1,87 @@ +-module(dockerl_steps). +-author("erikh"). + +%% API +-export([ + setup_feature/2, + teardown_feature/1, + given/2 +]). + +%% Utility +-export([ + get_port/3 +]). + +setup_feature(_Tokens, State) -> + application:ensure_all_started(hackney), + {ok, Pid} = dockerl:start_link(socket, <<"/var/run/docker.sock">>), + {ok, State#{{?MODULE, pid} => Pid, {?MODULE, containers} => []}}. + +teardown_feature(State = #{{?MODULE, pid} := Pid, {?MODULE, containers} := Containers}) -> + lists:foreach( + fun({Name, Id}) -> + ok = dockerl:stop_container(Pid, Id), + lager:notice("Docker container ~s stopped", [Name]), + ok = dockerl:remove_container(Pid, Id), + lager:notice("Docker container ~s removed", [Name]) + end, Containers), + {ok, State}. + +given([<<"a">>, <<"docker">>, <<"container">>, <<"named">>, Name, <<"running">>, Image, <<"with">>, <<"commands:">>, {docstring, Args}], State = #{{?MODULE, pid} := Pid, {?MODULE, containers} := Containers}) -> + {ok, _} = dockerl:pull_image(Pid, Image), + {ok, Id} = dockerl:create_container(Pid, Image, + #{ + 'Tty' => true, + 'Cmd' => binary:split(Args, <<" ">>, [trim_all, global]), + 'PublishAllPorts' => true + }), + lager:notice("Docker container ~s running ~s created: ~s", [Name, Image, Id]), + ok = dockerl:start_container(Pid, Id), + lager:notice("Docker container ~s started", [Id]), + {ok, State#{{?MODULE, containers} => [{Name, Id} | Containers]}}; + +given([Name, <<"container">>, <<"logs">>, <<"match">>, Pattern], State = #{{?MODULE, pid} := Pid, {?MODULE, containers} := Containers}) -> + Id = proplists:get_value(Name, Containers), + {ok, Stream} = dockerl:container_logs(Pid, Id), + ok = match_logs(Stream, Pattern), + {ok, State}. + +%%=================================================================== +%% Utility functions +%%=================================================================== +get_port(Name, Port, #{{?MODULE, pid} := Pid, {?MODULE, containers} := Containers}) -> + Id = proplists:get_value(Name, Containers), + {ok, Ports} = dockerl_utils:get_ports(Pid, Id), + [{_, IntPort}] = maps:get(Port, Ports), + BinPort = integer_to_binary(IntPort), + BinAddress = case os:type() of + {unix, darwin} -> %% Todo: remove this hack once routing is fixed in Docker for Mac + <<"127.0.0.1">>; + _ -> + {ok, Gateway} = dockerl_utils:get_gateway(Pid, Id), + list_to_binary(inet:ntoa(Gateway)) + end, + {BinAddress, BinPort}. + +%%=================================================================== +%% Internal functions +%%=================================================================== +match_logs(Stream, Pattern) -> + receive + done -> + {error, no_match}; + Msg -> + lager:debug("~p", [Msg]), + case re:run(Msg, Pattern) of + {match, _} -> + Stream ! stop, + ok; + _ -> + match_logs(Stream, Pattern) + end + after + 10000 -> + Stream ! stop, + {error, timeout} + end.