feat(license): check license before node start
This commit is contained in:
parent
50859bbd83
commit
64c59b5469
53
bin/emqx
53
bin/emqx
|
@ -341,19 +341,51 @@ relx_gen_id() {
|
||||||
od -t x -N 4 /dev/urandom | head -n1 | awk '{print $2}'
|
od -t x -N 4 /dev/urandom | head -n1 | awk '{print $2}'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
call_nodetool() {
|
||||||
|
"$ERTS_DIR/bin/escript" "$ROOTDIR/bin/nodetool" "$@"
|
||||||
|
}
|
||||||
|
|
||||||
# Control a node
|
# Control a node
|
||||||
relx_nodetool() {
|
relx_nodetool() {
|
||||||
command="$1"; shift
|
command="$1"; shift
|
||||||
ERL_FLAGS="${ERL_FLAGS:-} $EPMD_ARG" \
|
ERL_FLAGS="${ERL_FLAGS:-} $EPMD_ARG" \
|
||||||
"$ERTS_DIR/bin/escript" "$ROOTDIR/bin/nodetool" "$NAME_TYPE" "$NAME" \
|
call_nodetool "$NAME_TYPE" "$NAME" \
|
||||||
-setcookie "$COOKIE" "$command" "$@"
|
-setcookie "$COOKIE" "$command" "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
call_hocon() {
|
call_hocon() {
|
||||||
"$ERTS_DIR/bin/escript" "$ROOTDIR/bin/nodetool" hocon "$@" \
|
call_nodetool hocon "$@" \
|
||||||
|| die "call_hocon_failed: $*" $?
|
|| die "call_hocon_failed: $*" $?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get_config_value() {
|
||||||
|
path_to_value="$1"
|
||||||
|
call_hocon -s "$SCHEMA_MOD" -I "$CONFIGS_DIR/" -c "$RUNNER_ETC_DIR"/emqx.conf get "$path_to_value" | tr -d \"
|
||||||
|
}
|
||||||
|
|
||||||
|
check_license() {
|
||||||
|
if [ "$IS_ENTERPRISE" == "no" ]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
file_license="${EMQX_LICENSE__FILE:-$(get_config_value license.file)}"
|
||||||
|
|
||||||
|
if [[ -n "$file_license" && ("$file_license" != "undefined") ]]; then
|
||||||
|
call_nodetool check_license_file "$file_license"
|
||||||
|
else
|
||||||
|
key_license="${EMQX_LICENSE__KEY:-$(get_config_value license.key)}"
|
||||||
|
|
||||||
|
if [[ -n "$key_license" && ("$key_license" != "undefined") ]]; then
|
||||||
|
call_nodetool check_license_key "$key_license"
|
||||||
|
else
|
||||||
|
echoerr "License not found."
|
||||||
|
echoerr "Please specify one via EMQX_LICENSE__KEY or EMQX_LICENSE__FILE variables"
|
||||||
|
echoerr "or via license.key|file in emqx_enterprise.conf."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# Run an escript in the node's environment
|
# Run an escript in the node's environment
|
||||||
relx_escript() {
|
relx_escript() {
|
||||||
shift; scriptpath="$1"; shift
|
shift; scriptpath="$1"; shift
|
||||||
|
@ -374,11 +406,6 @@ generate_config() {
|
||||||
## changing the config 'log.rotation.size'
|
## changing the config 'log.rotation.size'
|
||||||
rm -rf "${RUNNER_LOG_DIR}"/*.siz
|
rm -rf "${RUNNER_LOG_DIR}"/*.siz
|
||||||
|
|
||||||
EMQX_LICENSE_CONF_OPTION=""
|
|
||||||
if [ "${EMQX_LICENSE_CONF:-}" != "" ]; then
|
|
||||||
EMQX_LICENSE_CONF_OPTION="-c ${EMQX_LICENSE_CONF}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
## timestamp for each generation
|
## timestamp for each generation
|
||||||
local NOW_TIME
|
local NOW_TIME
|
||||||
NOW_TIME="$(call_hocon now_time)"
|
NOW_TIME="$(call_hocon now_time)"
|
||||||
|
@ -387,9 +414,7 @@ generate_config() {
|
||||||
## NOTE: the generate command merges environment variables to the base config (emqx.conf),
|
## NOTE: the generate command merges environment variables to the base config (emqx.conf),
|
||||||
## but does not include the cluster-override.conf and local-override.conf
|
## but does not include the cluster-override.conf and local-override.conf
|
||||||
## meaning, certain overrides will not be mapped to app.<time>.config file
|
## meaning, certain overrides will not be mapped to app.<time>.config file
|
||||||
## disable SC2086 to allow EMQX_LICENSE_CONF_OPTION to split
|
call_hocon -v -t "$NOW_TIME" -I "$CONFIGS_DIR/" -s "$SCHEMA_MOD" -c "$RUNNER_ETC_DIR"/emqx.conf -d "$RUNNER_DATA_DIR"/configs generate
|
||||||
# shellcheck disable=SC2086
|
|
||||||
call_hocon -v -t "$NOW_TIME" -I "$CONFIGS_DIR/" -s "$SCHEMA_MOD" -c "$RUNNER_ETC_DIR"/emqx.conf $EMQX_LICENSE_CONF_OPTION -d "$RUNNER_DATA_DIR"/configs generate
|
|
||||||
|
|
||||||
## filenames are per-hocon convention
|
## filenames are per-hocon convention
|
||||||
local CONF_FILE="$CONFIGS_DIR/app.$NOW_TIME.config"
|
local CONF_FILE="$CONFIGS_DIR/app.$NOW_TIME.config"
|
||||||
|
@ -539,7 +564,7 @@ NAME="${EMQX_NODE__NAME:-}"
|
||||||
if [ -z "$NAME" ]; then
|
if [ -z "$NAME" ]; then
|
||||||
if [ "$IS_BOOT_COMMAND" = 'yes' ]; then
|
if [ "$IS_BOOT_COMMAND" = 'yes' ]; then
|
||||||
# for boot commands, inspect emqx.conf for node name
|
# for boot commands, inspect emqx.conf for node name
|
||||||
NAME="$(call_hocon -s "$SCHEMA_MOD" -I "$CONFIGS_DIR/" -c "$RUNNER_ETC_DIR"/emqx.conf get node.name | tr -d \")"
|
NAME="$(get_config_value node.name)"
|
||||||
else
|
else
|
||||||
vm_args_file="$(latest_vm_args 'EMQX_NODE__NAME')"
|
vm_args_file="$(latest_vm_args 'EMQX_NODE__NAME')"
|
||||||
NAME="$(grep -E '^-s?name' "${vm_args_file}" | awk '{print $2}')"
|
NAME="$(grep -E '^-s?name' "${vm_args_file}" | awk '{print $2}')"
|
||||||
|
@ -570,7 +595,7 @@ fi
|
||||||
COOKIE="${EMQX_NODE__COOKIE:-}"
|
COOKIE="${EMQX_NODE__COOKIE:-}"
|
||||||
if [ -z "$COOKIE" ]; then
|
if [ -z "$COOKIE" ]; then
|
||||||
if [ "$IS_BOOT_COMMAND" = 'yes' ]; then
|
if [ "$IS_BOOT_COMMAND" = 'yes' ]; then
|
||||||
COOKIE="$(call_hocon -s "$SCHEMA_MOD" -I "$CONFIGS_DIR/" -c "$RUNNER_ETC_DIR"/emqx.conf get node.cookie | tr -d \")"
|
COOKIE="$(get_config_value node.cookie)"
|
||||||
else
|
else
|
||||||
vm_args_file="$(latest_vm_args 'EMQX_NODE__COOKIE')"
|
vm_args_file="$(latest_vm_args 'EMQX_NODE__COOKIE')"
|
||||||
COOKIE="$(grep -E '^-setcookie' "${vm_args_file}" | awk '{print $2}')"
|
COOKIE="$(grep -E '^-setcookie' "${vm_args_file}" | awk '{print $2}')"
|
||||||
|
@ -742,6 +767,8 @@ case "${COMMAND}" in
|
||||||
#generate app.config and vm.args
|
#generate app.config and vm.args
|
||||||
generate_config "$NAME_TYPE" "$NAME"
|
generate_config "$NAME_TYPE" "$NAME"
|
||||||
|
|
||||||
|
check_license
|
||||||
|
|
||||||
# Setup beam-required vars
|
# Setup beam-required vars
|
||||||
EMU="beam"
|
EMU="beam"
|
||||||
PROGNAME="${0#*/}"
|
PROGNAME="${0#*/}"
|
||||||
|
@ -790,6 +817,8 @@ case "${COMMAND}" in
|
||||||
#generate app.config and vm.args
|
#generate app.config and vm.args
|
||||||
generate_config "$NAME_TYPE" "$NAME"
|
generate_config "$NAME_TYPE" "$NAME"
|
||||||
|
|
||||||
|
check_license
|
||||||
|
|
||||||
[ -f "$REL_DIR/$REL_NAME.boot" ] && BOOTFILE="$REL_NAME" || BOOTFILE=start
|
[ -f "$REL_DIR/$REL_NAME.boot" ] && BOOTFILE="$REL_NAME" || BOOTFILE=start
|
||||||
FOREGROUNDOPTIONS="-noshell -noinput +Bd"
|
FOREGROUNDOPTIONS="-noshell -noinput +Bd"
|
||||||
|
|
||||||
|
|
19
bin/nodetool
19
bin/nodetool
|
@ -24,6 +24,10 @@ main(Args) ->
|
||||||
["hocon" | Rest] ->
|
["hocon" | Rest] ->
|
||||||
%% forward the call to hocon_cli
|
%% forward the call to hocon_cli
|
||||||
hocon_cli:main(Rest);
|
hocon_cli:main(Rest);
|
||||||
|
["check_license_key", Key] ->
|
||||||
|
check_license(#{key => list_to_binary(Key)});
|
||||||
|
["check_license_file", File] ->
|
||||||
|
check_license(#{file => list_to_binary(File)});
|
||||||
_ ->
|
_ ->
|
||||||
do(Args)
|
do(Args)
|
||||||
end.
|
end.
|
||||||
|
@ -253,6 +257,21 @@ chkconfig(File) ->
|
||||||
halt(1)
|
halt(1)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
check_license(Config) ->
|
||||||
|
ok = application:load(emqx_license),
|
||||||
|
%% This checks formal license validity to ensure
|
||||||
|
%% that the node can successfully start with the given license.
|
||||||
|
|
||||||
|
%% However, a valid license may be expired. In this case, the node will
|
||||||
|
%% start but will not be able to receive connections due to connection limits.
|
||||||
|
%% It may receive license updates from the cluster further.
|
||||||
|
case emqx_license:read_license(Config) of
|
||||||
|
{ok, _} -> ok;
|
||||||
|
{error, Error} ->
|
||||||
|
io:format(standard_error, "Error reading license: ~p~n", [Error]),
|
||||||
|
halt(1)
|
||||||
|
end.
|
||||||
|
|
||||||
%%
|
%%
|
||||||
%% Given a string or binary, parse it into a list of terms, ala file:consult/0
|
%% Given a string or binary, parse it into a list of terms, ala file:consult/0
|
||||||
%%
|
%%
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
check/2,
|
check/2,
|
||||||
unload/0,
|
unload/0,
|
||||||
read_license/0,
|
read_license/0,
|
||||||
|
read_license/1,
|
||||||
update_file/1,
|
update_file/1,
|
||||||
update_key/1]).
|
update_key/1]).
|
||||||
|
|
||||||
|
|
6
mix.exs
6
mix.exs
|
@ -552,7 +552,8 @@ defmodule EMQXUmbrella.MixProject do
|
||||||
emqx_schema_mod: emqx_schema_mod(edition_type),
|
emqx_schema_mod: emqx_schema_mod(edition_type),
|
||||||
emqx_machine_boot_apps: emqx_machine_boot_app_list(edition_type),
|
emqx_machine_boot_apps: emqx_machine_boot_app_list(edition_type),
|
||||||
built_on_arch: built_on(),
|
built_on_arch: built_on(),
|
||||||
is_elixir: "yes"
|
is_elixir: "yes",
|
||||||
|
is_enterprise: (if edition_type == :enterprise, do: "yes", else: "no")
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -579,7 +580,8 @@ defmodule EMQXUmbrella.MixProject do
|
||||||
built_on_arch: built_on(),
|
built_on_arch: built_on(),
|
||||||
emqx_schema_mod: emqx_schema_mod(edition_type),
|
emqx_schema_mod: emqx_schema_mod(edition_type),
|
||||||
emqx_machine_boot_apps: emqx_machine_boot_app_list(edition_type),
|
emqx_machine_boot_apps: emqx_machine_boot_app_list(edition_type),
|
||||||
is_elixir: "yes"
|
is_elixir: "yes",
|
||||||
|
is_enterprise: (if edition_type == :enterprise, do: "yes", else: "no")
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -239,10 +239,12 @@ overlay_vars_rel(RelType) ->
|
||||||
|
|
||||||
overlay_vars_edition(ce) ->
|
overlay_vars_edition(ce) ->
|
||||||
[ {emqx_schema_mod, emqx_conf_schema}
|
[ {emqx_schema_mod, emqx_conf_schema}
|
||||||
|
, {is_enterprise, "no"}
|
||||||
, {emqx_machine_boot_apps, emqx_machine_boot_app_list(ce)}
|
, {emqx_machine_boot_apps, emqx_machine_boot_app_list(ce)}
|
||||||
];
|
];
|
||||||
overlay_vars_edition(ee) ->
|
overlay_vars_edition(ee) ->
|
||||||
[ {emqx_schema_mod, emqx_enterprise_conf_schema}
|
[ {emqx_schema_mod, emqx_enterprise_conf_schema}
|
||||||
|
, {is_enterprise, "yes"}
|
||||||
, {emqx_machine_boot_apps, emqx_machine_boot_app_list(ee)}
|
, {emqx_machine_boot_apps, emqx_machine_boot_app_list(ee)}
|
||||||
].
|
].
|
||||||
|
|
||||||
|
@ -324,7 +326,6 @@ relx_apps(ReleaseType, Edition) ->
|
||||||
, emqx_plugins
|
, emqx_plugins
|
||||||
]
|
]
|
||||||
++ [quicer || is_quicer_supported()]
|
++ [quicer || is_quicer_supported()]
|
||||||
%++ [emqx_license || is_enterprise(Edition)]
|
|
||||||
++ [bcrypt || provide_bcrypt_release(ReleaseType)]
|
++ [bcrypt || provide_bcrypt_release(ReleaseType)]
|
||||||
++ relx_apps_per_rel(ReleaseType)
|
++ relx_apps_per_rel(ReleaseType)
|
||||||
++ relx_additional_apps(ReleaseType, Edition).
|
++ relx_additional_apps(ReleaseType, Edition).
|
||||||
|
|
|
@ -15,6 +15,7 @@ RUNNER_DATA_DIR="{{ runner_data_dir }}"
|
||||||
RUNNER_USER="{{ runner_user }}"
|
RUNNER_USER="{{ runner_user }}"
|
||||||
IS_ELIXIR="{{ is_elixir }}"
|
IS_ELIXIR="{{ is_elixir }}"
|
||||||
SCHEMA_MOD="{{ emqx_schema_mod }}"
|
SCHEMA_MOD="{{ emqx_schema_mod }}"
|
||||||
|
IS_ENTERPRISE="{{ is_enterprise }}"
|
||||||
|
|
||||||
export EMQX_DESCRIPTION='{{ emqx_description }}'
|
export EMQX_DESCRIPTION='{{ emqx_description }}'
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue