feat(telemetry): save uuids to files
In order for the node and cluster UUIDs used by telemetry to survive database purges, we'll save the generated UUIDs to files in EMQX's data directory as well.
This commit is contained in:
parent
866810cea6
commit
4afb4d9dd8
|
@ -93,6 +93,9 @@
|
||||||
|
|
||||||
-define(TELEMETRY_SHARD, emqx_telemetry_shard).
|
-define(TELEMETRY_SHARD, emqx_telemetry_shard).
|
||||||
|
|
||||||
|
-define(NODE_UUID_FILENAME, "node.uuid").
|
||||||
|
-define(CLUSTER_UUID_FILENAME, "cluster.uuid").
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% API
|
%% API
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
@ -535,7 +538,11 @@ ensure_uuids() ->
|
||||||
NodeUUID =
|
NodeUUID =
|
||||||
case mnesia:wread({?TELEMETRY, node()}) of
|
case mnesia:wread({?TELEMETRY, node()}) of
|
||||||
[] ->
|
[] ->
|
||||||
NodeUUID0 = generate_uuid(),
|
NodeUUID0 =
|
||||||
|
case get_uuid_from_file(node) of
|
||||||
|
{ok, NUUID} -> NUUID;
|
||||||
|
undefined -> generate_uuid()
|
||||||
|
end,
|
||||||
mnesia:write(
|
mnesia:write(
|
||||||
?TELEMETRY,
|
?TELEMETRY,
|
||||||
#telemetry{
|
#telemetry{
|
||||||
|
@ -551,7 +558,11 @@ ensure_uuids() ->
|
||||||
ClusterUUID =
|
ClusterUUID =
|
||||||
case mnesia:wread({?TELEMETRY, ?CLUSTER_UUID_KEY}) of
|
case mnesia:wread({?TELEMETRY, ?CLUSTER_UUID_KEY}) of
|
||||||
[] ->
|
[] ->
|
||||||
ClusterUUID0 = generate_uuid(),
|
ClusterUUID0 =
|
||||||
|
case get_uuid_from_file(cluster) of
|
||||||
|
{ok, CUUID} -> CUUID;
|
||||||
|
undefined -> generate_uuid()
|
||||||
|
end,
|
||||||
mnesia:write(
|
mnesia:write(
|
||||||
?TELEMETRY,
|
?TELEMETRY,
|
||||||
#telemetry{
|
#telemetry{
|
||||||
|
@ -566,8 +577,35 @@ ensure_uuids() ->
|
||||||
end,
|
end,
|
||||||
{NodeUUID, ClusterUUID}
|
{NodeUUID, ClusterUUID}
|
||||||
end,
|
end,
|
||||||
{atomic, UUIDs} = mria:transaction(?TELEMETRY_SHARD, Txn),
|
{atomic, {NodeUUID, ClusterUUID}} = mria:transaction(?TELEMETRY_SHARD, Txn),
|
||||||
UUIDs.
|
save_uuid_to_file(NodeUUID, node),
|
||||||
|
save_uuid_to_file(ClusterUUID, cluster),
|
||||||
|
{NodeUUID, ClusterUUID}.
|
||||||
|
|
||||||
|
get_uuid_from_file(Type) ->
|
||||||
|
Path = uuid_file_path(Type),
|
||||||
|
case file:read_file(Path) of
|
||||||
|
{ok,
|
||||||
|
UUID =
|
||||||
|
<<_:8/binary, "-", _:4/binary, "-", _:4/binary, "-", _:4/binary, "-", _:12/binary>>} ->
|
||||||
|
{ok, UUID};
|
||||||
|
_ ->
|
||||||
|
undefined
|
||||||
|
end.
|
||||||
|
|
||||||
|
save_uuid_to_file(UUID, Type) when is_binary(UUID) ->
|
||||||
|
Path = uuid_file_path(Type),
|
||||||
|
ok = filelib:ensure_dir(Path),
|
||||||
|
ok = file:write_file(Path, UUID).
|
||||||
|
|
||||||
|
uuid_file_path(Type) ->
|
||||||
|
DataDir = emqx:data_dir(),
|
||||||
|
Filename =
|
||||||
|
case Type of
|
||||||
|
node -> ?NODE_UUID_FILENAME;
|
||||||
|
cluster -> ?CLUSTER_UUID_FILENAME
|
||||||
|
end,
|
||||||
|
filename:join(DataDir, Filename).
|
||||||
|
|
||||||
empty_state() ->
|
empty_state() ->
|
||||||
#state{
|
#state{
|
||||||
|
|
|
@ -151,6 +151,41 @@ init_per_testcase(t_cluster_uuid, Config) ->
|
||||||
Node = start_slave(n1),
|
Node = start_slave(n1),
|
||||||
ok = setup_slave(Node),
|
ok = setup_slave(Node),
|
||||||
[{n1, Node} | Config];
|
[{n1, Node} | Config];
|
||||||
|
init_per_testcase(t_uuid_restored_from_file, Config) ->
|
||||||
|
mock_httpc(),
|
||||||
|
NodeUUID = <<"AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE">>,
|
||||||
|
ClusterUUID = <<"FFFFFFFF-GGGG-HHHH-IIII-JJJJJJJJJJJJ">>,
|
||||||
|
DataDir = emqx:data_dir(),
|
||||||
|
NodeUUIDFile = filename:join(DataDir, "node.uuid"),
|
||||||
|
ClusterUUIDFile = filename:join(DataDir, "cluster.uuid"),
|
||||||
|
file:delete(NodeUUIDFile),
|
||||||
|
file:delete(ClusterUUIDFile),
|
||||||
|
ok = file:write_file(NodeUUIDFile, NodeUUID),
|
||||||
|
ok = file:write_file(ClusterUUIDFile, ClusterUUID),
|
||||||
|
|
||||||
|
%% clear the UUIDs in the DB
|
||||||
|
{atomic, ok} = mria:clear_table(emqx_telemetry),
|
||||||
|
emqx_common_test_helpers:stop_apps([emqx_conf, emqx_authn, emqx_authz, emqx_modules]),
|
||||||
|
emqx_common_test_helpers:start_apps(
|
||||||
|
[emqx_conf, emqx_authn, emqx_authz, emqx_modules],
|
||||||
|
fun set_special_configs/1
|
||||||
|
),
|
||||||
|
Node = start_slave(n1),
|
||||||
|
ok = setup_slave(Node),
|
||||||
|
[
|
||||||
|
{n1, Node},
|
||||||
|
{node_uuid, NodeUUID},
|
||||||
|
{cluster_uuid, ClusterUUID}
|
||||||
|
| Config
|
||||||
|
];
|
||||||
|
init_per_testcase(t_uuid_saved_to_file, Config) ->
|
||||||
|
mock_httpc(),
|
||||||
|
DataDir = emqx:data_dir(),
|
||||||
|
NodeUUIDFile = filename:join(DataDir, "node.uuid"),
|
||||||
|
ClusterUUIDFile = filename:join(DataDir, "cluster.uuid"),
|
||||||
|
file:delete(NodeUUIDFile),
|
||||||
|
file:delete(ClusterUUIDFile),
|
||||||
|
Config;
|
||||||
init_per_testcase(t_num_clients, Config) ->
|
init_per_testcase(t_num_clients, Config) ->
|
||||||
mock_httpc(),
|
mock_httpc(),
|
||||||
ok = snabbkaffe:start_trace(),
|
ok = snabbkaffe:start_trace(),
|
||||||
|
@ -213,6 +248,14 @@ end_per_testcase(t_num_clients, Config) ->
|
||||||
meck:unload([httpc]),
|
meck:unload([httpc]),
|
||||||
ok = snabbkaffe:stop(),
|
ok = snabbkaffe:stop(),
|
||||||
Config;
|
Config;
|
||||||
|
end_per_testcase(t_uuid_restored_from_file, _Config) ->
|
||||||
|
DataDir = emqx:data_dir(),
|
||||||
|
NodeUUIDFile = filename:join(DataDir, "node.uuid"),
|
||||||
|
ClusterUUIDFile = filename:join(DataDir, "cluster.uuid"),
|
||||||
|
ok = file:delete(NodeUUIDFile),
|
||||||
|
ok = file:delete(ClusterUUIDFile),
|
||||||
|
meck:unload([httpc]),
|
||||||
|
ok;
|
||||||
end_per_testcase(_Testcase, _Config) ->
|
end_per_testcase(_Testcase, _Config) ->
|
||||||
meck:unload([httpc]),
|
meck:unload([httpc]),
|
||||||
ok.
|
ok.
|
||||||
|
@ -248,6 +291,48 @@ t_cluster_uuid(Config) ->
|
||||||
?assertNotEqual(NodeUUID0, NodeUUID1),
|
?assertNotEqual(NodeUUID0, NodeUUID1),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
|
%% should attempt read UUID from file in data dir to keep UUIDs
|
||||||
|
%% unique, in the event of a database purge.
|
||||||
|
t_uuid_restored_from_file(Config) ->
|
||||||
|
ExpectedNodeUUID = ?config(node_uuid, Config),
|
||||||
|
ExpectedClusterUUID = ?config(cluster_uuid, Config),
|
||||||
|
?assertEqual(
|
||||||
|
{ok, ExpectedNodeUUID},
|
||||||
|
emqx_telemetry:get_node_uuid()
|
||||||
|
),
|
||||||
|
?assertEqual(
|
||||||
|
{ok, ExpectedClusterUUID},
|
||||||
|
emqx_telemetry:get_cluster_uuid()
|
||||||
|
),
|
||||||
|
ok.
|
||||||
|
|
||||||
|
t_uuid_saved_to_file(_Config) ->
|
||||||
|
DataDir = emqx:data_dir(),
|
||||||
|
NodeUUIDFile = filename:join(DataDir, "node.uuid"),
|
||||||
|
ClusterUUIDFile = filename:join(DataDir, "cluster.uuid"),
|
||||||
|
%% preconditions
|
||||||
|
?assertEqual({error, enoent}, file:read_file(NodeUUIDFile)),
|
||||||
|
?assertEqual({error, enoent}, file:read_file(ClusterUUIDFile)),
|
||||||
|
|
||||||
|
%% clear the UUIDs in the DB
|
||||||
|
{atomic, ok} = mria:clear_table(emqx_telemetry),
|
||||||
|
emqx_common_test_helpers:stop_apps([emqx_conf, emqx_authn, emqx_authz, emqx_modules]),
|
||||||
|
emqx_common_test_helpers:start_apps(
|
||||||
|
[emqx_conf, emqx_authn, emqx_authz, emqx_modules],
|
||||||
|
fun set_special_configs/1
|
||||||
|
),
|
||||||
|
{ok, NodeUUID} = emqx_telemetry:get_node_uuid(),
|
||||||
|
{ok, ClusterUUID} = emqx_telemetry:get_cluster_uuid(),
|
||||||
|
?assertEqual(
|
||||||
|
{ok, NodeUUID},
|
||||||
|
file:read_file(NodeUUIDFile)
|
||||||
|
),
|
||||||
|
?assertEqual(
|
||||||
|
{ok, ClusterUUID},
|
||||||
|
file:read_file(ClusterUUIDFile)
|
||||||
|
),
|
||||||
|
ok.
|
||||||
|
|
||||||
t_official_version(_) ->
|
t_official_version(_) ->
|
||||||
true = emqx_telemetry:official_version("0.0.0"),
|
true = emqx_telemetry:official_version("0.0.0"),
|
||||||
true = emqx_telemetry:official_version("1.1.1"),
|
true = emqx_telemetry:official_version("1.1.1"),
|
||||||
|
|
Loading…
Reference in New Issue