fix(sso): refactor update logic

This commit is contained in:
firest 2023-09-28 00:09:09 +08:00
parent 08ad09a68f
commit 66d2107007
2 changed files with 53 additions and 78 deletions

View File

@ -271,8 +271,6 @@ handle_backend_update_result(ok, _) ->
204; 204;
handle_backend_update_result({error, not_exists}, _) -> handle_backend_update_result({error, not_exists}, _) ->
{404, #{code => ?BACKEND_NOT_FOUND, message => <<"Backend not found">>}}; {404, #{code => ?BACKEND_NOT_FOUND, message => <<"Backend not found">>}};
handle_backend_update_result({error, already_exists}, _) ->
{400, #{code => ?BAD_REQUEST, message => <<"Backend already exists">>}};
handle_backend_update_result({error, failed_to_load_metadata}, _) -> handle_backend_update_result({error, failed_to_load_metadata}, _) ->
{400, #{code => ?BAD_REQUEST, message => <<"Failed to load metadata">>}}; {400, #{code => ?BAD_REQUEST, message => <<"Failed to load metadata">>}};
handle_backend_update_result({error, Reason}, _) when is_binary(Reason) -> handle_backend_update_result({error, Reason}, _) when is_binary(Reason) ->

View File

@ -24,8 +24,8 @@
-export([ -export([
running/0, running/0,
get_backend_status/2,
lookup_state/1, lookup_state/1,
get_backend_status/2,
make_resource_id/1, make_resource_id/1,
create_resource/3, create_resource/3,
update_resource/3 update_resource/3
@ -45,7 +45,7 @@
-define(MOD_KEY_PATH, [dashboard, sso]). -define(MOD_KEY_PATH, [dashboard, sso]).
-define(MOD_KEY_PATH(Sub), [dashboard, sso, Sub]). -define(MOD_KEY_PATH(Sub), [dashboard, sso, Sub]).
-define(RESOURCE_GROUP, <<"emqx_dashboard_sso">>). -define(RESOURCE_GROUP, <<"emqx_dashboard_sso">>).
-define(START_ERROR_KEY, start_error). -define(NO_ERROR, <<>>).
-define(DEFAULT_RESOURCE_OPTS, #{ -define(DEFAULT_RESOURCE_OPTS, #{
start_after_created => false start_after_created => false
}). }).
@ -53,7 +53,7 @@
-record(?MOD_TAB, { -record(?MOD_TAB, {
backend :: atom(), backend :: atom(),
state :: map(), state :: map(),
last_error = <<>> :: term() last_error = ?NO_ERROR :: term()
}). }).
%%------------------------------------------------------------------------------ %%------------------------------------------------------------------------------
@ -65,7 +65,7 @@ start_link() ->
running() -> running() ->
lists:filtermap( lists:filtermap(
fun fun
(#?MOD_TAB{backend = Backend, last_error = <<>>}) -> (#?MOD_TAB{backend = Backend, last_error = ?NO_ERROR}) ->
{true, Backend}; {true, Backend};
(_) -> (_) ->
false false
@ -78,7 +78,7 @@ get_backend_status(Backend, false) ->
backend => Backend, backend => Backend,
enable => false, enable => false,
running => false, running => false,
last_error => <<>> last_error => ?NO_ERROR
}; };
get_backend_status(Backend, _) -> get_backend_status(Backend, _) ->
case lookup(Backend) of case lookup(Backend) of
@ -87,7 +87,7 @@ get_backend_status(Backend, _) ->
backend => Backend, backend => Backend,
enable => true, enable => true,
running => false, running => false,
last_error => <<"resource not found">> last_error => <<"Resource not found">>
}; };
Data -> Data ->
maps:merge(#{backend => Backend, enable => true}, do_get_backend_status(Data)) maps:merge(#{backend => Backend, enable => true}, do_get_backend_status(Data))
@ -179,54 +179,41 @@ start_backend_services() ->
msg => "start_sso_backend_successfully", msg => "start_sso_backend_successfully",
backend => Backend backend => Backend
}), }),
ets:insert(?MOD_TAB, #?MOD_TAB{backend = Backend, state = State}); update_state(Backend, State);
{error, Reason} -> {error, Reason} ->
SafeReason = emqx_utils:redact(Reason),
update_last_error(Backend, SafeReason),
?SLOG(error, #{ ?SLOG(error, #{
msg => "start_sso_backend_failed", msg => "start_sso_backend_failed",
backend => Backend, backend => Backend,
reason => emqx_utils:redact(Reason) reason => SafeReason
}) })
end, end
record_start_error(Backend, false)
end, end,
maps:to_list(Backends) maps:to_list(Backends)
). ).
update_config(Backend, UpdateReq) -> update_config(Backend, UpdateReq) ->
OkFun = fun(Result) ->
?SLOG(info, #{
msg => "update_sso_successfully",
backend => Backend,
result => emqx_utils:redact(Result)
}),
Result
end,
ErrFun = fun({error, Reason} = Error) ->
SafeReason = emqx_utils:redact(Reason),
?SLOG(error, #{
msg => "update_sso_failed",
backend => Backend,
reason => SafeReason
}),
Error
end,
%% we always make sure the valid configuration will update successfully, %% we always make sure the valid configuration will update successfully,
%% ignore the runtime error during its update %% ignore the runtime error during its update
case emqx_conf:update(?MOD_KEY_PATH(Backend), UpdateReq, #{override_to => cluster}) of case emqx_conf:update(?MOD_KEY_PATH(Backend), UpdateReq, #{override_to => cluster}) of
{ok, UpdateResult} -> {ok, _UpdateResult} ->
#{post_config_update := #{?MODULE := Result}} = UpdateResult, case lookup(Backend) of
case Result of undefined ->
ok -> ok;
OkFun(Result); #?MOD_TAB{state = State, last_error = ?NO_ERROR} ->
{ok, _} -> {ok, State};
OkFun(Result); Data ->
{error, _} = Error -> {error, Data#?MOD_TAB.last_error}
ErrFun(Error)
end; end;
{error, _} = Error -> {error, Reason} = Error ->
ErrFun(Error) SafeReason = emqx_utils:redact(Reason),
?SLOG(error, #{
msg => "update_sso_failed",
backend => Backend,
reason => SafeReason
}),
Error
end. end.
pre_config_update(_, {update, _Backend, Config}, _OldConf) -> pre_config_update(_, {update, _Backend, Config}, _OldConf) ->
@ -237,7 +224,8 @@ pre_config_update(_, {delete, _Backend}, _OldConf) ->
{ok, null}. {ok, null}.
post_config_update(_, UpdateReq, NewConf, _OldConf, _AppEnvs) -> post_config_update(_, UpdateReq, NewConf, _OldConf, _AppEnvs) ->
{ok, on_config_update(UpdateReq, NewConf)}. _ = on_config_update(UpdateReq, NewConf),
ok.
propagated_post_config_update( propagated_post_config_update(
?MOD_KEY_PATH(BackendBin) = Path, _UpdateReq, undefined, OldConf, AppEnvs ?MOD_KEY_PATH(BackendBin) = Path, _UpdateReq, undefined, OldConf, AppEnvs
@ -265,26 +253,23 @@ on_config_update({update, Backend, _RawConfig}, Config) ->
on_backend_updated( on_backend_updated(
Backend, Backend,
emqx_dashboard_sso:create(Provider, Config), emqx_dashboard_sso:create(Provider, Config),
fun(State, LastError) -> fun(State) ->
ets:insert( update_state(Backend, State)
?MOD_TAB,
#?MOD_TAB{backend = Backend, state = State, last_error = LastError}
)
end end
); );
Data -> Data ->
on_backend_updated( on_backend_updated(
Backend, Backend,
emqx_dashboard_sso:update(Provider, Config, Data#?MOD_TAB.state), emqx_dashboard_sso:update(Provider, Config, Data#?MOD_TAB.state),
fun(State, LastError) -> fun(State) ->
ets:insert(?MOD_TAB, Data#?MOD_TAB{state = State, last_error = LastError}) update_state(Backend, State)
end end
) )
end; end;
on_config_update({delete, Backend}, _NewConf) -> on_config_update({delete, Backend}, _NewConf) ->
case lookup(Backend) of case lookup(Backend) of
undefined -> undefined ->
{error, not_exists}; on_backend_updated(Backend, {error, not_exists}, undefined);
Data -> Data ->
Provider = provider(Backend), Provider = provider(Backend),
on_backend_updated( on_backend_updated(
@ -306,31 +291,26 @@ lookup(Backend) ->
%% to avoid resource leakage the resource start will never affect the update result, %% to avoid resource leakage the resource start will never affect the update result,
%% so the resource_id will always be recorded %% so the resource_id will always be recorded
start_resource_if_enabled(ResourceId, {ok, _} = Result, #{enable := true}) -> start_resource_if_enabled(ResourceId, {ok, _} = Result, #{enable := true, backend := Backend}) ->
clear_start_error(),
case emqx_resource:start(ResourceId) of case emqx_resource:start(ResourceId) of
ok -> ok ->
ok; ok;
{error, Reason} -> {error, Reason} ->
SafeReason = emqx_utils:redact(Reason), SafeReason = emqx_utils:redact(Reason),
mark_start_error(SafeReason),
?SLOG(error, #{ ?SLOG(error, #{
msg => "start_backend_failed", msg => "start_backend_failed",
resource_id => ResourceId, resource_id => ResourceId,
reason => SafeReason reason => SafeReason
}), }),
update_last_error(Backend, SafeReason),
ok ok
end, end,
Result; Result;
start_resource_if_enabled(_ResourceId, Result, _Config) -> start_resource_if_enabled(_ResourceId, Result, _Config) ->
Result. Result.
on_backend_updated(Backend, {ok, State} = Ok, Fun) -> on_backend_updated(_Backend, {ok, State} = Ok, Fun) ->
Fun(State, <<>>), Fun(State),
record_start_error(Backend, true),
Ok;
on_backend_updated(_Backend, {ok, State, LastError} = Ok, Fun) ->
Fun(State, LastError),
Ok; Ok;
on_backend_updated(_Backend, ok, Fun) -> on_backend_updated(_Backend, ok, Fun) ->
Fun(), Fun(),
@ -373,29 +353,26 @@ new_ssl_source(Source, undefined) ->
new_ssl_source(Source, SSL) -> new_ssl_source(Source, SSL) ->
Source#{<<"ssl">> => SSL}. Source#{<<"ssl">> => SSL}.
clear_start_error() -> update_state(Backend, State) ->
mark_start_error(<<>>). Data = ensure_backend_data(Backend),
ets:insert(?MOD_TAB, Data#?MOD_TAB{state = State}).
mark_start_error(Reason) -> update_last_error(Backend, LastError) ->
erlang:put(?START_ERROR_KEY, Reason). Data = ensure_backend_data(Backend),
ets:insert(?MOD_TAB, Data#?MOD_TAB{last_error = LastError}).
record_start_error(Backend, Force) -> ensure_backend_data(Backend) ->
case erlang:get(?START_ERROR_KEY) of case ets:lookup(?MOD_TAB, Backend) of
<<>> when Force -> [Data] ->
update_last_error(Backend, <<>>); Data;
<<>> -> [] ->
ok; #?MOD_TAB{backend = Backend}
Reason ->
update_last_error(Backend, Reason)
end. end.
update_last_error(Backend, Reason) ->
ets:update_element(?MOD_TAB, Backend, {#?MOD_TAB.last_error, Reason}).
do_get_backend_status(#?MOD_TAB{state = #{resource_id := ResourceId}}) -> do_get_backend_status(#?MOD_TAB{state = #{resource_id := ResourceId}}) ->
case emqx_resource_manager:lookup(ResourceId) of case emqx_resource_manager:lookup(ResourceId) of
{ok, _Group, #{status := connected}} -> {ok, _Group, #{status := connected}} ->
#{running => true, last_error => <<>>}; #{running => true, last_error => ?NO_ERROR};
{ok, _Group, #{status := Status}} -> {ok, _Group, #{status := Status}} ->
#{ #{
running => false, running => false,
@ -407,8 +384,8 @@ do_get_backend_status(#?MOD_TAB{state = #{resource_id := ResourceId}}) ->
last_error => <<"Resource not found">> last_error => <<"Resource not found">>
} }
end; end;
do_get_backend_status(#?MOD_TAB{last_error = <<>>}) -> do_get_backend_status(#?MOD_TAB{last_error = ?NO_ERROR}) ->
#{running => true, last_error => <<>>}; #{running => true, last_error => ?NO_ERROR};
do_get_backend_status(#?MOD_TAB{last_error = LastError}) -> do_get_backend_status(#?MOD_TAB{last_error = LastError}) ->
#{ #{
running => false, running => false,