feat: add group/type to resource slog

This commit is contained in:
zhongwencool 2024-07-11 17:09:10 +08:00
parent cba3f532f8
commit 0a04b1ad6e
49 changed files with 232 additions and 122 deletions

View File

@ -30,6 +30,6 @@
-type authenticator_id() :: binary(). -type authenticator_id() :: binary().
-define(AUTHN_RESOURCE_GROUP, <<"emqx_authn">>). -define(AUTHN_RESOURCE_GROUP, <<"authn">>).
-endif. -endif.

View File

@ -158,7 +158,7 @@
count => 1 count => 1
}). }).
-define(AUTHZ_RESOURCE_GROUP, <<"emqx_authz">>). -define(AUTHZ_RESOURCE_GROUP, <<"authz">>).
-define(AUTHZ_FEATURES, [rich_actions]). -define(AUTHZ_FEATURES, [rich_actions]).

View File

@ -21,8 +21,8 @@
-include_lib("snabbkaffe/include/trace.hrl"). -include_lib("snabbkaffe/include/trace.hrl").
-export([ -export([
create_resource/3, create_resource/4,
update_resource/3, update_resource/4,
check_password_from_selected_map/3, check_password_from_selected_map/3,
parse_deep/1, parse_deep/1,
parse_str/1, parse_str/1,
@ -66,8 +66,9 @@
%% APIs %% APIs
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
create_resource(ResourceId, Module, Config) -> create_resource(Type, ResourceId, Module, Config) ->
Result = emqx_resource:create_local( Result = emqx_resource:create_local(
Type,
ResourceId, ResourceId,
?AUTHN_RESOURCE_GROUP, ?AUTHN_RESOURCE_GROUP,
Module, Module,
@ -76,9 +77,9 @@ create_resource(ResourceId, Module, Config) ->
), ),
start_resource_if_enabled(Result, ResourceId, Config). start_resource_if_enabled(Result, ResourceId, Config).
update_resource(Module, Config, ResourceId) -> update_resource(Type, Module, Config, ResourceId) ->
Result = emqx_resource:recreate_local( Result = emqx_resource:recreate_local(
ResourceId, Module, Config, ?DEFAULT_RESOURCE_OPTS Type, ResourceId, Module, Config, ?DEFAULT_RESOURCE_OPTS
), ),
start_resource_if_enabled(Result, ResourceId, Config). start_resource_if_enabled(Result, ResourceId, Config).

View File

@ -25,9 +25,9 @@
-export([ -export([
cleanup_resources/0, cleanup_resources/0,
make_resource_id/1, make_resource_id/1,
create_resource/2,
create_resource/3, create_resource/3,
update_resource/2, create_resource/4,
update_resource/3,
remove_resource/1, remove_resource/1,
update_config/2, update_config/2,
parse_deep/2, parse_deep/2,
@ -57,12 +57,13 @@
%% APIs %% APIs
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
create_resource(Module, Config) -> create_resource(Type, Module, Config) ->
ResourceId = make_resource_id(Module), ResourceId = make_resource_id(Module),
create_resource(ResourceId, Module, Config). create_resource(Type, ResourceId, Module, Config).
create_resource(ResourceId, Module, Config) -> create_resource(Type, ResourceId, Module, Config) ->
Result = emqx_resource:create_local( Result = emqx_resource:create_local(
Type,
ResourceId, ResourceId,
?AUTHZ_RESOURCE_GROUP, ?AUTHZ_RESOURCE_GROUP,
Module, Module,
@ -71,10 +72,11 @@ create_resource(ResourceId, Module, Config) ->
), ),
start_resource_if_enabled(Result, ResourceId, Config). start_resource_if_enabled(Result, ResourceId, Config).
update_resource(Module, #{annotations := #{id := ResourceId}} = Config) -> update_resource(Type, Module, #{annotations := #{id := ResourceId}} = Config) ->
Result = Result =
case case
emqx_resource:recreate_local( emqx_resource:recreate_local(
Type,
ResourceId, ResourceId,
Module, Module,
Config, Config,

View File

@ -40,6 +40,7 @@ create(Config0) ->
ResourceId = emqx_authn_utils:make_resource_id(?MODULE), ResourceId = emqx_authn_utils:make_resource_id(?MODULE),
% {Config, State} = parse_config(Config0), % {Config, State} = parse_config(Config0),
{ok, _Data} = emqx_authn_utils:create_resource( {ok, _Data} = emqx_authn_utils:create_resource(
http,
ResourceId, ResourceId,
emqx_bridge_http_connector, emqx_bridge_http_connector,
Config Config
@ -50,7 +51,9 @@ create(Config0) ->
update(Config0, #{resource_id := ResourceId} = _State) -> update(Config0, #{resource_id := ResourceId} = _State) ->
with_validated_config(Config0, fun(Config, NState) -> with_validated_config(Config0, fun(Config, NState) ->
% {Config, NState} = parse_config(Config0), % {Config, NState} = parse_config(Config0),
case emqx_authn_utils:update_resource(emqx_bridge_http_connector, Config, ResourceId) of case
emqx_authn_utils:update_resource(http, emqx_bridge_http_connector, Config, ResourceId)
of
{error, Reason} -> {error, Reason} ->
error({load_config_error, Reason}); error({load_config_error, Reason});
{ok, _} -> {ok, _} ->

View File

@ -66,12 +66,14 @@ description() ->
create(Config) -> create(Config) ->
NConfig = parse_config(Config), NConfig = parse_config(Config),
ResourceId = emqx_authn_utils:make_resource_id(?MODULE), ResourceId = emqx_authn_utils:make_resource_id(?MODULE),
{ok, _Data} = emqx_authz_utils:create_resource(ResourceId, emqx_bridge_http_connector, NConfig), {ok, _Data} = emqx_authz_utils:create_resource(
http, ResourceId, emqx_bridge_http_connector, NConfig
),
NConfig#{annotations => #{id => ResourceId}}. NConfig#{annotations => #{id => ResourceId}}.
update(Config) -> update(Config) ->
NConfig = parse_config(Config), NConfig = parse_config(Config),
case emqx_authz_utils:update_resource(emqx_bridge_http_connector, NConfig) of case emqx_authz_utils:update_resource(http, emqx_bridge_http_connector, NConfig) of
{error, Reason} -> error({load_config_error, Reason}); {error, Reason} -> error({load_config_error, Reason});
{ok, Id} -> NConfig#{annotations => #{id => Id}} {ok, Id} -> NConfig#{annotations => #{id => Id}}
end. end.

View File

@ -183,6 +183,7 @@ do_create(
) -> ) ->
ResourceId = emqx_authn_utils:make_resource_id(?MODULE), ResourceId = emqx_authn_utils:make_resource_id(?MODULE),
{ok, _Data} = emqx_resource:create_local( {ok, _Data} = emqx_resource:create_local(
jwt,
ResourceId, ResourceId,
?AUTHN_RESOURCE_GROUP, ?AUTHN_RESOURCE_GROUP,
emqx_authn_jwks_connector, emqx_authn_jwks_connector,

View File

@ -1,7 +1,7 @@
%% -*- mode: erlang -*- %% -*- mode: erlang -*-
{application, emqx_auth_ldap, [ {application, emqx_auth_ldap, [
{description, "EMQX LDAP Authentication and Authorization"}, {description, "EMQX LDAP Authentication and Authorization"},
{vsn, "0.1.2"}, {vsn, "0.1.3"},
{registered, []}, {registered, []},
{mod, {emqx_auth_ldap_app, []}}, {mod, {emqx_auth_ldap_app, []}},
{applications, [ {applications, [

View File

@ -40,12 +40,12 @@ create(_AuthenticatorID, Config) ->
do_create(Module, Config) -> do_create(Module, Config) ->
ResourceId = emqx_authn_utils:make_resource_id(Module), ResourceId = emqx_authn_utils:make_resource_id(Module),
State = parse_config(Config), State = parse_config(Config),
{ok, _Data} = emqx_authn_utils:create_resource(ResourceId, emqx_ldap, Config), {ok, _Data} = emqx_authn_utils:create_resource(ldap, ResourceId, emqx_ldap, Config),
{ok, State#{resource_id => ResourceId}}. {ok, State#{resource_id => ResourceId}}.
update(Config, #{resource_id := ResourceId} = _State) -> update(Config, #{resource_id := ResourceId} = _State) ->
NState = parse_config(Config), NState = parse_config(Config),
case emqx_authn_utils:update_resource(emqx_ldap, Config, ResourceId) of case emqx_authn_utils:update_resource(ldap, emqx_ldap, Config, ResourceId) of
{error, Reason} -> {error, Reason} ->
error({load_config_error, Reason}); error({load_config_error, Reason});
{ok, _} -> {ok, _} ->

View File

@ -56,12 +56,12 @@ description() ->
create(Source) -> create(Source) ->
ResourceId = emqx_authz_utils:make_resource_id(?MODULE), ResourceId = emqx_authz_utils:make_resource_id(?MODULE),
{ok, _Data} = emqx_authz_utils:create_resource(ResourceId, emqx_ldap, Source), {ok, _Data} = emqx_authz_utils:create_resource(ldap, ResourceId, emqx_ldap, Source),
Annotations = new_annotations(#{id => ResourceId}, Source), Annotations = new_annotations(#{id => ResourceId}, Source),
Source#{annotations => Annotations}. Source#{annotations => Annotations}.
update(Source) -> update(Source) ->
case emqx_authz_utils:update_resource(emqx_ldap, Source) of case emqx_authz_utils:update_resource(ldap, emqx_ldap, Source) of
{error, Reason} -> {error, Reason} ->
error({load_config_error, Reason}); error({load_config_error, Reason});
{ok, Id} -> {ok, Id} ->

View File

@ -47,6 +47,7 @@ init_per_suite(Config) ->
work_dir => ?config(priv_dir, Config) work_dir => ?config(priv_dir, Config)
}), }),
{ok, _} = emqx_resource:create_local( {ok, _} = emqx_resource:create_local(
ldap,
?LDAP_RESOURCE, ?LDAP_RESOURCE,
?AUTHN_RESOURCE_GROUP, ?AUTHN_RESOURCE_GROUP,
emqx_ldap, emqx_ldap,

View File

@ -47,6 +47,7 @@ init_per_suite(Config) ->
work_dir => ?config(priv_dir, Config) work_dir => ?config(priv_dir, Config)
}), }),
{ok, _} = emqx_resource:create_local( {ok, _} = emqx_resource:create_local(
ldap,
?LDAP_RESOURCE, ?LDAP_RESOURCE,
?AUTHN_RESOURCE_GROUP, ?AUTHN_RESOURCE_GROUP,
emqx_ldap, emqx_ldap,

View File

@ -178,6 +178,7 @@ stop_apps(Apps) ->
create_ldap_resource() -> create_ldap_resource() ->
{ok, _} = emqx_resource:create_local( {ok, _} = emqx_resource:create_local(
ldap,
?LDAP_RESOURCE, ?LDAP_RESOURCE,
?AUTHZ_RESOURCE_GROUP, ?AUTHZ_RESOURCE_GROUP,
emqx_ldap, emqx_ldap,

View File

@ -1,7 +1,7 @@
%% -*- mode: erlang -*- %% -*- mode: erlang -*-
{application, emqx_auth_mongodb, [ {application, emqx_auth_mongodb, [
{description, "EMQX MongoDB Authentication and Authorization"}, {description, "EMQX MongoDB Authentication and Authorization"},
{vsn, "0.2.0"}, {vsn, "0.2.1"},
{registered, []}, {registered, []},
{mod, {emqx_auth_mongodb_app, []}}, {mod, {emqx_auth_mongodb_app, []}},
{applications, [ {applications, [

View File

@ -37,6 +37,7 @@ create(Config0) ->
ResourceId = emqx_authn_utils:make_resource_id(?MODULE), ResourceId = emqx_authn_utils:make_resource_id(?MODULE),
{Config, State} = parse_config(Config0), {Config, State} = parse_config(Config0),
{ok, _Data} = emqx_authn_utils:create_resource( {ok, _Data} = emqx_authn_utils:create_resource(
mongodb,
ResourceId, ResourceId,
emqx_mongodb, emqx_mongodb,
Config Config
@ -45,7 +46,7 @@ create(Config0) ->
update(Config0, #{resource_id := ResourceId} = _State) -> update(Config0, #{resource_id := ResourceId} = _State) ->
{Config, NState} = parse_config(Config0), {Config, NState} = parse_config(Config0),
case emqx_authn_utils:update_resource(emqx_mongodb, Config, ResourceId) of case emqx_authn_utils:update_resource(mongodb, emqx_mongodb, Config, ResourceId) of
{error, Reason} -> {error, Reason} ->
error({load_config_error, Reason}); error({load_config_error, Reason});
{ok, _} -> {ok, _} ->

View File

@ -49,13 +49,13 @@ description() ->
create(#{filter := Filter} = Source) -> create(#{filter := Filter} = Source) ->
ResourceId = emqx_authz_utils:make_resource_id(?MODULE), ResourceId = emqx_authz_utils:make_resource_id(?MODULE),
{ok, _Data} = emqx_authz_utils:create_resource(ResourceId, emqx_mongodb, Source), {ok, _Data} = emqx_authz_utils:create_resource(mongodb, ResourceId, emqx_mongodb, Source),
FilterTemp = emqx_authz_utils:parse_deep(Filter, ?ALLOWED_VARS), FilterTemp = emqx_authz_utils:parse_deep(Filter, ?ALLOWED_VARS),
Source#{annotations => #{id => ResourceId}, filter_template => FilterTemp}. Source#{annotations => #{id => ResourceId}, filter_template => FilterTemp}.
update(#{filter := Filter} = Source) -> update(#{filter := Filter} = Source) ->
FilterTemp = emqx_authz_utils:parse_deep(Filter, ?ALLOWED_VARS), FilterTemp = emqx_authz_utils:parse_deep(Filter, ?ALLOWED_VARS),
case emqx_authz_utils:update_resource(emqx_mongodb, Source) of case emqx_authz_utils:update_resource(mongodb, emqx_mongodb, Source) of
{error, Reason} -> {error, Reason} ->
error({load_config_error, Reason}); error({load_config_error, Reason});
{ok, Id} -> {ok, Id} ->

View File

@ -39,12 +39,12 @@ create(_AuthenticatorID, Config) ->
create(Config0) -> create(Config0) ->
ResourceId = emqx_authn_utils:make_resource_id(?MODULE), ResourceId = emqx_authn_utils:make_resource_id(?MODULE),
{Config, State} = parse_config(Config0), {Config, State} = parse_config(Config0),
{ok, _Data} = emqx_authn_utils:create_resource(ResourceId, emqx_mysql, Config), {ok, _Data} = emqx_authn_utils:create_resource(mysql, ResourceId, emqx_mysql, Config),
{ok, State#{resource_id => ResourceId}}. {ok, State#{resource_id => ResourceId}}.
update(Config0, #{resource_id := ResourceId} = _State) -> update(Config0, #{resource_id := ResourceId} = _State) ->
{Config, NState} = parse_config(Config0), {Config, NState} = parse_config(Config0),
case emqx_authn_utils:update_resource(emqx_mysql, Config, ResourceId) of case emqx_authn_utils:update_resource(mysql, emqx_mysql, Config, ResourceId) of
{error, Reason} -> {error, Reason} ->
error({load_config_error, Reason}); error({load_config_error, Reason});
{ok, _} -> {ok, _} ->

View File

@ -53,13 +53,13 @@ create(#{query := SQL} = Source0) ->
{PrepareSQL, TmplToken} = emqx_authz_utils:parse_sql(SQL, '?', ?ALLOWED_VARS), {PrepareSQL, TmplToken} = emqx_authz_utils:parse_sql(SQL, '?', ?ALLOWED_VARS),
ResourceId = emqx_authz_utils:make_resource_id(?MODULE), ResourceId = emqx_authz_utils:make_resource_id(?MODULE),
Source = Source0#{prepare_statement => #{?PREPARE_KEY => PrepareSQL}}, Source = Source0#{prepare_statement => #{?PREPARE_KEY => PrepareSQL}},
{ok, _Data} = emqx_authz_utils:create_resource(ResourceId, emqx_mysql, Source), {ok, _Data} = emqx_authz_utils:create_resource(mysql, ResourceId, emqx_mysql, Source),
Source#{annotations => #{id => ResourceId, tmpl_token => TmplToken}}. Source#{annotations => #{id => ResourceId, tmpl_token => TmplToken}}.
update(#{query := SQL} = Source0) -> update(#{query := SQL} = Source0) ->
{PrepareSQL, TmplToken} = emqx_authz_utils:parse_sql(SQL, '?', ?ALLOWED_VARS), {PrepareSQL, TmplToken} = emqx_authz_utils:parse_sql(SQL, '?', ?ALLOWED_VARS),
Source = Source0#{prepare_statement => #{?PREPARE_KEY => PrepareSQL}}, Source = Source0#{prepare_statement => #{?PREPARE_KEY => PrepareSQL}},
case emqx_authz_utils:update_resource(emqx_mysql, Source) of case emqx_authz_utils:update_resource(mysql, emqx_mysql, Source) of
{error, Reason} -> {error, Reason} ->
error({load_config_error, Reason}); error({load_config_error, Reason});
{ok, Id} -> {ok, Id} ->

View File

@ -58,6 +58,7 @@ init_per_suite(Config) ->
work_dir => ?config(priv_dir, Config) work_dir => ?config(priv_dir, Config)
}), }),
{ok, _} = emqx_resource:create_local( {ok, _} = emqx_resource:create_local(
mysql,
?MYSQL_RESOURCE, ?MYSQL_RESOURCE,
?AUTHN_RESOURCE_GROUP, ?AUTHN_RESOURCE_GROUP,
emqx_mysql, emqx_mysql,

View File

@ -446,6 +446,7 @@ stop_apps(Apps) ->
create_mysql_resource() -> create_mysql_resource() ->
{ok, _} = emqx_resource:create_local( {ok, _} = emqx_resource:create_local(
mysql,
?MYSQL_RESOURCE, ?MYSQL_RESOURCE,
?AUTHZ_RESOURCE_GROUP, ?AUTHZ_RESOURCE_GROUP,
emqx_mysql, emqx_mysql,

View File

@ -45,6 +45,7 @@ create(Config0) ->
ResourceId = emqx_authn_utils:make_resource_id(?MODULE), ResourceId = emqx_authn_utils:make_resource_id(?MODULE),
{Config, State} = parse_config(Config0, ResourceId), {Config, State} = parse_config(Config0, ResourceId),
{ok, _Data} = emqx_authn_utils:create_resource( {ok, _Data} = emqx_authn_utils:create_resource(
postgresql,
ResourceId, ResourceId,
emqx_postgresql, emqx_postgresql,
Config Config
@ -53,7 +54,7 @@ create(Config0) ->
update(Config0, #{resource_id := ResourceId} = _State) -> update(Config0, #{resource_id := ResourceId} = _State) ->
{Config, NState} = parse_config(Config0, ResourceId), {Config, NState} = parse_config(Config0, ResourceId),
case emqx_authn_utils:update_resource(emqx_postgresql, Config, ResourceId) of case emqx_authn_utils:update_resource(postgresql, emqx_postgresql, Config, ResourceId) of
{error, Reason} -> {error, Reason} ->
error({load_config_error, Reason}); error({load_config_error, Reason});
{ok, _} -> {ok, _} ->

View File

@ -53,6 +53,7 @@ create(#{query := SQL0} = Source) ->
{SQL, PlaceHolders} = emqx_authz_utils:parse_sql(SQL0, '$n', ?ALLOWED_VARS), {SQL, PlaceHolders} = emqx_authz_utils:parse_sql(SQL0, '$n', ?ALLOWED_VARS),
ResourceID = emqx_authz_utils:make_resource_id(emqx_postgresql), ResourceID = emqx_authz_utils:make_resource_id(emqx_postgresql),
{ok, _Data} = emqx_authz_utils:create_resource( {ok, _Data} = emqx_authz_utils:create_resource(
postgresql,
ResourceID, ResourceID,
emqx_postgresql, emqx_postgresql,
Source#{prepare_statement => #{ResourceID => SQL}} Source#{prepare_statement => #{ResourceID => SQL}}
@ -63,6 +64,7 @@ update(#{query := SQL0, annotations := #{id := ResourceID}} = Source) ->
{SQL, PlaceHolders} = emqx_authz_utils:parse_sql(SQL0, '$n', ?ALLOWED_VARS), {SQL, PlaceHolders} = emqx_authz_utils:parse_sql(SQL0, '$n', ?ALLOWED_VARS),
case case
emqx_authz_utils:update_resource( emqx_authz_utils:update_resource(
postgresql,
emqx_postgresql, emqx_postgresql,
Source#{prepare_statement => #{ResourceID => SQL}} Source#{prepare_statement => #{ResourceID => SQL}}
) )

View File

@ -79,6 +79,7 @@ init_per_suite(Config) ->
work_dir => ?config(priv_dir, Config) work_dir => ?config(priv_dir, Config)
}), }),
{ok, _} = emqx_resource:create_local( {ok, _} = emqx_resource:create_local(
postgresql,
?PGSQL_RESOURCE, ?PGSQL_RESOURCE,
?AUTHN_RESOURCE_GROUP, ?AUTHN_RESOURCE_GROUP,
emqx_postgresql, emqx_postgresql,
@ -198,9 +199,9 @@ test_user_auth(#{
t_authenticate_disabled_prepared_statements(_Config) -> t_authenticate_disabled_prepared_statements(_Config) ->
ResConfig = maps:merge(pgsql_config(), #{disable_prepared_statements => true}), ResConfig = maps:merge(pgsql_config(), #{disable_prepared_statements => true}),
{ok, _} = emqx_resource:recreate_local(?PGSQL_RESOURCE, emqx_postgresql, ResConfig), {ok, _} = emqx_resource:recreate_local(postgresql, ?PGSQL_RESOURCE, emqx_postgresql, ResConfig),
on_exit(fun() -> on_exit(fun() ->
emqx_resource:recreate_local(?PGSQL_RESOURCE, emqx_postgresql, pgsql_config()) emqx_resource:recreate_local(postgresql, ?PGSQL_RESOURCE, emqx_postgresql, pgsql_config())
end), end),
ok = lists:foreach( ok = lists:foreach(
fun(Sample0) -> fun(Sample0) ->

View File

@ -437,6 +437,7 @@ pgsql_config() ->
create_pgsql_resource() -> create_pgsql_resource() ->
emqx_resource:create_local( emqx_resource:create_local(
postgresql,
?PGSQL_RESOURCE, ?PGSQL_RESOURCE,
?AUTHZ_RESOURCE_GROUP, ?AUTHZ_RESOURCE_GROUP,
emqx_postgresql, emqx_postgresql,

View File

@ -42,6 +42,7 @@ create(Config0) ->
Res; Res;
{Config, State} -> {Config, State} ->
{ok, _Data} = emqx_authn_utils:create_resource( {ok, _Data} = emqx_authn_utils:create_resource(
redis,
ResourceId, ResourceId,
emqx_redis, emqx_redis,
Config Config
@ -51,7 +52,7 @@ create(Config0) ->
update(Config0, #{resource_id := ResourceId} = _State) -> update(Config0, #{resource_id := ResourceId} = _State) ->
{Config, NState} = parse_config(Config0), {Config, NState} = parse_config(Config0),
case emqx_authn_utils:update_resource(emqx_redis, Config, ResourceId) of case emqx_authn_utils:update_resource(redis, emqx_redis, Config, ResourceId) of
{error, Reason} -> {error, Reason} ->
error({load_config_error, Reason}); error({load_config_error, Reason});
{ok, _} -> {ok, _} ->

View File

@ -50,12 +50,12 @@ description() ->
create(#{cmd := CmdStr} = Source) -> create(#{cmd := CmdStr} = Source) ->
CmdTemplate = parse_cmd(CmdStr), CmdTemplate = parse_cmd(CmdStr),
ResourceId = emqx_authz_utils:make_resource_id(?MODULE), ResourceId = emqx_authz_utils:make_resource_id(?MODULE),
{ok, _Data} = emqx_authz_utils:create_resource(ResourceId, emqx_redis, Source), {ok, _Data} = emqx_authz_utils:create_resource(redis, ResourceId, emqx_redis, Source),
Source#{annotations => #{id => ResourceId}, cmd_template => CmdTemplate}. Source#{annotations => #{id => ResourceId}, cmd_template => CmdTemplate}.
update(#{cmd := CmdStr} = Source) -> update(#{cmd := CmdStr} = Source) ->
CmdTemplate = parse_cmd(CmdStr), CmdTemplate = parse_cmd(CmdStr),
case emqx_authz_utils:update_resource(emqx_redis, Source) of case emqx_authz_utils:update_resource(redis, emqx_redis, Source) of
{error, Reason} -> {error, Reason} ->
error({load_config_error, Reason}); error({load_config_error, Reason});
{ok, Id} -> {ok, Id} ->

View File

@ -63,6 +63,7 @@ init_per_suite(Config) ->
work_dir => ?config(priv_dir, Config) work_dir => ?config(priv_dir, Config)
}), }),
{ok, _} = emqx_resource:create_local( {ok, _} = emqx_resource:create_local(
redis,
?REDIS_RESOURCE, ?REDIS_RESOURCE,
?AUTHN_RESOURCE_GROUP, ?AUTHN_RESOURCE_GROUP,
emqx_redis, emqx_redis,

View File

@ -384,6 +384,7 @@ stop_apps(Apps) ->
create_redis_resource() -> create_redis_resource() ->
{ok, _} = emqx_resource:create_local( {ok, _} = emqx_resource:create_local(
redis,
?REDIS_RESOURCE, ?REDIS_RESOURCE,
?AUTHZ_RESOURCE_GROUP, ?AUTHZ_RESOURCE_GROUP,
emqx_redis, emqx_redis,

View File

@ -195,8 +195,9 @@ create(Type, Name, Conf0, Opts) ->
TypeBin = bin(Type), TypeBin = bin(Type),
Conf = Conf0#{bridge_type => TypeBin, bridge_name => Name}, Conf = Conf0#{bridge_type => TypeBin, bridge_name => Name},
{ok, _Data} = emqx_resource:create_local( {ok, _Data} = emqx_resource:create_local(
Type,
resource_id(Type, Name), resource_id(Type, Name),
<<"emqx_bridge">>, <<"bridge">>,
bridge_to_resource_type(Type), bridge_to_resource_type(Type),
parse_confs(TypeBin, Name, Conf), parse_confs(TypeBin, Name, Conf),
parse_opts(Conf, Opts) parse_opts(Conf, Opts)
@ -264,6 +265,7 @@ recreate(Type, Name, Conf0, Opts) ->
TypeBin = bin(Type), TypeBin = bin(Type),
Conf = Conf0#{bridge_type => TypeBin, bridge_name => Name}, Conf = Conf0#{bridge_type => TypeBin, bridge_name => Name},
emqx_resource:recreate_local( emqx_resource:recreate_local(
Type,
resource_id(Type, Name), resource_id(Type, Name),
bridge_to_resource_type(Type), bridge_to_resource_type(Type),
parse_confs(TypeBin, Name, Conf), parse_confs(TypeBin, Name, Conf),
@ -300,7 +302,7 @@ create_dry_run_bridge_v1(Type, Conf0) ->
{error, Reason}; {error, Reason};
{ok, ConfNew} -> {ok, ConfNew} ->
ParseConf = parse_confs(TypeBin, TmpName, ConfNew), ParseConf = parse_confs(TypeBin, TmpName, ConfNew),
emqx_resource:create_dry_run_local(bridge_to_resource_type(Type), ParseConf) emqx_resource:create_dry_run_local(Type, bridge_to_resource_type(Type), ParseConf)
end end
catch catch
%% validation errors %% validation errors

View File

@ -212,6 +212,7 @@ check_config(Config) ->
create_local_resource(ResourceId, CheckedConfig) -> create_local_resource(ResourceId, CheckedConfig) ->
{ok, Bridge} = {ok, Bridge} =
emqx_resource:create_local( emqx_resource:create_local(
cassandra,
ResourceId, ResourceId,
?CONNECTOR_RESOURCE_GROUP, ?CONNECTOR_RESOURCE_GROUP,
?CASSANDRA_RESOURCE_MOD, ?CASSANDRA_RESOURCE_MOD,

View File

@ -109,6 +109,7 @@ t_start_passfile(Config) ->
?assertMatch( ?assertMatch(
{ok, #{status := connected}}, {ok, #{status := connected}},
emqx_resource:create_local( emqx_resource:create_local(
clickhouse,
ResourceID, ResourceID,
?CONNECTOR_RESOURCE_GROUP, ?CONNECTOR_RESOURCE_GROUP,
?CLICKHOUSE_RESOURCE_MOD, ?CLICKHOUSE_RESOURCE_MOD,
@ -138,6 +139,7 @@ perform_lifecycle_check(ResourceID, InitialConfig) ->
status := InitialStatus status := InitialStatus
}} = }} =
emqx_resource:create_local( emqx_resource:create_local(
clickhouse,
ResourceID, ResourceID,
?CONNECTOR_RESOURCE_GROUP, ?CONNECTOR_RESOURCE_GROUP,
?CLICKHOUSE_RESOURCE_MOD, ?CLICKHOUSE_RESOURCE_MOD,

View File

@ -83,6 +83,7 @@ perform_lifecycle_check(PoolName, InitialConfig) ->
state := #{client := #{pool := ReturnedPoolName}} = State, state := #{client := #{pool := ReturnedPoolName}} = State,
status := InitialStatus status := InitialStatus
}} = emqx_resource:create_local( }} = emqx_resource:create_local(
greptimedb,
PoolName, PoolName,
?CONNECTOR_RESOURCE_GROUP, ?CONNECTOR_RESOURCE_GROUP,
?GREPTIMEDB_RESOURCE_MOD, ?GREPTIMEDB_RESOURCE_MOD,

View File

@ -86,6 +86,7 @@ perform_lifecycle_check(PoolName, InitialConfig) ->
state := #{client := #{pool := ReturnedPoolName}} = State, state := #{client := #{pool := ReturnedPoolName}} = State,
status := InitialStatus status := InitialStatus
}} = emqx_resource:create_local( }} = emqx_resource:create_local(
influxdb,
PoolName, PoolName,
?CONNECTOR_RESOURCE_GROUP, ?CONNECTOR_RESOURCE_GROUP,
?INFLUXDB_RESOURCE_MOD, ?INFLUXDB_RESOURCE_MOD,
@ -197,6 +198,7 @@ perform_tls_opts_check(PoolName, InitialConfig, VerifyReturn) ->
config := #{ssl := #{enable := SslEnabled}}, config := #{ssl := #{enable := SslEnabled}},
status := Status status := Status
}} = emqx_resource:create_local( }} = emqx_resource:create_local(
influxdb,
PoolName, PoolName,
?CONNECTOR_RESOURCE_GROUP, ?CONNECTOR_RESOURCE_GROUP,
?INFLUXDB_RESOURCE_MOD, ?INFLUXDB_RESOURCE_MOD,

View File

@ -289,7 +289,7 @@ replayq_dir(ClientId) ->
filename:join([emqx:data_dir(), "pulsar", emqx_utils_conv:bin(ClientId)]). filename:join([emqx:data_dir(), "pulsar", emqx_utils_conv:bin(ClientId)]).
producer_name(InstanceId, ChannelId) -> producer_name(InstanceId, ChannelId) ->
case is_dry_run(InstanceId) of case emqx_resource:is_dry_run(InstanceId) of
%% do not create more atom %% do not create more atom
true -> true ->
pulsar_producer_probe_worker; pulsar_producer_probe_worker;

View File

@ -135,6 +135,7 @@ check_config(Config) ->
create_local_resource(ResourceID, CheckedConfig) -> create_local_resource(ResourceID, CheckedConfig) ->
{ok, Bridge} = emqx_resource:create_local( {ok, Bridge} = emqx_resource:create_local(
rabbitmq,
ResourceID, ResourceID,
?CONNECTOR_RESOURCE_GROUP, ?CONNECTOR_RESOURCE_GROUP,
emqx_bridge_rabbitmq_connector, emqx_bridge_rabbitmq_connector,

View File

@ -37,4 +37,4 @@
"The " ++ TYPE ++ " default port " ++ DEFAULT_PORT ++ " is used if `[:Port]` is not specified." "The " ++ TYPE ++ " default port " ++ DEFAULT_PORT ++ " is used if `[:Port]` is not specified."
). ).
-define(CONNECTOR_RESOURCE_GROUP, <<"emqx_connector">>). -define(CONNECTOR_RESOURCE_GROUP, <<"connector">>).

View File

@ -18,6 +18,7 @@
-include("../../emqx_bridge/include/emqx_bridge_resource.hrl"). -include("../../emqx_bridge/include/emqx_bridge_resource.hrl").
-include_lib("emqx/include/logger.hrl"). -include_lib("emqx/include/logger.hrl").
-include_lib("emqx_resource/include/emqx_resource.hrl"). -include_lib("emqx_resource/include/emqx_resource.hrl").
-include("emqx_connector.hrl").
-export([ -export([
connector_to_resource_type/1, connector_to_resource_type/1,
@ -125,8 +126,9 @@ create(Type, Name, Conf0, Opts) ->
ResourceId = resource_id(Type, Name), ResourceId = resource_id(Type, Name),
Conf = Conf0#{connector_type => TypeBin, connector_name => Name}, Conf = Conf0#{connector_type => TypeBin, connector_name => Name},
{ok, _Data} = emqx_resource:create_local( {ok, _Data} = emqx_resource:create_local(
Type,
ResourceId, ResourceId,
<<"emqx_connector">>, ?CONNECTOR_RESOURCE_GROUP,
?MODULE:connector_to_resource_type(Type), ?MODULE:connector_to_resource_type(Type),
parse_confs(TypeBin, Name, Conf), parse_confs(TypeBin, Name, Conf),
parse_opts(Conf, Opts) parse_opts(Conf, Opts)
@ -198,6 +200,7 @@ recreate(Type, Name, Conf) ->
recreate(Type, Name, Conf, Opts) -> recreate(Type, Name, Conf, Opts) ->
TypeBin = bin(Type), TypeBin = bin(Type),
emqx_resource:recreate_local( emqx_resource:recreate_local(
Type,
resource_id(Type, Name), resource_id(Type, Name),
?MODULE:connector_to_resource_type(Type), ?MODULE:connector_to_resource_type(Type),
parse_confs(TypeBin, Name, Conf), parse_confs(TypeBin, Name, Conf),
@ -234,7 +237,7 @@ create_dry_run(Type, Conf0, Callback) ->
{ok, ConfNew} -> {ok, ConfNew} ->
ParseConf = parse_confs(bin(Type), TmpName, ConfNew), ParseConf = parse_confs(bin(Type), TmpName, ConfNew),
emqx_resource:create_dry_run_local( emqx_resource:create_dry_run_local(
TmpName, ?MODULE:connector_to_resource_type(Type), ParseConf, Callback Type, TmpName, ?MODULE:connector_to_resource_type(Type), ParseConf, Callback
) )
end end
catch catch

View File

@ -45,7 +45,7 @@
-define(MOD_TAB, emqx_dashboard_sso). -define(MOD_TAB, emqx_dashboard_sso).
-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, <<"dashboard_sso">>).
-define(NO_ERROR, <<>>). -define(NO_ERROR, <<>>).
-define(DEFAULT_RESOURCE_OPTS, #{ -define(DEFAULT_RESOURCE_OPTS, #{
start_after_created => false start_after_created => false
@ -132,6 +132,7 @@ make_resource_id(Backend) ->
create_resource(ResourceId, Module, Config) -> create_resource(ResourceId, Module, Config) ->
Result = emqx_resource:create_local( Result = emqx_resource:create_local(
dashboard_sso,
ResourceId, ResourceId,
?RESOURCE_GROUP, ?RESOURCE_GROUP,
Module, Module,
@ -142,7 +143,7 @@ create_resource(ResourceId, Module, Config) ->
update_resource(ResourceId, Module, Config) -> update_resource(ResourceId, Module, Config) ->
Result = emqx_resource:recreate_local( Result = emqx_resource:recreate_local(
ResourceId, Module, Config, ?DEFAULT_RESOURCE_OPTS dashboard_sso, ResourceId, Module, Config, ?DEFAULT_RESOURCE_OPTS
), ),
start_resource_if_enabled(ResourceId, Result, Config). start_resource_if_enabled(ResourceId, Result, Config).

View File

@ -24,7 +24,7 @@
-define(MOD_TAB, emqx_dashboard_sso). -define(MOD_TAB, emqx_dashboard_sso).
-define(MOD_KEY_PATH, [dashboard, sso, ldap]). -define(MOD_KEY_PATH, [dashboard, sso, ldap]).
-define(RESOURCE_GROUP, <<"emqx_dashboard_sso">>). -define(RESOURCE_GROUP, <<"dashboard_sso">>).
-import(emqx_mgmt_api_test_util, [request/2, request/3, uri/1, request_api/3]). -import(emqx_mgmt_api_test_util, [request/2, request/3, uri/1, request_api/3]).

View File

@ -96,6 +96,7 @@ perform_lifecycle_check(ResourceId, InitialConfig) ->
state := #{pool_name := PoolName} = State, state := #{pool_name := PoolName} = State,
status := InitialStatus status := InitialStatus
}} = emqx_resource:create_local( }} = emqx_resource:create_local(
ldap,
ResourceId, ResourceId,
?CONNECTOR_RESOURCE_GROUP, ?CONNECTOR_RESOURCE_GROUP,
?LDAP_RESOURCE_MOD, ?LDAP_RESOURCE_MOD,
@ -171,6 +172,7 @@ t_get_status(Config) ->
?LDAP_RESOURCE_MOD, ldap_config(Config) ?LDAP_RESOURCE_MOD, ldap_config(Config)
), ),
{ok, _} = emqx_resource:create_local( {ok, _} = emqx_resource:create_local(
ldap,
ResourceId, ResourceId,
?CONNECTOR_RESOURCE_GROUP, ?CONNECTOR_RESOURCE_GROUP,
?LDAP_RESOURCE_MOD, ?LDAP_RESOURCE_MOD,

View File

@ -143,6 +143,7 @@ check_config(Config) ->
create_local_resource(ResourceId, CheckedConfig) -> create_local_resource(ResourceId, CheckedConfig) ->
{ok, Bridge} = emqx_resource:create_local( {ok, Bridge} = emqx_resource:create_local(
mongodb,
ResourceId, ResourceId,
?CONNECTOR_RESOURCE_GROUP, ?CONNECTOR_RESOURCE_GROUP,
?MONGO_RESOURCE_MOD, ?MONGO_RESOURCE_MOD,

View File

@ -67,6 +67,7 @@ perform_lifecycle_check(ResourceId, InitialConfig) ->
state := #{pool_name := PoolName} = State, state := #{pool_name := PoolName} = State,
status := InitialStatus status := InitialStatus
}} = emqx_resource:create_local( }} = emqx_resource:create_local(
mysql,
ResourceId, ResourceId,
?CONNECTOR_RESOURCE_GROUP, ?CONNECTOR_RESOURCE_GROUP,
?MYSQL_RESOURCE_MOD, ?MYSQL_RESOURCE_MOD,

View File

@ -75,6 +75,7 @@ perform_lifecycle_check(ResourceId, InitialConfig) ->
status := InitialStatus status := InitialStatus
}} = }} =
emqx_resource:create_local( emqx_resource:create_local(
postgresql,
ResourceId, ResourceId,
?CONNECTOR_RESOURCE_GROUP, ?CONNECTOR_RESOURCE_GROUP,
?PGSQL_RESOURCE_MOD, ?PGSQL_RESOURCE_MOD,

View File

@ -115,6 +115,7 @@ perform_lifecycle_check(ResourceId, InitialConfig, RedisCommand) ->
state := #{pool_name := PoolName} = State, state := #{pool_name := PoolName} = State,
status := InitialStatus status := InitialStatus
}} = emqx_resource:create_local( }} = emqx_resource:create_local(
redis,
ResourceId, ResourceId,
?CONNECTOR_RESOURCE_GROUP, ?CONNECTOR_RESOURCE_GROUP,
?REDIS_RESOURCE_MOD, ?REDIS_RESOURCE_MOD,

View File

@ -23,6 +23,7 @@
%% remind us of that. %% remind us of that.
-define(rm_status_stopped, stopped). -define(rm_status_stopped, stopped).
-type type() :: atom() | binary().
-type resource_type() :: module(). -type resource_type() :: module().
-type resource_id() :: binary(). -type resource_id() :: binary().
-type channel_id() :: binary(). -type channel_id() :: binary().

View File

@ -28,9 +28,9 @@
-export([ -export([
check_config/2, check_config/2,
check_and_create_local/4,
check_and_create_local/5, check_and_create_local/5,
check_and_recreate_local/4 check_and_create_local/6,
check_and_recreate_local/5
]). ]).
%% Sync resource instances and files %% Sync resource instances and files
@ -39,13 +39,13 @@
-export([ -export([
%% store the config and start the instance %% store the config and start the instance
create_local/4,
create_local/5, create_local/5,
create_dry_run_local/2, create_local/6,
create_dry_run_local/3, create_dry_run_local/3,
create_dry_run_local/4, create_dry_run_local/4,
recreate_local/3, create_dry_run_local/5,
recreate_local/4, recreate_local/4,
recreate_local/5,
%% remove the config and stop the instance %% remove the config and stop the instance
remove_local/1, remove_local/1,
reset_metrics/1, reset_metrics/1,
@ -282,12 +282,13 @@ is_resource_mod(Module) ->
%% APIs for resource instances %% APIs for resource instances
%% ================================================================================= %% =================================================================================
-spec create_local(resource_id(), resource_group(), resource_type(), resource_config()) -> -spec create_local(type(), resource_id(), resource_group(), resource_type(), resource_config()) ->
{ok, resource_data() | 'already_created'} | {error, Reason :: term()}. {ok, resource_data() | 'already_created'} | {error, Reason :: term()}.
create_local(ResId, Group, ResourceType, Config) -> create_local(Type, ResId, Group, ResourceType, Config) ->
create_local(ResId, Group, ResourceType, Config, #{}). create_local(Type, ResId, Group, ResourceType, Config, #{}).
-spec create_local( -spec create_local(
type(),
resource_id(), resource_id(),
resource_group(), resource_group(),
resource_type(), resource_type(),
@ -295,33 +296,39 @@ create_local(ResId, Group, ResourceType, Config) ->
creation_opts() creation_opts()
) -> ) ->
{ok, resource_data()}. {ok, resource_data()}.
create_local(ResId, Group, ResourceType, Config, Opts) -> create_local(Type, ResId, Group, ResourceType, Config, Opts) ->
emqx_resource_manager:ensure_resource(ResId, Group, ResourceType, Config, Opts). emqx_resource_manager:ensure_resource(Type, ResId, Group, ResourceType, Config, Opts).
-spec create_dry_run_local(resource_type(), resource_config()) -> -spec create_dry_run_local(type(), resource_type(), resource_config()) ->
ok | {error, Reason :: term()}. ok | {error, Reason :: term()}.
create_dry_run_local(ResourceType, Config) -> create_dry_run_local(Type, ResourceType, Config) ->
emqx_resource_manager:create_dry_run(ResourceType, Config). emqx_resource_manager:create_dry_run(Type, ResourceType, Config).
create_dry_run_local(ResId, ResourceType, Config) -> create_dry_run_local(Type, ResId, ResourceType, Config) ->
emqx_resource_manager:create_dry_run(ResId, ResourceType, Config). emqx_resource_manager:create_dry_run(Type, ResId, ResourceType, Config).
-spec create_dry_run_local(resource_id(), resource_type(), resource_config(), OnReadyCallback) -> -spec create_dry_run_local(
type(),
resource_id(),
resource_type(),
resource_config(),
OnReadyCallback
) ->
ok | {error, Reason :: term()} ok | {error, Reason :: term()}
when when
OnReadyCallback :: fun((resource_id()) -> ok | {error, Reason :: term()}). OnReadyCallback :: fun((resource_id()) -> ok | {error, Reason :: term()}).
create_dry_run_local(ResId, ResourceType, Config, OnReadyCallback) -> create_dry_run_local(Type, ResId, ResourceType, Config, OnReadyCallback) ->
emqx_resource_manager:create_dry_run(ResId, ResourceType, Config, OnReadyCallback). emqx_resource_manager:create_dry_run(Type, ResId, ResourceType, Config, OnReadyCallback).
-spec recreate_local(resource_id(), resource_type(), resource_config()) -> -spec recreate_local(type(), resource_id(), resource_type(), resource_config()) ->
{ok, resource_data()} | {error, Reason :: term()}. {ok, resource_data()} | {error, Reason :: term()}.
recreate_local(ResId, ResourceType, Config) -> recreate_local(Type, ResId, ResourceType, Config) ->
recreate_local(ResId, ResourceType, Config, #{}). recreate_local(Type, ResId, ResourceType, Config, #{}).
-spec recreate_local(resource_id(), resource_type(), resource_config(), creation_opts()) -> -spec recreate_local(type(), resource_id(), resource_type(), resource_config(), creation_opts()) ->
{ok, resource_data()} | {error, Reason :: term()}. {ok, resource_data()} | {error, Reason :: term()}.
recreate_local(ResId, ResourceType, Config, Opts) -> recreate_local(Type, ResId, ResourceType, Config, Opts) ->
emqx_resource_manager:recreate(ResId, ResourceType, Config, Opts). emqx_resource_manager:recreate(Type, ResId, ResourceType, Config, Opts).
-spec remove_local(resource_id()) -> ok. -spec remove_local(resource_id()) -> ok.
remove_local(ResId) -> remove_local(ResId) ->
@ -607,41 +614,44 @@ check_config(ResourceType, Conf) ->
emqx_hocon:check(ResourceType, Conf). emqx_hocon:check(ResourceType, Conf).
-spec check_and_create_local( -spec check_and_create_local(
type(),
resource_id(), resource_id(),
resource_group(), resource_group(),
resource_type(), resource_type(),
raw_resource_config() raw_resource_config()
) -> ) ->
{ok, resource_data()} | {error, term()}. {ok, resource_data()} | {error, term()}.
check_and_create_local(ResId, Group, ResourceType, RawConfig) -> check_and_create_local(Type, ResId, Group, ResourceType, RawConfig) ->
check_and_create_local(ResId, Group, ResourceType, RawConfig, #{}). check_and_create_local(Type, ResId, Group, ResourceType, RawConfig, #{}).
-spec check_and_create_local( -spec check_and_create_local(
type(),
resource_id(), resource_id(),
resource_group(), resource_group(),
resource_type(), resource_type(),
raw_resource_config(), raw_resource_config(),
creation_opts() creation_opts()
) -> {ok, resource_data()} | {error, term()}. ) -> {ok, resource_data()} | {error, term()}.
check_and_create_local(ResId, Group, ResourceType, RawConfig, Opts) -> check_and_create_local(Type, ResId, Group, ResourceType, RawConfig, Opts) ->
check_and_do( check_and_do(
ResourceType, ResourceType,
RawConfig, RawConfig,
fun(ResConf) -> create_local(ResId, Group, ResourceType, ResConf, Opts) end fun(ResConf) -> create_local(Type, ResId, Group, ResourceType, ResConf, Opts) end
). ).
-spec check_and_recreate_local( -spec check_and_recreate_local(
type(),
resource_id(), resource_id(),
resource_type(), resource_type(),
raw_resource_config(), raw_resource_config(),
creation_opts() creation_opts()
) -> ) ->
{ok, resource_data()} | {error, term()}. {ok, resource_data()} | {error, term()}.
check_and_recreate_local(ResId, ResourceType, RawConfig, Opts) -> check_and_recreate_local(Type, ResId, ResourceType, RawConfig, Opts) ->
check_and_do( check_and_do(
ResourceType, ResourceType,
RawConfig, RawConfig,
fun(ResConf) -> recreate_local(ResId, ResourceType, ResConf, Opts) end fun(ResConf) -> recreate_local(Type, ResId, ResourceType, ResConf, Opts) end
). ).
check_and_do(ResourceType, RawConfig, Do) when is_function(Do) -> check_and_do(ResourceType, RawConfig, Do) when is_function(Do) ->

View File

@ -25,12 +25,12 @@
% API % API
-export([ -export([
ensure_resource/5, ensure_resource/6,
recreate/4, recreate/5,
remove/1, remove/1,
create_dry_run/2,
create_dry_run/3, create_dry_run/3,
create_dry_run/4, create_dry_run/4,
create_dry_run/5,
restart/2, restart/2,
start/2, start/2,
stop/1, stop/1,
@ -59,7 +59,7 @@
]). ]).
% Server % Server
-export([start_link/5]). -export([start_link/6]).
% Behaviour % Behaviour
-export([init/1, callback_mode/0, handle_event/4, terminate/3]). -export([init/1, callback_mode/0, handle_event/4, terminate/3]).
@ -75,6 +75,7 @@
-record(data, { -record(data, {
id, id,
group, group,
type,
mod, mod,
callback_mode, callback_mode,
query_mode, query_mode,
@ -161,43 +162,44 @@
%% Triggers the emqx_resource_manager_sup supervisor to actually create %% Triggers the emqx_resource_manager_sup supervisor to actually create
%% and link the process itself if not already started. %% and link the process itself if not already started.
-spec ensure_resource( -spec ensure_resource(
type(),
resource_id(), resource_id(),
resource_group(), resource_group(),
resource_type(), resource_type(),
resource_config(), resource_config(),
creation_opts() creation_opts()
) -> {ok, resource_data()}. ) -> {ok, resource_data()}.
ensure_resource(ResId, Group, ResourceType, Config, Opts) -> ensure_resource(Type, ResId, Group, ResourceType, Config, Opts) ->
case lookup(ResId) of case lookup(ResId) of
{ok, _Group, Data} -> {ok, _Group, Data} ->
{ok, Data}; {ok, Data};
{error, not_found} -> {error, not_found} ->
create_and_return_data(ResId, Group, ResourceType, Config, Opts) create_and_return_data(Type, ResId, Group, ResourceType, Config, Opts)
end. end.
%% @doc Called from emqx_resource when recreating a resource which may or may not exist %% @doc Called from emqx_resource when recreating a resource which may or may not exist
-spec recreate(resource_id(), resource_type(), resource_config(), creation_opts()) -> -spec recreate(type(), resource_id(), resource_type(), resource_config(), creation_opts()) ->
{ok, resource_data()} | {error, not_found} | {error, updating_to_incorrect_resource_type}. {ok, resource_data()} | {error, not_found} | {error, updating_to_incorrect_resource_type}.
recreate(ResId, ResourceType, NewConfig, Opts) -> recreate(Type, ResId, ResourceType, NewConfig, Opts) ->
case lookup(ResId) of case lookup(ResId) of
{ok, Group, #{mod := ResourceType, status := _} = _Data} -> {ok, Group, #{mod := ResourceType, status := _} = _Data} ->
_ = remove(ResId, false), _ = remove(ResId, false),
create_and_return_data(ResId, Group, ResourceType, NewConfig, Opts); create_and_return_data(Type, ResId, Group, ResourceType, NewConfig, Opts);
{ok, _, #{mod := Mod}} when Mod =/= ResourceType -> {ok, _, #{mod := Mod}} when Mod =/= ResourceType ->
{error, updating_to_incorrect_resource_type}; {error, updating_to_incorrect_resource_type};
{error, not_found} -> {error, not_found} ->
{error, not_found} {error, not_found}
end. end.
create_and_return_data(ResId, Group, ResourceType, Config, Opts) -> create_and_return_data(Type, ResId, Group, ResourceType, Config, Opts) ->
_ = create(ResId, Group, ResourceType, Config, Opts), _ = create(Type, ResId, Group, ResourceType, Config, Opts),
{ok, _Group, Data} = lookup(ResId), {ok, _Group, Data} = lookup(ResId),
{ok, Data}. {ok, Data}.
%% @doc Create a resource_manager and wait until it is running %% @doc Create a resource_manager and wait until it is running
create(ResId, Group, ResourceType, Config, Opts) -> create(Type, ResId, Group, ResourceType, Config, Opts) ->
% The state machine will make the actual call to the callback/resource module after init % The state machine will make the actual call to the callback/resource module after init
ok = emqx_resource_manager_sup:ensure_child(ResId, Group, ResourceType, Config, Opts), ok = emqx_resource_manager_sup:ensure_child(Type, ResId, Group, ResourceType, Config, Opts),
% Create metrics for the resource % Create metrics for the resource
ok = emqx_resource:create_metrics(ResId), ok = emqx_resource:create_metrics(ResId),
QueryMode = emqx_resource:query_mode(ResourceType, Config, Opts), QueryMode = emqx_resource:query_mode(ResourceType, Config, Opts),
@ -219,30 +221,32 @@ create(ResId, Group, ResourceType, Config, Opts) ->
%% @doc Called from `emqx_resource` when doing a dry run for creating a resource instance. %% @doc Called from `emqx_resource` when doing a dry run for creating a resource instance.
%% %%
%% Triggers the `emqx_resource_manager_sup` supervisor to actually create %% Triggers the `emqx_resource_manager_sup` supervisor to actually create
%% and link the process itself if not already started, and then immedately stops. %% and link the process itself if not already started, and then immediately stops.
-spec create_dry_run(resource_type(), resource_config()) -> -spec create_dry_run(type(), resource_type(), resource_config()) ->
ok | {error, Reason :: term()}. ok | {error, Reason :: term()}.
create_dry_run(ResourceType, Config) -> create_dry_run(Type, ResourceType, Config) ->
ResId = make_test_id(), ResId = make_test_id(),
create_dry_run(ResId, ResourceType, Config). create_dry_run(Type, ResId, ResourceType, Config).
create_dry_run(ResId, ResourceType, Config) -> create_dry_run(Type, ResId, ResourceType, Config) ->
create_dry_run(ResId, ResourceType, Config, fun do_nothing_on_ready/1). create_dry_run(Type, ResId, ResourceType, Config, fun do_nothing_on_ready/1).
do_nothing_on_ready(_ResId) -> do_nothing_on_ready(_ResId) ->
ok. ok.
-spec create_dry_run(resource_id(), resource_type(), resource_config(), OnReadyCallback) -> -spec create_dry_run(type(), resource_id(), resource_type(), resource_config(), OnReadyCallback) ->
ok | {error, Reason :: term()} ok | {error, Reason :: term()}
when when
OnReadyCallback :: fun((resource_id()) -> ok | {error, Reason :: term()}). OnReadyCallback :: fun((resource_id()) -> ok | {error, Reason :: term()}).
create_dry_run(ResId, ResourceType, Config, OnReadyCallback) -> create_dry_run(Type, ResId, ResourceType, Config, OnReadyCallback) ->
Opts = Opts =
case is_map(Config) of case is_map(Config) of
true -> maps:get(resource_opts, Config, #{}); true -> maps:get(resource_opts, Config, #{});
false -> #{} false -> #{}
end, end,
ok = emqx_resource_manager_sup:ensure_child(ResId, <<"dry_run">>, ResourceType, Config, Opts), ok = emqx_resource_manager_sup:ensure_child(
Type, ResId, <<"dry_run">>, ResourceType, Config, Opts
),
HealthCheckInterval = maps:get(health_check_interval, Opts, ?HEALTHCHECK_INTERVAL), HealthCheckInterval = maps:get(health_check_interval, Opts, ?HEALTHCHECK_INTERVAL),
Timeout = emqx_utils:clamp(HealthCheckInterval, 5_000, 60_000), Timeout = emqx_utils:clamp(HealthCheckInterval, 5_000, 60_000),
case wait_for_ready(ResId, Timeout) of case wait_for_ready(ResId, Timeout) of
@ -491,7 +495,7 @@ try_clean_allocated_resources(ResId) ->
%% Server start/stop callbacks %% Server start/stop callbacks
%% @doc Function called from the supervisor to actually start the server %% @doc Function called from the supervisor to actually start the server
start_link(ResId, Group, ResourceType, Config, Opts) -> start_link(Type, ResId, Group, ResourceType, Config, Opts) ->
QueryMode = emqx_resource:query_mode( QueryMode = emqx_resource:query_mode(
ResourceType, ResourceType,
Config, Config,
@ -499,6 +503,7 @@ start_link(ResId, Group, ResourceType, Config, Opts) ->
), ),
Data = #data{ Data = #data{
id = ResId, id = ResId,
type = Type,
group = Group, group = Group,
mod = ResourceType, mod = ResourceType,
callback_mode = emqx_resource:get_callback_mode(ResourceType), callback_mode = emqx_resource:get_callback_mode(ResourceType),
@ -683,6 +688,9 @@ handle_event(EventType, EventData, State, Data) ->
error, error,
#{ #{
msg => "ignore_all_other_events", msg => "ignore_all_other_events",
resource_id => Data#data.id,
group => Data#data.group,
type => Data#data.type,
event_type => EventType, event_type => EventType,
event_data => EventData, event_data => EventData,
state => State, state => State,
@ -752,8 +760,8 @@ handle_remove_event(From, ClearMetrics, Data) ->
start_resource(Data, From) -> start_resource(Data, From) ->
%% in case the emqx_resource:call_start/2 hangs, the lookup/1 can read status from the cache %% in case the emqx_resource:call_start/2 hangs, the lookup/1 can read status from the cache
ResId = Data#data.id, #data{id = ResId, mod = Mod, config = Config, group = Group, type = Type} = Data,
case emqx_resource:call_start(ResId, Data#data.mod, Data#data.config) of case emqx_resource:call_start(ResId, Mod, Config) of
{ok, ResourceState} -> {ok, ResourceState} ->
UpdatedData1 = Data#data{status = ?status_connecting, state = ResourceState}, UpdatedData1 = Data#data{status = ?status_connecting, state = ResourceState},
%% Perform an initial health_check immediately before transitioning into a connected state %% Perform an initial health_check immediately before transitioning into a connected state
@ -764,7 +772,9 @@ start_resource(Data, From) ->
IsDryRun = emqx_resource:is_dry_run(ResId), IsDryRun = emqx_resource:is_dry_run(ResId),
?SLOG(log_level(IsDryRun), #{ ?SLOG(log_level(IsDryRun), #{
msg => "start_resource_failed", msg => "start_resource_failed",
id => ResId, resource_id => ResId,
group => Group,
type => Type,
reason => Reason reason => Reason
}), }),
_ = maybe_alarm(?status_disconnected, IsDryRun, ResId, Err, Data#data.error), _ = maybe_alarm(?status_disconnected, IsDryRun, ResId, Err, Data#data.error),
@ -798,14 +808,20 @@ add_channels(Data) ->
add_channels_in_list([], Data) -> add_channels_in_list([], Data) ->
Data; Data;
add_channels_in_list([{ChannelID, ChannelConfig} | Rest], Data) -> add_channels_in_list([{ChannelID, ChannelConfig} | Rest], Data) ->
Id = Data#data.id, #data{
id = ResId,
mod = Mod,
state = State,
added_channels = AddedChannelsMap,
group = Group,
type = Type
} = Data,
case case
emqx_resource:call_add_channel( emqx_resource:call_add_channel(
Id, Data#data.mod, Data#data.state, ChannelID, ChannelConfig ResId, Mod, State, ChannelID, ChannelConfig
) )
of of
{ok, NewState} -> {ok, NewState} ->
AddedChannelsMap = Data#data.added_channels,
%% Set the channel status to connecting to indicate that %% Set the channel status to connecting to indicate that
%% we have not yet performed the initial health_check %% we have not yet performed the initial health_check
NewAddedChannelsMap = maps:put( NewAddedChannelsMap = maps:put(
@ -819,10 +835,12 @@ add_channels_in_list([{ChannelID, ChannelConfig} | Rest], Data) ->
}, },
add_channels_in_list(Rest, NewData); add_channels_in_list(Rest, NewData);
{error, Reason} = Error -> {error, Reason} = Error ->
IsDryRun = emqx_resource:is_dry_run(Id), IsDryRun = emqx_resource:is_dry_run(ResId),
?SLOG(log_level(IsDryRun), #{ ?SLOG(log_level(IsDryRun), #{
msg => "add_channel_failed", msg => "add_channel_failed",
id => Id, resource_id => ResId,
type => Type,
group => Group,
channel_id => ChannelID, channel_id => ChannelID,
reason => Reason reason => Reason
}), }),
@ -872,9 +890,15 @@ remove_channels(Data) ->
remove_channels_in_list([], Data, _KeepInChannelMap) -> remove_channels_in_list([], Data, _KeepInChannelMap) ->
Data; Data;
remove_channels_in_list([ChannelID | Rest], Data, KeepInChannelMap) -> remove_channels_in_list([ChannelID | Rest], Data, KeepInChannelMap) ->
AddedChannelsMap = Data#data.added_channels, #data{
Id = Data#data.id, id = ResId,
IsDryRun = emqx_resource:is_dry_run(Id), added_channels = AddedChannelsMap,
mod = Mod,
state = State,
group = Group,
type = Type
} = Data,
IsDryRun = emqx_resource:is_dry_run(ResId),
NewAddedChannelsMap = NewAddedChannelsMap =
case KeepInChannelMap of case KeepInChannelMap of
true -> true ->
@ -883,7 +907,7 @@ remove_channels_in_list([ChannelID | Rest], Data, KeepInChannelMap) ->
_ = maybe_clear_alarm(IsDryRun, ChannelID), _ = maybe_clear_alarm(IsDryRun, ChannelID),
maps:remove(ChannelID, AddedChannelsMap) maps:remove(ChannelID, AddedChannelsMap)
end, end,
case safe_call_remove_channel(Id, Data#data.mod, Data#data.state, ChannelID) of case safe_call_remove_channel(ResId, Mod, State, ChannelID) of
{ok, NewState} -> {ok, NewState} ->
NewData = Data#data{ NewData = Data#data{
state = NewState, state = NewState,
@ -893,7 +917,9 @@ remove_channels_in_list([ChannelID | Rest], Data, KeepInChannelMap) ->
{error, Reason} -> {error, Reason} ->
?SLOG(log_level(IsDryRun), #{ ?SLOG(log_level(IsDryRun), #{
msg => "remove_channel_failed", msg => "remove_channel_failed",
id => Id, resource_id => ResId,
group => Group,
type => Type,
channel_id => ChannelID, channel_id => ChannelID,
reason => Reason reason => Reason
}), }),
@ -997,7 +1023,12 @@ handle_remove_channel(From, ChannelId, Data) ->
end. end.
handle_remove_channel_exists(From, ChannelId, Data) -> handle_remove_channel_exists(From, ChannelId, Data) ->
#data{id = Id, added_channels = AddedChannelsMap} = Data, #data{
id = Id,
group = Group,
type = Type,
added_channels = AddedChannelsMap
} = Data,
case case
emqx_resource:call_remove_channel( emqx_resource:call_remove_channel(
Id, Data#data.mod, Data#data.state, ChannelId Id, Data#data.mod, Data#data.state, ChannelId
@ -1014,7 +1045,9 @@ handle_remove_channel_exists(From, ChannelId, Data) ->
IsDryRun = emqx_resource:is_dry_run(Id), IsDryRun = emqx_resource:is_dry_run(Id),
?SLOG(log_level(IsDryRun), #{ ?SLOG(log_level(IsDryRun), #{
msg => "remove_channel_failed", msg => "remove_channel_failed",
id => Id, resource_id => Id,
group => Group,
type => Type,
channel_id => ChannelId, channel_id => ChannelId,
reason => Reason reason => Reason
}), }),
@ -1123,10 +1156,13 @@ continue_resource_health_check_connected(NewStatus, Data0) ->
Actions = Replies ++ resource_health_check_actions(Data), Actions = Replies ++ resource_health_check_actions(Data),
{keep_state, Data, Actions}; {keep_state, Data, Actions};
_ -> _ ->
IsDryRun = emqx_resource:is_dry_run(Data0#data.id), #data{id = ResId, group = Group, type = Type} = Data0,
IsDryRun = emqx_resource:is_dry_run(ResId),
?SLOG(log_level(IsDryRun), #{ ?SLOG(log_level(IsDryRun), #{
msg => "health_check_failed", msg => "health_check_failed",
id => Data0#data.id, resource_id => ResId,
group => Group,
type => Type,
status => NewStatus status => NewStatus
}), }),
%% Note: works because, coincidentally, channel/resource status is a %% Note: works because, coincidentally, channel/resource status is a
@ -1633,6 +1669,8 @@ parse_health_check_result({error, Error}, Data) ->
#{ #{
msg => "health_check_exception", msg => "health_check_exception",
resource_id => Data#data.id, resource_id => Data#data.id,
type => Data#data.type,
group => Data#data.group,
reason => Error reason => Error
} }
), ),

View File

@ -19,14 +19,16 @@
-include("emqx_resource.hrl"). -include("emqx_resource.hrl").
-export([ensure_child/5, delete_child/1]). -export([ensure_child/6, delete_child/1]).
-export([start_link/0]). -export([start_link/0]).
-export([init/1]). -export([init/1]).
ensure_child(ResId, Group, ResourceType, Config, Opts) -> ensure_child(Type, ResId, Group, ResourceType, Config, Opts) ->
case supervisor:start_child(?MODULE, child_spec(ResId, Group, ResourceType, Config, Opts)) of case
supervisor:start_child(?MODULE, child_spec(Type, ResId, Group, ResourceType, Config, Opts))
of
{error, Reason} -> {error, Reason} ->
%% This should not happen in production but it can be a huge time sink in %% This should not happen in production but it can be a huge time sink in
%% development environments if the error is just silently ignored. %% development environments if the error is just silently ignored.
@ -55,13 +57,14 @@ init([]) ->
SupFlags = #{strategy => one_for_one, intensity => 10, period => 10}, SupFlags = #{strategy => one_for_one, intensity => 10, period => 10},
{ok, {SupFlags, ChildSpecs}}. {ok, {SupFlags, ChildSpecs}}.
child_spec(ResId, Group, ResourceType, Config, Opts) -> child_spec(Type, ResId, Group, ResourceType, Config, Opts) ->
#{ #{
id => ResId, id => ResId,
start => {emqx_resource_manager, start_link, [ResId, Group, ResourceType, Config, Opts]}, start =>
{emqx_resource_manager, start_link, [Type, ResId, Group, ResourceType, Config, Opts]},
restart => transient, restart => transient,
%% never force kill a resource manager. %% never force kill a resource manager.
%% becasue otherwise it may lead to release leak, %% because otherwise it may lead to release leak,
%% resource_manager's terminate callback calls resource on_stop %% resource_manager's terminate callback calls resource on_stop
shutdown => infinity, shutdown => infinity,
type => worker, type => worker,

View File

@ -23,6 +23,7 @@
-include_lib("snabbkaffe/include/snabbkaffe.hrl"). -include_lib("snabbkaffe/include/snabbkaffe.hrl").
-define(TEST_RESOURCE, emqx_connector_demo). -define(TEST_RESOURCE, emqx_connector_demo).
-define(TYPE, test).
-define(ID, <<"id">>). -define(ID, <<"id">>).
-define(ID1, <<"id1">>). -define(ID1, <<"id1">>).
-define(DEFAULT_RESOURCE_GROUP, <<"default">>). -define(DEFAULT_RESOURCE_GROUP, <<"default">>).
@ -90,6 +91,7 @@ t_create_remove(_) ->
?assertMatch( ?assertMatch(
{error, _}, {error, _},
emqx_resource:check_and_create_local( emqx_resource:check_and_create_local(
?TYPE,
?ID, ?ID,
?DEFAULT_RESOURCE_GROUP, ?DEFAULT_RESOURCE_GROUP,
?TEST_RESOURCE, ?TEST_RESOURCE,
@ -110,6 +112,7 @@ t_create_remove(_) ->
?assertMatch( ?assertMatch(
{ok, _}, {ok, _},
emqx_resource:recreate_local( emqx_resource:recreate_local(
?TYPE,
?ID, ?ID,
?TEST_RESOURCE, ?TEST_RESOURCE,
#{name => test_resource}, #{name => test_resource},
@ -135,6 +138,7 @@ t_create_remove_local(_) ->
?assertMatch( ?assertMatch(
{error, _}, {error, _},
emqx_resource:check_and_create_local( emqx_resource:check_and_create_local(
?TYPE,
?ID, ?ID,
?DEFAULT_RESOURCE_GROUP, ?DEFAULT_RESOURCE_GROUP,
?TEST_RESOURCE, ?TEST_RESOURCE,
@ -153,6 +157,7 @@ t_create_remove_local(_) ->
), ),
emqx_resource:recreate_local( emqx_resource:recreate_local(
?TYPE,
?ID, ?ID,
?TEST_RESOURCE, ?TEST_RESOURCE,
#{name => test_resource}, #{name => test_resource},
@ -166,6 +171,7 @@ t_create_remove_local(_) ->
emqx_resource:set_resource_status_connecting(?ID), emqx_resource:set_resource_status_connecting(?ID),
emqx_resource:recreate_local( emqx_resource:recreate_local(
?TYPE,
?ID, ?ID,
?TEST_RESOURCE, ?TEST_RESOURCE,
#{name => test_resource}, #{name => test_resource},
@ -937,6 +943,7 @@ t_stop_start(_) ->
?assertMatch( ?assertMatch(
{error, _}, {error, _},
emqx_resource:check_and_create_local( emqx_resource:check_and_create_local(
?TYPE,
?ID, ?ID,
?DEFAULT_RESOURCE_GROUP, ?DEFAULT_RESOURCE_GROUP,
?TEST_RESOURCE, ?TEST_RESOURCE,
@ -947,6 +954,7 @@ t_stop_start(_) ->
?assertMatch( ?assertMatch(
{ok, _}, {ok, _},
emqx_resource:check_and_create_local( emqx_resource:check_and_create_local(
?TYPE,
?ID, ?ID,
?DEFAULT_RESOURCE_GROUP, ?DEFAULT_RESOURCE_GROUP,
?TEST_RESOURCE, ?TEST_RESOURCE,
@ -964,6 +972,7 @@ t_stop_start(_) ->
?assertMatch( ?assertMatch(
{ok, _}, {ok, _},
emqx_resource:check_and_recreate_local( emqx_resource:check_and_recreate_local(
?TYPE,
?ID, ?ID,
?TEST_RESOURCE, ?TEST_RESOURCE,
#{<<"name">> => <<"test_resource">>}, #{<<"name">> => <<"test_resource">>},
@ -1013,6 +1022,7 @@ t_stop_start_local(_) ->
?assertMatch( ?assertMatch(
{error, _}, {error, _},
emqx_resource:check_and_create_local( emqx_resource:check_and_create_local(
?TYPE,
?ID, ?ID,
?DEFAULT_RESOURCE_GROUP, ?DEFAULT_RESOURCE_GROUP,
?TEST_RESOURCE, ?TEST_RESOURCE,
@ -1023,6 +1033,7 @@ t_stop_start_local(_) ->
?assertMatch( ?assertMatch(
{ok, _}, {ok, _},
emqx_resource:check_and_create_local( emqx_resource:check_and_create_local(
?TYPE,
?ID, ?ID,
?DEFAULT_RESOURCE_GROUP, ?DEFAULT_RESOURCE_GROUP,
?TEST_RESOURCE, ?TEST_RESOURCE,
@ -1033,6 +1044,7 @@ t_stop_start_local(_) ->
?assertMatch( ?assertMatch(
{ok, _}, {ok, _},
emqx_resource:check_and_recreate_local( emqx_resource:check_and_recreate_local(
?TYPE,
?ID, ?ID,
?TEST_RESOURCE, ?TEST_RESOURCE,
#{<<"name">> => <<"test_resource">>}, #{<<"name">> => <<"test_resource">>},
@ -1108,6 +1120,7 @@ create_dry_run_local_succ() ->
?assertEqual( ?assertEqual(
ok, ok,
emqx_resource:create_dry_run_local( emqx_resource:create_dry_run_local(
test,
?TEST_RESOURCE, ?TEST_RESOURCE,
#{name => test_resource, register => true} #{name => test_resource, register => true}
) )
@ -1118,6 +1131,7 @@ t_create_dry_run_local_failed(_) ->
ct:timetrap({seconds, 120}), ct:timetrap({seconds, 120}),
ct:pal("creating with creation error"), ct:pal("creating with creation error"),
Res1 = emqx_resource:create_dry_run_local( Res1 = emqx_resource:create_dry_run_local(
test,
?TEST_RESOURCE, ?TEST_RESOURCE,
#{create_error => true} #{create_error => true}
), ),
@ -1125,6 +1139,7 @@ t_create_dry_run_local_failed(_) ->
ct:pal("creating with health check error"), ct:pal("creating with health check error"),
Res2 = emqx_resource:create_dry_run_local( Res2 = emqx_resource:create_dry_run_local(
test,
?TEST_RESOURCE, ?TEST_RESOURCE,
#{name => test_resource, health_check_error => true} #{name => test_resource, health_check_error => true}
), ),
@ -1132,6 +1147,7 @@ t_create_dry_run_local_failed(_) ->
ct:pal("creating with stop error"), ct:pal("creating with stop error"),
Res3 = emqx_resource:create_dry_run_local( Res3 = emqx_resource:create_dry_run_local(
test,
?TEST_RESOURCE, ?TEST_RESOURCE,
#{name => test_resource, stop_error => true} #{name => test_resource, stop_error => true}
), ),
@ -3490,10 +3506,10 @@ gauge_metric_set_fns() ->
]. ].
create(Id, Group, Type, Config) -> create(Id, Group, Type, Config) ->
emqx_resource:create_local(Id, Group, Type, Config). emqx_resource:create_local(test, Id, Group, Type, Config).
create(Id, Group, Type, Config, Opts) -> create(Id, Group, Type, Config, Opts) ->
emqx_resource:create_local(Id, Group, Type, Config, Opts). emqx_resource:create_local(test, Id, Group, Type, Config, Opts).
log_consistency_prop() -> log_consistency_prop() ->
{"check state and cache consistency", fun ?MODULE:log_consistency_prop/1}. {"check state and cache consistency", fun ?MODULE:log_consistency_prop/1}.