├── .ci ├── build_packages │ ├── Dockerfile │ ├── tests.sh │ └── upload_github_release_asset.sh ├── deps_tests │ ├── boot.py │ ├── docker-compose.yaml │ ├── emqx-erlang │ │ └── Dockerfile │ ├── emqx-ldap │ │ ├── Dockerfile │ │ ├── schema │ │ │ ├── emqx.io.ldif │ │ │ └── emqx.schema │ │ └── slapd.conf │ ├── emqx-nginx │ │ ├── Dockerfile │ │ └── default.conf │ └── emqx-redis │ │ ├── Dockerfile │ │ └── redis.conf ├── nightly_build │ ├── http_server │ │ ├── .gitignore │ │ ├── LICENSE │ │ ├── README.md │ │ ├── rebar.config │ │ └── src │ │ │ ├── http_server.app.src │ │ │ └── http_server.erl │ └── relup.lux └── paho_tests │ ├── Makefile │ └── docker-compose.yaml ├── .github ├── ISSUE_TEMPLATE.md └── workflows │ ├── build_cross_packages.yaml │ ├── run_deps_tests.yaml │ ├── run_paho_tests.yaml │ └── run_relup_tests.yaml ├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── bin ├── emqx ├── emqx.cmd ├── emqx_ctl ├── emqx_ctl.cmd ├── emqx_env ├── install_upgrade.escript └── nodetool ├── data ├── emqx_vars ├── loaded_modules.tmpl └── loaded_plugins.tmpl ├── deploy ├── charts │ └── emqx │ │ ├── Chart.yaml │ │ ├── README.md │ │ ├── templates │ │ ├── StatefulSet.yaml │ │ ├── _helpers.tpl │ │ ├── configmap.yaml │ │ ├── configmap_for_acl.yaml │ │ ├── ingress.yaml │ │ ├── rbac.yaml │ │ └── service.yaml │ │ └── values.yaml ├── docker │ ├── Dockerfile │ ├── README.md │ ├── docker-entrypoint.sh │ └── start.sh └── packages │ ├── README.md │ ├── deb │ ├── Makefile │ └── debian │ │ ├── changelog │ │ ├── compat │ │ ├── control │ │ ├── copyright │ │ ├── init.script │ │ ├── postinst │ │ ├── postrm │ │ └── rules │ └── rpm │ ├── Makefile │ ├── emqx.service │ ├── emqx.spec │ └── init.script ├── docker.mk ├── ensure-rebar3.sh ├── get-lastest-tag.escript ├── inject-deps.escript ├── packages.mk ├── post-compile.cmd ├── post-compile.sh ├── rebar.config ├── rebar.config.script ├── rebar3.cmd ├── vars-bin.config ├── vars-cloud.config ├── vars-edge.config └── vars-pkg.config /.ci/build_packages/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG BUILD_FROM=emqx/build-env:erl22.3-ubuntu20.04 2 | FROM ${BUILD_FROM} 3 | 4 | ARG EMQX_NAME=emqx 5 | 6 | COPY . /emqx-rel 7 | 8 | WORKDIR /emqx-rel 9 | 10 | RUN sed -i "/^export LC_ALL=.*$/d" Makefile && make ${EMQX_NAME}-pkg || cat rebar3.crashdump 11 | 12 | RUN /emqx-rel/.ci/build_packages/tests.sh 13 | -------------------------------------------------------------------------------- /.ci/build_packages/tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -x -e -u 3 | export EMQX_NAME=${EMQX_NAME:-"emqx"} 4 | export PACKAGE_PATH="/emqx-rel/_packages/${EMQX_NAME}" 5 | export RELUP_PACKAGE_PATH="/emqx-rel/relup_packages/${EMQX_NAME}" 6 | # export EMQX_NODE_NAME="emqx-on-$(uname -m)@127.0.0.1" 7 | # export EMQX_NODE_COOKIE=$(date +%s%N) 8 | 9 | emqx_prepare(){ 10 | mkdir -p ${PACKAGE_PATH} 11 | 12 | if [ ! -d "/paho-mqtt-testing" ]; then 13 | git clone -b develop-4.0 https://github.com/emqx/paho.mqtt.testing.git /paho-mqtt-testing 14 | fi 15 | pip3 install pytest 16 | } 17 | 18 | emqx_test(){ 19 | cd ${PACKAGE_PATH} 20 | 21 | for var in $(ls $PACKAGE_PATH/${EMQX_NAME}-*);do 22 | case ${var##*.} in 23 | "zip") 24 | packagename=`basename ${PACKAGE_PATH}/${EMQX_NAME}-*.zip` 25 | unzip -q ${PACKAGE_PATH}/$packagename 26 | sed -i "/zone.external.server_keepalive/c zone.external.server_keepalive = 60" ${PACKAGE_PATH}/emqx/etc/emqx.conf 27 | sed -i "/mqtt.max_topic_alias/c mqtt.max_topic_alias = 10" ${PACKAGE_PATH}/emqx/etc/emqx.conf 28 | 29 | if [ ! -z $(echo ${EMQX_DEPS_DEFAULT_VSN#v} | grep -oE "[0-9]+\.[0-9]+(\.[0-9]+)?-(alpha|beta|rc)\.[0-9]") ]; then 30 | if [ ! -d ${PACKAGE_PATH}/emqx/lib/emqx-${EMQX_DEPS_DEFAULT_VSN#v} ] || [ ! -d ${PACKAGE_PATH}/emqx/releases/${EMQX_DEPS_DEFAULT_VSN#v} ] ;then 31 | echo "emqx zip version error" 32 | exit 1 33 | fi 34 | fi 35 | 36 | echo "running ${packagename} start" 37 | ${PACKAGE_PATH}/emqx/bin/emqx start || tail ${PACKAGE_PATH}/emqx/log/erlang.log.1 38 | IDLE_TIME=0 39 | while [ -z "$(${PACKAGE_PATH}/emqx/bin/emqx_ctl status |grep 'is running'|awk '{print $1}')" ] 40 | do 41 | if [ $IDLE_TIME -gt 10 ] 42 | then 43 | echo "emqx running error" 44 | exit 1 45 | fi 46 | sleep 10 47 | IDLE_TIME=$((IDLE_TIME+1)) 48 | done 49 | pytest -v /paho-mqtt-testing/interoperability/test_client/V5/test_connect.py::test_basic 50 | ${PACKAGE_PATH}/emqx/bin/emqx stop 51 | echo "running ${packagename} stop" 52 | rm -rf ${PACKAGE_PATH}/emqx 53 | ;; 54 | "deb") 55 | packagename=`basename ${PACKAGE_PATH}/${EMQX_NAME}-*.deb` 56 | dpkg -i ${PACKAGE_PATH}/$packagename 57 | if [ $(dpkg -l |grep emqx |awk '{print $1}') != "ii" ] 58 | then 59 | echo "package install error" 60 | exit 1 61 | fi 62 | 63 | echo "running ${packagename} start" 64 | running_test 65 | echo "running ${packagename} stop" 66 | 67 | dpkg -r ${EMQX_NAME} 68 | if [ $(dpkg -l |grep emqx |awk '{print $1}') != "rc" ] 69 | then 70 | echo "package remove error" 71 | exit 1 72 | fi 73 | 74 | dpkg -P ${EMQX_NAME} 75 | if [ ! -z "$(dpkg -l |grep emqx)" ] 76 | then 77 | echo "package uninstall error" 78 | exit 1 79 | fi 80 | ;; 81 | "rpm") 82 | packagename=`basename ${PACKAGE_PATH}/${EMQX_NAME}-*.rpm` 83 | rpm -ivh ${PACKAGE_PATH}/$packagename 84 | if [ -z $(rpm -q emqx | grep -o emqx) ];then 85 | echo "package install error" 86 | exit 1 87 | fi 88 | 89 | echo "running ${packagename} start" 90 | running_test 91 | echo "running ${packagename} stop" 92 | 93 | rpm -e ${EMQX_NAME} 94 | if [ "$(rpm -q emqx)" != "package emqx is not installed" ];then 95 | echo "package uninstall error" 96 | exit 1 97 | fi 98 | ;; 99 | 100 | esac 101 | done 102 | } 103 | 104 | running_test(){ 105 | if [ ! -z $(echo ${EMQX_DEPS_DEFAULT_VSN#v} | grep -oE "[0-9]+\.[0-9]+(\.[0-9]+)?-(alpha|beta|rc)\.[0-9]") ]; then 106 | if [ ! -d /usr/lib/emqx/lib/emqx-${EMQX_DEPS_DEFAULT_VSN#v} ] || [ ! -d /usr/lib/emqx/releases/${EMQX_DEPS_DEFAULT_VSN#v} ];then 107 | echo "emqx package version error" 108 | exit 1 109 | fi 110 | fi 111 | 112 | sed -i "/zone.external.server_keepalive/c zone.external.server_keepalive = 60" /etc/emqx/emqx.conf 113 | sed -i "/mqtt.max_topic_alias/c mqtt.max_topic_alias = 10" /etc/emqx/emqx.conf 114 | 115 | emqx start || tail /var/log/emqx/erlang.log.1 116 | IDLE_TIME=0 117 | while [ -z "$(emqx_ctl status |grep 'is running'|awk '{print $1}')" ] 118 | do 119 | if [ $IDLE_TIME -gt 10 ] 120 | then 121 | echo "emqx running error" 122 | exit 1 123 | fi 124 | sleep 10 125 | IDLE_TIME=$((IDLE_TIME+1)) 126 | done 127 | pytest -v /paho-mqtt-testing/interoperability/test_client/V5/test_connect.py::test_basic 128 | emqx stop || kill $(ps -ef |grep emqx | grep beam.smp |awk '{print $2}') 129 | 130 | if [ $(sed -n '/^ID=/p' /etc/os-release | sed -r 's/ID=(.*)/\1/g' | sed 's/"//g') = ubuntu ] \ 131 | || [ $(sed -n '/^ID=/p' /etc/os-release | sed -r 's/ID=(.*)/\1/g' | sed 's/"//g') = debian ] \ 132 | || [ $(sed -n '/^ID=/p' /etc/os-release | sed -r 's/ID=(.*)/\1/g' | sed 's/"//g') = raspbian ];then 133 | service emqx start || tail /var/log/emqx/erlang.log.1 134 | IDLE_TIME=0 135 | while [ -z "$(emqx_ctl status |grep 'is running'|awk '{print $1}')" ] 136 | do 137 | if [ $IDLE_TIME -gt 10 ] 138 | then 139 | echo "emqx service error" 140 | exit 1 141 | fi 142 | sleep 10 143 | IDLE_TIME=$((IDLE_TIME+1)) 144 | done 145 | service emqx stop 146 | fi 147 | } 148 | 149 | relup_test(){ 150 | if [ -d ${RELUP_PACKAGE_PATH} ];then 151 | cd ${RELUP_PACKAGE_PATH } 152 | 153 | for var in $(ls ${EMQX_NAME}-*-$(uname -m).zip);do 154 | packagename=`basename ${var}` 155 | unzip $packagename 156 | ./emqx/bin/emqx start 157 | ./emqx/bin/emqx_ctl status 158 | ./emqx/bin/emqx versions 159 | cp ${PACKAGE_PATH}/${EMQX_NAME}-*-${EMQX_DEPS_DEFAULT_VSN#v}-$(uname -m).zip ./emqx/releases 160 | ./emqx/bin/emqx install ${EMQX_DEPS_DEFAULT_VSN#v} 161 | [ $(./emqx/bin/emqx versions |grep permanent | grep -oE "[0-9].[0-9].[0-9]") = ${EMQX_DEPS_DEFAULT_VSN#v} ] || exit 1 162 | ./emqx/bin/emqx_ctl status 163 | ./emqx/bin/emqx stop 164 | rm -rf emqx 165 | done 166 | fi 167 | } 168 | 169 | emqx_prepare 170 | emqx_test 171 | relup_test 172 | -------------------------------------------------------------------------------- /.ci/build_packages/upload_github_release_asset.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Author: Stefan Buck 4 | # License: MIT 5 | # https://gist.github.com/stefanbuck/ce788fee19ab6eb0b4447a85fc99f447 6 | # 7 | # 8 | # This script accepts the following parameters: 9 | # 10 | # * owner 11 | # * repo 12 | # * tag 13 | # * filename 14 | # * github_api_token 15 | # 16 | # Script to upload a release asset using the GitHub API v3. 17 | # 18 | # Example: 19 | # 20 | # upload-github-release-asset.sh github_api_token=TOKEN owner=stefanbuck repo=playground tag=v0.1.0 filename=./build.zip 21 | # 22 | 23 | # Check dependencies. 24 | set -e 25 | xargs=$(which gxargs || which xargs) 26 | 27 | # Validate settings. 28 | [ "$TRACE" ] && set -x 29 | 30 | CONFIG=$@ 31 | 32 | for line in $CONFIG; do 33 | eval "$line" 34 | done 35 | 36 | # Define variables. 37 | GH_API="https://api.github.com" 38 | GH_REPO="$GH_API/repos/$owner/$repo" 39 | GH_TAGS="$GH_REPO/releases/tags/$tag" 40 | AUTH="Authorization: token $github_api_token" 41 | WGET_ARGS="--content-disposition --auth-no-challenge --no-cookie" 42 | CURL_ARGS="-LJO#" 43 | 44 | if [[ "$tag" == 'LATEST' ]]; then 45 | GH_TAGS="$GH_REPO/releases/latest" 46 | fi 47 | 48 | # Validate token. 49 | curl -o /dev/null -sH "$AUTH" $GH_REPO || { echo "Error: Invalid repo, token or network issue!"; exit 1; } 50 | 51 | # Read asset tags. 52 | response=$(curl -sH "$AUTH" $GH_TAGS) 53 | 54 | # Get ID of the asset based on given filename. 55 | eval $(echo "$response" | grep -m 1 "id.:" | grep -w id | tr : = | tr -cd '[[:alnum:]]=') 56 | [ "$id" ] || { echo "Error: Failed to get release id for tag: $tag"; echo "$response" | awk 'length($0)<100' >&2; exit 1; } 57 | 58 | # Upload asset 59 | # Construct url 60 | GH_ASSET="https://uploads.github.com/repos/$owner/$repo/releases/$id/assets?name=$(basename $filename)" 61 | 62 | curl "$GITHUB_OAUTH_BASIC" --data-binary @"$filename" -H "Authorization: token $github_api_token" -H "Content-Type: application/octet-stream" $GH_ASSET 63 | -------------------------------------------------------------------------------- /.ci/deps_tests/boot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | ## 3 | import os 4 | import sys 5 | import re 6 | from bs4 import BeautifulSoup 7 | 8 | ## get all test catalog 9 | def get_test_all_catalog(name): 10 | CatalogList = [] 11 | PackageNameList = [] 12 | filepath = os.path.join(os.getcwd(), name) 13 | packagenames = os.listdir(name) 14 | for packagename in packagenames: 15 | tmp_path = os.path.join(filepath, packagename) 16 | if os.path.isdir(tmp_path): 17 | CatalogList.append(tmp_path) 18 | PackageNameList.append(packagename) 19 | return CatalogList, PackageNameList 20 | 21 | ## Start Galaxy Engine 22 | ## Save index. d by extracting important information from index.html. 23 | ## extract index.html and deal with path information in index.html 24 | def extract_core_content(path, filename, packagename): 25 | filepath = os.path.join(path, filename) 26 | if os.path.exists(filepath): 27 | fopen = open(filepath) 28 | filecontent = fopen.read() 29 | original_core_content = re.findall(r"<\s*body[^>]*>(.+?)
Copyright", filecontent, re.S) 30 | content = original_core_content[0] 31 | core_content = content.replace('Copyright(.+?)<\s*/\s*html\s*>", re.S) 42 | original_core_content = re_data.sub('', filecontent) 43 | replacecontent = original_core_content.replace('(.+?)", re.S) 48 | replacecontent = ra_title.sub(' Test Result ', replacecontent) 49 | return replacecontent 50 | 51 | # Splicing content 52 | def splicing_content(name, filename): 53 | CoreContent = [] 54 | index = 0, 55 | CatalogList, PackageNameList = get_test_all_catalog(name) 56 | for catalog, packageName in zip(CatalogList, PackageNameList): 57 | if(index == (0,)): 58 | Content = replace_href(catalog, filename, packageName) 59 | CoreContent.append(Content) 60 | index = 1 61 | else: 62 | Content = extract_core_content(catalog, filename, packageName) 63 | CoreContent.append(Content) 64 | str = "" 65 | con = str.join('%s' % id for id in CoreContent) 66 | con = con + "" 67 | return con 68 | 69 | ## process data statistics 70 | def data_statistics(filestream): 71 | soup_string = BeautifulSoup(filestream, "html.parser") 72 | body_datas = soup_string.find_all("tbody") 73 | testpluginList = [] 74 | testmoudleList = [] 75 | testsuccessList = [] 76 | testfailList = [] 77 | testskipList = [] 78 | allsuccessValue = allfailValue = allSkipValue = 0 79 | for body_data in body_datas: 80 | ## test moudle data 81 | # testmoudledata = body_data.find_all("a") 82 | testplugindata = body_data.find_all("tr") 83 | for testplugin in testplugindata: 84 | data = testplugin.find_all("td") 85 | testpluginname = data[8] 86 | con = testpluginname.find("a")['href'] 87 | re_data = re.compile(r"\\ct_run(.+?).html", re.S) 88 | re_data = re_data.sub('', con) 89 | testpluginList.append(str(re_data)) 90 | testmoudledata = testplugin.find_all("a")[0] 91 | testmoudleList.append(testmoudledata) 92 | successdata = data[3] 93 | testsuccessList.append(successdata) 94 | faildata = data[4] 95 | testfailList.append(faildata) 96 | skipdata = data[5] 97 | testskipList.append(skipdata) 98 | ## get all value 99 | testallvalues = soup_string.find_all("tfoot") 100 | for testallvalue in testallvalues: 101 | data = testallvalue.find_all("td") 102 | allsuccessValue += int(data[3].string) 103 | allfailValue += int(data[4].string) 104 | datas = str(data[5].string) 105 | re_skipdata = re.compile("(.+?)/", re.S) 106 | datas = str(re_skipdata.sub('', datas)).replace(")", "") 107 | allSkipValue += int(datas) 108 | tbody = "" 109 | table_head = "

Data Outline


" 110 | for testplugin, testmoudle, testsuccess, testfail, testskip in zip(testpluginList, testmoudleList, testsuccessList, testfailList, testskipList): 111 | moudlebody = "".format(testmoudle) 112 | successbody = "{}".format(testsuccess) 113 | failbody = "{}".format(testfail) 114 | skipbody = "{}".format(testskip) 115 | pluginbody = "".format(testplugin) 116 | tbody += str(moudlebody) + str(successbody) +str(failbody) + str(skipbody) + str(pluginbody) 117 | totalbody = "
Test NameSuccessFailedSkipedPlugin Name
{}{}
Total{}{}{} 
".format(allsuccessValue, allfailValue, allSkipValue) 118 | outline_head = "

Executing Plugin Name


" 119 | catalogList, packageNameList = get_test_all_catalog("logs") 120 | successPluginData = "" 121 | failedPluginData = "" 122 | for catalog, packagename in zip(catalogList, packageNameList): 123 | successPlugin, failedPlugin = outline_value(catalog, packagename) 124 | successPluginData += successPlugin + " " 125 | failedPluginData += failedPlugin +" " 126 | outline_body_value = "
All Test Plugin NameSuccess extract Log plugin nameEmpty plugin name
{}{}{}
".format(packageNameList, successPluginData, failedPluginData) 127 | data_outline_html = outline_head + outline_body_value + table_head + tbody + totalbody 128 | 129 | return data_outline_html, allfailValue 130 | 131 | def outline_value(path, pluginName): 132 | filepath = os.path.join(path, "index.html") 133 | successPlugin = "" 134 | failedPlugin = "" 135 | if os.path.exists(filepath): 136 | successPlugin = pluginName 137 | else: 138 | failedPlugin = pluginName 139 | return successPlugin, failedPlugin 140 | 141 | def produceHtml(): 142 | htmldata = splicing_content("logs", "index.html") 143 | data_outline_html, allfailValue = data_statistics(htmldata) 144 | headdatamatch = re.match(r"]*>", htmldata, re.S) 145 | headdata = "" 146 | if headdatamatch: 147 | headdata = headdatamatch.group() 148 | # re_data = re.compile(r"]*>", re.S) 149 | replacedata = headdata + data_outline_html 150 | htmldata = htmldata.replace(headdata, replacedata) 151 | savepath = os.path.join(os.getcwd(), "logs") 152 | savepath = os.path.join(savepath, "index.html") 153 | if os.path.exists(savepath): 154 | os.remove(savepath) 155 | f = open(savepath, 'w') 156 | f.write(htmldata) 157 | f.close 158 | 159 | ## send exit message when failed 160 | if allfailValue >0 : 161 | exit(1) 162 | # htmldata = splicing_content("logs", "index.html") 163 | # data_statistics(htmldata) 164 | produceHtml() -------------------------------------------------------------------------------- /.ci/deps_tests/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | nginx: 5 | build: ./emqx-nginx 6 | image: emqx-nginx:1.15 7 | restart: always 8 | ports: 9 | - "18080:80" 10 | networks: 11 | - emqx_bridge 12 | volumes: 13 | - ../../tests/logs:/usr/share/nginx/html 14 | 15 | emqx: 16 | build: ./emqx-erlang 17 | image: emqx-erlang 18 | depends_on: 19 | - mysql_server 20 | - redis_server 21 | - mongo_server 22 | - pgsql_server 23 | - ldap_server 24 | networks: 25 | - emqx_bridge 26 | volumes: 27 | - ../../.:/emqx-rel 28 | working_dir: /emqx-rel 29 | tty: true 30 | 31 | python: 32 | image: python:3.7.2 33 | networks: 34 | - emqx_bridge 35 | volumes: 36 | - ../../.:/emqx-rel 37 | tty: true 38 | 39 | mysql_server: 40 | image: mysql:5.7 41 | restart: always 42 | environment: 43 | MYSQL_ROOT_PASSWORD: public 44 | MYSQL_DATABASE: mqtt 45 | volumes: 46 | - ../../_build/emqx/lib/emqx_auth_mysql/test/emqx_auth_mysql_SUITE_data/ca.pem:/etc/certs/ca-cert.pem 47 | - ../../_build/emqx/lib/emqx_auth_mysql/test/emqx_auth_mysql_SUITE_data/server-cert.pem:/etc/certs/server-cert.pem 48 | - ../../_build/emqx/lib/emqx_auth_mysql/test/emqx_auth_mysql_SUITE_data/server-key.pem:/etc/certs/server-key.pem 49 | networks: 50 | - emqx_bridge 51 | command: 52 | --bind-address 0.0.0.0 53 | --default-authentication-plugin=mysql_native_password 54 | --character-set-server=utf8mb4 55 | --collation-server=utf8mb4_general_ci 56 | --explicit_defaults_for_timestamp=true 57 | --lower_case_table_names=1 58 | --max_allowed_packet=128M 59 | --skip-symbolic-links 60 | --ssl-ca=/etc/certs/ca.pem 61 | --ssl-cert=/etc/certs/server-cert.pem 62 | --ssl-key=/etc/certs/server-key.pem 63 | 64 | redis_server: 65 | build: ./emqx-redis 66 | image: emqx-redis:5 67 | restart: always 68 | networks: 69 | - emqx_bridge 70 | 71 | mongo_server: 72 | image: mongo:4.1 73 | restart: always 74 | environment: 75 | MONGO_INITDB_DATABASE: mqtt 76 | networks: 77 | - emqx_bridge 78 | command: --bind_ip_all 79 | 80 | pgsql_server: 81 | image: postgres:11 82 | restart: always 83 | environment: 84 | POSTGRES_PASSWORD: public 85 | POSTGRES_USER: root 86 | POSTGRES_DB: mqtt 87 | networks: 88 | - emqx_bridge 89 | 90 | ldap_server: 91 | build: ./emqx-ldap 92 | image: emqx-ldap:1.0 93 | restart: always 94 | networks: 95 | - emqx_bridge 96 | 97 | networks: 98 | emqx_bridge: 99 | driver: bridge 100 | 101 | volumes: 102 | logs-volumes: 103 | -------------------------------------------------------------------------------- /.ci/deps_tests/emqx-erlang/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM erlang:22.3 2 | 3 | # RUN curl -L -o /tmp/openjdk-14.0.1_linux-x64_bin.tar.gz https://download.java.net/java/GA/jdk14.0.1/664493ef4a6946b186ff29eb326336a2/7/GPL/openjdk-14.0.1_linux-x64_bin.tar.gz \ 4 | # && tar xvf /tmp/openjdk-14.0.1_linux-x64_bin.tar.gz -C /usr/local 5 | # 6 | # ENV PATH=/usr/local/jdk-14.0.1/bin:$PATH 7 | 8 | # RUN wget --no-cookies \ 9 | # --no-check-certificate \ 10 | # --header "Cookie: oraclelicense=accept-securebackup-cookie" \ 11 | # https://download.oracle.com/otn-pub/java/jdk/8u251-b08/3d5a2bb8f8d4428bbe94aed7ec7ae784/jdk-8u251-linux-x64.tar.gz \ 12 | # -O /tmp/jdk-8u251-linux-x64.tar.gz \ 13 | # && tar xvf /tmp/jdk-8u251-linux-x64.tar.gz -C /usr/local 14 | # 15 | # ENV PATH=/usr/local/jdk1.8.0_251/bin:$PATH 16 | 17 | RUN wget https://download.java.net/openjdk/jdk8u41/ri/openjdk-8u41-b04-linux-x64-14_jan_2020.tar.gz \ 18 | -O /tmp/openjdk8.tar.gz \ 19 | && tar xvf /tmp/openjdk8.tar.gz -C /usr/local 20 | 21 | ENV PATH=/usr/local/java-se-8u41-ri/bin:$PATH 22 | -------------------------------------------------------------------------------- /.ci/deps_tests/emqx-ldap/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM buildpack-deps:stretch 2 | 3 | ENV VERSION=2.4.50 4 | 5 | RUN apt-get update && apt-get install -y groff groff-base 6 | RUN wget ftp://ftp.openldap.org/pub/OpenLDAP/openldap-release/openldap-${VERSION}.tgz \ 7 | && gunzip -c openldap-${VERSION}.tgz | tar xvfB - \ 8 | && cd openldap-${VERSION} \ 9 | && ./configure && make depend && make && make install \ 10 | && cd .. && rm -rf openldap-${VERSION} 11 | 12 | COPY ./slapd.conf /usr/local/etc/openldap/slapd.conf 13 | COPY ./emqx.io.ldif /usr/local/etc/openldap/schema/emqx.io.ldif 14 | COPY ./emqx.schema /usr/local/etc/openldap/schema/emqx.schema 15 | COPY ./*.pem /usr/local/etc/openldap/ 16 | 17 | RUN mkdir -p /usr/local/etc/openldap/data \ 18 | && slapadd -l /usr/local/etc/openldap/schema/emqx.io.ldif -f /usr/local/etc/openldap/slapd.conf 19 | 20 | WORKDIR /usr/local/etc/openldap 21 | 22 | EXPOSE 389 636 23 | 24 | ENTRYPOINT ["/usr/local/libexec/slapd", "-h", "ldap:/// ldaps:///", "-d", "3", "-f", "/usr/local/etc/openldap/slapd.conf"] 25 | 26 | CMD [] 27 | -------------------------------------------------------------------------------- /.ci/deps_tests/emqx-ldap/schema/emqx.io.ldif: -------------------------------------------------------------------------------- 1 | ## create emqx.io 2 | 3 | dn:dc=emqx,dc=io 4 | objectclass: top 5 | objectclass: dcobject 6 | objectclass: organization 7 | dc:emqx 8 | o:emqx,Inc. 9 | 10 | # create testdevice.emqx.io 11 | dn:ou=testdevice,dc=emqx,dc=io 12 | objectClass: top 13 | objectclass:organizationalUnit 14 | ou:testdevice 15 | 16 | # create user admin 17 | dn:uid=admin,ou=testdevice,dc=emqx,dc=io 18 | objectClass: top 19 | objectClass: simpleSecurityObject 20 | objectClass: account 21 | userPassword:: e1NIQX1XNnBoNU1tNVB6OEdnaVVMYlBnekczN21qOWc9 22 | uid: admin 23 | 24 | ## create user=mqttuser0001, 25 | # password=mqttuser0001, 26 | # passhash={SHA}mlb3fat40MKBTXUVZwCKmL73R/0= 27 | # base64passhash=e1NIQX1tbGIzZmF0NDBNS0JUWFVWWndDS21MNzNSLzA9 28 | dn:uid=mqttuser0001,ou=testdevice,dc=emqx,dc=io 29 | objectClass: top 30 | objectClass: mqttUser 31 | objectClass: mqttDevice 32 | objectClass: mqttSecurity 33 | uid: mqttuser0001 34 | isEnabled: TRUE 35 | mqttPublishTopic: mqttuser0001/pub/1 36 | mqttPublishTopic: mqttuser0001/pub/+ 37 | mqttPublishTopic: mqttuser0001/pub/# 38 | mqttSubscriptionTopic: mqttuser0001/sub/1 39 | mqttSubscriptionTopic: mqttuser0001/sub/+ 40 | mqttSubscriptionTopic: mqttuser0001/sub/# 41 | mqttPubSubTopic: mqttuser0001/pubsub/1 42 | mqttPubSubTopic: mqttuser0001/pubsub/+ 43 | mqttPubSubTopic: mqttuser0001/pubsub/# 44 | userPassword:: e1NIQX1tbGIzZmF0NDBNS0JUWFVWWndDS21MNzNSLzA9 45 | 46 | ## create user=mqttuser0002 47 | # password=mqttuser0002, 48 | # passhash={SSHA}n9XdtoG4Q/TQ3TQF4Y+khJbMBH4qXj4M 49 | # base64passhash=e1NTSEF9bjlYZHRvRzRRL1RRM1RRRjRZK2toSmJNQkg0cVhqNE0= 50 | dn:uid=mqttuser0002,ou=testdevice,dc=emqx,dc=io 51 | objectClass: top 52 | objectClass: mqttUser 53 | objectClass: mqttDevice 54 | objectClass: mqttSecurity 55 | uid: mqttuser0002 56 | isEnabled: TRUE 57 | mqttPublishTopic: mqttuser0002/pub/1 58 | mqttPublishTopic: mqttuser0002/pub/+ 59 | mqttPublishTopic: mqttuser0002/pub/# 60 | mqttSubscriptionTopic: mqttuser0002/sub/1 61 | mqttSubscriptionTopic: mqttuser0002/sub/+ 62 | mqttSubscriptionTopic: mqttuser0002/sub/# 63 | mqttPubSubTopic: mqttuser0002/pubsub/1 64 | mqttPubSubTopic: mqttuser0002/pubsub/+ 65 | mqttPubSubTopic: mqttuser0002/pubsub/# 66 | userPassword:: e1NTSEF9bjlYZHRvRzRRL1RRM1RRRjRZK2toSmJNQkg0cVhqNE0= 67 | 68 | ## create user mqttuser0003 69 | # password=mqttuser0003, 70 | # passhash={MD5}ybsPGoaK3nDyiQvveiCOIw== 71 | # base64passhash=e01ENX15YnNQR29hSzNuRHlpUXZ2ZWlDT0l3PT0= 72 | dn:uid=mqttuser0003,ou=testdevice,dc=emqx,dc=io 73 | objectClass: top 74 | objectClass: mqttUser 75 | objectClass: mqttDevice 76 | objectClass: mqttSecurity 77 | uid: mqttuser0003 78 | isEnabled: TRUE 79 | mqttPublishTopic: mqttuser0003/pub/1 80 | mqttPublishTopic: mqttuser0003/pub/+ 81 | mqttPublishTopic: mqttuser0003/pub/# 82 | mqttSubscriptionTopic: mqttuser0003/sub/1 83 | mqttSubscriptionTopic: mqttuser0003/sub/+ 84 | mqttSubscriptionTopic: mqttuser0003/sub/# 85 | mqttPubSubTopic: mqttuser0003/pubsub/1 86 | mqttPubSubTopic: mqttuser0003/pubsub/+ 87 | mqttPubSubTopic: mqttuser0003/pubsub/# 88 | userPassword:: e01ENX15YnNQR29hSzNuRHlpUXZ2ZWlDT0l3PT0= 89 | 90 | ## create user mqttuser0004 91 | # password=mqttuser0004, 92 | # passhash={MD5}2Br6pPDSEDIEvUlu9+s+MA== 93 | # base64passhash=e01ENX0yQnI2cFBEU0VESUV2VWx1OStzK01BPT0= 94 | dn:uid=mqttuser0004,ou=testdevice,dc=emqx,dc=io 95 | objectClass: top 96 | objectClass: mqttUser 97 | objectClass: mqttDevice 98 | objectClass: mqttSecurity 99 | uid: mqttuser0004 100 | isEnabled: TRUE 101 | mqttPublishTopic: mqttuser0004/pub/1 102 | mqttPublishTopic: mqttuser0004/pub/+ 103 | mqttPublishTopic: mqttuser0004/pub/# 104 | mqttSubscriptionTopic: mqttuser0004/sub/1 105 | mqttSubscriptionTopic: mqttuser0004/sub/+ 106 | mqttSubscriptionTopic: mqttuser0004/sub/# 107 | mqttPubSubTopic: mqttuser0004/pubsub/1 108 | mqttPubSubTopic: mqttuser0004/pubsub/+ 109 | mqttPubSubTopic: mqttuser0004/pubsub/# 110 | userPassword: {MD5}2Br6pPDSEDIEvUlu9+s+MA== 111 | 112 | ## create user mqttuser0005 113 | # password=mqttuser0005, 114 | # passhash={SHA}jKnxeEDGR14kE8AR7yuVFOelhz4= 115 | # base64passhash=e1NIQX1qS254ZUVER1IxNGtFOEFSN3l1VkZPZWxoejQ9 116 | objectClass: top 117 | dn:uid=mqttuser0005,ou=testdevice,dc=emqx,dc=io 118 | objectClass: mqttUser 119 | objectClass: mqttDevice 120 | objectClass: mqttSecurity 121 | uid: mqttuser0005 122 | isEnabled: TRUE 123 | mqttPublishTopic: mqttuser0005/pub/1 124 | mqttPublishTopic: mqttuser0005/pub/+ 125 | mqttPublishTopic: mqttuser0005/pub/# 126 | mqttSubscriptionTopic: mqttuser0005/sub/1 127 | mqttSubscriptionTopic: mqttuser0005/sub/+ 128 | mqttSubscriptionTopic: mqttuser0005/sub/# 129 | mqttPubSubTopic: mqttuser0005/pubsub/1 130 | mqttPubSubTopic: mqttuser0005/pubsub/+ 131 | mqttPubSubTopic: mqttuser0005/pubsub/# 132 | userPassword: {SHA}jKnxeEDGR14kE8AR7yuVFOelhz4= -------------------------------------------------------------------------------- /.ci/deps_tests/emqx-ldap/schema/emqx.schema: -------------------------------------------------------------------------------- 1 | # 2 | # Preliminary Apple OS X Native LDAP Schema 3 | # This file is subject to change. 4 | # 5 | attributetype ( 1.3.6.1.4.1.11.2.53.2.2.3.1.2.3.1.3 NAME 'isEnabled' 6 | EQUALITY booleanMatch 7 | SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 8 | SINGLE-VALUE 9 | USAGE userApplications ) 10 | 11 | attributetype ( 1.3.6.1.4.1.11.2.53.2.2.3.1.2.3.4.1 NAME ( 'mqttPublishTopic' 'mpt' ) 12 | EQUALITY caseIgnoreMatch 13 | SUBSTR caseIgnoreSubstringsMatch 14 | SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 15 | USAGE userApplications ) 16 | attributetype ( 1.3.6.1.4.1.11.2.53.2.2.3.1.2.3.4.2 NAME ( 'mqttSubscriptionTopic' 'mst' ) 17 | EQUALITY caseIgnoreMatch 18 | SUBSTR caseIgnoreSubstringsMatch 19 | SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 20 | USAGE userApplications ) 21 | attributetype ( 1.3.6.1.4.1.11.2.53.2.2.3.1.2.3.4.3 NAME ( 'mqttPubSubTopic' 'mpst' ) 22 | EQUALITY caseIgnoreMatch 23 | SUBSTR caseIgnoreSubstringsMatch 24 | SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 25 | USAGE userApplications ) 26 | 27 | objectclass ( 1.3.6.1.4.1.11.2.53.2.2.3.1.2.3.4 NAME 'mqttUser' 28 | AUXILIARY 29 | MAY ( mqttPublishTopic $ mqttSubscriptionTopic $ mqttPubSubTopic) ) 30 | 31 | objectclass ( 1.3.6.1.4.1.11.2.53.2.2.3.1.2.3.2 NAME 'mqttDevice' 32 | SUP top 33 | STRUCTURAL 34 | MUST ( uid ) 35 | MAY ( isEnabled ) ) 36 | 37 | objectclass ( 1.3.6.1.4.1.11.2.53.2.2.3.1.2.3.3 NAME 'mqttSecurity' 38 | SUP top 39 | AUXILIARY 40 | MAY ( userPassword $ userPKCS12 $ pwdAttribute $ pwdLockout ) ) -------------------------------------------------------------------------------- /.ci/deps_tests/emqx-ldap/slapd.conf: -------------------------------------------------------------------------------- 1 | include /usr/local/etc/openldap/schema/core.schema 2 | include /usr/local/etc/openldap/schema/cosine.schema 3 | include /usr/local/etc/openldap/schema/inetorgperson.schema 4 | include /usr/local/etc/openldap/schema/ppolicy.schema 5 | include /usr/local/etc/openldap/schema/emqx.schema 6 | 7 | TLSCACertificateFile /usr/local/etc/openldap/cacert.pem 8 | TLSCertificateFile /usr/local/etc/openldap/cert.pem 9 | TLSCertificateKeyFile /usr/local/etc/openldap/key.pem 10 | 11 | database bdb 12 | suffix "dc=emqx,dc=io" 13 | rootdn "cn=root,dc=emqx,dc=io" 14 | rootpw {SSHA}eoF7NhNrejVYYyGHqnt+MdKNBh4r1w3W 15 | 16 | directory /usr/local/etc/openldap/data 17 | -------------------------------------------------------------------------------- /.ci/deps_tests/emqx-nginx/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx:1.15 2 | COPY default.conf /etc/nginx/conf.d/default.conf -------------------------------------------------------------------------------- /.ci/deps_tests/emqx-nginx/default.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | server_name localhost; 4 | autoindex on; 5 | 6 | #charset koi8-r; 7 | #access_log /var/log/nginx/host.access.log main; 8 | 9 | location / { 10 | root /usr/share/nginx/html; 11 | index index.html index.htm; 12 | } 13 | 14 | #error_page 404 /404.html; 15 | 16 | # redirect server error pages to the static page /50x.html 17 | # 18 | error_page 500 502 503 504 /50x.html; 19 | location = /50x.html { 20 | root /usr/share/nginx/html; 21 | } 22 | 23 | # proxy the PHP scripts to Apache listening on 127.0.0.1:80 24 | # 25 | #location ~ \.php$ { 26 | # proxy_pass http://127.0.0.1; 27 | #} 28 | 29 | # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 30 | # 31 | #location ~ \.php$ { 32 | # root html; 33 | # fastcgi_pass 127.0.0.1:9000; 34 | # fastcgi_index index.php; 35 | # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; 36 | # include fastcgi_params; 37 | #} 38 | 39 | # deny access to .htaccess files, if Apache's document root 40 | # concurs with nginx's one 41 | # 42 | #location ~ /\.ht { 43 | # deny all; 44 | #} 45 | } 46 | 47 | -------------------------------------------------------------------------------- /.ci/deps_tests/emqx-redis/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM redis:5 2 | COPY redis.conf /usr/local/etc/redis/redis.conf 3 | CMD [ "redis-server", "/usr/local/etc/redis/redis.conf" ] -------------------------------------------------------------------------------- /.ci/nightly_build/http_server/.gitignore: -------------------------------------------------------------------------------- 1 | .rebar3 2 | _* 3 | .eunit 4 | *.o 5 | *.beam 6 | *.plt 7 | *.swp 8 | *.swo 9 | .erlang.cookie 10 | ebin 11 | log 12 | erl_crash.dump 13 | .rebar 14 | logs 15 | _build 16 | .idea 17 | *.iml 18 | rebar3.crashdump 19 | *~ 20 | -------------------------------------------------------------------------------- /.ci/nightly_build/http_server/LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | Copyright 2020, zhanghongtong . 179 | 180 | Licensed under the Apache License, Version 2.0 (the "License"); 181 | you may not use this file except in compliance with the License. 182 | You may obtain a copy of the License at 183 | 184 | http://www.apache.org/licenses/LICENSE-2.0 185 | 186 | Unless required by applicable law or agreed to in writing, software 187 | distributed under the License is distributed on an "AS IS" BASIS, 188 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 189 | See the License for the specific language governing permissions and 190 | limitations under the License. 191 | 192 | -------------------------------------------------------------------------------- /.ci/nightly_build/http_server/README.md: -------------------------------------------------------------------------------- 1 | http_server 2 | ===== 3 | 4 | An OTP application 5 | 6 | Build 7 | ----- 8 | 9 | $ rebar3 compile 10 | -------------------------------------------------------------------------------- /.ci/nightly_build/http_server/rebar.config: -------------------------------------------------------------------------------- 1 | {erl_opts, [debug_info]}. 2 | {deps, 3 | [ 4 | {minirest, {git, "https://github.com/emqx/minirest.git", {tag, "0.3.1"}}} 5 | ]}. 6 | 7 | {shell, [ 8 | % {config, "config/sys.config"}, 9 | {apps, [http_server]} 10 | ]}. 11 | -------------------------------------------------------------------------------- /.ci/nightly_build/http_server/src/http_server.app.src: -------------------------------------------------------------------------------- 1 | {application, http_server, 2 | [{description, "An OTP application"}, 3 | {vsn, "0.1.0"}, 4 | {registered, []}, 5 | % {mod, {http_server_app, []}}, 6 | {modules, []}, 7 | {applications, 8 | [kernel, 9 | stdlib, 10 | minirest 11 | ]}, 12 | {env,[]}, 13 | {modules, []}, 14 | 15 | {licenses, ["Apache 2.0"]}, 16 | {links, []} 17 | ]}. 18 | -------------------------------------------------------------------------------- /.ci/nightly_build/http_server/src/http_server.erl: -------------------------------------------------------------------------------- 1 | -module(http_server). 2 | 3 | -import(minirest, [ return/0 4 | , return/1 5 | ]). 6 | 7 | -export([ start/0 8 | , stop/0 9 | ]). 10 | 11 | -rest_api(#{ name => get_counter 12 | , method => 'GET' 13 | , path => "/counter" 14 | , func => get_counter 15 | , descr => "Check counter" 16 | }). 17 | -rest_api(#{ name => add_counter 18 | , method => 'POST' 19 | , path => "/counter" 20 | , func => add_counter 21 | , descr => "Counter plus one" 22 | }). 23 | 24 | -export([ get_counter/2 25 | , add_counter/2 26 | ]). 27 | 28 | start() -> 29 | application:ensure_all_started(minirest), 30 | ets:new(relup_test_message, [named_table, public]), 31 | Handlers = [{"/", minirest:handler(#{modules => [?MODULE]})}], 32 | Dispatch = [{"/[...]", minirest, Handlers}], 33 | minirest:start_http(?MODULE, #{socket_opts => [inet, {port, 8080}]}, Dispatch). 34 | 35 | stop() -> 36 | ets:delete(relup_test_message), 37 | minirest:stop_http(?MODULE). 38 | 39 | get_counter(_Binding, _Params) -> 40 | return({ok, ets:info(relup_test_message, size)}). 41 | 42 | add_counter(_Binding, Params) -> 43 | case lists:keymember(<<"payload">>, 1, Params) of 44 | true -> 45 | {value, {<<"id">>, ID}, Params1} = lists:keytake(<<"id">>, 1, Params), 46 | ets:insert(relup_test_message, {ID, Params1}); 47 | _ -> 48 | ok 49 | end, 50 | return(). 51 | -------------------------------------------------------------------------------- /.ci/nightly_build/relup.lux: -------------------------------------------------------------------------------- 1 | [config var=PACKAGE_PATH] 2 | [config var=BENCH_PATH] 3 | [config var=ONE_MORE_EMQX_PATH] 4 | [config var=TAG] 5 | [config var=OLD_TAGS] 6 | 7 | [config shell_cmd=/bin/bash] 8 | [config timeout=600000] 9 | 10 | [loop old_tag $OLD_TAGS] 11 | 12 | [shell http_server] 13 | !cd http_server 14 | !rebar3 shell 15 | ???Eshell 16 | ???> 17 | !http_server:start(). 18 | ?Start http_server listener on 8080 successfully. 19 | ?ok 20 | ?> 21 | 22 | [shell emqx] 23 | !cd $PACKAGE_PATH 24 | !unzip -q -o emqx-ubuntu20.04-$old_tag-x86_64.zip 25 | ?SH-PROMPT 26 | 27 | !cd emqx 28 | !sed -i 's|listener.wss.external[ \t]*=.*|listener.wss.external = 8085|g' etc/emqx.conf 29 | !./bin/emqx start 30 | ?EMQ X Broker $old_tag is started successfully! 31 | 32 | !./bin/emqx_ctl status 33 | """? 34 | Node 'emqx@127.0.0.1' is started 35 | emqx $old_tag is running 36 | """ 37 | 38 | [shell emqx2] 39 | !cd $PACKAGE_PATH 40 | !cp $ONE_MORE_EMQX_PATH/one_more_emqx.sh . 41 | !./one_more_emqx.sh emqx2 42 | ?SH-PROMPT 43 | !cd emqx2 44 | 45 | !./bin/emqx start 46 | ?EMQ X Broker $old_tag is started successfully! 47 | 48 | !./bin/emqx_ctl status 49 | """? 50 | Node 'emqx2@127.0.0.1' is started 51 | emqx $old_tag is running 52 | """ 53 | ?SH-PROMPT 54 | 55 | !./bin/emqx_ctl cluster join emqx@127.0.0.1 56 | ???Join the cluster successfully. 57 | ?SH-PROMPT 58 | 59 | !./bin/emqx_ctl cluster status 60 | """??? 61 | Cluster status: #{running_nodes => ['emqx2@127.0.0.1','emqx@127.0.0.1'], 62 | stopped_nodes => []} 63 | """ 64 | ?SH-PROMPT 65 | 66 | !./bin/emqx_ctl resources create 'web_hook' -i 'resource:691c29ba' -c '{"url": "http://127.0.0.1:8080/counter", "method": "POST"}' 67 | ?created 68 | ?SH-PROMPT 69 | !./bin/emqx_ctl rules create 'SELECT * FROM "t/#"' '[{"name":"data_to_webserver", "params": {"$$resource": "resource:691c29ba"}}]' 70 | ?created 71 | ?SH-PROMPT 72 | 73 | [shell emqx] 74 | !./bin/emqx_ctl resources list 75 | ?691c29ba 76 | ?SH-PROMPT 77 | !./bin/emqx_ctl rules list 78 | ?691c29ba 79 | ?SH-PROMPT 80 | 81 | [shell bench] 82 | !cd $BENCH_PATH 83 | !./emqtt_bench pub -c 10 -I 1000 -t t/%i -s 64 -L 300 84 | ???sent 85 | 86 | [shell emqx] 87 | !cp -f ../emqx-ubuntu20.04-$TAG-x86_64.zip releases/ 88 | !./bin/emqx install $TAG 89 | ?SH-PROMPT 90 | !./bin/emqx versions |grep permanent | grep -oE "[0-9].[0-9].[0-9]" 91 | ?$TAG 92 | ?SH-PROMPT 93 | 94 | !./bin/emqx_ctl cluster status 95 | """??? 96 | Cluster status: #{running_nodes => ['emqx2@127.0.0.1','emqx@127.0.0.1'], 97 | stopped_nodes => []} 98 | """ 99 | ?SH-PROMPT 100 | 101 | [shell emqx2] 102 | !cp -f ../emqx-ubuntu20.04-$TAG-x86_64.zip releases/ 103 | !./bin/emqx install $TAG 104 | ?SH-PROMPT 105 | !./bin/emqx versions |grep permanent | grep -oE "[0-9].[0-9].[0-9]" 106 | ?$TAG 107 | ?SH-PROMPT 108 | 109 | !./bin/emqx_ctl cluster status 110 | """??? 111 | Cluster status: #{running_nodes => ['emqx2@127.0.0.1','emqx@127.0.0.1'], 112 | stopped_nodes => []} 113 | """ 114 | ?SH-PROMPT 115 | 116 | [shell bench] 117 | ???publish complete 118 | ??SH-PROMPT: 119 | # !curl http://127.0.0.1:8080/counter 120 | # ???{"data":300,"code":0} 121 | # ?SH-PROMPT 122 | 123 | [shell http_server] 124 | !http_server:stop(). 125 | ?ok 126 | ?> 127 | !halt(3). 128 | ?SH-PROMPT: 129 | 130 | [shell emqx2] 131 | # !cat log/emqx.log.1 |grep -v 691c29ba |tail -n 100 132 | # -error 133 | # ??SH-PROMPT: 134 | 135 | !./bin/emqx stop 136 | ?ok 137 | ?SH-PROMPT: 138 | 139 | !rm -rf $PACKAGE_PATH/emqx2 140 | ?SH-PROMPT: 141 | 142 | [shell emqx] 143 | # !cat log/emqx.log.1 |grep -v 691c29ba |tail -n 100 144 | # -error 145 | # ??SH-PROMPT: 146 | 147 | !./bin/emqx stop 148 | ?ok 149 | ?SH-PROMPT: 150 | 151 | !rm -rf $PACKAGE_PATH/emqx 152 | ?SH-PROMPT: 153 | 154 | [endloop] 155 | 156 | [cleanup] 157 | !rm -rf $PACKAGE_PATH/one_more_emqx.sh 158 | ?SH-PROMPT: 159 | !echo ==$$?== 160 | ?==0== 161 | -------------------------------------------------------------------------------- /.ci/paho_tests/Makefile: -------------------------------------------------------------------------------- 1 | ## default globals 2 | TARGET ?= emqx/emqx 3 | EMQX_NAME = $(subst emqx/,,$(TARGET)) 4 | 5 | .PHONY: all 6 | all: test 7 | 8 | define wait_emqx 9 | @while [ "$$(docker inspect -f '{{ .State.Health.Status}}' $$(docker ps -a -q -f name=paho_test_emqx1))" != "healthy" ] || [ "$$(docker inspect -f '{{ .State.Health.Status}}' $$(docker ps -a -q -f name=paho_test_emqx2))" != "healthy" ]; do \ 10 | if [ $$(docker ps -a -f name=paho_test_emqx -f status=exited -q | wc -l) -ne 0 ]; then \ 11 | echo "['$$(date -u +"%Y-%m-%dT%H:%M:%SZ")']:emqx stop"; \ 12 | exit; \ 13 | else \ 14 | echo "['$$(date -u +"%Y-%m-%dT%H:%M:%SZ")']:waiting emqx"; \ 15 | sleep 5; \ 16 | fi; \ 17 | done 18 | endef 19 | 20 | .PHONY: create_container 21 | create_container: clean 22 | @docker-compose -p paho_test up -d 23 | 24 | $(call wait_emqx) 25 | 26 | .PHONY: test 27 | test: create_container 28 | @docker exec -i $$(docker ps -a -q -f name=paho_test_client) sh -c "apk update && apk add git curl \ 29 | && git clone -b $(PAHO_BRANCH) https://github.com/emqx/paho.mqtt.testing.git /paho.mqtt.testing \ 30 | && pip install pytest \ 31 | && pytest -v /paho.mqtt.testing/interoperability/test_client/ --host node1.emqx.io" 32 | 33 | @docker-compose -p paho_test down 34 | 35 | .PHONY: cluster_test 36 | cluster_test: create_container 37 | @docker exec -i $$(docker ps -a -q -f name=paho_test_client) sh -c "apk update && apk add git curl \ 38 | && git clone -b $(PAHO_BRANCH) https://github.com/emqx/paho.mqtt.testing.git /paho.mqtt.testing \ 39 | && pip install pytest \ 40 | && pytest -v /paho.mqtt.testing/interoperability/test_client/V5/test_connect.py -k test_basic --host node1.emqx.io \ 41 | && pytest -v /paho.mqtt.testing/interoperability/test_cluster --host1 node1.emqx.io --host2 node2.emqx.io" 42 | 43 | @docker-compose -p paho_test down 44 | 45 | .PHONY: clean 46 | clean: 47 | @if [ ! -z "$$(docker ps -a -q -f name=paho_test)" ]; then docker-compose -p paho_test down; fi 48 | -------------------------------------------------------------------------------- /.ci/paho_tests/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | emqx1: 5 | image: emqx/emqx:build-alpine-amd64 6 | environment: 7 | - "EMQX_NAME=emqx" 8 | - "EMQX_HOST=node1.emqx.io" 9 | - "EMQX_CLUSTER__DISCOVERY=static" 10 | - "EMQX_CLUSTER__STATIC__SEEDS=emqx@node1.emqx.io, emqx@node2.emqx.io" 11 | - "EMQX_ZONE__EXTERNAL__RETRY_INTERVAL=2s" 12 | - "EMQX_MQTT__MAX_TOPIC_ALIAS=10" 13 | command: 14 | - /bin/sh 15 | - -c 16 | - | 17 | sed -i "s 127.0.0.1 $$(ip route show |grep "link" |awk '{print $$1}') g" /opt/emqx/etc/acl.conf 18 | /usr/bin/start.sh 19 | healthcheck: 20 | test: ["CMD", "/opt/emqx/bin/emqx_ctl", "status"] 21 | interval: 5s 22 | timeout: 25s 23 | retries: 5 24 | networks: 25 | emqx-bridge: 26 | aliases: 27 | - node1.emqx.io 28 | 29 | emqx2: 30 | image: emqx/emqx:build-alpine-amd64 31 | environment: 32 | - "EMQX_NAME=emqx" 33 | - "EMQX_HOST=node2.emqx.io" 34 | - "EMQX_CLUSTER__DISCOVERY=static" 35 | - "EMQX_CLUSTER__STATIC__SEEDS=emqx@node1.emqx.io, emqx@node2.emqx.io" 36 | - "EMQX_ZONE__EXTERNAL__RETRY_INTERVAL=2s" 37 | - "EMQX_MQTT__MAX_TOPIC_ALIAS=10" 38 | command: 39 | - /bin/sh 40 | - -c 41 | - | 42 | sed -i "s 127.0.0.1 $$(ip route show |grep "link" |awk '{print $$1}') g" /opt/emqx/etc/acl.conf 43 | /usr/bin/start.sh 44 | healthcheck: 45 | test: ["CMD", "/opt/emqx/bin/emqx_ctl", "status"] 46 | interval: 5s 47 | timeout: 25s 48 | retries: 5 49 | networks: 50 | emqx-bridge: 51 | aliases: 52 | - node2.emqx.io 53 | 54 | client: 55 | image: python:3.7.2-alpine3.9 56 | depends_on: 57 | - emqx1 58 | - emqx2 59 | tty: true 60 | networks: 61 | emqx-bridge: 62 | 63 | networks: 64 | emqx-bridge: 65 | driver: bridge 66 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | #### Environment 2 | 3 | - OS: 4 | - Erlang/OTP: 5 | - EMQ: 6 | 7 | #### Description 8 | 9 | *A description of the issue* 10 | -------------------------------------------------------------------------------- /.github/workflows/run_deps_tests.yaml: -------------------------------------------------------------------------------- 1 | name: Run deps tests 2 | 3 | on: 4 | push: 5 | tags: 6 | - v* 7 | workflow_dispatch: 8 | inputs: 9 | version: 10 | required: true 11 | repository_dispatch: 12 | types: [run_tests] 13 | 14 | jobs: 15 | run_deps_tests: 16 | runs-on: ubuntu-latest 17 | 18 | steps: 19 | - uses: actions/checkout@v1 20 | - name: get deps 21 | run: | 22 | if [ ${{ github.event_name}} = 'repository_dispatch' ]; then 23 | version=${{ github.event.client_payload.version }} 24 | elif [ ${{ github.event_name}} = 'workflow_dispatch' ]; then 25 | version=${{ github.event.inputs.version }} 26 | else 27 | version=$(echo ${{ github.ref }} | sed -r "s ^refs/heads/|^refs/tags/(.*) \1 g") 28 | fi 29 | docker run -i --rm \ 30 | -e EMQX_DEPS_DEFAULT_VSN=$version \ 31 | -v $(pwd):/emqx-rel \ 32 | -w /emqx-rel \ 33 | emqx/build-env:erl22.3-debian10 \ 34 | bash -c "make deps-emqx" 35 | - name: Install docker-compose 36 | run: | 37 | 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 38 | sudo chmod +x /usr/local/bin/docker-compose 39 | - name: docker-compose build 40 | run: | 41 | cp _build/emqx/lib/emqx_auth_ldap/emqx.io.ldif .ci/deps_tests/emqx-ldap 42 | cp _build/emqx/lib/emqx_auth_ldap/emqx.schema .ci/deps_tests/emqx-ldap 43 | cp _build/emqx/lib/emqx_auth_ldap/test/certs/* .ci/deps_tests/emqx-ldap 44 | docker-compose -f .ci/deps_tests/docker-compose.yaml build --no-cache 45 | docker network create --driver bridge --ipv6 --subnet fd15:555::/64 emqx_auto_func_test_emqx_bridge 46 | - name: docker-compose up 47 | run: docker-compose -p emqx_auto_func_test -f .ci/deps_tests/docker-compose.yaml up -d 48 | - name: set config files 49 | run: | 50 | cd _build/emqx/lib 51 | sudo chmod -R 777 ./emqx*/etc 52 | for var in $(ls |grep emqx); do 53 | if [ $var == "emqx_auth_mysql" ];then 54 | sed -i "/auth.mysql.server/c auth.mysql.server = mysql_server:3306" ./$var/etc/emqx_auth_mysql.conf 55 | echo "auth.mysql.username = root" >> ./$var/etc/emqx_auth_mysql.conf 56 | echo "auth.mysql.password = public" >> ./$var/etc/emqx_auth_mysql.conf 57 | 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 58 | echo "auth.mysql.ssl.certfile = /emqx-rel/_build/emqx/lib/emqx_auth_mysql/test/emqx_auth_mysql_SUITE_data/client-cert.pem" >> ./$var/etc/emqx_auth_mysql.conf 59 | echo "auth.mysql.ssl.keyfile = /emqx-rel/_build/emqx/lib/emqx_auth_mysql/test/emqx_auth_mysql_SUITE_data/client-key.pem" >> ./$var/etc/emqx_auth_mysql.conf 60 | fi 61 | if [ $var == "emqx_auth_redis" ];then 62 | sed -i "/auth.redis.server/c auth.redis.server = redis_server:6379" ./$var/etc/emqx_auth_redis.conf 63 | fi 64 | if [ $var == "emqx_auth_mongo" ];then 65 | sed -i "/auth.mongo.server/c auth.mongo.server = mongo_server:27017" ./$var/etc/emqx_auth_mongo.conf 66 | fi 67 | if [ $var == "emqx_auth_pgsql" ];then 68 | sed -i "/auth.pgsql.server/c auth.pgsql.server = pgsql_server:5432" ./$var/etc/emqx_auth_pgsql.conf 69 | fi 70 | if [ $var == "emqx_auth_ldap" ];then 71 | sed -i "/auth.ldap.servers/c auth.ldap.servers = ldap_server" ./$var/etc/emqx_auth_ldap.conf 72 | fi 73 | done 74 | cd - 75 | - name: run all test cases 76 | run: docker exec emqx_auto_func_test_emqx_1 bash -c "make -C /emqx-rel ct -k" 77 | - name: get the results 78 | if: always() 79 | run: docker exec emqx_auto_func_test_python_1 bash -c "pip install --upgrade pip && pip install beautifulsoup4 && cd /emqx-rel/tests && python /emqx-rel/.ci/deps_tests/boot.py" 80 | - uses: actions/upload-artifact@v1 81 | if: always() 82 | with: 83 | name: logs 84 | path: tests/logs 85 | -------------------------------------------------------------------------------- /.github/workflows/run_paho_tests.yaml: -------------------------------------------------------------------------------- 1 | name: Run paho tests 2 | 3 | on: 4 | push: 5 | tags: 6 | - v* 7 | workflow_dispatch: 8 | inputs: 9 | version: 10 | required: true 11 | repository_dispatch: 12 | types: [run_tests] 13 | 14 | jobs: 15 | 16 | run_paho_tests: 17 | 18 | runs-on: ubuntu-latest 19 | 20 | steps: 21 | - name: Install docker-compose 22 | run: | 23 | 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 24 | sudo chmod +x /usr/local/bin/docker-compose 25 | - uses: actions/checkout@v1 26 | - name: get deps 27 | run: | 28 | if [ ${{ github.event_name}} = 'repository_dispatch' ]; then 29 | version=${{ github.event.client_payload.version }} 30 | elif [ ${{ github.event_name}} = 'workflow_dispatch' ]; then 31 | version=${{ github.event.inputs.version }} 32 | else 33 | version=$(echo ${{ github.ref }} | sed -r "s ^refs/heads/|^refs/tags/(.*) \1 g") 34 | fi 35 | 36 | docker run -i --rm \ 37 | -e EMQX_DEPS_DEFAULT_VSN=$version \ 38 | -v $(pwd):/emqx-rel \ 39 | -w /emqx-rel \ 40 | emqx/build-env:erl22.3-debian10 \ 41 | bash -c "make deps-emqx" 42 | - name: make emqx image 43 | run: TARGET=emqx/emqx make docker-build 44 | - name: make paho tests 45 | run: TARGET=emqx/emqx PAHO_BRANCH="develop-4.0" make -C .ci/paho_tests test 46 | -------------------------------------------------------------------------------- /.github/workflows/run_relup_tests.yaml: -------------------------------------------------------------------------------- 1 | name: Run relup tests 2 | 3 | on: 4 | push: 5 | tags: 6 | - v* 7 | workflow_dispatch: 8 | inputs: 9 | version: 10 | required: true 11 | 12 | jobs: 13 | run_relup_test: 14 | runs-on: ubuntu-20.04 15 | container: emqx/build-env:erl22.3-ubuntu20.04 16 | defaults: 17 | run: 18 | shell: bash 19 | steps: 20 | # - uses: bajankristof/setup-erlang@master 21 | # with: 22 | # otp-version: 22.3 23 | # allow-cache: false 24 | # - uses: actions/setup-python@v2 25 | # with: 26 | # python-version: '3.8' 27 | # architecture: 'x64' 28 | # - uses: actions/checkout@v2 29 | # with: 30 | # repository: emqx/paho.mqtt.testing 31 | # ref: develop-4.0 32 | # path: paho.mqtt.testing 33 | - uses: actions/checkout@v2 34 | with: 35 | repository: terry-xiaoyu/one_more_emqx 36 | ref: master 37 | path: one_more_emqx 38 | - uses: actions/checkout@v2 39 | with: 40 | repository: emqx/emqtt-bench 41 | ref: master 42 | path: emqtt-bench 43 | - uses: actions/checkout@v2 44 | with: 45 | repository: hawk/lux 46 | ref: lux-2.4 47 | path: lux 48 | - uses: actions/checkout@v2 49 | with: 50 | repository: emqx/emqx-rel 51 | path: emqx-rel 52 | fetch-depth: 0 53 | - name: get version 54 | run: | 55 | set -e -x -u 56 | cd emqx-rel 57 | if [ $(echo $GITHUB_REF | grep -o -E "[ev0-9]+.[0-9]+.[0-9]+?") ]; then 58 | tag="$(echo $GITHUB_REF | grep -oE '[ev0-9]+.[0-9]+.[0-9]+?')" 59 | else 60 | tag=$(./get-lastest-tag.escript tag) 61 | fi 62 | echo "TAG=$tag" >> $GITHUB_ENV 63 | pre_tag="$(echo $tag | grep -oE '^[ev0-9]+.[0-9]+')" 64 | old_tags="$(git tag -l "$pre_tag.[0-9]*" | grep -v $tag | tr "\n" " " )" 65 | echo "OLD_TAGS=$old_tags" >> $GITHUB_ENV 66 | - name: download emqx 67 | run: | 68 | set -e -x -u 69 | cd emqx-rel 70 | old_tags=($(echo $OLD_TAGS | tr ' ' ' ')) 71 | for old_tag in ${old_tags[@]}; do 72 | wget https://s3-us-west-2.amazonaws.com/packages.emqx/emqx-ce/$old_tag/emqx-ubuntu20.04-${old_tag#[e|v]}-x86_64.zip 73 | done 74 | - name: build emqx 75 | run: | 76 | set -e -x -u 77 | make -C emqx-rel emqx-zip 78 | # make deps-emqx 79 | # docker run -i --rm \ 80 | # -e EMQX_DEPS_DEFAULT_VSN=$TAG \ 81 | # -v $(pwd):/emqx-rel \ 82 | # emqx/build-env:erl22.3-ubuntu20.04 \ 83 | # bash -c "make -C /emqx-rel emqx-zip" 84 | # sudo chown -R $USER:$USER _packages/emqx 85 | # - name: run paho test 86 | # run: | 87 | # set -e -x -u 88 | # unzip -q emqx-rel/_packages/emqx/emqx-ubuntu20.04-${TAG#[e|v]}-x86_64.zip 89 | # sed -i 's|listener.wss.external[ \t]*=.*|listener.wss.external = 8085|g' emqx/etc/listeners.conf 90 | # sed -i 's|mqtt.max_topic_alias[ \t]*=.*|mqtt.max_topic_alias = 10|g' emqx/etc/emqx.conf 91 | # sed -i 's|zone.external.retry_interval[ \t]*=.*|zone.external.retry_interval = 2s|g' emqx/etc/zones.conf 92 | # ./emqx/bin/emqx start || cat emqx/log/erlang.log.1 93 | # pip install pytest 94 | # pytest -v paho.mqtt.testing/interoperability/test_client/ --host 127.0.0.1 95 | # ./emqx/bin/emqx stop 96 | # rm -rf emqx 97 | - name: build emqtt-bench 98 | run: | 99 | set -e -u -x 100 | make -C emqtt-bench 101 | - name: build lux 102 | run: | 103 | set -e -u -x 104 | cd lux 105 | autoconf 106 | ./configure 107 | make 108 | make install 109 | - name: run relup test 110 | run: | 111 | set -e -x -u 112 | cp emqx-rel/*.zip . 113 | cp emqx-rel/_packages/emqx/*.zip . 114 | if [ -n "$OLD_TAGS" ]; then 115 | lux -v \ 116 | --case_timeout infinity \ 117 | --var PACKAGE_PATH=$(pwd) \ 118 | --var BENCH_PATH=$(pwd)/emqtt-bench \ 119 | --var ONE_MORE_EMQX_PATH=$(pwd)/one_more_emqx \ 120 | --var TAG=${TAG#[e|v]} \ 121 | --var OLD_TAGS="${OLD_TAGS//[e|v]}" \ 122 | emqx-rel/.ci/nightly_build/relup.lux 123 | fi 124 | - uses: actions/upload-artifact@v1 125 | if: failure() 126 | with: 127 | name: lux_logs 128 | path: lux_logs 129 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .eunit 2 | deps 3 | *.o 4 | *.beam 5 | *.plt 6 | erl_crash.dump 7 | rebar3.crashdump 8 | ebin 9 | _rel/* 10 | .concrete/DEV_MODE 11 | .rebar 12 | .erlang.mk/ 13 | etc/plugins/ 14 | data/configs/*.config 15 | data/configs/*.conf 16 | data/configs/*.args 17 | rel/ 18 | log/ 19 | ct/logs/* 20 | .DS_Store 21 | .idea/ 22 | *.d 23 | *.iml 24 | vars.config 25 | erlang.mk 26 | _build 27 | rebar.lock 28 | test/ 29 | _checkouts 30 | _packages 31 | deploy/docker/tmp 32 | tmp 33 | .vscode/settings.json 34 | .ignore 35 | /rebar3 36 | /.tool-versions 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ## shallow clone for speed 2 | 3 | REBAR_GIT_CLONE_OPTIONS += --depth 1 4 | export REBAR_GIT_CLONE_OPTIONS 5 | export LC_ALL=en_US.UTF-8 6 | 7 | REBAR_VERSION = 3.13.2-emqx-4 8 | REBAR = $(CURDIR)/rebar3 9 | 10 | PROFILE ?= emqx 11 | PROFILES := emqx emqx-edge 12 | PKG_PROFILES := emqx-pkg emqx-edge-pkg 13 | 14 | export EMQX_DEPS_DEFAULT_VSN ?= $(shell ./get-lastest-tag.escript ref) 15 | ifneq ($(shell echo $(EMQX_DEPS_DEFAULT_VSN) | grep -oE "^[ev0-9]+\.[0-9]+(\.[0-9]+)?"),) 16 | export PKG_VSN := $(patsubst v%,%,$(patsubst e%,%,$(EMQX_DEPS_DEFAULT_VSN))) 17 | else 18 | export PKG_VSN := $(patsubst v%,%,$(shell ./get-lastest-tag.escript tag)) 19 | endif 20 | 21 | CT_APPS := emqx \ 22 | emqx_auth_clientid \ 23 | emqx_auth_http \ 24 | emqx_auth_jwt \ 25 | emqx_auth_ldap \ 26 | emqx_auth_mongo \ 27 | emqx_auth_mysql \ 28 | emqx_auth_pgsql \ 29 | emqx_auth_redis \ 30 | emqx_auth_username \ 31 | emqx_auth_mnesia \ 32 | emqx_sasl \ 33 | emqx_coap \ 34 | emqx_recon \ 35 | emqx_dashboard \ 36 | emqx_delayed_publish \ 37 | emqx_lua_hook \ 38 | emqx_lwm2m \ 39 | emqx_management \ 40 | emqx_retainer \ 41 | emqx_sn \ 42 | emqx_stomp \ 43 | emqx_telemetry \ 44 | emqx_web_hook \ 45 | emqx_bridge_mqtt \ 46 | emqx_rule_engine \ 47 | emqx_extension_hook \ 48 | emqx_exproto 49 | 50 | .PHONY: default 51 | default: $(REBAR) $(PROFILE) 52 | 53 | .PHONY: all 54 | all: $(REBAR) $(PROFILES) 55 | 56 | .PHONY: distclean 57 | distclean: remove-build-meta-files 58 | @rm -rf _build 59 | @rm -rf _checkouts 60 | 61 | .PHONY: distclean-deps 62 | distclean-deps: remove-deps remove-build-meta-files 63 | 64 | .PHONY: remove-deps 65 | remove-deps: 66 | @rm -rf _build/$(PROFILE)/lib 67 | @rm -rf _build/$(PROFILE)/conf 68 | @rm -rf _build/$(PROFILE)/plugins 69 | 70 | .PHONY: remove-build-meta-files 71 | remove-build-meta-files: 72 | @rm -f data/app.*.config data/vm.*.args rebar.lock 73 | 74 | .PHONY: emqx 75 | emqx: $(REBAR) 76 | ifneq ($(OS),Windows_NT) 77 | ln -snf _build/$(@)/lib ./_checkouts 78 | endif 79 | EMQX_DESC="EMQ X Broker" $(REBAR) as $(@) release 80 | 81 | .PHONY: emqx-edge 82 | emqx-edge: $(REBAR) 83 | ifneq ($(OS),Windows_NT) 84 | ln -snf _build/$(@)/lib ./_checkouts 85 | endif 86 | EMQX_DESC="EMQ X Edge" $(REBAR) as $(@) release 87 | 88 | .PHONY: $(PROFILES:%=build-%) 89 | $(PROFILES:%=build-%): $(REBAR) 90 | $(REBAR) as $(@:build-%=%) compile 91 | 92 | .PHONY: run $(PROFILES:%=run-%) 93 | run: run-$(PROFILE) 94 | $(PROFILES:%=run-%): $(REBAR) 95 | ifneq ($(OS),Windows_NT) 96 | @ln -snf _build/$(@:run-%=%)/lib ./_checkouts 97 | endif 98 | $(REBAR) as $(@:run-%=%) run 99 | 100 | .PHONY: clean $(PROFILES:%=clean-%) 101 | clean: $(PROFILES:%=clean-%) 102 | $(PROFILES:%=clean-%): $(REBAR) 103 | @rm -rf _build/$(@:clean-%=%) 104 | @rm -rf _build/$(@:clean-%=%)+test 105 | 106 | .PHONY: $(PROFILES:%=checkout-%) 107 | $(PROFILES:%=checkout-%): $(REBAR) build-$(PROFILE) 108 | ln -s -f _build/$(@:checkout-%=%)/lib ./_checkouts 109 | 110 | # Checkout current profile 111 | .PHONY: checkout 112 | checkout: 113 | @ln -s -f _build/$(PROFILE)/lib ./_checkouts 114 | 115 | # Run ct for an app in current profile 116 | .PHONY: $(REBAR) $(CT_APPS:%=ct-%) 117 | ct: $(CT_APPS:%=ct-%) 118 | $(CT_APPS:%=ct-%): checkout-$(PROFILE) 119 | -make -C _build/emqx/lib/$(@:ct-%=%) ct 120 | @mkdir -p tests/logs/$(@:ct-%=%) 121 | @if [ -d _build/emqx/lib/$(@:ct-%=%)/_build/test/logs ]; then cp -r _build/emqx/lib/$(@:ct-%=%)/_build/test/logs/* tests/logs/$(@:ct-%=%); fi 122 | 123 | .PHONY: $(REBAR) 124 | $(REBAR): 125 | $(CURDIR)/ensure-rebar3.sh $(REBAR_VERSION) 126 | 127 | .PHONY: deps-all 128 | deps-all: $(REBAR) $(PROFILES:%=deps-%) $(PKG_PROFILES:%=deps-%) 129 | 130 | .PHONY: deps-emqx deps-emqx-pkg 131 | deps-emqx deps-emqx-pkg: $(REBAR) 132 | EMQX_DESC="EMQ X Broker" $(REBAR) as $(@:deps-%=%) get-deps 133 | 134 | .PHONY: deps-emqx-edge deps-emqx-edge-pkg 135 | deps-emqx-edge deps-emqx-edge-pkg: $(REBAR) 136 | EMQX_DESC="EMQ X Edge" $(REBAR) as $(@:deps-%=%) get-deps 137 | 138 | 139 | include packages.mk 140 | include docker.mk 141 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # emqx-rel 2 | 3 | 4 | The Release Project for EMQX Broker. 5 | 6 | NOTICE: Requires Erlang/OTP 21.3 .. 22 to build since EMQX 3.2 7 | 8 | EMQX no longer uses this repository since version 4.3. Use https://github.com/emqx/emqx/ instead. 9 | 10 | 11 | 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. 12 | 13 | ## rebar3 14 | 15 | This project has rebar3 (compiled from OTP 21.3) included. 16 | 17 | ## Build on Linux/Unix/Mac 18 | 19 | ```shell 20 | $ git clone https://github.com/emqx/emqx-rel.git emqx-rel 21 | $ cd emqx-rel 22 | $ git checkout $(git describe --tags $(git rev-list --tags --max-count=1)) 23 | $ make 24 | $ ./_build/emqx/rel/emqx/bin/emqx console 25 | ``` 26 | 27 | ## Build rpm or deb package on Linux 28 | ```shell 29 | $ git clone https://github.com/emqx/emqx-rel.git emqx-rel 30 | $ cd emqx-rel 31 | $ git checkout $(git describe --tags $(git rev-list --tags --max-count=1)) 32 | $ make emqx-pkg 33 | $ ls _packages/emqx 34 | ``` 35 | 36 | ## Build docker image 37 | ```shell 38 | $ git clone https://github.com/emqx/emqx-rel.git emqx-rel 39 | $ cd emqx-rel 40 | $ git checkout $(git describe --tags $(git rev-list --tags --max-count=1)) 41 | $ TARGET=emqx/emqx make docker 42 | ``` 43 | 44 | ## Build on Windows 45 | 46 | ```powershell 47 | git clone -b v4.0.0 https://github.com/emqx/emqx-rel.git emqx-rel 48 | cd emqx-rel 49 | make 50 | cd _build\emqx\rel\emqx 51 | bin\emqx console 52 | ``` 53 | 54 | ## Build with elixir plugins 55 | 56 | Modify the rebar.config. 57 | 58 | ```erlang 59 | 60 | {elixir_deps, 61 | [ {plugin_name, {git, "url_of_plugin", {tag, "tag_of_plugin"}}} 62 | , .... 63 | .... 64 | ] 65 | } 66 | 67 | ...... 68 | ...... 69 | 70 | {elixir_relx_apps, 71 | [ app_name1 72 | , app_name2]}. 73 | 74 | ``` 75 | 76 | Due to the limit of the `rebar3_elixir_compile`, users have to specify all the 77 | dependencies of the the elixir plugin in rebar.config in emqx-rel. 78 | 79 | ## Start with epmd 80 | 81 | For now, emqx starts without epmd by default. If you want to run emqx with epmd, 82 | you should set the environment variable $WITH_EPMD with any value you want, for example, execute `export $WITH_EPMD=true` in your shell, then run emqx, epmd will start soon afterwards. 83 | 84 | # Test 85 | 86 | ```bash 87 | make ct 88 | ``` 89 | 90 | # License 91 | 92 | Apache License Version 2.0 93 | 94 | # Author 95 | 96 | EMQX Team. 97 | -------------------------------------------------------------------------------- /bin/emqx.cmd: -------------------------------------------------------------------------------- 1 | :: This batch file handles managing an Erlang node as a Windows service. 2 | :: 3 | :: Commands provided: 4 | :: 5 | :: * install - install the release as a Windows service 6 | :: * start - start the service and Erlang node 7 | :: * stop - stop the service and Erlang node 8 | :: * restart - run the stop command and start command 9 | :: * uninstall - uninstall the service and kill a running node 10 | :: * ping - check if the node is running 11 | :: * console - start the Erlang release in a `werl` Windows shell 12 | :: * attach - connect to a running node and open an interactive console 13 | :: * list - display a listing of installed Erlang services 14 | :: * usage - display available commands 15 | 16 | :: Set variables that describe the release 17 | @set rel_name=emqx 18 | @set rel_vsn={{ rel_vsn }} 19 | @set erts_vsn={{ erts_vsn }} 20 | @set erl_opts={{ erl_opts }} 21 | 22 | @set script=%~n0 23 | 24 | :: Discover the release root directory from the directory 25 | :: of this script 26 | @set script_dir=%~dp0 27 | @for %%A in ("%script_dir%\..") do @( 28 | set rel_root_dir=%%~fA 29 | ) 30 | @set rel_dir=%rel_root_dir%\releases\%rel_vsn% 31 | 32 | @set etc_dir=%rel_root_dir%\etc 33 | @set lib_dir=%rel_root_dir%\lib 34 | @set data_dir=%rel_root_dir%\data 35 | @set emqx_conf=%etc_dir%\emqx.conf 36 | 37 | @call :find_erts_dir 38 | @call :find_vm_args 39 | @call :find_sys_config 40 | @call :set_boot_script_var 41 | 42 | @set service_name=%rel_name%_%rel_vsn% 43 | @set bindir=%erts_dir%\bin 44 | @set progname=erl.exe 45 | @set clean_boot_script=%rel_root_dir%\bin\start_clean 46 | @set erlsrv="%bindir%\erlsrv.exe" 47 | @set epmd="%bindir%\epmd.exe" 48 | @set escript="%bindir%\escript.exe" 49 | @set werl="%bindir%\werl.exe" 50 | @set erl_exe="%bindir%\erl.exe" 51 | @set nodetool="%rel_root_dir%\bin\nodetool" 52 | @set cuttlefish="%rel_root_dir%\bin\cuttlefish" 53 | @set node_type="-name" 54 | 55 | :: Extract node name from emqx.conf 56 | @for /f "usebackq delims=\= tokens=2" %%I in (`findstr /b node\.name "%emqx_conf%"`) do @( 57 | @call :set_trim node_name %%I 58 | ) 59 | 60 | :: Extract node cookie from emqx.conf 61 | @for /f "usebackq delims=\= tokens=2" %%I in (`findstr /b node\.cookie "%emqx_conf%"`) do @( 62 | @call :set_trim node_cookie= %%I 63 | ) 64 | 65 | :: Write the erl.ini file to set up paths relative to this script 66 | @call :write_ini 67 | 68 | :: If a start.boot file is not present, copy one from the named .boot file 69 | @if not exist "%rel_dir%\start.boot" ( 70 | copy "%rel_dir%\%rel_name%.boot" "%rel_dir%\start.boot" >nul 71 | ) 72 | 73 | @if "%1"=="install" @goto install 74 | @if "%1"=="uninstall" @goto uninstall 75 | @if "%1"=="start" @goto start 76 | @if "%1"=="stop" @goto stop 77 | @if "%1"=="restart" @call :stop && @goto start 78 | ::@if "%1"=="upgrade" @goto relup 79 | ::@if "%1"=="downgrade" @goto relup 80 | @if "%1"=="console" @goto console 81 | @if "%1"=="ping" @goto ping 82 | @if "%1"=="list" @goto list 83 | @if "%1"=="attach" @goto attach 84 | @if "%1"=="" @goto usage 85 | @echo Unknown command: "%1" 86 | 87 | @goto :eof 88 | 89 | :: Find the ERTS dir 90 | :find_erts_dir 91 | @set possible_erts_dir=%rel_root_dir%\erts-%erts_vsn% 92 | @if exist "%possible_erts_dir%" ( 93 | call :set_erts_dir_from_default 94 | ) else ( 95 | call :set_erts_dir_from_erl 96 | ) 97 | @goto :eof 98 | 99 | :: Set the ERTS dir from the passed in erts_vsn 100 | :set_erts_dir_from_default 101 | @set erts_dir=%possible_erts_dir% 102 | @set rootdir=%rel_root_dir% 103 | @goto :eof 104 | 105 | :: Set the ERTS dir from erl 106 | :set_erts_dir_from_erl 107 | @for /f "delims=" %%i in ('where erl') do @( 108 | set erl=%%i 109 | ) 110 | @set dir_cmd="%erl%" -noshell -eval "io:format(\"~s\", [filename:nativename(code:root_dir())])." -s init stop 111 | @for /f %%i in ('%%dir_cmd%%') do @( 112 | set erl_root=%%i 113 | ) 114 | @set erts_dir=%erl_root%\erts-%erts_vsn% 115 | @set rootdir=%erl_root% 116 | @goto :eof 117 | 118 | :find_vm_args 119 | @set possible_vm=%etc_dir%\vm.args 120 | @if exist %possible_vm% ( 121 | set args_file=-args_file "%possible_vm%" 122 | ) 123 | @goto :eof 124 | 125 | :: Find the sys.config file 126 | :find_sys_config 127 | @set possible_sys=%etc_dir%\sys.config 128 | @if exist %possible_sys% ( 129 | set sys_config=-config "%possible_sys%" 130 | ) 131 | @goto :eof 132 | 133 | :create_mnesia_dir 134 | @set create_dir_cmd=%escript% %nodetool% mnesia_dir %data_dir%\mnesia %node_name% 135 | @for /f "delims=" %%Z in ('%%create_dir_cmd%%') do @( 136 | set mnesia_dir=%%Z 137 | ) 138 | @goto :eof 139 | 140 | :generate_app_config 141 | @set gen_config_cmd=%escript% %cuttlefish% -i %rel_dir%\emqx.schema -c %etc_dir%\emqx.conf -d %data_dir%\configs generate 142 | @for /f "delims=" %%A in ('%%gen_config_cmd%%') do @( 143 | set generated_config_args=%%A 144 | ) 145 | @goto :eof 146 | 147 | :: set boot_script variable 148 | :set_boot_script_var 149 | @if exist "%rel_dir%\%rel_name%.boot" ( 150 | set boot_script=%rel_dir%\%rel_name% 151 | ) else ( 152 | set boot_script=%rel_dir%\start 153 | ) 154 | @goto :eof 155 | 156 | :: Write the erl.ini file 157 | :write_ini 158 | @set erl_ini=%erts_dir%\bin\erl.ini 159 | @set converted_bindir=%bindir:\=\\% 160 | @set converted_rootdir=%rootdir:\=\\% 161 | @echo [erlang] > "%erl_ini%" 162 | @echo Bindir=%converted_bindir% >> "%erl_ini%" 163 | @echo Progname=%progname% >> "%erl_ini%" 164 | @echo Rootdir=%converted_rootdir% >> "%erl_ini%" 165 | @goto :eof 166 | 167 | :: Display usage information 168 | :usage 169 | @echo usage: %~n0 ^(install^|uninstall^|start^|stop^|restart^|console^|ping^|list^|attach^) 170 | @goto :eof 171 | 172 | :: Install the release as a Windows service 173 | :: or install the specified version passed as argument 174 | :install 175 | @call :create_mnesia_dir 176 | @call :generate_app_config 177 | :: Install the service 178 | @set args="-boot %boot_script% %sys_config% %generated_config_args% -mnesia dir '%mnesia_dir%'" 179 | @set description=EMQX node %node_name% in %rootdir% 180 | @if "" == "%2" ( 181 | %erlsrv% add %service_name% %node_type% "%node_name%" -on restart -c "%description%" ^ 182 | -i "emqx" -w "%rootdir%" -m %erl_exe% -args %args% ^ 183 | -st "init:stop()." 184 | sc config emqx start=delayed-auto 185 | ) else ( 186 | :: relup and reldown 187 | goto relup 188 | ) 189 | 190 | @goto :eof 191 | 192 | :: Uninstall the Windows service 193 | :uninstall 194 | @%erlsrv% remove %service_name% 195 | @%epmd% -kill 196 | @goto :eof 197 | 198 | :: Start the Windows service 199 | :start 200 | :: window service? 201 | :: @%erlsrv% start %service_name% 202 | @call :create_mnesia_dir 203 | @call :generate_app_config 204 | @set args=-detached %sys_config% %generated_config_args% -mnesia dir '%mnesia_dir%' 205 | @echo off 206 | cd /d %rel_root_dir% 207 | @echo on 208 | @start "%rel_name%" %werl% -boot "%boot_script%" %args% 209 | @goto :eof 210 | 211 | :: Stop the Windows service 212 | :stop 213 | :: window service? 214 | :: @%erlsrv% stop %service_name% 215 | @%escript% %nodetool% %node_type% %node_name% -setcookie %node_cookie% stop 216 | @goto :eof 217 | 218 | :: Relup and reldown 219 | :relup 220 | @if "" == "%2" ( 221 | echo Missing package argument 222 | echo Usage: %rel_name% %1 {package base name} 223 | echo NOTE {package base name} MUST NOT include the .tar.gz suffix 224 | set ERRORLEVEL=1 225 | exit /b %ERRORLEVEL% 226 | ) 227 | @%escript% "%rootdir%/bin/install_upgrade.escript" "%rel_name%" "%node_name%" "%node_cookie%" "%2" 228 | @goto :eof 229 | 230 | :: Start a console 231 | :console 232 | @call :create_mnesia_dir 233 | @call :generate_app_config 234 | @set args=%sys_config% %generated_config_args% -mnesia dir '%mnesia_dir%' 235 | @echo off 236 | cd /d %rel_root_dir% 237 | @echo on 238 | @start "bin\%rel_name% console" %werl% -boot "%boot_script%" %args% 239 | @echo emqx is started! 240 | @goto :eof 241 | 242 | :: Ping the running node 243 | :ping 244 | @%escript% %nodetool% ping %node_type% "%node_name%" -setcookie "%node_cookie%" 245 | @goto :eof 246 | 247 | :: List installed Erlang services 248 | :list 249 | @%erlsrv% list %service_name% 250 | @goto :eof 251 | 252 | :: Attach to a running node 253 | :attach 254 | :: @start "%node_name% attach" 255 | @start "%node_name% attach" %werl% -boot "%clean_boot_script%" ^ 256 | -remsh %node_name% %node_type% console_%node_name% -setcookie %node_cookie% 257 | @goto :eof 258 | 259 | :: Trim variable 260 | :set_trim 261 | @set %1=%2 262 | @goto :eof 263 | 264 | -------------------------------------------------------------------------------- /bin/emqx_ctl: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # -*- tab-width:4;indent-tabs-mode:nil -*- 3 | # ex: ts=4 sw=4 et 4 | 5 | set -e 6 | 7 | ROOT_DIR="$(cd $(dirname $(readlink $0 || echo $0))/..; pwd -P)" 8 | . $ROOT_DIR/releases/emqx_vars 9 | 10 | # Echo to stderr on errors 11 | echoerr() { echo "$@" 1>&2; } 12 | 13 | if [ -z "$WITH_EPMD" ]; then 14 | EPMD_ARG="-start_epmd false -epmd_module ekka_epmd -proto_dist ekka" 15 | else 16 | EPMD_ARG="-start_epmd true" 17 | fi 18 | 19 | relx_get_nodename() { 20 | id="longname$(relx_gen_id)-${NAME}" 21 | "$BINDIR/erl" -boot start_clean -eval '[Host] = tl(string:tokens(atom_to_list(node()),"@")), io:format("~s~n", [Host]), halt()' -noshell ${NAME_TYPE} $id 22 | } 23 | 24 | # Control a node 25 | relx_nodetool() { 26 | command="$1"; shift 27 | 28 | ERL_FLAGS="$ERL_FLAGS $EPMD_ARG $PROTO_DIST_ARG" \ 29 | "$ERTS_DIR/bin/escript" "$ROOTDIR/bin/nodetool" "$NAME_TYPE" "$NAME" \ 30 | -setcookie "$COOKIE" "$command" "$@" 31 | } 32 | 33 | 34 | # Extract the target node name from node.args 35 | if [ -z "$NAME_ARG" ]; then 36 | if [ ! -z "$EMQX_NODE_NAME" ]; then 37 | NODENAME="$EMQX_NODE_NAME" 38 | elif [ ! -z `ps -ef | grep "$ERTS_PATH/beam.smp" | grep -o -E '\-name (\S*)' | awk '{print $2}'` ]; then 39 | NODENAME=`ps -ef | grep "$ERTS_PATH/beam.smp" | grep -o -E '\-name (\S*)' | awk '{print $2}'` 40 | else 41 | NODENAME=`egrep '^[ \t]*node.name[ \t]*=[ \t]*' $RUNNER_ETC_DIR/emqx.conf 2> /dev/null | tail -1 | cut -d = -f 2-` 42 | fi 43 | if [ -z "$NODENAME" ]; then 44 | echoerr "vm.args needs to have a -name parameter." 45 | echoerr " -sname is not supported." 46 | echoerr "please check $RUNNER_ETC_DIR/emqx.conf" 47 | exit 1 48 | else 49 | NAME_ARG="-name ${NODENAME# *}" 50 | fi 51 | fi 52 | 53 | # Extract the name type and name from the NAME_ARG for REMSH 54 | NAME_TYPE="$(echo "$NAME_ARG" | awk '{print $1}')" 55 | NAME="$(echo "$NAME_ARG" | awk '{print $2}')" 56 | 57 | # Extract the target cookie 58 | if [ -z "$COOKIE_ARG" ]; then 59 | if [ ! -z "$EMQX_NODE_COOKIE" ]; then 60 | COOKIE="$EMQX_NODE_COOKIE" 61 | elif [ ! -z `ps -ef | grep "$ERTS_PATH/beam.smp" | grep -o -E '\-setcookie (\S*)' | awk '{print $2}'` ]; then 62 | COOKIE=`ps -ef | grep "$ERTS_PATH/beam.smp" | grep -o -E '\-setcookie (\S*)' | awk '{print $2}'` 63 | else 64 | COOKIE=`egrep '^[ \t]*node.cookie[ \t]*=[ \t]*' $RUNNER_ETC_DIR/emqx.conf 2> /dev/null | tail -1 | cut -d = -f 2-` 65 | fi 66 | if [ -z "$COOKIE" ]; then 67 | echoerr "vm.args needs to have a -setcookie parameter." 68 | echoerr "please check $RUNNER_ETC_DIR/emqx.conf" 69 | exit 1 70 | else 71 | COOKIE_ARG="-setcookie $COOKIE" 72 | fi 73 | fi 74 | 75 | # Extract cookie name from COOKIE_ARG 76 | COOKIE="$(echo "$COOKIE_ARG" | awk '{print $2}')" 77 | 78 | # Support for IPv6 Dist. See: https://github.com/emqtt/emqttd/issues/1460 79 | PROTO_DIST=`egrep '^[ \t]*cluster.proto_dist[ \t]*=[ \t]*' $RUNNER_ETC_DIR/emqx.conf 2> /dev/null | tail -1 | cut -d = -f 2-` 80 | if [ -z "$PROTO_DIST" ]; then 81 | PROTO_DIST_ARG="" 82 | else 83 | PROTO_DIST_ARG="-proto_dist $PROTO_DIST" 84 | fi 85 | 86 | export ROOTDIR="$RUNNER_ROOT_DIR" 87 | export ERTS_DIR="$ROOTDIR/erts-$ERTS_VSN" 88 | export BINDIR="$ERTS_DIR/bin" 89 | cd "$ROOTDIR" 90 | 91 | relx_nodetool rpc emqx_ctl run_command "$@" 92 | 93 | -------------------------------------------------------------------------------- /bin/emqx_ctl.cmd: -------------------------------------------------------------------------------- 1 | :: The batch file for emqx_ctl command 2 | 3 | @set args=%* 4 | 5 | :: Set variables that describe the release 6 | @set rel_name=emqx 7 | @set rel_vsn={{ rel_vsn }} 8 | @set erts_vsn={{ erts_vsn }} 9 | @set erl_opts={{ erl_opts }} 10 | 11 | :: Discover the release root directory from the directory 12 | :: of this script 13 | @set script_dir=%~dp0 14 | @for %%A in ("%script_dir%\..") do @( 15 | set rel_root_dir=%%~fA 16 | ) 17 | @set rel_dir=%rel_root_dir%\releases\%rel_vsn% 18 | @set emqx_conf=%rel_root_dir%\etc\emqx.conf 19 | 20 | @call :find_erts_dir 21 | 22 | @set bindir=%erts_dir%\bin 23 | @set progname=erl.exe 24 | @set escript="%bindir%\escript.exe" 25 | @set nodetool="%rel_root_dir%\bin\nodetool" 26 | @set node_type="-name" 27 | 28 | :: Extract node name from emqx.conf 29 | @for /f "usebackq delims=\= tokens=2" %%I in (`findstr /b node\.name "%emqx_conf%"`) do @( 30 | @call :set_trim node_name %%I 31 | ) 32 | 33 | :: Extract node cookie from emqx.conf 34 | @for /f "usebackq delims=\= tokens=2" %%I in (`findstr /b node\.cookie "%emqx_conf%"`) do @( 35 | @call :set_trim node_cookie= %%I 36 | ) 37 | 38 | :: Write the erl.ini file to set up paths relative to this script 39 | @call :write_ini 40 | 41 | :: If a start.boot file is not present, copy one from the named .boot file 42 | @if not exist "%rel_dir%\start.boot" ( 43 | copy "%rel_dir%\%rel_name%.boot" "%rel_dir%\start.boot" >nul 44 | ) 45 | 46 | @%escript% %nodetool% %node_type% "%node_name%" -setcookie "%node_cookie%" rpc emqx_ctl run_command %args% 47 | 48 | :: Find the ERTS dir 49 | :find_erts_dir 50 | @set possible_erts_dir=%rel_root_dir%\erts-%erts_vsn% 51 | @if exist "%possible_erts_dir%" ( 52 | call :set_erts_dir_from_default 53 | ) else ( 54 | call :set_erts_dir_from_erl 55 | ) 56 | @goto :eof 57 | 58 | :: Set the ERTS dir from the passed in erts_vsn 59 | :set_erts_dir_from_default 60 | @set erts_dir=%possible_erts_dir% 61 | @set rootdir=%rel_root_dir% 62 | @goto :eof 63 | 64 | :: Set the ERTS dir from erl 65 | :set_erts_dir_from_erl 66 | @for /f "delims=" %%i in ('where erl') do @( 67 | set erl=%%i 68 | ) 69 | @set dir_cmd="%erl%" -noshell -eval "io:format(\"~s\", [filename:nativename(code:root_dir())])." -s init stop 70 | @for /f %%i in ('%%dir_cmd%%') do @( 71 | set erl_root=%%i 72 | ) 73 | @set erts_dir=%erl_root%\erts-%erts_vsn% 74 | @set rootdir=%erl_root% 75 | @goto :eof 76 | 77 | :: Write the erl.ini file 78 | :write_ini 79 | @set erl_ini=%erts_dir%\bin\erl.ini 80 | @set converted_bindir=%bindir:\=\\% 81 | @set converted_rootdir=%rootdir:\=\\% 82 | @echo [erlang] > "%erl_ini%" 83 | @echo Bindir=%converted_bindir% >> "%erl_ini%" 84 | @echo Progname=%progname% >> "%erl_ini%" 85 | @echo Rootdir=%converted_rootdir% >> "%erl_ini%" 86 | @goto :eof 87 | 88 | :: Trim variable 89 | :set_trim 90 | @set %1=%2 91 | @goto :eof 92 | 93 | -------------------------------------------------------------------------------- /bin/emqx_env: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | [ "x" = "x$EMQX_NODE_NAME" ] && EMQX_NODE_NAME=emqx@127.0.0.1 4 | [ "x" = "x$EMQX_NODE_COOKIE" ] && EMQX_NODE_COOKIE=emqxsecretcookie 5 | [ "x" = "x$EMQX_MAX_PACKET_SIZE" ] && EMQX_MAX_PACKET_SIZE=64KB 6 | [ "x" = "x$EMQX_MAX_PORTS" ] && EMQX_MAX_PORTS=65536 7 | [ "x" = "x$EMQX_TCP_PORT" ] && EMQX_TCP_PORT=1883 8 | [ "x" = "x$EMQX_SSL_PORT" ] && EMQX_SSL_PORT=8883 9 | [ "x" = "x$EMQX_WS_PORT" ] && EMQX_WS_PORT=8083 10 | [ "x" = "x$EMQX_WSS_PORT" ] && EMQX_WSS_PORT=8084 11 | 12 | -------------------------------------------------------------------------------- /data/emqx_vars: -------------------------------------------------------------------------------- 1 | ###################################################################### 2 | ## NOTE: Do NOT replace this file during release upgrade. 3 | ## Update the vars to the end of this file instead. 4 | ###################################################################### 5 | ## constants from relx template 6 | REL_VSN="{{ rel_vsn }}" 7 | ERTS_VSN="{{ erts_vsn }}" 8 | ERL_OPTS="{{ erl_opts }}" 9 | RUNNER_ROOT_DIR="{{ runner_root_dir }}" 10 | RUNNER_BIN_DIR="{{ runner_bin_dir }}" 11 | RUNNER_LOG_DIR="{{ runner_log_dir }}" 12 | RUNNER_LIB_DIR="{{ runner_lib_dir }}" 13 | RUNNER_ETC_DIR="{{ runner_etc_dir }}" 14 | RUNNER_DATA_DIR="{{ runner_data_dir }}" 15 | RUNNER_USER="{{ runner_user }}" 16 | EMQX_DISCR="{{ emqx_description }}" 17 | 18 | ## computed vars 19 | REL_NAME="emqx" 20 | ERTS_PATH=$RUNNER_ROOT_DIR/erts-$ERTS_VSN/bin 21 | 22 | ## updated vars here 23 | -------------------------------------------------------------------------------- /data/loaded_modules.tmpl: -------------------------------------------------------------------------------- 1 | {emqx_mod_acl_internal, true}. 2 | {emqx_mod_presence, true}. 3 | {emqx_mod_delayed, false}. 4 | {emqx_mod_rewrite, false}. 5 | {emqx_mod_subscription, false}. 6 | {emqx_mod_topic_metrics, false}. 7 | -------------------------------------------------------------------------------- /data/loaded_plugins.tmpl: -------------------------------------------------------------------------------- 1 | {emqx_management, true}. 2 | {emqx_recon, true}. 3 | {emqx_retainer, true}. 4 | {emqx_dashboard, true}. 5 | {emqx_telemetry, true}. 6 | {emqx_rule_engine, {{enable_plugin_emqx_rule_engine}}}. 7 | {emqx_bridge_mqtt, {{enable_plugin_emqx_bridge_mqtt}}}. 8 | -------------------------------------------------------------------------------- /deploy/charts/emqx/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: emqx 3 | description: A Helm chart for EMQ X 4 | # A chart can be either an 'application' or a 'library' chart. 5 | # 6 | # Application charts are a collection of templates that can be packaged into versioned archives 7 | # to be deployed. 8 | # 9 | # Library charts provide useful utilities or functions for the chart developer. They're included as 10 | # a dependency of application charts to inject those utilities and functions into the rendering 11 | # pipeline. Library charts do not define any templates and therefore cannot be deployed. 12 | type: application 13 | 14 | # This is the chart version. This version number should be incremented each time you make changes 15 | # to the chart and its templates, including the app version. 16 | version: v4.1.1 17 | 18 | # This is the version number of the application being deployed. This version number should be 19 | # incremented each time you make changes to the application. 20 | appVersion: v4.1.1 21 | -------------------------------------------------------------------------------- /deploy/charts/emqx/README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | This chart bootstraps an emqx deployment on a Kubernetes cluster using the Helm package manager. 3 | 4 | # Prerequisites 5 | + Kubernetes 1.6+ 6 | + Helm 7 | 8 | # Installing the Chart 9 | To install the chart with the release name `my-emqx`: 10 | 11 | + From github 12 | ``` 13 | $ git clone https://github.com/emqx/emqx-rel.git 14 | $ cd emqx-rel/deploy/charts/emqx 15 | $ helm install my-emqx . 16 | ``` 17 | 18 | + From chart repos 19 | ``` 20 | helm repo add emqx https://repos.emqx.io/charts 21 | helm install my-emqx emqx/emqx 22 | ``` 23 | > If you want to install an unstable version, you need to add `--devel` when you execute the `helm install` command. 24 | 25 | # Uninstalling the Chart 26 | To uninstall/delete the `my-emqx` deployment: 27 | ``` 28 | $ helm del my-emqx 29 | ``` 30 | 31 | # Configuration 32 | The following table lists the configurable parameters of the emqx chart and their default values. 33 | 34 | | Parameter | Description | Default Value | 35 | | --- | --- | --- | 36 | | `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| 37 | | `image.repository` | EMQX Image name |emqx/emqx| 38 | | `image.pullPolicy` | The image pull policy |IfNotPresent| 39 | | `image.pullSecrets ` | The image pull secrets |`[]` (does not add image pull secrets to deployed pods)| 40 | | `persistence.enabled` | Enable EMQX persistence using PVC |false| 41 | | `persistence.storageClass` | Storage class of backing PVC |`nil` (uses alpha storage class annotation)| 42 | | `persistence.existingClaim` | EMQX data Persistent Volume existing claim name, evaluated as a template |""| 43 | | `persistence.accessMode` | PVC Access Mode for EMQX volume |ReadWriteOnce| 44 | | `persistence.size` | PVC Storage Request for EMQX volume |20Mi| 45 | | `initContainers` | Containers that run before the creation of EMQX containers. They can contain utilities or setup scripts. |`{}`| 46 | | `resources` | CPU/Memory resource requests/limits |{}| 47 | | `nodeSelector` | Node labels for pod assignment |`{}`| 48 | | `tolerations` | Toleration labels for pod assignment |`[]`| 49 | | `affinity` | Map of node/pod affinities |`{}`| 50 | | `service.type` | Kubernetes Service type. |ClusterIP| 51 | | `service.mqtt` | Port for MQTT. |1883| 52 | | `service.mqttssl` | Port for MQTT(SSL). |8883| 53 | | `service.mgmt` | Port for mgmt API. |8081| 54 | | `service.ws` | Port for WebSocket/HTTP. |8083| 55 | | `service.wss` | Port for WSS/HTTPS. |8084| 56 | | `service.dashboard` | Port for dashboard. |18083| 57 | | `service.nodePorts.mqtt` | Kubernetes node port for MQTT. |nil| 58 | | `service.nodePorts.mqttssl` | Kubernetes node port for MQTT(SSL). |nil| 59 | | `service.nodePorts.mgmt` | Kubernetes node port for mgmt API. |nil| 60 | | `service.nodePorts.ws` | Kubernetes node port for WebSocket/HTTP. |nil| 61 | | `service.nodePorts.wss` | Kubernetes node port for WSS/HTTPS. |nil| 62 | | `service.nodePorts.dashboard` | Kubernetes node port for dashboard. |nil| 63 | | `service.loadBalancerIP` | loadBalancerIP for Service | nil | 64 | | `service.loadBalancerSourceRanges` | Address(es) that are allowed when service is LoadBalancer | [] | 65 | | `service.annotations` | Service annotations | {}(evaluated as a template)| 66 | | `ingress.dashboard.enabled` | Enable ingress for EMQX Dashboard | false | 67 | | `ingress.dashboard.path` | Ingress path for EMQX Dashboard | / | 68 | | `ingress.dashboard.hosts` | Ingress hosts for EMQX Mgmt API | dashboard.emqx.local | 69 | | `ingress.dashboard.tls` | Ingress tls for EMQX Mgmt API | [] | 70 | | `ingress.dashboard.annotations` | Ingress annotations for EMQX Mgmt API | {} | 71 | | `ingress.mgmt.enabled` | Enable ingress for EMQX Mgmt API | false | 72 | | `ingress.mgmt.path` | Ingress path for EMQX Mgmt API | / | 73 | | `ingress.mgmt.hosts` | Ingress hosts for EMQX Mgmt API | api.emqx.local | 74 | | `ingress.mgmt.tls` | Ingress tls for EMQX Mgmt API | [] | 75 | | `ingress.mgmt.annotations` | Ingress annotations for EMQX Mgmt API | {} | 76 | | `emqxConfig` | Emqx configuration item, see the [documentation](https://hub.docker.com/r/emqx/emqx) | | 77 | | `emqxAclConfig` | Emqx acl configuration item, see the [documentation](https://docs.emqx.io/broker/latest/en/advanced/acl-file.html) | | 78 | -------------------------------------------------------------------------------- /deploy/charts/emqx/templates/StatefulSet.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: StatefulSet 3 | metadata: 4 | name: {{ include "emqx.fullname" . }} 5 | namespace: {{ .Release.Namespace }} 6 | labels: 7 | app.kubernetes.io/name: {{ include "emqx.name" . }} 8 | helm.sh/chart: {{ include "emqx.chart" . }} 9 | app.kubernetes.io/instance: {{ .Release.Name }} 10 | app.kubernetes.io/managed-by: {{ .Release.Service }} 11 | spec: 12 | serviceName: {{ include "emqx.fullname" . }}-headless 13 | {{- if and .Values.persistence.enabled (not .Values.persistence.existingClaim) }} 14 | volumeClaimTemplates: 15 | - metadata: 16 | name: emqx-data 17 | namespace: {{ .Release.Namespace }} 18 | labels: 19 | app.kubernetes.io/name: {{ include "emqx.name" . }} 20 | helm.sh/chart: {{ include "emqx.chart" . }} 21 | app.kubernetes.io/instance: {{ .Release.Name }} 22 | app.kubernetes.io/managed-by: {{ .Release.Service }} 23 | annotations: 24 | {{- if .Values.persistence.storageClass }} 25 | volume.beta.kubernetes.io/storage-class: {{ .Values.persistence.storageClass | quote }} 26 | {{- else }} 27 | volume.alpha.kubernetes.io/storage-class: default 28 | {{- end }} 29 | spec: 30 | accessModes: 31 | - {{ .Values.persistence.accessMode | quote }} 32 | resources: 33 | requests: 34 | storage: {{ .Values.persistence.size | quote }} 35 | {{- end }} 36 | updateStrategy: 37 | type: RollingUpdate 38 | replicas: {{ .Values.replicaCount }} 39 | selector: 40 | matchLabels: 41 | app.kubernetes.io/name: {{ include "emqx.name" . }} 42 | app.kubernetes.io/instance: {{ .Release.Name }} 43 | template: 44 | metadata: 45 | labels: 46 | app: {{ include "emqx.name" . }} 47 | version: {{ .Chart.AppVersion }} 48 | app.kubernetes.io/name: {{ include "emqx.name" . }} 49 | app.kubernetes.io/instance: {{ .Release.Name }} 50 | spec: 51 | {{- if .Values.image.pullSecrets }} 52 | imagePullSecrets: 53 | {{- range .Values.image.pullSecrets }} 54 | - name: {{ . }} 55 | {{- end }} 56 | {{- end }} 57 | volumes: 58 | - name: emqx-acl 59 | configMap: 60 | name: {{ include "emqx.fullname" . }}-acl 61 | items: 62 | - key: acl.conf 63 | path: acl.conf 64 | {{- if not .Values.persistence.enabled }} 65 | - name: emqx-data 66 | emptyDir: {} 67 | {{- else if .Values.persistence.existingClaim }} 68 | - name: emqx-data 69 | persistentVolumeClaim: 70 | {{- with .Values.persistence.existingClaim }} 71 | claimName: {{ tpl . $ }} 72 | {{- end }} 73 | {{- end }} 74 | {{- if .Values.emqxLicenseSecretName }} 75 | - name: emqx-license 76 | secret: 77 | secretName: {{ .Values.emqxLicenseSecretName }} 78 | {{- end }} 79 | serviceAccountName: {{ include "emqx.fullname" . }} 80 | {{- if .Values.podSecurityContext.enabled }} 81 | securityContext: {{- omit .Values.podSecurityContext "enabled" | toYaml | nindent 8 }} 82 | {{- end }} 83 | {{- if .Values.initContainers }} 84 | initContainers: 85 | {{ toYaml .Values.initContainers | indent 8 }} 86 | {{- end }} 87 | containers: 88 | - name: emqx 89 | image: "{{ .Values.image.repository }}:{{ .Chart.AppVersion }}" 90 | {{- if .Values.containerSecurityContext.enabled }} 91 | securityContext: {{- omit .Values.containerSecurityContext "enabled" | toYaml | nindent 12 }} 92 | {{- end }} 93 | imagePullPolicy: {{ .Values.image.pullPolicy }} 94 | ports: 95 | - name: mqtt 96 | containerPort: {{ .Values.emqxConfig.EMQX_LISTENER__TCP__EXTERNAL | default 1883 }} 97 | - name: mqttssl 98 | containerPort: {{ .Values.emqxConfig.EMQX_LISTENER__SSL__EXTERNAL | default 8883 }} 99 | - name: mgmt 100 | containerPort: {{ .Values.emqxConfig.EMQX_MANAGEMENT__LISTENER__HTTP | default 8081 }} 101 | - name: ws 102 | containerPort: {{ .Values.emqxConfig.EMQX_LISTENER__WS__EXTERNAL | default 8083 }} 103 | - name: wss 104 | containerPort: {{ .Values.emqxConfig.EMQX_LISTENER__WSS__EXTERNAL | default 8084 }} 105 | - name: dashboard 106 | containerPort: {{ .Values.emqxConfig.EMQX_DASHBOARD__LISTENER__HTTP | default 18083 }} 107 | - name: ekka 108 | containerPort: 4370 109 | envFrom: 110 | - configMapRef: 111 | name: {{ include "emqx.fullname" . }}-env 112 | env: 113 | - name: EMQX_NAME 114 | value: {{ .Release.Name }} 115 | - name: EMQX_CLUSTER__K8S__APP_NAME 116 | value: {{ .Release.Name }} 117 | - name: EMQX_CLUSTER__DISCOVERY 118 | value: k8s 119 | - name: EMQX_CLUSTER__K8S__SERVICE_NAME 120 | value: {{ include "emqx.fullname" . }}-headless 121 | - name: EMQX_CLUSTER__K8S__NAMESPACE 122 | value: {{ .Release.Namespace }} 123 | resources: 124 | {{ toYaml .Values.resources | indent 12 }} 125 | volumeMounts: 126 | - name: emqx-data 127 | mountPath: "/opt/emqx/data/mnesia" 128 | - name: emqx-acl 129 | mountPath: "/opt/emqx/etc/acl.conf" 130 | subPath: "acl.conf" 131 | {{ if .Values.emqxLicenseSecretName }} 132 | - name: emqx-license 133 | mountPath: "/opt/emqx/etc/emqx.lic" 134 | subPath: "emqx.lic" 135 | readOnly: true 136 | {{ end }} 137 | readinessProbe: 138 | httpGet: 139 | path: /status 140 | port: {{ .Values.emqxConfig.EMQX_MANAGEMENT__LISTENER__HTTP | default 8081 }} 141 | initialDelaySeconds: 5 142 | periodSeconds: 5 143 | {{- with .Values.nodeSelector }} 144 | nodeSelector: 145 | {{- toYaml . | nindent 8 }} 146 | {{- end }} 147 | {{- with .Values.affinity }} 148 | affinity: 149 | {{- toYaml . | nindent 8 }} 150 | {{- end }} 151 | {{- with .Values.tolerations }} 152 | tolerations: 153 | {{- toYaml . | nindent 8 }} 154 | {{- end }} 155 | -------------------------------------------------------------------------------- /deploy/charts/emqx/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* vim: set filetype=mustache: */}} 2 | {{/* 3 | Expand the name of the chart. 4 | */}} 5 | {{- define "emqx.name" -}} 6 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} 7 | {{- end -}} 8 | 9 | {{/* 10 | Create a default fully qualified app name. 11 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 12 | If release name contains chart name it will be used as a full name. 13 | */}} 14 | {{- define "emqx.fullname" -}} 15 | {{- if .Values.fullnameOverride -}} 16 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} 17 | {{- else -}} 18 | {{- $name := default .Chart.Name .Values.nameOverride -}} 19 | {{- if contains $name .Release.Name -}} 20 | {{- .Release.Name | trunc 63 | trimSuffix "-" -}} 21 | {{- else -}} 22 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} 23 | {{- end -}} 24 | {{- end -}} 25 | {{- end -}} 26 | 27 | {{/* 28 | Create chart name and version as used by the chart label. 29 | */}} 30 | {{- define "emqx.chart" -}} 31 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} 32 | {{- end -}} 33 | -------------------------------------------------------------------------------- /deploy/charts/emqx/templates/configmap.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: {{ include "emqx.fullname" . }}-env 5 | namespace: {{ .Release.Namespace }} 6 | labels: 7 | app.kubernetes.io/name: {{ include "emqx.name" . }} 8 | helm.sh/chart: {{ include "emqx.chart" . }} 9 | app.kubernetes.io/instance: {{ .Release.Name }} 10 | app.kubernetes.io/managed-by: {{ .Release.Service }} 11 | data: 12 | {{- range $index, $value := .Values.emqxConfig}} 13 | {{$index}}: "{{ $value }}" 14 | {{- end}} -------------------------------------------------------------------------------- /deploy/charts/emqx/templates/configmap_for_acl.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: {{ include "emqx.fullname" . }}-acl 5 | namespace: {{ .Release.Namespace }} 6 | labels: 7 | app.kubernetes.io/name: {{ include "emqx.name" . }} 8 | helm.sh/chart: {{ include "emqx.chart" . }} 9 | app.kubernetes.io/instance: {{ .Release.Name }} 10 | app.kubernetes.io/managed-by: {{ .Release.Service }} 11 | data: 12 | "acl.conf": | 13 | {{ .Values.emqxAclConfig }} -------------------------------------------------------------------------------- /deploy/charts/emqx/templates/ingress.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.ingress.dashboard.enabled -}} 2 | {{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} 3 | apiVersion: networking.k8s.io/v1beta1 4 | {{- else -}} 5 | apiVersion: extensions/v1beta1 6 | {{- end }} 7 | kind: Ingress 8 | metadata: 9 | name: {{ printf "%s-%s" (include "emqx.fullname" .) "dashboard" }} 10 | labels: 11 | app.kubernetes.io/name: {{ include "emqx.name" . }} 12 | helm.sh/chart: {{ include "emqx.chart" . }} 13 | app.kubernetes.io/instance: {{ .Release.Name }} 14 | app.kubernetes.io/managed-by: {{ .Release.Service }} 15 | {{- if .Values.ingress.dashboard.annotations }} 16 | annotations: 17 | {{- toYaml .Values.ingress.dashboard.annotations | nindent 4 }} 18 | {{- end }} 19 | spec: 20 | rules: 21 | {{- range $host := .Values.ingress.dashboard.hosts }} 22 | - host: {{ $host }} 23 | http: 24 | paths: 25 | - path: / 26 | backend: 27 | serviceName: {{ include "emqx.fullname" $ }} 28 | servicePort: {{ $.Values.service.dashboard }} 29 | {{- end -}} 30 | {{- if .Values.ingress.dashboard.tls }} 31 | tls: 32 | {{- toYaml .Values.ingress.dashboard.tls | nindent 4 }} 33 | {{- end }} 34 | --- 35 | {{- end }} 36 | {{- if .Values.ingress.mgmt.enabled -}} 37 | {{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} 38 | apiVersion: networking.k8s.io/v1beta1 39 | {{- else -}} 40 | apiVersion: extensions/v1beta1 41 | {{- end }} 42 | kind: Ingress 43 | metadata: 44 | name: {{ printf "%s-%s" (include "emqx.fullname" .) "mgmt" }} 45 | labels: 46 | app.kubernetes.io/name: {{ include "emqx.name" . }} 47 | helm.sh/chart: {{ include "emqx.chart" . }} 48 | app.kubernetes.io/instance: {{ .Release.Name }} 49 | app.kubernetes.io/managed-by: {{ .Release.Service }} 50 | {{- if .Values.ingress.mgmt.annotations }} 51 | annotations: 52 | {{- toYaml .Values.ingress.mgmt.annotations | nindent 4 }} 53 | {{- end }} 54 | spec: 55 | rules: 56 | {{- range $host := .Values.ingress.mgmt.hosts }} 57 | - host: {{ $host }} 58 | http: 59 | paths: 60 | - path: / 61 | backend: 62 | serviceName: {{ include "emqx.fullname" $ }} 63 | servicePort: {{ $.Values.service.mgmt }} 64 | {{- end -}} 65 | {{- if .Values.ingress.mgmt.tls }} 66 | tls: 67 | {{- toYaml .Values.ingress.mgmt.tls | nindent 4 }} 68 | {{- end }} 69 | --- 70 | {{- end }} -------------------------------------------------------------------------------- /deploy/charts/emqx/templates/rbac.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | namespace: {{ .Release.Namespace }} 5 | name: {{ include "emqx.fullname" . }} 6 | --- 7 | kind: Role 8 | apiVersion: rbac.authorization.k8s.io/v1beta1 9 | metadata: 10 | namespace: {{ .Release.Namespace }} 11 | name: {{ include "emqx.fullname" . }} 12 | rules: 13 | - apiGroups: 14 | - "" 15 | resources: 16 | - endpoints 17 | verbs: 18 | - get 19 | - watch 20 | - list 21 | --- 22 | kind: RoleBinding 23 | apiVersion: rbac.authorization.k8s.io/v1beta1 24 | metadata: 25 | namespace: {{ .Release.Namespace }} 26 | name: {{ include "emqx.fullname" . }} 27 | subjects: 28 | - kind: ServiceAccount 29 | name: {{ include "emqx.fullname" . }} 30 | namespace: {{ .Release.Namespace }} 31 | roleRef: 32 | kind: Role 33 | name: {{ include "emqx.fullname" . }} 34 | apiGroup: rbac.authorization.k8s.io -------------------------------------------------------------------------------- /deploy/charts/emqx/templates/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ include "emqx.fullname" . }} 5 | namespace: {{ .Release.Namespace }} 6 | labels: 7 | app.kubernetes.io/name: {{ include "emqx.name" . }} 8 | helm.sh/chart: {{ include "emqx.chart" . }} 9 | app.kubernetes.io/instance: {{ .Release.Name }} 10 | app.kubernetes.io/managed-by: {{ .Release.Service }} 11 | {{- if .Values.service.annotations }} 12 | annotations: 13 | {{ toYaml .Values.service.annotations | indent 4 }} 14 | {{- end }} 15 | spec: 16 | type: {{ .Values.service.type }} 17 | {{- if eq .Values.service.type "LoadBalancer" }} 18 | {{- if .Values.service.loadBalancerIP }} 19 | loadBalancerIP: {{ .Values.service.loadBalancerIP }} 20 | {{- end }} 21 | {{- if .Values.service.loadBalancerSourceRanges }} 22 | loadBalancerSourceRanges: {{- toYaml .Values.service.loadBalancerSourceRanges | nindent 4 }} 23 | {{- end }} 24 | {{- end }} 25 | ports: 26 | - name: mqtt 27 | port: {{ .Values.service.mqtt | default 1883 }} 28 | protocol: TCP 29 | targetPort: mqtt 30 | {{- if and (or (eq .Values.service.type "NodePort") (eq .Values.service.type "LoadBalancer")) (not (empty .Values.service.nodePorts.mqtt)) }} 31 | nodePort: {{ .Values.service.nodePorts.mqtt }} 32 | {{- else if eq .Values.service.type "ClusterIP" }} 33 | nodePort: null 34 | {{- end }} 35 | - name: mqttssl 36 | port: {{ .Values.service.mqttssl | default 8883 }} 37 | protocol: TCP 38 | targetPort: mqttssl 39 | {{- if and (or (eq .Values.service.type "NodePort") (eq .Values.service.type "LoadBalancer")) (not (empty .Values.service.nodePorts.mqttssl)) }} 40 | nodePort: {{ .Values.service.nodePorts.mqttssl }} 41 | {{- else if eq .Values.service.type "ClusterIP" }} 42 | nodePort: null 43 | {{- end }} 44 | - name: mgmt 45 | port: {{ .Values.service.mgmt | default 8081 }} 46 | protocol: TCP 47 | targetPort: mgmt 48 | {{- if and (or (eq .Values.service.type "NodePort") (eq .Values.service.type "LoadBalancer")) (not (empty .Values.service.nodePorts.mgmt)) }} 49 | nodePort: {{ .Values.service.nodePorts.mgmt }} 50 | {{- else if eq .Values.service.type "ClusterIP" }} 51 | nodePort: null 52 | {{- end }} 53 | - name: ws 54 | port: {{ .Values.service.ws | default 8083 }} 55 | protocol: TCP 56 | targetPort: ws 57 | {{- if and (or (eq .Values.service.type "NodePort") (eq .Values.service.type "LoadBalancer")) (not (empty .Values.service.nodePorts.ws)) }} 58 | nodePort: {{ .Values.service.nodePorts.ws }} 59 | {{- else if eq .Values.service.type "ClusterIP" }} 60 | nodePort: null 61 | {{- end }} 62 | - name: wss 63 | port: {{ .Values.service.wss | default 8084 }} 64 | protocol: TCP 65 | targetPort: wss 66 | {{- if and (or (eq .Values.service.type "NodePort") (eq .Values.service.type "LoadBalancer")) (not (empty .Values.service.nodePorts.wss)) }} 67 | nodePort: {{ .Values.service.nodePorts.wss }} 68 | {{- else if eq .Values.service.type "ClusterIP" }} 69 | nodePort: null 70 | {{- end }} 71 | - name: dashboard 72 | port: {{ .Values.service.dashboard | default 18083 }} 73 | protocol: TCP 74 | targetPort: dashboard 75 | {{- if and (or (eq .Values.service.type "NodePort") (eq .Values.service.type "LoadBalancer")) (not (empty .Values.service.nodePorts.dashboard)) }} 76 | nodePort: {{ .Values.service.nodePorts.dashboard }} 77 | {{- else if eq .Values.service.type "ClusterIP" }} 78 | nodePort: null 79 | {{- end }} 80 | selector: 81 | app.kubernetes.io/name: {{ include "emqx.name" . }} 82 | app.kubernetes.io/instance: {{ .Release.Name }} 83 | 84 | --- 85 | apiVersion: v1 86 | kind: Service 87 | metadata: 88 | name: {{ include "emqx.fullname" . }}-headless 89 | namespace: {{ .Release.Namespace }} 90 | labels: 91 | app.kubernetes.io/name: {{ include "emqx.name" . }} 92 | helm.sh/chart: {{ include "emqx.chart" . }} 93 | app.kubernetes.io/instance: {{ .Release.Name }} 94 | app.kubernetes.io/managed-by: {{ .Release.Service }} 95 | spec: 96 | type: ClusterIP 97 | sessionAffinity: None 98 | clusterIP: None 99 | ports: 100 | - name: mqtt 101 | port: {{ .Values.service.mqtt | default 1883 }} 102 | protocol: TCP 103 | targetPort: mqtt 104 | - name: mqttssl 105 | port: {{ .Values.service.mqttssl | default 8883 }} 106 | protocol: TCP 107 | targetPort: mqttssl 108 | - name: mgmt 109 | port: {{ .Values.service.mgmt | default 8081 }} 110 | protocol: TCP 111 | targetPort: mgmt 112 | - name: ws 113 | port: {{ .Values.service.ws | default 8083 }} 114 | protocol: TCP 115 | targetPort: ws 116 | - name: wss 117 | port: {{ .Values.service.wss | default 8084 }} 118 | protocol: TCP 119 | targetPort: wss 120 | - name: dashboard 121 | port: {{ .Values.service.dashboard | default 18083 }} 122 | protocol: TCP 123 | targetPort: dashboard 124 | - name: ekka 125 | port: 4370 126 | protocol: TCP 127 | targetPort: ekka 128 | selector: 129 | app.kubernetes.io/name: {{ include "emqx.name" . }} 130 | app.kubernetes.io/instance: {{ .Release.Name }} 131 | -------------------------------------------------------------------------------- /deploy/charts/emqx/values.yaml: -------------------------------------------------------------------------------- 1 | ## Default values for emqx. 2 | ## This is a YAML-formatted file. 3 | ## Declare variables to be passed into your templates. 4 | 5 | ## 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. 6 | replicaCount: 3 7 | image: 8 | repository: emqx/emqx 9 | pullPolicy: IfNotPresent 10 | ## Optionally specify an array of imagePullSecrets. 11 | ## Secrets must be manually created in the namespace. 12 | ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ 13 | ## 14 | # pullSecrets: 15 | # - myRegistryKeySecretName 16 | 17 | persistence: 18 | enabled: false 19 | size: 20Mi 20 | ## If defined, volume.beta.kubernetes.io/storage-class: 21 | ## Default: volume.alpha.kubernetes.io/storage-class: default 22 | # storageClass: "-" 23 | accessMode: ReadWriteOnce 24 | ## Existing PersistentVolumeClaims 25 | ## The value is evaluated as a template 26 | ## So, for example, the name can depend on .Release or .Chart 27 | # existingClaim: "" 28 | 29 | resources: {} 30 | # limits: 31 | # cpu: 500m 32 | # memory: 512Mi 33 | # requests: 34 | # cpu: 500m 35 | # memory: 512Mi 36 | 37 | # Containers that run before the creation of EMQX containers. They can contain utilities or setup scripts. 38 | initContainers: {} 39 | # - name: mysql-probe 40 | # image: alpine 41 | # command: ["sh", "-c", "for i in $(seq 1 300); do nc -zvw1 mysql 3306 && exit 0 || sleep 3; done; exit 1"] 42 | 43 | ## EMQX configuration item, see the documentation (https://github.com/emqx/emqx-docker#emq-x-configuration) 44 | emqxConfig: 45 | EMQX_CLUSTER__K8S__APISERVER: "https://kubernetes.default.svc:443" 46 | ## The address type is used to extract host from k8s service. 47 | ## Value: ip | dns | hostname 48 | ## Note:Hostname is only supported after v4.0-rc.2 49 | EMQX_CLUSTER__K8S__ADDRESS_TYPE: "hostname" 50 | EMQX_CLUSTER__K8S__SUFFIX: "svc.cluster.local" 51 | ## if EMQX_CLUSTER__K8S__ADDRESS_TYPE eq dns 52 | # EMQX_CLUSTER__K8S__SUFFIX: "pod.cluster.local" 53 | 54 | ## -------------------------------------------------------------------- 55 | ## [ACL](https://docs.emqx.io/broker/latest/en/advanced/acl-file.html) 56 | 57 | ## -type(who() :: all | binary() | 58 | ## {ipaddr, esockd_access:cidr()} | 59 | ## {client, binary()} | 60 | ## {user, binary()}). 61 | 62 | ## -type(access() :: subscribe | publish | pubsub). 63 | 64 | ## -type(topic() :: binary()). 65 | 66 | ## -type(rule() :: {allow, all} | 67 | ## {allow, who(), access(), list(topic())} | 68 | ## {deny, all} | 69 | ## {deny, who(), access(), list(topic())}). 70 | ## -------------------------------------------------------------------- 71 | emqxAclConfig: > 72 | {allow, {user, "dashboard"}, subscribe, ["$SYS/#"]}. 73 | {allow, {ipaddr, "127.0.0.1"}, pubsub, ["$SYS/#", "#"]}. 74 | {deny, all, subscribe, ["$SYS/#", {eq, "#"}]}. 75 | {allow, all}. 76 | 77 | ## EMQX Enterprise Edition requires manual creation of a Secret containing the licensed content. Write the name of Secret to the value of "emqxLicenseSecretName" 78 | ## Example: 79 | ## kubectl create secret generic emqx-license-secret-name --from-file=/path/to/emqx.lic 80 | emqxLicenseSecretName: 81 | 82 | service: 83 | ## Service type 84 | ## 85 | type: ClusterIP 86 | ## Port for MQTT 87 | ## 88 | mqtt: 1883 89 | ## Port for MQTT(SSL) 90 | ## 91 | mqttssl: 8883 92 | ## Port for mgmt API 93 | ## 94 | mgmt: 8081 95 | ## Port for WebSocket/HTTP 96 | ## 97 | ws: 8083 98 | ## Port for WSS/HTTPS 99 | ## 100 | wss: 8084 101 | ## Port for dashboard 102 | ## 103 | dashboard: 18083 104 | ## Specify the nodePort(s) value for the LoadBalancer and NodePort service types. 105 | ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport 106 | ## 107 | nodePorts: 108 | mqtt: 109 | mqttssl: 110 | mgmt: 111 | ws: 112 | wss: 113 | dashboard: 114 | ## Set the LoadBalancer service type to internal only. 115 | ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#internal-load-balancer 116 | ## 117 | # loadBalancerIP: 118 | ## Load Balancer sources 119 | ## ref: https://kubernetes.io/docs/tasks/access-application-cluster/configure-cloud-provider-firewall/#restrict-access-for-loadbalancer-service 120 | ## Example: 121 | ## loadBalancerSourceRanges: 122 | ## - 10.10.10.0/24 123 | ## 124 | loadBalancerSourceRanges: [] 125 | ## Provide any additional annotations which may be required. Evaluated as a template 126 | ## 127 | annotations: {} 128 | 129 | nodeSelector: {} 130 | 131 | tolerations: [] 132 | 133 | affinity: {} 134 | 135 | ingress: 136 | ## ingress for EMQX Dashboard 137 | dashboard: 138 | enabled: false 139 | annotations: {} 140 | # kubernetes.io/ingress.class: nginx 141 | # kubernetes.io/tls-acme: "true" 142 | path: / 143 | hosts: 144 | - dashboard.emqx.local 145 | tls: [] 146 | 147 | ## ingress for EMQX Mgmt API 148 | mgmt: 149 | enabled: false 150 | annotations: {} 151 | # kubernetes.io/ingress.class: nginx 152 | # kubernetes.io/tls-acme: "true" 153 | path: / 154 | hosts: 155 | - api.emqx.local 156 | tls: [] 157 | 158 | podSecurityContext: 159 | enabled: true 160 | fsGroup: 1000 161 | fsGroupChangePolicy: Always 162 | runAsUser: 1000 163 | supplementalGroups: 164 | - 1000 165 | 166 | containerSecurityContext: 167 | enabled: true 168 | runAsNonRoot: true 169 | runAsUser: 1000 170 | -------------------------------------------------------------------------------- /deploy/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG BUILD_FROM=emqx/build-env:erl22.3-alpine-amd64 2 | ARG RUN_FROM=alpine:3.11 3 | FROM ${BUILD_FROM} AS builder 4 | 5 | ARG QEMU_ARCH=x86_64 6 | COPY tmp/qemu-$QEMU_ARCH-stati* /usr/bin/ 7 | 8 | RUN apk add --no-cache \ 9 | git \ 10 | curl \ 11 | gcc \ 12 | g++ \ 13 | make \ 14 | perl \ 15 | ncurses-dev \ 16 | openssl-dev \ 17 | coreutils \ 18 | bsd-compat-headers \ 19 | libc-dev \ 20 | libstdc++ 21 | 22 | COPY . /emqx-rel 23 | 24 | ARG EMQX_DEPS_DEFAULT_VSN=develop 25 | ARG EMQX_NAME=emqx 26 | 27 | RUN cd /emqx-rel && make $EMQX_NAME 28 | 29 | FROM $RUN_FROM 30 | 31 | # Basic build-time metadata as defined at http://label-schema.org 32 | LABEL org.label-schema.docker.dockerfile="Dockerfile" \ 33 | org.label-schema.license="GNU" \ 34 | org.label-schema.name="emqx" \ 35 | org.label-schema.version=${EMQX_DEPS_DEFAULT_VSN} \ 36 | org.label-schema.description="EMQ (Erlang MQTT Broker) is a distributed, massively scalable, highly extensible MQTT messaging broker written in Erlang/OTP." \ 37 | org.label-schema.url="http://emqx.io" \ 38 | org.label-schema.vcs-type="Git" \ 39 | org.label-schema.vcs-url="https://github.com/emqx/emqx-docker" \ 40 | maintainer="Raymond M Mouthaan , Huang Rui , EMQ X Team " 41 | 42 | ARG QEMU_ARCH=x86_64 43 | ARG EMQX_NAME=emqx 44 | 45 | COPY deploy/docker/docker-entrypoint.sh deploy/docker/start.sh tmp/qemu-$QEMU_ARCH-stati* /usr/bin/ 46 | COPY --from=builder /emqx-rel/_build/$EMQX_NAME/rel/emqx /opt/emqx 47 | 48 | RUN ln -s /opt/emqx/bin/* /usr/local/bin/ 49 | RUN apk add --no-cache curl ncurses-libs openssl sudo libstdc++ bash 50 | 51 | WORKDIR /opt/emqx 52 | 53 | RUN adduser -D -u 1000 emqx \ 54 | && echo "emqx ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers 55 | 56 | RUN chgrp -Rf emqx /opt/emqx && chmod -Rf g+w /opt/emqx \ 57 | && chown -Rf emqx /opt/emqx 58 | 59 | USER emqx 60 | 61 | VOLUME ["/opt/emqx/log", "/opt/emqx/data", "/opt/emqx/lib", "/opt/emqx/etc"] 62 | 63 | # emqx will occupy these port: 64 | # - 1883 port for MQTT 65 | # - 8081 for mgmt API 66 | # - 8083 for WebSocket/HTTP 67 | # - 8084 for WSS/HTTPS 68 | # - 8883 port for MQTT(SSL) 69 | # - 11883 port for internal MQTT/TCP 70 | # - 18083 for dashboard 71 | # - 4369 for port mapping (epmd) 72 | # - 4370 for port mapping 73 | # - 5369 for gen_rpc port mapping 74 | # - 6369 for distributed node 75 | EXPOSE 1883 8081 8083 8084 8883 11883 18083 4369 4370 5369 6369 76 | 77 | ENTRYPOINT ["/usr/bin/docker-entrypoint.sh"] 78 | 79 | CMD ["/usr/bin/start.sh"] 80 | -------------------------------------------------------------------------------- /deploy/docker/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ## EMQ docker image start script 3 | # Huang Rui 4 | # EMQ X Team 5 | 6 | ## Shell setting 7 | if [[ -n "$DEBUG" ]]; then 8 | set -ex 9 | else 10 | set -e 11 | fi 12 | 13 | shopt -s nullglob 14 | 15 | ## Local IP address setting 16 | 17 | 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) 18 | 19 | ## EMQ Base settings and plugins setting 20 | # Base settings in /opt/emqx/etc/emqx.conf 21 | # Plugin settings in /opt/emqx/etc/plugins 22 | 23 | _EMQX_HOME='/opt/emqx' 24 | 25 | if [[ -z "$EMQX_NAME" ]]; then 26 | EMQX_NAME="$(hostname)" 27 | export EMQX_NAME 28 | fi 29 | 30 | if [[ -z "$EMQX_HOST" ]]; then 31 | if [[ "$EMQX_CLUSTER__K8S__ADDRESS_TYPE" == "dns" ]] && [[ -n "$EMQX_CLUSTER__K8S__NAMESPACE" ]]; then 32 | EMQX_CLUSTER__K8S__SUFFIX=${EMQX_CLUSTER__K8S__SUFFIX:-"pod.cluster.local"} 33 | EMQX_HOST="${LOCAL_IP//./-}.$EMQX_CLUSTER__K8S__NAMESPACE.$EMQX_CLUSTER__K8S__SUFFIX" 34 | elif [[ "$EMQX_CLUSTER__K8S__ADDRESS_TYPE" == 'hostname' ]] && [[ -n "$EMQX_CLUSTER__K8S__NAMESPACE" ]]; then 35 | EMQX_CLUSTER__K8S__SUFFIX=${EMQX_CLUSTER__K8S__SUFFIX:-'svc.cluster.local'} 36 | EMQX_HOST=$(grep -h "^$LOCAL_IP" /etc/hosts | grep -o "$(hostname).*.$EMQX_CLUSTER__K8S__NAMESPACE.$EMQX_CLUSTER__K8S__SUFFIX") 37 | else 38 | EMQX_HOST="$LOCAL_IP" 39 | fi 40 | export EMQX_HOST 41 | fi 42 | 43 | if [[ -z "$EMQX_WAIT_TIME" ]]; then 44 | export EMQX_WAIT_TIME=5 45 | fi 46 | 47 | if [[ -z "$EMQX_NODE_NAME" ]]; then 48 | export EMQX_NODE_NAME="$EMQX_NAME@$EMQX_HOST" 49 | fi 50 | 51 | # Set hosts to prevent cluster mode failed 52 | 53 | if [[ -z "$EMQX_NODE__PROCESS_LIMIT" ]]; then 54 | export EMQX_NODE__PROCESS_LIMIT=2097152 55 | fi 56 | 57 | if [[ -z "$EMQX_NODE__MAX_PORTS" ]]; then 58 | export EMQX_NODE__MAX_PORTS=1048576 59 | fi 60 | 61 | if [[ -z "$EMQX_NODE__MAX_ETS_TABLES" ]]; then 62 | export EMQX_NODE__MAX_ETS_TABLES=2097152 63 | fi 64 | 65 | if [[ -z "$EMQX_LISTENER__TCP__EXTERNAL__ACCEPTORS" ]]; then 66 | export EMQX_LISTENER__TCP__EXTERNAL__ACCEPTORS=64 67 | fi 68 | 69 | if [[ -z "$EMQX_LISTENER__TCP__EXTERNAL__MAX_CONNECTIONS" ]]; then 70 | export EMQX_LISTENER__TCP__EXTERNAL__MAX_CONNECTIONS=1024000 71 | fi 72 | 73 | if [[ -z "$EMQX_LISTENER__SSL__EXTERNAL__ACCEPTORS" ]]; then 74 | export EMQX_LISTENER__SSL__EXTERNAL__ACCEPTORS=32 75 | fi 76 | 77 | if [[ -z "$EMQX_LISTENER__SSL__EXTERNAL__MAX_CONNECTIONS" ]]; then 78 | export EMQX_LISTENER__SSL__EXTERNAL__MAX_CONNECTIONS=102400 79 | fi 80 | 81 | if [[ -z "$EMQX_LISTENER__WS__EXTERNAL__ACCEPTORS" ]]; then 82 | export EMQX_LISTENER__WS__EXTERNAL__ACCEPTORS=16 83 | fi 84 | 85 | if [[ -z "$EMQX_LISTENER__WS__EXTERNAL__MAX_CONNECTIONS" ]]; then 86 | export EMQX_LISTENER__WS__EXTERNAL__MAX_CONNECTIONS=102400 87 | fi 88 | 89 | if [[ -z "$EMQX_LISTENER__WSS__EXTERNAL__ACCEPTORS" ]]; then 90 | export EMQX_LISTENER__WSS__EXTERNAL__ACCEPTORS=16 91 | fi 92 | 93 | if [[ -z "$EMQX_LISTENER__WSS__EXTERNAL__MAX_CONNECTIONS" ]]; then 94 | export EMQX_LISTENER__WSS__EXTERNAL__MAX_CONNECTIONS=102400 95 | fi 96 | 97 | # Fix issue #42 - export env EMQX_DASHBOARD__DEFAULT_USER__PASSWORD to configure 98 | # 'dashboard.default_user.password' in etc/plugins/emqx_dashboard.conf 99 | if [[ -n "$EMQX_ADMIN_PASSWORD" ]]; then 100 | export EMQX_DASHBOARD__DEFAULT_USER__PASSWORD=$EMQX_ADMIN_PASSWORD 101 | fi 102 | 103 | # echo value of $VAR hiding secrets if any 104 | # SYNOPSIS 105 | # echo_value KEY VALUE 106 | echo_value() { 107 | # get MASK_CONFIG 108 | MASK_CONFIG_FILTER="$MASK_CONFIG_FILTER|password|passwd|key|token|secret" 109 | 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') 110 | local key=$1 111 | local value=$2 112 | # check if contains sensitive value 113 | if echo "$key" | grep -iqwE "$FORMAT_MASK_CONFIG_FILTER"; then 114 | echo "$key=***secret***" 115 | else 116 | echo "$key=$value" 117 | fi 118 | } 119 | 120 | # fill config on specific file if the key exists 121 | # SYNOPSIS 122 | # try_fill_config FILE KEY VALUE 123 | try_fill_config() { 124 | local file=$1 125 | local key=$2 126 | local value=$3 127 | local escaped_key 128 | # shellcheck disable=SC2001 129 | escaped_key=$(echo "$key" | sed 's/[^a-zA-Z0-9_]/\\&/g') 130 | local escaped_value 131 | escaped_value=$(echo "$value" | sed 's/[\/&]/\\&/g') 132 | if grep -qE "^[#[:space:]]*$escaped_key\s*=" "$file"; then 133 | echo_value "$key" "$value" 134 | if [[ -z "$value" ]]; then 135 | echo "$(sed -r "s/^[#[:space:]]*($escaped_key)\s*=\s*(.*)/# \1 = \2/" "$file")" > "$file" 136 | else 137 | echo "$(sed -r "s/^[#[:space:]]*($escaped_key)\s*=\s*(.*)/\1 = $escaped_value/" "$file")" > "$file" 138 | fi 139 | # Check if config has a numbering system, but no existing configuration line in file 140 | elif echo "$key" | grep -qE '\.\d+|\d+\.'; then 141 | if [[ -n "$value" ]]; then 142 | local template 143 | template="$(echo "$escaped_key" | sed -r -e 's/\\\.[0-9]+/\\.[0-9]+/g' -e 's/[0-9]+\\\./[0-9]+\\./g')" 144 | if grep -qE "^[#[:space:]]*$template\s*=" "$file"; then 145 | echo_value "$key" "$value" 146 | echo "$(sed '$a'\\ "$file")" > "$file" 147 | echo "$key = $value" >> "$file" 148 | fi 149 | fi 150 | fi 151 | } 152 | 153 | # Catch all EMQX_ prefix environment variable and match it in configure file 154 | CONFIG_FILE="$_EMQX_HOME/etc/emqx.conf" 155 | CONFIG_PLUGINS="$_EMQX_HOME/etc/plugins" 156 | for VAR in $(compgen -e); do 157 | # Config normal keys such like node.name = emqx@127.0.0.1 158 | if echo "$VAR" | grep -q '^EMQX_'; then 159 | VAR_NAME=$(echo "$VAR" | sed -e 's/^EMQX_//' -e 's/__/./g' | tr '[:upper:]' '[:lower:]' | tr -d '[:cntrl:]') 160 | VAR_VALUE=$(echo "${!VAR}" | tr -d '[:cntrl:]') 161 | # Config in emqx.conf 162 | try_fill_config "$CONFIG_FILE" "$VAR_NAME" "$VAR_VALUE" 163 | # Config in plugins/* 164 | for CONFIG_PLUGINS_FILE in "$CONFIG_PLUGINS"/*; do 165 | try_fill_config "$CONFIG_PLUGINS_FILE" "$VAR_NAME" "$VAR_VALUE" 166 | done 167 | fi 168 | done 169 | 170 | # fill tuples on specific file 171 | # SYNOPSIS 172 | # fill_tuples FILE [ELEMENTS ...] 173 | fill_tuples() { 174 | local file=$1 175 | local elements=${*:2} 176 | for var in $elements; do 177 | if grep -qE "\{\s*$var\s*,\s*(true|false)\s*\}\s*\." "$file"; then 178 | echo "$(sed -r "s/\{\s*($var)\s*,\s*(true|false)\s*\}\s*\./{\1, true}./1" "$file")" > "$file" 179 | elif grep -q "$var\s*\." "$file"; then 180 | # backward compatible. 181 | echo "$(sed -r "s/($var)\s*\./{\1, true}./1" "$file")" > "$file" 182 | else 183 | echo "$(sed '$a'\\ "$file")" > "$file" 184 | echo "{$var, true}." >> "$file" 185 | fi 186 | done 187 | } 188 | 189 | ## EMQX Plugin load settings 190 | # Plugins loaded by default 191 | LOADED_PLUGINS="$_EMQX_HOME/data/loaded_plugins" 192 | if [[ -n "$EMQX_LOADED_PLUGINS" ]]; then 193 | 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') 194 | echo "EMQX_LOADED_PLUGINS=$EMQX_LOADED_PLUGINS" 195 | # Parse module names and place `{module_name, true}.` tuples in `loaded_plugins`. 196 | fill_tuples "$LOADED_PLUGINS" "$EMQX_LOADED_PLUGINS" 197 | fi 198 | 199 | ## EMQX Modules load settings 200 | # Modules loaded by default 201 | LOADED_MODULES="$_EMQX_HOME/data/loaded_modules" 202 | if [[ -n "$EMQX_LOADED_MODULES" ]]; then 203 | 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') 204 | echo "EMQX_LOADED_MODULES=$EMQX_LOADED_MODULES" 205 | # Parse module names and place `{module_name, true}.` tuples in `loaded_modules`. 206 | fill_tuples "$LOADED_MODULES" "$EMQX_LOADED_MODULES" 207 | fi 208 | 209 | exec "$@" 210 | -------------------------------------------------------------------------------- /deploy/docker/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e -u 3 | 4 | emqx_exit(){ 5 | # At least erlang.log.1 exists 6 | if [ -f /opt/emqx/log/erlang.log.1 ]; then 7 | # tail emqx.log.* 8 | erlang_log=$(echo $(ls -t /opt/emqx/log/erlang.log.*) | awk '{print $1}') 9 | num=$(sed -n -e '/LOGGING STARTED/=' ${erlang_log} | tail -1) 10 | [ ! -z $num ] && [ $num -gt 2 ] && tail -n +$(expr $num - 2) ${erlang_log} 11 | fi 12 | 13 | echo "['$(date -u +"%Y-%m-%dT%H:%M:%SZ")']:emqx exit abnormally" 14 | exit 1 15 | } 16 | 17 | ## EMQ Main script 18 | 19 | # When receiving the EXIT signal, execute emqx_exit function 20 | trap "emqx_exit" EXIT 21 | 22 | # Start and run emqx, and when emqx crashed, this container will stop 23 | /opt/emqx/bin/emqx start 24 | 25 | # Sleep 5 seconds to wait for the loaded plugins catch up. 26 | sleep 5 27 | 28 | echo "['$(date -u +"%Y-%m-%dT%H:%M:%SZ")']:emqx start" 29 | 30 | ## Fork tailing erlang.log, the fork is not killed after this script exits 31 | ## The assumption is that this is the docker entrypoint, 32 | ## hence docker container is terminated after entrypoint exists 33 | tail -f /opt/emqx/log/erlang.log.1 & 34 | 35 | # monitor emqx is running, or the docker must stop to let docker PaaS know 36 | # warning: never use infinite loops such as `` while true; do sleep 1000; done`` here 37 | # you must let user know emqx crashed and stop this container, 38 | # and docker dispatching system can known and restart this container. 39 | IDLE_TIME=0 40 | MGMT_CONF='/opt/emqx/etc/plugins/emqx_management.conf' 41 | MGMT_PORT=$(sed -n -r '/^management.listener.http[ \t]=[ \t].*$/p' $MGMT_CONF | sed -r 's/^management.listener.http = (.*)$/\1/g') 42 | while [ $IDLE_TIME -lt 5 ]; do 43 | IDLE_TIME=$(expr $IDLE_TIME + 1) 44 | if curl http://localhost:${MGMT_PORT}/status >/dev/null 2>&1; then 45 | IDLE_TIME=0 46 | # Print the latest erlang.log 47 | now_erlang_log=$(ps -ef |grep "tail -f /opt/emqx/log/erlang.log" |grep -v grep | sed -r "s/.*tail -f (.*)/\1/g") 48 | new_erlang_log="$(ls -t /opt/emqx/log/erlang.log.* | head -1)" 49 | if [ $now_erlang_log != $new_erlang_log ];then 50 | tail -f $new_erlang_log & 51 | kill $(ps -ef |grep "tail -f $now_erlang_log" | grep -v grep | awk '{print $1}') 52 | fi 53 | else 54 | echo "['$(date -u +"%Y-%m-%dT%H:%M:%SZ")']:emqx not running, waiting for recovery in $((25-IDLE_TIME*5)) seconds" 55 | fi 56 | sleep 5 57 | done 58 | 59 | # If running to here (the result 5 times not is running, thus in 25s emqx is not running), exit docker image 60 | # Then the high level PaaS, e.g. docker swarm mode, will know and alert, rebanlance this service 61 | -------------------------------------------------------------------------------- /deploy/packages/README.md: -------------------------------------------------------------------------------- 1 | emqx-packages 2 | ============= 3 | 4 | EMQX RPM/Debian Packages 5 | 6 | NOTICE: Requires Erlang/OTP R21+ to build since 3.0 release. 7 | 8 | How to use 9 | ---------------------------- 10 | 11 | ``` 12 | cd project-root-directory-path 13 | EMQX_DEPS_DEFAULT_VSN=${version} make emqx-pkg 14 | ``` 15 | 16 | License 17 | ------- 18 | 19 | Apache License Version 2.0 20 | 21 | Author 22 | ------ 23 | 24 | EMQX Team. 25 | -------------------------------------------------------------------------------- /deploy/packages/deb/Makefile: -------------------------------------------------------------------------------- 1 | # Keep this short to avoid bloating beam files with long file path info 2 | TOPDIR := /tmp/emqx 3 | SRCDIR := $(TOPDIR)/$(PKG_VSN) 4 | BUILT := $(SRCDIR)/BUILT 5 | 6 | EMQX_NAME=$(subst -pkg,,$(EMQX_BUILD)) 7 | 8 | TAR_PKG := $(EMQX_REL)/_build/$(EMQX_BUILD)/rel/emqx/emqx-$(PKG_VSN).tar.gz 9 | SOURCE_PKG := $(EMQX_NAME)_$(PKG_VSN)_$(shell dpkg --print-architecture) 10 | TARGET_PKG := $(EMQX_NAME)-$(SYSTEM)-$(PKG_VSN)-$(shell uname -m) 11 | 12 | .PHONY: all 13 | all: | $(BUILT) 14 | cp -r debian $(SRCDIR)/ 15 | sed -i "s##$(shell date -u '+%a, %d %b %Y %T %z')#g" $(SRCDIR)/debian/changelog 16 | sed -i "s##$(PKG_VSN)#g" $(SRCDIR)/debian/changelog 17 | if [ ! -z $(shell echo $(EMQX_NAME) |grep edge) ]; then \ 18 | sed -i "s/emqx-pkg/emqx-edge-pkg/g" $(SRCDIR)/debian/rules; \ 19 | sed -i "s debian/emqx debian/emqx-edge g" $(SRCDIR)/debian/rules; \ 20 | sed -i "s/Package: emqx/Package: emqx-edge/1" $(SRCDIR)/debian/control; \ 21 | fi 22 | cd $(SRCDIR) && dpkg-buildpackage -us -uc 23 | mkdir -p $(EMQX_REL)/_packages/$(EMQX_NAME) 24 | cp $(SRCDIR)/../$(SOURCE_PKG).deb $(EMQX_REL)/_packages/$(EMQX_NAME)/$(TARGET_PKG).deb 25 | 26 | $(BUILT): 27 | mkdir -p $(TOPDIR) $(SRCDIR) 28 | tar zxf $(TAR_PKG) -C $(SRCDIR) 29 | 30 | clean: 31 | rm -rf $(SRCDIR) 32 | -------------------------------------------------------------------------------- /deploy/packages/deb/debian/changelog: -------------------------------------------------------------------------------- 1 | emqx () unstable; urgency=medium 2 | 3 | * See github commit history: https://github.com/emqx/emqx 4 | 5 | -- emqx 6 | -------------------------------------------------------------------------------- /deploy/packages/deb/debian/compat: -------------------------------------------------------------------------------- 1 | 9 2 | -------------------------------------------------------------------------------- /deploy/packages/deb/debian/control: -------------------------------------------------------------------------------- 1 | Source: emqx 2 | Section: unknown 3 | Priority: optional 4 | Maintainer: emqx 5 | Build-Depends: debhelper (>=9) 6 | Standards-Version: 3.9.6 7 | Homepage: https://www.emqx.io 8 | 9 | Package: emqx 10 | Architecture: any 11 | Depends: ${shlibs:Depends}, ${misc:Depends} 12 | Description: EMQX, a distributed, massively scalable, highly extensible MQTT message broker written in Erlang/OTP 13 | -------------------------------------------------------------------------------- /deploy/packages/deb/debian/copyright: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /deploy/packages/deb/debian/init.script: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | ### BEGIN INIT INFO 3 | # Provides: emqx 4 | # Required-Start: $remote_fs $syslog 5 | # Required-Stop: $remote_fs $syslog 6 | # Default-Start: 2 3 4 5 7 | # Default-Stop: 0 1 6 8 | # Short-Description: Erlang MQTT Broker 9 | # Description: EMQX, a distributed, massively scalable, highly extensible MQTT message broker written in Erlang/OT 10 | ### END INIT INFO 11 | 12 | NAME=emqx 13 | DAEMON=/usr/bin/$NAME 14 | SCRIPTNAME=/etc/init.d/$NAME 15 | 16 | # Read configuration variable file if it is present 17 | [ -r /etc/default/$NAME ] && . /etc/default/$NAME 18 | 19 | # Load the VERBOSE setting and other rcS variables 20 | . /lib/init/vars.sh 21 | . /lib/lsb/init-functions 22 | 23 | # `service` strips all environmental VARS so 24 | # if no HOME was set in /etc/default/$NAME then set one here 25 | # to the data directory for erlexec's sake 26 | if [ -z "$HOME" ]; then 27 | export HOME=/var/lib/emqx 28 | fi 29 | 30 | # 31 | # Function that starts the daemon/service 32 | # 33 | do_start() 34 | { 35 | # Return 36 | # 0 if daemon has been started 37 | # 1 if daemon was already running 38 | # 2 if daemon could not be started 39 | 40 | # Startup with the appropriate user 41 | start-stop-daemon --start \ 42 | --name emqx \ 43 | --user emqx \ 44 | --exec $DAEMON -- start \ 45 | || return 2 46 | } 47 | 48 | # 49 | # Function that stops the daemon/service 50 | # 51 | do_stop() 52 | { 53 | # Identify the erts directory 54 | ERTS_PATH=`$DAEMON ertspath` 55 | 56 | # Attempt a clean shutdown. 57 | $DAEMON stop 58 | 59 | # waiting stop done sleep 5 60 | sleep 5 61 | 62 | # Return 63 | # 0 if daemon has been stopped 64 | # 1 if daemon was already stopped 65 | # 2 if daemon could not be stopped 66 | # other if a failure occurred 67 | # Make sure it's down by using a more direct approach 68 | start-stop-daemon --stop \ 69 | --quiet \ 70 | --retry=TERM/30/KILL/5 \ 71 | --user emqx \ 72 | --exec $ERTS_PATH/run_erl 73 | return $? 74 | } 75 | 76 | # 77 | # Function that graceful reload the daemon/service 78 | # 79 | do_reload() { 80 | # Restart the VM without exiting the process 81 | $DAEMON restart && return $? || return 2 82 | } 83 | 84 | # Checks the status of a node 85 | do_status() { 86 | $DAEMON ping && echo $"$NAME is running" && return 0 87 | echo $"$NAME is stopped" && return 2 88 | } 89 | 90 | case "$1" in 91 | start) 92 | log_daemon_msg "Starting $NAME" 93 | $DAEMON ping >/dev/null 2>&1 && echo $"$NAME is already running" && exit 0 94 | do_start 95 | case "$?" in 96 | 0|1) log_end_msg 0 ;; 97 | 2) log_end_msg 1 98 | exit 1 99 | ;; 100 | esac 101 | ;; 102 | stop) 103 | log_daemon_msg "Stopping $NAME" 104 | do_stop 105 | case "$?" in 106 | 0|1) log_end_msg 0 ;; 107 | 2) log_end_msg 1 108 | exit 1 109 | ;; 110 | esac 111 | ;; 112 | ping) 113 | # See if the VM is alive 114 | $DAEMON ping || exit $? 115 | ;; 116 | reload|force-reload) 117 | log_daemon_msg "Reloading $NAME" 118 | do_reload 119 | ES=$? 120 | log_end_msg $ES 121 | exit $ES 122 | ;; 123 | restart) 124 | log_daemon_msg "Restarting $NAME" 125 | do_stop 126 | case "$?" in 127 | 0|1) 128 | do_start 129 | case "$?" in 130 | 0) log_end_msg 0 ;; 131 | 1) log_end_msg 1 && exit 1 ;; # Old process is still running 132 | *) log_end_msg 1 && exit 1 ;; # Failed to start 133 | esac 134 | ;; 135 | *) 136 | # Failed to stop 137 | log_end_msg 1 && exit 1 138 | ;; 139 | esac 140 | ;; 141 | status) 142 | do_status && exit 0 || exit $? 143 | ;; 144 | *) 145 | echo "Usage: $SCRIPTNAME {start|stop|ping|restart|force-reload|status}" >&2 146 | exit 3 147 | ;; 148 | esac 149 | 150 | 151 | -------------------------------------------------------------------------------- /deploy/packages/deb/debian/postinst: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # postinst script for emqx 3 | # 4 | # see: dh_installdeb(1) 5 | 6 | set -e 7 | 8 | # install startup script 9 | update-rc.d emqx defaults >/dev/null 10 | 11 | # create group 12 | if ! getent group emqx >/dev/null; then 13 | addgroup --system emqx 14 | fi 15 | 16 | # create user 17 | if ! getent passwd emqx >/dev/null; then 18 | adduser --ingroup emqx \ 19 | --home /var/lib/emqx \ 20 | --disabled-password \ 21 | --system --shell /bin/bash --no-create-home \ 22 | --gecos "emqx user" emqx 23 | fi 24 | 25 | for i in lib run log; do 26 | chown -R emqx:emqx /var/$i/emqx 27 | done 28 | 29 | chown -R emqx:emqx /usr/lib/emqx 30 | chown -R emqx:emqx /etc/emqx 31 | 32 | chmod 0755 /var/run/emqx /etc/emqx 33 | chmod 0644 /etc/emqx/* 34 | chmod -R +X /etc/emqx 35 | chmod -R 0755 /usr/lib/emqx/bin 36 | [ -f /usr/bin/emqx ] && rm /usr/bin/emqx 37 | [ -f /usr/bin/emqx_ctl ] && rm /usr/bin/emqx_ctl 38 | ln -s /usr/lib/emqx/bin/emqx /usr/bin/emqx 39 | ln -s /usr/lib/emqx/bin/emqx_ctl /usr/bin/emqx_ctl 40 | 41 | case "$1" in 42 | configure) 43 | ;; 44 | 45 | abort-upgrade|abort-remove|abort-deconfigure) 46 | ;; 47 | 48 | *) 49 | echo "postinst called with unknown argument \`$1'" >&2 50 | exit 1 51 | ;; 52 | esac 53 | 54 | # dh_installdeb will replace this with shell code automatically 55 | # generated by other debhelper scripts. 56 | 57 | #DEBHELPER# 58 | 59 | exit 0 60 | -------------------------------------------------------------------------------- /deploy/packages/deb/debian/postrm: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # postrm script for emqx 3 | # 4 | # see: dh_installdeb(1) 5 | 6 | 7 | # summary of how this script can be called: 8 | # * `remove' 9 | # * `purge' 10 | # * `upgrade' 11 | # * `failed-upgrade' 12 | # * `abort-install' 13 | # * `abort-install' 14 | # * `abort-upgrade' 15 | # * `disappear' 16 | # 17 | # for details, see http://www.debian.org/doc/debian-policy/ or 18 | # the debian-policy package 19 | 20 | set -e 21 | 22 | case "$1" in 23 | purge) 24 | rm -f /etc/default/emqx 25 | 26 | # ensure we remove the rc.d scripts installed by postinst 27 | update-rc.d emqx remove >/dev/null 28 | 29 | if [ -d /var/lib/emqx ]; then 30 | rm -r /var/lib/emqx 31 | fi 32 | if [ -d /var/log/emqx ]; then 33 | rm -r /var/log/emqx 34 | fi 35 | if [ -d /var/run/emqx ]; then 36 | rm -r /var/run/emqx 37 | fi 38 | if [ -d /etc/emqx ]; then 39 | rm -r /etc/emqx 40 | fi 41 | if [ -e /etc/init.d/emqx ]; then 42 | rm /etc/init.d/emqx 43 | fi 44 | # Remove User & Group, killing any process owned by them 45 | if getent passwd emqx >/dev/null; then 46 | pkill -u emqx || true 47 | deluser --quiet --system emqx 48 | fi 49 | if getent group emqx >/dev/null; then 50 | delgroup --quiet --system --only-if-empty emqx || true 51 | fi 52 | if [ -f /usr/bin/emqx ]; then 53 | rm /usr/bin/emqx 54 | fi 55 | if [ -f /usr/bin/emqx_ctl ]; then 56 | rm /usr/bin/emqx_ctl 57 | fi 58 | if [ -d /usr/lib/emqx ]; then 59 | rm -r /usr/lib/emqx 60 | fi 61 | ;; 62 | 63 | remove) 64 | rm /usr/bin/emqx 65 | rm /usr/bin/emqx_ctl 66 | ;; 67 | 68 | upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) 69 | ;; 70 | 71 | *) 72 | echo "postrm called with unknown argument \`$1\`" >&2 73 | exit 1 74 | ;; 75 | esac 76 | 77 | # dh_installdeb will replace this with shell code automatically 78 | # generated by other debhelper scripts. 79 | 80 | #DEBHELPER# 81 | 82 | exit 0 83 | -------------------------------------------------------------------------------- /deploy/packages/deb/debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | # -*- makefile -*- 3 | # Sample debian/rules that uses debhelper. 4 | # This file was originally written by Joey Hess and Craig Small. 5 | # As a special exception, when this file is copied by dh-make into a 6 | # dh-make output file, you may use that output file without restriction. 7 | # This special exception was added by Craig Small in version 0.37 of dh-make. 8 | 9 | # modified for node_package by dizzyd@basho.com and jared@basho.com 10 | 11 | # Uncomment this to turn on verbose mode. 12 | export DH_VERBOSE=1 13 | 14 | 15 | ## Clear variables that may confound our build of sub-projects; also 16 | ## note that it is necessary to use overlay_vars relative to .. as 17 | ## the generate command EXECUTES in rel/ 18 | build: 19 | 20 | clean: 21 | dh_clean 22 | rm -f build 23 | # make clean 24 | 25 | ## dh_shlibdeps was added to figure out the dependencies on shared libraries 26 | ## and will populate the ${shlibs:Depends} callout in the control file 27 | install: build 28 | dh_testdir 29 | dh_testroot 30 | dh_prep 31 | dh_installdirs 32 | mkdir -p debian/emqx/usr/lib/emqx 33 | mkdir -p debian/emqx/var/lib/emqx 34 | mkdir -p debian/emqx/var/run/emqx 35 | mkdir -p debian/emqx/var/log/emqx 36 | 37 | mkdir -p debian/emqx/usr/lib/emqx/bin 38 | 39 | mkdir -p debian/emqx/etc/emqx 40 | mkdir -p debian/emqx/etc/init.d 41 | 42 | cp bin/* debian/emqx/usr/lib/emqx/bin 43 | 44 | cp -R lib debian/emqx/usr/lib/emqx 45 | cp -R erts* debian/emqx/usr/lib/emqx 46 | cp -R releases debian/emqx/usr/lib/emqx 47 | cp -R etc/* debian/emqx/etc/emqx 48 | cp -R data/* debian/emqx/var/lib/emqx 49 | install -m755 debian/init.script debian/emqx/etc/init.d/emqx 50 | 51 | dh_shlibdeps 52 | 53 | # We have nothing to do by default. 54 | binary-indep: install build-stamp 55 | build-stamp: 56 | 57 | # Build architecture-dependent files here. 58 | binary-arch: install 59 | dh_strip -a 60 | dh_compress -a 61 | dh_installdeb 62 | dh_gencontrol 63 | dh_builddeb 64 | 65 | binary: binary-indep binary-arch 66 | -------------------------------------------------------------------------------- /deploy/packages/rpm/Makefile: -------------------------------------------------------------------------------- 1 | # Keep this short to avoid bloating beam files with long file path info 2 | TOPDIR := /tmp/emqx 3 | SRCDIR := $(TOPDIR)/$(PKG_VSN) 4 | BUILT := $(SRCDIR)/BUILT 5 | dash := - 6 | none := 7 | space := $(none) $(none) 8 | RPM_VSN ?= $(shell echo $(PKG_VSN) | grep -oE "[0-9]+\.[0-9]+(\.[0-9]+)?") 9 | RPM_REL ?= $(shell echo $(PKG_VSN) | grep -oE "(alpha|beta|rc)\.[0-9]") 10 | 11 | ARCH:=$(shell uname -m) 12 | ifeq ($(ARCH),mips64) 13 | ARCH:=mips64el 14 | endif 15 | 16 | EMQX_NAME=$(subst -pkg,,$(EMQX_BUILD)) 17 | 18 | TAR_PKG := $(EMQX_REL)/_build/$(EMQX_BUILD)/rel/emqx/emqx-$(PKG_VSN).tar.gz 19 | TARGET_PKG := $(EMQX_NAME)-$(SYSTEM)-$(PKG_VSN)-$(ARCH) 20 | ifeq ($(RPM_REL),) 21 | # no tail 22 | RPM_REL := 1 23 | endif 24 | SOURCE_PKG := emqx-$(SYSTEM)-$(RPM_VSN)-$(RPM_REL).$(ARCH) 25 | 26 | SYSTEMD := $(shell if command -v systemctl >/dev/null 2>&1; then echo yes; fi) 27 | # Not $(PWD) as it does not work for make -C 28 | CURDIR := $(shell pwd) 29 | 30 | SERVICE_SRC := $(if $(SYSTEMD),$(CURDIR)/emqx.service,$(CURDIR)/init.script) 31 | SERVICE_DST := $(if $(SYSTEMD),%{_unitdir}/emqx.service,%{_initddir}/emqx) 32 | 33 | POST_ADDITION := $(if $(SYSTEMD),%systemd_post %{_name}.service,echo post) 34 | PREUN_ADDITION := $(if $(SYSTEMD),%systemd_preun %{_name}.service,echo preun) 35 | 36 | .PHONY: all 37 | all: | $(BUILT) 38 | cd $(SRCDIR) 39 | rpmbuild -v -bb \ 40 | --define "_package_name $(EMQX_NAME)" \ 41 | --define "_name emqx" \ 42 | --define "_topdir $(TOPDIR)" \ 43 | --define "_version $(RPM_VSN)" \ 44 | --define "_reldir $(SRCDIR)" \ 45 | --define "_release $(RPM_REL)" \ 46 | --define "_service_src $(SERVICE_SRC)" \ 47 | --define "_service_dst $(SERVICE_DST)" \ 48 | --define "_post_addition $(POST_ADDITION)" \ 49 | --define "_preun_addition $(PREUN_ADDITION)" \ 50 | --define "_ostype -$(SYSTEM)" \ 51 | --define "_sharedstatedir /var/lib" \ 52 | emqx.spec 53 | mkdir -p $(EMQX_REL)/_packages/$(EMQX_NAME) 54 | cp $(TOPDIR)/RPMS/$(ARCH)/$(SOURCE_PKG).rpm $(EMQX_REL)/_packages/$(EMQX_NAME)/$(TARGET_PKG).rpm 55 | 56 | $(BUILT): 57 | mkdir -p $(TOPDIR) $(SRCDIR) $(SRCDIR)/BUILT 58 | tar zxf $(TAR_PKG) -C $(SRCDIR) 59 | 60 | clean: 61 | rm -rf $(SRCDIR) 62 | 63 | -------------------------------------------------------------------------------- /deploy/packages/rpm/emqx.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=emqx daemon 3 | After=network.target 4 | 5 | [Service] 6 | User=emqx 7 | Group=emqx 8 | Type=forking 9 | Environment=HOME=/var/lib/emqx 10 | ExecStart=/bin/sh /usr/bin/emqx start 11 | LimitNOFILE=1048576 12 | ExecStop=/bin/sh /usr/bin/emqx stop 13 | 14 | [Install] 15 | WantedBy=multi-user.target 16 | -------------------------------------------------------------------------------- /deploy/packages/rpm/emqx.spec: -------------------------------------------------------------------------------- 1 | %define debug_package %{nil} 2 | %define _user %{_name} 3 | %define _group %{_name} 4 | %define _conf_dir %{_sysconfdir}/%{_name} 5 | %define _log_dir %{_var}/log/%{_name} 6 | %define _lib_home /usr/lib/%{_name} 7 | %define _var_home %{_sharedstatedir}/%{_name} 8 | %define _build_name_fmt %{_arch}/%{_name}%{?_ostype}-%{_version}-%{_release}.%{_arch}.rpm 9 | %define _build_id_links none 10 | 11 | Name: %{_package_name} 12 | Version: %{_version} 13 | Release: %{_release}%{?dist} 14 | Summary: emqx 15 | Group: System Environment/Daemons 16 | License: Apache License Version 2.0 17 | URL: https://www.emqx.io 18 | BuildRoot: %{_tmppath}/%{_name}-%{_version}-root 19 | Provides: %{_name} 20 | AutoReq: 0 21 | 22 | %description 23 | EMQX, a distributed, massively scalable, highly extensible MQTT message broker written in Erlang/OTP. 24 | 25 | %prep 26 | 27 | %build 28 | 29 | %install 30 | mkdir -p %{buildroot}%{_lib_home} 31 | mkdir -p %{buildroot}%{_log_dir} 32 | mkdir -p %{buildroot}%{_unitdir} 33 | mkdir -p %{buildroot}%{_conf_dir} 34 | mkdir -p %{buildroot}%{_bindir} 35 | mkdir -p %{buildroot}%{_var_home} 36 | mkdir -p %{buildroot}%{_initddir} 37 | 38 | cp -R %{_reldir}/lib %{buildroot}%{_lib_home}/ 39 | cp -R %{_reldir}/erts-* %{buildroot}%{_lib_home}/ 40 | cp -R %{_reldir}/releases %{buildroot}%{_lib_home}/ 41 | cp -R %{_reldir}/bin %{buildroot}%{_lib_home}/ 42 | cp -R %{_reldir}/etc/* %{buildroot}%{_conf_dir}/ 43 | cp -R %{_reldir}/data/* %{buildroot}%{_var_home}/ 44 | install -m644 %{_service_src} %{buildroot}%{_service_dst} 45 | 46 | %pre 47 | if [ $1 = 1 ]; then 48 | # Initial installation 49 | /usr/bin/getent group %{_group} >/dev/null || /usr/sbin/groupadd -r %{_group} 50 | if ! /usr/bin/getent passwd %{_user} >/dev/null ; then 51 | /usr/sbin/useradd -r -g %{_group} -m -d %{_sharedstatedir}/%{_name} -c "%{_name}" %{_user} 52 | fi 53 | fi 54 | 55 | %post 56 | if [ $1 = 1 ]; then 57 | ln -s %{_lib_home}/bin/emqx %{_bindir}/emqx 58 | ln -s %{_lib_home}/bin/emqx_ctl %{_bindir}/emqx_ctl 59 | fi 60 | %{_post_addition} 61 | if [ -e %{_initddir}/%{_name} ] ; then 62 | /sbin/chkconfig --add %{_name} 63 | else 64 | systemctl enable %{_name}.service 65 | fi 66 | chown -R %{_user}:%{_group} %{_lib_home} 67 | 68 | %preun 69 | %{_preun_addition} 70 | # Only on uninstall, not upgrades 71 | if [ $1 = 0 ]; then 72 | if [ -e %{_initddir}/%{_name} ] ; then 73 | /sbin/service %{_name} stop > /dev/null 2>&1 74 | /sbin/chkconfig --del %{_name} 75 | else 76 | systemctl disable %{_name}.service 77 | fi 78 | rm -f %{_bindir}/emqx 79 | rm -f %{_bindir}/emqx_ctl 80 | fi 81 | exit 0 82 | 83 | %postun 84 | if [ $1 = 0 ]; then 85 | rm -rf %{_lib_home} 86 | fi 87 | exit 0 88 | 89 | %files 90 | %defattr(-,root,root) 91 | %{_service_dst} 92 | %attr(-,%{_user},%{_group}) %{_lib_home}/* 93 | %attr(-,%{_user},%{_group}) %dir %{_var_home} 94 | %attr(-,%{_user},%{_group}) %config(noreplace) %{_var_home}/* 95 | %attr(-,%{_user},%{_group}) %dir %{_log_dir} 96 | %attr(-,%{_user},%{_group}) %config(noreplace) %{_conf_dir}/* 97 | 98 | %clean 99 | rm -rf %{buildroot} 100 | 101 | %changelog 102 | 103 | -------------------------------------------------------------------------------- /deploy/packages/rpm/init.script: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # emqx 4 | # 5 | # chkconfig: 2345 80 30 6 | # description: EMQX, a distributed, massively scalable, highly extensible MQTT message broker written in Erlang/OTP 7 | # processname: beam 8 | # 9 | 10 | # Source function library. 11 | . /etc/rc.d/init.d/functions 12 | 13 | RETVAL=0 14 | PATH=/sbin:/usr/sbin:/bin:/usr/bin 15 | DESC="EMQX, a distributed, massively scalable, highly extensible MQTT message broker written in Erlang/OTP" 16 | NAME=emqx 17 | DAEMON=/usr/bin/$NAME 18 | lockfile=/var/lock/subsys/$NAME 19 | mkdir -p /var/run/$NAME 20 | pidfile=/var/run/$NAME/$NAME.pid 21 | 22 | # Check for script, config and data dirs 23 | [ -x /usr/bin/$NAME ] || exit 0 24 | [ -d /etc/$NAME ] || exit 0 25 | [ -d /var/lib/$NAME ] || exit 0 26 | 27 | # Read configuration variable file if it is present and readable 28 | [ -r /etc/sysconfig/$NAME ] && . /etc/sysconfig/$NAME 29 | 30 | # `service` strips all environmental VARS so 31 | # if no HOME was set in /etc/sysconfig/$NAME then set one here 32 | # to the data directory for erlexec's sake 33 | if [ -z "$HOME" ]; then 34 | export HOME= 35 | fi 36 | 37 | status -p $pidfile -l $(basename $lockfile) $NAME >/dev/null 2>&1 38 | running=$? 39 | 40 | find_pid() { 41 | ps ax | grep beam.smp | grep -E "\-progname.+$NAME" | awk '{print $1}' 42 | } 43 | 44 | check_pid_status() { 45 | local pid="$(find_pid)" 46 | if [ "$pid" = "" ]; then 47 | # prog not running? 48 | return 1 49 | else 50 | # running 51 | return 0 52 | fi 53 | } 54 | 55 | start() { 56 | # Start daemons. 57 | echo -n $"Starting emqx: " 58 | $DAEMON start 59 | RETVAL=$? 60 | if [ $RETVAL -eq 0 ]; then 61 | touch $lockfile 62 | find_pid > $pidfile 63 | success 64 | else 65 | failure $"$NAME start" 66 | fi 67 | echo 68 | return $RETVAL 69 | } 70 | 71 | stop() { 72 | # Stop daemon. 73 | echo -n $"Shutting down emqx: " 74 | $DAEMON stop 2>/dev/null 75 | for n in $(seq 1 10); do 76 | sleep 1 77 | check_pid_status 78 | RETVAL=$? 79 | if [ $RETVAL -eq 1 ]; then 80 | break 81 | fi 82 | done 83 | if [ $RETVAL -eq 1 ]; then 84 | rm -f $lockfile $pidfile 85 | success 86 | echo && return 0 87 | else 88 | failure $"$NAME stop" 89 | echo && return 1 90 | fi 91 | } 92 | 93 | hardstop() { 94 | echo -n $"Shutting down $NAME: " 95 | su - emqx -c "ps -ef | grep beam.smp | grep '\-progname $NAME ' | grep -v grep | awk '{print \$2}' | xargs kill -9" 96 | for n in $(seq 1 10); do 97 | sleep 1 98 | check_pid_status 99 | RETVAL=$? 100 | if [ $RETVAL -eq 1 ]; then 101 | break 102 | fi 103 | done 104 | if [ $RETVAL -eq 1 ]; then 105 | rm -f $lockfile $pidfile 106 | success 107 | echo && return 0 108 | else 109 | failure $"$NAME hardstop" 110 | echo && return 1 111 | fi 112 | } 113 | 114 | # See how we were called. 115 | case "$1" in 116 | start) 117 | [ $running -eq 0 ] && exit 0 118 | start 119 | ;; 120 | stop) 121 | stop 122 | ;; 123 | restart|force-reload) 124 | [ $running -eq 0 ] && stop 125 | start 126 | ;; 127 | hardstop) 128 | [ $running -eq 0 ] || exit 0 129 | hardstop 130 | ;; 131 | condrestart|try-restart) 132 | [ $running -eq 0 ] || exit 0 133 | restart 134 | ;; 135 | status) 136 | status -p $pidfile -l $(basename $lockfile) $NAME 137 | ;; 138 | ping) 139 | $DAEMON ping || exit $? 140 | ;; 141 | *) 142 | echo $"Usage: $0 {start|stop|restart|force-reload|hardstop|condrestart|try-restart|status|ping}" 143 | exit 1 144 | esac 145 | 146 | exit $? 147 | -------------------------------------------------------------------------------- /docker.mk: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | # -*- makefile -*- 3 | 4 | ## default globals 5 | TARGET ?= emqx/emqx 6 | QEMU_ARCH ?= x86_64 7 | ARCH ?= amd64 8 | QEMU_VERSION ?= v5.0.0-2 9 | OS ?= alpine 10 | 11 | EMQX_NAME = $(subst emqx/,,$(TARGET)) 12 | ARCH_LIST = amd64 arm64v8 arm32v7 i386 s390x 13 | 14 | .PHONY: docker 15 | docker: docker-build docker-tag docker-save 16 | 17 | .PHONY: docker-prepare 18 | docker-prepare: 19 | ## Prepare the machine before any code installation scripts 20 | # @echo "PREPARE: Setting up dependencies." 21 | # @apt update -y 22 | # @apt install --only-upgrade docker-ce -y 23 | 24 | ## Update docker configuration to enable docker manifest command 25 | @echo "PREPARE: Updating docker configuration" 26 | @mkdir -p $$HOME/.docker 27 | 28 | # enable experimental to use docker manifest command 29 | @echo '{ "experimental": "enabled" }' | tee $$HOME/.docker/config.json 30 | # enable experimental 31 | @echo '{ "experimental": true, "storage-driver": "overlay2", "max-concurrent-downloads": 50, "max-concurrent-uploads": 50 }' | tee /etc/docker/daemon.json 32 | @service docker restart 33 | 34 | .PHONY: docker-build 35 | docker-build: 36 | ## Build Docker image 37 | @echo "DOCKER BUILD: Build Docker image." 38 | @echo "DOCKER BUILD: build version -> $(PKG_VSN)." 39 | @echo "DOCKER BUILD: arch - $(ARCH)." 40 | @echo "DOCKER BUILD: qemu arch - $(QEMU_ARCH)." 41 | @echo "DOCKER BUILD: docker repo - $(TARGET) " 42 | @echo "DOCKER BUILD: emqx name - $(EMQX_NAME)." 43 | @echo "DOCKER BUILD: emqx version - $(EMQX_DEPS_DEFAULT_VSN)." 44 | 45 | ## Prepare qemu to build images other then x86_64 on travis 46 | @echo "PREPARE: Qemu" \ 47 | && docker run --rm --privileged multiarch/qemu-user-static:register --reset 48 | 49 | @mkdir -p tmp \ 50 | && cd tmp \ 51 | && curl -L -o qemu-$(QEMU_ARCH)-static.tar.gz https://github.com/multiarch/qemu-user-static/releases/download/$(QEMU_VERSION)/qemu-$(QEMU_ARCH)-static.tar.gz \ 52 | && tar xzf qemu-$(QEMU_ARCH)-static.tar.gz \ 53 | && cd - 54 | 55 | @docker build --no-cache \ 56 | --build-arg EMQX_DEPS_DEFAULT_VSN=$(EMQX_DEPS_DEFAULT_VSN) \ 57 | --build-arg BUILD_FROM=emqx/build-env:erl22.3-alpine-$(ARCH) \ 58 | --build-arg RUN_FROM=$(ARCH)/alpine:3.11 \ 59 | --build-arg EMQX_NAME=$(EMQX_NAME) \ 60 | --build-arg QEMU_ARCH=$(QEMU_ARCH) \ 61 | --tag $(TARGET):build-$(OS)-$(ARCH) \ 62 | -f deploy/docker/Dockerfile . 63 | 64 | .PHONY: docker-tag 65 | docker-tag: 66 | @echo "DOCKER TAG: Tag Docker image." 67 | @for arch in $(ARCH_LIST); do \ 68 | if [ -n "$$(docker images -q $(TARGET):build-$(OS)-$${arch})" ]; then \ 69 | docker tag $(TARGET):build-$(OS)-$${arch} $(TARGET):$(PKG_VSN)-$(OS)-$${arch}; \ 70 | echo "DOCKER TAG: $(TARGET):$(PKG_VSN)-$(OS)-$${arch}"; \ 71 | if [ $${arch} = amd64 ]; then \ 72 | docker tag $(TARGET):$(PKG_VSN)-$(OS)-amd64 $(TARGET):$(PKG_VSN); \ 73 | echo "DOCKER TAG: $(TARGET):$(PKG_VSN)"; \ 74 | fi; \ 75 | fi; \ 76 | done 77 | 78 | .PHONY: docker-save 79 | docker-save: 80 | @echo "DOCKER SAVE: Save Docker image." 81 | 82 | @mkdir -p _packages/$(EMQX_NAME) 83 | 84 | @if [ -n "$$(docker images -q $(TARGET):$(PKG_VSN))" ]; then \ 85 | docker save $(TARGET):$(PKG_VSN) > $(EMQX_NAME)-docker-$(PKG_VSN); \ 86 | zip -r -m $(EMQX_NAME)-docker-$(PKG_VSN).zip $(EMQX_NAME)-docker-$(PKG_VSN); \ 87 | mv ./$(EMQX_NAME)-docker-$(PKG_VSN).zip _packages/$(EMQX_NAME)/$(EMQX_NAME)-docker-$(PKG_VSN).zip; \ 88 | fi 89 | 90 | @for arch in $(ARCH_LIST); do \ 91 | if [ -n "$$(docker images -q $(TARGET):$(PKG_VSN)-$(OS)-$${arch})" ]; then \ 92 | docker save $(TARGET):$(PKG_VSN)-$(OS)-$${arch} > $(EMQX_NAME)-docker-$(PKG_VSN)-$(OS)-$${arch}; \ 93 | zip -r -m $(EMQX_NAME)-docker-$(PKG_VSN)-$(OS)-$${arch}.zip $(EMQX_NAME)-docker-$(PKG_VSN)-$(OS)-$${arch}; \ 94 | mv ./$(EMQX_NAME)-docker-$(PKG_VSN)-$(OS)-$${arch}.zip _packages/$(EMQX_NAME)/$(EMQX_NAME)-docker-$(PKG_VSN)-$(OS)-$${arch}.zip; \ 95 | fi; \ 96 | done 97 | 98 | .PHONY: docker-push 99 | docker-push: 100 | @echo "DOCKER PUSH: Push Docker image."; 101 | @echo "DOCKER PUSH: pushing - $(TARGET):$(PKG_VSN)."; 102 | 103 | @if [ -n "$$(docker images -q $(TARGET):$(PKG_VSN))" ]; then \ 104 | docker push $(TARGET):$(PKG_VSN); \ 105 | docker tag $(TARGET):$(PKG_VSN) $(TARGET):latest; \ 106 | docker push $(TARGET):latest; \ 107 | fi; 108 | 109 | @for arch in $(ARCH_LIST); do \ 110 | if [ -n "$$(docker images -q $(TARGET):$(PKG_VSN)-$(OS)-$${arch})" ]; then \ 111 | docker push $(TARGET):$(PKG_VSN)-$(OS)-$${arch}; \ 112 | fi; \ 113 | done 114 | 115 | .PHONY: docker-manifest-list 116 | docker-manifest-list: 117 | version="docker manifest create --amend $(TARGET):$(PKG_VSN)"; \ 118 | latest="docker manifest create --amend $(TARGET):latest"; \ 119 | for arch in $(ARCH_LIST); do \ 120 | if [ -n "$$(docker images -q $(TARGET):$(PKG_VSN)-$(OS)-$${arch})" ];then \ 121 | version="$${version} $(TARGET):$(PKG_VSN)-$(OS)-$${arch} "; \ 122 | latest="$${latest} $(TARGET):$(PKG_VSN)-$(OS)-$${arch} "; \ 123 | fi; \ 124 | done; \ 125 | eval $$version; \ 126 | eval $$latest; 127 | 128 | for arch in $(ARCH_LIST); do \ 129 | case $${arch} in \ 130 | "amd64") \ 131 | if [ -n "$$(docker images -q $(TARGET):$(PKG_VSN)-$(OS)-$${arch})" ]; then \ 132 | docker manifest annotate $(TARGET):$(PKG_VSN) $(TARGET):$(PKG_VSN)-$(OS)-amd64 --os=linux --arch=amd64; \ 133 | docker manifest annotate $(TARGET):latest $(TARGET):$(PKG_VSN)-$(OS)-amd64 --os=linux --arch=amd64; \ 134 | fi; \ 135 | ;; \ 136 | "arm64v8") \ 137 | if [ -n "$$(docker images -q $(TARGET):$(PKG_VSN)-$(OS)-$${arch})" ]; then \ 138 | docker manifest annotate $(TARGET):$(PKG_VSN) $(TARGET):$(PKG_VSN)-$(OS)-arm64v8 --os=linux --arch=arm64 --variant=v8; \ 139 | docker manifest annotate $(TARGET):latest $(TARGET):$(PKG_VSN)-$(OS)-arm64v8 --os=linux --arch=arm64 --variant=v8; \ 140 | fi; \ 141 | ;; \ 142 | "arm32v7") \ 143 | if [ -n "$$(docker images -q $(TARGET):$(PKG_VSN)-$(OS)-$${arch})" ]; then \ 144 | docker manifest annotate $(TARGET):$(PKG_VSN) $(TARGET):$(PKG_VSN)-$(OS)-arm32v7 --os=linux --arch=arm --variant=v7; \ 145 | docker manifest annotate $(TARGET):latest $(TARGET):$(PKG_VSN)-$(OS)-arm32v7 --os=linux --arch=arm --variant=v7; \ 146 | fi; \ 147 | ;; \ 148 | "i386") \ 149 | if [ -n "$$(docker images -q $(TARGET):$(PKG_VSN)-$(OS)-$${arch})" ]; then \ 150 | docker manifest annotate $(TARGET):$(PKG_VSN) $(TARGET):$(PKG_VSN)-$(OS)-i386 --os=linux --arch=386; \ 151 | docker manifest annotate $(TARGET):latest $(TARGET):$(PKG_VSN)-$(OS)-i386 --os=linux --arch=386; \ 152 | fi; \ 153 | ;; \ 154 | "s390x") \ 155 | if [ -n "$$(docker images -q $(TARGET):$(PKG_VSN)-$(OS)-$${arch})" ]; then \ 156 | docker manifest annotate $(TARGET):$(PKG_VSN) $(TARGET):$(PKG_VSN)-$(OS)-s390x --os=linux --arch=s390x; \ 157 | docker manifest annotate $(TARGET):latest $(TARGET):$(PKG_VSN)-$(OS)-s390x --os=linux --arch=s390x; \ 158 | fi; \ 159 | ;; \ 160 | esac; \ 161 | done; 162 | 163 | docker manifest inspect $(TARGET):$(PKG_VSN) 164 | docker manifest push $(TARGET):$(PKG_VSN); 165 | docker manifest inspect $(TARGET):latest 166 | docker manifest push $(TARGET):latest; 167 | 168 | .PHONY: docker-clean 169 | docker-clean: 170 | @echo "DOCKER CLEAN: Clean Docker image." 171 | 172 | @if [ -n "$$(docker images -q $(TARGET):$(PKG_VSN))" ]; then docker rmi -f $$(docker images -q $(TARGET):$(PKG_VSN)); fi 173 | 174 | @for arch in $(ARCH_LIST); do \ 175 | if [ -n "$$(docker images -q $(TARGET):$(PKG_VSN)-$(OS)-$${arch})" ]; then \ 176 | docker rmi -f $$(docker images -q $(TARGET):$(PKG_VSN)-$(OS)-$${arch}); \ 177 | fi \ 178 | done 179 | -------------------------------------------------------------------------------- /ensure-rebar3.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | #set -euo pipefail 4 | set -eu 5 | 6 | VERSION="$1" 7 | 8 | DOWNLOAD_URL='https://github.com/emqx/rebar3/releases/download' 9 | 10 | download() { 11 | curl -f -L "${DOWNLOAD_URL}/${VERSION}/rebar3" -o ./rebar3 12 | } 13 | 14 | # get the version number from the second line of the escript 15 | # because command `rebar3 -v` tries to load rebar.config 16 | # which is slow and may print some logs 17 | version() { 18 | head -n 2 ./rebar3 | tail -n 1 | tr ' ' '\n' | grep -E '^.+-emqx-.+' 19 | } 20 | 21 | if [ -f 'rebar3' ] && [ "$(version)" = "$VERSION" ]; then 22 | exit 0 23 | fi 24 | 25 | download 26 | chmod +x ./rebar3 27 | -------------------------------------------------------------------------------- /get-lastest-tag.escript: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env escript 2 | %% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*- 3 | %% ex: ft=erlang ts=4 sw=4 et 4 | %% ------------------------------------------------------------------- 5 | %% 6 | %% nodetool: Helper Script for interacting with live nodes 7 | %% 8 | %% ------------------------------------------------------------------- 9 | 10 | main(Args) -> 11 | case Args of 12 | ["ref"] -> io:format(getRef()); 13 | ["tag"] -> io:format(latestTag()) 14 | end. 15 | 16 | comparingFun([C1|R1], [C2|R2]) when is_list(C1), is_list(C2); 17 | is_integer(C1), is_integer(C2) -> C1 < C2 orelse comparingFun(R1, R2); 18 | comparingFun([C1|R1], [C2|R2]) when is_integer(C1), is_list(C2) -> comparingFun(R1, R2); 19 | comparingFun([C1|_R1], [C2|_R2]) when is_list(C1), is_integer(C2) -> true; 20 | comparingFun(_, _) -> false. 21 | 22 | sortFun(T1, T2) -> 23 | C = fun(T) -> 24 | [case catch list_to_integer(E) of 25 | I when is_integer(I) -> I; 26 | _ -> E 27 | end || E <- re:split(string:sub_string(T, 2), "[.-]", [{return, list}])] 28 | end, 29 | comparingFun(C(T1), C(T2)). 30 | 31 | latestTag() -> 32 | Tag = os:cmd("git describe --abbrev=0 --tags") -- "\n", 33 | LatestTagCommitId = os:cmd(io_lib:format("git rev-parse ~s", [Tag])) -- "\n", 34 | Tags = string:tokens(os:cmd(io_lib:format("git tag -l \"v*\" --points-at ~s", [LatestTagCommitId])), "\n"), 35 | lists:last(lists:sort(fun(T1, T2) -> sortFun(T1, T2) end, Tags)). 36 | 37 | branch() -> 38 | case os:getenv("GITHUB_RUN_ID") of 39 | false -> os:cmd("git branch | grep -e '^*' | cut -d' ' -f 2") -- "\n"; 40 | _ -> re:replace(os:getenv("GITHUB_REF"), "^refs/heads/|^refs/tags/", "", [global, {return ,list}]) 41 | end. 42 | 43 | getRef() -> 44 | case re:run(branch(), "master|^dev/|^hotfix/", [{capture, none}]) of 45 | match -> branch(); 46 | _ -> latestTag() 47 | end. 48 | 49 | -------------------------------------------------------------------------------- /inject-deps.escript: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env escript 2 | 3 | %% This script injects implicit relup dependencies for emqx applications. 4 | %% 5 | %% By 'implicit', it means that it is not feasible to define application 6 | %% dependencies in .app.src files. 7 | %% 8 | %% For instance, during upgrade/downgrade, emqx_dashboard usually requires 9 | %% a restart after (but not before) all plugins are upgraded (and maybe 10 | %% restarted), however, the dependencies are not resolvable at build time 11 | %% when relup is generated. 12 | %% 13 | %% This script is to be executed after compile, with the profile given as the 14 | %% first argument. For each dependency overlay, it modifies the .app file to 15 | %% have the 'relup_deps' list extended. 16 | 17 | -mode(compile). 18 | 19 | usage() -> 20 | "Usage: " ++ escript:script_name() ++ " emqx|emqx-edge". 21 | 22 | -type app() :: atom(). 23 | -type deps_overlay() :: {re, string()} | app(). 24 | 25 | %% deps/0 returns the dependency overlays. 26 | %% {re, Pattern} to match application names using regexp pattern 27 | -spec deps(string()) -> [{app(), [deps_overlay()]}]. 28 | deps("emqx-edge" ++ _) -> 29 | %% special case for edge 30 | base_deps() ++ [{{re, ".+"}, [{exclude, emqx_reloader}]}]; 31 | deps(_Profile) -> 32 | base_deps(). 33 | 34 | base_deps() -> 35 | [ {emqx_dashboard, [{re, "emqx_.*"}]} 36 | , {emqx_management, [{re, "emqx_.*"}, {exclude, emqx_dashboard}]} 37 | , {{re, "emqx_.*"}, [emqx]} 38 | , {{re, "emqx_auth_.*"}, [emqx_passwd]} 39 | ]. 40 | 41 | main([Profile | _]) -> 42 | ok = inject(Profile); 43 | main(_Args) -> 44 | io:format(standard_error, "~s", [usage()]), 45 | erlang:halt(1). 46 | 47 | expand_names({Name, Deps}, AppNames) -> 48 | Names = match_pattern(Name, AppNames), 49 | [{N, Deps} || N <- Names]. 50 | 51 | %% merge k-v pairs with v1 ++ v2 52 | merge([], Acc) -> Acc; 53 | merge([{K, V0} | Rest], Acc) -> 54 | V = case lists:keyfind(K, 1, Acc) of 55 | {K, V1} -> V1 ++ V0; 56 | false -> V0 57 | end, 58 | NewAcc = lists:keystore(K, 1, Acc, {K, V}), 59 | merge(Rest, NewAcc). 60 | 61 | expand_deps([], _AppNames, Acc) -> Acc; 62 | expand_deps([{exclude, Dep} | Deps], AppNames, Acc) -> 63 | Matches = expand_deps([Dep], AppNames, []), 64 | expand_deps(Deps, AppNames, Acc -- Matches); 65 | expand_deps([Dep | Deps], AppNames, Acc) -> 66 | NewAcc = add_to_list(Acc, match_pattern(Dep, AppNames)), 67 | expand_deps(Deps, AppNames, NewAcc). 68 | 69 | inject(Profile) -> 70 | LibDir = lib_dir(Profile), 71 | AppNames = list_apps(LibDir), 72 | Deps0 = lists:flatmap(fun(Dep) -> expand_names(Dep, AppNames) end, deps(Profile)), 73 | Deps1 = merge(Deps0, []), 74 | Deps2 = lists:map(fun({Name, DepsX}) -> 75 | NewDeps = expand_deps(DepsX, AppNames, []), 76 | {Name, NewDeps} 77 | end, Deps1), 78 | lists:foreach(fun({App, Deps}) -> inject(App, Deps, LibDir) end, Deps2). 79 | 80 | %% list the profile/lib dir to get all apps 81 | list_apps(LibDir) -> 82 | Apps = filelib:wildcard("*", LibDir), 83 | lists:foldl(fun(App, Acc) -> [App || is_app(LibDir, App)] ++ Acc end, [], Apps). 84 | 85 | is_app(_LibDir, "." ++ _) -> false; %% ignore hidden dir 86 | is_app(LibDir, AppName) -> 87 | filelib:is_regular(filename:join([ebin_dir(LibDir, AppName), AppName ++ ".app"])) orelse 88 | error({unknown_app, AppName}). %% wtf 89 | 90 | lib_dir(Profile) -> 91 | filename:join(["_build", Profile, lib]). 92 | 93 | ebin_dir(LibDir, AppName) -> filename:join([LibDir, AppName, "ebin"]). 94 | 95 | inject(App0, DepsToAdd, LibDir) -> 96 | App = str(App0), 97 | AppEbinDir = ebin_dir(LibDir, App), 98 | [AppFile0] = filelib:wildcard("*.app", AppEbinDir), 99 | AppFile = filename:join(AppEbinDir, AppFile0), 100 | {ok, [{application, AppName, Props}]} = file:consult(AppFile), 101 | Deps0 = case lists:keyfind(relup_deps, 1, Props) of 102 | {_, X} -> X; 103 | false -> [] 104 | end, 105 | %% merge extra deps, but do not self-include 106 | Deps = add_to_list(Deps0, DepsToAdd) -- [App0], 107 | case Deps =:= [] of 108 | true -> ok; 109 | _ -> 110 | NewProps = lists:keystore(relup_deps, 1, Props, {relup_deps, Deps}), 111 | AppSpec = {application, AppName, NewProps}, 112 | AppSpecIoData = io_lib:format("~p.", [AppSpec]), 113 | io:format(user, "updated_relup_deps for ~p~n", [App]), 114 | file:write_file(AppFile, AppSpecIoData) 115 | end. 116 | 117 | str(A) when is_atom(A) -> atom_to_list(A). 118 | 119 | match_pattern({re, Re}, AppNames) -> 120 | Match = fun(AppName) -> re:run(AppName, Re) =/= nomatch end, 121 | AppNamesToAdd = lists:filter(Match, AppNames), 122 | AppsToAdd = lists:map(fun(N) -> list_to_atom(N) end, AppNamesToAdd), 123 | case AppsToAdd =:= [] of 124 | true -> error({nomatch, Re}); 125 | false -> AppsToAdd 126 | end; 127 | match_pattern(NameAtom, AppNames) -> 128 | case lists:member(str(NameAtom), AppNames) of 129 | true -> [NameAtom]; 130 | false -> error({notfound, NameAtom}) 131 | end. 132 | 133 | %% Append elements to list without duplication. No reordering. 134 | add_to_list(List, []) -> List; 135 | add_to_list(List, [H | T]) -> 136 | case lists:member(H, List) of 137 | true -> add_to_list(List, T); 138 | false -> add_to_list(List ++ [H], T) 139 | end. 140 | -------------------------------------------------------------------------------- /packages.mk: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | # -*- makefile -*- 3 | 4 | PROFILES := emqx emqx-edge 5 | PKG_PROFILES := emqx-pkg emqx-edge-pkg 6 | 7 | ifeq ($(shell uname -s),Darwin) 8 | SYSTEM := macos 9 | else ifeq ($(shell uname -s),Linux) 10 | ifneq ($(shell cat /etc/*-release |grep -o -i centos),) 11 | ID := centos 12 | VERSION_ID := $(shell rpm --eval '%{centos_ver}') 13 | else 14 | ID := $(shell sed -n '/^ID=/p' /etc/os-release | sed -r 's/ID=(.*)/\1/g' | sed 's/"//g' ) 15 | VERSION_ID := $(shell sed -n '/^VERSION_ID=/p' /etc/os-release | sed -r 's/VERSION_ID=(.*)/\1/g' | sed 's/"//g') 16 | endif 17 | SYSTEM := $(shell echo $(ID)$(VERSION_ID) | sed -r "s/([a-zA-Z]*)-.*/\1/g") 18 | ## 19 | ## Support RPM and Debian based linux systems 20 | ## 21 | ifeq ($(ID),ubuntu) 22 | PKGERDIR := deb 23 | else ifeq ($(ID),debian) 24 | PKGERDIR := deb 25 | else ifeq ($(ID),raspbian) 26 | PKGERDIR := deb 27 | else 28 | PKGERDIR := rpm 29 | endif 30 | endif 31 | 32 | .PHONY: relup-emqx 33 | relup-emqx: $(REBAR) 34 | ifneq ($(OS),Windows_NT) 35 | @ln -snf _build/$(@:relup-%=%)/lib ./_checkouts 36 | @if [ ! -z $$(ls | grep -E "$(@:relup-%=%)-$(SYSTEM)-(.*)-$$(uname -m).zip" | head -1 ) ]; then \ 37 | mkdir -p tmp/relup_packages/$(@:relup-%=%); \ 38 | cp $(@:relup-%=%)-$(SYSTEM)-*-$$(uname -m).zip tmp/relup_packages/$(@:relup-%=%); \ 39 | fi 40 | EMQX_DESC="EMQ X Broker" $(REBAR) as $(@:relup-%=%) relup 41 | endif 42 | .PHONY: relup-emqx-edge 43 | relup-emqx-edge: $(REBAR) 44 | ifneq ($(OS),Windows_NT) 45 | @ln -snf _build/$(@:relup-%=%)/lib ./_checkouts 46 | @if [ ! -z $$(ls | grep -E "$(@:relup-%=%)-$(SYSTEM)-(.*)-$$(uname -m).zip" | head -1 ) ]; then \ 47 | mkdir -p tmp/relup_packages/$(@:relup-%=%); \ 48 | cp $(@:relup-%=%)-$(SYSTEM)-*-$$(uname -m).zip tmp/relup_packages/$(@:relup-%=%); \ 49 | fi 50 | EMQX_DESC="EMQ X Edge" $(REBAR) as $(@:relup-%=%) relup 51 | endif 52 | 53 | .PHONY: emqx-tar emqx-pkg-tar 54 | emqx-tar emqx-pkg-tar: $(REBAR) 55 | ifneq ($(OS),Windows_NT) 56 | @ln -snf _build/$(subst -tar,,$(@))/lib ./_checkouts 57 | endif 58 | EMQX_DESC="EMQ X Broker" $(REBAR) as $(subst -tar,,$(@)) tar 59 | 60 | .PHONY: emqx-edge-tar emqx-edge-pkg-tar 61 | emqx-edge-tar emqx-edge-pkg-tar: $(REBAR) 62 | ifneq ($(OS),Windows_NT) 63 | @ln -snf _build/$(subst -tar,,$(@))/lib ./_checkouts 64 | endif 65 | EMQX_DESC="EMQ X Edge" $(REBAR) as $(subst -tar,,$(@)) tar 66 | 67 | .PHONY: $(PROFILES:%=%-zip) 68 | $(PROFILES:%=%-zip): $(REBAR) 69 | ifneq ($(shell echo $(PKG_VSN) | grep -oE "^[0-9]+\.[0-9]+\.[1-9]+?"),) 70 | make relup-$(subst -zip,,$(@)) 71 | endif 72 | make $(subst -zip,,$(@))-tar 73 | 74 | @tard="/tmp/emqx_untar_$(PKG_VSN)" \ 75 | && rm -rf "$${tard}" && mkdir -p "$${tard}/emqx" \ 76 | && prof="$(subst -zip,,$(@))" \ 77 | && relpath="$$(pwd)/_build/$${prof}/rel/emqx" \ 78 | && pkgpath="$$(pwd)/_packages/$${prof}" \ 79 | && mkdir -p $${pkgpath} \ 80 | && tarball="$${relpath}/emqx-$(PKG_VSN).tar.gz" \ 81 | && zipball="$${pkgpath}/$${prof}-$(SYSTEM)-$(PKG_VSN)-$$(uname -m).zip" \ 82 | && tar zxf "$${tarball}" -C "$${tard}/emqx" \ 83 | && cd "$${tard}" && zip -q -r "$${zipball}" ./emqx && cd - 84 | 85 | .PHONY: $(PKG_PROFILES) 86 | $(PKG_PROFILES:%=%): $(REBAR) 87 | ifneq ($(PKGERDIR),) 88 | make $(subst -pkg,,$(@))-zip 89 | make $(@)-tar 90 | make -C deploy/packages/$(PKGERDIR) clean 91 | EMQX_REL=$$(pwd) EMQX_BUILD=$(@) PKG_VSN=$(PKG_VSN) SYSTEM=$(SYSTEM) make -C deploy/packages/$(PKGERDIR) 92 | else 93 | make $(subst -pkg,,$(@))-zip 94 | endif 95 | 96 | -------------------------------------------------------------------------------- /post-compile.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | :: cd %REBAR_BUILD_DIR% 3 | 4 | :: set REBAR_BUILD_DIR=c:/Users/Gilbe/emqx/emqx_rel/_build/emqx (for debug) 5 | 6 | rmdir /s/q "%REBAR_BUILD_DIR%\conf" 7 | mkdir "%REBAR_BUILD_DIR%\conf\plugins" 8 | mkdir "%REBAR_BUILD_DIR%\conf\schema" 9 | 10 | pushd "%REBAR_BUILD_DIR%" 11 | 12 | 13 | for /d %%i in ("lib\emqx*") do call :conf %%i 14 | 15 | for /d %%i in ("lib\emqx*") do call :schema %%i 16 | 17 | exit 0 18 | 19 | :conf 20 | pushd %1 21 | for %%f in ("etc\*.conf") do ( 22 | :: echo %%f 23 | if "emqx" == "%%~nf" ( 24 | copy %%f "%REBAR_BUILD_DIR%\conf\" 25 | ) else ( 26 | if "acl" == "%%~nf" ( 27 | copy %%f "%REBAR_BUILD_DIR%\conf\" 28 | ) else ( 29 | if "ssl_dist" == "%%~nf" ( 30 | copy %%f "%REBAR_BUILD_DIR%\conf\" 31 | ) else copy %%f "%REBAR_BUILD_DIR%\conf\plugins\" 32 | ) 33 | ) 34 | ) 35 | popd 36 | :end 37 | 38 | :schema 39 | pushd %1 40 | copy priv\emqx.schema "%REBAR_BUILD_DIR%\conf\schema\" 41 | popd 42 | :end 43 | 44 | -------------------------------------------------------------------------------- /post-compile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -eu 2 | 3 | case ${REBAR_BUILD_DIR} in *+test) exit 0;; esac 4 | 5 | if [ ! -d ${REBAR_BUILD_DIR} ]; then 6 | # profile dir is not created yet 7 | exit 0 8 | fi 9 | 10 | cd ${REBAR_BUILD_DIR} 11 | 12 | ## Collect config files, some are direct usable 13 | ## some are relx-overlay templated 14 | rm -rf conf 15 | mkdir -p conf/plugins 16 | for conf in lib/*/etc/*.conf* ; do 17 | if [ "emqx.conf" = "${conf##*/}" ]; then 18 | cp ${conf} conf/ 19 | elif [ "acl.conf" = "${conf##*/}" ]; then 20 | cp ${conf} conf/ 21 | elif [ "ssl_dist.conf" = "${conf##*/}" ]; then 22 | cp ${conf} conf/ 23 | else 24 | cp ${conf} conf/plugins/ 25 | fi 26 | done 27 | 28 | ## Collect all schema files 29 | mkdir -p conf/schema 30 | cp lib/emqx/priv/emqx.schema conf/schema/ 31 | 32 | -------------------------------------------------------------------------------- /rebar.config: -------------------------------------------------------------------------------- 1 | %% NOTE: Order of the deps matters! 2 | {elixir_deps, []}. 3 | 4 | {deps, 5 | [emqx, 6 | emqx_retainer, 7 | emqx_management, 8 | emqx_dashboard, 9 | emqx_bridge_mqtt, 10 | emqx_sn, 11 | emqx_coap, 12 | emqx_stomp, 13 | emqx_auth_clientid, 14 | emqx_auth_username, 15 | emqx_auth_http, 16 | emqx_auth_jwt, 17 | emqx_auth_mysql, 18 | emqx_auth_mnesia, 19 | emqx_web_hook, 20 | emqx_recon, 21 | emqx_rule_engine, 22 | emqx_sasl, 23 | emqx_telemetry 24 | ]}. 25 | 26 | %% Added to deps list for 'cloud' profile 27 | {cloud_deps, 28 | [emqx_lwm2m, 29 | emqx_auth_ldap, 30 | emqx_auth_pgsql, 31 | emqx_auth_redis, 32 | emqx_auth_mongo, 33 | emqx_lua_hook, 34 | emqx_prometheus, 35 | emqx_reloader, 36 | emqx_psk_file, 37 | emqx_extension_hook, 38 | emqx_exproto, 39 | emqx_plugin_template 40 | ]}. 41 | 42 | {edge_deps, []}. 43 | 44 | {relx, 45 | [{include_src, false}, 46 | {extended_start_script, false}, 47 | {generate_start_script, false}, 48 | {sys_config, false}, 49 | {vm_args, false}, 50 | {release, {emqx, git_describe}, 51 | [kernel, 52 | sasl, 53 | crypto, 54 | public_key, 55 | asn1, 56 | syntax_tools, 57 | ssl, 58 | os_mon, 59 | inets, 60 | compiler, 61 | runtime_tools, 62 | cuttlefish, 63 | emqx, 64 | {mnesia, load}, 65 | {ekka, load}, 66 | {emqx_retainer, load}, 67 | {emqx_management, load}, 68 | {emqx_dashboard, load}, 69 | {emqx_bridge_mqtt, load}, 70 | {emqx_sn, load}, 71 | {emqx_coap, load}, 72 | {emqx_stomp, load}, 73 | {emqx_auth_clientid, load}, 74 | {emqx_auth_username, load}, 75 | {emqx_auth_http, load}, 76 | {emqx_auth_mysql, load}, 77 | {emqx_auth_jwt, load}, 78 | {emqx_auth_mnesia, load}, 79 | {emqx_web_hook, load}, 80 | {emqx_recon, load}, 81 | {emqx_rule_engine, load}, 82 | {emqx_sasl, load}, 83 | {emqx_telemetry, load} 84 | ]}, 85 | {overlay, 86 | [{mkdir,"etc/"}, 87 | {mkdir,"log/"}, 88 | {mkdir,"data/"}, 89 | {mkdir,"data/mnesia"}, 90 | {mkdir,"data/configs"}, 91 | {mkdir,"data/scripts"}, 92 | {template,"data/emqx_vars","releases/emqx_vars"}, 93 | {template,"bin/emqx_env","bin/emqx_env"}, 94 | {copy,"bin/emqx","bin/emqx"}, 95 | {copy,"bin/emqx_ctl","bin/emqx_ctl"}, 96 | {copy,"bin/install_upgrade.escript", "bin/install_upgrade.escript"}, 97 | {copy,"bin/emqx","bin/emqx-{{rel_vsn}}"}, %% for relup 98 | {copy,"bin/emqx_ctl","bin/emqx_ctl-{{rel_vsn}}"}, %% for relup 99 | {copy,"bin/install_upgrade.escript", "bin/install_upgrade.escript-{{rel_vsn}}"}, %% for relup 100 | {template,"bin/emqx.cmd","bin/emqx.cmd"}, 101 | {template,"bin/emqx_ctl.cmd","bin/emqx_ctl.cmd"}, 102 | {copy,"{{output_dir}}/../../conf/plugins","etc/"}, 103 | {template,"{{output_dir}}/../../conf/emqx.conf","etc/emqx.conf"}, 104 | {template,"{{output_dir}}/../../conf/ssl_dist.conf","etc/ssl_dist.conf"}, 105 | {template,"{{output_dir}}/../../conf/plugins/emqx_bridge_mqtt.conf", "etc/plugins/emqx_bridge_mqtt.conf"}, 106 | {template,"{{output_dir}}/../../conf/plugins/emqx_coap.conf", "etc/plugins/emqx_coap.conf"}, 107 | {template,"{{output_dir}}/../../conf/plugins/emqx_auth_http.conf", "etc/plugins/emqx_auth_http.conf"}, 108 | {template, "data/loaded_plugins.tmpl", "data/loaded_plugins"}, 109 | {template, "data/loaded_modules.tmpl", "data/loaded_modules"}, 110 | {copy,"{{output_dir}}/../../conf/acl.conf","etc/acl.conf"}, 111 | {copy,"bin/nodetool","bin/nodetool"}, 112 | {copy,"bin/nodetool","bin/nodetool-{{rel_vsn}}"}, 113 | {copy,"{{output_dir}}/../../conf/schema/emqx.schema","releases/{{rel_vsn}}/"}, 114 | {template,"{{output_dir}}/../../lib/emqx/etc/{{vm_args_file}}","etc/vm.args"}, 115 | {copy, "{{output_dir}}/../../lib/emqx/etc/certs","etc/"}, 116 | {copy, "{{output_dir}}/../../lib/cuttlefish/cuttlefish","bin/"}, 117 | {copy, "{{output_dir}}/../../lib/cuttlefish/cuttlefish","bin/cuttlefish-{{rel_vsn}}"} 118 | ]} 119 | ]}. 120 | 121 | {elixir_relx_apps, []}. 122 | 123 | {edge_relx_apps, []}. 124 | 125 | {cloud_relx_apps, 126 | [{emqx_lwm2m, load}, 127 | {emqx_auth_ldap, load}, 128 | {emqx_auth_pgsql, load}, 129 | {emqx_auth_redis, load}, 130 | {emqx_auth_mongo, load}, 131 | {emqx_lua_hook, load}, 132 | {emqx_extension_hook, load}, 133 | {emqx_exproto, load}, 134 | {emqx_prometheus, load}, 135 | {emqx_reloader, load}, 136 | {emqx_psk_file, load}, 137 | {emqx_plugin_template, load}, 138 | {observer, load}, 139 | luerl, 140 | xmerl 141 | ]}. 142 | 143 | {cloud_relx_overlay, 144 | [{template,"{{output_dir}}/../../conf/plugins/emqx_lwm2m.conf", "etc/plugins/emqx_lwm2m.conf"}, 145 | {template,"{{output_dir}}/../../conf/plugins/emqx_psk_file.conf", "etc/plugins/emqx_psk_file.conf"}, 146 | {template,"{{output_dir}}/../../conf/plugins/emqx_extension_hook.conf", "etc/plugins/emqx_extension_hook.conf"}, 147 | {template,"{{output_dir}}/../../conf/plugins/emqx_exproto.conf", "etc/plugins/emqx_exproto.conf"}, 148 | {copy,"{{output_dir}}/../../lib/emqx_lwm2m/lwm2m_xml","etc/"}, 149 | {copy, "{{output_dir}}/../../lib/emqx_psk_file/etc/psk.txt", "etc/psk.txt"} 150 | ]}. 151 | 152 | {edge_relx_overlay, []}. 153 | 154 | {edoc_opts, [{preprocess,true}]}. 155 | 156 | {erl_opts, [warn_unused_vars,warn_shadow_vars,warn_unused_import, 157 | warn_obsolete_guard,no_debug_info,compressed,deterministic]}. 158 | 159 | {overrides, [ 160 | {add, [{erl_opts, [no_debug_info, compressed, {parse_transform, mod_vsn}, deterministic]}]} 161 | ]}. 162 | 163 | {xref_checks, [undefined_function_calls,undefined_functions,locals_not_used, 164 | deprecated_function_calls,warnings_as_errors, 165 | deprecated_functions]}. 166 | {cover_enabled, true}. 167 | {cover_opts, [verbose]}. 168 | {cover_export_enabled, true}. 169 | 170 | {plugins, [ 171 | {relup_helper, {git, "https://github.com/emqx/relup_helper", {branch, "master"}}}, 172 | {rebar3_run, {git, "https://github.com/emqx/rebar3_run", {tag, "0.2.3"}}} 173 | ]}. 174 | 175 | {provider_hooks, [ 176 | {pre, [{release, {relup_helper, gen_appups}}]}, 177 | {post, [{release, {relup_helper, otp_vsn}}, 178 | {release, {relup_helper, untar}}]} 179 | ]}. 180 | 181 | {post_hooks, 182 | [{"(linux|darwin|solaris|freebsd|netbsd|openbsd)", compile, "./post-compile.sh"}, 183 | {"win32", compile, "post-compile.cmd"} 184 | ]}. 185 | -------------------------------------------------------------------------------- /rebar.config.script: -------------------------------------------------------------------------------- 1 | %%-*- mode: erlang -*- 2 | 3 | %% ============================================================================= 4 | %% maybe upload coverdata 5 | %% ============================================================================= 6 | 7 | CONFIG0 = case os:getenv("TRAVIS") of 8 | "true" -> 9 | JobId = os:getenv("TRAVIS_JOB_ID"), 10 | [{coveralls_service_job_id, JobId}, 11 | {coveralls_coverdata, "_build/test/cover/*.coverdata"}, 12 | {coveralls_service_name , "travis-ci"} | CONFIG]; 13 | _ -> 14 | CONFIG 15 | end, 16 | 17 | %% ============================================================================= 18 | %% Dependencies 19 | %% ============================================================================= 20 | PluginsNeededByElixir = [rebar_mix, 21 | {rebar3_elixir_compile, 22 | {git, "https://github.com/barrel-db/rebar3_elixir_compile.git", 23 | {branch, "master"}}}], 24 | 25 | HooksNeededByElixir = {provider_hooks, [{pre, [{compile, {ex, compile}}]}]}, 26 | 27 | OptsNeededByElixir = {elixir_opts, [{env, dev}]}, 28 | 29 | Kf = fun(K, L) -> {K, V} = lists:keyfind(K, 1, L), V end, 30 | {ElixirDeps, CONFIG1} = case Kf(elixir_deps, CONFIG0) of 31 | false ->{[], CONFIG0}; 32 | [] -> {[], CONFIG0}; 33 | ElixirDeps0 -> 34 | Plugins = Kf(plugins, CONFIG0), 35 | NewConfig = lists:keydelete(plugins, 1, CONFIG0), 36 | Plugins1 = {plugins, Plugins ++ PluginsNeededByElixir}, 37 | {ElixirDeps0, 38 | [Plugins1, HooksNeededByElixir, OptsNeededByElixir | NewConfig]} 39 | end, 40 | 41 | PluginCompatWindowsPlatform = fun(Config) -> 42 | PluginsTmp = Kf(plugins, Config), 43 | ConfigTmp = lists:keydelete(plugins, 1, Config), 44 | Plugins2 = {plugins, case os:type() of 45 | {win32, nt} -> PluginsTmp -- [rebar3_run]; 46 | _ -> PluginsTmp 47 | end}, 48 | CONFIG2 = [Plugins2 | ConfigTmp] 49 | end, 50 | 51 | CONFIG2 = PluginCompatWindowsPlatform(CONFIG1), 52 | BaseDeps = Kf(deps, CONFIG2) ++ ElixirDeps, 53 | CloudDeps = BaseDeps ++ Kf(cloud_deps, CONFIG2), 54 | EdgeDeps = BaseDeps ++ Kf(edge_deps, CONFIG2), 55 | 56 | %% Make a dep element for rebar.config GitRef should be either {tag, Tag} or {branch, Branch} 57 | MakeDep = 58 | fun({Name, {git, _, _}} = App, _DefaultDepRef) -> 59 | %% alreay a complete ref 60 | App; 61 | (App, DefaultDepRef) -> 62 | {AppName, GitRef} = 63 | case App of 64 | {Name, Pinned} when is_tuple(Pinned) -> {Name, Pinned}; 65 | {Name, Tag} when is_list(Tag) -> {Name, {tag, Tag}}; 66 | Name when is_atom(Name) -> {Name, DefaultDepRef} 67 | end, 68 | RepoName = string:join(string:tokens(atom_to_list(AppName), "_"), "-"), 69 | URL = "https://github.com/emqx/" ++ RepoName, 70 | {AppName, {git, URL, GitRef}} 71 | end, 72 | 73 | MakeDeps = fun(Deps, DefaultDepRef, TestDeps) -> [MakeDep(App, DefaultDepRef) || App <- Deps] ++ TestDeps end, 74 | 75 | %% TODO: this is only a temporary workaround in order to be backward compatible 76 | %% The right way is to always pin dependency version in rebar.config 77 | %% Any dependency that can not be tested and released independently 78 | %% (i.e. has to be a part of a emqx release in order to be tested) 79 | %% should not be a dependency but a local application reside in the same repo. 80 | %% (Meaning: emqx should be an umbrella project) 81 | 82 | ComparingFun = fun 83 | _Fun([C1|R1], [C2|R2]) when is_list(C1), is_list(C2); 84 | is_integer(C1), is_integer(C2) -> C1 < C2 orelse _Fun(R1, R2); 85 | _Fun([C1|R1], [C2|R2]) when is_integer(C1), is_list(C2) -> _Fun(R1, R2); 86 | _Fun([C1|R1], [C2|R2]) when is_list(C1), is_integer(C2) -> true; 87 | _Fun(_, _) -> false 88 | end, 89 | 90 | SortFun = fun(T1, T2) -> 91 | C = fun(T) -> 92 | [case catch list_to_integer(E) of 93 | I when is_integer(I) -> I; 94 | _ -> E 95 | end || E <- re:split(string:sub_string(T, 2), "[.-]", [{return, list}])] 96 | end, 97 | ComparingFun(C(T1), C(T2)) 98 | end, 99 | 100 | Tag = os:cmd("git describe --abbrev=0 --tags") -- "\n", 101 | LatestTagCommitId = os:cmd(io_lib:format("git rev-parse ~s", [Tag])) -- "\n", 102 | Tags = string:tokens(os:cmd(io_lib:format("git tag -l \"v*\" --points-at ~s", [LatestTagCommitId])), "\n"), 103 | 104 | LatestTag = lists:last(lists:sort(SortFun, Tags)), 105 | 106 | Branch = case os:getenv("GITHUB_RUN_ID") of 107 | false -> os:cmd("git branch | grep -e '^*' | cut -d' ' -f 2") -- "\n"; 108 | _ -> re:replace(os:getenv("GITHUB_REF"), "^refs/heads/|^refs/tags/", "", [global, {return ,list}]) 109 | end, 110 | 111 | GitRef = case re:run(Branch, "master|^dev/|^hotfix/", [{capture, none}]) of 112 | match -> {branch, Branch}; 113 | _ -> {tag, LatestTag} 114 | end, 115 | 116 | DefaultDepRef = 117 | case os:getenv("EMQX_DEPS_DEFAULT_VSN") of 118 | false -> GitRef; %% not set 119 | "" -> GitRef; %% set empty 120 | [] -> GitRef; %% set empty 121 | MaybeTag -> 122 | case re:run(MaybeTag, "^[ev0-9\]+\.\[0-9\]+\.*") of 123 | nomatch -> {branch, MaybeTag}; 124 | _ -> {tag, MaybeTag} 125 | end 126 | end, 127 | 128 | %% ============================================================================= 129 | %% Relx configs 130 | %% ============================================================================= 131 | 132 | GitDescribe = begin 133 | T = case DefaultDepRef of 134 | {tag, EnvTag} -> EnvTag; 135 | _Else -> LatestTag 136 | end, 137 | re:replace(T, "v", "", [{return ,list}]) 138 | end, 139 | Relx0 = Kf(relx, CONFIG2), 140 | {release, {_, Vsn0}, RelxBaseApps0} = lists:keyfind(release, 1, Relx0), 141 | Vsn1 = case Vsn0 of 142 | git_describe -> GitDescribe; 143 | Vsn -> Vsn 144 | end, 145 | RelxElixirApps = Kf(elixir_relx_apps, CONFIG2), 146 | RelxBaseApps = RelxBaseApps0 ++ RelxElixirApps, 147 | RelxOverlay = Kf(overlay, Relx0), 148 | RelxCloudApps = RelxBaseApps ++ Kf(cloud_relx_apps, CONFIG2), 149 | RelxEdgeApps = RelxBaseApps ++ Kf(edge_relx_apps, CONFIG2), 150 | RelxCloudOverlay0 = Kf(cloud_relx_overlay, CONFIG2), 151 | RelxEdgeOverlay0 = Kf(edge_relx_overlay, CONFIG2), 152 | RelxCloudOverlay = RelxOverlay ++ RelxCloudOverlay0, 153 | RelxEdgeOverlay = RelxOverlay ++ RelxEdgeOverlay0, 154 | 155 | MakeRelx = 156 | fun(Apps, Overlay, Vars) -> 157 | VarFiles = ["vars-" ++ atom_to_list(Var) ++ ".config" || Var <- Vars], 158 | Apps1 = case os:type() of {win32, nt} -> Apps -- [bcrypt]; _Other -> Apps end, 159 | Relx1 = lists:keystore(release, 1, Relx0, {release, {emqx, Vsn1}, Apps1}), 160 | Relx2 = lists:keystore(overlay, 1, Relx1, {overlay, Overlay}), 161 | lists:keystore(overlay_vars, 1, Relx2, {overlay_vars, VarFiles}) 162 | end, 163 | Relx = fun(Vars) -> MakeRelx(RelxBaseApps, RelxOverlay, Vars) end, 164 | RelxCloud = fun(Vars) -> MakeRelx(RelxCloudApps, RelxCloudOverlay, Vars) end, 165 | RelxEdge = fun(Vars) -> MakeRelx(RelxEdgeApps, RelxEdgeOverlay, Vars) end, 166 | 167 | TestDeps = [ {meck, "0.8.13"} % hex 168 | , {bbmustache, "1.7.0"} % hex 169 | , {emqx_ct_helpers, {git, "https://github.com/emqx/emqx-ct-helpers", {tag, "v1.1.1"}}} 170 | ], 171 | 172 | %% ============================================================================= 173 | %% Profiles 174 | %% ============================================================================= 175 | Profiles = 176 | [ {emqx, 177 | [ {deps, MakeDeps(CloudDeps, DefaultDepRef, [])} 178 | , {relx, RelxCloud([cloud, bin])} 179 | , {post_hooks, [{"(linux|darwin|solaris|freebsd|netbsd|openbsd)", compile, "./inject-deps.escript emqx"}]} 180 | ]} 181 | , {'emqx-pkg', 182 | [ {deps, MakeDeps(CloudDeps, DefaultDepRef, [])} 183 | , {relx, RelxCloud([cloud, pkg])} 184 | , {post_hooks, [{"(linux|darwin|solaris|freebsd|netbsd|openbsd)", compile, "./inject-deps.escript emqx-pkg"}]} 185 | ]} 186 | , {'emqx-edge', 187 | [ {deps, MakeDeps(EdgeDeps, DefaultDepRef, [])} 188 | , {relx, RelxEdge([edge, bin])} 189 | , {post_hooks, [{"(linux|darwin|solaris|freebsd|netbsd|openbsd)", compile, "./inject-deps.escript emqx-edge"}]} 190 | ]} 191 | , {'emqx-edge-pkg', 192 | [ {deps, MakeDeps(EdgeDeps, DefaultDepRef, [])} 193 | , {relx, RelxEdge([edge, pkg])} 194 | , {post_hooks, [{"(linux|darwin|solaris|freebsd|netbsd|openbsd)", compile, "./inject-deps.escript emqx-edge-pkg"}]} 195 | ]} 196 | ], 197 | 198 | Deletes = [ deps 199 | , relx 200 | , elixir_deps 201 | , edge_deps 202 | , cloud_deps 203 | , elixir_relx_apps 204 | , edge_relx_apps 205 | , cloud_relx_apps 206 | , cloud_relx_overlay 207 | ], 208 | 209 | Additions = [{profiles, Profiles}], 210 | 211 | CONFIG3 = lists:foldl(fun(K, Acc) -> lists:keydelete(K, 1, Acc) end, CONFIG2, Deletes), 212 | 213 | CONFIG4 = lists:foldl(fun({K, V}, Acc) -> lists:keystore(K, 1, Acc, {K, V}) end, CONFIG3, Additions), 214 | 215 | FilePath = case os:type() of 216 | {win32, nt} -> 217 | "emqx.rebar.config"; 218 | _ -> 219 | "/tmp/emqx.rebar.config" 220 | end, 221 | 222 | file:write_file(FilePath, [io_lib:format("~p.\n", [I]) || I <- CONFIG4]), 223 | 224 | CONFIG4. 225 | 226 | -------------------------------------------------------------------------------- /rebar3.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | set rebarscript=%~f0 4 | escript.exe "%rebarscript:.cmd=%" %* 5 | -------------------------------------------------------------------------------- /vars-bin.config: -------------------------------------------------------------------------------- 1 | %% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*- 2 | %% ex: ft=erlang ts=4 sw=4 et 3 | 4 | %% Platform-specific installation paths 5 | {platform_bin_dir, "bin"}. 6 | {platform_data_dir, "data"}. 7 | {platform_etc_dir, "etc"}. 8 | {platform_lib_dir, "lib"}. 9 | {platform_log_dir, "log"}. 10 | {platform_plugins_dir, "plugins"}. 11 | 12 | %% 13 | %% bin/emqx 14 | %% 15 | {runner_root_dir, "$(cd $(dirname $(readlink $0 || echo $0))/..; pwd -P)"}. 16 | {runner_bin_dir, "$RUNNER_ROOT_DIR/bin"}. 17 | {runner_etc_dir, "$RUNNER_ROOT_DIR/etc"}. 18 | {runner_lib_dir, "$RUNNER_ROOT_DIR/lib"}. 19 | {runner_log_dir, "$RUNNER_ROOT_DIR/log"}. 20 | {runner_data_dir, "$RUNNER_ROOT_DIR/data"}. 21 | {pipe_dir, "/tmp/$RUNNER_SCRIPT/"}. 22 | {runner_user, ""}. 23 | 24 | -------------------------------------------------------------------------------- /vars-cloud.config: -------------------------------------------------------------------------------- 1 | {enable_plugin_emqx_rule_engine, true}. 2 | {enable_plugin_emqx_bridge_mqtt, false}. 3 | {vm_args_file, "vm.args"}. 4 | {emqx_description, "EMQ X Broker"}. -------------------------------------------------------------------------------- /vars-edge.config: -------------------------------------------------------------------------------- 1 | {enable_plugin_emqx_rule_engine, false}. 2 | {enable_plugin_emqx_bridge_mqtt, true}. 3 | {vm_args_file, "vm.args.edge"}. 4 | {emqx_description, "EMQ X Edge"}. 5 | -------------------------------------------------------------------------------- /vars-pkg.config: -------------------------------------------------------------------------------- 1 | %% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*- 2 | %% ex: ft=erlang ts=4 sw=4 et 3 | 4 | %% Platform-specific installation paths 5 | {platform_bin_dir, ""}. 6 | {platform_data_dir, "/var/lib/emqx"}. 7 | {platform_etc_dir, "/etc/emqx"}. 8 | {platform_lib_dir, ""}. 9 | {platform_log_dir, "/var/log/emqx"}. 10 | {platform_plugins_dir, "/var/lib/emqx/plugins"}. 11 | 12 | %% 13 | %% bin/emqx 14 | %% 15 | {runner_root_dir, "/usr/lib/emqx"}. 16 | {runner_bin_dir, "/usr/bin"}. 17 | {runner_etc_dir, "/etc/emqx"}. 18 | {runner_lib_dir, "$RUNNER_ROOT_DIR/lib"}. 19 | {runner_log_dir, "/var/log/emqx"}. 20 | {runner_data_dir, "/var/lib/emqx"}. 21 | {pipe_dir, "/tmp/$RUNNER_SCRIPT/"}. 22 | {runner_user, "emqx"}. 23 | --------------------------------------------------------------------------------