diff --git a/.ci/deps_tests/docker-compose.yaml b/.ci/deps_tests/docker-compose.yaml index 7b714370..656186ff 100644 --- a/.ci/deps_tests/docker-compose.yaml +++ b/.ci/deps_tests/docker-compose.yaml @@ -25,6 +25,7 @@ services: - emqx_bridge volumes: - ../../.:/emqx-rel + working_dir: /emqx-rel tty: true python: diff --git a/.ci/nightly_build/http_server/.gitignore b/.ci/nightly_build/http_server/.gitignore new file mode 100644 index 00000000..f1c45545 --- /dev/null +++ b/.ci/nightly_build/http_server/.gitignore @@ -0,0 +1,19 @@ +.rebar3 +_* +.eunit +*.o +*.beam +*.plt +*.swp +*.swo +.erlang.cookie +ebin +log +erl_crash.dump +.rebar +logs +_build +.idea +*.iml +rebar3.crashdump +*~ diff --git a/.ci/nightly_build/http_server/LICENSE b/.ci/nightly_build/http_server/LICENSE new file mode 100644 index 00000000..55aec1ca --- /dev/null +++ b/.ci/nightly_build/http_server/LICENSE @@ -0,0 +1,191 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2020, zhanghongtong . + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/.ci/nightly_build/http_server/README.md b/.ci/nightly_build/http_server/README.md new file mode 100644 index 00000000..01c4b473 --- /dev/null +++ b/.ci/nightly_build/http_server/README.md @@ -0,0 +1,9 @@ +http_server +===== + +An OTP application + +Build +----- + + $ rebar3 compile diff --git a/.ci/nightly_build/http_server/rebar.config b/.ci/nightly_build/http_server/rebar.config new file mode 100644 index 00000000..9cc5f3d0 --- /dev/null +++ b/.ci/nightly_build/http_server/rebar.config @@ -0,0 +1,10 @@ +{erl_opts, [debug_info]}. +{deps, + [ + {minirest, {git, "https://github.com/emqx/minirest.git", {tag, "0.3.1"}}} + ]}. + +{shell, [ + % {config, "config/sys.config"}, + {apps, [http_server]} +]}. diff --git a/.ci/nightly_build/http_server/src/http_server.app.src b/.ci/nightly_build/http_server/src/http_server.app.src new file mode 100644 index 00000000..f351bb34 --- /dev/null +++ b/.ci/nightly_build/http_server/src/http_server.app.src @@ -0,0 +1,17 @@ +{application, http_server, + [{description, "An OTP application"}, + {vsn, "0.1.0"}, + {registered, []}, + % {mod, {http_server_app, []}}, + {modules, []}, + {applications, + [kernel, + stdlib, + minirest + ]}, + {env,[]}, + {modules, []}, + + {licenses, ["Apache 2.0"]}, + {links, []} + ]}. diff --git a/.ci/nightly_build/http_server/src/http_server.erl b/.ci/nightly_build/http_server/src/http_server.erl new file mode 100644 index 00000000..b66b7293 --- /dev/null +++ b/.ci/nightly_build/http_server/src/http_server.erl @@ -0,0 +1,50 @@ +-module(http_server). + +-import(minirest, [ return/0 + , return/1 + ]). + +-export([ start/0 + , stop/0 + ]). + +-rest_api(#{ name => get_counter + , method => 'GET' + , path => "/counter" + , func => get_counter + , descr => "Check counter" + }). +-rest_api(#{ name => add_counter + , method => 'POST' + , path => "/counter" + , func => add_counter + , descr => "Counter plus one" + }). + +-export([ get_counter/2 + , add_counter/2 + ]). + +start() -> + application:ensure_all_started(minirest), + ets:new(relup_test_message, [named_table, public]), + Handlers = [{"/", minirest:handler(#{modules => [?MODULE]})}], + Dispatch = [{"/[...]", minirest, Handlers}], + minirest:start_http(?MODULE, #{socket_opts => [inet, {port, 8080}]}, Dispatch). + +stop() -> + ets:delete(relup_test_message), + minirest:stop_http(?MODULE). + +get_counter(_Binding, _Params) -> + return({ok, ets:info(relup_test_message, size)}). + +add_counter(_Binding, Params) -> + case lists:keymember(<<"payload">>, 1, Params) of + true -> + {value, {<<"id">>, ID}, Params1} = lists:keytake(<<"id">>, 1, Params), + ets:insert(relup_test_message, {ID, Params1}); + _ -> + ok + end, + return(). diff --git a/.ci/nightly_build/relup.lux b/.ci/nightly_build/relup.lux new file mode 100644 index 00000000..49659db6 --- /dev/null +++ b/.ci/nightly_build/relup.lux @@ -0,0 +1,160 @@ +[config var=PACKAGE_PATH] +[config var=BENCH_PATH] +[config var=ONE_MORE_EMQX_PATH] +[config var=TAG] +[config var=OLD_TAGS] + +[config shell_cmd=/bin/bash] +[config timeout=600000] + +[loop old_tag $OLD_TAGS] + +[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 + !unzip -q -o emqx-ubuntu20.04-$old_tag-x86_64.zip + ?SH-PROMPT + + !cd emqx + !sed -i 's|listener.wss.external[ \t]*=.*|listener.wss.external = 8085|g' etc/emqx.conf + !./bin/emqx start + ?EMQ X Broker $old_tag is started successfully! + + !./bin/emqx_ctl status + """? + Node 'emqx@127.0.0.1' is started + emqx $old_tag is running + """ + +[shell emqx2] + !cd $PACKAGE_PATH + !cp $ONE_MORE_EMQX_PATH/one_more_emqx.sh . + !./one_more_emqx.sh emqx2 + ?SH-PROMPT + !cd emqx2 + + !./bin/emqx start + ?EMQ X Broker $old_tag is started successfully! + + !./bin/emqx_ctl status + """? + Node 'emqx2@127.0.0.1' is started + emqx $old_tag is running + """ + ?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] + !cp -f ../emqx-ubuntu20.04-$TAG-x86_64.zip releases/ + !./bin/emqx install $TAG + ?SH-PROMPT + !./bin/emqx versions |grep permanent | grep -oE "[0-9].[0-9].[0-9]" + ?$TAG + ?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 + +[shell emqx2] + !cp -f ../emqx-ubuntu20.04-$TAG-x86_64.zip releases/ + !./bin/emqx install $TAG + ?SH-PROMPT + !./bin/emqx versions |grep permanent | grep -oE "[0-9].[0-9].[0-9]" + ?$TAG + ?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 + +[shell bench] + ???publish complete + ??SH-PROMPT: +# !curl http://127.0.0.1:8080/counter +# ???{"data":300,"code":0} +# ?SH-PROMPT + +[shell http_server] + !http_server:stop(). + ?ok + ?> + !halt(3). + ?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: + +[endloop] + +[cleanup] + !rm -rf $PACKAGE_PATH/one_more_emqx.sh + ?SH-PROMPT: + !echo ==$$?== + ?==0== diff --git a/.github/workflows/build_cross_packages.yaml b/.github/workflows/build_cross_packages.yaml index 39ab797e..2fbe51a3 100644 --- a/.github/workflows/build_cross_packages.yaml +++ b/.github/workflows/build_cross_packages.yaml @@ -13,16 +13,22 @@ jobs: steps: - uses: actions/checkout@v1 - uses: ilammy/msvc-dev-cmd@v1 + - uses: gleam-lang/setup-erlang@v1.1.0 + id: install_erlang + with: + otp-version: 22.3 - name: build run: | - set-executionpolicy remotesigned -s cu - iex (new-object net.webclient).downloadstring('https://get.scoop.sh') - $env:path + ";" + $env:USERPROFILE + "\scoop\shims" - scoop bucket add extras https://github.com/lukesampson/scoop-extras.git - scoop bucket add java - scoop update - scoop install sudo curl 7zip ojdkbuild8 vcredist2013 - scoop install erlang@22.3 + # set-executionpolicy remotesigned -s cu + # iex (new-object net.webclient).downloadstring('https://get.scoop.sh') + # # $env:path + ";" + $env:USERPROFILE + "\scoop\shims" + ';C:\Program Files\erl10.4\bin' + # [environment]::SetEnvironmentvariable("Path", ";" + $env:USERPROFILE + "\scoop\shims") + # [environment]::SetEnvironmentvariable("Path", ';C:\Program Files\erl10.4\bin') + # scoop bucket add extras https://github.com/lukesampson/scoop-extras.git + # scoop update + # scoop install sudo curl vcredist2013 + + $env:PATH = "${{ steps.install_erlang.outputs.erlpath }}\bin;$env:PATH" $version = $( "${{ github.ref }}" -replace "^(.*)/(.*)/" ) if ($version -match "^v[0-9]+\.[0-9]+(\.[0-9]+)?") { @@ -111,7 +117,7 @@ jobs: sudo systemctl restart docker docker info docker buildx create --use --name mybuild - docker run --rm --privileged multiarch/qemu-user-static --reset -p yes + docker run --rm --privileged tonistiigi/binfmt --install all - uses: actions/checkout@v1 - name: get deps run: | @@ -119,15 +125,16 @@ jobs: -e GITHUB_RUN_ID=$GITHUB_RUN_ID \ -e GITHUB_REF=$GITHUB_REF \ -v $(pwd):/emqx-rel \ + -w /emqx-rel \ emqx/build-env:erl22.3-debian10 \ - bash -c "make -C /emqx-rel deps-all" + bash -c "make deps-all" - name: downloads emqx zip packages env: SYSTEM: ${{ matrix.os }} run: | set -e -u -x version=$(echo ${{ github.ref }} | sed -r "s ^refs/heads/|^refs/tags/(.*) \1 g") - if [ "$(echo $version | grep -oE "^[ev0-9]+\.[0-9]+\.[1-9]?")" = "$version" ]; then + if [ "$(echo $version | grep -oE "^[ev0-9]+\.[0-9]+\.[1-9]+?")" = "$version" ]; then tags=$(git tag -l "$(echo $version | grep -oE "^[ev0-9]+\.[0-9]").*" |grep -v "$version") for tag in ${tags[@]};do for arch in x86_64 aarch64; do @@ -249,8 +256,9 @@ jobs: -e GITHUB_RUN_ID=$GITHUB_RUN_ID \ -e GITHUB_REF=$GITHUB_REF \ -v $(pwd):/emqx-rel \ + -w /emqx-rel \ emqx/build-env:erl22.3-alpine-amd64 \ - sh -c "make -C /emqx-rel deps-emqx" + sh -c "make deps-emqx" - name: build emqx docker image env: ARCH: ${{ matrix.arch[0] }} @@ -318,9 +326,6 @@ jobs: set -e -x -u version=$(echo ${{ github.ref }} | sed -r "s ^refs/heads/|^refs/tags/(.*) \1 g") if [ ! -z $(echo $version | grep -oE "^[ev0-9]+\.[0-9]+(\.[0-9]+)?") ]; then - curl "https://d1vvhvl2y92vvt.cloudfront.net/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" - unzip awscliv2.zip - sudo ./aws/install aws configure set aws_access_key_id ${{ secrets.AWS_ACCESS_KEY_ID }} aws configure set aws_secret_access_key ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws configure set default.region us-west-2 @@ -360,7 +365,7 @@ jobs: version=$(echo ${{ github.ref }} | sed -r "s ^refs/heads/|^refs/tags/(.*) \1 g") if [ ! -z $(echo $version | grep -oE "^[ev0-9]+\.[0-9]+(\.[0-9]+)?") ]; then sudo make -C emqx-rel docker-prepare - cd ./packages && for var in $(ls |grep docker |grep -v sha256); do unzip $var; sudo docker load < ${var%.*}; rm -f ${var%.*}; done && cd - + cd packages && for var in $(ls |grep docker |grep -v sha256); do unzip $var; sudo docker load < ${var%.*}; rm -f ${var%.*}; done && cd - echo ${{ secrets.DOCKER_HUB_TOKEN }} |sudo docker login -u ${{ secrets.DOCKER_HUB_USER }} --password-stdin sudo EMQX_DEPS_DEFAULT_VSN=$version TARGET=emqx/emqx make -C emqx-rel docker-push sudo EMQX_DEPS_DEFAULT_VSN=$version TARGET=emqx/emqx make -C emqx-rel docker-manifest-list diff --git a/.github/workflows/run_deps_tests.yaml b/.github/workflows/run_deps_tests.yaml index a8456ab8..1e626350 100644 --- a/.github/workflows/run_deps_tests.yaml +++ b/.github/workflows/run_deps_tests.yaml @@ -29,10 +29,11 @@ jobs: docker run -i --rm \ -e EMQX_DEPS_DEFAULT_VSN=$version \ -v $(pwd):/emqx-rel \ + -w /emqx-rel \ emqx/build-env:erl22.3-debian10 \ - bash -c "make -C /emqx-rel deps-emqx" + bash -c "make deps-emqx" - name: Install docker-compose - run: | + run: | sudo curl -L "https://github.com/docker/compose/releases/download/1.25.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose sudo chmod +x /usr/local/bin/docker-compose - name: docker-compose build @@ -50,7 +51,7 @@ jobs: sudo chmod -R 777 ./emqx*/etc for var in $(ls |grep emqx); do if [ $var == "emqx_auth_mysql" ];then - sed -i "/auth.mysql.server/c auth.mysql.server = mysql_server:3306" ./$var/etc/emqx_auth_mysql.conf + sed -i "/auth.mysql.server/c auth.mysql.server = mysql_server:3306" ./$var/etc/emqx_auth_mysql.conf echo "auth.mysql.username = root" >> ./$var/etc/emqx_auth_mysql.conf echo "auth.mysql.password = public" >> ./$var/etc/emqx_auth_mysql.conf echo "auth.mysql.ssl.cafile = /emqx-rel/_build/emqx/lib/emqx_auth_mysql/test/emqx_auth_mysql_SUITE_data/ca.pem" >> ./$var/etc/emqx_auth_mysql.conf diff --git a/.github/workflows/run_paho_tests.yaml b/.github/workflows/run_paho_tests.yaml index 986f4eb8..93f1e5c7 100644 --- a/.github/workflows/run_paho_tests.yaml +++ b/.github/workflows/run_paho_tests.yaml @@ -1,6 +1,6 @@ name: Run paho tests -on: +on: push: tags: - v* @@ -19,7 +19,7 @@ jobs: steps: - name: Install docker-compose - run: | + run: | sudo curl -L "https://github.com/docker/compose/releases/download/1.25.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose sudo chmod +x /usr/local/bin/docker-compose - uses: actions/checkout@v1 @@ -36,8 +36,9 @@ jobs: docker run -i --rm \ -e EMQX_DEPS_DEFAULT_VSN=$version \ -v $(pwd):/emqx-rel \ + -w /emqx-rel \ emqx/build-env:erl22.3-debian10 \ - bash -c "make -C /emqx-rel deps-emqx" + bash -c "make deps-emqx" - name: make emqx image run: TARGET=emqx/emqx make docker-build - name: make paho tests diff --git a/.github/workflows/run_relup_tests.yaml b/.github/workflows/run_relup_tests.yaml new file mode 100644 index 00000000..b4ab245d --- /dev/null +++ b/.github/workflows/run_relup_tests.yaml @@ -0,0 +1,128 @@ +name: Run relup tests + +on: + push: + tags: + - v* + workflow_dispatch: + inputs: + version: + required: true + +jobs: + run_relup_test: + runs-on: ubuntu-20.04 + container: emqx/build-env:erl22.3-ubuntu20.04 + defaults: + run: + shell: bash + steps: + # - uses: bajankristof/setup-erlang@master + # with: + # otp-version: 22.3 + # allow-cache: false + # - uses: actions/setup-python@v2 + # with: + # python-version: '3.8' + # architecture: 'x64' + # - uses: actions/checkout@v2 + # with: + # repository: emqx/paho.mqtt.testing + # ref: develop-4.0 + # path: paho.mqtt.testing + - uses: actions/checkout@v2 + with: + repository: terry-xiaoyu/one_more_emqx + ref: master + path: one_more_emqx + - uses: actions/checkout@v2 + with: + repository: emqx/emqtt-bench + ref: master + path: emqtt-bench + - uses: actions/checkout@v2 + with: + repository: hawk/lux + ref: lux-2.4 + path: lux + - uses: actions/checkout@v2 + with: + repository: emqx/emqx-rel + path: emqx-rel + fetch-depth: 0 + - name: get version + run: | + set -e -x -u + cd emqx-rel + if [ $(echo $GITHUB_REF | grep -o -E "[ev0-9]+.[0-9]+.[0-9]+?") ]; then + tag="$(echo $GITHUB_REF | grep -oE '[ev0-9]+.[0-9]+.[0-9]+?')" + else + tag=$(./get-lastest-tag.escript tag) + fi + echo "TAG=$tag" >> $GITHUB_ENV + pre_tag="$(echo $tag | grep -oE '^[ev0-9]+.[0-9]+')" + old_tags="$(git tag -l "$pre_tag.[0-9]*" | grep -v $tag | tr "\n" " " )" + echo "OLD_TAGS=$old_tags" >> $GITHUB_ENV + - name: download emqx + run: | + set -e -x -u + cd emqx-rel + old_tags=($(echo $OLD_TAGS | tr ' ' ' ')) + for old_tag in ${old_tags[@]}; do + wget https://s3-us-west-2.amazonaws.com/packages.emqx/emqx-ce/$old_tag/emqx-ubuntu20.04-${old_tag#[e|v]}-x86_64.zip + done + - name: build emqx + run: | + set -e -x -u + make -C emqx-rel emqx-zip + # make deps-emqx + # docker run -i --rm \ + # -e EMQX_DEPS_DEFAULT_VSN=$TAG \ + # -v $(pwd):/emqx-rel \ + # emqx/build-env:erl22.3-ubuntu20.04 \ + # bash -c "make -C /emqx-rel emqx-zip" + # sudo chown -R $USER:$USER _packages/emqx + # - name: run paho test + # run: | + # set -e -x -u + # unzip -q emqx-rel/_packages/emqx/emqx-ubuntu20.04-${TAG#[e|v]}-x86_64.zip + # sed -i 's|listener.wss.external[ \t]*=.*|listener.wss.external = 8085|g' emqx/etc/listeners.conf + # sed -i 's|mqtt.max_topic_alias[ \t]*=.*|mqtt.max_topic_alias = 10|g' emqx/etc/emqx.conf + # sed -i 's|zone.external.retry_interval[ \t]*=.*|zone.external.retry_interval = 2s|g' emqx/etc/zones.conf + # ./emqx/bin/emqx start || cat emqx/log/erlang.log.1 + # pip install pytest + # pytest -v paho.mqtt.testing/interoperability/test_client/ --host 127.0.0.1 + # ./emqx/bin/emqx stop + # rm -rf emqx + - name: build emqtt-bench + run: | + set -e -u -x + make -C emqtt-bench + - name: build lux + run: | + set -e -u -x + cd lux + autoconf + ./configure + make + make install + - name: run relup test + run: | + set -e -x -u + cp emqx-rel/*.zip . + cp emqx-rel/_packages/emqx/*.zip . + if [ -n "$OLD_TAGS" ]; then + lux -v \ + --case_timeout infinity \ + --var PACKAGE_PATH=$(pwd) \ + --var BENCH_PATH=$(pwd)/emqtt-bench \ + --var ONE_MORE_EMQX_PATH=$(pwd)/one_more_emqx \ + --var TAG=${TAG#[e|v]} \ + --var OLD_TAGS="${OLD_TAGS//[e|v]}" \ + emqx-rel/.ci/nightly_build/relup.lux + fi + - uses: actions/upload-artifact@v1 + if: failure() + with: + name: lux_logs + path: lux_logs diff --git a/.gitignore b/.gitignore index 77c806ae..6be406fc 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,5 @@ deploy/docker/tmp tmp .vscode/settings.json .ignore +/rebar3 +/.tool-versions diff --git a/Makefile b/Makefile index b3f41a98..7271fc7a 100644 --- a/Makefile +++ b/Makefile @@ -4,10 +4,9 @@ REBAR_GIT_CLONE_OPTIONS += --depth 1 export REBAR_GIT_CLONE_OPTIONS export LC_ALL=en_US.UTF-8 +REBAR_VERSION = 3.13.2-emqx-4 REBAR = $(CURDIR)/rebar3 -REBAR_URL = https://s3.amazonaws.com/rebar3/rebar3 - PROFILE ?= emqx PROFILES := emqx emqx-edge PKG_PROFILES := emqx-pkg emqx-edge-pkg @@ -121,11 +120,9 @@ $(CT_APPS:%=ct-%): checkout-$(PROFILE) @mkdir -p tests/logs/$(@:ct-%=%) @if [ -d _build/emqx/lib/$(@:ct-%=%)/_build/test/logs ]; then cp -r _build/emqx/lib/$(@:ct-%=%)/_build/test/logs/* tests/logs/$(@:ct-%=%); fi +.PHONY: $(REBAR) $(REBAR): -ifneq ($(wildcard rebar3),rebar3) - @curl -Lo rebar3 $(REBAR_URL) || wget $(REBAR_URL) -endif - @chmod a+x rebar3 + $(CURDIR)/ensure-rebar3.sh $(REBAR_VERSION) .PHONY: deps-all deps-all: $(REBAR) $(PROFILES:%=deps-%) $(PKG_PROFILES:%=deps-%) diff --git a/README.md b/README.md index 4f0b8d17..436afa03 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,18 @@ # emqx-rel -The Release Project for EMQ X Broker. +The Release Project for EMQX Broker. -NOTICE: Requires Erlang/OTP 21.3 to build since EMQ X 3.2 +NOTICE: Requires Erlang/OTP 21.3 .. 22 to build since EMQX 3.2 +EMQX no longer uses this repository since version 4.3. Use https://github.com/emqx/emqx/ instead. -There are 4 target profiles for building emqx-rel: emqx, emqx-pkg, emqx-edge,and emqx-edge-pkg. The default target profile is emqx. User can build specified target release by execute command `make ${target-release}` in emqx_rel. -## Install Erlang/OTP-R21.3 and rebar3 +There are 4 target profiles for building emqx-rel: emqx, emqx-pkg, emqx-edge,and emqx-edge-pkg. The default target profile is emqx. User can build specified target release by execute command `make ${target-release}` in emqx_rel. -Read the section below and install rebar3 +## rebar3 -``` -https://www.rebar3.org/docs/getting-started#section-installing-from-source -``` +This project has rebar3 (compiled from OTP 21.3) included. ## Build on Linux/Unix/Mac @@ -95,4 +93,4 @@ Apache License Version 2.0 # Author -EMQ X Team. +EMQX Team. diff --git a/data/loaded_modules.tmpl b/data/loaded_modules.tmpl index 25ecbd4b..074d1796 100644 --- a/data/loaded_modules.tmpl +++ b/data/loaded_modules.tmpl @@ -1,2 +1,6 @@ {emqx_mod_acl_internal, true}. {emqx_mod_presence, true}. +{emqx_mod_delayed, false}. +{emqx_mod_rewrite, false}. +{emqx_mod_subscription, false}. +{emqx_mod_topic_metrics, false}. diff --git a/deploy/charts/emqx/README.md b/deploy/charts/emqx/README.md index 93df8e52..ff0dff04 100644 --- a/deploy/charts/emqx/README.md +++ b/deploy/charts/emqx/README.md @@ -34,11 +34,12 @@ The following table lists the configurable parameters of the emqx chart and thei | Parameter | Description | Default Value | | --- | --- | --- | | `replicaCount` | It is recommended to have odd number of nodes in a cluster, otherwise the emqx cluster cannot be automatically healed in case of net-split. |3| -| `image.repository` | EMQ X Image name |emqx/emqx| -| `image.pullPolicy` | Global Docker registry secret names as an array |IfNotPresent| +| `image.repository` | EMQX Image name |emqx/emqx| +| `image.pullPolicy` | The image pull policy |IfNotPresent| +| `image.pullSecrets ` | The image pull secrets |`[]` (does not add image pull secrets to deployed pods)| | `persistence.enabled` | Enable EMQX persistence using PVC |false| | `persistence.storageClass` | Storage class of backing PVC |`nil` (uses alpha storage class annotation)| -| `persistence.existingClaim` | EMQ X data Persistent Volume existing claim name, evaluated as a template |""| +| `persistence.existingClaim` | EMQX data Persistent Volume existing claim name, evaluated as a template |""| | `persistence.accessMode` | PVC Access Mode for EMQX volume |ReadWriteOnce| | `persistence.size` | PVC Storage Request for EMQX volume |20Mi| | `initContainers` | Containers that run before the creation of EMQX containers. They can contain utilities or setup scripts. |`{}`| diff --git a/deploy/charts/emqx/templates/StatefulSet.yaml b/deploy/charts/emqx/templates/StatefulSet.yaml index 2b04e31d..96bb2c6f 100644 --- a/deploy/charts/emqx/templates/StatefulSet.yaml +++ b/deploy/charts/emqx/templates/StatefulSet.yaml @@ -48,6 +48,12 @@ spec: app.kubernetes.io/name: {{ include "emqx.name" . }} app.kubernetes.io/instance: {{ .Release.Name }} spec: + {{- if .Values.image.pullSecrets }} + imagePullSecrets: + {{- range .Values.image.pullSecrets }} + - name: {{ . }} + {{- end }} + {{- end }} volumes: - name: emqx-acl configMap: @@ -65,14 +71,15 @@ spec: claimName: {{ tpl . $ }} {{- end }} {{- end }} - {{- if .Values.emqxLicneseSecretName }} + {{- if .Values.emqxLicenseSecretName }} - name: emqx-license secret: - secretName: {{ .Values.emqxLicneseSecretName }} + secretName: {{ .Values.emqxLicenseSecretName }} {{- end }} serviceAccountName: {{ include "emqx.fullname" . }} - securityContext: - fsGroup: 1000 + {{- if .Values.podSecurityContext.enabled }} + securityContext: {{- omit .Values.podSecurityContext "enabled" | toYaml | nindent 8 }} + {{- end }} {{- if .Values.initContainers }} initContainers: {{ toYaml .Values.initContainers | indent 8 }} @@ -80,6 +87,9 @@ spec: containers: - name: emqx image: "{{ .Values.image.repository }}:{{ .Chart.AppVersion }}" + {{- if .Values.containerSecurityContext.enabled }} + securityContext: {{- omit .Values.containerSecurityContext "enabled" | toYaml | nindent 12 }} + {{- end }} imagePullPolicy: {{ .Values.image.pullPolicy }} ports: - name: mqtt @@ -118,7 +128,7 @@ spec: - name: emqx-acl mountPath: "/opt/emqx/etc/acl.conf" subPath: "acl.conf" - {{ if .Values.emqxLicneseSecretName }} + {{ if .Values.emqxLicenseSecretName }} - name: emqx-license mountPath: "/opt/emqx/etc/emqx.lic" subPath: "emqx.lic" diff --git a/deploy/charts/emqx/values.yaml b/deploy/charts/emqx/values.yaml index ffaefa05..5d6ab079 100644 --- a/deploy/charts/emqx/values.yaml +++ b/deploy/charts/emqx/values.yaml @@ -7,6 +7,12 @@ replicaCount: 3 image: repository: emqx/emqx pullPolicy: IfNotPresent + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## + # pullSecrets: + # - myRegistryKeySecretName persistence: enabled: false @@ -68,10 +74,10 @@ emqxAclConfig: > {deny, all, subscribe, ["$SYS/#", {eq, "#"}]}. {allow, all}. -## EMQX Enterprise Edition requires manual creation of a Secret containing the licensed content. Write the name of Secret to the value of "emqxLicneseSecretName" +## EMQX Enterprise Edition requires manual creation of a Secret containing the licensed content. Write the name of Secret to the value of "emqxLicenseSecretName" ## Example: ## kubectl create secret generic emqx-license-secret-name --from-file=/path/to/emqx.lic -emqxLicneseSecretName: +emqxLicenseSecretName: service: ## Service type @@ -149,4 +155,15 @@ ingress: - api.emqx.local tls: [] - +podSecurityContext: + enabled: true + fsGroup: 1000 + fsGroupChangePolicy: Always + runAsUser: 1000 + supplementalGroups: + - 1000 + +containerSecurityContext: + enabled: true + runAsNonRoot: true + runAsUser: 1000 diff --git a/deploy/docker/Dockerfile b/deploy/docker/Dockerfile index 727e4708..a7a175f6 100644 --- a/deploy/docker/Dockerfile +++ b/deploy/docker/Dockerfile @@ -4,9 +4,9 @@ FROM ${BUILD_FROM} AS builder ARG QEMU_ARCH=x86_64 COPY tmp/qemu-$QEMU_ARCH-stati* /usr/bin/ -COPY . /emqx-rel -RUN apk add git \ +RUN apk add --no-cache \ + git \ curl \ gcc \ g++ \ @@ -19,6 +19,8 @@ RUN apk add git \ libc-dev \ libstdc++ +COPY . /emqx-rel + ARG EMQX_DEPS_DEFAULT_VSN=develop ARG EMQX_NAME=emqx @@ -39,11 +41,12 @@ LABEL org.label-schema.docker.dockerfile="Dockerfile" \ ARG QEMU_ARCH=x86_64 ARG EMQX_NAME=emqx + COPY deploy/docker/docker-entrypoint.sh deploy/docker/start.sh tmp/qemu-$QEMU_ARCH-stati* /usr/bin/ COPY --from=builder /emqx-rel/_build/$EMQX_NAME/rel/emqx /opt/emqx -RUN ln -s /opt/emqx/bin/* /usr/local/bin/ -RUN apk add --no-cache curl ncurses-libs openssl sudo libstdc++ +RUN ln -s /opt/emqx/bin/* /usr/local/bin/ +RUN apk add --no-cache curl ncurses-libs openssl sudo libstdc++ bash WORKDIR /opt/emqx diff --git a/deploy/docker/README.md b/deploy/docker/README.md index b6a65faf..8aeda1d8 100644 --- a/deploy/docker/README.md +++ b/deploy/docker/README.md @@ -17,11 +17,11 @@ [the latest release](https://github.com/docker/docker-ce/releases/latest) -# What is EMQ X +# What is EMQX -[EMQ X MQTT broker](https://emqx.io/products/broker) is a fully open source, highly scalable, highly available distributed MQTT messaging broker for IoT, M2M and Mobile applications that can handle tens of millions of concurrent clients. +[EMQX MQTT broker](https://emqx.io/products/broker) is a fully open source, highly scalable, highly available distributed MQTT messaging broker for IoT, M2M and Mobile applications that can handle tens of millions of concurrent clients. -Starting from 3.0 release, *EMQ X* broker fully supports MQTT V5.0 protocol specifications and backward compatible with MQTT V3.1 and V3.1.1, as well as other communication protocols such as MQTT-SN, CoAP, LwM2M, WebSocket and STOMP. The 3.0 release of the *EMQ X* broker can scaled to 10+ million concurrent MQTT connections on one cluster. +Starting from 3.0 release, *EMQX* broker fully supports MQTT V5.0 protocol specifications and backward compatible with MQTT V3.1 and V3.1.1, as well as other communication protocols such as MQTT-SN, CoAP, LwM2M, WebSocket and STOMP. The 3.0 release of the *EMQ X* broker can scaled to 10+ million concurrent MQTT connections on one cluster. # How to use this image @@ -39,7 +39,7 @@ The emqx broker runs as linux user `emqx` in the docker container. ### Configuration -Use the environment variable to configure the EMQ X docker container. +Use the environment variable to configure the EMQX docker container. The environment variables which with ``EMQX_`` prefix are mapped to configuration fils. @@ -63,9 +63,9 @@ EMQX_HOST These environment variables will ignore for configuration file. -#### EMQ X Configuration +#### EMQX Configuration -> NOTE: All EMQ X Configuration in [etc/emqx.conf](https://github.com/emqx/emqx/blob/master/etc/emqx.conf) could config by environment. The following list is just an example, not a complete configuration. +> NOTE: All EMQX Configuration in [etc/emqx.conf](https://github.com/emqx/emqx/blob/master/etc/emqx.conf) could config by environment. The following list is just an example, not a complete configuration. | Options | Default | Mapped | Description | | ---------------------------| ------------------ | ------------------------- | ------------------------------------- | @@ -149,7 +149,7 @@ EMQX_LOADED_PLUGINS="emqx_auth_redis emqx_auth_mysql" EMQX_LOADED_PLUGINS="emqx_auth_redis | emqx_auth_mysql" ``` -#### EMQ X Plugins Configuration +#### EMQX Plugins Configuration The environment variables which with ``EMQX_`` prefix are mapped to all emqx plugins' configuration file, ``.`` get replaced by ``__``. @@ -211,7 +211,7 @@ The configuration should match whole word (after splitting it by '.') with `MASK ### Cluster -EMQ X supports a variety of clustering methods, see our [documentation](https://docs.emqx.io/broker/latest/en/advanced/cluster.html#emqx-service-discovery) for details. +EMQX supports a variety of clustering methods, see our [documentation](https://docs.emqx.io/broker/latest/en/advanced/cluster.html#emqx-service-discovery) for details. Let's create a static node list cluster from docker-compose. @@ -267,7 +267,7 @@ Let's create a static node list cluster from docker-compose. ### Persistence -If you want to persist the EMQ X docker container, you need to keep the following directories: +If you want to persist the EMQX docker container, you need to keep the following directories: + `/opt/emqx/data` + `/opt/emqx/etc` @@ -327,7 +327,7 @@ docker run -d --name emqx -p 18083:18083 -p 1883:1883 -p 4369:4369 \ ``` -> REMEMBER: DO NOT RUN EMQ X DOCKER PRIVILEGED OR MOUNT SYSTEM PROC IN CONTAINER TO TUNE LINUX KERNEL, IT IS UNSAFE. +> REMEMBER: DO NOT RUN EMQX DOCKER PRIVILEGED OR MOUNT SYSTEM PROC IN CONTAINER TO TUNE LINUX KERNEL, IT IS UNSAFE. ### Thanks diff --git a/deploy/docker/docker-entrypoint.sh b/deploy/docker/docker-entrypoint.sh index 30c921f6..77d40d4f 100755 --- a/deploy/docker/docker-entrypoint.sh +++ b/deploy/docker/docker-entrypoint.sh @@ -1,41 +1,43 @@ -#!/bin/sh +#!/bin/bash ## EMQ docker image start script # Huang Rui # EMQ X Team ## Shell setting -if [[ ! -z "$DEBUG" ]]; then +if [[ -n "$DEBUG" ]]; then set -ex else set -e fi +shopt -s nullglob + ## Local IP address setting -LOCAL_IP=$(hostname -i |grep -E -oh '((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])'|head -n 1) +LOCAL_IP=$(hostname -i | grep -oE '((25[0-5]|(2[0-4]|1[0-9]|[1-9]|)[0-9])\.){3}(25[0-5]|(2[0-4]|1[0-9]|[1-9]|)[0-9])' | head -n 1) ## EMQ Base settings and plugins setting # Base settings in /opt/emqx/etc/emqx.conf # Plugin settings in /opt/emqx/etc/plugins -_EMQX_HOME="/opt/emqx" +_EMQX_HOME='/opt/emqx' if [[ -z "$EMQX_NAME" ]]; then - export EMQX_NAME="$(hostname)" + EMQX_NAME="$(hostname)" + export EMQX_NAME fi if [[ -z "$EMQX_HOST" ]]; then - if [[ "$EMQX_CLUSTER__K8S__ADDRESS_TYPE" == "dns" ]] && [[ ! -z "$EMQX_CLUSTER__K8S__NAMESPACE" ]];then + if [[ "$EMQX_CLUSTER__K8S__ADDRESS_TYPE" == "dns" ]] && [[ -n "$EMQX_CLUSTER__K8S__NAMESPACE" ]]; then EMQX_CLUSTER__K8S__SUFFIX=${EMQX_CLUSTER__K8S__SUFFIX:-"pod.cluster.local"} - DNSAddress="${LOCAL_IP//./-}.${EMQX_CLUSTER__K8S__NAMESPACE}.${EMQX_CLUSTER__K8S__SUFFIX}" - export EMQX_HOST="$DNSAddress" - elif [[ "$EMQX_CLUSTER__K8S__ADDRESS_TYPE" == "hostname" ]] && [[ ! -z "$EMQX_CLUSTER__K8S__NAMESPACE" ]]; then - EMQX_CLUSTER__K8S__SUFFIX=${EMQX_CLUSTER__K8S__SUFFIX:-"svc.cluster.local"} - HostAddress=$(sed -n "/^${LOCAL_IP}/"p /etc/hosts | grep -e "$(hostname).*.${EMQX_CLUSTER__K8S__NAMESPACE}.${EMQX_CLUSTER__K8S__SUFFIX}" -o) - export EMQX_HOST="$HostAddress" + EMQX_HOST="${LOCAL_IP//./-}.$EMQX_CLUSTER__K8S__NAMESPACE.$EMQX_CLUSTER__K8S__SUFFIX" + elif [[ "$EMQX_CLUSTER__K8S__ADDRESS_TYPE" == 'hostname' ]] && [[ -n "$EMQX_CLUSTER__K8S__NAMESPACE" ]]; then + EMQX_CLUSTER__K8S__SUFFIX=${EMQX_CLUSTER__K8S__SUFFIX:-'svc.cluster.local'} + EMQX_HOST=$(grep -h "^$LOCAL_IP" /etc/hosts | grep -o "$(hostname).*.$EMQX_CLUSTER__K8S__NAMESPACE.$EMQX_CLUSTER__K8S__SUFFIX") else - export EMQX_HOST="$LOCAL_IP" + EMQX_HOST="$LOCAL_IP" fi + export EMQX_HOST fi if [[ -z "$EMQX_WAIT_TIME" ]]; then @@ -48,9 +50,6 @@ fi # Set hosts to prevent cluster mode failed -# unset EMQX_NAME -# unset EMQX_HOST - if [[ -z "$EMQX_NODE__PROCESS_LIMIT" ]]; then export EMQX_NODE__PROCESS_LIMIT=2097152 fi @@ -63,129 +62,148 @@ if [[ -z "$EMQX_NODE__MAX_ETS_TABLES" ]]; then export EMQX_NODE__MAX_ETS_TABLES=2097152 fi -if [[ -z "$EMQX__LOG_CONSOLE" ]]; then - export EMQX__LOG_CONSOLE="console" -fi - if [[ -z "$EMQX_LISTENER__TCP__EXTERNAL__ACCEPTORS" ]]; then export EMQX_LISTENER__TCP__EXTERNAL__ACCEPTORS=64 fi -if [[ -z "$EMQX_LISTENER__TCP__EXTERNAL__MAX_CLIENTS" ]]; then - export EMQX_LISTENER__TCP__EXTERNAL__MAX_CLIENTS=1000000 +if [[ -z "$EMQX_LISTENER__TCP__EXTERNAL__MAX_CONNECTIONS" ]]; then + export EMQX_LISTENER__TCP__EXTERNAL__MAX_CONNECTIONS=1024000 fi if [[ -z "$EMQX_LISTENER__SSL__EXTERNAL__ACCEPTORS" ]]; then export EMQX_LISTENER__SSL__EXTERNAL__ACCEPTORS=32 fi -if [[ -z "$EMQX_LISTENER__SSL__EXTERNAL__MAX_CLIENTS" ]]; then - export EMQX_LISTENER__SSL__EXTERNAL__MAX_CLIENTS=500000 +if [[ -z "$EMQX_LISTENER__SSL__EXTERNAL__MAX_CONNECTIONS" ]]; then + export EMQX_LISTENER__SSL__EXTERNAL__MAX_CONNECTIONS=102400 fi if [[ -z "$EMQX_LISTENER__WS__EXTERNAL__ACCEPTORS" ]]; then export EMQX_LISTENER__WS__EXTERNAL__ACCEPTORS=16 fi -if [[ -z "$EMQX_LISTENER__WS__EXTERNAL__MAX_CLIENTS" ]]; then - export EMQX_LISTENER__WS__EXTERNAL__MAX_CLIENTS=250000 +if [[ -z "$EMQX_LISTENER__WS__EXTERNAL__MAX_CONNECTIONS" ]]; then + export EMQX_LISTENER__WS__EXTERNAL__MAX_CONNECTIONS=102400 +fi + +if [[ -z "$EMQX_LISTENER__WSS__EXTERNAL__ACCEPTORS" ]]; then + export EMQX_LISTENER__WSS__EXTERNAL__ACCEPTORS=16 +fi + +if [[ -z "$EMQX_LISTENER__WSS__EXTERNAL__MAX_CONNECTIONS" ]]; then + export EMQX_LISTENER__WSS__EXTERNAL__MAX_CONNECTIONS=102400 fi # Fix issue #42 - export env EMQX_DASHBOARD__DEFAULT_USER__PASSWORD to configure # 'dashboard.default_user.password' in etc/plugins/emqx_dashboard.conf -if [[ ! -z "$EMQX_ADMIN_PASSWORD" ]]; then +if [[ -n "$EMQX_ADMIN_PASSWORD" ]]; then export EMQX_DASHBOARD__DEFAULT_USER__PASSWORD=$EMQX_ADMIN_PASSWORD fi -# echo value of $VAR_FULL_NAME hiding secrets if any -echo_value () { +# echo value of $VAR hiding secrets if any +# SYNOPSIS +# echo_value KEY VALUE +echo_value() { # get MASK_CONFIG MASK_CONFIG_FILTER="$MASK_CONFIG_FILTER|password|passwd|key|token|secret" - FORMAT_MASK_CONFIG_FILTER=$(echo $MASK_CONFIG_FILTER |sed -e "s/^[^A-Za-z0-9_]\{1,\}//g"|sed -e "s/[^A-Za-z0-9_]\{1,\}/\|/g") - + FORMAT_MASK_CONFIG_FILTER=$(echo "$MASK_CONFIG_FILTER" | sed -r -e 's/^[^A-Za-z0-9_]+//' -e 's/[^A-Za-z0-9_]+$//' -e 's/[^A-Za-z0-9_]+/|/g') + local key=$1 + local value=$2 # check if contains sensitive value - if [ ! -z $(echo $(echo $VAR_NAME | tr '.' ' ') |grep -w -o -E "$FORMAT_MASK_CONFIG_FILTER") ]; then - echo "$VAR_NAME=***secret***" + if echo "$key" | grep -iqwE "$FORMAT_MASK_CONFIG_FILTER"; then + echo "$key=***secret***" else - echo "$VAR_NAME=$(eval echo \$$VAR_FULL_NAME)" + echo "$key=$value" fi } -# Catch all EMQX_ prefix environment variable and match it in configure file -CONFIG="${_EMQX_HOME}/etc/emqx.conf" -CONFIG_PLUGINS="${_EMQX_HOME}/etc/plugins" -for VAR in $(env) -do - # Config normal keys such like node.name = emqx@127.0.0.1 - if [[ ! -z "$(echo $VAR | grep -E '^EMQX_')" ]]; then - VAR_NAME=$(echo "$VAR" | sed -r "s/EMQX_([^=]*)=.*/\1/g" | tr '[:upper:]' '[:lower:]' | sed -r "s/__/\./g") - VAR_FULL_NAME=$(echo "$VAR" | sed -r "s/([^=]*)=.*/\1/g") - # Config in emq.conf - if [[ ! -z "$(cat $CONFIG |grep -E "^(^|^#*|^#*\s*)$VAR_NAME")" ]]; then - echo_value - if [[ -z "$(eval echo \$$VAR_FULL_NAME)" ]]; then - echo "$(sed -r "s/(^\s*)($VAR_NAME\s*=\s*.*)/#\2/g" $CONFIG)" > $CONFIG - else - echo "$(sed -r "s/(^#*\s*)($VAR_NAME)\s*=\s*(.*)/\2 = $(eval echo \$$VAR_FULL_NAME|sed -e 's/\//\\\//g')/g" $CONFIG)" > $CONFIG +# fill config on specific file if the key exists +# SYNOPSIS +# try_fill_config FILE KEY VALUE +try_fill_config() { + local file=$1 + local key=$2 + local value=$3 + local escaped_key + # shellcheck disable=SC2001 + escaped_key=$(echo "$key" | sed 's/[^a-zA-Z0-9_]/\\&/g') + local escaped_value + escaped_value=$(echo "$value" | sed 's/[\/&]/\\&/g') + if grep -qE "^[#[:space:]]*$escaped_key\s*=" "$file"; then + echo_value "$key" "$value" + if [[ -z "$value" ]]; then + echo "$(sed -r "s/^[#[:space:]]*($escaped_key)\s*=\s*(.*)/# \1 = \2/" "$file")" > "$file" + else + echo "$(sed -r "s/^[#[:space:]]*($escaped_key)\s*=\s*(.*)/\1 = $escaped_value/" "$file")" > "$file" + fi + # Check if config has a numbering system, but no existing configuration line in file + elif echo "$key" | grep -qE '\.\d+|\d+\.'; then + if [[ -n "$value" ]]; then + local template + template="$(echo "$escaped_key" | sed -r -e 's/\\\.[0-9]+/\\.[0-9]+/g' -e 's/[0-9]+\\\./[0-9]+\\./g')" + if grep -qE "^[#[:space:]]*$template\s*=" "$file"; then + echo_value "$key" "$value" + echo "$(sed '$a'\\ "$file")" > "$file" + echo "$key = $value" >> "$file" fi fi + fi +} + +# Catch all EMQX_ prefix environment variable and match it in configure file +CONFIG_FILE="$_EMQX_HOME/etc/emqx.conf" +CONFIG_PLUGINS="$_EMQX_HOME/etc/plugins" +for VAR in $(compgen -e); do + # Config normal keys such like node.name = emqx@127.0.0.1 + if echo "$VAR" | grep -q '^EMQX_'; then + VAR_NAME=$(echo "$VAR" | sed -e 's/^EMQX_//' -e 's/__/./g' | tr '[:upper:]' '[:lower:]' | tr -d '[:cntrl:]') + VAR_VALUE=$(echo "${!VAR}" | tr -d '[:cntrl:]') + # Config in emqx.conf + try_fill_config "$CONFIG_FILE" "$VAR_NAME" "$VAR_VALUE" # Config in plugins/* - for CONFIG_PLUGINS_FILE in $(ls $CONFIG_PLUGINS); do - if [[ ! -z "$(cat $CONFIG_PLUGINS/$CONFIG_PLUGINS_FILE |grep -E "^(^|^#*|^#*\s*)$VAR_NAME")" ]]; then - echo_value - if [[ -z "$(eval echo \$$VAR_FULL_NAME)" ]]; then - echo "$(sed -r "s/(^\s*)($VAR_NAME\s*=\s*.*)/#\2/g" $CONFIG_PLUGINS/$CONFIG_PLUGINS_FILE)" > $CONFIG_PLUGINS/$CONFIG_PLUGINS_FILE - else - echo "$(sed -r "s/(^#*\s*)($VAR_NAME)\s*=\s*(.*)/\2 = $(eval echo \$$VAR_FULL_NAME|sed -e 's/\//\\\//g')/g" $CONFIG_PLUGINS/$CONFIG_PLUGINS_FILE)" > $CONFIG_PLUGINS/$CONFIG_PLUGINS_FILE - fi - # Check if config has a numbering system, but no existing configuration line in file - elif [[ ! -z "$(echo "$VAR_NAME" | grep '\(\.[0-9]\|[0-9]\.\)')" ]]; then - if [[ ! -z "$(eval echo \$$VAR_FULL_NAME)" ]]; then - VAR_TEMPLATE_NAME="$(echo "$VAR_NAME" | sed -r -e 's|[.]|\\.|g' -e 's|\\.[0-9]+|\\.[0-9]|' -e 's|[0-9]+\\.|[0-9]\\.|')" - if [[ ! -z "$(grep "$VAR_TEMPLATE_NAME" "$CONFIG_PLUGINS/$CONFIG_PLUGINS_FILE")" ]]; then - echo_value - echo "$VAR_NAME = $(eval echo \$$VAR_FULL_NAME)" >> $CONFIG_PLUGINS/$CONFIG_PLUGINS_FILE - fi - fi - fi + for CONFIG_PLUGINS_FILE in "$CONFIG_PLUGINS"/*; do + try_fill_config "$CONFIG_PLUGINS_FILE" "$VAR_NAME" "$VAR_VALUE" done fi done -## EMQX Plugin load settings -# Plugins loaded by default - -if [[ ! -z "$EMQX_LOADED_PLUGINS" ]]; then - echo "EMQX_LOADED_PLUGINS=$EMQX_LOADED_PLUGINS" - # Parse plugin names and place `{plugin_name, true}.` tuples in `loaded_plugins`. - for var in $(echo "$EMQX_LOADED_PLUGINS"|sed -e "s/^[^A-Za-z0-9_]\{1,\}//g"|sed -e "s/[^A-Za-z0-9_]\{1,\}/\ /g"); do - if [ ! -z "$(grep -oE "\{($var),[ ]*(true|false)\}" ${_EMQX_HOME}/data/loaded_plugins)" ]; then - echo "$(sed -r "s/\{($var),[ ]*(true|false)\}./\{\1, true\}./1" ${_EMQX_HOME}/data/loaded_plugins)" > ${_EMQX_HOME}/data/loaded_plugins - elif [ ! -z $(grep -o "$var\." ${_EMQX_HOME}/data/loaded_plugins) ]; then +# fill tuples on specific file +# SYNOPSIS +# fill_tuples FILE [ELEMENTS ...] +fill_tuples() { + local file=$1 + local elements=${*:2} + for var in $elements; do + if grep -qE "\{\s*$var\s*,\s*(true|false)\s*\}\s*\." "$file"; then + echo "$(sed -r "s/\{\s*($var)\s*,\s*(true|false)\s*\}\s*\./{\1, true}./1" "$file")" > "$file" + elif grep -q "$var\s*\." "$file"; then # backward compatible. - echo "$(sed -r "s/($var)./\{\1, true\}./1" ${_EMQX_HOME}/data/loaded_plugins)" > ${_EMQX_HOME}/data/loaded_plugins + echo "$(sed -r "s/($var)\s*\./{\1, true}./1" "$file")" > "$file" else - echo "{$var, true}." >> ${_EMQX_HOME}/data/loaded_plugins + echo "$(sed '$a'\\ "$file")" > "$file" + echo "{$var, true}." >> "$file" fi done +} + +## EMQX Plugin load settings +# Plugins loaded by default +LOADED_PLUGINS="$_EMQX_HOME/data/loaded_plugins" +if [[ -n "$EMQX_LOADED_PLUGINS" ]]; then + EMQX_LOADED_PLUGINS=$(echo "$EMQX_LOADED_PLUGINS" | tr -d '[:cntrl:]' | sed -r -e 's/^[^A-Za-z0-9_]+//g' -e 's/[^A-Za-z0-9_]+$//g' -e 's/[^A-Za-z0-9_]+/ /g') + echo "EMQX_LOADED_PLUGINS=$EMQX_LOADED_PLUGINS" + # Parse module names and place `{module_name, true}.` tuples in `loaded_plugins`. + fill_tuples "$LOADED_PLUGINS" "$EMQX_LOADED_PLUGINS" fi ## EMQX Modules load settings # Modules loaded by default - -if [[ ! -z "$EMQX_LOADED_MODULES" ]]; then +LOADED_MODULES="$_EMQX_HOME/data/loaded_modules" +if [[ -n "$EMQX_LOADED_MODULES" ]]; then + EMQX_LOADED_MODULES=$(echo "$EMQX_LOADED_MODULES" | tr -d '[:cntrl:]' | sed -r -e 's/^[^A-Za-z0-9_]+//g' -e 's/[^A-Za-z0-9_]+$//g' -e 's/[^A-Za-z0-9_]+/ /g') echo "EMQX_LOADED_MODULES=$EMQX_LOADED_MODULES" # Parse module names and place `{module_name, true}.` tuples in `loaded_modules`. - for var in $(echo "$EMQX_LOADED_MODULES"|sed -e "s/^[^A-Za-z0-9_]\{1,\}//g"|sed -e "s/[^A-Za-z0-9_]\{1,\}/\ /g"); do - if [ ! -z "$(grep -oE "\{($var),[ ]*(true|false)\}" ${_EMQX_HOME}/data/loaded_modules)" ]; then - echo "$(sed -r "s/\{($var),[ ]*(true|false)\}./\{\1, true\}./1" ${_EMQX_HOME}/data/loaded_modules)" > ${_EMQX_HOME}/data/loaded_modules - elif [ ! -z $(grep -o "$var\." ${_EMQX_HOME}/data/loaded_modules) ]; then - # backward compatible. - echo "$(sed -r "s/($var)./\{\1, true\}./1" ${_EMQX_HOME}/data/loaded_modules)" > ${_EMQX_HOME}/data/loaded_modules - else - echo "{$var, true}." >> ${_EMQX_HOME}/data/loaded_modules - fi - done + fill_tuples "$LOADED_MODULES" "$EMQX_LOADED_MODULES" fi exec "$@" diff --git a/deploy/packages/README.md b/deploy/packages/README.md index cdb3384f..3843ac41 100644 --- a/deploy/packages/README.md +++ b/deploy/packages/README.md @@ -1,7 +1,7 @@ emqx-packages ============= -EMQ X RPM/Debian Packages +EMQX RPM/Debian Packages NOTICE: Requires Erlang/OTP R21+ to build since 3.0 release. @@ -21,4 +21,4 @@ Apache License Version 2.0 Author ------ -EMQ X Team. +EMQX Team. diff --git a/ensure-rebar3.sh b/ensure-rebar3.sh new file mode 100755 index 00000000..dc2d0476 --- /dev/null +++ b/ensure-rebar3.sh @@ -0,0 +1,26 @@ +#!/bin/sh + +#set -euo pipefail +set -eu + +VERSION="$1" + +DOWNLOAD_URL='https://github.com/emqx/rebar3/releases/download' + +download() { + curl -f -L "${DOWNLOAD_URL}/${VERSION}/rebar3" -o ./rebar3 +} + +# get the version number from the second line of the escript +# because command `rebar3 -v` tries to load rebar.config +# which is slow and may print some logs +version() { + head -n 2 ./rebar3 | tail -n 1 | tr ' ' '\n' | grep -E '^.+-emqx-.+' +} + +if [ -f 'rebar3' ] && [ "$(version)" = "$VERSION" ]; then + exit 0 +fi + +download +chmod +x ./rebar3 diff --git a/inject-deps.escript b/inject-deps.escript new file mode 100755 index 00000000..24fcd62e --- /dev/null +++ b/inject-deps.escript @@ -0,0 +1,139 @@ +#!/usr/bin/env escript + +%% This script injects implicit relup dependencies for emqx applications. +%% +%% By 'implicit', it means that it is not feasible to define application +%% dependencies in .app.src files. +%% +%% For instance, during upgrade/downgrade, emqx_dashboard usually requires +%% a restart after (but not before) all plugins are upgraded (and maybe +%% restarted), however, the dependencies are not resolvable at build time +%% when relup is generated. +%% +%% This script is to be executed after compile, with the profile given as the +%% first argument. For each dependency overlay, it modifies the .app file to +%% have the 'relup_deps' list extended. + +-mode(compile). + +usage() -> + "Usage: " ++ escript:script_name() ++ " emqx|emqx-edge". + +-type app() :: atom(). +-type deps_overlay() :: {re, string()} | app(). + +%% deps/0 returns the dependency overlays. +%% {re, Pattern} to match application names using regexp pattern +-spec deps(string()) -> [{app(), [deps_overlay()]}]. +deps("emqx-edge" ++ _) -> + %% special case for edge + base_deps() ++ [{{re, ".+"}, [{exclude, emqx_reloader}]}]; +deps(_Profile) -> + base_deps(). + +base_deps() -> + [ {emqx_dashboard, [{re, "emqx_.*"}]} + , {emqx_management, [{re, "emqx_.*"}, {exclude, emqx_dashboard}]} + , {{re, "emqx_.*"}, [emqx]} + , {{re, "emqx_auth_.*"}, [emqx_passwd]} + ]. + +main([Profile | _]) -> + ok = inject(Profile); +main(_Args) -> + io:format(standard_error, "~s", [usage()]), + erlang:halt(1). + +expand_names({Name, Deps}, AppNames) -> + Names = match_pattern(Name, AppNames), + [{N, Deps} || N <- Names]. + +%% merge k-v pairs with v1 ++ v2 +merge([], Acc) -> Acc; +merge([{K, V0} | Rest], Acc) -> + V = case lists:keyfind(K, 1, Acc) of + {K, V1} -> V1 ++ V0; + false -> V0 + end, + NewAcc = lists:keystore(K, 1, Acc, {K, V}), + merge(Rest, NewAcc). + +expand_deps([], _AppNames, Acc) -> Acc; +expand_deps([{exclude, Dep} | Deps], AppNames, Acc) -> + Matches = expand_deps([Dep], AppNames, []), + expand_deps(Deps, AppNames, Acc -- Matches); +expand_deps([Dep | Deps], AppNames, Acc) -> + NewAcc = add_to_list(Acc, match_pattern(Dep, AppNames)), + expand_deps(Deps, AppNames, NewAcc). + +inject(Profile) -> + LibDir = lib_dir(Profile), + AppNames = list_apps(LibDir), + Deps0 = lists:flatmap(fun(Dep) -> expand_names(Dep, AppNames) end, deps(Profile)), + Deps1 = merge(Deps0, []), + Deps2 = lists:map(fun({Name, DepsX}) -> + NewDeps = expand_deps(DepsX, AppNames, []), + {Name, NewDeps} + end, Deps1), + lists:foreach(fun({App, Deps}) -> inject(App, Deps, LibDir) end, Deps2). + +%% list the profile/lib dir to get all apps +list_apps(LibDir) -> + Apps = filelib:wildcard("*", LibDir), + lists:foldl(fun(App, Acc) -> [App || is_app(LibDir, App)] ++ Acc end, [], Apps). + +is_app(_LibDir, "." ++ _) -> false; %% ignore hidden dir +is_app(LibDir, AppName) -> + filelib:is_regular(filename:join([ebin_dir(LibDir, AppName), AppName ++ ".app"])) orelse + error({unknown_app, AppName}). %% wtf + +lib_dir(Profile) -> + filename:join(["_build", Profile, lib]). + +ebin_dir(LibDir, AppName) -> filename:join([LibDir, AppName, "ebin"]). + +inject(App0, DepsToAdd, LibDir) -> + App = str(App0), + AppEbinDir = ebin_dir(LibDir, App), + [AppFile0] = filelib:wildcard("*.app", AppEbinDir), + AppFile = filename:join(AppEbinDir, AppFile0), + {ok, [{application, AppName, Props}]} = file:consult(AppFile), + Deps0 = case lists:keyfind(relup_deps, 1, Props) of + {_, X} -> X; + false -> [] + end, + %% merge extra deps, but do not self-include + Deps = add_to_list(Deps0, DepsToAdd) -- [App0], + case Deps =:= [] of + true -> ok; + _ -> + NewProps = lists:keystore(relup_deps, 1, Props, {relup_deps, Deps}), + AppSpec = {application, AppName, NewProps}, + AppSpecIoData = io_lib:format("~p.", [AppSpec]), + io:format(user, "updated_relup_deps for ~p~n", [App]), + file:write_file(AppFile, AppSpecIoData) + end. + +str(A) when is_atom(A) -> atom_to_list(A). + +match_pattern({re, Re}, AppNames) -> + Match = fun(AppName) -> re:run(AppName, Re) =/= nomatch end, + AppNamesToAdd = lists:filter(Match, AppNames), + AppsToAdd = lists:map(fun(N) -> list_to_atom(N) end, AppNamesToAdd), + case AppsToAdd =:= [] of + true -> error({nomatch, Re}); + false -> AppsToAdd + end; +match_pattern(NameAtom, AppNames) -> + case lists:member(str(NameAtom), AppNames) of + true -> [NameAtom]; + false -> error({notfound, NameAtom}) + end. + +%% Append elements to list without duplication. No reordering. +add_to_list(List, []) -> List; +add_to_list(List, [H | T]) -> + case lists:member(H, List) of + true -> add_to_list(List, T); + false -> add_to_list(List ++ [H], T) + end. diff --git a/rebar.config.script b/rebar.config.script index 38804a91..9a60cbb2 100644 --- a/rebar.config.script +++ b/rebar.config.script @@ -1,8 +1,8 @@ %%-*- mode: erlang -*- -%% ============================================================================== +%% ============================================================================= %% maybe upload coverdata -%% ============================================================================== +%% ============================================================================= CONFIG0 = case os:getenv("TRAVIS") of "true" -> @@ -14,9 +14,9 @@ CONFIG0 = case os:getenv("TRAVIS") of CONFIG end, -%% ============================================================================== +%% ============================================================================= %% Dependencies -%% ============================================================================== +%% ============================================================================= PluginsNeededByElixir = [rebar_mix, {rebar3_elixir_compile, {git, "https://github.com/barrel-db/rebar3_elixir_compile.git", @@ -33,7 +33,7 @@ Kf = fun(K, L) -> {K, V} = lists:keyfind(K, 1, L), V end, ElixirDeps0 -> Plugins = Kf(plugins, CONFIG0), NewConfig = lists:keydelete(plugins, 1, CONFIG0), - Plugins1 = {plugins, PluginsNeededByElixir ++ Plugins}, + Plugins1 = {plugins, Plugins ++ PluginsNeededByElixir}, {ElixirDeps0, [Plugins1, HooksNeededByElixir, OptsNeededByElixir | NewConfig]} end, @@ -125,9 +125,9 @@ DefaultDepRef = end end, -%% ============================================================================== +%% ============================================================================= %% Relx configs -%% ============================================================================== +%% ============================================================================= GitDescribe = begin T = case DefaultDepRef of @@ -169,22 +169,30 @@ TestDeps = [ {meck, "0.8.13"} % hex , {emqx_ct_helpers, {git, "https://github.com/emqx/emqx-ct-helpers", {tag, "v1.1.1"}}} ], -%% ============================================================================== +%% ============================================================================= %% Profiles -%% ============================================================================== +%% ============================================================================= Profiles = -[ {emqx, [ {deps, MakeDeps(CloudDeps, DefaultDepRef, [])} - , {relx, RelxCloud([cloud, bin])} - ]} -, {'emqx-pkg', [ {deps, MakeDeps(CloudDeps, DefaultDepRef, [])} - , {relx, RelxCloud([cloud, pkg])} - ]} -, {'emqx-edge', [ {deps, MakeDeps(EdgeDeps, DefaultDepRef, [])} - , {relx, RelxEdge([edge, bin])} - ]} -, {'emqx-edge-pkg', [ {deps, MakeDeps(EdgeDeps, DefaultDepRef, [])} - , {relx, RelxEdge([edge, pkg])} - ]} +[ {emqx, + [ {deps, MakeDeps(CloudDeps, DefaultDepRef, [])} + , {relx, RelxCloud([cloud, bin])} + , {post_hooks, [{"(linux|darwin|solaris|freebsd|netbsd|openbsd)", compile, "./inject-deps.escript emqx"}]} + ]} +, {'emqx-pkg', + [ {deps, MakeDeps(CloudDeps, DefaultDepRef, [])} + , {relx, RelxCloud([cloud, pkg])} + , {post_hooks, [{"(linux|darwin|solaris|freebsd|netbsd|openbsd)", compile, "./inject-deps.escript emqx-pkg"}]} + ]} +, {'emqx-edge', + [ {deps, MakeDeps(EdgeDeps, DefaultDepRef, [])} + , {relx, RelxEdge([edge, bin])} + , {post_hooks, [{"(linux|darwin|solaris|freebsd|netbsd|openbsd)", compile, "./inject-deps.escript emqx-edge"}]} + ]} +, {'emqx-edge-pkg', + [ {deps, MakeDeps(EdgeDeps, DefaultDepRef, [])} + , {relx, RelxEdge([edge, pkg])} + , {post_hooks, [{"(linux|darwin|solaris|freebsd|netbsd|openbsd)", compile, "./inject-deps.escript emqx-edge-pkg"}]} + ]} ], Deletes = [ deps diff --git a/rebar3 b/rebar3 deleted file mode 100755 index 6cd9d429..00000000 Binary files a/rebar3 and /dev/null differ