refactor: do not destory resource when update authn/authz resource
This commit is contained in:
parent
a5ddc5390f
commit
87af77ec35
|
@ -20,6 +20,8 @@
|
||||||
-include_lib("emqx_authn.hrl").
|
-include_lib("emqx_authn.hrl").
|
||||||
|
|
||||||
-export([
|
-export([
|
||||||
|
create_resource/3,
|
||||||
|
update_resource/3,
|
||||||
check_password_from_selected_map/3,
|
check_password_from_selected_map/3,
|
||||||
parse_deep/1,
|
parse_deep/1,
|
||||||
parse_str/1,
|
parse_str/1,
|
||||||
|
@ -47,6 +49,27 @@
|
||||||
%% APIs
|
%% APIs
|
||||||
%%------------------------------------------------------------------------------
|
%%------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
create_resource(ResourceId, Module, Config) ->
|
||||||
|
{ok, _Data} = emqx_resource:create_local(
|
||||||
|
ResourceId,
|
||||||
|
?RESOURCE_GROUP,
|
||||||
|
Module,
|
||||||
|
Config,
|
||||||
|
#{}
|
||||||
|
).
|
||||||
|
|
||||||
|
update_resource(Module, Config, ResourceId) ->
|
||||||
|
%% recreate before maybe stop
|
||||||
|
%% resource will auto start during recreate
|
||||||
|
Result = emqx_resource:recreate_local(ResourceId, Module, Config),
|
||||||
|
case Config of
|
||||||
|
#{enable := true} ->
|
||||||
|
Result;
|
||||||
|
#{enable := false} ->
|
||||||
|
ok = emqx_resource:stop(ResourceId),
|
||||||
|
Result
|
||||||
|
end.
|
||||||
|
|
||||||
check_password_from_selected_map(_Algorithm, _Selected, undefined) ->
|
check_password_from_selected_map(_Algorithm, _Selected, undefined) ->
|
||||||
{error, bad_username_or_password};
|
{error, bad_username_or_password};
|
||||||
check_password_from_selected_map(
|
check_password_from_selected_map(
|
||||||
|
|
|
@ -158,45 +158,24 @@ refs() ->
|
||||||
create(_AuthenticatorID, Config) ->
|
create(_AuthenticatorID, Config) ->
|
||||||
create(Config).
|
create(Config).
|
||||||
|
|
||||||
create(
|
create(Config0) ->
|
||||||
#{
|
|
||||||
method := Method,
|
|
||||||
url := RawUrl,
|
|
||||||
headers := Headers,
|
|
||||||
request_timeout := RequestTimeout
|
|
||||||
} = Config
|
|
||||||
) ->
|
|
||||||
{BaseUrl0, Path, Query} = parse_url(RawUrl),
|
|
||||||
{ok, BaseUrl} = emqx_http_lib:uri_parse(BaseUrl0),
|
|
||||||
ResourceId = emqx_authn_utils:make_resource_id(?MODULE),
|
ResourceId = emqx_authn_utils:make_resource_id(?MODULE),
|
||||||
State = #{
|
{Config, State} = parse_config(Config0),
|
||||||
method => Method,
|
{ok, _Data} = emqx_authn_utils:create_resource(
|
||||||
path => Path,
|
|
||||||
headers => ensure_header_name_type(Headers),
|
|
||||||
base_path_templete => emqx_authn_utils:parse_str(Path),
|
|
||||||
base_query_template => emqx_authn_utils:parse_deep(
|
|
||||||
cow_qs:parse_qs(to_bin(Query))
|
|
||||||
),
|
|
||||||
body_template => emqx_authn_utils:parse_deep(maps:get(body, Config, #{})),
|
|
||||||
request_timeout => RequestTimeout,
|
|
||||||
resource_id => ResourceId
|
|
||||||
},
|
|
||||||
{ok, _Data} = emqx_resource:create_local(
|
|
||||||
ResourceId,
|
ResourceId,
|
||||||
?RESOURCE_GROUP,
|
|
||||||
emqx_connector_http,
|
emqx_connector_http,
|
||||||
Config#{
|
Config
|
||||||
base_url => BaseUrl,
|
|
||||||
pool_type => random
|
|
||||||
},
|
|
||||||
#{}
|
|
||||||
),
|
),
|
||||||
{ok, State}.
|
{ok, State#{resource_id => ResourceId}}.
|
||||||
|
|
||||||
update(Config, State) ->
|
update(Config0, #{resource_id := ResourceId} = _State) ->
|
||||||
{ok, NewState} = create(Config),
|
{Config, NState} = parse_config(Config0),
|
||||||
ok = destroy(State),
|
case emqx_authn_utils:update_resource(emqx_connector_http, Config, ResourceId) of
|
||||||
{ok, NewState}.
|
{error, Reason} ->
|
||||||
|
error({load_config_error, Reason});
|
||||||
|
{ok, _} ->
|
||||||
|
{ok, NState#{resource_id => ResourceId}}
|
||||||
|
end.
|
||||||
|
|
||||||
authenticate(#{auth_method := _}, _) ->
|
authenticate(#{auth_method := _}, _) ->
|
||||||
ignore;
|
ignore;
|
||||||
|
@ -325,6 +304,29 @@ parse_url(Url) ->
|
||||||
throw({invalid_url, Url})
|
throw({invalid_url, Url})
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
parse_config(
|
||||||
|
#{
|
||||||
|
method := Method,
|
||||||
|
url := RawUrl,
|
||||||
|
headers := Headers,
|
||||||
|
request_timeout := RequestTimeout
|
||||||
|
} = Config
|
||||||
|
) ->
|
||||||
|
{BaseUrl0, Path, Query} = parse_url(RawUrl),
|
||||||
|
{ok, BaseUrl} = emqx_http_lib:uri_parse(BaseUrl0),
|
||||||
|
State = #{
|
||||||
|
method => Method,
|
||||||
|
path => Path,
|
||||||
|
headers => ensure_header_name_type(Headers),
|
||||||
|
base_path_templete => emqx_authn_utils:parse_str(Path),
|
||||||
|
base_query_template => emqx_authn_utils:parse_deep(
|
||||||
|
cow_qs:parse_qs(to_bin(Query))
|
||||||
|
),
|
||||||
|
body_template => emqx_authn_utils:parse_deep(maps:get(body, Config, #{})),
|
||||||
|
request_timeout => RequestTimeout
|
||||||
|
},
|
||||||
|
{Config#{base_url => BaseUrl, pool_type => random}, State}.
|
||||||
|
|
||||||
generate_request(Credential, #{
|
generate_request(Credential, #{
|
||||||
method := Method,
|
method := Method,
|
||||||
headers := Headers0,
|
headers := Headers0,
|
||||||
|
|
|
@ -126,39 +126,28 @@ refs() ->
|
||||||
create(_AuthenticatorID, Config) ->
|
create(_AuthenticatorID, Config) ->
|
||||||
create(Config).
|
create(Config).
|
||||||
|
|
||||||
create(#{filter := Filter} = Config) ->
|
create(Config0) ->
|
||||||
FilterTemplate = emqx_authn_utils:parse_deep(Filter),
|
ResourceId = emqx_authn_utils:make_resource_id(?MODULE),
|
||||||
State = maps:with(
|
{Config, State} = parse_config(Config0),
|
||||||
[
|
{ok, _Data} = emqx_authn_utils:create_resource(
|
||||||
collection,
|
ResourceId,
|
||||||
password_hash_field,
|
emqx_connector_mongo,
|
||||||
salt_field,
|
|
||||||
is_superuser_field,
|
|
||||||
password_hash_algorithm,
|
|
||||||
salt_position
|
|
||||||
],
|
|
||||||
Config
|
Config
|
||||||
),
|
),
|
||||||
#{password_hash_algorithm := Algorithm} = State,
|
{ok, State#{resource_id => ResourceId}}.
|
||||||
ok = emqx_authn_password_hashing:init(Algorithm),
|
|
||||||
ResourceId = emqx_authn_utils:make_resource_id(?MODULE),
|
|
||||||
NState = State#{
|
|
||||||
filter_template => FilterTemplate,
|
|
||||||
resource_id => ResourceId
|
|
||||||
},
|
|
||||||
{ok, _Data} = emqx_resource:create_local(
|
|
||||||
ResourceId,
|
|
||||||
?RESOURCE_GROUP,
|
|
||||||
emqx_connector_mongo,
|
|
||||||
Config,
|
|
||||||
#{}
|
|
||||||
),
|
|
||||||
{ok, NState}.
|
|
||||||
|
|
||||||
update(Config, State) ->
|
update(Config0, #{resource_id := ResourceId} = _State) ->
|
||||||
{ok, NewState} = create(Config),
|
{Config, NState} = parse_config(Config0),
|
||||||
ok = destroy(State),
|
case emqx_authn_utils:update_resource(emqx_connector_mongo, Config, ResourceId) of
|
||||||
{ok, NewState}.
|
{error, Reason} ->
|
||||||
|
error({load_config_error, Reason});
|
||||||
|
{ok, _} ->
|
||||||
|
{ok, NState#{resource_id => ResourceId}}
|
||||||
|
end.
|
||||||
|
|
||||||
|
destroy(#{resource_id := ResourceId}) ->
|
||||||
|
_ = emqx_resource:remove_local(ResourceId),
|
||||||
|
ok.
|
||||||
|
|
||||||
authenticate(#{auth_method := _}, _) ->
|
authenticate(#{auth_method := _}, _) ->
|
||||||
ignore;
|
ignore;
|
||||||
|
@ -201,14 +190,26 @@ authenticate(
|
||||||
end
|
end
|
||||||
end.
|
end.
|
||||||
|
|
||||||
destroy(#{resource_id := ResourceId}) ->
|
|
||||||
_ = emqx_resource:remove_local(ResourceId),
|
|
||||||
ok.
|
|
||||||
|
|
||||||
%%------------------------------------------------------------------------------
|
%%------------------------------------------------------------------------------
|
||||||
%% Internal functions
|
%% Internal functions
|
||||||
%%------------------------------------------------------------------------------
|
%%------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
parse_config(#{filter := Filter} = Config) ->
|
||||||
|
FilterTemplate = emqx_authn_utils:parse_deep(Filter),
|
||||||
|
State = maps:with(
|
||||||
|
[
|
||||||
|
collection,
|
||||||
|
password_hash_field,
|
||||||
|
salt_field,
|
||||||
|
is_superuser_field,
|
||||||
|
password_hash_algorithm,
|
||||||
|
salt_position
|
||||||
|
],
|
||||||
|
Config
|
||||||
|
),
|
||||||
|
ok = emqx_authn_password_hashing:init(maps:get(password_hash_algorithm, State)),
|
||||||
|
{Config, State#{filter_template => FilterTemplate}}.
|
||||||
|
|
||||||
check_password(undefined, _Selected, _State) ->
|
check_password(undefined, _Selected, _State) ->
|
||||||
{error, bad_username_or_password};
|
{error, bad_username_or_password};
|
||||||
check_password(
|
check_password(
|
||||||
|
|
|
@ -83,35 +83,24 @@ refs() ->
|
||||||
create(_AuthenticatorID, Config) ->
|
create(_AuthenticatorID, Config) ->
|
||||||
create(Config).
|
create(Config).
|
||||||
|
|
||||||
create(
|
create(Config0) ->
|
||||||
#{
|
|
||||||
password_hash_algorithm := Algorithm,
|
|
||||||
query := Query0,
|
|
||||||
query_timeout := QueryTimeout
|
|
||||||
} = Config
|
|
||||||
) ->
|
|
||||||
ok = emqx_authn_password_hashing:init(Algorithm),
|
|
||||||
{PrepareSql, TmplToken} = emqx_authn_utils:parse_sql(Query0, '?'),
|
|
||||||
ResourceId = emqx_authn_utils:make_resource_id(?MODULE),
|
ResourceId = emqx_authn_utils:make_resource_id(?MODULE),
|
||||||
State = #{
|
{Config, State} = parse_config(Config0),
|
||||||
password_hash_algorithm => Algorithm,
|
{ok, _Data} = emqx_authn_utils:create_resource(ResourceId, emqx_connector_mysql, Config),
|
||||||
tmpl_token => TmplToken,
|
{ok, State#{resource_id => ResourceId}}.
|
||||||
query_timeout => QueryTimeout,
|
|
||||||
resource_id => ResourceId
|
|
||||||
},
|
|
||||||
{ok, _Data} = emqx_resource:create_local(
|
|
||||||
ResourceId,
|
|
||||||
?RESOURCE_GROUP,
|
|
||||||
emqx_connector_mysql,
|
|
||||||
Config#{prepare_statement => #{?PREPARE_KEY => PrepareSql}},
|
|
||||||
#{}
|
|
||||||
),
|
|
||||||
{ok, State}.
|
|
||||||
|
|
||||||
update(Config, State) ->
|
update(Config0, #{resource_id := ResourceId} = _State) ->
|
||||||
{ok, NewState} = create(Config),
|
{Config, NState} = parse_config(Config0),
|
||||||
ok = destroy(State),
|
case emqx_authn_utils:update_resource(emqx_connector_mysql, Config, ResourceId) of
|
||||||
{ok, NewState}.
|
{error, Reason} ->
|
||||||
|
error({load_config_error, Reason});
|
||||||
|
{ok, _} ->
|
||||||
|
{ok, NState#{resource_id => ResourceId}}
|
||||||
|
end.
|
||||||
|
|
||||||
|
destroy(#{resource_id := ResourceId}) ->
|
||||||
|
_ = emqx_resource:remove_local(ResourceId),
|
||||||
|
ok.
|
||||||
|
|
||||||
authenticate(#{auth_method := _}, _) ->
|
authenticate(#{auth_method := _}, _) ->
|
||||||
ignore;
|
ignore;
|
||||||
|
@ -152,6 +141,18 @@ authenticate(
|
||||||
ignore
|
ignore
|
||||||
end.
|
end.
|
||||||
|
|
||||||
destroy(#{resource_id := ResourceId}) ->
|
parse_config(
|
||||||
_ = emqx_resource:remove_local(ResourceId),
|
#{
|
||||||
ok.
|
password_hash_algorithm := Algorithm,
|
||||||
|
query := Query0,
|
||||||
|
query_timeout := QueryTimeout
|
||||||
|
} = Config
|
||||||
|
) ->
|
||||||
|
ok = emqx_authn_password_hashing:init(Algorithm),
|
||||||
|
{PrepareSql, TmplToken} = emqx_authn_utils:parse_sql(Query0, '?'),
|
||||||
|
State = #{
|
||||||
|
password_hash_algorithm => Algorithm,
|
||||||
|
tmpl_token => TmplToken,
|
||||||
|
query_timeout => QueryTimeout
|
||||||
|
},
|
||||||
|
{Config#{prepare_statement => #{?PREPARE_KEY => PrepareSql}}, State}.
|
||||||
|
|
|
@ -82,33 +82,28 @@ refs() ->
|
||||||
create(_AuthenticatorID, Config) ->
|
create(_AuthenticatorID, Config) ->
|
||||||
create(Config).
|
create(Config).
|
||||||
|
|
||||||
create(
|
create(Config0) ->
|
||||||
#{
|
|
||||||
query := Query0,
|
|
||||||
password_hash_algorithm := Algorithm
|
|
||||||
} = Config
|
|
||||||
) ->
|
|
||||||
ok = emqx_authn_password_hashing:init(Algorithm),
|
|
||||||
{Query, PlaceHolders} = emqx_authn_utils:parse_sql(Query0, '$n'),
|
|
||||||
ResourceId = emqx_authn_utils:make_resource_id(?MODULE),
|
ResourceId = emqx_authn_utils:make_resource_id(?MODULE),
|
||||||
State = #{
|
{Config, State} = parse_config(Config0, ResourceId),
|
||||||
placeholders => PlaceHolders,
|
{ok, _Data} = emqx_authn_utils:create_resource(
|
||||||
password_hash_algorithm => Algorithm,
|
|
||||||
resource_id => ResourceId
|
|
||||||
},
|
|
||||||
{ok, _Data} = emqx_resource:create_local(
|
|
||||||
ResourceId,
|
ResourceId,
|
||||||
?RESOURCE_GROUP,
|
|
||||||
emqx_connector_pgsql,
|
emqx_connector_pgsql,
|
||||||
Config#{prepare_statement => #{ResourceId => Query}},
|
Config
|
||||||
#{}
|
|
||||||
),
|
),
|
||||||
{ok, State}.
|
{ok, State#{resource_id => ResourceId}}.
|
||||||
|
|
||||||
update(Config, State) ->
|
update(Config0, #{resource_id := ResourceId} = _State) ->
|
||||||
{ok, NewState} = create(Config),
|
{Config, NState} = parse_config(Config0, ResourceId),
|
||||||
ok = destroy(State),
|
case emqx_authn_utils:update_resource(emqx_connector_pgsql, Config, ResourceId) of
|
||||||
{ok, NewState}.
|
{error, Reason} ->
|
||||||
|
error({load_config_error, Reason});
|
||||||
|
{ok, _} ->
|
||||||
|
{ok, NState#{resource_id => ResourceId}}
|
||||||
|
end.
|
||||||
|
|
||||||
|
destroy(#{resource_id := ResourceId}) ->
|
||||||
|
_ = emqx_resource:remove_local(ResourceId),
|
||||||
|
ok.
|
||||||
|
|
||||||
authenticate(#{auth_method := _}, _) ->
|
authenticate(#{auth_method := _}, _) ->
|
||||||
ignore;
|
ignore;
|
||||||
|
@ -147,6 +142,17 @@ authenticate(
|
||||||
ignore
|
ignore
|
||||||
end.
|
end.
|
||||||
|
|
||||||
destroy(#{resource_id := ResourceId}) ->
|
parse_config(
|
||||||
_ = emqx_resource:remove_local(ResourceId),
|
#{
|
||||||
ok.
|
query := Query0,
|
||||||
|
password_hash_algorithm := Algorithm
|
||||||
|
} = Config,
|
||||||
|
ResourceId
|
||||||
|
) ->
|
||||||
|
ok = emqx_authn_password_hashing:init(Algorithm),
|
||||||
|
{Query, PlaceHolders} = emqx_authn_utils:parse_sql(Query0, '$n'),
|
||||||
|
State = #{
|
||||||
|
placeholders => PlaceHolders,
|
||||||
|
password_hash_algorithm => Algorithm
|
||||||
|
},
|
||||||
|
{Config#{prepare_statement => #{ResourceId => Query}}, State}.
|
||||||
|
|
|
@ -96,51 +96,33 @@ refs() ->
|
||||||
create(_AuthenticatorID, Config) ->
|
create(_AuthenticatorID, Config) ->
|
||||||
create(Config).
|
create(Config).
|
||||||
|
|
||||||
create(
|
create(Config0) ->
|
||||||
#{
|
ResourceId = emqx_authn_utils:make_resource_id(?MODULE),
|
||||||
cmd := Cmd,
|
case parse_config(Config0) of
|
||||||
password_hash_algorithm := Algorithm
|
{error, _} = Res ->
|
||||||
} = Config
|
Res;
|
||||||
) ->
|
{Config, State} ->
|
||||||
ok = emqx_authn_password_hashing:init(Algorithm),
|
{ok, _Data} = emqx_authn_utils:create_resource(
|
||||||
try
|
ResourceId,
|
||||||
NCmd = parse_cmd(Cmd),
|
emqx_connector_redis,
|
||||||
ok = emqx_authn_utils:ensure_apps_started(Algorithm),
|
|
||||||
State = maps:with(
|
|
||||||
[password_hash_algorithm, salt_position],
|
|
||||||
Config
|
Config
|
||||||
),
|
),
|
||||||
ResourceId = emqx_authn_utils:make_resource_id(?MODULE),
|
{ok, State#{resource_id => ResourceId}}
|
||||||
NState = State#{
|
|
||||||
cmd => NCmd,
|
|
||||||
resource_id => ResourceId
|
|
||||||
},
|
|
||||||
{ok, _Data} = emqx_resource:create_local(
|
|
||||||
ResourceId,
|
|
||||||
?RESOURCE_GROUP,
|
|
||||||
emqx_connector_redis,
|
|
||||||
Config,
|
|
||||||
#{}
|
|
||||||
),
|
|
||||||
{ok, NState}
|
|
||||||
catch
|
|
||||||
error:{unsupported_cmd, _Cmd} ->
|
|
||||||
{error, {unsupported_cmd, Cmd}};
|
|
||||||
error:missing_password_hash ->
|
|
||||||
{error, missing_password_hash};
|
|
||||||
error:{unsupported_fields, Fields} ->
|
|
||||||
{error, {unsupported_fields, Fields}}
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
update(Config, State) ->
|
update(Config0, #{resource_id := ResourceId} = _State) ->
|
||||||
case create(Config) of
|
{Config, NState} = parse_config(Config0),
|
||||||
{ok, NewState} ->
|
case emqx_authn_utils:update_resource(emqx_connector_redis, Config, ResourceId) of
|
||||||
ok = destroy(State),
|
|
||||||
{ok, NewState};
|
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
{error, Reason}
|
error({load_config_error, Reason});
|
||||||
|
{ok, _} ->
|
||||||
|
{ok, NState#{resource_id => ResourceId}}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
destroy(#{resource_id := ResourceId}) ->
|
||||||
|
_ = emqx_resource:remove_local(ResourceId),
|
||||||
|
ok.
|
||||||
|
|
||||||
authenticate(#{auth_method := _}, _) ->
|
authenticate(#{auth_method := _}, _) ->
|
||||||
ignore;
|
ignore;
|
||||||
authenticate(
|
authenticate(
|
||||||
|
@ -190,14 +172,31 @@ authenticate(
|
||||||
ignore
|
ignore
|
||||||
end.
|
end.
|
||||||
|
|
||||||
destroy(#{resource_id := ResourceId}) ->
|
|
||||||
_ = emqx_resource:remove_local(ResourceId),
|
|
||||||
ok.
|
|
||||||
|
|
||||||
%%------------------------------------------------------------------------------
|
%%------------------------------------------------------------------------------
|
||||||
%% Internal functions
|
%% Internal functions
|
||||||
%%------------------------------------------------------------------------------
|
%%------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
parse_config(
|
||||||
|
#{
|
||||||
|
cmd := Cmd,
|
||||||
|
password_hash_algorithm := Algorithm
|
||||||
|
} = Config
|
||||||
|
) ->
|
||||||
|
try
|
||||||
|
NCmd = parse_cmd(Cmd),
|
||||||
|
ok = emqx_authn_password_hashing:init(Algorithm),
|
||||||
|
ok = emqx_authn_utils:ensure_apps_started(Algorithm),
|
||||||
|
State = maps:with([password_hash_algorithm, salt_position], Config),
|
||||||
|
{Config, State#{cmd => NCmd}}
|
||||||
|
catch
|
||||||
|
error:{unsupported_cmd, _Cmd} ->
|
||||||
|
{error, {unsupported_cmd, Cmd}};
|
||||||
|
error:missing_password_hash ->
|
||||||
|
{error, missing_password_hash};
|
||||||
|
error:{unsupported_fields, Fields} ->
|
||||||
|
{error, {unsupported_fields, Fields}}
|
||||||
|
end.
|
||||||
|
|
||||||
%% Only support HGET and HMGET
|
%% Only support HGET and HMGET
|
||||||
parse_cmd(Cmd) ->
|
parse_cmd(Cmd) ->
|
||||||
case string:tokens(Cmd, " ") of
|
case string:tokens(Cmd, " ") of
|
||||||
|
|
|
@ -63,16 +63,20 @@
|
||||||
%% Initialize authz backend.
|
%% Initialize authz backend.
|
||||||
%% Populate the passed configuration map with necessary data,
|
%% Populate the passed configuration map with necessary data,
|
||||||
%% like `ResourceID`s
|
%% like `ResourceID`s
|
||||||
-callback init(source()) -> source().
|
-callback create(source()) -> source().
|
||||||
|
|
||||||
%% Get authz text description.
|
%% Update authz backend.
|
||||||
-callback description() -> string().
|
%% Change configuration, or simply enable/disable
|
||||||
|
-callback update(source()) -> source().
|
||||||
|
|
||||||
%% Destroy authz backend.
|
%% Destroy authz backend.
|
||||||
%% Make cleanup of all allocated data.
|
%% Make cleanup of all allocated data.
|
||||||
%% An authz backend will not be used after `destroy`.
|
%% An authz backend will not be used after `destroy`.
|
||||||
-callback destroy(source()) -> ok.
|
-callback destroy(source()) -> ok.
|
||||||
|
|
||||||
|
%% Get authz text description.
|
||||||
|
-callback description() -> string().
|
||||||
|
|
||||||
%% Authorize client action.
|
%% Authorize client action.
|
||||||
-callback authorize(
|
-callback authorize(
|
||||||
emqx_types:clientinfo(),
|
emqx_types:clientinfo(),
|
||||||
|
@ -81,6 +85,10 @@
|
||||||
source()
|
source()
|
||||||
) -> match_result().
|
) -> match_result().
|
||||||
|
|
||||||
|
-optional_callbacks([
|
||||||
|
update/1
|
||||||
|
]).
|
||||||
|
|
||||||
-spec register_metrics() -> ok.
|
-spec register_metrics() -> ok.
|
||||||
register_metrics() ->
|
register_metrics() ->
|
||||||
lists:foreach(fun emqx_metrics:ensure/1, ?METRICS).
|
lists:foreach(fun emqx_metrics:ensure/1, ?METRICS).
|
||||||
|
@ -90,7 +98,7 @@ init() ->
|
||||||
emqx_conf:add_handler(?CONF_KEY_PATH, ?MODULE),
|
emqx_conf:add_handler(?CONF_KEY_PATH, ?MODULE),
|
||||||
Sources = emqx_conf:get(?CONF_KEY_PATH, []),
|
Sources = emqx_conf:get(?CONF_KEY_PATH, []),
|
||||||
ok = check_dup_types(Sources),
|
ok = check_dup_types(Sources),
|
||||||
NSources = init_sources(Sources),
|
NSources = create_sources(Sources),
|
||||||
ok = emqx_hooks:add('client.authorize', {?MODULE, authorize, [NSources]}, -1).
|
ok = emqx_hooks:add('client.authorize', {?MODULE, authorize, [NSources]}, -1).
|
||||||
|
|
||||||
deinit() ->
|
deinit() ->
|
||||||
|
@ -170,7 +178,7 @@ do_post_config_update({?CMD_MOVE, _Type, _Where} = Cmd, _Sources) ->
|
||||||
InitedSources = lookup(),
|
InitedSources = lookup(),
|
||||||
do_move(Cmd, InitedSources);
|
do_move(Cmd, InitedSources);
|
||||||
do_post_config_update({?CMD_PREPEND, RawNewSource}, Sources) ->
|
do_post_config_update({?CMD_PREPEND, RawNewSource}, Sources) ->
|
||||||
InitedNewSource = init_source(get_source_by_type(type(RawNewSource), Sources)),
|
InitedNewSource = create_source(get_source_by_type(type(RawNewSource), Sources)),
|
||||||
%% create metrics
|
%% create metrics
|
||||||
TypeName = type(RawNewSource),
|
TypeName = type(RawNewSource),
|
||||||
ok = emqx_metrics_worker:create_metrics(
|
ok = emqx_metrics_worker:create_metrics(
|
||||||
|
@ -181,14 +189,13 @@ do_post_config_update({?CMD_PREPEND, RawNewSource}, Sources) ->
|
||||||
),
|
),
|
||||||
[InitedNewSource] ++ lookup();
|
[InitedNewSource] ++ lookup();
|
||||||
do_post_config_update({?CMD_APPEND, RawNewSource}, Sources) ->
|
do_post_config_update({?CMD_APPEND, RawNewSource}, Sources) ->
|
||||||
InitedNewSource = init_source(get_source_by_type(type(RawNewSource), Sources)),
|
InitedNewSource = create_source(get_source_by_type(type(RawNewSource), Sources)),
|
||||||
lookup() ++ [InitedNewSource];
|
lookup() ++ [InitedNewSource];
|
||||||
do_post_config_update({{?CMD_REPLACE, Type}, RawNewSource}, Sources) ->
|
do_post_config_update({{?CMD_REPLACE, Type}, RawNewSource}, Sources) ->
|
||||||
OldSources = lookup(),
|
OldSources = lookup(),
|
||||||
{OldSource, Front, Rear} = take(Type, OldSources),
|
{OldSource, Front, Rear} = take(Type, OldSources),
|
||||||
NewSource = get_source_by_type(type(RawNewSource), Sources),
|
NewSource = get_source_by_type(type(RawNewSource), Sources),
|
||||||
ok = ensure_resource_deleted(OldSource),
|
InitedSources = update_source(type(RawNewSource), OldSource, NewSource),
|
||||||
InitedSources = init_source(NewSource),
|
|
||||||
Front ++ [InitedSources] ++ Rear;
|
Front ++ [InitedSources] ++ Rear;
|
||||||
do_post_config_update({{?CMD_DELETE, Type}, _RawNewSource}, _Sources) ->
|
do_post_config_update({{?CMD_DELETE, Type}, _RawNewSource}, _Sources) ->
|
||||||
OldInitedSources = lookup(),
|
OldInitedSources = lookup(),
|
||||||
|
@ -203,7 +210,7 @@ do_post_config_update({?CMD_REPLACE, _RawNewSources}, Sources) ->
|
||||||
OldInitedSources = lookup(),
|
OldInitedSources = lookup(),
|
||||||
lists:foreach(fun ensure_resource_deleted/1, OldInitedSources),
|
lists:foreach(fun ensure_resource_deleted/1, OldInitedSources),
|
||||||
lists:foreach(fun clear_certs/1, OldInitedSources),
|
lists:foreach(fun clear_certs/1, OldInitedSources),
|
||||||
init_sources(Sources).
|
create_sources(Sources).
|
||||||
|
|
||||||
%% @doc do source move
|
%% @doc do source move
|
||||||
do_move({?CMD_MOVE, Type, ?CMD_MOVE_FRONT}, Sources) ->
|
do_move({?CMD_MOVE, Type, ?CMD_MOVE_FRONT}, Sources) ->
|
||||||
|
@ -251,20 +258,22 @@ check_dup_types([Source | Sources], Checked) ->
|
||||||
check_dup_types(Sources, [Type | Checked])
|
check_dup_types(Sources, [Type | Checked])
|
||||||
end.
|
end.
|
||||||
|
|
||||||
init_sources(Sources) ->
|
create_sources(Sources) ->
|
||||||
{_Enabled, Disabled} = lists:partition(fun(#{enable := Enable}) -> Enable end, Sources),
|
{_Enabled, Disabled} = lists:partition(fun(#{enable := Enable}) -> Enable end, Sources),
|
||||||
case Disabled =/= [] of
|
case Disabled =/= [] of
|
||||||
true -> ?SLOG(info, #{msg => "disabled_sources_ignored", sources => Disabled});
|
true -> ?SLOG(info, #{msg => "disabled_sources_ignored", sources => Disabled});
|
||||||
false -> ok
|
false -> ok
|
||||||
end,
|
end,
|
||||||
ok = lists:foreach(fun init_metrics/1, Sources),
|
ok = lists:foreach(fun init_metrics/1, Sources),
|
||||||
lists:map(fun init_source/1, Sources).
|
lists:map(fun create_source/1, Sources).
|
||||||
|
|
||||||
init_source(#{enable := false} = Source) ->
|
create_source(#{type := Type} = Source) ->
|
||||||
Source;
|
|
||||||
init_source(#{type := Type} = Source) ->
|
|
||||||
Module = authz_module(Type),
|
Module = authz_module(Type),
|
||||||
Module:init(Source).
|
Module:create(Source).
|
||||||
|
|
||||||
|
update_source(Type, OldSource, NewSource) ->
|
||||||
|
Module = authz_module(Type),
|
||||||
|
Module:update(maps:merge(OldSource, NewSource)).
|
||||||
|
|
||||||
init_metrics(Source) ->
|
init_metrics(Source) ->
|
||||||
TypeName = type(Source),
|
TypeName = type(Source),
|
||||||
|
|
|
@ -317,6 +317,7 @@ lookup_from_local_node(Type) ->
|
||||||
end;
|
end;
|
||||||
_ ->
|
_ ->
|
||||||
Metrics = emqx_metrics_worker:get_metrics(authz_metrics, Type),
|
Metrics = emqx_metrics_worker:get_metrics(authz_metrics, Type),
|
||||||
|
%% for authz file/authz mnesia
|
||||||
{ok, {NodeId, connected, Metrics, #{}}}
|
{ok, {NodeId, connected, Metrics, #{}}}
|
||||||
catch
|
catch
|
||||||
_:Reason -> {error, {NodeId, list_to_binary(io_lib:format("~p", [Reason]))}}
|
_:Reason -> {error, {NodeId, list_to_binary(io_lib:format("~p", [Reason]))}}
|
||||||
|
|
|
@ -29,7 +29,8 @@
|
||||||
%% APIs
|
%% APIs
|
||||||
-export([
|
-export([
|
||||||
description/0,
|
description/0,
|
||||||
init/1,
|
create/1,
|
||||||
|
update/1,
|
||||||
destroy/1,
|
destroy/1,
|
||||||
authorize/4
|
authorize/4
|
||||||
]).
|
]).
|
||||||
|
@ -37,7 +38,7 @@
|
||||||
description() ->
|
description() ->
|
||||||
"AuthZ with static rules".
|
"AuthZ with static rules".
|
||||||
|
|
||||||
init(#{path := Path} = Source) ->
|
create(#{path := Path} = Source) ->
|
||||||
Rules =
|
Rules =
|
||||||
case file:consult(Path) of
|
case file:consult(Path) of
|
||||||
{ok, Terms} ->
|
{ok, Terms} ->
|
||||||
|
@ -55,6 +56,9 @@ init(#{path := Path} = Source) ->
|
||||||
end,
|
end,
|
||||||
Source#{annotations => #{rules => Rules}}.
|
Source#{annotations => #{rules => Rules}}.
|
||||||
|
|
||||||
|
update(#{path := _Path} = Source) ->
|
||||||
|
create(Source).
|
||||||
|
|
||||||
destroy(_Source) -> ok.
|
destroy(_Source) -> ok.
|
||||||
|
|
||||||
authorize(Client, PubSub, Topic, #{annotations := #{rules := Rules}}) ->
|
authorize(Client, PubSub, Topic, #{annotations := #{rules := Rules}}) ->
|
||||||
|
|
|
@ -26,7 +26,8 @@
|
||||||
%% AuthZ Callbacks
|
%% AuthZ Callbacks
|
||||||
-export([
|
-export([
|
||||||
description/0,
|
description/0,
|
||||||
init/1,
|
create/1,
|
||||||
|
update/1,
|
||||||
destroy/1,
|
destroy/1,
|
||||||
authorize/4,
|
authorize/4,
|
||||||
parse_url/1
|
parse_url/1
|
||||||
|
@ -50,10 +51,18 @@
|
||||||
description() ->
|
description() ->
|
||||||
"AuthZ with http".
|
"AuthZ with http".
|
||||||
|
|
||||||
init(Config) ->
|
create(Config) ->
|
||||||
NConfig = parse_config(Config),
|
NConfig = parse_config(Config),
|
||||||
{ok, Id} = emqx_authz_utils:create_resource(emqx_connector_http, NConfig),
|
ResourceId = emqx_authn_utils:make_resource_id(?MODULE),
|
||||||
NConfig#{annotations => #{id => Id}}.
|
{ok, _Data} = emqx_authz_utils:create_resource(ResourceId, emqx_connector_http, NConfig),
|
||||||
|
NConfig#{annotations => #{id => ResourceId}}.
|
||||||
|
|
||||||
|
update(Config) ->
|
||||||
|
NConfig = parse_config(Config),
|
||||||
|
case emqx_authz_utils:update_resource(emqx_connector_http, NConfig) of
|
||||||
|
{error, Reason} -> error({load_config_error, Reason});
|
||||||
|
{ok, Id} -> NConfig#{annotations => #{id => Id}}
|
||||||
|
end.
|
||||||
|
|
||||||
destroy(#{annotations := #{id := Id}}) ->
|
destroy(#{annotations := #{id := Id}}) ->
|
||||||
ok = emqx_resource:remove_local(Id).
|
ok = emqx_resource:remove_local(Id).
|
||||||
|
|
|
@ -28,7 +28,8 @@
|
||||||
%% APIs
|
%% APIs
|
||||||
-export([
|
-export([
|
||||||
description/0,
|
description/0,
|
||||||
init/1,
|
create/1,
|
||||||
|
update/1,
|
||||||
destroy/1,
|
destroy/1,
|
||||||
authorize/4
|
authorize/4
|
||||||
]).
|
]).
|
||||||
|
@ -46,7 +47,10 @@
|
||||||
description() ->
|
description() ->
|
||||||
"AuthZ with JWT".
|
"AuthZ with JWT".
|
||||||
|
|
||||||
init(#{acl_claim_name := _AclClaimName} = Source) ->
|
create(#{acl_claim_name := _AclClaimName} = Source) ->
|
||||||
|
Source.
|
||||||
|
|
||||||
|
update(#{acl_claim_name := _AclClaimName} = Source) ->
|
||||||
Source.
|
Source.
|
||||||
|
|
||||||
destroy(_Source) -> ok.
|
destroy(_Source) -> ok.
|
||||||
|
|
|
@ -46,7 +46,8 @@
|
||||||
%% AuthZ Callbacks
|
%% AuthZ Callbacks
|
||||||
-export([
|
-export([
|
||||||
description/0,
|
description/0,
|
||||||
init/1,
|
create/1,
|
||||||
|
update/1,
|
||||||
destroy/1,
|
destroy/1,
|
||||||
authorize/4
|
authorize/4
|
||||||
]).
|
]).
|
||||||
|
@ -88,7 +89,9 @@ mnesia(boot) ->
|
||||||
description() ->
|
description() ->
|
||||||
"AuthZ with Mnesia".
|
"AuthZ with Mnesia".
|
||||||
|
|
||||||
init(Source) -> Source.
|
create(Source) -> Source.
|
||||||
|
|
||||||
|
update(Source) -> Source.
|
||||||
|
|
||||||
destroy(_Source) -> ok.
|
destroy(_Source) -> ok.
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,8 @@
|
||||||
%% AuthZ Callbacks
|
%% AuthZ Callbacks
|
||||||
-export([
|
-export([
|
||||||
description/0,
|
description/0,
|
||||||
init/1,
|
create/1,
|
||||||
|
update/1,
|
||||||
destroy/1,
|
destroy/1,
|
||||||
authorize/4
|
authorize/4
|
||||||
]).
|
]).
|
||||||
|
@ -45,15 +46,20 @@
|
||||||
description() ->
|
description() ->
|
||||||
"AuthZ with MongoDB".
|
"AuthZ with MongoDB".
|
||||||
|
|
||||||
init(#{filter := Filter} = Source) ->
|
create(#{filter := Filter} = Source) ->
|
||||||
{ok, Id} = emqx_authz_utils:create_resource(emqx_connector_mongo, Source),
|
ResourceId = emqx_authz_utils:make_resource_id(?MODULE),
|
||||||
Source#{
|
{ok, _Data} = emqx_authz_utils:create_resource(ResourceId, emqx_connector_mongo, Source),
|
||||||
annotations => #{id => Id},
|
FilterTemp = emqx_authz_utils:parse_deep(Filter, ?PLACEHOLDERS),
|
||||||
filter_template => emqx_authz_utils:parse_deep(
|
Source#{annotations => #{id => ResourceId}, filter_template => FilterTemp}.
|
||||||
Filter,
|
|
||||||
?PLACEHOLDERS
|
update(#{filter := Filter} = Source) ->
|
||||||
)
|
FilterTemp = emqx_authz_utils:parse_deep(Filter, ?PLACEHOLDERS),
|
||||||
}.
|
case emqx_authz_utils:update_resource(emqx_connector_mongo, Source) of
|
||||||
|
{error, Reason} ->
|
||||||
|
error({load_config_error, Reason});
|
||||||
|
{ok, Id} ->
|
||||||
|
Source#{annotations => #{id => Id}, filter_template => FilterTemp}
|
||||||
|
end.
|
||||||
|
|
||||||
destroy(#{annotations := #{id := Id}}) ->
|
destroy(#{annotations := #{id := Id}}) ->
|
||||||
ok = emqx_resource:remove_local(Id).
|
ok = emqx_resource:remove_local(Id).
|
||||||
|
|
|
@ -28,7 +28,8 @@
|
||||||
%% AuthZ Callbacks
|
%% AuthZ Callbacks
|
||||||
-export([
|
-export([
|
||||||
description/0,
|
description/0,
|
||||||
init/1,
|
create/1,
|
||||||
|
update/1,
|
||||||
destroy/1,
|
destroy/1,
|
||||||
authorize/4
|
authorize/4
|
||||||
]).
|
]).
|
||||||
|
@ -49,11 +50,22 @@
|
||||||
description() ->
|
description() ->
|
||||||
"AuthZ with Mysql".
|
"AuthZ with Mysql".
|
||||||
|
|
||||||
init(#{query := SQL} = Source0) ->
|
create(#{query := SQL} = Source0) ->
|
||||||
|
{PrepareSQL, TmplToken} = emqx_authz_utils:parse_sql(SQL, '?', ?PLACEHOLDERS),
|
||||||
|
ResourceId = emqx_authz_utils:make_resource_id(?MODULE),
|
||||||
|
Source = Source0#{prepare_statement => #{?PREPARE_KEY => PrepareSQL}},
|
||||||
|
{ok, _Data} = emqx_authz_utils:create_resource(ResourceId, emqx_connector_mysql, Source),
|
||||||
|
Source#{annotations => #{id => ResourceId, tmpl_oken => TmplToken}}.
|
||||||
|
|
||||||
|
update(#{query := SQL} = Source0) ->
|
||||||
{PrepareSQL, TmplToken} = emqx_authz_utils:parse_sql(SQL, '?', ?PLACEHOLDERS),
|
{PrepareSQL, TmplToken} = emqx_authz_utils:parse_sql(SQL, '?', ?PLACEHOLDERS),
|
||||||
Source = Source0#{prepare_statement => #{?PREPARE_KEY => PrepareSQL}},
|
Source = Source0#{prepare_statement => #{?PREPARE_KEY => PrepareSQL}},
|
||||||
{ok, Id} = emqx_authz_utils:create_resource(emqx_connector_mysql, Source),
|
case emqx_authz_utils:update_resource(emqx_connector_mysql, Source) of
|
||||||
Source#{annotations => #{id => Id, tmpl_oken => TmplToken}}.
|
{error, Reason} ->
|
||||||
|
error({load_config_error, Reason});
|
||||||
|
{ok, Id} ->
|
||||||
|
Source#{annotations => #{id => Id, tmpl_oken => TmplToken}}
|
||||||
|
end.
|
||||||
|
|
||||||
destroy(#{annotations := #{id := Id}}) ->
|
destroy(#{annotations := #{id := Id}}) ->
|
||||||
ok = emqx_resource:remove_local(Id).
|
ok = emqx_resource:remove_local(Id).
|
||||||
|
|
|
@ -26,7 +26,8 @@
|
||||||
%% AuthZ Callbacks
|
%% AuthZ Callbacks
|
||||||
-export([
|
-export([
|
||||||
description/0,
|
description/0,
|
||||||
init/1,
|
create/1,
|
||||||
|
update/1,
|
||||||
destroy/1,
|
destroy/1,
|
||||||
authorize/4
|
authorize/4
|
||||||
]).
|
]).
|
||||||
|
@ -47,27 +48,29 @@
|
||||||
description() ->
|
description() ->
|
||||||
"AuthZ with PostgreSQL".
|
"AuthZ with PostgreSQL".
|
||||||
|
|
||||||
init(#{query := SQL0} = Source) ->
|
create(#{query := SQL0} = Source) ->
|
||||||
{SQL, PlaceHolders} = emqx_authz_utils:parse_sql(
|
{SQL, PlaceHolders} = emqx_authz_utils:parse_sql(SQL0, '$n', ?PLACEHOLDERS),
|
||||||
SQL0,
|
|
||||||
'$n',
|
|
||||||
?PLACEHOLDERS
|
|
||||||
),
|
|
||||||
ResourceID = emqx_authz_utils:make_resource_id(emqx_connector_pgsql),
|
ResourceID = emqx_authz_utils:make_resource_id(emqx_connector_pgsql),
|
||||||
{ok, _Data} = emqx_resource:create_local(
|
{ok, _Data} = emqx_authz_utils:create_resource(
|
||||||
ResourceID,
|
ResourceID,
|
||||||
?RESOURCE_GROUP,
|
|
||||||
emqx_connector_pgsql,
|
emqx_connector_pgsql,
|
||||||
Source#{prepare_statement => #{ResourceID => SQL}},
|
Source#{prepare_statement => #{ResourceID => SQL}}
|
||||||
#{}
|
|
||||||
),
|
),
|
||||||
Source#{
|
Source#{annotations => #{id => ResourceID, placeholders => PlaceHolders}}.
|
||||||
annotations =>
|
|
||||||
#{
|
update(#{query := SQL0, annotations := #{id := ResourceID}} = Source) ->
|
||||||
id => ResourceID,
|
{SQL, PlaceHolders} = emqx_authz_utils:parse_sql(SQL0, '$n', ?PLACEHOLDERS),
|
||||||
placeholders => PlaceHolders
|
case
|
||||||
}
|
emqx_authz_utils:update_resource(
|
||||||
}.
|
emqx_connector_pgsql,
|
||||||
|
Source#{prepare_statement => #{ResourceID => SQL}}
|
||||||
|
)
|
||||||
|
of
|
||||||
|
{error, Reason} ->
|
||||||
|
error({load_config_error, Reason});
|
||||||
|
{ok, Id} ->
|
||||||
|
Source#{annotations => #{id => Id, placeholders => PlaceHolders}}
|
||||||
|
end.
|
||||||
|
|
||||||
destroy(#{annotations := #{id := Id}}) ->
|
destroy(#{annotations := #{id := Id}}) ->
|
||||||
ok = emqx_resource:remove_local(Id).
|
ok = emqx_resource:remove_local(Id).
|
||||||
|
|
|
@ -26,7 +26,8 @@
|
||||||
%% AuthZ Callbacks
|
%% AuthZ Callbacks
|
||||||
-export([
|
-export([
|
||||||
description/0,
|
description/0,
|
||||||
init/1,
|
create/1,
|
||||||
|
update/1,
|
||||||
destroy/1,
|
destroy/1,
|
||||||
authorize/4
|
authorize/4
|
||||||
]).
|
]).
|
||||||
|
@ -47,14 +48,22 @@
|
||||||
description() ->
|
description() ->
|
||||||
"AuthZ with Redis".
|
"AuthZ with Redis".
|
||||||
|
|
||||||
init(#{cmd := CmdStr} = Source) ->
|
create(#{cmd := CmdStr} = Source) ->
|
||||||
|
Cmd = tokens(CmdStr),
|
||||||
|
ResourceId = emqx_authz_utils:make_resource_id(?MODULE),
|
||||||
|
CmdTemplate = emqx_authz_utils:parse_deep(Cmd, ?PLACEHOLDERS),
|
||||||
|
{ok, _Data} = emqx_authz_utils:create_resource(ResourceId, emqx_connector_redis, Source),
|
||||||
|
Source#{annotations => #{id => ResourceId}, cmd_template => CmdTemplate}.
|
||||||
|
|
||||||
|
update(#{cmd := CmdStr} = Source) ->
|
||||||
Cmd = tokens(CmdStr),
|
Cmd = tokens(CmdStr),
|
||||||
CmdTemplate = emqx_authz_utils:parse_deep(Cmd, ?PLACEHOLDERS),
|
CmdTemplate = emqx_authz_utils:parse_deep(Cmd, ?PLACEHOLDERS),
|
||||||
{ok, Id} = emqx_authz_utils:create_resource(emqx_connector_redis, Source),
|
case emqx_authz_utils:update_resource(emqx_connector_redis, Source) of
|
||||||
Source#{
|
{error, Reason} ->
|
||||||
annotations => #{id => Id},
|
error({load_config_error, Reason});
|
||||||
cmd_template => CmdTemplate
|
{ok, Id} ->
|
||||||
}.
|
Source#{annotations => #{id => Id}, cmd_template => CmdTemplate}
|
||||||
|
end.
|
||||||
|
|
||||||
destroy(#{annotations := #{id := Id}}) ->
|
destroy(#{annotations := #{id := Id}}) ->
|
||||||
ok = emqx_resource:remove_local(Id).
|
ok = emqx_resource:remove_local(Id).
|
||||||
|
|
|
@ -23,6 +23,8 @@
|
||||||
cleanup_resources/0,
|
cleanup_resources/0,
|
||||||
make_resource_id/1,
|
make_resource_id/1,
|
||||||
create_resource/2,
|
create_resource/2,
|
||||||
|
create_resource/3,
|
||||||
|
update_resource/2,
|
||||||
update_config/2,
|
update_config/2,
|
||||||
parse_deep/2,
|
parse_deep/2,
|
||||||
parse_str/2,
|
parse_str/2,
|
||||||
|
@ -37,15 +39,37 @@
|
||||||
%%------------------------------------------------------------------------------
|
%%------------------------------------------------------------------------------
|
||||||
|
|
||||||
create_resource(Module, Config) ->
|
create_resource(Module, Config) ->
|
||||||
ResourceID = make_resource_id(Module),
|
ResourceId = make_resource_id(Module),
|
||||||
|
create_resource(ResourceId, Module, Config).
|
||||||
|
|
||||||
|
create_resource(ResourceId, Module, Config) ->
|
||||||
{ok, _Data} = emqx_resource:create_local(
|
{ok, _Data} = emqx_resource:create_local(
|
||||||
ResourceID,
|
ResourceId,
|
||||||
?RESOURCE_GROUP,
|
?RESOURCE_GROUP,
|
||||||
Module,
|
Module,
|
||||||
Config,
|
Config,
|
||||||
#{}
|
#{}
|
||||||
),
|
).
|
||||||
{ok, ResourceID}.
|
|
||||||
|
update_resource(Module, #{annotations := #{id := ResourceId}} = Source) ->
|
||||||
|
Result =
|
||||||
|
case
|
||||||
|
emqx_resource:recreate_local(
|
||||||
|
ResourceId,
|
||||||
|
Module,
|
||||||
|
Source
|
||||||
|
)
|
||||||
|
of
|
||||||
|
{ok, _} -> {ok, ResourceId};
|
||||||
|
{error, Reason} -> {error, Reason}
|
||||||
|
end,
|
||||||
|
case Source of
|
||||||
|
#{enable := true} ->
|
||||||
|
Result;
|
||||||
|
#{enable := false} ->
|
||||||
|
ok = emqx_resource:stop(ResourceId),
|
||||||
|
Result
|
||||||
|
end.
|
||||||
|
|
||||||
cleanup_resources() ->
|
cleanup_resources() ->
|
||||||
lists:foreach(
|
lists:foreach(
|
||||||
|
|
Loading…
Reference in New Issue