Sync v4.3 to v4.4 (#6262)
* fix(http): fix duplicate http headers * chore(appup): add appup.src * fix(appup): fix multiply defined module in appup * chore(appup): fix wrong version * chore(ekka): Bump version to 0.8.1.5 * fix(update_appup): Fix warnings, add support for external repos * build: use find command's -delete option * ci: do not sync master branch * build: ensure openssl11 * build: copy only libcrypto and libtinfo * fix(trace): handler_id now always return atom Co-authored-by: zhouzb <zhouzb@emqx.io> Co-authored-by: k32 <10274441+k32@users.noreply.github.com>
This commit is contained in:
parent
95e8671c7f
commit
2514f474b0
|
@ -88,6 +88,12 @@ emqx_test(){
|
||||||
;;
|
;;
|
||||||
"rpm")
|
"rpm")
|
||||||
packagename=$(basename "${PACKAGE_PATH}/${EMQX_NAME}"-*.rpm)
|
packagename=$(basename "${PACKAGE_PATH}/${EMQX_NAME}"-*.rpm)
|
||||||
|
|
||||||
|
if [[ "${ARCH}" == "amd64" && $(rpm -E '%{rhel}') == 7 ]] ; then
|
||||||
|
# EMQX OTP requires openssl11 to have TLS1.3 support
|
||||||
|
yum install -y openssl11
|
||||||
|
fi
|
||||||
|
|
||||||
rpm -ivh "${PACKAGE_PATH}/${packagename}"
|
rpm -ivh "${PACKAGE_PATH}/${packagename}"
|
||||||
if ! rpm -q emqx | grep -q emqx; then
|
if ! rpm -q emqx | grep -q emqx; then
|
||||||
echo "package install error"
|
echo "package install error"
|
||||||
|
|
|
@ -3,7 +3,6 @@ name: Sync to enterprise
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
|
||||||
- main-v*
|
- main-v*
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
@ -23,11 +22,7 @@ jobs:
|
||||||
id: create_pull_request
|
id: create_pull_request
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
if [ "$GITHUB_REF" = "refs/heads/master" ]; then
|
EE_REF="${GITHUB_REF}-enterprise"
|
||||||
EE_REF="refs/heads/enterprise"
|
|
||||||
else
|
|
||||||
EE_REF="${GITHUB_REF}-enterprise"
|
|
||||||
fi
|
|
||||||
R=$(curl --silent --show-error \
|
R=$(curl --silent --show-error \
|
||||||
-H "Accept: application/vnd.github.v3+json" \
|
-H "Accept: application/vnd.github.v3+json" \
|
||||||
-H "Authorization: token ${{ secrets.CI_GIT_TOKEN }}" \
|
-H "Authorization: token ${{ secrets.CI_GIT_TOKEN }}" \
|
||||||
|
|
2
Makefile
2
Makefile
|
@ -91,7 +91,7 @@ $(PROFILES:%=clean-%):
|
||||||
rm rebar.lock \
|
rm rebar.lock \
|
||||||
rm -rf _build/$(@:clean-%=%)/rel; \
|
rm -rf _build/$(@:clean-%=%)/rel; \
|
||||||
find _build/$(@:clean-%=%) -name '*.beam' -o -name '*.so' -o -name '*.app' -o -name '*.appup' -o -name '*.o' -o -name '*.d' -type f | xargs rm -f; \
|
find _build/$(@:clean-%=%) -name '*.beam' -o -name '*.so' -o -name '*.app' -o -name '*.appup' -o -name '*.o' -o -name '*.d' -type f | xargs rm -f; \
|
||||||
find _build/$(@:clean-%=%) -type l | xargs rm -i -f ; \
|
find _build/$(@:clean-%=%) -type l -delete; \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
.PHONY: clean-all
|
.PHONY: clean-all
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{application, emqx_auth_http,
|
{application, emqx_auth_http,
|
||||||
[{description, "EMQ X Authentication/ACL with HTTP API"},
|
[{description, "EMQ X Authentication/ACL with HTTP API"},
|
||||||
{vsn, "4.3.2"}, % strict semver, bump manually!
|
{vsn, "4.3.3"}, % strict semver, bump manually!
|
||||||
{modules, []},
|
{modules, []},
|
||||||
{registered, [emqx_auth_http_sup]},
|
{registered, [emqx_auth_http_sup]},
|
||||||
{applications, [kernel,stdlib,ehttpc]},
|
{applications, [kernel,stdlib,ehttpc]},
|
||||||
|
|
|
@ -2,12 +2,22 @@
|
||||||
|
|
||||||
{VSN,
|
{VSN,
|
||||||
[
|
[
|
||||||
|
{"4.3.2", [
|
||||||
|
{apply, {application, stop, [emqx_auth_http]}},
|
||||||
|
{load_module, emqx_auth_http_app, brutal_purge, soft_purge,[]},
|
||||||
|
{load_module, emqx_auth_http_cli, brutal_purge, soft_purge,[]}
|
||||||
|
]},
|
||||||
{<<"4.3.[0-1]">>, [
|
{<<"4.3.[0-1]">>, [
|
||||||
{restart_application, emqx_auth_http}
|
{restart_application, emqx_auth_http}
|
||||||
]},
|
]},
|
||||||
{<<".*">>, []}
|
{<<".*">>, []}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
{"4.3.2", [
|
||||||
|
{apply, {application, stop, [emqx_auth_http]}},
|
||||||
|
{load_module, emqx_auth_http_app, brutal_purge, soft_purge,[]},
|
||||||
|
{load_module, emqx_auth_http_cli, brutal_purge, soft_purge,[]}
|
||||||
|
]},
|
||||||
{<<"4.3.[0-1]">>, [
|
{<<"4.3.[0-1]">>, [
|
||||||
{restart_application, emqx_auth_http}
|
{restart_application, emqx_auth_http}
|
||||||
]},
|
]},
|
||||||
|
|
|
@ -150,7 +150,7 @@ ensure_content_type_header(Method, Headers)
|
||||||
when Method =:= post orelse Method =:= put ->
|
when Method =:= post orelse Method =:= put ->
|
||||||
Headers;
|
Headers;
|
||||||
ensure_content_type_header(_Method, Headers) ->
|
ensure_content_type_header(_Method, Headers) ->
|
||||||
lists:keydelete("content-type", 1, Headers).
|
lists:keydelete(<<"content-type">>, 1, Headers).
|
||||||
|
|
||||||
path(#{path := "", 'query' := Query}) ->
|
path(#{path := "", 'query' := Query}) ->
|
||||||
"?" ++ Query;
|
"?" ++ Query;
|
||||||
|
|
|
@ -32,7 +32,7 @@ request(PoolName, get, Path, Headers, Params, Timeout) ->
|
||||||
reply(ehttpc:request(PoolName, get, {NewPath, Headers}, Timeout));
|
reply(ehttpc:request(PoolName, get, {NewPath, Headers}, Timeout));
|
||||||
|
|
||||||
request(PoolName, post, Path, Headers, Params, Timeout) ->
|
request(PoolName, post, Path, Headers, Params, Timeout) ->
|
||||||
Body = case proplists:get_value("content-type", Headers) of
|
Body = case proplists:get_value(<<"content-type">>, Headers) of
|
||||||
"application/x-www-form-urlencoded" ->
|
"application/x-www-form-urlencoded" ->
|
||||||
cow_qs:qs(bin_kw(Params));
|
cow_qs:qs(bin_kw(Params));
|
||||||
"application/json" ->
|
"application/json" ->
|
||||||
|
|
|
@ -379,16 +379,12 @@ to_trace(TraceParam) ->
|
||||||
{error, "type=[topic,clientid,ip_address] required"};
|
{error, "type=[topic,clientid,ip_address] required"};
|
||||||
{ok, #?TRACE{filter = undefined}} ->
|
{ok, #?TRACE{filter = undefined}} ->
|
||||||
{error, "topic/clientid/ip_address filter required"};
|
{error, "topic/clientid/ip_address filter required"};
|
||||||
{ok, TraceRec0 = #?TRACE{name = Name, type = Type}} ->
|
{ok, TraceRec0 = #?TRACE{}} ->
|
||||||
case emqx_trace_handler:handler_id(Name, Type) of
|
case fill_default(TraceRec0) of
|
||||||
{ok, _} ->
|
#?TRACE{start_at = Start, end_at = End} when End =< Start ->
|
||||||
case fill_default(TraceRec0) of
|
{error, "failed by start_at >= end_at"};
|
||||||
#?TRACE{start_at = Start, end_at = End} when End =< Start ->
|
TraceRec ->
|
||||||
{error, "failed by start_at >= end_at"};
|
{ok, TraceRec}
|
||||||
TraceRec -> {ok, TraceRec}
|
|
||||||
end;
|
|
||||||
{error, Reason} ->
|
|
||||||
{error, Reason}
|
|
||||||
end
|
end
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
@ -408,7 +404,7 @@ fill_default(Trace) -> Trace.
|
||||||
|
|
||||||
to_trace([], Rec) -> {ok, Rec};
|
to_trace([], Rec) -> {ok, Rec};
|
||||||
to_trace([{name, Name} | Trace], Rec) ->
|
to_trace([{name, Name} | Trace], Rec) ->
|
||||||
case io_lib:printable_unicode_list(binary_to_list(Name)) of
|
case io_lib:printable_unicode_list(unicode:characters_to_list(Name, utf8)) of
|
||||||
true ->
|
true ->
|
||||||
case binary:match(Name, [<<"/">>], []) of
|
case binary:match(Name, [<<"/">>], []) of
|
||||||
nomatch -> to_trace(Trace, Rec#?TRACE{name = Name});
|
nomatch -> to_trace(Trace, Rec#?TRACE{name = Name});
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{application, emqx_web_hook,
|
{application, emqx_web_hook,
|
||||||
[{description, "EMQ X WebHook Plugin"},
|
[{description, "EMQ X WebHook Plugin"},
|
||||||
{vsn, "4.3.7"}, % strict semver, bump manually!
|
{vsn, "4.3.8"}, % strict semver, bump manually!
|
||||||
{modules, []},
|
{modules, []},
|
||||||
{registered, [emqx_web_hook_sup]},
|
{registered, [emqx_web_hook_sup]},
|
||||||
{applications, [kernel,stdlib,ehttpc]},
|
{applications, [kernel,stdlib,ehttpc]},
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
%% -*- mode: erlang -*-
|
%% -*- mode: erlang -*-
|
||||||
{VSN,
|
{VSN,
|
||||||
[{"4.3.5",[{load_module,emqx_web_hook_actions,brutal_purge,soft_purge,[]}]},
|
[{"4.3.7",
|
||||||
|
[{apply,{application,stop,[emqx_web_hook]}},
|
||||||
|
{load_module,emqx_web_hook_app,brutal_purge,soft_purge,[]},
|
||||||
|
{load_module,emqx_web_hook_actions,brutal_purge,soft_purge,[]}]},
|
||||||
|
{"4.3.5",[{load_module,emqx_web_hook_actions,brutal_purge,soft_purge,[]}]},
|
||||||
{<<"4.3.[0-2]">>,
|
{<<"4.3.[0-2]">>,
|
||||||
[{apply,{application,stop,[emqx_web_hook]}},
|
[{apply,{application,stop,[emqx_web_hook]}},
|
||||||
{load_module,emqx_web_hook_app,brutal_purge,soft_purge,[]},
|
{load_module,emqx_web_hook_app,brutal_purge,soft_purge,[]},
|
||||||
|
@ -9,7 +13,11 @@
|
||||||
{<<"4.3.[3-4]">>,
|
{<<"4.3.[3-4]">>,
|
||||||
[{load_module,emqx_web_hook_actions,brutal_purge,soft_purge,[]}]},
|
[{load_module,emqx_web_hook_actions,brutal_purge,soft_purge,[]}]},
|
||||||
{<<".*">>,[]}],
|
{<<".*">>,[]}],
|
||||||
[{"4.3.5",[{load_module,emqx_web_hook_actions,brutal_purge,soft_purge,[]}]},
|
[{"4.3.7",
|
||||||
|
[{apply,{application,stop,[emqx_web_hook]}},
|
||||||
|
{load_module,emqx_web_hook_app,brutal_purge,soft_purge,[]},
|
||||||
|
{load_module,emqx_web_hook_actions,brutal_purge,soft_purge,[]}]},
|
||||||
|
{"4.3.5",[{load_module,emqx_web_hook_actions,brutal_purge,soft_purge,[]}]},
|
||||||
{<<"4.3.[0-2]">>,
|
{<<"4.3.[0-2]">>,
|
||||||
[{apply,{application,stop,[emqx_web_hook]}},
|
[{apply,{application,stop,[emqx_web_hook]}},
|
||||||
{load_module,emqx_web_hook_app,brutal_purge,soft_purge,[]},
|
{load_module,emqx_web_hook_app,brutal_purge,soft_purge,[]},
|
||||||
|
|
|
@ -295,7 +295,7 @@ create_req(_, Path, Headers, Body) ->
|
||||||
parse_action_params(Params = #{<<"url">> := URL}) ->
|
parse_action_params(Params = #{<<"url">> := URL}) ->
|
||||||
{ok, #{path := CommonPath}} = emqx_http_lib:uri_parse(URL),
|
{ok, #{path := CommonPath}} = emqx_http_lib:uri_parse(URL),
|
||||||
Method = method(maps:get(<<"method">>, Params, <<"POST">>)),
|
Method = method(maps:get(<<"method">>, Params, <<"POST">>)),
|
||||||
Headers = headers(maps:get(<<"headers">>, Params, undefined)),
|
Headers = headers(maps:get(<<"headers">>, Params, #{})),
|
||||||
NHeaders = ensure_content_type_header(Headers, Method),
|
NHeaders = ensure_content_type_header(Headers, Method),
|
||||||
#{method => Method,
|
#{method => Method,
|
||||||
path => merge_path(CommonPath, maps:get(<<"path">>, Params, <<>>)),
|
path => merge_path(CommonPath, maps:get(<<"path">>, Params, <<>>)),
|
||||||
|
@ -307,7 +307,7 @@ parse_action_params(Params = #{<<"url">> := URL}) ->
|
||||||
ensure_content_type_header(Headers, Method) when Method =:= post orelse Method =:= put ->
|
ensure_content_type_header(Headers, Method) when Method =:= post orelse Method =:= put ->
|
||||||
Headers;
|
Headers;
|
||||||
ensure_content_type_header(Headers, _Method) ->
|
ensure_content_type_header(Headers, _Method) ->
|
||||||
lists:keydelete("content-type", 1, Headers).
|
lists:keydelete(<<"content-type">>, 1, Headers).
|
||||||
|
|
||||||
merge_path(CommonPath, <<>>) ->
|
merge_path(CommonPath, <<>>) ->
|
||||||
l2b(CommonPath);
|
l2b(CommonPath);
|
||||||
|
@ -326,11 +326,8 @@ method(POST) when POST == <<"POST">>; POST == <<"post">> -> post;
|
||||||
method(PUT) when PUT == <<"PUT">>; PUT == <<"put">> -> put;
|
method(PUT) when PUT == <<"PUT">>; PUT == <<"put">> -> put;
|
||||||
method(DEL) when DEL == <<"DELETE">>; DEL == <<"delete">> -> delete.
|
method(DEL) when DEL == <<"DELETE">>; DEL == <<"delete">> -> delete.
|
||||||
|
|
||||||
headers(undefined) -> [];
|
headers(Headers) ->
|
||||||
headers(Headers) when is_map(Headers) ->
|
emqx_http_lib:normalise_headers(maps:to_list(Headers)).
|
||||||
headers(maps:to_list(Headers));
|
|
||||||
headers(Headers) when is_list(Headers) ->
|
|
||||||
[{string:to_lower(str(K)), str(V)} || {K, V} <- Headers].
|
|
||||||
|
|
||||||
str(Str) when is_list(Str) -> Str;
|
str(Str) when is_list(Str) -> Str;
|
||||||
str(Atom) when is_atom(Atom) -> atom_to_list(Atom);
|
str(Atom) when is_atom(Atom) -> atom_to_list(Atom);
|
||||||
|
|
|
@ -87,7 +87,7 @@ translate_env() ->
|
||||||
application:set_env(?APP, path, Path),
|
application:set_env(?APP, path, Path),
|
||||||
application:set_env(?APP, pool_opts, PoolOpts),
|
application:set_env(?APP, pool_opts, PoolOpts),
|
||||||
Headers = application:get_env(?APP, headers, []),
|
Headers = application:get_env(?APP, headers, []),
|
||||||
NHeaders = set_content_type(Headers),
|
NHeaders = set_content_type(emqx_http_lib:normalise_headers(Headers)),
|
||||||
application:set_env(?APP, headers, NHeaders).
|
application:set_env(?APP, headers, NHeaders).
|
||||||
|
|
||||||
path(#{path := "", 'query' := Query}) ->
|
path(#{path := "", 'query' := Query}) ->
|
||||||
|
@ -100,5 +100,5 @@ path(#{path := Path}) ->
|
||||||
Path.
|
Path.
|
||||||
|
|
||||||
set_content_type(Headers) ->
|
set_content_type(Headers) ->
|
||||||
NHeaders = proplists:delete(<<"Content-Type">>, proplists:delete(<<"content-type">>, Headers)),
|
NHeaders = proplists:delete(<<"content-type">>, Headers),
|
||||||
[{<<"content-type">>, <<"application/json">>} | NHeaders].
|
[{<<"content-type">>, <<"application/json">>} | NHeaders].
|
||||||
|
|
7
bin/emqx
7
bin/emqx
|
@ -41,9 +41,10 @@ if ! check_eralng_start >/dev/null 2>&1; then
|
||||||
export LD_LIBRARY_PATH="$DYNLIBS_DIR:$LD_LIBRARY_PATH"
|
export LD_LIBRARY_PATH="$DYNLIBS_DIR:$LD_LIBRARY_PATH"
|
||||||
if ! check_eralng_start; then
|
if ! check_eralng_start; then
|
||||||
## it's hopeless
|
## it's hopeless
|
||||||
echoerr "FATAL: Unable to start Erlang (with libcrypto)."
|
echoerr "FATAL: Unable to start Erlang."
|
||||||
echoerr "Please make sure it's running on the correct platform with all required dependencies."
|
echoerr "Please make sure openssl-1.1.1 (libcrypto) and libncurses are installed."
|
||||||
echoerr "This EMQ X release is built for $BUILT_ON"
|
echoerr "Also ensure it's running on the correct platform,"
|
||||||
|
echoerr "this EMQ X release is built for $BUILT_ON"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
echoerr "WARNING: There seem to be missing dynamic libs from the OS. Using libs from ${DYNLIBS_DIR}"
|
echoerr "WARNING: There seem to be missing dynamic libs from the OS. Using libs from ${DYNLIBS_DIR}"
|
||||||
|
|
6
build
6
build
|
@ -96,7 +96,11 @@ cp_dyn_libs() {
|
||||||
mkdir -p "$target_dir"
|
mkdir -p "$target_dir"
|
||||||
while read -r so_file; do
|
while read -r so_file; do
|
||||||
cp -L "$so_file" "$target_dir/"
|
cp -L "$so_file" "$target_dir/"
|
||||||
done < <(find "$rel_dir" -type f \( -name "*.so*" -o -name "beam.smp" \) -print0 | xargs -0 ldd | grep -E '^\s+.*=>\s(/lib|/usr)' | awk '{print $3}')
|
done < <(find "$rel_dir" -type f \( -name "*.so*" -o -name "beam.smp" \) -print0 \
|
||||||
|
| xargs -0 ldd \
|
||||||
|
| grep -E '(libcrypto)|(libtinfo)' \
|
||||||
|
| awk '{print $3}' \
|
||||||
|
| sort -u)
|
||||||
}
|
}
|
||||||
|
|
||||||
## make_zip turns .tar.gz into a .zip with a slightly different name.
|
## make_zip turns .tar.gz into a .zip with a slightly different name.
|
||||||
|
|
|
@ -19,6 +19,12 @@ BuildRoot: %{_tmppath}/%{_name}-%{_version}-root
|
||||||
Provides: %{_name}
|
Provides: %{_name}
|
||||||
AutoReq: 0
|
AutoReq: 0
|
||||||
|
|
||||||
|
%if "%{_arch} %{?rhel}" == "amd64 7"
|
||||||
|
Requires: openssl11 libatomic
|
||||||
|
%else
|
||||||
|
Requires: libatomic
|
||||||
|
%endif
|
||||||
|
|
||||||
%description
|
%description
|
||||||
EMQX, a distributed, massively scalable, highly extensible MQTT message broker written in Erlang/OTP.
|
EMQX, a distributed, massively scalable, highly extensible MQTT message broker written in Erlang/OTP.
|
||||||
|
|
||||||
|
|
|
@ -163,18 +163,6 @@ download_prev_release(Tag, #{binary_rel_url := {ok, URL0}, clone_url := Repo}) -
|
||||||
find_upstream_repo(Remote) ->
|
find_upstream_repo(Remote) ->
|
||||||
string:trim(os:cmd("git remote get-url " ++ Remote)).
|
string:trim(os:cmd("git remote get-url " ++ Remote)).
|
||||||
|
|
||||||
find_prev_tag(CurrentRelease) ->
|
|
||||||
case getopt(prev_tag) of
|
|
||||||
undefined ->
|
|
||||||
{Maj, Min, Patch} = parse_semver(CurrentRelease),
|
|
||||||
case Patch of
|
|
||||||
0 -> undefined;
|
|
||||||
_ -> {ok, semver(Maj, Min, Patch - 1)}
|
|
||||||
end;
|
|
||||||
Tag ->
|
|
||||||
{ok, Tag}
|
|
||||||
end.
|
|
||||||
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
%% Appup action creation and updating
|
%% Appup action creation and updating
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
@ -208,10 +196,21 @@ find_old_appup_actions(App, PrevVersion) ->
|
||||||
{Upgrade0, Downgrade0} =
|
{Upgrade0, Downgrade0} =
|
||||||
case locate(ebin_current, App, ".appup") of
|
case locate(ebin_current, App, ".appup") of
|
||||||
{ok, AppupFile} ->
|
{ok, AppupFile} ->
|
||||||
|
log("Found the previous appup file: ~s~n", [AppupFile]),
|
||||||
{_, U, D} = read_appup(AppupFile),
|
{_, U, D} = read_appup(AppupFile),
|
||||||
{U, D};
|
{U, D};
|
||||||
undefined ->
|
undefined ->
|
||||||
{[], []}
|
%% Fallback to the app.src file, in case the
|
||||||
|
%% application doesn't have a release (useful for the
|
||||||
|
%% apps that live outside the EMQX monorepo):
|
||||||
|
case locate(src, App, ".appup.src") of
|
||||||
|
{ok, AppupSrcFile} ->
|
||||||
|
log("Using ~s as a source of previous update actions~n", [AppupSrcFile]),
|
||||||
|
{_, U, D} = read_appup(AppupSrcFile),
|
||||||
|
{U, D};
|
||||||
|
undefined ->
|
||||||
|
{[], []}
|
||||||
|
end
|
||||||
end,
|
end,
|
||||||
{ensure_version(PrevVersion, Upgrade0), ensure_version(PrevVersion, Downgrade0)}.
|
{ensure_version(PrevVersion, Upgrade0), ensure_version(PrevVersion, Downgrade0)}.
|
||||||
|
|
||||||
|
@ -390,17 +389,6 @@ is_valid() ->
|
||||||
%% Utility functions
|
%% Utility functions
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
parse_semver(Version) ->
|
|
||||||
case re(Version, "^([0-9]+)\\.([0-9]+)\\.([0-9]+)(\\.[0-9]+)?$") of
|
|
||||||
{match, [Maj, Min, Patch|_]} ->
|
|
||||||
{list_to_integer(Maj), list_to_integer(Min), list_to_integer(Patch)};
|
|
||||||
_ ->
|
|
||||||
error({not_a_semver, Version})
|
|
||||||
end.
|
|
||||||
|
|
||||||
semver(Maj, Min, Patch) ->
|
|
||||||
lists:flatten(io_lib:format("~p.~p.~p", [Maj, Min, Patch])).
|
|
||||||
|
|
||||||
%% Locate a file in a specified application
|
%% Locate a file in a specified application
|
||||||
locate(ebin_current, App, Suffix) ->
|
locate(ebin_current, App, Suffix) ->
|
||||||
ReleaseDir = getopt(beams_dir),
|
ReleaseDir = getopt(beams_dir),
|
||||||
|
@ -425,6 +413,7 @@ bash(Script) ->
|
||||||
bash(Script, []).
|
bash(Script, []).
|
||||||
|
|
||||||
bash(Script, Env) ->
|
bash(Script, Env) ->
|
||||||
|
log("+ ~s~n+ Env: ~p~n", [Script, Env]),
|
||||||
case cmd("bash", #{args => ["-c", Script], env => Env}) of
|
case cmd("bash", #{args => ["-c", Script], env => Env}) of
|
||||||
0 -> true;
|
0 -> true;
|
||||||
_ -> fail("Failed to run command: ~s", [Script])
|
_ -> fail("Failed to run command: ~s", [Script])
|
||||||
|
@ -456,9 +445,6 @@ fail(Str, Args) ->
|
||||||
log(Str ++ "~n", Args),
|
log(Str ++ "~n", Args),
|
||||||
halt(1).
|
halt(1).
|
||||||
|
|
||||||
re(Subject, RE) ->
|
|
||||||
re:run(Subject, RE, [{capture, all_but_first, list}]).
|
|
||||||
|
|
||||||
log(Msg) ->
|
log(Msg) ->
|
||||||
log(Msg, []).
|
log(Msg, []).
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{application, emqx,
|
{application, emqx,
|
||||||
[{id, "emqx"},
|
[{id, "emqx"},
|
||||||
{description, "EMQ X"},
|
{description, "EMQ X"},
|
||||||
{vsn, "4.3.11"}, % strict semver, bump manually!
|
{vsn, "4.3.12"}, % strict semver, bump manually!
|
||||||
{modules, []},
|
{modules, []},
|
||||||
{registered, []},
|
{registered, []},
|
||||||
{applications, [kernel,stdlib,gproc,gen_rpc,esockd,cowboy,sasl,os_mon]},
|
{applications, [kernel,stdlib,gproc,gen_rpc,esockd,cowboy,sasl,os_mon]},
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
%% -*- mode: erlang -*-
|
%% -*- mode: erlang -*-
|
||||||
{VSN,
|
{VSN,
|
||||||
[{"4.3.10",
|
[{"4.3.11",
|
||||||
[{load_module,emqx_app,brutal_purge,soft_purge,[]},
|
[{load_module,emqx_http_lib,brutal_purge,soft_purge,[]}]},
|
||||||
|
{"4.3.10",
|
||||||
|
[{load_module,emqx_http_lib,brutal_purge,soft_purge,[]},
|
||||||
|
{load_module,emqx_app,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_connection,brutal_purge,soft_purge,[]}]},
|
{load_module,emqx_connection,brutal_purge,soft_purge,[]}]},
|
||||||
{"4.3.9",
|
{"4.3.9",
|
||||||
[{load_module,emqx_connection,brutal_purge,soft_purge,[]},
|
[{load_module,emqx_http_lib,brutal_purge,soft_purge,[]},
|
||||||
|
{load_module,emqx_connection,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_channel,brutal_purge,soft_purge,[]},
|
{load_module,emqx_channel,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_cm,brutal_purge,soft_purge,[]},
|
{load_module,emqx_cm,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_ws_connection,brutal_purge,soft_purge,[]},
|
{load_module,emqx_ws_connection,brutal_purge,soft_purge,[]},
|
||||||
|
@ -14,7 +18,8 @@
|
||||||
{load_module,emqx_rpc,brutal_purge,soft_purge,[]},
|
{load_module,emqx_rpc,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_app,brutal_purge,soft_purge,[]}]},
|
{load_module,emqx_app,brutal_purge,soft_purge,[]}]},
|
||||||
{"4.3.8",
|
{"4.3.8",
|
||||||
[{load_module,emqx_connection,brutal_purge,soft_purge,[]},
|
[{load_module,emqx_http_lib,brutal_purge,soft_purge,[]},
|
||||||
|
{load_module,emqx_connection,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_channel,brutal_purge,soft_purge,[]},
|
{load_module,emqx_channel,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_cm,brutal_purge,soft_purge,[]},
|
{load_module,emqx_cm,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_ws_connection,brutal_purge,soft_purge,[]},
|
{load_module,emqx_ws_connection,brutal_purge,soft_purge,[]},
|
||||||
|
@ -24,7 +29,8 @@
|
||||||
{load_module,emqx_rpc,brutal_purge,soft_purge,[]},
|
{load_module,emqx_rpc,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_app,brutal_purge,soft_purge,[]}]},
|
{load_module,emqx_app,brutal_purge,soft_purge,[]}]},
|
||||||
{"4.3.7",
|
{"4.3.7",
|
||||||
[{load_module,emqx_connection,brutal_purge,soft_purge,[]},
|
[{load_module,emqx_http_lib,brutal_purge,soft_purge,[]},
|
||||||
|
{load_module,emqx_connection,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_channel,brutal_purge,soft_purge,[]},
|
{load_module,emqx_channel,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_cm,brutal_purge,soft_purge,[]},
|
{load_module,emqx_cm,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_ws_connection,brutal_purge,soft_purge,[]},
|
{load_module,emqx_ws_connection,brutal_purge,soft_purge,[]},
|
||||||
|
@ -36,7 +42,8 @@
|
||||||
{load_module,emqx_rpc,brutal_purge,soft_purge,[]},
|
{load_module,emqx_rpc,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_app,brutal_purge,soft_purge,[]}]},
|
{load_module,emqx_app,brutal_purge,soft_purge,[]}]},
|
||||||
{"4.3.6",
|
{"4.3.6",
|
||||||
[{load_module,emqx_connection,brutal_purge,soft_purge,[]},
|
[{load_module,emqx_http_lib,brutal_purge,soft_purge,[]},
|
||||||
|
{load_module,emqx_connection,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_channel,brutal_purge,soft_purge,[]},
|
{load_module,emqx_channel,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_cm,brutal_purge,soft_purge,[]},
|
{load_module,emqx_cm,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_ws_connection,brutal_purge,soft_purge,[]},
|
{load_module,emqx_ws_connection,brutal_purge,soft_purge,[]},
|
||||||
|
@ -49,7 +56,8 @@
|
||||||
{load_module,emqx_rpc,brutal_purge,soft_purge,[]},
|
{load_module,emqx_rpc,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_app,brutal_purge,soft_purge,[]}]},
|
{load_module,emqx_app,brutal_purge,soft_purge,[]}]},
|
||||||
{"4.3.5",
|
{"4.3.5",
|
||||||
[{load_module,emqx_connection,brutal_purge,soft_purge,[]},
|
[{load_module,emqx_http_lib,brutal_purge,soft_purge,[]},
|
||||||
|
{load_module,emqx_connection,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_channel,brutal_purge,soft_purge,[]},
|
{load_module,emqx_channel,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_ws_connection,brutal_purge,soft_purge,[]},
|
{load_module,emqx_ws_connection,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_alarm_handler,brutal_purge,soft_purge,[]},
|
{load_module,emqx_alarm_handler,brutal_purge,soft_purge,[]},
|
||||||
|
@ -63,7 +71,8 @@
|
||||||
{load_module,emqx_rpc,brutal_purge,soft_purge,[]},
|
{load_module,emqx_rpc,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_app,brutal_purge,soft_purge,[]}]},
|
{load_module,emqx_app,brutal_purge,soft_purge,[]}]},
|
||||||
{"4.3.4",
|
{"4.3.4",
|
||||||
[{load_module,emqx_connection,brutal_purge,soft_purge,[]},
|
[{load_module,emqx_http_lib,brutal_purge,soft_purge,[]},
|
||||||
|
{load_module,emqx_connection,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_channel,brutal_purge,soft_purge,[]},
|
{load_module,emqx_channel,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_ws_connection,brutal_purge,soft_purge,[]},
|
{load_module,emqx_ws_connection,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_alarm_handler,brutal_purge,soft_purge,[]},
|
{load_module,emqx_alarm_handler,brutal_purge,soft_purge,[]},
|
||||||
|
@ -78,7 +87,8 @@
|
||||||
{load_module,emqx_rpc,brutal_purge,soft_purge,[]},
|
{load_module,emqx_rpc,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_app,brutal_purge,soft_purge,[]}]},
|
{load_module,emqx_app,brutal_purge,soft_purge,[]}]},
|
||||||
{"4.3.3",
|
{"4.3.3",
|
||||||
[{load_module,emqx_connection,brutal_purge,soft_purge,[]},
|
[{load_module,emqx_http_lib,brutal_purge,soft_purge,[]},
|
||||||
|
{load_module,emqx_connection,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_channel,brutal_purge,soft_purge,[]},
|
{load_module,emqx_channel,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_alarm_handler,brutal_purge,soft_purge,[]},
|
{load_module,emqx_alarm_handler,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_misc,brutal_purge,soft_purge,[]},
|
{load_module,emqx_misc,brutal_purge,soft_purge,[]},
|
||||||
|
@ -157,11 +167,15 @@
|
||||||
{load_module,emqx_rpc,brutal_purge,soft_purge,[]},
|
{load_module,emqx_rpc,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_app,brutal_purge,soft_purge,[]}]},
|
{load_module,emqx_app,brutal_purge,soft_purge,[]}]},
|
||||||
{<<".*">>,[]}],
|
{<<".*">>,[]}],
|
||||||
[{"4.3.10",
|
[{"4.3.11",
|
||||||
[{load_module,emqx_app,brutal_purge,soft_purge,[]},
|
[{load_module,emqx_http_lib,brutal_purge,soft_purge,[]}]},
|
||||||
|
{"4.3.10",
|
||||||
|
[{load_module,emqx_http_lib,brutal_purge,soft_purge,[]},
|
||||||
|
{load_module,emqx_app,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_connection,brutal_purge,soft_purge,[]}]},
|
{load_module,emqx_connection,brutal_purge,soft_purge,[]}]},
|
||||||
{"4.3.9",
|
{"4.3.9",
|
||||||
[{load_module,emqx_connection,brutal_purge,soft_purge,[]},
|
[{load_module,emqx_http_lib,brutal_purge,soft_purge,[]},
|
||||||
|
{load_module,emqx_connection,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_channel,brutal_purge,soft_purge,[]},
|
{load_module,emqx_channel,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_cm,brutal_purge,soft_purge,[]},
|
{load_module,emqx_cm,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_ws_connection,brutal_purge,soft_purge,[]},
|
{load_module,emqx_ws_connection,brutal_purge,soft_purge,[]},
|
||||||
|
@ -171,7 +185,8 @@
|
||||||
{load_module,emqx_rpc,brutal_purge,soft_purge,[]},
|
{load_module,emqx_rpc,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_app,brutal_purge,soft_purge,[]}]},
|
{load_module,emqx_app,brutal_purge,soft_purge,[]}]},
|
||||||
{"4.3.8",
|
{"4.3.8",
|
||||||
[{load_module,emqx_connection,brutal_purge,soft_purge,[]},
|
[{load_module,emqx_http_lib,brutal_purge,soft_purge,[]},
|
||||||
|
{load_module,emqx_connection,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_channel,brutal_purge,soft_purge,[]},
|
{load_module,emqx_channel,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_cm,brutal_purge,soft_purge,[]},
|
{load_module,emqx_cm,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_ws_connection,brutal_purge,soft_purge,[]},
|
{load_module,emqx_ws_connection,brutal_purge,soft_purge,[]},
|
||||||
|
@ -181,7 +196,8 @@
|
||||||
{load_module,emqx_rpc,brutal_purge,soft_purge,[]},
|
{load_module,emqx_rpc,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_app,brutal_purge,soft_purge,[]}]},
|
{load_module,emqx_app,brutal_purge,soft_purge,[]}]},
|
||||||
{"4.3.7",
|
{"4.3.7",
|
||||||
[{load_module,emqx_connection,brutal_purge,soft_purge,[]},
|
[{load_module,emqx_http_lib,brutal_purge,soft_purge,[]},
|
||||||
|
{load_module,emqx_connection,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_channel,brutal_purge,soft_purge,[]},
|
{load_module,emqx_channel,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_cm,brutal_purge,soft_purge,[]},
|
{load_module,emqx_cm,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_ws_connection,brutal_purge,soft_purge,[]},
|
{load_module,emqx_ws_connection,brutal_purge,soft_purge,[]},
|
||||||
|
@ -193,7 +209,8 @@
|
||||||
{load_module,emqx_rpc,brutal_purge,soft_purge,[]},
|
{load_module,emqx_rpc,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_app,brutal_purge,soft_purge,[]}]},
|
{load_module,emqx_app,brutal_purge,soft_purge,[]}]},
|
||||||
{"4.3.6",
|
{"4.3.6",
|
||||||
[{load_module,emqx_connection,brutal_purge,soft_purge,[]},
|
[{load_module,emqx_http_lib,brutal_purge,soft_purge,[]},
|
||||||
|
{load_module,emqx_connection,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_channel,brutal_purge,soft_purge,[]},
|
{load_module,emqx_channel,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_cm,brutal_purge,soft_purge,[]},
|
{load_module,emqx_cm,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_ws_connection,brutal_purge,soft_purge,[]},
|
{load_module,emqx_ws_connection,brutal_purge,soft_purge,[]},
|
||||||
|
@ -206,7 +223,8 @@
|
||||||
{load_module,emqx_rpc,brutal_purge,soft_purge,[]},
|
{load_module,emqx_rpc,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_app,brutal_purge,soft_purge,[]}]},
|
{load_module,emqx_app,brutal_purge,soft_purge,[]}]},
|
||||||
{"4.3.5",
|
{"4.3.5",
|
||||||
[{load_module,emqx_connection,brutal_purge,soft_purge,[]},
|
[{load_module,emqx_http_lib,brutal_purge,soft_purge,[]},
|
||||||
|
{load_module,emqx_connection,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_channel,brutal_purge,soft_purge,[]},
|
{load_module,emqx_channel,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_ws_connection,brutal_purge,soft_purge,[]},
|
{load_module,emqx_ws_connection,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_pqueue,brutal_purge,soft_purge,[]},
|
{load_module,emqx_pqueue,brutal_purge,soft_purge,[]},
|
||||||
|
@ -220,7 +238,8 @@
|
||||||
{load_module,emqx_rpc,brutal_purge,soft_purge,[]},
|
{load_module,emqx_rpc,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_app,brutal_purge,soft_purge,[]}]},
|
{load_module,emqx_app,brutal_purge,soft_purge,[]}]},
|
||||||
{"4.3.4",
|
{"4.3.4",
|
||||||
[{load_module,emqx_connection,brutal_purge,soft_purge,[]},
|
[{load_module,emqx_http_lib,brutal_purge,soft_purge,[]},
|
||||||
|
{load_module,emqx_connection,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_channel,brutal_purge,soft_purge,[]},
|
{load_module,emqx_channel,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_ws_connection,brutal_purge,soft_purge,[]},
|
{load_module,emqx_ws_connection,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_pqueue,brutal_purge,soft_purge,[]},
|
{load_module,emqx_pqueue,brutal_purge,soft_purge,[]},
|
||||||
|
@ -235,7 +254,8 @@
|
||||||
{load_module,emqx_rpc,brutal_purge,soft_purge,[]},
|
{load_module,emqx_rpc,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_app,brutal_purge,soft_purge,[]}]},
|
{load_module,emqx_app,brutal_purge,soft_purge,[]}]},
|
||||||
{"4.3.3",
|
{"4.3.3",
|
||||||
[{load_module,emqx_connection,brutal_purge,soft_purge,[]},
|
[{load_module,emqx_http_lib,brutal_purge,soft_purge,[]},
|
||||||
|
{load_module,emqx_connection,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_channel,brutal_purge,soft_purge,[]},
|
{load_module,emqx_channel,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_pqueue,brutal_purge,soft_purge,[]},
|
{load_module,emqx_pqueue,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_mqueue,brutal_purge,soft_purge,[]},
|
{load_module,emqx_mqueue,brutal_purge,soft_purge,[]},
|
||||||
|
|
|
@ -96,11 +96,11 @@ do_parse(URI) ->
|
||||||
%% underscores replaced with hyphens
|
%% underscores replaced with hyphens
|
||||||
%% NOTE: assuming the input Headers list is a proplists,
|
%% NOTE: assuming the input Headers list is a proplists,
|
||||||
%% that is, when a key is duplicated, list header overrides tail
|
%% that is, when a key is duplicated, list header overrides tail
|
||||||
%% e.g. [{"Content_Type", "applicaiton/binary"}, {"content-type", "applicaiton/json"}]
|
%% e.g. [{"Content_Type", "applicaiton/binary"}, {<<"content-type">>, "applicaiton/json"}]
|
||||||
%% results in: [{"content-type", "applicaiton/binary"}]
|
%% results in: [{"content-type", "applicaiton/binary"}]
|
||||||
normalise_headers(Headers0) ->
|
normalise_headers(Headers0) ->
|
||||||
F = fun({K0, V}) ->
|
F = fun({K0, V}) ->
|
||||||
K = re:replace(K0, "_", "-", [{return,list}]),
|
K = re:replace(K0, "_", "-", [{return,binary}]),
|
||||||
{string:lowercase(K), V}
|
{string:lowercase(K), V}
|
||||||
end,
|
end,
|
||||||
Headers = lists:map(F, Headers0),
|
Headers = lists:map(F, Headers0),
|
||||||
|
|
|
@ -113,10 +113,8 @@ install(Who, Level, LogFile) ->
|
||||||
-spec uninstall(Type :: clientid | topic | ip_address,
|
-spec uninstall(Type :: clientid | topic | ip_address,
|
||||||
Name :: binary() | list()) -> ok | {error, term()}.
|
Name :: binary() | list()) -> ok | {error, term()}.
|
||||||
uninstall(Type, Name) ->
|
uninstall(Type, Name) ->
|
||||||
case handler_id(ensure_bin(Name), Type) of
|
HandlerId = handler_id(ensure_bin(Name), Type),
|
||||||
{ok, HandlerId} -> uninstall(HandlerId);
|
uninstall(HandlerId).
|
||||||
{error, Reason} -> {error, Reason}
|
|
||||||
end.
|
|
||||||
|
|
||||||
-spec uninstall(HandlerId :: atom()) -> ok | {error, term()}.
|
-spec uninstall(HandlerId :: atom()) -> ok | {error, term()}.
|
||||||
uninstall(HandlerId) ->
|
uninstall(HandlerId) ->
|
||||||
|
|
|
@ -89,6 +89,6 @@ uri_parse_test_() ->
|
||||||
].
|
].
|
||||||
|
|
||||||
normalise_headers_test() ->
|
normalise_headers_test() ->
|
||||||
?assertEqual([{"content-type", "applicaiton/binary"}],
|
?assertEqual([{<<"content-type">>, "applicaiton/binary"}],
|
||||||
emqx_http_lib:normalise_headers([{"Content_Type", "applicaiton/binary"},
|
emqx_http_lib:normalise_headers([{"Content_Type", "applicaiton/binary"},
|
||||||
{"content-type", "applicaiton/json"}])).
|
{"content-type", "applicaiton/json"}])).
|
||||||
|
|
Loading…
Reference in New Issue