diff --git a/src/dog_api_router.erl b/src/dog_api_router.erl index 73d1373..3919db4 100644 --- a/src/dog_api_router.erl +++ b/src/dog_api_router.erl @@ -115,7 +115,9 @@ start_link() -> {"/api/V2/fact/:id", api_handler_v2, #{}}, {"/api/V2/fact/:id/:sub", api_handler_v2, #{}}, {"/api/V2/facts", plural_api_handler_v2, #{}}, - {"/api/V2/facts/:sub", plural_api_handler_v2, #{}} + {"/api/V2/facts/:sub", plural_api_handler_v2, #{}}, + {"/api/hcl/:sub", hcl_api_handler, #{}}, + {"/api/V2/hcl/:sub", hcl_api_handler_v2, #{}} ]} ]), {ok, _} = cowboy:start_clear( diff --git a/src/dog_ruleset_api_v2.erl b/src/dog_ruleset_api_v2.erl index ba281fe..5b7975a 100644 --- a/src/dog_ruleset_api_v2.erl +++ b/src/dog_ruleset_api_v2.erl @@ -490,11 +490,11 @@ rule_names_to_ids(Rules, ServicesByName, ZonesByName, GroupsByName) -> -spec to_hcl_by_id(RulesetId :: iolist()) -> iolist(). to_hcl_by_id(RulesetId) -> {ok, RulesetWithIds} = get_by_id(RulesetId), - to_hcl(RulesetWithIds). + Ruleset = ids_to_names(RulesetWithIds), + to_hcl(Ruleset). -spec to_hcl(Ruleset :: map()) -> binary(). -to_hcl(RulesetWithIds) -> - Ruleset = ids_to_names(RulesetWithIds), +to_hcl(Ruleset) -> InboundRules = rules_to_hcl(nested:get([<<"rules">>,<<"inbound">>],Ruleset)), OutboundRules = rules_to_hcl(nested:get([<<"rules">>,<<"outbound">>],Ruleset)), Bindings = #{ diff --git a/src/hcl_api_handler.erl b/src/hcl_api_handler.erl new file mode 100644 index 0000000..419d074 --- /dev/null +++ b/src/hcl_api_handler.erl @@ -0,0 +1,76 @@ +-module(hcl_api_handler). + +-include("dog_trainer.hrl"). +-include_lib("kernel/include/logger.hrl"). + +-export([init/2]). +-export([content_types_provided/2]). +-export([content_types_accepted/2]). +-export([allowed_methods/2]). +-export([from_json/2]). +-export([resource_exists/2]). +-export([extract_module_from_path/3]). + +init(Req, Opts) -> + {cowboy_rest, Req, Opts}. + +extract_module_from_path(Path, Start, Length) -> + Path@0 = erlang:binary_to_list(Path), + Path@1 = lists:flatten( + lists:join("/", lists:sublist(string:split(Path@0, "/", all), Start, Length)) + ), + Path@2 = erlang:list_to_binary(Path@1), + Path@2. + +get_handler_module(Path) -> + handler_lookup(extract_module_from_path(Path, 4, 1)). + +handler_lookup(<<"group">>) -> dog_group_api_v2; +handler_lookup(<<"host">>) -> dog_host_api_v2; +handler_lookup(<<"link">>) -> dog_link_api_v2; +handler_lookup(<<"profile">>) -> dog_profile_api_v2; +handler_lookup(<<"service">>) -> dog_service_api_v2; +handler_lookup(<<"zone">>) -> dog_zone_api_v2; +handler_lookup(<<"ruleset">>) -> dog_ruleset_api_v2; +handler_lookup(<<"fact">>) -> dog_fact_api_v2. + +content_types_provided(Req, State) -> + { + [ + {<<"text/plain">>, to_hcl} + ], + Req, + State + }. + +content_types_accepted(Req, State) -> + case cowboy_req:method(Req) of + <<"PUT">> -> + {[{<<"application/json">>, from_json}], Req, State }; + <<"POST">> -> + {[{<<"application/json">>, from_json}], Req, State } + end. + +allowed_methods(Req, State) -> + {[<<"PUT">>,<<"POST">>], Req, State}. + +resource_exists(Req@0, State@0) -> + {false, Req@0, State@0}. + +from_json(Req@0, State@0) -> + Body = cowboy_req:read_body(Req@0), + Path = cowboy_req:path(Req@0), + Handler = get_handler_module(Path), + {ok, NewContent, Req@1} = Body, + Map = jsx:decode(NewContent, [return_maps]), + State@1 = maps:put(<<"object">>, Map, State@0), + State@2 = maps:put(<<"content">>, NewContent, State@1), + cowboy_req:reply( + 200, + #{ + <<"content-type">> => <<"plain/text">> + }, + Handler:to_hcl(Map), + Req@1 + ), + {stop, Req@1, State@2}. diff --git a/src/hcl_api_handler_v2.erl b/src/hcl_api_handler_v2.erl new file mode 100644 index 0000000..dc51878 --- /dev/null +++ b/src/hcl_api_handler_v2.erl @@ -0,0 +1,76 @@ +-module(hcl_api_handler_v2). + +-include("dog_trainer.hrl"). +-include_lib("kernel/include/logger.hrl"). + +-export([init/2]). +-export([content_types_provided/2]). +-export([content_types_accepted/2]). +-export([allowed_methods/2]). +-export([from_json/2]). +-export([resource_exists/2]). +-export([extract_module_from_path/3]). + +init(Req, Opts) -> + {cowboy_rest, Req, Opts}. + +extract_module_from_path(Path, Start, Length) -> + Path@0 = erlang:binary_to_list(Path), + Path@1 = lists:flatten( + lists:join("/", lists:sublist(string:split(Path@0, "/", all), Start, Length)) + ), + Path@2 = erlang:list_to_binary(Path@1), + Path@2. + +get_handler_module(Path) -> + handler_lookup(extract_module_from_path(Path, 5, 1)). + +handler_lookup(<<"group">>) -> dog_group_api_v2; +handler_lookup(<<"host">>) -> dog_host_api_v2; +handler_lookup(<<"link">>) -> dog_link_api_v2; +handler_lookup(<<"profile">>) -> dog_profile_api_v2; +handler_lookup(<<"service">>) -> dog_service_api_v2; +handler_lookup(<<"zone">>) -> dog_zone_api_v2; +handler_lookup(<<"ruleset">>) -> dog_ruleset_api_v2; +handler_lookup(<<"fact">>) -> dog_fact_api_v2. + +content_types_provided(Req, State) -> + { + [ + {<<"text/plain">>, to_hcl} + ], + Req, + State + }. + +content_types_accepted(Req, State) -> + case cowboy_req:method(Req) of + <<"PUT">> -> + {[{<<"application/json">>, from_json}], Req, State }; + <<"POST">> -> + {[{<<"application/json">>, from_json}], Req, State } + end. + +allowed_methods(Req, State) -> + {[<<"PUT">>,<<"POST">>], Req, State}. + +resource_exists(Req@0, State@0) -> + {false, Req@0, State@0}. + +from_json(Req@0, State@0) -> + Body = cowboy_req:read_body(Req@0), + Path = cowboy_req:path(Req@0), + Handler = get_handler_module(Path), + {ok, NewContent, Req@1} = Body, + Map = jsx:decode(NewContent, [return_maps]), + State@1 = maps:put(<<"object">>, Map, State@0), + State@2 = maps:put(<<"content">>, NewContent, State@1), + cowboy_req:reply( + 200, + #{ + <<"content-type">> => <<"plain/text">> + }, + Handler:to_hcl(Map), + Req@1 + ), + {stop, Req@1, State@2}.