Merge pull request #8308 from zmstone/0623-fix-relup

5.0: fix relup
This commit is contained in:
Zaiming (Stone) Shi 2022-06-29 13:41:24 +01:00 committed by GitHub
commit 79be7f9420
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 550 additions and 350 deletions

View File

@ -3,7 +3,7 @@ version: '3.9'
services: services:
erlang24: erlang24:
container_name: erlang24 container_name: erlang24
image: ghcr.io/emqx/emqx-builder/5.0-16:1.13.4-24.2.1-1-ubuntu20.04 image: ghcr.io/emqx/emqx-builder/5.0-17:1.13.4-24.2.1-1-ubuntu20.04
env_file: env_file:
- conf.env - conf.env
environment: environment:

View File

@ -1,43 +1,49 @@
-module(http_server). -module(http_server).
-import(minirest, [ return/0 -import(minirest, [
, return/1 return/0,
return/1
]). ]).
-export([ start/0 -export([
, stop/0 start/0,
stop/0
]). ]).
-rest_api(#{ name => get_counter -rest_api(#{
, method => 'GET' name => get_counter,
, path => "/counter" method => 'GET',
, func => get_counter path => "/counter",
, descr => "Check counter" func => get_counter,
descr => "Check counter"
}). }).
-rest_api(#{ name => add_counter -rest_api(#{
, method => 'POST' name => add_counter,
, path => "/counter" method => 'POST',
, func => add_counter path => "/counter",
, descr => "Counter plus one" func => add_counter,
descr => "Counter plus one"
}). }).
-export([ get_counter/2 -export([
, add_counter/2 get_counter/2,
add_counter/2
]). ]).
start() -> start() ->
application:ensure_all_started(minirest), application:ensure_all_started(minirest),
ets:new(relup_test_message, [named_table, public]), _ = spawn(fun ets_owner/0),
Handlers = [{"/", minirest:handler(#{modules => [?MODULE]})}], Handlers = [{"/", minirest:handler(#{modules => [?MODULE]})}],
Dispatch = [{"/[...]", minirest, Handlers}], Dispatch = [{"/[...]", minirest, Handlers}],
minirest:start_http(?MODULE, #{socket_opts => [inet, {port, 8080}]}, Dispatch). minirest:start_http(?MODULE, #{socket_opts => [inet, {port, 7077}]}, Dispatch).
stop() -> stop() ->
ets:delete(relup_test_message), ets:delete(relup_test_message),
minirest:stop_http(?MODULE). minirest:stop_http(?MODULE).
get_counter(_Binding, _Params) -> get_counter(_Binding, _Params) ->
return({ok, ets:info(relup_test_message, size)}). V = ets:info(relup_test_message, size),
return({ok, V}).
add_counter(_Binding, Params) -> add_counter(_Binding, Params) ->
case lists:keymember(<<"payload">>, 1, Params) of case lists:keymember(<<"payload">>, 1, Params) of
@ -45,6 +51,13 @@ add_counter(_Binding, Params) ->
{value, {<<"id">>, ID}, Params1} = lists:keytake(<<"id">>, 1, Params), {value, {<<"id">>, ID}, Params1} = lists:keytake(<<"id">>, 1, Params),
ets:insert(relup_test_message, {ID, Params1}); ets:insert(relup_test_message, {ID, Params1});
_ -> _ ->
io:format("discarded: ~p\n", [Params]),
ok ok
end, end,
return(). return().
ets_owner() ->
ets:new(relup_test_message, [named_table, public]),
receive
stop -> ok
end.

View File

@ -1,225 +0,0 @@
[config var=PROFILE]
[config var=PACKAGE_PATH]
[config var=BENCH_PATH]
[config var=ONE_MORE_EMQX_PATH]
[config var=VSN]
[config var=OLD_VSNS]
[config shell_cmd=/bin/bash]
[config timeout=600000]
[loop old_vsn $OLD_VSNS]
[shell http_server]
!cd http_server
!rebar3 shell
???Eshell
???>
!http_server:start().
?Start http_server listener on 8080 successfully.
?ok
?>
[shell emqx]
!cd $PACKAGE_PATH
mkdir -p emqx
!tar -C emqx -zxf ${PROFILE}-$(echo $old_vsn | sed -r 's/[v|e]//g')-*-ubuntu20.04-amd64.tar.gz
?SH-PROMPT
!cd emqx
!sed -i 's|listener.wss.external[ \t]*=.*|listener.wss.external = 8085|g' etc/emqx.conf
!sed -i '/emqx_telemetry/d' data/loaded_plugins
!./bin/emqx start
?EMQ X .* is started successfully!
?SH-PROMPT
[shell emqx2]
!cd $PACKAGE_PATH
!cp -f $ONE_MORE_EMQX_PATH/one_more_$(echo $PROFILE | sed 's/-/_/g').sh .
!./one_more_$(echo $PROFILE | sed 's/-/_/g').sh emqx2
?SH-PROMPT
!cd emqx2
!sed -i '/emqx_telemetry/d' data/loaded_plugins
!./bin/emqx start
?EMQ X .* is started successfully!
?SH-PROMPT
!./bin/emqx_ctl cluster join emqx@127.0.0.1
???Join the cluster successfully.
?SH-PROMPT
!./bin/emqx_ctl cluster status
"""???
Cluster status: #{running_nodes => ['emqx2@127.0.0.1','emqx@127.0.0.1'],
stopped_nodes => []}
"""
?SH-PROMPT
!./bin/emqx_ctl resources create 'web_hook' -i 'resource:691c29ba' -c '{"url": "http://127.0.0.1:8080/counter", "method": "POST"}'
?created
?SH-PROMPT
!./bin/emqx_ctl rules create 'SELECT * FROM "t/#"' '[{"name":"data_to_webserver", "params": {"$$resource": "resource:691c29ba"}}]'
?created
?SH-PROMPT
[shell emqx]
!./bin/emqx_ctl resources list
?691c29ba
?SH-PROMPT
!./bin/emqx_ctl rules list
?691c29ba
?SH-PROMPT
[shell bench]
!cd $BENCH_PATH
!./emqtt_bench pub -c 10 -I 1000 -t t/%i -s 64 -L 300
???sent
[shell emqx]
!echo "" > log/emqx.log.1
?SH-PROMPT
!cp -f ../$PROFILE-$VSN-*-ubuntu20.04-amd64.tar.gz releases/
## 1. upgrade to the new version
!./bin/emqx install $VSN
?Made release permanent: "$VSN"
?SH-PROMPT
!./bin/emqx versions |grep permanent
?(.*)$VSN
?SH-PROMPT
## 2. downgrade to the old version
!./bin/emqx install $old_vsn
?Made release permanent:.*
?SH-PROMPT
!./bin/emqx versions |grep permanent | grep -qs "$old_vsn"
?SH-PROMPT:
!echo ==$$?==
?^==0==
?SH-PROMPT:
## 3. again, upgrade to the new version
!./bin/emqx install $VSN
?Made release permanent: "$VSN"
?SH-PROMPT
!./bin/emqx versions |grep permanent
?(.*)$VSN
?SH-PROMPT
!./bin/emqx_ctl cluster status
"""???
Cluster status: #{running_nodes => ['emqx2@127.0.0.1','emqx@127.0.0.1'],
stopped_nodes => []}
"""
?SH-PROMPT
!./bin/emqx_ctl plugins list | grep emqx_management
?Plugin\(emqx_management.*active=true\)
?SH-PROMPT
[shell emqx2]
!echo "" > log/emqx.log.1
?SH-PROMPT
!cp -f ../$PROFILE-$VSN-*-ubuntu20.04-amd64.tar.gz releases/
## 1. upgrade to the new version
!./bin/emqx install $VSN
?Made release permanent: "$VSN"
?SH-PROMPT
!./bin/emqx versions |grep permanent
?(.*)$VSN
?SH-PROMPT
## 2. downgrade to the old version
!./bin/emqx install $old_vsn
?Made release permanent:.*
?SH-PROMPT
!./bin/emqx versions |grep permanent | grep -qs "$old_vsn"
?SH-PROMPT:
!echo ==$$?==
?^==0==
?SH-PROMPT:
## 3. again, upgrade to the new version
!./bin/emqx install $VSN
?Made release permanent: "$VSN"
?SH-PROMPT
!./bin/emqx versions |grep permanent
?(.*)$VSN
?SH-PROMPT
!./bin/emqx_ctl cluster status
"""???
Cluster status: #{running_nodes => ['emqx2@127.0.0.1','emqx@127.0.0.1'],
stopped_nodes => []}
"""
?SH-PROMPT
!./bin/emqx_ctl plugins list | grep emqx_management
?Plugin\(emqx_management.*active=true\)
?SH-PROMPT
## We don't guarantee not to lose a single message!
## So even if we received 290~300 messages, we consider it as success
[shell bench]
???publish complete
??SH-PROMPT:
!sleep 5
?SH-PROMPT
!curl --user admin:public --silent --show-error http://localhost:18083/api/v5/rules | jq --raw-output ".[0].node_metrics[] | select(.node==\"emqx@127.0.0.1\") | .metrics.matched"
?300
?SH-PROMPT
!curl --user admin:public --silent --show-error http://localhost:18083/api/v5/rules | jq --raw-output ".[0].node_metrics[] | select(.node==\"emqx@127.0.0.1\") | .metrics.\"actions.success\""
?\{"data":(29[0-9])|(300),"code":0\}
?SH-PROMPT
[shell emqx2]
!cat log/emqx.log.1 |grep -v 691c29ba |tail -n 100
-error
??SH-PROMPT:
!./bin/emqx stop
?ok
?SH-PROMPT:
!rm -rf $PACKAGE_PATH/emqx2
?SH-PROMPT:
[shell emqx]
!cat log/emqx.log.1 |grep -v 691c29ba |tail -n 100
-error
??SH-PROMPT:
!./bin/emqx stop
?ok
?SH-PROMPT:
!rm -rf $PACKAGE_PATH/emqx
?SH-PROMPT:
[shell http_server]
!http_server:stop().
?ok
?>
!halt(3).
?SH-PROMPT:
[endloop]
[cleanup]
!echo ==$$?==
?==0==

View File

@ -20,7 +20,7 @@ jobs:
prepare: prepare:
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
# prepare source with any OTP version, no need for a matrix # prepare source with any OTP version, no need for a matrix
container: "ghcr.io/emqx/emqx-builder/5.0-16:1.13.4-24.2.1-1-ubuntu20.04" container: "ghcr.io/emqx/emqx-builder/5.0-17:1.13.4-24.2.1-1-ubuntu20.04"
outputs: outputs:
BUILD_PROFILE: ${{ steps.get_profile.outputs.BUILD_PROFILE }} BUILD_PROFILE: ${{ steps.get_profile.outputs.BUILD_PROFILE }}
@ -211,7 +211,7 @@ jobs:
tags: ${{ steps.meta.outputs.tags }} tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }} labels: ${{ steps.meta.outputs.labels }}
build-args: | build-args: |
BUILD_FROM=ghcr.io/emqx/emqx-builder/5.0-16:${{ matrix.elixir }}-${{ matrix.otp }}-${{ matrix.os[0] }} BUILD_FROM=ghcr.io/emqx/emqx-builder/5.0-17:${{ matrix.elixir }}-${{ matrix.otp }}-${{ matrix.os[0] }}
RUN_FROM=${{ matrix.os[1] }} RUN_FROM=${{ matrix.os[1] }}
EMQX_NAME=${{ steps.pre-meta.outputs.emqx_name }} EMQX_NAME=${{ steps.pre-meta.outputs.emqx_name }}
file: source/${{ matrix.os[2] }} file: source/${{ matrix.os[2] }}

View File

@ -213,7 +213,7 @@ jobs:
needs: prepare needs: prepare
runs-on: ${{ matrix.build_machine }} runs-on: ${{ matrix.build_machine }}
container: container:
image: "ghcr.io/emqx/emqx-builder/5.0-16:${{ matrix.elixir }}-${{ matrix.otp }}-${{ matrix.os }}" image: "ghcr.io/emqx/emqx-builder/5.0-17:${{ matrix.elixir }}-${{ matrix.otp }}-${{ matrix.os }}"
strategy: strategy:
fail-fast: false fail-fast: false
@ -328,7 +328,7 @@ jobs:
--pkgtype "${PKGTYPE}" \ --pkgtype "${PKGTYPE}" \
--arch "${ARCH}" \ --arch "${ARCH}" \
--elixir "${IsElixir}" \ --elixir "${IsElixir}" \
--builder "ghcr.io/emqx/emqx-builder/5.0-16:${ELIXIR}-${OTP}-${SYSTEM}" --builder "ghcr.io/emqx/emqx-builder/5.0-17:${ELIXIR}-${OTP}-${SYSTEM}"
done done
- uses: actions/upload-artifact@v1 - uses: actions/upload-artifact@v1
with: with:

View File

@ -39,7 +39,7 @@ jobs:
- ubuntu20.04 - ubuntu20.04
- el8 - el8
container: "ghcr.io/emqx/emqx-builder/5.0-16:${{ matrix.elixir }}-${{ matrix.otp }}-${{ matrix.os }}" container: "ghcr.io/emqx/emqx-builder/5.0-17:${{ matrix.elixir }}-${{ matrix.otp }}-${{ matrix.os }}"
steps: steps:
- uses: AutoModality/action-clean@v1 - uses: AutoModality/action-clean@v1

View File

@ -5,7 +5,7 @@ on: [pull_request, push]
jobs: jobs:
check_deps_integrity: check_deps_integrity:
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
container: ghcr.io/emqx/emqx-builder/5.0-16:1.13.4-24.2.1-1-ubuntu20.04 container: ghcr.io/emqx/emqx-builder/5.0-17:1.13.4-24.2.1-1-ubuntu20.04
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2

View File

@ -5,7 +5,7 @@ on: [pull_request]
jobs: jobs:
code_style_check: code_style_check:
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
container: "ghcr.io/emqx/emqx-builder/5.0-16:1.13.4-24.2.1-1-ubuntu20.04" container: "ghcr.io/emqx/emqx-builder/5.0-17:1.13.4-24.2.1-1-ubuntu20.04"
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
with: with:

View File

@ -8,7 +8,7 @@ jobs:
elixir_apps_check: elixir_apps_check:
runs-on: ubuntu-latest runs-on: ubuntu-latest
# just use the latest builder # just use the latest builder
container: "ghcr.io/emqx/emqx-builder/5.0-16:1.13.4-24.2.1-1-ubuntu20.04" container: "ghcr.io/emqx/emqx-builder/5.0-17:1.13.4-24.2.1-1-ubuntu20.04"
strategy: strategy:
fail-fast: false fail-fast: false

View File

@ -7,7 +7,7 @@ on: [pull_request, push]
jobs: jobs:
elixir_deps_check: elixir_deps_check:
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
container: ghcr.io/emqx/emqx-builder/5.0-16:1.13.4-24.2.1-1-ubuntu20.04 container: ghcr.io/emqx/emqx-builder/5.0-17:1.13.4-24.2.1-1-ubuntu20.04
steps: steps:
- name: Checkout - name: Checkout

View File

@ -12,7 +12,7 @@ on:
jobs: jobs:
elixir_release_build: elixir_release_build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: ghcr.io/emqx/emqx-builder/5.0-16:1.13.4-24.2.1-1-ubuntu20.04 container: ghcr.io/emqx/emqx-builder/5.0-17:1.13.4-24.2.1-1-ubuntu20.04
steps: steps:
- name: Checkout - name: Checkout

View File

@ -24,7 +24,7 @@ jobs:
- amd64 - amd64
runs-on: aws-amd64 runs-on: aws-amd64
container: "ghcr.io/emqx/emqx-builder/5.0-16:${{ matrix.elixir}}-${{ matrix.otp }}-${{ matrix.os }}" container: "ghcr.io/emqx/emqx-builder/5.0-17:${{ matrix.elixir}}-${{ matrix.otp }}-${{ matrix.os }}"
defaults: defaults:
run: run:

View File

@ -16,7 +16,7 @@ jobs:
prepare: prepare:
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
# prepare source with any OTP version, no need for a matrix # prepare source with any OTP version, no need for a matrix
container: ghcr.io/emqx/emqx-builder/5.0-16:1.13.4-24.2.1-1-alpine3.15.1 container: ghcr.io/emqx/emqx-builder/5.0-17:1.13.4-24.2.1-1-alpine3.15.1
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
@ -68,7 +68,7 @@ jobs:
- name: make docker image - name: make docker image
working-directory: source working-directory: source
env: env:
EMQX_BUILDER: ghcr.io/emqx/emqx-builder/5.0-16:${{ matrix.elixir }}-${{ matrix.otp }}-${{ matrix.os[0] }} EMQX_BUILDER: ghcr.io/emqx/emqx-builder/5.0-17:${{ matrix.elixir }}-${{ matrix.otp }}-${{ matrix.os[0] }}
EMQX_RUNNER: ${{ matrix.os[1] }} EMQX_RUNNER: ${{ matrix.os[1] }}
run: | run: |
make ${{ matrix.profile }}-docker make ${{ matrix.profile }}-docker
@ -140,7 +140,7 @@ jobs:
- name: make docker image - name: make docker image
working-directory: source working-directory: source
env: env:
EMQX_BUILDER: ghcr.io/emqx/emqx-builder/5.0-16:${{ matrix.elixir }}-${{ matrix.otp }}-${{ matrix.os[0] }} EMQX_BUILDER: ghcr.io/emqx/emqx-builder/5.0-17:${{ matrix.elixir }}-${{ matrix.otp }}-${{ matrix.os[0] }}
EMQX_RUNNER: ${{ matrix.os[1] }} EMQX_RUNNER: ${{ matrix.os[1] }}
run: | run: |
make ${{ matrix.profile }}-docker make ${{ matrix.profile }}-docker

View File

@ -14,101 +14,117 @@ on:
pull_request: pull_request:
jobs: jobs:
relup_test: relup_test_plan:
strategy:
matrix:
profile:
- emqx
- emqx-enterprise
otp:
- 24.2.1-1
# no need to use more than 1 version of Elixir, since tests
# run using only Erlang code. This is needed just to specify
# the base image.
elixir:
- 1.13.4
os:
- ubuntu20.04
arch:
- amd64
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
container: "ghcr.io/emqx/emqx-builder/5.0-16:${{ matrix.elixir }}-${{ matrix.otp }}-${{ matrix.os }}" container: "ghcr.io/emqx/emqx-builder/5.0-17:1.13.4-24.2.1-1-ubuntu20.04"
outputs:
CUR_CE_VSN: ${{ steps.find-versions.outputs.CUR_CE_VSN }}
CUR_EE_VSN: ${{ steps.find-versions.outputs.CUR_EE_VSN }}
OLD_VERSIONS: ${{ steps.find-versions.outputs.OLD_VERSIONS }}
defaults: defaults:
run: run:
shell: bash shell: bash
steps: steps:
- uses: actions/setup-python@v2
with:
python-version: '3.8'
architecture: 'x64'
- uses: actions/checkout@v2 - uses: actions/checkout@v2
name: Checkout
with: with:
repository: emqx/paho.mqtt.testing path: emqx
ref: develop-4.0 fetch-depth: 0
path: paho.mqtt.testing - name: Find versions
- uses: actions/checkout@v2 id: find-versions
run: |
set -x
cd emqx
ce_vsn="$(./pkg-vsn.sh opensource)"
ee_vsn="$(./pkg-vsn.sh enterprise)"
old_ce_vsns="$(./scripts/relup-base-vsns.sh opensource | xargs)"
old_ee_vsns="$(./scripts/relup-base-vsns.sh enterprise | xargs)"
old_vsns=$(echo -n "${old_ce_vsns} ${old_ee_vsns}" | sed 's/ $//g' | jq -R -s -c 'split(" ")')
echo "::set-output name=CUR_CE_VSN::$ce_vsn"
echo "::set-output name=CUR_EE_VSN::$ee_vsn"
echo "::set-output name=OLD_VERSIONS::$old_vsns"
- name: build emqx
run: |
set -x
cd emqx
make emqx-tgz
make emqx-enterprise-tgz
- uses: actions/upload-artifact@v2
name: Upload built emqx and test scenario
with: with:
repository: terry-xiaoyu/one_more_emqx name: emqx_built
ref: master path: |
path: one_more_emqx emqx/_upgrade_base
- uses: actions/checkout@v2 emqx/_packages
emqx/scripts
emqx/.ci
relup_test_run:
needs:
- relup_test_plan
runs-on: ubuntu-20.04
strategy:
fail-fast: false
matrix:
old_vsn: ${{ fromJson(needs.relup_test_plan.outputs.OLD_VERSIONS) }}
env:
OLD_VSN: "${{ matrix.old_vsn }}"
CUR_CE_VSN: "${{ needs.relup_test_plan.outputs.CUR_CE_VSN }}"
CUR_EE_VSN: "${{ needs.relup_test_plan.outputs.CUR_EE_VSN }}"
defaults:
run:
shell: bash
steps:
# setup Erlang to run lux
- uses: erlef/setup-beam@v1
with: with:
repository: emqx/emqtt-bench otp-version: "24.2"
ref: 0.3.4
path: emqtt-bench
- uses: actions/checkout@v2 - uses: actions/checkout@v2
with: with:
repository: hawk/lux repository: hawk/lux
ref: lux-2.6 ref: lux-2.8.1
path: lux path: lux
- uses: actions/checkout@v2 - name: Install lux
with:
repository: ${{ github.repository }}
path: emqx
fetch-depth: 0
- name: Get old vsn
run: echo "OLD_VSNS=$(emqx/scripts/relup-base-vsns.sh ${{ matrix.profile }} | xargs echo -n)" >> $GITHUB_ENV
run: echo "VSN=$(emqx/pkg-vsn.sh ${{ matrix.profile }})" >> $GITHUB_ENV
- name: build emqx
env:
PROFILE: ${{ matrix.profile }}
run: make -C emqx ${PROFILE}-tgz
- name: build emqtt-bench
run: make -C emqtt-bench
- name: build lux
run: | run: |
set -e -u -x set -e -u -x
cd lux cd lux
autoconf autoconf
./configure ./configure
make make
make install echo "$(pwd)/bin" >> $GITHUB_PATH
- uses: actions/download-artifact@v2
name: Download built emqx and test scenario
with:
name: emqx_built
path: .
- name: run relup test - name: run relup test
env:
PROFILE: ${{ matrix.profile }}
timeout-minutes: 20
run: | run: |
set -e -x -u set -e -x -u
if [ -n "$OLD_VSNS" ]; then chmod a+x scripts/**/*.sh
mkdir -p packages ls -l scripts
cp emqx/_packages/${PROFILE}/*.tar.gz packages ls -l scripts/relup-test
cp emqx/_upgrade_base/*.tar.gz packages case "$OLD_VSN" in
lux \ e*)
--case_timeout infinity \ export CUR_VSN="$CUR_EE_VSN"
--var PROFILE=$PROFILE \ ;;
--var PACKAGE_PATH=$(pwd)/packages \ v*)
--var BENCH_PATH=$(pwd)/emqtt-bench \ export CUR_VSN="$CUR_CE_VSN"
--var ONE_MORE_EMQX_PATH=$(pwd)/one_more_emqx \ ;;
--var VSN="$VSN" \ *)
--var OLD_VSNS="$OLD_VSNS" \ echo "unknown old version $OLD_VSN"
emqx/.ci/fvt_tests/relup.lux exit 1
;;
esac
mkdir -p lux_logs
if ! ./scripts/relup-test/run-relup-lux.sh $OLD_VSN; then
docker logs node1.emqx.io | tee lux_logs/emqx1.log
docker logs node2.emqx.io | tee lux_logs/emqx2.log
exit 1
fi fi
- uses: actions/upload-artifact@v1 - uses: actions/upload-artifact@v2
name: Save debug data
if: failure() if: failure()
with: with:
name: lux_logs name: debug_data
path: lux_logs path: |
lux_logs

View File

@ -17,7 +17,7 @@ jobs:
prepare: prepare:
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
# prepare source with any OTP version, no need for a matrix # prepare source with any OTP version, no need for a matrix
container: "ghcr.io/emqx/emqx-builder/5.0-16:1.13.4-24.2.1-1-ubuntu20.04" container: "ghcr.io/emqx/emqx-builder/5.0-17:1.13.4-24.2.1-1-ubuntu20.04"
outputs: outputs:
fast_ct_apps: ${{ steps.run_find_apps.outputs.fast_ct_apps }} fast_ct_apps: ${{ steps.run_find_apps.outputs.fast_ct_apps }}
docker_ct_apps: ${{ steps.run_find_apps.outputs.docker_ct_apps }} docker_ct_apps: ${{ steps.run_find_apps.outputs.docker_ct_apps }}
@ -54,7 +54,7 @@ jobs:
defaults: defaults:
run: run:
shell: bash shell: bash
container: "ghcr.io/emqx/emqx-builder/5.0-16:1.13.4-24.2.1-1-ubuntu20.04" container: "ghcr.io/emqx/emqx-builder/5.0-17:1.13.4-24.2.1-1-ubuntu20.04"
steps: steps:
- uses: AutoModality/action-clean@v1 - uses: AutoModality/action-clean@v1
@ -144,7 +144,7 @@ jobs:
matrix: matrix:
app_name: ${{ fromJson(needs.prepare.outputs.fast_ct_apps) }} app_name: ${{ fromJson(needs.prepare.outputs.fast_ct_apps) }}
runs-on: aws-amd64 runs-on: aws-amd64
container: "ghcr.io/emqx/emqx-builder/5.0-16:1.13.4-24.2.1-1-ubuntu20.04" container: "ghcr.io/emqx/emqx-builder/5.0-17:1.13.4-24.2.1-1-ubuntu20.04"
defaults: defaults:
run: run:
shell: bash shell: bash
@ -179,7 +179,7 @@ jobs:
- ct - ct
- ct_docker - ct_docker
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
container: "ghcr.io/emqx/emqx-builder/5.0-16:1.13.4-24.2.1-1-ubuntu20.04" container: "ghcr.io/emqx/emqx-builder/5.0-17:1.13.4-24.2.1-1-ubuntu20.04"
steps: steps:
- uses: AutoModality/action-clean@v1 - uses: AutoModality/action-clean@v1
- uses: actions/download-artifact@v2 - uses: actions/download-artifact@v2

1
.gitignore vendored
View File

@ -66,3 +66,4 @@ mix.lock
apps/emqx/test/emqx_static_checks_data/master.bpapi apps/emqx/test/emqx_static_checks_data/master.bpapi
# rendered configurations # rendered configurations
*.conf.rendered *.conf.rendered
lux_logs/

View File

@ -3,7 +3,7 @@ REBAR = $(CURDIR)/rebar3
BUILD = $(CURDIR)/build BUILD = $(CURDIR)/build
SCRIPTS = $(CURDIR)/scripts SCRIPTS = $(CURDIR)/scripts
export EMQX_RELUP ?= true export EMQX_RELUP ?= true
export EMQX_DEFAULT_BUILDER = ghcr.io/emqx/emqx-builder/5.0-16:1.13.4-24.2.1-1-debian11 export EMQX_DEFAULT_BUILDER = ghcr.io/emqx/emqx-builder/5.0-17:1.13.4-24.2.1-1-debian11
export EMQX_DEFAULT_RUNNER = debian:11-slim export EMQX_DEFAULT_RUNNER = debian:11-slim
export OTP_VSN ?= $(shell $(CURDIR)/scripts/get-otp-vsn.sh) export OTP_VSN ?= $(shell $(CURDIR)/scripts/get-otp-vsn.sh)
export ELIXIR_VSN ?= $(shell $(CURDIR)/scripts/get-elixir-vsn.sh) export ELIXIR_VSN ?= $(shell $(CURDIR)/scripts/get-elixir-vsn.sh)

View File

@ -135,14 +135,35 @@ cluster(["force-leave", SNode]) ->
end; end;
cluster(["status"]) -> cluster(["status"]) ->
emqx_ctl:print("Cluster status: ~p~n", [ekka_cluster:info()]); emqx_ctl:print("Cluster status: ~p~n", [ekka_cluster:info()]);
cluster(["status", "--json"]) ->
Info = sort_map_list_fields(ekka_cluster:info()),
emqx_ctl:print("~ts~n", [emqx_logger_jsonfmt:best_effort_json(Info)]);
cluster(_) -> cluster(_) ->
emqx_ctl:usage([ emqx_ctl:usage([
{"cluster join <Node>", "Join the cluster"}, {"cluster join <Node>", "Join the cluster"},
{"cluster leave", "Leave the cluster"}, {"cluster leave", "Leave the cluster"},
{"cluster force-leave <Node>", "Force the node leave from cluster"}, {"cluster force-leave <Node>", "Force the node leave from cluster"},
{"cluster status", "Cluster status"} {"cluster status [--json]", "Cluster status"}
]). ]).
%% sort lists for deterministic output
sort_map_list_fields(Map) when is_map(Map) ->
lists:foldl(
fun(Field, Acc) ->
sort_map_list_field(Field, Acc)
end,
Map,
maps:keys(Map)
);
sort_map_list_fields(NotMap) ->
NotMap.
sort_map_list_field(Field, Map) ->
case maps:get(Field, Map) of
[_ | _] = L -> Map#{Field := lists:sort(L)};
_ -> Map
end.
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
%% @doc Query clients %% @doc Query clients

View File

@ -1,4 +1,4 @@
ARG BUILD_FROM=ghcr.io/emqx/emqx-builder/5.0-16:1.13.4-24.2.1-1-debian11 ARG BUILD_FROM=ghcr.io/emqx/emqx-builder/5.0-17:1.13.4-24.2.1-1-debian11
ARG RUN_FROM=debian:11-slim ARG RUN_FROM=debian:11-slim
FROM ${BUILD_FROM} AS builder FROM ${BUILD_FROM} AS builder

View File

@ -9,7 +9,7 @@
## example: ## example:
## ./scripts/buildx.sh --profile emqx --pkgtype tgz --arch arm64 \ ## ./scripts/buildx.sh --profile emqx --pkgtype tgz --arch arm64 \
## --builder ghcr.io/emqx/emqx-builder/5.0-16:1.13.4-24.2.1-1-debian10 ## --builder ghcr.io/emqx/emqx-builder/5.0-17:1.13.4-24.2.1-1-debian10
set -euo pipefail set -euo pipefail
@ -24,7 +24,7 @@ help() {
echo "--arch amd64|arm64: Target arch to build the EMQX package for" echo "--arch amd64|arm64: Target arch to build the EMQX package for"
echo "--src_dir <SRC_DIR>: EMQX source ode in this dir, default to PWD" echo "--src_dir <SRC_DIR>: EMQX source ode in this dir, default to PWD"
echo "--builder <BUILDER>: Builder image to pull" echo "--builder <BUILDER>: Builder image to pull"
echo " E.g. ghcr.io/emqx/emqx-builder/5.0-16:1.13.4-24.2.1-1-debian10" echo " E.g. ghcr.io/emqx/emqx-builder/5.0-17:1.13.4-24.2.1-1-debian10"
} }
while [ "$#" -gt 0 ]; do while [ "$#" -gt 0 ]; do

View File

@ -0,0 +1,11 @@
# Hot-upgrade test
This collection of scripts is used in CI.
It can also be used to run the test locally, but limited to ubuntu 20.04 so far.
How to:
```
./scripts/relup-test/run-relup-lux.sh v5.0.0
```

View File

@ -0,0 +1,37 @@
#!/usr/bin/env bash
set -euo pipefail
matched_node1="$(curl --user admin:public -sf http://localhost:18083/api/v5/rules | jq --raw-output ".[0].node_metrics[] | select(.node==\"emqx@node1.emqx.io\") | .metrics.matched")"
matched_node2="$(curl --user admin:public -sf http://localhost:18084/api/v5/rules | jq --raw-output ".[0].node_metrics[] | select(.node==\"emqx@node2.emqx.io\") | .metrics.matched")"
success_node1="$(curl --user admin:public -sf http://localhost:18083/api/v5/rules | jq --raw-output ".[0].node_metrics[] | select(.node==\"emqx@node1.emqx.io\") | .metrics.\"actions.success\"")"
success_node2="$(curl --user admin:public -sf http://localhost:18084/api/v5/rules | jq --raw-output ".[0].node_metrics[] | select(.node==\"emqx@node2.emqx.io\") | .metrics.\"actions.success\"")"
webhook="$(curl -sf http://localhost:7077/counter | jq '.data')"
MATCHED_TOTAL="$(( matched_node1 + matched_node2 ))"
SUCCESS_TOTAL="$(( success_node1 + success_node2 ))"
COLLECTED_TOTAL="$webhook"
is_number() {
re='^[0-9]+$'
if ! [[ $2 =~ $re ]] ; then
echo "error: $1=$2 is not a number" >&2; exit 1
fi
}
is_number MATCHED_TOTAL "$MATCHED_TOTAL"
is_number SUCCESS_TOTAL "$SUCCESS_TOTAL"
is_number COLLECTED_TOTAL "$COLLECTED_TOTAL"
if [ "$MATCHED_TOTAL" -lt 290 ] || \
[ "$SUCCESS_TOTAL" -lt 290 ] || \
[ "$COLLECTED_TOTAL" -lt 290 ]; then
echo "FAILED"
echo "MATCHED_TOTAL=$MATCHED_TOTAL"
echo "SUCCESS_TOTAL=$SUCCESS_TOTAL"
echo "COLLECTED_TOTAL=$COLLECTED_TOTAL"
exit 1
else
echo "ALL_IS_WELL"
exit 0
fi

View File

@ -0,0 +1,130 @@
[config var=PROJ_ROOT]
[config var=VSN]
[config var=CUR_PKG]
[config var=OLD_VSN]
[config var=NODE1]
[config var=NODE2]
[config var=BENCH]
[config shell_cmd=/bin/bash]
[config timeout=600000]
[shell emqx1]
!docker exec -it $NODE1 emqx_ctl cluster status
???running_nodes => ['emqx@node1.emqx.io','emqx@node2.emqx.io']
?SH-PROMPT
## create a webhook data bridge with id "my_webhook"
!curl --user admin:public --silent --show-error 'http://localhost:18083/api/v5/bridges' -X 'POST' -H 'Content-Type: application/json' --data-binary '{"name":"my_webhook","body":"","method":"post","url":"http://webhook.emqx.io:7077/counter","headers":{"content-type":"application/json"},"pool_size":4,"enable_pipelining":100,"connect_timeout":"5s","request_timeout":"5s","max_retries":3,"type":"webhook","ssl":{"enable":false,"verify":"verify_none"}}' | jq '.status'
?connected
?SH-PROMPT
## create a rule that uses the webhook as action, the rule id = "rule_edsy"
!curl --user admin:public --silent --show-error 'http://localhost:18083/api/v5/rules' -X 'POST' -H 'Content-Type: application/json' --data-binary '{"id":"rule_edsy","sql":"SELECT\n *\nFROM\n \"t/#\"","actions":["webhook:my_webhook"]}' | jq '.id'
?rule_edsy
?SH-PROMPT
[shell emqx2]
## verify the bridges and rules are sync to the other node
!curl --user admin:public --silent --show-error 'http://localhost:18084/api/v5/bridges/webhook:my_webhook' -X 'GET' -H 'Content-Type: application/json' | jq '.name'
?my_webhook
?SH-PROMPT
!curl --user admin:public --silent --show-error 'http://localhost:18084/api/v5/rules/rule_edsy' -X 'GET' -H 'Content-Type: application/json' | jq '.id'
?rule_edsy
?SH-PROMPT
[shell bench]
!docker exec -it $BENCH emqtt_bench pub --host 'node1.emqx.io' --port 1883 -c 10 -I 1000 -t t/%i -s 64 -L 300
[shell emqx1]
!docker cp $CUR_PKG $NODE1:/emqx/releases/
## 1. upgrade to the new version
!docker exec -it $NODE1 emqx install $VSN
?Made release permanent: "$VSN"
?SH-PROMPT
!docker exec -it $NODE1 emqx versions | grep permanent
?(.*)$VSN
?SH-PROMPT
## 2. downgrade to the old version
!docker exec -it $NODE1 emqx install $OLD_VSN
?Made release permanent:.*
?SH-PROMPT
!docker exec -it $NODE1 emqx versions | grep permanent | grep -qs "$OLD_VSN"
?SH-PROMPT:
!echo ==$$?==
?^==0==
?SH-PROMPT:
## 3. again, upgrade to the new version
!docker exec -it $NODE1 emqx install $VSN
?Made release permanent: "$VSN"
?SH-PROMPT
!docker exec -it $NODE1 emqx versions | grep permanent
?(.*)$VSN
?SH-PROMPT
!docker exec -it $NODE1 emqx_ctl cluster status
???running_nodes => ['emqx@node1.emqx.io','emqx@node2.emqx.io']
?SH-PROMPT
[shell emqx2]
!docker cp $CUR_PKG $NODE2:/emqx/releases/
## 1. upgrade to the new version
!docker exec -it $NODE2 emqx install $VSN
?Made release permanent: "$VSN"
?SH-PROMPT
!docker exec -it $NODE2 emqx versions | grep permanent
?(.*)$VSN
?SH-PROMPT
## 2. downgrade to the old version
!docker exec -it $NODE2 emqx install $OLD_VSN
?Made release permanent:.*
?SH-PROMPT
!docker exec -it $NODE2 emqx versions | grep permanent | grep -qs "$OLD_VSN"
?SH-PROMPT:
!echo ==$$?==
?^==0==
?SH-PROMPT:
## 3. again, upgrade to the new version
!docker exec -it $NODE2 emqx install $VSN
?Made release permanent: "$VSN"
?SH-PROMPT
!docker exec -it $NODE2 emqx versions | grep permanent
?(.*)$VSN
?SH-PROMPT
!docker exec -it $NODE1 emqx_ctl cluster status
???running_nodes => ['emqx@node1.emqx.io','emqx@node2.emqx.io']
?SH-PROMPT
## We don't guarantee not to lose a single message!
## So even if we received 290~300 messages, we consider it as success
[shell bench]
???publish complete
??SH-PROMPT:
!sleep 5
?SH-PROMPT
!$PROJ_ROOT/scripts/relup-test/check-results.sh
!echo ==$$?==
???ALL_IS_WELL
?SH-PROMPT:
!echo ==$$?==
?^==0==
?SH-PROMPT:
[cleanup]
!echo ==$$?==
?==0==

16
scripts/relup-test/run-pkg.sh Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env bash
## This script is intended to run in docker
## extracts a .tar.gz package and runs EMQX in console mode
set -euo pipefail
PKG="$1"
mkdir -p emqx
tar -C emqx -zxf "$PKG"
ln -s "$(pwd)/emqx/bin/emqx" /usr/bin/emqx
ln -s "$(pwd)/emqx/bin/emqx_ctl" /usr/bin/emqx_ctl
emqx console

View File

@ -0,0 +1,69 @@
#!/usr/bin/env bash
## This script needs the 'lux' command in PATH
## it runs the scripts/relup-test/relup.lux script
set -euo pipefail
old_vsn="${1:-}"
if [ -z "$old_vsn" ]; then
echo "arg1 should be the upgrade base version"
exit 1
fi
# ensure dir
cd -P -- "$(dirname -- "$0")/../.."
set -x
if [ ! -d '.git' ] && [ -z "${CUR_VSN:-}" ]; then
echo "Unable to resolve current version, because it's not a git repo, and CUR_VSN is not set"
exit 1
fi
case "$old_vsn" in
e*)
cur_vsn="${CUR_VSN:-$(./pkg-vsn.sh emqx-enterprise)}"
profile='emqx-enterprise'
;;
v*)
cur_vsn="${CUR_VSN:-$(./pkg-vsn.sh emqx)}"
profile='emqx'
;;
*)
echo "unknown old version $old_vsn"
exit 1
;;
esac
# From now on, no need for the v|e prefix
OLD_VSN="${old_vsn#[e|v]}"
OLD_PKG="$(pwd)/_upgrade_base/${profile}-${OLD_VSN}-otp24.2.1-1-ubuntu20.04-amd64.tar.gz"
CUR_PKG="$(pwd)/_packages/${profile}/${profile}-${cur_vsn}-otp24.2.1-1-ubuntu20.04-amd64.tar.gz"
if [ ! -f "$OLD_PKG" ]; then
echo "$OLD_PKG not found"
exit 1
fi
if [ ! -f "$CUR_PKG" ]; then
echo "$CUR_PKG not found"
exit 1
fi
# start two nodes and their friends (webhook server and a bench) in docker
./scripts/relup-test/start-relup-test-cluster.sh 'ubuntu:20.04' "$OLD_PKG"
# run relup tests
lux \
--progress verbose \
--case_timeout infinity \
--var PROJ_ROOT="$(pwd)" \
--var VSN="$cur_vsn" \
--var CUR_PKG="$CUR_PKG" \
--var OLD_VSN="$OLD_VSN" \
--var NODE1="node1.emqx.io" \
--var NODE2="node2.emqx.io" \
--var BENCH="bench.emqx.io" \
./scripts/relup-test/relup.lux

View File

@ -0,0 +1,111 @@
#!/usr/bin/env bash
set -euo pipefail
## EMQX can only start with longname (https://erlang.org/doc/reference_manual/distributed.html)
## The host name part of EMQX's node name has to be static, this means we should either
## pre-assign static IP for containers, or ensure containers can communiate with each other by name
## this is why a docker network is created, and the containers's names have a dot.
# ensure dir
cd -P -- "$(dirname -- "$0")/../.."
set -x
IMAGE="${1}"
PKG="$(readlink -f "${2}")"
NET='emqx.io'
NODE1="node1.$NET"
NODE2="node2.$NET"
WEBHOOK="webhook.$NET"
BENCH="bench.$NET"
COOKIE='this-is-a-secret'
## Erlang image is needed to run webhook server and emqtt-bench
ERLANG_IMAGE="ghcr.io/emqx/emqx-builder/5.0-17:1.13.4-24.2.1-1-ubuntu20.04"
# builder has emqtt-bench installed
BENCH_IMAGE="$ERLANG_IMAGE"
## clean up
docker rm -f "$BENCH" >/dev/null 2>&1 || true
docker rm -f "$WEBHOOK" >/dev/null 2>&1 || true
docker rm -f "$NODE1" >/dev/null 2>&1 || true
docker rm -f "$NODE2" >/dev/null 2>&1 || true
docker network rm "$NET" >/dev/null 2>&1 || true
docker network create "$NET"
docker run -d -t --name "$NODE1" \
--net "$NET" \
-e EMQX_LOG__CONSOLE_HANDLER__LEVEL=warning \
-e EMQX_NODE_NAME="emqx@$NODE1" \
-e EMQX_NODE_COOKIE="$COOKIE" \
-p 18083:18083 \
-v "$PKG:/emqx.tar.gz" \
-v "$(pwd)/scripts/relup-test/run-pkg.sh:/run-pkg.sh" \
"$IMAGE" /run-pkg.sh emqx.tar.gz
docker run -d -t --name "$NODE2" \
--net "$NET" \
-e EMQX_LOG__CONSOLE_HANDLER__LEVEL=warning \
-e EMQX_NODE_NAME="emqx@$NODE2" \
-e EMQX_NODE_COOKIE="$COOKIE" \
-p 18084:18083 \
-v "$PKG:/emqx.tar.gz" \
-v "$(pwd)/scripts/relup-test/run-pkg.sh:/run-pkg.sh" \
"$IMAGE" /run-pkg.sh emqx.tar.gz
docker run -d -t --name "$WEBHOOK" \
--net "$NET" \
-v "$(pwd)/.ci/fvt_tests/http_server:/http_server" \
-w /http_server \
-p 7077:7077 \
"$ERLANG_IMAGE" bash -c 'rebar3 compile; erl -pa _build/default/lib/*/ebin -eval "http_server:start()"'
docker run -d -t --name "$BENCH" \
--net "$NET" \
"$BENCH_IMAGE" \
bash -c 'sleep 10000; exit 1'
wait_limit=60
wait_for_emqx() {
wait_sec=0
container="$1"
wait_limit="$2"
set +x
while ! docker exec "$container" emqx_ctl status >/dev/null 2>&1; do
wait_sec=$(( wait_sec + 1 ))
if [ $wait_sec -gt "$wait_limit" ]; then
echo "timeout wait for EMQX"
exit 1
fi
echo -n '.'
sleep 1
done
}
wait_for_webhook() {
wait_sec=0
wait_limit="$1"
set +x
while ! curl -f -s localhost:7077; do
wait_sec=$(( wait_sec + 1 ))
if [ $wait_sec -gt "$wait_limit" ]; then
echo "timeout wait for EMQX"
exit 1
fi
echo -n '.'
sleep 1
done
}
# wait for webhook http server to start,
# it may take a while because it needs to compile from source code
wait_for_webhook 120
# after webhook start, it should not cost more than 30 seconds
wait_for_emqx $NODE1 30
# afer node1 is up, it should not cost more than 10 seconds
wait_for_emqx $NODE2 10
echo
docker exec $NODE1 emqx_ctl cluster join "emqx@$NODE2"