Merge branch 'master' of github.com:emqx/emqx into merge-master-to-v5

This commit is contained in:
z8674558 2021-04-07 20:29:08 +09:00
commit 971e6ca90e
216 changed files with 3619 additions and 2052 deletions

View File

@ -1,115 +0,0 @@
version: '3'
services:
erlang:
container_name: erlang
image: emqx/build-env:erl23.2.2-ubuntu20.04
depends_on:
- mysql_server
- redis_server
- mongo_server
- pgsql_server
- ldap_server
networks:
- emqx_bridge
env_file:
- conf.env
environment:
GITHUB_ACTIONS: ${GITHUB_ACTIONS}
GITHUB_TOKEN: ${GITHUB_TOKEN}
GITHUB_RUN_ID: ${GITHUB_RUN_ID}
GITHUB_SHA: ${GITHUB_SHA}
GITHUB_RUN_NUMBER: ${GITHUB_RUN_NUMBER}
GITHUB_EVENT_NAME: ${GITHUB_EVENT_NAME}
GITHUB_REF: ${GITHUB_REF}
volumes:
- ../../.:/emqx
working_dir: /emqx
tty: true
mysql_server:
container_name: mysql
image: mysql:${MYSQL_TAG}
restart: always
ports:
- 3306:3306
environment:
MYSQL_ROOT_PASSWORD: public
MYSQL_DATABASE: mqtt
command:
--bind-address 0.0.0.0
--default-authentication-plugin=mysql_native_password
--character-set-server=utf8mb4
--collation-server=utf8mb4_general_ci
--explicit_defaults_for_timestamp=true
--lower_case_table_names=1
--max_allowed_packet=128M
--skip-symbolic-links
networks:
- emqx_bridge
redis_server:
container_name: redis
image: redis:${REDIS_TAG}
ports:
- 6379:6379
command:
- redis-server
- "--bind 0.0.0.0 ::"
restart: always
networks:
- emqx_bridge
mongo_server:
container_name: mongo
image: mongo:${MONGO_TAG}
ports:
- 27017:27017
restart: always
environment:
MONGO_INITDB_DATABASE: mqtt
command:
--ipv6
--bind_ip_all
networks:
- emqx_bridge
pgsql_server:
container_name: pgsql
image: postgres:${PGSQL_TAG}
ports:
- 5432:5432
restart: always
environment:
POSTGRES_PASSWORD: public
POSTGRES_USER: root
POSTGRES_DB: mqtt
networks:
- emqx_bridge
ldap_server:
container_name: openldap
build:
context: ../..
dockerfile: .ci/apps_tests/openldap/Dockerfile
args:
LDAP_TAG: ${LDAP_TAG}
image: emqx-ldap:1.0
ports:
- 389:389
restart: always
networks:
- emqx_bridge
networks:
emqx_bridge:
driver: bridge
name: emqx_bridge
enable_ipv6: true
ipam:
driver: default
config:
- subnet: 172.100.239.0/24
gateway: 172.100.239.1
- subnet: 2001:3200:3200::/64
gateway: 2001:3200:3200::1

View File

@ -1,26 +0,0 @@
FROM buildpack-deps:stretch
ARG LDAP_TAG=2.4.50
RUN apt-get update && apt-get install -y groff groff-base
RUN wget ftp://ftp.openldap.org/pub/OpenLDAP/openldap-release/openldap-${LDAP_TAG}.tgz \
&& gunzip -c openldap-${LDAP_TAG}.tgz | tar xvfB - \
&& cd openldap-${LDAP_TAG} \
&& ./configure && make depend && make && make install \
&& cd .. && rm -rf openldap-${LDAP_TAG}
COPY .ci/apps_tests/openldap/slapd.conf /usr/local/etc/openldap/slapd.conf
COPY apps/emqx_auth_ldap/emqx.io.ldif /usr/local/etc/openldap/schema/emqx.io.ldif
COPY apps/emqx_auth_ldap/emqx.schema /usr/local/etc/openldap/schema/emqx.schema
COPY apps/emqx_auth_ldap/test/certs/*.pem /usr/local/etc/openldap/
RUN mkdir -p /usr/local/etc/openldap/data \
&& slapadd -l /usr/local/etc/openldap/schema/emqx.io.ldif -f /usr/local/etc/openldap/slapd.conf
WORKDIR /usr/local/etc/openldap
EXPOSE 389 636
ENTRYPOINT ["/usr/local/libexec/slapd", "-h", "ldap:/// ldaps:///", "-d", "3", "-f", "/usr/local/etc/openldap/slapd.conf"]
CMD []

View File

@ -1,4 +1,4 @@
ARG BUILD_FROM=emqx/build-env:erl23.2.2-ubuntu20.04
ARG BUILD_FROM=emqx/build-env:erl23.2.7-ubuntu20.04
FROM ${BUILD_FROM}
ARG EMQX_NAME=emqx

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
set -x -e -u
export CODE_PATH=${CODE_PATH:-"/emqx"}
export EMQX_NAME=${EMQX_NAME:-"emqx"}
@ -29,7 +29,7 @@ emqx_test(){
sed -i '/emqx_telemetry/d' "${PACKAGE_PATH}"/emqx/data/loaded_plugins
echo "running ${packagename} start"
"${PACKAGE_PATH}"/emqx/bin/emqx start || tail "${PACKAGE_PATH}"/emqx/log/erlang.log.1
"${PACKAGE_PATH}"/emqx/bin/emqx start || ( tail "${PACKAGE_PATH}"/emqx/log/emqx.log.1 && exit 1 )
IDLE_TIME=0
while [ -z "$("${PACKAGE_PATH}"/emqx/bin/emqx_ctl status |grep 'is running'|awk '{print $1}')" ]
do
@ -101,7 +101,7 @@ running_test(){
EMQX_MQTT__MAX_TOPIC_ALIAS=10
sed -i '/emqx_telemetry/d' /var/lib/emqx/loaded_plugins
emqx start || tail /var/log/emqx/erlang.log.1
emqx start || ( tail /var/log/emqx/emqx.log.1 && exit 1 )
IDLE_TIME=0
while [ -z "$(emqx_ctl status |grep 'is running'|awk '{print $1}')" ]
do
@ -118,9 +118,8 @@ running_test(){
emqx stop || kill "$(ps -ef | grep -E '\-progname\s.+emqx\s' |awk '{print $2}')"
if [ "$(sed -n '/^ID=/p' /etc/os-release | sed -r 's/ID=(.*)/\1/g' | sed 's/"//g')" = ubuntu ] \
|| [ "$(sed -n '/^ID=/p' /etc/os-release | sed -r 's/ID=(.*)/\1/g' | sed 's/"//g')" = debian ] \
|| [ "$(sed -n '/^ID=/p' /etc/os-release | sed -r 's/ID=(.*)/\1/g' | sed 's/"//g')" = raspbian ];then
service emqx start || tail /var/log/emqx/erlang.log.1
|| [ "$(sed -n '/^ID=/p' /etc/os-release | sed -r 's/ID=(.*)/\1/g' | sed 's/"//g')" = debian ] ;then
service emqx start || ( tail /var/log/emqx/emqx.log.1 && exit 1 )
IDLE_TIME=0
while [ -z "$(emqx_ctl status |grep 'is running'|awk '{print $1}')" ]
do
@ -144,7 +143,7 @@ relup_test(){
for var in "${EMQX_NAME}"-*-"$(uname -m)".zip;do
packagename=$(basename "${var}")
unzip "$packagename"
./emqx/bin/emqx start
./emqx/bin/emqx start || ( tail emqx/log/emqx.log.1 && exit 1 )
./emqx/bin/emqx_ctl status
./emqx/bin/emqx versions
cp "${PACKAGE_PATH}/${EMQX_NAME}"-*-"${TARGET_VERSION}-$(uname -m)".zip ./emqx/releases

View File

@ -1,5 +0,0 @@
MYSQL_TAG=5.7
REDIS_TAG=6
MONGO_TAG=4.1
PGSQL_TAG=11
LDAP_TAG=2.4.50

View File

@ -1,43 +0,0 @@
version: '3'
services:
erlang:
container_name: erlang
image: emqx/build-env:erl23.2.2-ubuntu20.04
volumes:
- ../../:/emqx
working_dir: /emqx
networks:
- emqx_bridge
depends_on:
- mongo_server
tty: true
mongo_server:
container_name: mongo
image: mongo:${MONGO_TAG}
restart: always
environment:
MONGO_INITDB_DATABASE: mqtt
volumes:
- ../../apps/emqx_auth_mongo/test/emqx_auth_mongo_SUITE_data/mongodb.pem/:/etc/certs/mongodb.pem
networks:
- emqx_bridge
command:
--ipv6
--bind_ip_all
--sslMode requireSSL
--sslPEMKeyFile /etc/certs/mongodb.pem
networks:
emqx_bridge:
driver: bridge
name: emqx_bridge
enable_ipv6: true
ipam:
driver: default
config:
- subnet: 172.100.100.0/24
gateway: 172.100.100.1
- subnet: 2001:3200:3200::/64
gateway: 2001:3200:3200::1

View File

@ -1,39 +0,0 @@
version: '3'
services:
erlang:
container_name: erlang
image: emqx/build-env:erl23.2.2-ubuntu20.04
volumes:
- ../..:/emqx
working_dir: /emqx
networks:
- emqx_bridge
depends_on:
- mongo_server
tty: true
mongo_server:
container_name: mongo
image: mongo:${MONGO_TAG}
restart: always
environment:
MONGO_INITDB_DATABASE: mqtt
networks:
- emqx_bridge
command:
--ipv6
--bind_ip_all
networks:
emqx_bridge:
driver: bridge
name: emqx_bridge
enable_ipv6: true
ipam:
driver: default
config:
- subnet: 172.100.100.0/24
gateway: 172.100.100.1
- subnet: 2001:3200:3200::/64
gateway: 2001:3200:3200::1

View File

@ -1,46 +0,0 @@
version: '3'
services:
erlang:
container_name: erlang
image: emqx/build-env:erl23.2.2-ubuntu20.04
volumes:
- ../../:/emqx
working_dir: /emqx
networks:
- emqx_bridge
depends_on:
- mysql_server
tty: true
mysql_server:
container_name: mysql
image: mysql:${MYSQL_TAG}
restart: always
environment:
MYSQL_ROOT_PASSWORD: public
MYSQL_DATABASE: mqtt
networks:
- emqx_bridge
command:
--bind-address "::"
--default-authentication-plugin=mysql_native_password
--character-set-server=utf8mb4
--collation-server=utf8mb4_general_ci
--explicit_defaults_for_timestamp=true
--lower_case_table_names=1
--max_allowed_packet=128M
--skip-symbolic-links
networks:
emqx_bridge:
driver: bridge
name: emqx_bridge
enable_ipv6: true
ipam:
driver: default
config:
- subnet: 172.100.100.0/24
gateway: 172.100.100.1
- subnet: 2001:3200:3200::/64
gateway: 2001:3200:3200::1

View File

@ -1,38 +0,0 @@
version: '3'
services:
erlang:
container_name: erlang
image: emqx/build-env:erl23.2.2-ubuntu20.04
volumes:
- ../../:/emqx
working_dir: /emqx
networks:
- emqx_bridge
depends_on:
- pgsql_server
tty: true
pgsql_server:
container_name: pgsql
image: postgres:${PGSQL_TAG}
restart: always
environment:
POSTGRES_PASSWORD: public
POSTGRES_USER: root
POSTGRES_DB: mqtt
networks:
- emqx_bridge
networks:
emqx_bridge:
driver: bridge
name: emqx_bridge
enable_ipv6: true
ipam:
driver: default
config:
- subnet: 172.100.100.0/24
gateway: 172.100.100.1
- subnet: 2001:3200:3200::/64
gateway: 2001:3200:3200::1

View File

@ -1,41 +0,0 @@
version: '2.4'
# network configuration is limited in version 3
# https://github.com/docker/compose/issues/4958
services:
erlang:
container_name: erlang
image: emqx/build-env:erl23.2.2-ubuntu20.04
volumes:
- ../..:/emqx
networks:
- app_net
depends_on:
- redis_cluster
working_dir: /emqx
tty: true
redis_cluster:
container_name: redis
image: redis:${REDIS_TAG}
volumes:
- ../../apps/emqx_auth_redis/test/emqx_auth_redis_SUITE_data/certs:/tls
- ./redis/:/data/conf
command: bash -c "/bin/bash /data/conf/redis.sh --node cluster --tls-enabled && while true; do echo 1; sleep 1; done"
networks:
app_net:
# Assign a public address. Erlang container cannot find cluster nodes by network-scoped alias (redis_cluster).
ipv4_address: 172.16.239.10
ipv6_address: 2001:3200:3200::20
networks:
app_net:
driver: bridge
enable_ipv6: true
ipam:
driver: default
config:
- subnet: 172.16.239.0/24
gateway: 172.16.239.1
- subnet: 2001:3200:3200::/64
gateway: 2001:3200:3200::1

View File

@ -1,40 +0,0 @@
version: '2.4'
# network configuration is limited in version 3
# https://github.com/docker/compose/issues/4958
services:
erlang:
container_name: erlang
image: emqx/build-env:erl23.2.2-ubuntu20.04
volumes:
- ../..:/emqx
networks:
- app_net
depends_on:
- redis_cluster
working_dir: /emqx
tty: true
redis_cluster:
image: redis:${REDIS_TAG}
container_name: redis
volumes:
- ./redis/:/data/conf
command: bash -c "/bin/bash /data/conf/redis.sh --node cluster && while true; do echo 1; sleep 1; done"
networks:
app_net:
# Assign a public address. Erlang container cannot find cluster nodes by network-scoped alias (redis_cluster).
ipv4_address: 172.16.239.10
ipv6_address: 2001:3200:3200::20
networks:
app_net:
driver: bridge
enable_ipv6: true
ipam:
driver: default
config:
- subnet: 172.16.239.0/24
gateway: 172.16.239.1
- subnet: 2001:3200:3200::/64
gateway: 2001:3200:3200::1

View File

@ -1,40 +0,0 @@
version: '2.4'
# network configuration is limited in version 3
# https://github.com/docker/compose/issues/4958
services:
erlang:
container_name: erlang
image: emqx/build-env:erl23.2.2-ubuntu20.04
volumes:
- ../..:/emqx
networks:
- app_net
depends_on:
- redis_cluster
working_dir: /emqx
tty: true
redis_cluster:
container_name: redis
image: redis:${REDIS_TAG}
volumes:
- ./redis/:/data/conf
command: bash -c "/bin/bash /data/conf/redis.sh --node sentinel && while true; do echo 1; sleep 1; done"
networks:
app_net:
# Assign a public address. Erlang container cannot find cluster nodes by network-scoped alias (redis_cluster).
ipv4_address: 172.16.239.10
ipv6_address: 2001:3200:3200::20
networks:
app_net:
driver: bridge
enable_ipv6: true
ipam:
driver: default
config:
- subnet: 172.16.239.0/24
gateway: 172.16.239.1
- subnet: 2001:3200:3200::/64
gateway: 2001:3200:3200::1

View File

@ -1,43 +0,0 @@
version: '3'
services:
erlang:
container_name: erlang
image: emqx/build-env:erl23.2.2-ubuntu20.04
volumes:
- ../..:/emqx
networks:
- emqx_bridge
depends_on:
- redis_server
working_dir: /emqx
tty: true
redis_server:
container_name: redis
image: redis:${REDIS_TAG}
volumes:
- ../../apps/emqx_auth_redis/test/emqx_auth_redis_SUITE_data/certs:/tls
command:
- redis-server
- "--bind 0.0.0.0 ::"
- --tls-port 6380
- --tls-cert-file /tls/redis.crt
- --tls-key-file /tls/redis.key
- --tls-ca-cert-file /tls/ca.crt
restart: always
networks:
- emqx_bridge
networks:
emqx_bridge:
driver: bridge
name: emqx_bridge
enable_ipv6: true
ipam:
driver: default
config:
- subnet: 172.100.100.0/24
gateway: 172.100.100.1
- subnet: 2001:3200:3200::/64
gateway: 2001:3200:3200::1

View File

@ -1,37 +0,0 @@
version: '3'
services:
erlang:
container_name: erlang
image: emqx/build-env:erl23.2.2-ubuntu20.04
volumes:
- ../..:/emqx
networks:
- emqx_bridge
depends_on:
- redis_server
working_dir: /emqx
tty: true
redis_server:
container_name: redis
image: redis:${REDIS_TAG}
command:
- redis-server
- "--bind 0.0.0.0 ::"
restart: always
networks:
- emqx_bridge
networks:
emqx_bridge:
driver: bridge
name: emqx_bridge
enable_ipv6: true
ipam:
driver: default
config:
- subnet: 172.100.100.0/24
gateway: 172.100.100.1
- subnet: 2001:3200:3200::/64
gateway: 2001:3200:3200::1

View File

@ -1,16 +0,0 @@
include /usr/local/etc/openldap/schema/core.schema
include /usr/local/etc/openldap/schema/cosine.schema
include /usr/local/etc/openldap/schema/inetorgperson.schema
include /usr/local/etc/openldap/schema/ppolicy.schema
include /usr/local/etc/openldap/schema/emqx.schema
TLSCACertificateFile /usr/local/etc/openldap/cacert.pem
TLSCertificateFile /usr/local/etc/openldap/cert.pem
TLSCertificateKeyFile /usr/local/etc/openldap/key.pem
database bdb
suffix "dc=emqx,dc=io"
rootdn "cn=root,dc=emqx,dc=io"
rootpw {SSHA}eoF7NhNrejVYYyGHqnt+MdKNBh4r1w3W
directory /usr/local/etc/openldap/data

View File

@ -1,2 +0,0 @@
daemonize yes
bind 0.0.0.0 ::

View File

@ -1,6 +1,5 @@
EMQX_AUTH__LDAP__SERVERS=ldap_server
EMQX_AUTH__MONGO__SERVER=mongo_server:27017
EMQX_AUTH__REDIS__SERVER=redis_server:6379
EMQX_AUTH__MYSQL__SERVER=mysql_server:3306
EMQX_AUTH__MYSQL__USERNAME=root
EMQX_AUTH__MYSQL__PASSWORD=public
@ -9,4 +8,6 @@ EMQX_AUTH__PGSQL__SERVER=pgsql_server:5432
EMQX_AUTH__PGSQL__USERNAME=root
EMQX_AUTH__PGSQL__PASSWORD=public
EMQX_AUTH__PGSQL__DATABASE=mqtt
EMQX_AUTH__REDIS__SERVER=redis_server:6379
EMQX_AUTH__REDIS__PASSWORD=public
CUTTLEFISH_ENV_OVERRIDE_PREFIX=EMQX_

View File

@ -0,0 +1,16 @@
version: '3.9'
services:
ldap_server:
container_name: ldap
build:
context: ../..
dockerfile: .ci/docker-compose-file/openldap/Dockerfile
args:
LDAP_TAG: ${LDAP_TAG}
image: openldap
ports:
- 389:389
restart: always
networks:
- emqx_bridge

View File

@ -0,0 +1,14 @@
version: '3.9'
services:
mongo_server:
container_name: mongo
image: mongo:${MONGO_TAG}
restart: always
environment:
MONGO_INITDB_DATABASE: mqtt
networks:
- emqx_bridge
command:
--ipv6
--bind_ip_all

View File

@ -0,0 +1,18 @@
version: '3.9'
services:
mongo_server:
container_name: mongo
image: mongo:${MONGO_TAG}
restart: always
environment:
MONGO_INITDB_DATABASE: mqtt
volumes:
- ../../apps/emqx_auth_mongo/test/emqx_auth_mongo_SUITE_data/mongodb.pem/:/etc/certs/mongodb.pem
networks:
- emqx_bridge
command:
--ipv6
--bind_ip_all
--sslMode requireSSL
--sslPEMKeyFile /etc/certs/mongodb.pem

View File

@ -0,0 +1,20 @@
version: '3.9'
services:
mysql_server:
container_name: mysql
image: mysql:${MYSQL_TAG}
restart: always
environment:
MYSQL_ROOT_PASSWORD: public
MYSQL_DATABASE: mqtt
networks:
- emqx_bridge
command:
--bind-address "::"
--character-set-server=utf8mb4
--collation-server=utf8mb4_general_ci
--explicit_defaults_for_timestamp=true
--lower_case_table_names=1
--max_allowed_packet=128M
--skip-symbolic-links

View File

@ -1,18 +1,6 @@
version: '3'
version: '3.9'
services:
erlang:
container_name: erlang
image: emqx/build-env:erl23.2.2-ubuntu20.04
volumes:
- ../../:/emqx
working_dir: /emqx
networks:
- emqx_bridge
depends_on:
- mysql_server
tty: true
mysql_server:
container_name: mysql
image: mysql:${MYSQL_TAG}
@ -20,6 +8,8 @@ services:
environment:
MYSQL_ROOT_PASSWORD: public
MYSQL_DATABASE: mqtt
MYSQL_USER: ssluser
MYSQL_PASSWORD: public
volumes:
- ../../apps/emqx_auth_mysql/test/emqx_auth_mysql_SUITE_data/ca.pem:/etc/certs/ca-cert.pem
- ../../apps/emqx_auth_mysql/test/emqx_auth_mysql_SUITE_data/server-cert.pem:/etc/certs/server-cert.pem
@ -38,15 +28,18 @@ services:
--ssl-cert=/etc/certs/server-cert.pem
--ssl-key=/etc/certs/server-key.pem
networks:
emqx_bridge:
driver: bridge
name: emqx_bridge
enable_ipv6: true
ipam:
driver: default
config:
- subnet: 172.100.100.0/24
gateway: 172.100.100.1
- subnet: 2001:3200:3200::/64
gateway: 2001:3200:3200::1
mysql_client:
container_name: mysql_client
image: mysql:${MYSQL_TAG}
networks:
- emqx_bridge
depends_on:
- mysql_server
command:
- /bin/bash
- -c
- |
service mysql start
echo "show tables;" | mysql -h mysql_server -u root -ppublic mqtt mqtt
while [[ $$? -ne 0 ]];do echo "show tables;" | mysql -h mysql_server -u root -ppublic mqtt; done
echo "ALTER USER 'ssluser'@'%' REQUIRE X509;" | mysql -h mysql_server -u root -ppublic mqtt

View File

@ -0,0 +1,15 @@
version: '3.9'
services:
pgsql_server:
container_name: pgsql
image: postgres:${PGSQL_TAG}
restart: always
environment:
POSTGRES_PASSWORD: public
POSTGRES_USER: root
POSTGRES_DB: mqtt
ports:
- "5432:5432"
networks:
- emqx_bridge

View File

@ -1,23 +1,11 @@
version: '3'
version: '3.9'
services:
erlang:
container_name: erlang
image: emqx/build-env:erl23.2.2-ubuntu20.04
volumes:
- ../../:/emqx
working_dir: /emqx
networks:
- emqx_bridge
depends_on:
- pgsql_server
tty: true
pgsql_server:
container_name: pgsql
build:
context: ../..
dockerfile: .ci/compatibility_tests/pgsql/Dockerfile
dockerfile: .ci/docker-compose-file/pgsql/Dockerfile
args:
POSTGRES_USER: postgres
BUILD_FROM: postgres:${PGSQL_TAG}
@ -42,16 +30,3 @@ services:
- hba_file=/var/lib/postgresql/pg_hba.conf
networks:
- emqx_bridge
networks:
emqx_bridge:
driver: bridge
name: emqx_bridge
enable_ipv6: true
ipam:
driver: default
config:
- subnet: 172.100.100.0/24
gateway: 172.100.100.1
- subnet: 2001:3200:3200::/64
gateway: 2001:3200:3200::1

View File

@ -0,0 +1,11 @@
version: '3.9'
services:
redis_cluster:
image: redis:${REDIS_TAG}
container_name: redis
volumes:
- ./redis/:/data/conf
command: bash -c "/bin/bash /data/conf/redis.sh --node cluster && tail -f /var/log/redis-server.log"
networks:
- emqx_bridge

View File

@ -0,0 +1,12 @@
version: '3.9'
services:
redis_cluster:
container_name: redis
image: redis:${REDIS_TAG}
volumes:
- ../../apps/emqx_auth_redis/test/emqx_auth_redis_SUITE_data/certs:/tls
- ./redis/:/data/conf
command: bash -c "/bin/bash /data/conf/redis.sh --node cluster --tls-enabled && tail -f /var/log/redis-server.log"
networks:
- emqx_bridge

View File

@ -0,0 +1,11 @@
version: '3.9'
services:
redis_cluster:
container_name: redis
image: redis:${REDIS_TAG}
volumes:
- ./redis/:/data/conf
command: bash -c "/bin/bash /data/conf/redis.sh --node sentinel && tail -f /var/log/redis-server.log"
networks:
- emqx_bridge

View File

@ -0,0 +1,13 @@
version: '3.9'
services:
redis_server:
container_name: redis
image: redis:${REDIS_TAG}
command:
- redis-server
- "--bind 0.0.0.0 ::"
- --requirepass public
restart: always
networks:
- emqx_bridge

View File

@ -0,0 +1,19 @@
version: '3.9'
services:
redis_server:
container_name: redis
image: redis:${REDIS_TAG}
volumes:
- ../../apps/emqx_auth_redis/test/emqx_auth_redis_SUITE_data/certs:/tls
command:
- redis-server
- "--bind 0.0.0.0 ::"
- --requirepass public
- --tls-port 6380
- --tls-cert-file /tls/redis.crt
- --tls-key-file /tls/redis.key
- --tls-ca-cert-file /tls/ca.crt
restart: always
networks:
- emqx_bridge

View File

@ -1,32 +1,26 @@
version: '3'
version: '3.9'
services:
erlang:
container_name: erlang
image: emqx/build-env:erl23.2.2-ubuntu20.04
depends_on:
- ldap_server
image: emqx/build-env:erl23.2.7-ubuntu20.04
env_file:
- conf.env
environment:
GITHUB_ACTIONS: ${GITHUB_ACTIONS}
GITHUB_TOKEN: ${GITHUB_TOKEN}
GITHUB_RUN_ID: ${GITHUB_RUN_ID}
GITHUB_SHA: ${GITHUB_SHA}
GITHUB_RUN_NUMBER: ${GITHUB_RUN_NUMBER}
GITHUB_EVENT_NAME: ${GITHUB_EVENT_NAME}
GITHUB_REF: ${GITHUB_REF}
networks:
- emqx_bridge
volumes:
- ../../.:/emqx
- ../..:/emqx
working_dir: /emqx
tty: true
ldap_server:
container_name: ldap
build:
context: ../..
dockerfile: .ci/compatibility_tests/openldap/Dockerfile
args:
LDAP_TAG: ${LDAP_TAG}
image: openldap
ports:
- 389:389
restart: always
networks:
- emqx_bridge
networks:
emqx_bridge:
driver: bridge

View File

@ -9,7 +9,7 @@ RUN wget ftp://ftp.openldap.org/pub/OpenLDAP/openldap-release/openldap-${LDAP_TA
&& ./configure && make depend && make && make install \
&& cd .. && rm -rf openldap-${LDAP_TAG}
COPY .ci/compatibility_tests/openldap/slapd.conf /usr/local/etc/openldap/slapd.conf
COPY .ci/docker-compose-file/openldap/slapd.conf /usr/local/etc/openldap/slapd.conf
COPY apps/emqx_auth_ldap/emqx.io.ldif /usr/local/etc/openldap/schema/emqx.io.ldif
COPY apps/emqx_auth_ldap/emqx.schema /usr/local/etc/openldap/schema/emqx.schema
COPY apps/emqx_auth_ldap/test/certs/*.pem /usr/local/etc/openldap/

View File

@ -1,10 +1,10 @@
ARG BUILD_FROM=postgres:11
FROM ${BUILD_FROM}
ARG POSTGRES_USER=postgres
COPY --chown=$POSTGRES_USER .ci/compatibility_tests/pgsql/pg_hba.conf /var/lib/postgresql/pg_hba.conf
COPY --chown=$POSTGRES_USER apps/emqx_auth_pgsql/test/emqx_auth_pgsql_SUITE_data/server.key /var/lib/postgresql/server.key
COPY --chown=$POSTGRES_USER apps/emqx_auth_pgsql/test/emqx_auth_pgsql_SUITE_data/server.crt /var/lib/postgresql/server.crt
COPY --chown=$POSTGRES_USER apps/emqx_auth_pgsql/test/emqx_auth_pgsql_SUITE_data/root.crt /var/lib/postgresql/root.crt
COPY --chown=$POSTGRES_USER .ci/docker-compose-file/pgsql/pg_hba.conf /var/lib/postgresql/pg_hba.conf
COPY --chown=$POSTGRES_USER apps/emqx_auth_pgsql/test/emqx_auth_pgsql_SUITE_data/server-key.pem /var/lib/postgresql/server.key
COPY --chown=$POSTGRES_USER apps/emqx_auth_pgsql/test/emqx_auth_pgsql_SUITE_data/server-cert.pem /var/lib/postgresql/server.crt
COPY --chown=$POSTGRES_USER apps/emqx_auth_pgsql/test/emqx_auth_pgsql_SUITE_data/ca.pem /var/lib/postgresql/root.crt
RUN chmod 600 /var/lib/postgresql/pg_hba.conf
RUN chmod 600 /var/lib/postgresql/server.key
RUN chmod 600 /var/lib/postgresql/server.crt

View File

@ -1,5 +1,7 @@
daemonize yes
bind 0.0.0.0 ::
logfile /var/log/redis-server.log
tls-cert-file /tls/redis.crt
tls-key-file /tls/redis.key
tls-ca-cert-file /tls/ca.crt
tls-ca-cert-file /tls/ca.crt
requirepass public

View File

@ -0,0 +1,4 @@
daemonize yes
bind 0.0.0.0 ::
logfile /var/log/redis-server.log
requirepass public

View File

@ -1,5 +1,9 @@
#!/bin/bash
set -x
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)
node=single
tls=false
while [[ $# -gt 0 ]]
@ -48,9 +52,9 @@ elif [ "${node}" = "sentinel" ] ; then
redis-server /data/conf/redis.conf --port 7000 --cluster-config-file /data/conf/nodes.7000.conf \
--cluster-enabled no;
redis-server /data/conf/redis.conf --port 7001 --cluster-config-file /data/conf/nodes.7001.conf \
--cluster-enabled no --slaveof 172.16.239.10 7000;
--cluster-enabled no --slaveof "$LOCAL_IP" 7000;
redis-server /data/conf/redis.conf --port 7002 --cluster-config-file /data/conf/nodes.7002.conf \
--cluster-enabled no --slaveof 172.16.239.10 7000;
--cluster-enabled no --slaveof "$LOCAL_IP" 7000;
fi
REDIS_LOAD_FLG=true;
@ -76,7 +80,7 @@ do
continue;
fi
if [ "${node}" = "cluster" ] ; then
yes "yes" | redis-cli --cluster create 172.16.239.10:7000 172.16.239.10:7001 172.16.239.10:7002;
yes "yes" | redis-cli --cluster create "$LOCAL_IP:7000" "$LOCAL_IP:7001" "$LOCAL_IP:7002" --pass public --no-auth-warning;
elif [ "${node}" = "sentinel" ] ; then
cp /data/conf/sentinel.conf /_sentinel.conf
redis-server /_sentinel.conf --sentinel;

View File

@ -1,3 +1,4 @@
port 26379
dir /tmp
sentinel monitor mymaster 172.16.239.10 7000 1
logfile /var/log/redis-server.log

1
.ci/fvt_tests/.env Normal file
View File

@ -0,0 +1 @@
TARGET=emqx/emqx

View File

@ -3,7 +3,7 @@ version: '3'
services:
emqx1:
container_name: node1.emqx.io
image: emqx/emqx:build-alpine-amd64
image: ${TARGET}:build-alpine-amd64
environment:
- "EMQX_NAME=emqx"
- "EMQX_HOST=node1.emqx.io"
@ -11,6 +11,7 @@ services:
- "EMQX_CLUSTER__STATIC__SEEDS=emqx@node1.emqx.io, emqx@node2.emqx.io"
- "EMQX_ZONE__EXTERNAL__RETRY_INTERVAL=2s"
- "EMQX_MQTT__MAX_TOPIC_ALIAS=10"
- "EMQX_LOG__LEVEL=debug"
command:
- /bin/sh
- -c
@ -30,7 +31,7 @@ services:
emqx2:
container_name: node2.emqx.io
image: emqx/emqx:build-alpine-amd64
image: ${TARGET}:build-alpine-amd64
environment:
- "EMQX_NAME=emqx"
- "EMQX_HOST=node2.emqx.io"
@ -38,6 +39,7 @@ services:
- "EMQX_CLUSTER__STATIC__SEEDS=emqx@node1.emqx.io, emqx@node2.emqx.io"
- "EMQX_ZONE__EXTERNAL__RETRY_INTERVAL=2s"
- "EMQX_MQTT__MAX_TOPIC_ALIAS=10"
- "EMQX_LOG__LEVEL=debug"
command:
- /bin/sh
- -c
@ -46,7 +48,7 @@ services:
sed -i '/emqx_telemetry/d' /opt/emqx/data/loaded_plugins
/opt/emqx/bin/emqx foreground
healthcheck:
test: ["CMD", "/opt/emqx/bin/emqx_ctl", "status"]
test: ["CMD", "/opt/emqx/bin/emqx", "ping"]
interval: 5s
timeout: 25s
retries: 5
@ -64,6 +66,8 @@ services:
tty: true
networks:
emqx-bridge:
volumes:
- ./scripts:/scripts
networks:
emqx-bridge:

22
.ci/fvt_tests/scripts/pytest.sh Executable file
View File

@ -0,0 +1,22 @@
#!/bin/sh
## This script is to run emqx cluster smoke tests (fvt) in github action
## This script is executed in pacho_client
set -x
set +e
NODE1="node1.emqx.io"
NODE2="node2.emqx.io"
apk update && apk add git curl
git clone -b develop-4.0 https://github.com/emqx/paho.mqtt.testing.git /paho.mqtt.testing
pip install pytest
pytest -v /paho.mqtt.testing/interoperability/test_client/V5/test_connect.py -k test_basic --host "$NODE1"
RESULT=$?
pytest -v /paho.mqtt.testing/interoperability/test_cluster --host1 "$NODE1" --host2 "$NODE2"
RESULT=$(( RESULT + $? ))
pytest -v /paho.mqtt.testing/interoperability/test_client --host "$NODE1"
RESULT=$(( RESULT + $? ))
exit $RESULT

5
.gitattributes vendored Normal file
View File

@ -0,0 +1,5 @@
* text=auto
*.* text eol=lf
*.jpg -text
*.png -text
*.pdf -text

View File

@ -6,71 +6,133 @@ on:
push:
tags:
- v*
- e*
release:
types:
- published
workflow_dispatch:
jobs:
prepare:
runs-on: ubuntu-20.04
container: emqx/build-env:erl23.2.7-ubuntu20.04
outputs:
profiles: ${{ steps.set_profile.outputs.profiles}}
steps:
- uses: actions/checkout@v2
with:
path: source
- name: set profile
id: set_profile
shell: bash
run: |
if make -C source emqx-ee --dry-run > /dev/null 2>&1; then
echo "::set-output name=profiles::[\"emqx-ee\"]"
else
echo "::set-output name=profiles::[\"emqx\", \"emqx-edge\"]"
fi
- name: get_all_deps
if: endsWith(github.repository, 'emqx')
run: |
make -C source deps-all
zip -ryq source.zip source
- name: get_all_deps
if: endsWith(github.repository, 'enterprise')
run: |
echo "https://ci%40emqx.io:${{ secrets.CI_GIT_TOKEN }}@github.com" > $HOME/.git-credentials
git config --global credential.helper store
echo "${{ secrets.CI_GIT_TOKEN }}" >> source/scripts/git-token
make -C source deps-all
zip -ryq source.zip source
- uses: actions/upload-artifact@v2
with:
name: source
path: source.zip
windows:
runs-on: windows-2019
needs: prepare
if: endsWith(github.repository, 'emqx')
strategy:
matrix:
profile: ${{fromJSON(needs.prepare.outputs.profiles)}}
exclude:
- profile: emqx-edge
steps:
- uses: actions/checkout@v1
- uses: actions/download-artifact@v2
with:
name: source
path: .
- name: unzip source code
run: Expand-Archive -Path source.zip -DestinationPath ./
- uses: ilammy/msvc-dev-cmd@v1
- uses: gleam-lang/setup-erlang@v1.1.0
id: install_erlang
with:
otp-version: 23.2
- name: build
env:
PYTHON: python
run: |
# set-executionpolicy remotesigned -s cu
# iex (new-object net.webclient).downloadstring('https://get.scoop.sh')
# # $env:path + ";" + $env:USERPROFILE + "\scoop\shims" + ';C:\Program Files\erl10.4\bin'
# [environment]::SetEnvironmentvariable("Path", ";" + $env:USERPROFILE + "\scoop\shims")
# [environment]::SetEnvironmentvariable("Path", ';C:\Program Files\erl10.4\bin')
# scoop bucket add extras https://github.com/lukesampson/scoop-extras.git
# scoop update
# scoop install sudo curl vcredist2013
$env:PATH = "${{ steps.install_erlang.outputs.erlpath }}\bin;$env:PATH"
$version = $( "${{ github.ref }}" -replace "^(.*)/(.*)/" )
if ($version -match "^v[0-9]+\.[0-9]+(\.[0-9]+)?") {
$regex = "[0-9]+\.[0-9]+(-alpha|-beta|-rc)?\.[0-9]"
$pkg_name = "emqx-windows-$([regex]::matches($version, $regex).value).zip"
$pkg_name = "${{ matrix.profile }}-windows-$([regex]::matches($version, $regex).value).zip"
}
else {
$pkg_name = "emqx-windows-$($version -replace '/').zip"
$pkg_name = "${{ matrix.profile }}-windows-$($version -replace '/').zip"
}
make deps-emqx || cat rebar3.crashdump
$rebar3 = $env:USERPROFILE + "\rebar3"
(New-Object System.Net.WebClient).DownloadFile('https://s3.amazonaws.com/rebar3/rebar3', $rebar3)
cd _build/emqx/lib/jiffy/
escript $rebar3 compile
cd ../../../../
make emqx
mkdir -p _packages/emqx
Compress-Archive -Path _build/emqx/rel/emqx -DestinationPath _build/emqx/rel/$pkg_name
mv _build/emqx/rel/$pkg_name _packages/emqx
Get-FileHash -Path "_packages/emqx/$pkg_name" | Format-List | grep 'Hash' | awk '{print $3}' > _packages/emqx/$pkg_name.sha256
cd source
## We do not build/release bcrypt for windows package
Remove-Item -Recurse -Force -Path _build/default/lib/bcrypt/
if (Test-Path rebar.lock) {
Remove-Item -Force -Path rebar.lock
}
make ${{ matrix.profile }}
mkdir -p _packages/${{ matrix.profile }}
Compress-Archive -Path _build/${{ matrix.profile }}/rel/emqx -DestinationPath _build/${{ matrix.profile }}/rel/$pkg_name
mv _build/${{ matrix.profile }}/rel/$pkg_name _packages/${{ matrix.profile }}
Get-FileHash -Path "_packages/${{ matrix.profile }}/$pkg_name" | Format-List | grep 'Hash' | awk '{print $3}' > _packages/${{ matrix.profile }}/$pkg_name.sha256
- name: run emqx
timeout-minutes: 1
run: |
./_build/emqx/rel/emqx/bin/emqx start
./_build/emqx/rel/emqx/bin/emqx stop
./_build/emqx/rel/emqx/bin/emqx install
./_build/emqx/rel/emqx/bin/emqx uninstall
cd source
./_build/${{ matrix.profile }}/rel/emqx/bin/emqx start
Start-Sleep -s 5
./_build/${{ matrix.profile }}/rel/emqx/bin/emqx stop
./_build/${{ matrix.profile }}/rel/emqx/bin/emqx install
./_build/${{ matrix.profile }}/rel/emqx/bin/emqx uninstall
- uses: actions/upload-artifact@v1
if: startsWith(github.ref, 'refs/tags/')
with:
name: emqx
path: ./_packages/emqx/.
name: ${{ matrix.profile }}
path: source/_packages/${{ matrix.profile }}/.
mac:
runs-on: macos-10.15
needs: prepare
strategy:
matrix:
profile: ${{fromJSON(needs.prepare.outputs.profiles)}}
exclude:
- profile: emqx-edge
steps:
- uses: actions/checkout@v1
- uses: actions/download-artifact@v2
with:
name: source
path: .
- name: unzip source code
run: unzip -q source.zip
- name: prepare
run: |
brew install curl zip unzip gnu-sed kerl unixodbc freetds
@ -79,16 +141,17 @@ jobs:
- name: build erlang
timeout-minutes: 60
run: |
kerl build 23.2.2
kerl install 23.2.2 $HOME/.kerl/23.2.2
kerl build 23.2.7
kerl install 23.2.7 $HOME/.kerl/23.2.7
- name: build
run: |
. $HOME/.kerl/23.2.2/activate
make emqx-pkg
. $HOME/.kerl/23.2.7/activate
make -C source ${{ matrix.profile }}-pkg
- name: test
run: |
pkg_name=$(basename _packages/emqx/emqx-macos-*.zip)
unzip _packages/emqx/$pkg_name
cd source
pkg_name=$(basename _packages/${{ matrix.profile }}/${{ matrix.profile }}-*.zip)
unzip _packages/${{ matrix.profile }}/$pkg_name
gsed -i '/emqx_telemetry/d' ./emqx/data/loaded_plugins
./emqx/bin/emqx start || cat emqx/log/erlang.log.1
ready='no'
@ -107,46 +170,51 @@ jobs:
./emqx/bin/emqx_ctl status
./emqx/bin/emqx stop
rm -rf emqx
openssl dgst -sha256 ./_packages/emqx/$pkg_name | awk '{print $2}' > ./_packages/emqx/$pkg_name.sha256
openssl dgst -sha256 ./_packages/${{ matrix.profile }}/$pkg_name | awk '{print $2}' > ./_packages/${{ matrix.profile }}/$pkg_name.sha256
- uses: actions/upload-artifact@v1
if: startsWith(github.ref, 'refs/tags/')
with:
name: emqx
path: ./_packages/emqx/.
name: ${{ matrix.profile }}
path: source/_packages/${{ matrix.profile }}/.
linux:
runs-on: ubuntu-20.04
needs: prepare
strategy:
matrix:
profile: ${{fromJSON(needs.prepare.outputs.profiles)}}
arch:
- amd64
- arm64
emqx:
- emqx
- emqx-edge
- amd64
- arm64
os:
- ubuntu20.04
- ubuntu18.04
- ubuntu16.04
- debian10
- debian9
- opensuse
- centos8
- centos7
- centos6
- raspbian10
- raspbian9
- ubuntu20.04
- ubuntu18.04
- ubuntu16.04
- debian10
- debian9
# - opensuse
- centos8
- centos7
- centos6
- raspbian10
- raspbian9
exclude:
- os: raspbian9
arch: amd64
- os: raspbian9
emqx: emqx
- os: raspbian10
arch: amd64
- os: raspbian10
emqx: emqx
- os: centos6
arch: arm64
- os: raspbian9
arch: amd64
- os: raspbian10
arch: amd64
- os: raspbian9
profile: emqx
- os: raspbian10
profile: emqx
- os: raspbian9
profile: emqx-ee
- os: raspbian10
profile: emqx-ee
defaults:
run:
@ -162,71 +230,71 @@ jobs:
docker info
docker buildx create --use --name mybuild
docker run --rm --privileged tonistiigi/binfmt --install all
- uses: actions/checkout@v1
- name: get deps
env:
ERL_OTP: erl23.2.2
run: |
docker run -i --rm \
-e GITHUB_RUN_ID=$GITHUB_RUN_ID \
-e GITHUB_REF=$GITHUB_REF \
-v $(pwd):/emqx \
-w /emqx \
emqx/build-env:${ERL_OTP}-debian10 \
bash -c "make deps-all"
- uses: actions/download-artifact@v2
with:
name: source
path: .
- name: unzip source code
run: unzip -q source.zip
- name: downloads emqx zip packages
env:
EMQX: ${{ matrix.emqx }}
PROFILE: ${{ matrix.profile }}
ARCH: ${{ matrix.arch }}
SYSTEM: ${{ matrix.os }}
run: |
set -e -u -x
if [ $EMQX = "emqx-edge" ];then broker="emqx-edge"; else broker="emqx-ce"; fi
if [ $ARCH = "arm64" ];then arch="aarch64"; else arch="x86_64"; fi
cd source
if [ $PROFILE = "emqx" ];then broker="emqx-ce"; else broker="$PROFILE"; fi
if [ $PROFILE = "emqx-ee" ];then edition='enterprise'; else edition='opensource'; fi
vsn="$(grep -oE '\{vsn, (.*)\}' src/emqx.app.src | sed -r 's/\{vsn, (.*)\}/\1/g' | sed 's/\"//g')"
vsn="$(grep -E "define.+EMQX_RELEASE.+${edition}" include/emqx_release.hrl | cut -d '"' -f2)"
pre_vsn="$(echo $vsn | grep -oE '^[0-9]+.[0-9]')"
old_vsns=($(git tag -l "$pre_vsn.[0-9]" | sed "s/$vsn//"))
if [ $PROFILE = "emqx-ee" ]; then
old_vsns=($(git tag -l "e$pre_vsn.[0-9]" | sed "s/e$vsn//"))
else
old_vsns=($(git tag -l "v$pre_vsn.[0-9]" | sed "s/v$vsn//"))
fi
mkdir -p tmp/relup_packages/$EMQX
cd tmp/relup_packages/$EMQX
mkdir -p tmp/relup_packages/$PROFILE
cd tmp/relup_packages/$PROFILE
for tag in ${old_vsns[@]};do
if [ ! -z "$(echo $(curl -I -m 10 -o /dev/null -s -w %{http_code} https://s3-us-west-2.amazonaws.com/packages.emqx/$broker/v${tag#[e|v]}/$EMQX-$SYSTEM-${tag#[e|v]}-$arch.zip) | grep -oE "^[23]+")" ];then
wget https://s3-us-west-2.amazonaws.com/packages.emqx/$broker/v${tag#[e|v]}/$EMQX-$SYSTEM-${tag#[e|v]}-$arch.zip
wget https://s3-us-west-2.amazonaws.com/packages.emqx/$broker/v${tag#[e|v]}/$EMQX-$SYSTEM-${tag#[e|v]}-$arch.zip.sha256
echo "$(cat $EMQX-$SYSTEM-${tag#[e|v]}-$arch.zip.sha256) $EMQX-$SYSTEM-${tag#[e|v]}-$arch.zip" | sha256sum -c || exit 1
if [ ! -z "$(echo $(curl -I -m 10 -o /dev/null -s -w %{http_code} https://s3-${{ secrets.AWS_DEFAULT_REGION }}.amazonaws.com/${{ secrets.AWS_S3_BUCKET }}/$broker/$tag/$PROFILE-$SYSTEM-${tag#[e|v]}-$ARCH.zip) | grep -oE "^[23]+")" ];then
wget https://s3-${{ secrets.AWS_DEFAULT_REGION }}.amazonaws.com/${{ secrets.AWS_S3_BUCKET }}/$broker/$tag/$PROFILE-$SYSTEM-${tag#[e|v]}-$ARCH.zip
wget https://s3-${{ secrets.AWS_DEFAULT_REGION }}.amazonaws.com/${{ secrets.AWS_S3_BUCKET }}/$broker/$tag/$PROFILE-$SYSTEM-${tag#[e|v]}-$ARCH.zip.sha256
echo "$(cat $PROFILE-$SYSTEM-${tag#[e|v]}-$ARCH.zip.sha256) $PROFILE-$SYSTEM-${tag#[e|v]}-$ARCH.zip" | sha256sum -c || exit 1
fi
done
cd -
- name: build emqx packages
env:
ERL_OTP: erl23.2.2
EMQX: ${{ matrix.emqx }}
ERL_OTP: erl23.2.7
PROFILE: ${{ matrix.profile }}
ARCH: ${{ matrix.arch }}
SYSTEM: ${{ matrix.os }}
run: |
set -e -u -x
set -e -u
cd source
docker buildx build --no-cache \
--platform=linux/$ARCH \
-t cross_build_emqx_for_$SYSTEM \
-f .ci/build_packages/Dockerfile \
--build-arg BUILD_FROM=emqx/build-env:$ERL_OTP-$SYSTEM \
--build-arg EMQX_NAME=$EMQX \
--output type=tar,dest=/tmp/cross-build-$EMQX-for-$SYSTEM.tar .
--build-arg EMQX_NAME=$PROFILE \
--output type=tar,dest=/tmp/cross-build-$PROFILE-for-$SYSTEM.tar .
mkdir -p /tmp/packages/$EMQX
tar -xvf /tmp/cross-build-$EMQX-for-$SYSTEM.tar --wildcards emqx/_packages/$EMQX/*
mv emqx/_packages/$EMQX/* /tmp/packages/$EMQX/
rm -rf /tmp/cross-build-$EMQX-for-$SYSTEM.tar
mkdir -p /tmp/packages/$PROFILE
tar -xvf /tmp/cross-build-$PROFILE-for-$SYSTEM.tar --wildcards emqx/_packages/$PROFILE/*
mv emqx/_packages/$PROFILE/* /tmp/packages/$PROFILE/
rm -rf /tmp/cross-build-$PROFILE-for-$SYSTEM.tar
docker rm -f $(docker ps -a -q)
docker volume prune -f
- name: create sha256
env:
EMQX: ${{ matrix.emqx }}
PROFILE: ${{ matrix.profile}}
run: |
if [ -d /tmp/packages/$EMQX ]; then
cd /tmp/packages/$EMQX
if [ -d /tmp/packages/$PROFILE ]; then
cd /tmp/packages/$PROFILE
for var in $(ls emqx-* ); do
bash -c "echo $(sha256sum $var | awk '{print $1}') > $var.sha256"
done
@ -235,52 +303,74 @@ jobs:
- uses: actions/upload-artifact@v1
if: startsWith(github.ref, 'refs/tags/')
with:
name: ${{ matrix.emqx }}
path: /tmp/packages/${{ matrix.emqx }}/.
name: ${{ matrix.profile }}
path: /tmp/packages/${{ matrix.profile }}/.
docker:
runs-on: ubuntu-20.04
needs: prepare
strategy:
matrix:
profile: ${{fromJSON(needs.prepare.outputs.profiles)}}
arch:
- [amd64, x86_64]
- [arm64v8, aarch64]
- [arm32v7, arm]
- [i386, i386]
- [s390x, s390x]
- [amd64, x86_64]
- [arm64v8, aarch64]
- [arm32v7, arm]
- [i386, i386]
- [s390x, s390x]
exclude:
- profile: emqx-ee
arch: [i386, i386]
- profile: emqx-ee
arch: [s390x, s390x]
steps:
- uses: actions/checkout@v1
- uses: actions/download-artifact@v2
with:
name: source
path: .
- name: unzip source code
run: unzip -q source.zip
- name: build emqx docker image
env:
PROFILE: ${{ matrix.profile }}
ARCH: ${{ matrix.arch[0] }}
QEMU_ARCH: ${{ matrix.arch[1] }}
run: |
sudo docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
sudo TARGET=emqx/emqx ARCH=$ARCH QEMU_ARCH=$QEMU_ARCH make docker
cd _packages/emqx && for var in $(ls emqx-docker-* ); do sudo bash -c "echo $(sha256sum $var | awk '{print $1}') > $var.sha256"; done && cd -
cd source
sudo TARGET=emqx/$PROFILE ARCH=$ARCH QEMU_ARCH=$QEMU_ARCH make docker
cd _packages/$PROFILE && for var in $(ls ${PROFILE}-docker-* ); do sudo bash -c "echo $(sha256sum $var | awk '{print $1}') > $var.sha256"; done && cd -
- uses: actions/upload-artifact@v1
if: startsWith(github.ref, 'refs/tags/')
with:
name: ${{ matrix.profile }}
path: source/_packages/${{ matrix.profile }}/.
sudo TARGET=emqx/emqx-edge ARCH=$ARCH QEMU_ARCH=$QEMU_ARCH make docker
cd _packages/emqx-edge && for var in $(ls emqx-edge-docker-* ); do sudo bash -c "echo $(sha256sum $var | awk '{print $1}') > $var.sha256"; done && cd -
- uses: actions/upload-artifact@v1
delete-artifact:
runs-on: ubuntu-20.04
needs: [prepare, mac, linux, docker]
steps:
- uses: geekyeggo/delete-artifact@v1
with:
name: emqx
path: ./_packages/emqx/.
- uses: actions/upload-artifact@v1
with:
name: emqx-edge
path: ./_packages/emqx-edge/.
name: source
upload:
runs-on: ubuntu-20.04
needs: [windows, mac, linux, docker]
if: startsWith(github.ref, 'refs/tags/')
needs: [prepare, mac, linux, docker]
strategy:
matrix:
profile: ${{fromJSON(needs.prepare.outputs.profiles)}}
steps:
- uses: actions/checkout@v2
- name: get_version
run: |
echo 'version<<EOF' >> $GITHUB_ENV
@ -288,47 +378,38 @@ jobs:
echo 'EOF' >> $GITHUB_ENV
- uses: actions/download-artifact@v2
with:
name: emqx
path: ./_packages/emqx
- uses: actions/download-artifact@v2
with:
name: emqx-edge
path: ./_packages/emqx-edge
name: ${{ matrix.profile }}
path: ./_packages/${{ matrix.profile }}
- name: install dos2unix
run: sudo apt-get update && sudo apt install -y dos2unix
- name: get packages
run: |
set -e -x -u
for EMQX in emqx emqx-edge; do
cd _packages/$EMQX
for var in $( ls |grep emqx |grep -v sha256); do
dos2unix $var.sha256
echo "$(cat $var.sha256) $var" | sha256sum -c || exit 1
done
cd -
set -e -u
cd _packages/${{ matrix.profile }}
for var in $( ls |grep emqx |grep -v sha256); do
dos2unix $var.sha256
echo "$(cat $var.sha256) $var" | sha256sum -c || exit 1
done
cd -
- name: upload aws s3
run: |
set -e -x -u
set -e -u
if [ "${{ matrix.profile }}" == "emqx" ];then
broker="emqx-ce"
else
broker=${{ matrix.profile }}
fi
aws configure set aws_access_key_id ${{ secrets.AWS_ACCESS_KEY_ID }}
aws configure set aws_secret_access_key ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws configure set default.region us-west-2
aws configure set default.region ${{ secrets.AWS_DEFAULT_REGION }}
aws s3 cp --recursive _packages/emqx s3://packages.emqx/emqx-ce/${{ env.version }}
aws s3 cp --recursive _packages/emqx-edge s3://packages.emqx/emqx-edge/${{ env.version }}
aws cloudfront create-invalidation --distribution-id E170YEULGLT8XB --paths "/emqx-ce/${{ env.version }}/*,/emqx-edge/${{ env.version }}/*"
mkdir packages
mv _packages/emqx/* packages
mv _packages/emqx-edge/* packages
- uses: actions/checkout@v2
with:
path: emqx
aws s3 cp --recursive _packages/${{ matrix.profile }} s3://${{ secrets.AWS_S3_BUCKET }}/$broker/${{ env.version }}
aws cloudfront create-invalidation --distribution-id ${{ secrets.AWS_CLOUDFRONT_ID }} --paths "/$broker/${{ env.version }}/*"
- uses: Rory-Z/upload-release-asset@v1
if: github.event_name == 'release'
with:
repo: emqx
path: "packages/emqx-*"
path: "_packages/${{ matrix.profile }}/emqx-*"
token: ${{ github.token }}
- name: update to emqx.io
if: github.event_name == 'release'
@ -345,15 +426,22 @@ jobs:
if: github.event_name == 'release'
run: |
set -e -x -u
sudo make -C emqx docker-prepare
cd packages && for var in $(ls |grep docker |grep -v sha256); do unzip $var; sudo docker load < ${var%.*}; rm -f ${var%.*}; done && cd -
sudo make docker-prepare
cd _packages/${{ matrix.profile }} && for var in $(ls |grep docker |grep -v sha256); do unzip $var; sudo docker load < ${var%.*}; rm -f ${var%.*}; done && cd -
echo ${{ secrets.DOCKER_HUB_TOKEN }} |sudo docker login -u ${{ secrets.DOCKER_HUB_USER }} --password-stdin
sudo TARGET=emqx/emqx make -C emqx docker-push
sudo TARGET=emqx/emqx make -C emqx docker-manifest-list
sudo TARGET=emqx/emqx-edge make -C emqx docker-push
sudo TARGET=emqx/emqx-edge make -C emqx docker-manifest-list
sudo TARGET=emqx/${{ matrix.profile }} make docker-push
sudo TARGET=emqx/${{ matrix.profile }} make docker-manifest-list
- name: update repo.emqx.io
if: github.event_name == 'release'
if: github.event_name == 'release' && endsWith(github.repository, 'enterprise') && matrix.profile == 'emqx-ee'
run: |
curl --silent --show-error \
-H "Authorization: token ${{ secrets.CI_GIT_TOKEN }}" \
-H "Accept: application/vnd.github.v3+json" \
-X POST \
-d "{\"ref\":\"v1.0.1\",\"inputs\":{\"version\": \"${{ env.version }}\", \"emqx_ee\": \"true\"}}" \
"https://api.github.com/repos/emqx/emqx-ci-helper/actions/workflows/update_emqx_repos.yaml/dispatches"
- name: update repo.emqx.io
if: github.event_name == 'release' && endsWith(github.repository, 'emqx') && matrix.profile == 'emqx'
run: |
curl --silent --show-error \
-H "Authorization: token ${{ secrets.CI_GIT_TOKEN }}" \
@ -362,7 +450,7 @@ jobs:
-d "{\"ref\":\"v1.0.1\",\"inputs\":{\"version\": \"${{ env.version }}\", \"emqx_ce\": \"true\"}}" \
"https://api.github.com/repos/emqx/emqx-ci-helper/actions/workflows/update_emqx_repos.yaml/dispatches"
- name: update homebrew packages
if: github.event_name == 'release'
if: github.event_name == 'release' && endsWith(github.repository, 'emqx') && matrix.profile == 'emqx'
run: |
if [ -z $(echo $version | grep -oE "(alpha|beta|rc)\.[0-9]") ]; then
curl --silent --show-error \
@ -374,7 +462,4 @@ jobs:
fi
- uses: geekyeggo/delete-artifact@v1
with:
name: emqx
- uses: geekyeggo/delete-artifact@v1
with:
name: emqx-edge
name: ${{ matrix.profile }}

View File

@ -1,26 +1,42 @@
name: Build slim packages
on: [pull_request]
on:
- pull_request
- workflow_dispatch
jobs:
build:
runs-on: ubuntu-20.04
strategy:
matrix:
erl_otp:
- erl23.2.2
- erl23.2.7
os:
- ubuntu20.04
- centos8
- centos7
container: emqx/build-env:${{ matrix.erl_otp }}-${{ matrix.os }}
steps:
- uses: actions/checkout@v1
- name: prepare
run: |
if make emqx-ee --dry-run > /dev/null 2>&1; then
echo "https://ci%40emqx.io:${{ secrets.CI_GIT_TOKEN }}@github.com" > $HOME/.git-credentials
git config --global credential.helper store
echo "${{ secrets.CI_GIT_TOKEN }}" >> ./scripts/git-token
echo "EMQX_NAME=emqx-ee" >> $GITHUB_ENV
else
echo "EMQX_NAME=emqx" >> $GITHUB_ENV
fi
- name: build packages
run: make emqx-pkg
run: make ${EMQX_NAME}-pkg
- name: pakcages test
run: |
export CODE_PATH=$GITHUB_WORKSPACE
.ci/build_packages/tests.sh
- uses: actions/upload-artifact@v2
with:
name: ${{ matrix.os }}
path: _packages/**/*.zip

View File

@ -5,7 +5,7 @@ on: [pull_request]
jobs:
check_deps_integrity:
runs-on: ubuntu-20.04
container: emqx/build-env:erl23.2.2-ubuntu20.04
container: emqx/build-env:erl23.2.7-ubuntu20.04
steps:
- uses: actions/checkout@v2

View File

@ -6,6 +6,11 @@ jobs:
build:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v2
- name: Set git token
if: endsWith(github.repository, 'enterprise')
run: |
echo "https://ci%40emqx.io:${{ secrets.CI_GIT_TOKEN }}@github.com" > $HOME/.git-credentials
git config --global credential.helper store
- run: |
./scripts/elvis-check.sh $GITHUB_BASE_REF

View File

@ -19,11 +19,24 @@ jobs:
destination_branch: ${{ github.ref }}
destination_ssh_private_key: "${{ secrets.CI_SSH_PRIVATE_KEY }}"
- name: create pull request
id: create_pull_request
run: |
set -euo pipefail
R=$(curl --silent --show-error \
-H "Accept: application/vnd.github.v3+json" \
-H "Authorization: token ${{ secrets.CI_GIT_TOKEN }}" \
-X POST \
-d '{"title": "Sync code into enterprise from opensource", "head": "master", "base":"enterprise"}' \
https://api.github.com/repos/${{ github.repository_owner }}/emqx-enterprise/pulls)
echo $R | jq
echo "::set-output name=url::$(echo $R | jq '.url')"
- name: request reviewers for a pull request
if: steps.create_pull_request.outputs.url != 'null'
run: |
set -euo pipefail
curl --silent --show-error \
-H "Accept: application/vnd.github.v3+json" \
-H "Authorization: token ${{ secrets.CI_GIT_TOKEN }}" \
-X POST \
-d '{"title": "Sync code into enterprise from opensource", "head": "master", "base":"enterprise"}' \
https://api.github.com/repos/${{ github.repository_owner }}/emqx-enterprise/pulls
-d '{"team_reviewers":["emqx-devs"]}' \
${{ steps.create_pull_request.outputs.url }}/requested_reviewers

View File

@ -24,12 +24,14 @@ jobs:
steps:
- uses: actions/checkout@v1
- name: setup
- name: docker compose up
env:
LDAP_TAG: ${{ matrix.ldap_tag }}
run: |
docker-compose -f .ci/apps_tests/docker-compose.yaml build --no-cache
docker-compose -f .ci/compatibility_tests/docker-compose-ldap.yaml up -d
docker-compose \
-f .ci/docker-compose-file/docker-compose-ldap-tcp.yaml \
-f .ci/docker-compose-file/docker-compose.yaml \
up -d --build
- name: setup
if: matrix.network_type == 'ipv4'
run: |
@ -38,6 +40,11 @@ jobs:
if: matrix.network_type == 'ipv6'
run: |
echo EMQX_AUTH__LDAP__SERVERS=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.GlobalIPv6Address}}{{end}}' ldap) >> "$GITHUB_ENV"
- name: set git token
run: |
if make emqx-ee --dry-run > /dev/null 2>&1; then
docker exec -i erlang bash -c "echo \"https://ci%40emqx.io:${{ secrets.CI_GIT_TOKEN }}@github.com\" > /root/.git-credentials && git config --global credential.helper store"
fi
- name: run test cases
run: |
export CUTTLEFISH_ENV_OVERRIDE_PREFIX=EMQX_
@ -69,24 +76,30 @@ jobs:
steps:
- uses: actions/checkout@v1
- name: docker-compose up
run: |
docker-compose \
-f .ci/docker-compose-file/docker-compose-mongo-${{ matrix.connect_type }}.yaml \
-f .ci/docker-compose-file/docker-compose.yaml \
up -d --build
- name: setup
env:
MONGO_TAG: ${{ matrix.mongo_tag }}
if: matrix.connect_type == 'tls'
run: |
docker-compose -f .ci/compatibility_tests/docker-compose-mongo-tls.yaml up -d
cat <<-EOF >> "$GITHUB_ENV"
EMQX_AUTH__MONGO__SSL__ENABLE=on
EMQX_AUTH__MONGO__CACERTFILE=/emqx/apps/emqx_auth_mongo/test/emqx_auth_mongo_SUITE_data/ca.pem
EMQX_AUTH__MONGO__CERTFILE=/emqx/apps/emqx_auth_mongo/test/emqx_auth_mongo_SUITE_data/client-cert.pem
EMQX_AUTH__MONGO__KEYFILE=/emqx/apps/emqx_auth_mongo/test/emqx_auth_mongo_SUITE_data/client-key.pem
EMQX_AUTH__MONGO__SSL__CACERTFILE=/emqx/apps/emqx_auth_mongo/test/emqx_auth_mongo_SUITE_data/ca.pem
EMQX_AUTH__MONGO__SSL__CERTFILE=/emqx/apps/emqx_auth_mongo/test/emqx_auth_mongo_SUITE_data/client-cert.pem
EMQX_AUTH__MONGO__SSL__KEYFILE=/emqx/apps/emqx_auth_mongo/test/emqx_auth_mongo_SUITE_data/client-key.pem
EMQX_AUTH__MONGO__SSL__VERIFY=true
EMQX_AUTH__MONGO__SSL__SERVER_NAME_INDICATION=disable
EOF
- name: setup
env:
MONGO_TAG: ${{ matrix.mongo_tag }}
if: matrix.connect_type == 'tcp'
run: |
docker-compose -f .ci/compatibility_tests/docker-compose-mongo.yaml up -d
echo EMQX_AUTH__MONGO__SSL__ENABLE=off >> "$GITHUB_ENV"
- name: setup
if: matrix.network_type == 'ipv4'
@ -96,6 +109,11 @@ jobs:
if: matrix.network_type == 'ipv6'
run: |
echo "EMQX_AUTH__MONGO__SERVER=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.GlobalIPv6Address}}{{end}}' mongo):27017" >> "$GITHUB_ENV"
- name: set git token
run: |
if make emqx-ee --dry-run > /dev/null 2>&1; then
docker exec -i erlang bash -c "echo \"https://ci%40emqx.io:${{ secrets.CI_GIT_TOKEN }}@github.com\" > /root/.git-credentials && git config --global credential.helper store"
fi
- name: run test cases
run: |
export CUTTLEFISH_ENV_OVERRIDE_PREFIX=EMQX_
@ -127,25 +145,44 @@ jobs:
steps:
- uses: actions/checkout@v1
- name: docker-compose up
timeout-minutes: 5
run: |
docker-compose \
-f .ci/docker-compose-file/docker-compose-mysql-${{ matrix.connect_type }}.yaml \
-f .ci/docker-compose-file/docker-compose.yaml \
up -d --build
while [ $(docker ps -a --filter name=client --filter exited=0 | wc -l) \
!= $(docker ps -a --filter name=client | wc -l) ]; do
sleep 5
done
- name: setup
env:
MYSQL_TAG: ${{ matrix.mysql_tag }}
if: matrix.connect_type == 'tls'
run: |
docker-compose -f .ci/compatibility_tests/docker-compose-mysql-tls.yaml up -d
cat <<-EOF >> "$GITHUB_ENV"
EMQX_AUTH__MYSQL__SSL__ENABLE=on
EMQX_AUTH__MYSQL__USERNAME=ssluser
EMQX_AUTH__MYSQL__PASSWORD=public
EMQX_AUTH__MYSQL__DATABASE=mqtt
EMQX_AUTH__MYSQL__SSL__CACERTFILE=/emqx/apps/emqx_auth_mysql/test/emqx_auth_mysql_SUITE_data/ca.pem
EMQX_AUTH__MYSQL__SSL__CERTFILE=/emqx/apps/emqx_auth_mysql/test/emqx_auth_mysql_SUITE_data/client-cert.pem
EMQX_AUTH__MYSQL__SSL__KEYFILE=/emqx/apps/emqx_auth_mysql/test/emqx_auth_mysql_SUITE_data/client-key.pem
EMQX_AUTH__MYSQL__SSL__VERIFY=true
EMQX_AUTH__MYSQL__SSL__SERVER_NAME_INDICATION=disable
EOF
- name: setup
env:
MYSQL_TAG: ${{ matrix.mysql_tag }}
if: matrix.connect_type == 'tcp'
run: |
docker-compose -f .ci/compatibility_tests/docker-compose-mysql.yaml up -d
echo EMQX_AUTH__MYSQL__SSL__ENABLE=off >> "$GITHUB_ENV"
cat <<-EOF >> "$GITHUB_ENV"
EMQX_AUTH__MYSQL__USERNAME=root
EMQX_AUTH__MYSQL__PASSWORD=public
EMQX_AUTH__MYSQL__DATABASE=mqtt
EMQX_AUTH__MYSQL__SSL__ENABLE=off
EOF
- name: setup
if: matrix.network_type == 'ipv4'
run: |
@ -154,12 +191,14 @@ jobs:
if: matrix.network_type == 'ipv6'
run: |
echo "EMQX_AUTH__MYSQL__SERVER=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.GlobalIPv6Address}}{{end}}' mysql):3306" >> "$GITHUB_ENV"
- name: set git token
run: |
if make emqx-ee --dry-run > /dev/null 2>&1; then
docker exec -i erlang bash -c "echo \"https://ci%40emqx.io:${{ secrets.CI_GIT_TOKEN }}@github.com\" > /root/.git-credentials && git config --global credential.helper store"
fi
- name: run test cases
run: |
export EMQX_AUTH__MYSQL__USERNAME=root \
EMQX_AUTH__MYSQL__PASSWORD=public \
EMQX_AUTH__MYSQL__DATABASE=mqtt \
CUTTLEFISH_ENV_OVERRIDE_PREFIX=EMQX_
export CUTTLEFISH_ENV_OVERRIDE_PREFIX=EMQX_
printenv > .env
docker exec -i erlang sh -c "make ensure-rebar3"
docker exec -i erlang sh -c "./rebar3 eunit --dir apps/emqx_auth_mysql"
@ -190,23 +229,30 @@ jobs:
- tcp
steps:
- uses: actions/checkout@v1
- name: docker-compose up
run: |
docker-compose \
-f .ci/docker-compose-file/docker-compose-pgsql-${{ matrix.connect_type }}.yaml \
-f .ci/docker-compose-file/docker-compose.yaml \
up -d --build
- name: setup
env:
PGSQL_TAG: ${{ matrix.pgsql_tag }}
if: matrix.connect_type == 'tls'
run: |
docker-compose -f .ci/compatibility_tests/docker-compose-pgsql-tls.yaml build --no-cache
docker-compose -f .ci/compatibility_tests/docker-compose-pgsql-tls.yaml up -d
cat <<-EOF >> "$GITHUB_ENV"
EMQX_AUTH__PGSQL__SSL__ENABLE=on
EMQX_AUTH__PGSQL__SSL__CACERTFILE=/emqx/apps/emqx_auth_pgsql/test/emqx_auth_pgsql_SUITE_data/root.crt
EMQX_AUTH__PGSQL__SSL__CACERTFILE=/emqx/apps/emqx_auth_pgsql/test/emqx_auth_pgsql_SUITE_data/ca.pem
EMQX_AUTH__PGSQL__SSL__CERTFILE=/emqx/apps/emqx_auth_pgsql/test/emqx_auth_pgsql_SUITE_data/client-cert.pem
EMQX_AUTH__PGSQL__SSL__KEYFILE=/emqx/apps/emqx_auth_pgsql/test/emqx_auth_pgsql_SUITE_data/client-key.pem
EMQX_AUTH__PGSQL__SSL__VERIFY=true
EMQX_AUTH__PGSQL__SSL__SERVER_NAME_INDICATION=disable
EOF
- name: setup
env:
PGSQL_TAG: ${{ matrix.pgsql_tag }}
if: matrix.connect_type == 'tcp'
run: |
docker-compose -f .ci/compatibility_tests/docker-compose-pgsql.yaml up -d
echo EMQX_AUTH__PGSQL__SSL__ENABLE=off >> "$GITHUB_ENV"
- name: setup
if: matrix.network_type == 'ipv4'
@ -216,6 +262,11 @@ jobs:
if: matrix.network_type == 'ipv6'
run: |
echo "EMQX_AUTH__PGSQL__SERVER=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.GlobalIPv6Address}}{{end}}' pgsql):5432" >> "$GITHUB_ENV"
- name: set git token
run: |
if make emqx-ee --dry-run > /dev/null 2>&1; then
docker exec -i erlang bash -c "echo \"https://ci%40emqx.io:${{ secrets.CI_GIT_TOKEN }}@github.com\" > /root/.git-credentials && git config --global credential.helper store"
fi
- name: run test cases
run: |
export EMQX_AUTH__PGSQL__USERNAME=root \
@ -250,33 +301,39 @@ jobs:
node_type:
- single
- cluster
exclude:
- redis_tag: 5
connect_type: tls
steps:
- uses: actions/checkout@v1
- name: docker-compose up
run: |
docker-compose \
-f .ci/docker-compose-file/docker-compose-redis-${{ matrix.node_type }}-${{ matrix.connect_type }}.yaml \
-f .ci/docker-compose-file/docker-compose.yaml \
up -d --build
- name: setup
env:
REDIS_TAG: ${{ matrix.redis_tag }}
if: matrix.connect_type == 'tls' && matrix.redis_tag != '5'
if: matrix.connect_type == 'tls'
run: |
set -exu
docker-compose -f .ci/compatibility_tests/docker-compose-redis-${{ matrix.node_type }}-tls.yaml up -d
cat <<-EOF >> "$GITHUB_ENV"
EMQX_AUTH__REDIS__SSL__ENABLE=on
EMQX_AUTH__REDIS__SSL__CACERTFILE=/emqx/apps/emqx_auth_redis/test/emqx_auth_redis_SUITE_data/certs/ca.crt
EMQX_AUTH__REDIS__SSL__CERTFILE=/emqx/apps/emqx_auth_redis/test/emqx_auth_redis_SUITE_data/certs/redis.crt
EMQX_AUTH__REDIS__SSL__KEYFILE=/emqx/apps/emqx_auth_redis/test/emqx_auth_redis_SUITE_data/certs/redis.key
EMQX_AUTH__REDIS__SSL__VERIFY=true
EMQX_AUTH__REDIS__SSL__SERVER_NAME_INDICATION=disable
EOF
- name: setup
env:
REDIS_TAG: ${{ matrix.redis_tag }}
if: matrix.connect_type == 'tcp'
run: |
docker-compose -f .ci/compatibility_tests/docker-compose-redis-${{ matrix.node_type }}.yaml up -d
echo EMQX_AUTH__REDIS__SSL__ENABLE=off >> "$GITHUB_ENV"
- name: get server address
if: matrix.connect_type == 'tcp' || (matrix.connect_type == 'tls' && matrix.redis_tag != '5')
run: |
set -exu
ipv4_address=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' redis)
ipv6_address=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.GlobalIPv6Address}}{{end}}' redis)
cat <<-EOF >> "$GITHUB_ENV"
@ -286,15 +343,13 @@ jobs:
- name: setup
if: matrix.node_type == 'single' && matrix.connect_type == 'tcp'
run: |
set -exu
cat <<-EOF >> "$GITHUB_ENV"
EMQX_AUTH__REDIS__TYPE=single
EMQX_AUTH__REDIS__SERVER=${redis_${{ matrix.network_type }}_address}:6379
EOF
- name: setup
if: matrix.node_type == 'single' && matrix.connect_type == 'tls' && matrix.redis_tag != '5'
if: matrix.node_type == 'single' && matrix.connect_type == 'tls'
run: |
set -exu
cat <<-EOF >> "$GITHUB_ENV"
EMQX_AUTH__REDIS__TYPE=single
EMQX_AUTH__REDIS__SERVER=${redis_${{ matrix.network_type }}_address}:6380
@ -302,23 +357,26 @@ jobs:
- name: setup
if: matrix.node_type == 'cluster' && matrix.connect_type == 'tcp'
run: |
set -exu
cat <<-EOF >> "$GITHUB_ENV"
EMQX_AUTH__REDIS__TYPE=cluster
EMQX_AUTH__REDIS__SERVER=${redis_${{ matrix.network_type }}_address}:7000
EOF
- name: setup
if: matrix.node_type == 'cluster' && matrix.connect_type == 'tls' && matrix.redis_tag != '5'
if: matrix.node_type == 'cluster' && matrix.connect_type == 'tls'
run: |
set -exu
cat <<-EOF >> "$GITHUB_ENV"
EMQX_AUTH__REDIS__TYPE=cluster
EMQX_AUTH__REDIS__SERVER=${redis_${{ matrix.network_type }}_address}:8000
EOF
- name: set git token
run: |
if make emqx-ee --dry-run > /dev/null 2>&1; then
docker exec -i erlang bash -c "echo \"https://ci%40emqx.io:${{ secrets.CI_GIT_TOKEN }}@github.com\" > /root/.git-credentials && git config --global credential.helper store"
fi
- name: run test cases
if: matrix.connect_type == 'tcp' || (matrix.connect_type == 'tls' && matrix.redis_tag != '5')
run: |
export CUTTLEFISH_ENV_OVERRIDE_PREFIX=EMQX_
export EMQX_AUTH__REIDS__PASSWORD=public
printenv > .env
docker exec -i erlang sh -c "make ensure-rebar3"
docker exec -i erlang sh -c "./rebar3 eunit --dir apps/emqx_auth_redis"

View File

@ -15,8 +15,19 @@ jobs:
steps:
- uses: actions/checkout@v1
- name: prepare
run: |
if make emqx-ee --dry-run > /dev/null 2>&1; then
echo "https://ci%40emqx.io:${{ secrets.CI_GIT_TOKEN }}@github.com" > $HOME/.git-credentials
git config --global credential.helper store
echo "${{ secrets.CI_GIT_TOKEN }}" >> scripts/git-token
make deps-emqx-ee
echo "TARGET=emqx/emqx-ee" >> $GITHUB_ENV
else
echo "TARGET=emqx/emqx" >> $GITHUB_ENV
fi
- name: make emqx image
run: TARGET=emqx/emqx make docker
run: make docker
- name: run emqx
timeout-minutes: 5
run: |
@ -33,20 +44,30 @@ jobs:
done
- name: make paho tests
run: |
docker exec -i paho_client sh -c "apk update && apk add git curl \
&& git clone -b develop-4.0 https://github.com/emqx/paho.mqtt.testing.git /paho.mqtt.testing \
&& pip install pytest \
&& pytest -v /paho.mqtt.testing/interoperability/test_client/V5/test_connect.py -k test_basic --host node1.emqx.io \
&& pytest -v /paho.mqtt.testing/interoperability/test_cluster --host1 node1.emqx.io --host2 node2.emqx.io \
&& pytest -v /paho.mqtt.testing/interoperability/test_client --host node1.emqx.io"
if ! docker exec -i paho_client /scripts/pytest.sh; then
docker logs node1.emqx.io
docker logs node2.emqx.io
exit 1
fi
helm_test:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v1
- name: prepare
run: |
if make emqx-ee --dry-run > /dev/null 2>&1; then
echo "https://ci%40emqx.io:${{ secrets.CI_GIT_TOKEN }}@github.com" > $HOME/.git-credentials
git config --global credential.helper store
echo "${{ secrets.CI_GIT_TOKEN }}" >> scripts/git-token
make deps-emqx-ee
echo "TARGET=emqx/emqx-ee" >> $GITHUB_ENV
else
echo "TARGET=emqx/emqx" >> $GITHUB_ENV
fi
- name: make emqx image
run: TARGET=emqx/emqx make docker
run: make docker
- name: install k3s
env:
KUBECONFIG: "/etc/rancher/k3s/k3s.yaml"
@ -69,15 +90,21 @@ jobs:
timeout-minutes: 5
run: |
version=$(./pkg-vsn.sh)
sudo docker save emqx/emqx:$version -o emqx.tar.gz
sudo docker save ${TARGET}:$version -o emqx.tar.gz
sudo k3s ctr image import emqx.tar.gz
sed -i -r "s/^appVersion: .*$/appVersion: \"${version}\"/g" deploy/charts/emqx/Chart.yaml
sed -i -r 's/ pullPolicy: .*$/ pullPolicy: Never/g' deploy/charts/emqx/values.yaml
sed -i '/emqx_telemetry/d' deploy/charts/emqx/values.yaml
helm install emqx --set emqxAclConfig="" --set emqxConfig.EMQX_ZONE__EXTERNAL__RETRY_INTERVAL=2s --set emqxConfig.EMQX_MQTT__MAX_TOPIC_ALIAS=10 deploy/charts/emqx --debug --dry-run
helm install emqx --set emqxAclConfig="" --set emqxConfig.EMQX_ZONE__EXTERNAL__RETRY_INTERVAL=2s --set emqxConfig.EMQX_MQTT__MAX_TOPIC_ALIAS=10 deploy/charts/emqx
helm install emqx \
--set image.repository=${TARGET} \
--set image.pullPolicy=Never \
--set emqxAclConfig="" \
--set image.pullPolicy=Never \
--set emqxConfig.EMQX_ZONE__EXTERNAL__RETRY_INTERVAL=2s \
--set emqxConfig.EMQX_MQTT__MAX_TOPIC_ALIAS=10 \
deploy/charts/emqx \
--debug
while [ "$(kubectl get StatefulSet -l app.kubernetes.io/name=emqx -o jsonpath='{.items[0].status.replicas}')" \
!= "$(kubectl get StatefulSet -l app.kubernetes.io/name=emqx -o jsonpath='{.items[0].status.readyReplicas}')" ]; do
@ -110,11 +137,18 @@ jobs:
emqx2=$(kubectl get pods emqx-2 -o jsonpath='{.status.podIP}')
pytest -v paho.mqtt.testing/interoperability/test_client/V5/test_connect.py -k test_basic --host $emqx_svc
RESULT=$?
pytest -v paho.mqtt.testing/interoperability/test_cluster --host1 $emqx1 --host2 $emqx2
RESULT=$((RESULT + $?))
if [ 0 -ne $RESULT ]; then
kubectl logs emqx-1
kubectl logs emqx-2
fi
exit $RESULT
relup_test:
runs-on: ubuntu-20.04
container: emqx/build-env:erl23.2.2-ubuntu20.04
container: emqx/build-env:erl23.2.7-ubuntu20.04
defaults:
run:
shell: bash
@ -148,14 +182,37 @@ jobs:
repository: ${{ github.repository }}
path: emqx
fetch-depth: 0
- name: prepare
run: |
if make -C emqx emqx-ee --dry-run > /dev/null 2>&1; then
echo "https://ci%40emqx.io:${{ secrets.CI_GIT_TOKEN }}@github.com" > $HOME/.git-credentials
git config --global credential.helper store
echo "${{ secrets.CI_GIT_TOKEN }}" >> emqx/scripts/git-token
echo "PROFILE=emqx-ee" >> $GITHUB_ENV
else
echo "PROFILE=emqx" >> $GITHUB_ENV
fi
- name: get version
run: |
set -e -x -u
cd emqx
vsn="$(erl -eval '{ok, [{application,emqx, L} | _]} = file:consult("src/emqx.app.src"), {vsn, VSN} = lists:keyfind(vsn,1,L), io:fwrite(VSN), halt().' -noshell)"
if [ $PROFILE = "emqx" ];then
broker="emqx-ce"
edition='opensource'
else
broker="emqx-ee"
edition='enterprise'
fi
vsn="$(grep -E "define.+EMQX_RELEASE.+${edition}" include/emqx_release.hrl | cut -d '"' -f2)"
echo "VSN=$vsn" >> $GITHUB_ENV
pre_tag="$(echo $vsn | grep -oE '^[0-9]+.[0-9]')"
old_vsns="$(git tag -l "$pre_tag.[0-9]" | tr "\n" " " | sed "s/$vsn//")"
pre_vsn="$(echo $vsn | grep -oE '^[0-9]+.[0-9]')"
if [ $PROFILE = "emqx" ]; then
old_vsns="$(git tag -l "v$pre_vsn.[0-9]" | tr "\n" " " | sed "s/v$vsn//")"
else
old_vsns="$(git tag -l "e$pre_vsn.[0-9]" | tr "\n" " " | sed "s/v$vsn//")"
fi
echo "OLD_VSNS=$old_vsns" >> $GITHUB_ENV
- name: download emqx
run: |
@ -163,10 +220,10 @@ jobs:
cd emqx
old_vsns=($(echo $OLD_VSNS | tr ' ' ' '))
for old_vsn in ${old_vsns[@]}; do
wget https://s3-us-west-2.amazonaws.com/packages.emqx/emqx-ce/v$old_vsn/emqx-ubuntu20.04-${old_vsn}-x86_64.zip
wget https://s3-${{ secrets.AWS_DEFAULT_REGION }}.amazonaws.com/${{ secrets.AWS_S3_BUCKET }}/$broker/$old_vsn/$PROFILE-ubuntu20.04-${old_vsn#[e|v]}-x86_64.zip
done
- name: build emqx
run: make -C emqx emqx-zip
run: make -C emqx ${PROFILE}-zip
- name: build emqtt-bench
run: make -C emqtt-bench
- name: build lux

View File

@ -12,15 +12,25 @@ jobs:
run: |
sudo apt-get update
sudo apt install gitlint
- name: Set auth header
if: endsWith(github.repository, 'enterprise')
run: |
echo 'AUTH_HEADER<<EOF' >> $GITHUB_ENV
echo "Authorization: token ${{ secrets.CI_GIT_TOKEN }}" >> $GITHUB_ENV
echo 'EOF' >> $GITHUB_ENV
- name: Run gitlint
shell: bash
run: |
pr_number=$(echo $GITHUB_REF | awk 'BEGIN { FS = "/" } ; { print $3 }')
messages=$(curl "https://api.github.com/repos/${GITHUB_REPOSITORY}/pulls/${pr_number}/commits")
messages="$(curl --silent --show-error \
--header "${{ env.AUTH_HEADER }}" \
--header "Accept: application/vnd.github.v3+json" \
"https://api.github.com/repos/${GITHUB_REPOSITORY}/pulls/${pr_number}/commits")"
len=$(echo $messages | jq length)
result=true
for i in $( seq 0 $(($len - 1)) ); do
message=$(echo $messages | jq -r .[$i].commit.message)
echo commit message: $message
echo "commit message: $message"
status=0
echo $message | gitlint -C ./.github/workflows/.gitlint || status=$?
if [ $status -ne 0 ]; then

View File

@ -12,10 +12,16 @@ on:
jobs:
run_static_analysis:
runs-on: ubuntu-20.04
container: emqx/build-env:erl23.2.2-ubuntu20.04
container: emqx/build-env:erl23.2.7-ubuntu20.04
steps:
- uses: actions/checkout@v2
- name: set git credentials
run: |
if make emqx-ee --dry-run > /dev/null 2>&1; then
echo "https://ci%40emqx.io:${{ secrets.CI_GIT_TOKEN }}@github.com" > $HOME/.git-credentials
git config --global credential.helper store
fi
- name: xref
run: make xref
- name: dialyzer
@ -26,7 +32,16 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: set up
- name: set edition
id: set_edition
run: |
if make emqx-ee --dry-run > /dev/null 2>&1; then
echo "EDITION=enterprise" >> $GITHUB_ENV
else
echo "EDITION=opensource" >> $GITHUB_ENV
fi
- name: docker compose up
if: env.EDITION == 'opensource'
env:
MYSQL_TAG: 8
REDIS_TAG: 6
@ -35,16 +50,63 @@ jobs:
LDAP_TAG: 2.4.50
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
docker-compose -f .ci/apps_tests/docker-compose.yaml build --no-cache
docker-compose -f .ci/apps_tests/docker-compose.yaml up -d
docker-compose \
-f .ci/docker-compose-file/docker-compose.yaml \
-f .ci/docker-compose-file/docker-compose-ldap-tcp.yaml \
-f .ci/docker-compose-file/docker-compose-mongo-tcp.yaml \
-f .ci/docker-compose-file/docker-compose-mysql-tcp.yaml \
-f .ci/docker-compose-file/docker-compose-pgsql-tcp.yaml \
-f .ci/docker-compose-file/docker-compose-redis-single-tcp.yaml \
up -d --build
- name: docker compose up
if: env.EDITION == 'enterprise'
env:
MYSQL_TAG: 8
REDIS_TAG: 6
MONGO_TAG: 4
PGSQL_TAG: 13
LDAP_TAG: 2.4.50
OPENTSDB_TAG: latest
INFLUXDB_TAG: 1.7.6
DYNAMODB_TAG: 1.11.477
TIMESCALE_TAG: latest-pg11
CASSANDRA_TAG: 3.11.6
RABBITMQ_TAG: 3.7
KAFKA_TAG: 2.5.0
PULSAR_TAG: 2.3.2
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
timeout-minutes: 20
run: |
docker-compose \
-f .ci/docker-compose-file/docker-compose.yaml \
-f .ci/docker-compose-file/docker-compose-ldap-tcp.yaml \
-f .ci/docker-compose-file/docker-compose-mongo-tcp.yaml \
-f .ci/docker-compose-file/docker-compose-mysql-tcp.yaml \
-f .ci/docker-compose-file/docker-compose-pgsql-tcp.yaml \
-f .ci/docker-compose-file/docker-compose-redis-single-tcp.yaml \
-f .ci/docker-compose-file/docker-compose-enterprise.yaml \
-f .ci/docker-compose-file/docker-compose-enterprise-cassandra-tcp.yaml \
-f .ci/docker-compose-file/docker-compose-enterprise-dynamodb-tcp.yaml \
-f .ci/docker-compose-file/docker-compose-enterprise-influxdb-tcp.yaml \
-f .ci/docker-compose-file/docker-compose-enterprise-kafka-tcp.yaml \
-f .ci/docker-compose-file/docker-compose-enterprise-opentsdb-tcp.yaml \
-f .ci/docker-compose-file/docker-compose-enterprise-pulsar-tcp.yaml \
-f .ci/docker-compose-file/docker-compose-enterprise-rabbit-tcp.yaml \
-f .ci/docker-compose-file/docker-compose-enterprise-timescale-tcp.yaml \
-f .ci/docker-compose-file/docker-compose-enterprise-mysql-client.yaml \
-f .ci/docker-compose-file/docker-compose-enterprise-pgsql-and-timescale-client.yaml \
up -d --build
docker exec -i erlang bash -c "echo \"https://ci%40emqx.io:${{ secrets.CI_GIT_TOKEN }}@github.com\" > /root/.git-credentials && git config --global credential.helper store"
while [ $(docker ps -a --filter name=client --filter exited=0 | wc -l) \
!= $(docker ps -a --filter name=client | wc -l) ]; do
sleep 5
done
- name: run eunit
run: |
docker exec -i erlang bash -c "make eunit"
docker exec --env EMQX_EXTRA_PLUGINS=all -i erlang bash -c "./rebar3 eunit --dir $(find lib-extra/ -mindepth 1 -maxdepth 2 -type l | tr '\n' ',')"
- name: run common test
run: |
docker exec -i erlang bash -c "make ct"
docker exec --env EMQX_EXTRA_PLUGINS=all -i erlang bash -c "./rebar3 ct --dir $(find lib-extra/ -mindepth 1 -maxdepth 2 -type l | tr '\n' ',')"
- name: run cover
run: |
docker exec -i erlang bash -c "make cover"

View File

@ -1,4 +1,4 @@
$(shell scripts/git-hooks-init.sh)
$(shell $(CURDIR)/scripts/git-hooks-init.sh)
REBAR_VERSION = 3.14.3-emqx-5
REBAR = $(CURDIR)/rebar3
BUILD = $(CURDIR)/build
@ -6,6 +6,9 @@ SCRIPTS = $(CURDIR)/scripts
export PKG_VSN ?= $(shell $(CURDIR)/pkg-vsn.sh)
export EMQX_DESC ?= EMQ X
export EMQX_CE_DASHBOARD_VERSION ?= v4.3.0-beta.1
ifeq ($(OS),Windows_NT)
export REBAR_COLOR=none
endif
PROFILE ?= emqx
REL_PROFILES := emqx emqx-edge
@ -33,27 +36,37 @@ get-dashboard:
.PHONY: eunit
eunit: $(REBAR)
@$(REBAR) eunit -v -c
@ENABLE_COVER_COMPILE=1 $(REBAR) eunit -v -c
.PHONY: proper
proper: $(REBAR)
@$(REBAR) as test proper -d test/props -c
@ENABLE_COVER_COMPILE=1 $(REBAR) as test proper -d test/props -c
.PHONY: ct
ct: $(REBAR)
@$(REBAR) ct --name 'test@127.0.0.1' -c -v
@ENABLE_COVER_COMPILE=1 $(REBAR) ct --name 'test@127.0.0.1' -c -v
APPS=$(shell $(CURDIR)/scripts/find-apps.sh)
## app/name-ct targets are intended for local tests hence cover is not enabled
.PHONY: $(APPS:%=%-ct)
define gen-app-ct-target
$1-ct:
$(REBAR) ct --name 'test@127.0.0.1' -v --suite $(shell $(CURDIR)/scripts/find-suites.sh $1)
endef
$(foreach app,$(APPS),$(eval $(call gen-app-ct-target,$(app))))
.PHONY: cover
cover: $(REBAR)
@$(REBAR) cover
@ENABLE_COVER_COMPILE=1 $(REBAR) cover
.PHONY: coveralls
coveralls: $(REBAR)
@$(REBAR) as test coveralls send
@ENABLE_COVER_COMPILE=1 $(REBAR) as test coveralls send
.PHONY: $(REL_PROFILES)
$(REL_PROFILES:%=%): $(REBAR) get-dashboard
@$(REBAR) as $(@) release
@$(REBAR) as $(@) do compile,release
## Not calling rebar3 clean because
## 1. rebar3 clean relies on rebar3, meaning it reads config, fetches dependencies etc.
@ -97,7 +110,7 @@ ifneq ($(OS),Windows_NT)
endif
.PHONY: $(REL_PROFILES:%=%-tar) $(PKG_PROFILES:%=%-tar)
$(REL_PROFILES:%=%-tar) $(PKG_PROFILES:%=%-tar): $(REBAR) get-dashboard
$(REL_PROFILES:%=%-tar) $(PKG_PROFILES:%=%-tar): $(REBAR) get-dashboard $(CONF_SEGS)
@$(BUILD) $(subst -tar,,$(@)) tar
## zip targets depend on the corresponding relup and tar artifacts
@ -118,4 +131,11 @@ $1: $(subst -pkg,,$1)-zip $1-tar
endef
$(foreach pt,$(PKG_PROFILES),$(eval $(call gen-pkg-target,$(pt))))
.PHONY: run
run: $(PROFILE) quickrun
.PHONY: quickrun
quickrun:
./_build/$(PROFILE)/rel/emqx/bin/emqx console
include docker.mk

View File

@ -6,8 +6,9 @@
[![Docker Pulls](https://img.shields.io/docker/pulls/emqx/emqx)](https://hub.docker.com/r/emqx/emqx)
[![Slack Invite](<https://slack-invite.emqx.io/badge.svg>)](https://slack-invite.emqx.io)
[![Twitter](https://img.shields.io/badge/Twitter-EMQ%20X-1DA1F2?logo=twitter)](https://twitter.com/emqtt)
[![Community](https://img.shields.io/badge/Community-EMQ%20X-yellow)](https://askemq.com)
[![最棒的物联网 MQTT 开源团队期待您的加入](https://www.emqx.io/static/img/github_readme_cn_bg.png)](https://www.emqx.io/cn/careers)
[![最棒的物联网 MQTT 开源团队期待您的加入](https://www.emqx.io/static/img/github_readme_cn_bg.png)](https://careers.emqx.cn/)
[English](./README.md) | 简体中文 | [日本語](./README-JP.md)
@ -16,7 +17,7 @@
从 3.0 版本开始,*EMQ X* 完整支持 MQTT V5.0 协议规范,向下兼容 MQTT V3.1 和 V3.1.1,并支持 MQTT-SN、CoAP、LwM2M、WebSocket 和 STOMP 等通信协议。EMQ X 3.0 单集群可支持千万级别的 MQTT 并发连接。
- 新功能的完整列表,请参阅 [EMQ X Release Notes](https://github.com/emqx/emqx/releases)。
- 获取更多信息,请访问 [EMQ X 官网](https://www.emqx.io/cn/)。
- 获取更多信息,请访问 [EMQ X 官网](https://www.emqx.cn/)。
## 安装
@ -25,15 +26,15 @@
#### EMQ X Docker 镜像安装
```
docker run -d --name emqx -p 1883:1883 -p 8083:8083 -p 8883:8883 -p 8084:8084 -p 18083:18083 emqx/emqx
docker run -d --name emqx -p 1883:1883 -p 8081:8081 -p 8083:8083 -p 8883:8883 -p 8084:8084 -p 18083:18083 emqx/emqx
```
#### 二进制软件包安装
需从 [EMQ X 下载](https://www.emqx.io/cn/downloads) 页面获取相应操作系统的二进制软件包。
需从 [EMQ X 下载](https://www.emqx.cn/downloads) 页面获取相应操作系统的二进制软件包。
- [单节点安装文档](https://docs.emqx.io/broker/latest/cn/getting-started/install.html)
- [集群配置文档](https://docs.emqx.io/broker/latest/cn/advanced/cluster.html)
- [单节点安装文档](https://docs.emqx.cn/broker/latest/getting-started/install.html)
- [集群配置文档](https://docs.emqx.cn/broker/latest/advanced/cluster.html)
## 从源码构建
@ -75,7 +76,7 @@ DIALYZER_ANALYSE_APP=emqx_lwm2m,emqx_auth_jwt,emqx_auth_ldap make dialyzer
## FAQ
访问 [EMQ X FAQ](https://docs.emqx.io/broker/latest/cn/faq/faq.html) 以获取常见问题的帮助。
访问 [EMQ X FAQ](https://docs.emqx.cn/broker/latest/faq/faq.html) 以获取常见问题的帮助。
## 产品路线
@ -89,9 +90,9 @@ DIALYZER_ANALYSE_APP=emqx_lwm2m,emqx_auth_jwt,emqx_auth_ldap make dialyzer
- [Twitter](https://twitter.com/emqtt)
- [Facebook](https://www.facebook.com/emqxmqtt)
- [Reddit](https://www.reddit.com/r/emqx/)
- [Forum](https://groups.google.com/d/forum/emqtt)
- [Forum](https://askemq.com)
- [Weibo](https://weibo.com/emqtt)
- [Blog](https://www.emqx.io/cn/blog)
- [Blog](https://www.emqx.cn/blog)
欢迎你将任何 bug、问题和功能请求提交到 [emqx/emqx](https://github.com/emqx/emqx/issues)。

View File

@ -23,18 +23,20 @@ Starting from 3.0 release, *EMQ X* broker fully supports MQTT V5.0 protocol spec
The *EMQ X* broker is cross-platform, which supports Linux, Unix, macOS and Windows. It means *EMQ X* can be deployed on x86_64 architecture servers and ARM devices like Raspberry Pi.
See more details for building and running *EMQ X* on Windows in [Windows.md](./Windows.md)
#### Installing via EMQ X Docker Image
```
docker run -d --name emqx -p 1883:1883 -p 8083:8083 -p 8883:8883 -p 8084:8084 -p 18083:18083 emqx/emqx
docker run -d --name emqx -p 1883:1883 -p 8081:8081 -p 8083:8083 -p 8883:8883 -p 8084:8084 -p 18083:18083 emqx/emqx
```
#### Installing via Binary Package
Get the binary package of the corresponding OS from [EMQ X Download](https://www.emqx.io/downloads) page.
- [Single Node Install](https://docs.emqx.io/broker/latest/en/getting-started/install.html)
- [Multi Node Install](https://docs.emqx.io/broker/latest/en/advanced/cluster.html)
- [Single Node Install](https://docs.emqx.io/en/broker/latest/getting-started/install.html)
- [Multi Node Install](https://docs.emqx.io/en/broker/latest/advanced/cluster.html)
## Build From Source
@ -87,17 +89,12 @@ make eunit ct
### To run subset of the common tests
examples
Examples
```bash
./rebar3 ct --name 'test@127.0.0.1' -c -v --dir test,apps/emqx_sn,apps/emqx_coap
./rebar3 ct --name 'test@127.0.0.1' -c -v --dir apps/emqx_auth_mnesi --suite emqx_acl_mnesia_SUITE
./rebar3 ct --name 'test@127.0.0.1' -c -v --dir apps/emqx_auth_mnesi --suite emqx_acl_mnesia_SUITE --case t_rest_api
make apps/emqx_bridge_mqtt-ct
```
NOTE: Do *NOT* use full (relative) path to SUITE files like this `--suite apps/emqx_auth_mnesia/test/emqx_acl_mnesia_SUITE.erl`,
because it will lead to a full copy of `apps` dir into `_buid/test/lib/emqx`.
### Dialyzer
##### To Analyze all the apps
```
@ -109,19 +106,25 @@ make dialyzer
DIALYZER_ANALYSE_APP=emqx_lwm2m,emqx_auth_jwt,emqx_auth_ldap make dialyzer
```
## FAQ
Visiting [EMQ X FAQ](https://docs.emqx.io/broker/latest/en/faq/faq.html) to get help of common problems.
## Roadmap
The [EMQ X Roadmap uses Github milestones](https://github.com/emqx/emqx/milestones) to track the progress of the project.
## Community
The EMQ X community can be found on [GitHub Discussions](https://github.com/emqx/emqx/discussions), where you can ask questions, voice ideas, and share your projects.
### FAQ
Visiting [EMQ X FAQ](https://docs.emqx.io/en/broker/latest/faq/faq.html) to get help of common problems.
### Questions
[GitHub Discussions](https://github.com/emqx/emqx/discussions) is where you can ask questions, and share ideas.
### Proposals
For more organised improvement proposals, you can send pull requests to [EIP](https://github.com/emqx/eip).
### Plugin development
To develop your own plugins, see [lib-extra/README.md](./lib-extra/README.md)
To chat with other community members you can join the [EMQ X Slack](https://slack-invite.emqx.io).
## MQTT Specifications

127
Windows.md Normal file
View File

@ -0,0 +1,127 @@
# Build and run EMQ X on Windows
NOTE: The instructions and examples are based on Windows 10.
## Build Environment
### Visual studio for C/C++ compile and link
EMQ X includes Erlang NIF (Native Implmented Function) components, implemented
in C/C++. To compile and link C/C++ libraries, the easiest way is perhaps to
install Visual Studio.
Visual Studio 2019 is used in our tests.
If you are like me (@zmstone), do not know where to start,
please follow this OTP guide:
https://github.com/erlang/otp/blob/master/HOWTO/INSTALL-WIN32.md
NOTE: To avoid surprises, you may need to add below two paths to `Path` environment variable
and order them before other paths.
```
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.28.29910\bin\Hostx64\x64
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build
```
Depending on your visual studio version and OS, the paths may differ.
The first path is for rebar3 port compiler to find `cl.exe` and `link.exe`
The second path is for Powershell or CMD to setup environment variables.
### Erlang/OTP
Install Erlang/OTP 23.2 from https://www.erlang.org/downloads
You may need to edit the `Path` environment variable to allow running
Erlang commands such as `erl` from powershell.
To validate Erlang installation in CMD or powershell:
* Start (or restart) CMD or powershell
* Execute `erl` command to enter Erlang shell
* Evaluate Erlang expression `halt().` to exit Erlang shell.
e.g.
```
PS C:\Users\zmsto> erl
Eshell V11.1.4 (abort with ^G)
1> halt().
```
### bash
All EMQ X build/run scripts are either in `bash` or `escript`.
`escript` is installed as a part of Erlang. To install a `bash`
environment in Windows, there are quite a few options.
Cygwin is what we tested with.
* Add `cygwin\bin` dir to `Path` environment variable
To do so, search for Edit environment variable in control pannel and
add `C:\tools\cygwin\bin` (depending on the location where it was installed)
to `Path` list.
* Validate installation.
Start (restart) CMD or powershell console and execute `which bash`, it should
print out `/usr/bin/bash`
### Other tools
Some of the unix world tools are required to build EMQ X. Including:
* git
* curl
* make
* jq
* zip / unzip
We recommend using [scoop](https://scoop.sh/), or [Chocolatey](https://chocolatey.org/install) to install the tools.
When using scoop:
```
scoop install git curl make jq zip unzip
```
## Build EMQ X source code
* Clone the repo: `git clone https://github.com/emqx/emqx.git`
* Start CMD or Powershell
* Execute `vcvarsall.bat x86_amd64` to load environment variables
* Change to emqx directory and execute `make`
### Possible errors
* `'cl.exe' is not recognized as an internal or external command`
This error is likely due to Visual Studio executables are not set in `Path` environment variable.
To fix it, either add path like `C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.28.29910\bin\Hostx64\x64`
to `Paht`. Or make sure `vcvarsall.bat x86_amd64` is executed prior to the `make` command
* `fatal error C1083: Cannot open include file: 'assert.h': No such file or directory`
If Visual Studio is installed correctly, this is likely `LIB` and `LIB_PATH` environment
variables are not set. Make sure `vcvarsall.bat x86_amd64` is executed prior to the `make` command
* `link: extra operand 'some.obj'`
This is likely due ot the usage of GNU `lnik.exe` but not the one from Visual Studio.
Exeucte `link.exe --version` to inspect which one is in use. The one installed from
Visual Studio should print out `Microsoft (R) Incremental Linker`.
To fix it, Visual Studio's bin paths should be ordered prior to Cygwin's (or similar installation's)
bin paths in `Path` environment variable.
## Run EMQ X
To start EMQ X broker.
Execute `_build\emqx\rel\emqx>.\bin\emqx console` or `_build\emqx\rel\emqx>.\bin\emqx start` to start EMQ X.
Then execute `_build\emqx\rel\emqx>.\bin\emqx_ctl status` to check status.
If everything works fine, it should print out
```
Node 'emqx@127.0.0.1' 4.3-beta.1 is started
Application emqx 4.3.0 is running
```

View File

@ -16,14 +16,14 @@ auth.http.auth_req.method = post
## HTTP Request Headers for Auth Request, Content-Type header is configured by default.
## The possible values of the Content-Type header: application/x-www-form-urlencoded, application/json
##
##
## Examples: auth.http.auth_req.headers.accept = */*
auth.http.auth_req.headers.content-type = "application/x-www-form-urlencoded"
## Parameters used to construct the request body or query string parameters
## When the request method is GET, these parameters will be converted into query string parameters
## When the request method is POST, the final format is determined by content-type
##
##
## Available Variables:
## - %u: username
## - %c: clientid
@ -58,7 +58,7 @@ auth.http.super_req.headers.content-type = "application/x-www-form-urlencoded"
## Parameters used to construct the request body or query string parameters
## When the request method is GET, these parameters will be converted into query string parameters
## When the request method is POST, the final format is determined by content-type
##
##
## Available Variables:
## - %u: username
## - %c: clientid
@ -93,7 +93,7 @@ auth.http.acl_req.headers.content-type = "application/x-www-form-urlencoded"
## Parameters used to construct the request body or query string parameters
## When the request method is GET, these parameters will be converted into query string parameters
## When the request method is POST, the final format is determined by content-type
##
##
## Available Variables:
## - %u: username
## - %c: clientid
@ -117,7 +117,7 @@ auth.http.acl_req.params = "access=%A,username=%u,clientid=%c,ipaddr=%a,topic=%t
## Default: 5s
auth.http.timeout = 5s
## Connection time-out time, used during the initial request,
## Connection time-out time, used during the initial request,
## when the client is connecting to the server.
##
## Value: Duration
@ -151,3 +151,18 @@ auth.http.pool_size = 32
##
## Value: File
## auth.http.ssl.keyfile = "{{ platform_etc_dir }}/certs/client-key.pem"
## In mode verify_none the default behavior is to allow all x509-path
## validation errors.
##
## Value: true | false
## auth.http.ssl.verify = false
## If not specified, the server's names returned in server's certificate is validated against
## what's provided `auth.http.auth_req.url` config's host part.
## Setting to 'disable' will make EMQ X ignore unmatched server names.
## If set with a host name, the server's names returned in server's certificate is validated
## against this value.
##
## Value: String | disable
## auth.http.ssl.server_name_indication = disable

View File

@ -116,3 +116,12 @@ end}.
{mapping, "auth.http.ssl.keyfile", "emqx_auth_http.keyfile", [
{datatype, string}
]}.
{mapping, "auth.http.ssl.verify", "emqx_auth_http.verify", [
{default, false},
{datatype, {enum, [true, false]}}
]}.
{mapping, "auth.http.ssl.server_name_indication", "emqx_auth_http.server_name_indication", [
{datatype, string}
]}.

View File

@ -66,11 +66,22 @@ translate_env(EnvName) ->
CACertFile = application:get_env(?APP, cacertfile, undefined),
CertFile = application:get_env(?APP, certfile, undefined),
KeyFile = application:get_env(?APP, keyfile, undefined),
TLSOpts = lists:filter(fun({_K, V}) when V =:= <<>> ->
false;
(_) ->
true
end, [{keyfile, KeyFile}, {certfile, CertFile}, {cacertfile, CACertFile}]),
Verify = case application:get_env(?APP, verify, fasle) of
true -> verify_peer;
false -> verify_none
end,
SNI = case application:get_env(?APP, server_name_indication, undefined) of
"disable" -> disable;
SNI0 -> SNI0
end,
TLSOpts = lists:filter(
fun({_, V}) ->
V =/= <<>> andalso V =/= undefined
end, [{keyfile, KeyFile},
{certfile, CertFile},
{cacertfile, CACertFile},
{verify, Verify},
{server_name_indication, SNI}]),
NTLSOpts = [ {versions, emqx_tls_lib:default_versions()}
, {ciphers, emqx_tls_lib:default_ciphers()}
| TLSOpts

View File

@ -90,7 +90,9 @@ set_https_client_opts() ->
SSLOpt = emqx_ct_helpers:client_ssl_twoway(),
application:set_env(emqx_auth_http, cacertfile, proplists:get_value(cacertfile, SSLOpt, undefined)),
application:set_env(emqx_auth_http, certfile, proplists:get_value(certfile, SSLOpt, undefined)),
application:set_env(emqx_auth_http, keyfile, proplists:get_value(keyfile, SSLOpt, undefined)).
application:set_env(emqx_auth_http, keyfile, proplists:get_value(keyfile, SSLOpt, undefined)),
application:set_env(emqx_auth_http, verify, true),
application:set_env(emqx_auth_http, server_name_indication, "disable").
%% @private
http_server(http, inet) -> "http://127.0.0.1:8991";

View File

@ -73,6 +73,4 @@ auth.ldap.ssl.enable = false
#auth.ldap.ssl.verify = "verify_peer"
#auth.ldap.ssl.fail_if_no_peer_cert = true
#auth.ldap.ssl.server_name_indication = your_server_name

View File

@ -53,10 +53,6 @@
{datatype, {enum, [verify_none, verify_peer]}}
]}.
{mapping, "auth.ldap.ssl.fail_if_no_peer_cert", "emqx_auth_ldap.ldap", [
{datatype, {enum, [true, false]}}
]}.
{mapping, "auth.ldap.ssl.server_name_indication", "emqx_auth_ldap.ldap", [
{datatype, string}
]}.
@ -75,8 +71,10 @@
{keyfile, cuttlefish:conf_get("auth.ldap.ssl.keyfile", Conf)},
{cacertfile, cuttlefish:conf_get("auth.ldap.ssl.cacertfile", Conf, undefined)},
{verify, cuttlefish:conf_get("auth.ldap.ssl.verify", Conf, undefined)},
{server_name_indication, cuttlefish:conf_get("auth.ldap.ssl.server_name_indication", Conf, disable)},
{fail_if_no_peer_cert, cuttlefish:conf_get("auth.ldap.ssl.fail_if_no_peer_cert", Conf, undefined)}]
{server_name_indication, case cuttlefish:conf_get("auth.ldap.ssl.server_name_indication", Conf, undefined) of
"disable" -> disable;
SNI -> SNI
end}]
end,
Opts = [{servers, Servers},
{port, Port},

View File

@ -44,13 +44,11 @@ groups() ->
init_per_group(GrpName, Cfg) ->
Fun = fun(App) -> set_special_configs(GrpName, App) end,
emqx_ct_helpers:start_apps([emqx_modules]),
emqx_ct_helpers:start_apps([emqx_auth_ldap], Fun),
emqx_mod_acl_internal:unload([]),
Cfg.
end_per_group(_GrpName, _Cfg) ->
emqx_ct_helpers:stop_apps([emqx_auth_ldap, emqx_modules]).
emqx_ct_helpers:stop_apps([emqx_auth_ldap]).
%%--------------------------------------------------------------------
%% Cases

View File

@ -36,12 +36,11 @@ all() ->
check_acl].
init_per_suite(Config) ->
emqx_ct_helpers:start_apps([emqx_modules, emqx_auth_ldap], fun set_special_configs/1),
emqx_mod_acl_internal:unload([]),
emqx_ct_helpers:start_apps([emqx_auth_ldap], fun set_special_configs/1),
Config.
end_per_suite(_Config) ->
emqx_ct_helpers:stop_apps([emqx_auth_ldap, emqx_modules]).
emqx_ct_helpers:stop_apps([emqx_auth_ldap]).
check_auth(_) ->
MqttUser1 = #{clientid => <<"mqttuser1">>,
@ -62,7 +61,6 @@ check_auth(_) ->
?assertEqual({error, not_authorized}, emqx_access_control:authenticate(NonExistUser1)).
check_acl(_) ->
% emqx_modules:load_module(emqx_mod_acl_internal, false),
MqttUser = #{clientid => <<"mqttuser1">>, username => <<"user1">>, zone => external},
NoMqttUser = #{clientid => <<"mqttuser2">>, username => <<"user7">>, zone => external},
allow = emqx_access_control:check_acl(MqttUser, publish, <<"mqttuser0001/pub/1">>),

View File

@ -31,6 +31,7 @@
init() ->
ok = ekka_mnesia:create_table(emqx_acl, [
{type, bag},
{disc_copies, [node()]},
{attributes, record_info(fields, emqx_acl)},
{storage_properties, [{ets, [{read_concurrency, true}]}]}]),

View File

@ -39,13 +39,24 @@
-spec(add_acl(login() | all, emqx_topic:topic(), pub | sub | pubsub, allow | deny) ->
ok | {error, any()}).
add_acl(Login, Topic, Action, Access) ->
Acls = #?TABLE{
filter = {Login, Topic},
action = Action,
access = Access,
created_at = erlang:system_time(millisecond)
},
ret(mnesia:transaction(fun mnesia:write/1, [Acls])).
Filter = {Login, Topic},
Acl = #?TABLE{
filter = Filter,
action = Action,
access = Access,
created_at = erlang:system_time(millisecond)
},
ret(mnesia:transaction(
fun() ->
OldRecords = mnesia:wread({?TABLE, Filter}),
case Action of
pubsub ->
update_permission(pub, Acl, OldRecords),
update_permission(sub, Acl, OldRecords);
_ ->
update_permission(Action, Acl, OldRecords)
end
end)).
%% @doc Lookup acl by login
-spec(lookup_acl(login() | all) -> list()).
@ -160,18 +171,27 @@ cli(["show", "username", Username]) ->
[print_acl(Acl) || Acl <- lookup_acl({username, iolist_to_binary(Username)})];
cli(["del", "clientid", Clientid, Topic])->
cli(["delete", "clientid", Clientid, Topic]);
cli(["delete", "clientid", Clientid, Topic])->
case remove_acl({clientid, iolist_to_binary(Clientid)}, iolist_to_binary(Topic)) of
ok -> emqx_ctl:print("ok~n");
{error, Reason} -> emqx_ctl:print("Error: ~p~n", [Reason])
end;
cli(["del", "username", Username, Topic])->
cli(["delete", "username", Username, Topic]);
cli(["delete", "username", Username, Topic])->
case remove_acl({username, iolist_to_binary(Username)}, iolist_to_binary(Topic)) of
ok -> emqx_ctl:print("ok~n");
{error, Reason} -> emqx_ctl:print("Error: ~p~n", [Reason])
end;
cli(["del", "_all", Topic])->
cli(["delete", "_all", Topic]);
cli(["delete", "_all", Topic])->
case remove_acl(all, iolist_to_binary(Topic)) of
ok -> emqx_ctl:print("ok~n");
{error, Reason} -> emqx_ctl:print("Error: ~p~n", [Reason])
@ -186,9 +206,9 @@ cli(_) ->
, {"acl aad clientid <Clientid> <Topic> <Action> <Access>", "Add clientid acl"}
, {"acl add Username <Username> <Topic> <Action> <Access>", "Add username acl"}
, {"acl add _all <Topic> <Action> <Access>", "Add $all acl"}
, {"acl del clientid <Clientid> <Topic>", "Delete clientid acl"}
, {"acl del username <Username> <Topic>", "Delete username acl"}
, {"acl del _all <Topic>", "Delete $all acl"}
, {"acl delete clientid <Clientid> <Topic>", "Delete clientid acl"}
, {"acl delete username <Username> <Topic>", "Delete username acl"}
, {"acl delete _all <Topic>", "Delete $all acl"}
]).
%%--------------------------------------------------------------------
@ -224,3 +244,27 @@ print_acl({all, Topic, Action, Access, _}) ->
"Acl($all topic = ~p action = ~p access = ~p)~n",
[Topic, Action, Access]
).
update_permission(Action, Acl0, OldRecords) ->
Acl = Acl0 #?TABLE{action = Action},
maybe_delete_shadowed_records(Action, OldRecords),
mnesia:write(Acl).
maybe_delete_shadowed_records(_, []) ->
ok;
maybe_delete_shadowed_records(Action1, [Rec = #emqx_acl{action = Action2} | Rest]) ->
if Action1 =:= Action2 ->
ok = mnesia:delete_object(Rec);
Action2 =:= pubsub ->
%% Perform migration from the old data format on the
%% fly. This is needed only for the enterprise version,
%% delete this branch on 5.0
mnesia:delete_object(Rec),
mnesia:write(Rec#?TABLE{action = other_action(Action1)});
true ->
ok
end,
maybe_delete_shadowed_records(Action1, Rest).
other_action(pub) -> sub;
other_action(sub) -> pub.

View File

@ -144,6 +144,9 @@ auth_clientid_cli(["update", ClientId, NewPassword]) ->
end;
auth_clientid_cli(["del", ClientId]) ->
auth_clientid_cli(["delete", ClientId]);
auth_clientid_cli(["delete", ClientId]) ->
case remove_user({clientid, iolist_to_binary(ClientId)}) of
ok -> emqx_ctl:print("ok~n");
{error, Reason} -> emqx_ctl:print("Error: ~p~n", [Reason])
@ -153,7 +156,7 @@ auth_clientid_cli(_) ->
emqx_ctl:usage([{"clientid list", "List clientid auth rules"},
{"clientid add <Username> <Password>", "Add clientid auth rule"},
{"clientid update <Username> <NewPassword>", "Update clientid auth rule"},
{"clientid del <Username>", "Delete clientid auth rule"}]).
{"clientid delete <Username>", "Delete clientid auth rule"}]).
%%--------------------------------------------------------------------
%% Auth Username Cli
@ -176,6 +179,9 @@ auth_username_cli(["update", Username, NewPassword]) ->
{error, Reason} -> emqx_ctl:print("Error: ~p~n", [Reason])
end;
auth_username_cli(["del", Username]) ->
auth_username_cli(["delete", Username]);
auth_username_cli(["delete", Username]) ->
case remove_user({username, iolist_to_binary(Username)}) of
ok -> emqx_ctl:print("ok~n");
{error, Reason} -> emqx_ctl:print("Error: ~p~n", [Reason])
@ -185,4 +191,4 @@ auth_username_cli(_) ->
emqx_ctl:usage([{"user list", "List username auth rules"},
{"user add <Username> <Password>", "Add username auth rule"},
{"user update <Username> <NewPassword>", "Update username auth rule"},
{"user del <Username>", "Delete username auth rule"}]).
{"user delete <Username>", "Delete username auth rule"}]).

View File

@ -42,13 +42,13 @@ groups() ->
[].
init_per_suite(Config) ->
emqx_ct_helpers:start_apps([emqx_management, emqx_auth_mnesia], fun set_special_configs/1),
emqx_ct_helpers:start_apps([emqx_modules, emqx_management, emqx_auth_mnesia], fun set_special_configs/1),
create_default_app(),
Config.
end_per_suite(_Config) ->
delete_default_app(),
emqx_ct_helpers:stop_apps([emqx_management, emqx_auth_mnesia]).
emqx_ct_helpers:stop_apps([emqx_modules, emqx_management, emqx_auth_mnesia]).
init_per_testcase(t_check_acl_as_clientid, Config) ->
emqx:hook('client.check_acl', fun emqx_acl_mnesia:check_acl/5, [#{key_as => clientid}]),
@ -86,11 +86,15 @@ t_management(_Config) ->
ok = emqx_acl_mnesia_cli:add_acl({username, <<"test_username">>}, <<"topic/%u">>, sub, deny),
ok = emqx_acl_mnesia_cli:add_acl({username, <<"test_username">>}, <<"topic/+">>, pub, allow),
ok = emqx_acl_mnesia_cli:add_acl(all, <<"#">>, pubsub, deny),
%% Sleeps below are needed to hide the race condition between
%% mnesia and ets dirty select in check_acl, that make this test
%% flaky
timer:sleep(100),
?assertEqual(2, length(emqx_acl_mnesia_cli:lookup_acl({clientid, <<"test_clientid">>}))),
?assertEqual(2, length(emqx_acl_mnesia_cli:lookup_acl({username, <<"test_username">>}))),
?assertEqual(1, length(emqx_acl_mnesia_cli:lookup_acl(all))),
?assertEqual(5, length(emqx_acl_mnesia_cli:all_acls())),
?assertEqual(2, length(emqx_acl_mnesia_cli:lookup_acl(all))),
?assertEqual(6, length(emqx_acl_mnesia_cli:all_acls())),
User1 = #{zone => external, clientid => <<"test_clientid">>},
User2 = #{zone => external, clientid => <<"no_exist">>, username => <<"test_username">>},
@ -105,11 +109,55 @@ t_management(_Config) ->
deny = emqx_access_control:check_acl(User3, subscribe, <<"topic/A/B">>),
deny = emqx_access_control:check_acl(User3, publish, <<"topic/A/B">>),
%% Test merging of pubsub capability:
ok = emqx_acl_mnesia_cli:add_acl({clientid, <<"test_clientid">>}, <<"topic/mix">>, pubsub, deny),
timer:sleep(100),
deny = emqx_access_control:check_acl(User1, subscribe, <<"topic/mix">>),
deny = emqx_access_control:check_acl(User1, publish, <<"topic/mix">>),
ok = emqx_acl_mnesia_cli:add_acl({clientid, <<"test_clientid">>}, <<"topic/mix">>, pub, allow),
timer:sleep(100),
deny = emqx_access_control:check_acl(User1, subscribe, <<"topic/mix">>),
allow = emqx_access_control:check_acl(User1, publish, <<"topic/mix">>),
ok = emqx_acl_mnesia_cli:add_acl({clientid, <<"test_clientid">>}, <<"topic/mix">>, pubsub, allow),
timer:sleep(100),
allow = emqx_access_control:check_acl(User1, subscribe, <<"topic/mix">>),
allow = emqx_access_control:check_acl(User1, publish, <<"topic/mix">>),
ok = emqx_acl_mnesia_cli:add_acl({clientid, <<"test_clientid">>}, <<"topic/mix">>, sub, deny),
timer:sleep(100),
deny = emqx_access_control:check_acl(User1, subscribe, <<"topic/mix">>),
allow = emqx_access_control:check_acl(User1, publish, <<"topic/mix">>),
ok = emqx_acl_mnesia_cli:add_acl({clientid, <<"test_clientid">>}, <<"topic/mix">>, pub, deny),
timer:sleep(100),
deny = emqx_access_control:check_acl(User1, subscribe, <<"topic/mix">>),
deny = emqx_access_control:check_acl(User1, publish, <<"topic/mix">>),
%% Test implicit migration of pubsub to pub and sub:
ok = emqx_acl_mnesia_cli:remove_acl({clientid, <<"test_clientid">>}, <<"topic/mix">>),
ok = mnesia:dirty_write(#emqx_acl{
filter = {{clientid, <<"test_clientid">>}, <<"topic/mix">>},
action = pubsub,
access = allow,
created_at = erlang:system_time(millisecond)
}),
timer:sleep(100),
allow = emqx_access_control:check_acl(User1, subscribe, <<"topic/mix">>),
allow = emqx_access_control:check_acl(User1, publish, <<"topic/mix">>),
ok = emqx_acl_mnesia_cli:add_acl({clientid, <<"test_clientid">>}, <<"topic/mix">>, pub, deny),
timer:sleep(100),
allow = emqx_access_control:check_acl(User1, subscribe, <<"topic/mix">>),
deny = emqx_access_control:check_acl(User1, publish, <<"topic/mix">>),
ok = emqx_acl_mnesia_cli:add_acl({clientid, <<"test_clientid">>}, <<"topic/mix">>, sub, deny),
timer:sleep(100),
deny = emqx_access_control:check_acl(User1, subscribe, <<"topic/mix">>),
deny = emqx_access_control:check_acl(User1, publish, <<"topic/mix">>),
ok = emqx_acl_mnesia_cli:remove_acl({clientid, <<"test_clientid">>}, <<"topic/%c">>),
ok = emqx_acl_mnesia_cli:remove_acl({clientid, <<"test_clientid">>}, <<"topic/+">>),
ok = emqx_acl_mnesia_cli:remove_acl({clientid, <<"test_clientid">>}, <<"topic/mix">>),
ok = emqx_acl_mnesia_cli:remove_acl({username, <<"test_username">>}, <<"topic/%u">>),
ok = emqx_acl_mnesia_cli:remove_acl({username, <<"test_username">>}, <<"topic/+">>),
ok = emqx_acl_mnesia_cli:remove_acl(all, <<"#">>),
timer:sleep(100),
?assertEqual([], emqx_acl_mnesia_cli:all_acls()).
@ -124,6 +172,7 @@ t_acl_cli(_Config) ->
?assertEqual(0, length(emqx_acl_mnesia_cli:cli(["list"]))),
emqx_acl_mnesia_cli:cli(["add", "clientid", "test_clientid", "topic/A", "pub", "deny"]),
emqx_acl_mnesia_cli:cli(["add", "clientid", "test_clientid", "topic/A", "pub", "allow"]),
R1 = emqx_ctl:format("Acl(clientid = ~p topic = ~p action = ~p access = ~p)~n",
[<<"test_clientid">>, <<"topic/A">>, pub, allow]),
@ -136,11 +185,14 @@ t_acl_cli(_Config) ->
?assertEqual([R2], emqx_acl_mnesia_cli:cli(["show", "username", "test_username"])),
?assertEqual([R2], emqx_acl_mnesia_cli:cli(["list", "username"])),
emqx_acl_mnesia_cli:cli(["add", "_all", "#", "pub", "allow"]),
emqx_acl_mnesia_cli:cli(["add", "_all", "#", "pubsub", "deny"]),
?assertMatch(["Acl($all topic = <<\"#\">> action = pubsub access = deny)\n"],
emqx_acl_mnesia_cli:cli(["list", "_all"])
?assertMatch(["",
"Acl($all topic = <<\"#\">> action = pub access = deny)",
"Acl($all topic = <<\"#\">> action = sub access = deny)"],
lists:sort(string:split(emqx_acl_mnesia_cli:cli(["list", "_all"]), "\n", all))
),
?assertEqual(3, length(emqx_acl_mnesia_cli:cli(["list"]))),
?assertEqual(4, length(emqx_acl_mnesia_cli:cli(["list"]))),
emqx_acl_mnesia_cli:cli(["del", "clientid", "test_clientid", "topic/A"]),
emqx_acl_mnesia_cli:cli(["del", "username", "test_username", "topic/B"]),
@ -169,7 +221,7 @@ t_rest_api(_Config) ->
}],
{ok, _} = request_http_rest_add([], Params1),
{ok, Re1} = request_http_rest_list(["clientid", "test_clientid"]),
?assertMatch(3, length(get_http_data(Re1))),
?assertMatch(4, length(get_http_data(Re1))),
{ok, _} = request_http_rest_delete(["clientid", "test_clientid", "topic", "topic/A"]),
{ok, _} = request_http_rest_delete(["clientid", "test_clientid", "topic", "topic/B"]),
{ok, _} = request_http_rest_delete(["clientid", "test_clientid", "topic", "topic/C"]),
@ -193,7 +245,7 @@ t_rest_api(_Config) ->
}],
{ok, _} = request_http_rest_add([], Params2),
{ok, Re2} = request_http_rest_list(["username", "test_username"]),
?assertMatch(3, length(get_http_data(Re2))),
?assertMatch(4, length(get_http_data(Re2))),
{ok, _} = request_http_rest_delete(["username", "test_username", "topic", "topic/A"]),
{ok, _} = request_http_rest_delete(["username", "test_username", "topic", "topic/B"]),
{ok, _} = request_http_rest_delete(["username", "test_username", "topic", "topic/C"]),
@ -214,7 +266,7 @@ t_rest_api(_Config) ->
}],
{ok, _} = request_http_rest_add([], Params3),
{ok, Re3} = request_http_rest_list(["$all"]),
?assertMatch(3, length(get_http_data(Re3))),
?assertMatch(4, length(get_http_data(Re3))),
{ok, _} = request_http_rest_delete(["$all", "topic", "topic/A"]),
{ok, _} = request_http_rest_delete(["$all", "topic", "topic/B"]),
{ok, _} = request_http_rest_delete(["$all", "topic", "topic/C"]),

View File

@ -47,13 +47,13 @@ groups() ->
[].
init_per_suite(Config) ->
ok = emqx_ct_helpers:start_apps([emqx_management, emqx_auth_mnesia], fun set_special_configs/1),
ok = emqx_ct_helpers:start_apps([emqx_modules, emqx_management, emqx_auth_mnesia], fun set_special_configs/1),
create_default_app(),
Config.
end_per_suite(_Config) ->
delete_default_app(),
emqx_ct_helpers:stop_apps([emqx_management, emqx_auth_mnesia]).
emqx_ct_helpers:stop_apps([emqx_modules, emqx_management, emqx_auth_mnesia]).
init_per_testcase(t_check_as_clientid, Config) ->
Params = #{

View File

@ -70,6 +70,21 @@ auth.mongo.database = mqtt
## Value: File
## auth.mongo.ssl.cacertfile =
## In mode verify_none the default behavior is to allow all x509-path
## validation errors.
##
## Value: true | false
## auth.mongo.ssl.verify = false
## If not specified, the server's names returned in server's certificate is validated against
## what's provided `auth.mongo.server` config's host part.
## Setting to 'disable' will make EMQ X ignore unmatched server names.
## If set with a host name, the server's names returned in server's certificate is validated
## against this value.
##
## Value: String | disable
## auth.mongo.ssl.server_name_indication = disable
## MongoDB write mode.
##
## Value: unsafe | safe

View File

@ -62,6 +62,15 @@
{datatype, string}
]}.
{mapping, "auth.mongo.ssl.verify", "emqx_auth_mongo.server", [
{default, false},
{datatype, {enum, [true, false]}}
]}.
{mapping, "auth.mongo.ssl.server_name_indication", "emqx_auth_mongo.server", [
{datatype, string}
]}.
%% FIXME: compatible with 4.0-4.2 version format, plan to delete in 5.0
{mapping, "auth.mongo.ssl_opts.keyfile", "emqx_auth_mongo.server", [
{datatype, string}
@ -123,8 +132,17 @@
end,
Filter = fun(Opts) -> [{K, V} || {K, V} <- Opts, V =/= undefined] end,
SslOpts = fun(Prefix) ->
Filter([{keyfile, cuttlefish:conf_get(Prefix ++ ".keyfile", Conf, undefined)},
{certfile, cuttlefish:conf_get(Prefix ++ ".certfile", Conf, undefined)},
Verify = case cuttlefish:conf_get(Prefix ++ ".verify", Conf, false) of
true -> verify_peer;
flase -> verify_none
end,
Filter([{verify, Verify},
{server_name_indication, case cuttlefish:conf_get(Prefix ++ ".server_name_indication", Conf, undefined) of
"disable" -> disable;
SNI -> SNI
end},
{keyfile, cuttlefish:conf_get(Prefix ++ ".keyfile", Conf, undefined)},
{certfile, cuttlefish:conf_get(Prefix ++ ".certfile", Conf, undefined)},
{cacertfile, cuttlefish:conf_get(Prefix ++ ".cacertfile", Conf, undefined)}])
end,

View File

@ -50,23 +50,18 @@ all() ->
emqx_ct:all(?MODULE).
init_per_suite(Cfg) ->
emqx_ct_helpers:start_apps([emqx_modules, emqx_auth_mongo], fun set_special_confs/1),
emqx_modules:load_module(emqx_mod_acl_internal, false),
emqx_ct_helpers:start_apps([emqx_auth_mongo], fun set_special_confs/1),
init_mongo_data(),
Cfg.
end_per_suite(_Cfg) ->
deinit_mongo_data(),
emqx_ct_helpers:stop_apps([emqx_auth_mongo, emqx_modules]).
emqx_ct_helpers:stop_apps([emqx_auth_mongo]).
set_special_confs(emqx) ->
application:set_env(emqx, acl_nomatch, deny),
application:set_env(emqx, acl_file,
emqx_ct_helpers:deps_path(emqx, "test/emqx_SUITE_data/acl.conf")),
application:set_env(emqx, allow_anonymous, false),
application:set_env(emqx, enable_acl_cache, false),
application:set_env(emqx, plugins_loaded_file,
emqx_ct_helpers:deps_path(emqx, "test/emqx_SUITE_data/loaded_plugins"));
application:set_env(emqx, enable_acl_cache, false);
set_special_confs(_App) ->
ok.
@ -133,7 +128,7 @@ t_check_acl(_) ->
allow = emqx_access_control:check_acl(User2, subscribe, <<"$SYS/testuser/1">>),
allow = emqx_access_control:check_acl(User3, publish, <<"a/b/c">>),
deny = emqx_access_control:check_acl(User3, publish, <<"c">>),
allow = emqx_access_control:check_acl(User4, publish, <<"a/b/c">>).
deny = emqx_access_control:check_acl(User4, publish, <<"a/b/c">>).
t_acl_super(_) ->
reload({auth_query, [{password_hash, plain}, {password_field, [<<"password">>]}]}),

View File

@ -114,3 +114,18 @@ auth.mysql.acl_query = "select allow, ipaddr, username, clientid, access, topic
##
## Value: File
#auth.mysql.ssl.keyfile = /path/to/your/clientkey.pem
## In mode verify_none the default behavior is to allow all x509-path
## validation errors.
##
## Value: true | false
#auth.mysql.ssl.verify = false
## If not specified, the server's names returned in server's certificate is validated against
## what's provided `auth.mysql.server` config's host part.
## Setting to 'disable' will make EMQ X ignore unmatched server names.
## If set with a host name, the server's names returned in server's certificate is validated
## against this value.
##
## Value: String | disable
## auth.mysql.ssl.server_name_indication = disable

View File

@ -52,6 +52,15 @@
{datatype, string}
]}.
{mapping, "auth.mysql.ssl.verify", "emqx_auth_mysql.server", [
{default, false},
{datatype, {enum, [true, false]}}
]}.
{mapping, "auth.mysql.ssl.server_name_indication", "emqx_auth_mysql.server", [
{datatype, string}
]}.
{translation, "emqx_auth_mysql.server", fun(Conf) ->
{MyHost, MyPort} =
case cuttlefish:conf_get("auth.mysql.server", Conf) of
@ -94,10 +103,20 @@
),
Cert = cuttlefish:conf_get("auth.mysql.ssl.certfile", Conf, undefined),
Key = cuttlefish:conf_get("auth.mysql.ssl.keyfile", Conf, undefined),
Options ++ [{ssl, Filter([{server_name_indication, disable},
Verify = case cuttlefish:conf_get("auth.mysql.ssl.verify", Conf, false) of
true -> verify_peer;
flase -> verify_none
end,
SNI = case cuttlefish:conf_get("auth.mysql.ssl.server_name_indication", Conf, undefined) of
"disable" -> disable;
SNI0 -> SNI0
end,
Options ++ [{ssl, Filter([{server_name_indication, SNI},
{cacertfile, CA},
{certfile, Cert},
{keyfile, Key}])
{keyfile, Key},
{verify, Verify}
])
}];
_ ->
Options

View File

@ -62,6 +62,21 @@ auth.pgsql.ssl.enable = off
## Value: File
#auth.pgsql.ssl.cacertfile =
## In mode verify_none the default behavior is to allow all x509-path
## validation errors.
##
## Value: true | false
#auth.pgsql.ssl.verify = false
## If not specified, the server's names returned in server's certificate is validated against
## what's provided `auth.pgsql.server` config's host part.
## Setting to 'disable' will make EMQ X ignore unmatched server names.
## If set with a host name, the server's names returned in server's certificate is validated
## against this value.
##
## Value: String | disable
## auth.pgsql.ssl.server_name_indication = disable
## Authentication query.
##
## Value: SQL

View File

@ -52,6 +52,15 @@
{datatype, string}
]}.
{mapping, "auth.pgsql.ssl.verify", "emqx_auth_pgsql.server", [
{default, false},
{datatype, {enum, [true, false]}}
]}.
{mapping, "auth.pgsql.ssl.server_name_indication", "emqx_auth_pgsql.server", [
{datatype, string}
]}.
%% FIXME: compatible with 4.0-4.2 version format, plan to delete in 5.0
{mapping, "auth.pgsql.ssl_opts.keyfile", "emqx_auth_pgsql.server", [
{datatype, string}
@ -90,9 +99,18 @@
Filter = fun(Opts) -> [{K, V} || {K, V} <- Opts, V =/= undefined] end,
SslOpts = fun(Prefix) ->
Verify = case cuttlefish:conf_get(Prefix ++ ".verify", Conf, false) of
true -> verify_peer;
flase -> verify_none
end,
Filter([{keyfile, cuttlefish:conf_get(Prefix ++ ".keyfile", Conf, undefined)},
{certfile, cuttlefish:conf_get(Prefix ++ ".certfile", Conf, undefined)},
{cacertfile, cuttlefish:conf_get(Prefix ++ ".cacertfile", Conf, undefined)},
{verify, Verify},
{server_name_indication, case cuttlefish:conf_get(Prefix ++ ".server_name_indication", Conf, undefined) of
"disable" -> disable;
SNI -> SNI
end},
{versions, [list_to_existing_atom(Value)
|| Value <- string:tokens(cuttlefish:conf_get(Prefix ++ ".tls_versions", Conf), " ,")]}])
end,

View File

@ -70,7 +70,7 @@ all() ->
emqx_ct:all(?MODULE).
init_per_suite(Config) ->
emqx_ct_helpers:start_apps([emqx_modules, emqx_auth_pgsql]),
emqx_ct_helpers:start_apps([emqx_auth_pgsql]),
drop_acl(),
drop_auth(),
init_auth(),
@ -79,7 +79,7 @@ init_per_suite(Config) ->
Config.
end_per_suite(Config) ->
emqx_ct_helpers:stop_apps([emqx_auth_pgsql, emqx_modules]),
emqx_ct_helpers:stop_apps([emqx_auth_pgsql]),
Config.
set_special_configs() ->
@ -161,7 +161,6 @@ t_check_auth(_) ->
{error, not_authorized} = emqx_access_control:authenticate(Bcrypt#{password => <<"password">>}).
t_check_acl(_) ->
emqx_modules:load_module(emqx_mod_acl_internal, false),
User1 = #{zone => external, peerhost => {127,0,0,1}, clientid => <<"c1">>, username => <<"u1">>},
User2 = #{zone => external, peerhost => {127,0,0,1}, clientid => <<"c2">>, username => <<"u2">>},
allow = emqx_access_control:check_acl(User1, subscribe, <<"t1">>),
@ -170,8 +169,8 @@ t_check_acl(_) ->
User4 = #{zone => external, peerhost => {10,10,10,110}, clientid => <<"c1">>, username => <<"u1">>},
allow = emqx_access_control:check_acl(User3, subscribe, <<"t1">>),
allow = emqx_access_control:check_acl(User3, subscribe, <<"t1">>),
allow = emqx_access_control:check_acl(User3, subscribe, <<"t2">>),%% nomatch -> ignore -> emqttd acl
allow = emqx_access_control:check_acl(User4, subscribe, <<"t1">>),%% nomatch -> ignore -> emqttd acl
deny = emqx_access_control:check_acl(User3, subscribe, <<"t2">>),%% nomatch -> ignore -> emqx acl
deny = emqx_access_control:check_acl(User4, subscribe, <<"t1">>),%% nomatch -> ignore -> emqx acl
User5 = #{zone => external, peerhost => {127,0,0,1}, clientid => <<"c3">>, username => <<"u3">>},
allow = emqx_access_control:check_acl(User5, subscribe, <<"t1">>),
allow = emqx_access_control:check_acl(User5, publish, <<"t1">>).

View File

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA0kGUBi9NDp65jgdxKfizIfuSr2wpwb44yM9SuP4oUQSULOA2
4iFpLR/c5FAYHU81y9Vx91dQjdZfffaBZuv2zVvteXUkol8Nez7boKbo2E41MTew
8edtNKZAQVvnaHAC2NCZxjchCzUCDEoUUcl+cIERZ8R48FBqK5iTVcMRIx1akwus
+dhBqP0ykA5TGOWZkJrLM9aUXSPQha9+wXlOpkvu0Ur2nkX8PPJnifWao9UShSar
ll1IqPZNCSlZMwcFYcQNBCpdvITUUYlHvMRQV64bUpOxUGDuJkQL3dLKBlNuBRlJ
BcjBAKw7rFnwwHZcMmQ9tan/dZzpzwjo/T0XjwIDAQABAoIBAQCSHvUqnzDkWjcG
l/Fzg92qXlYBCCC0/ugj1sHcwvVt6Mq5rVE3MpUPwTcYjPlVVTlD4aEEjm/zQuq2
ddxUlOS+r4aIhHrjRT/vSS4FpjnoKeIZxGR6maVxk6DQS3i1QjMYT1CvSpzyVvKH
a+xXMrtmoKxh+085ZAmFJtIuJhUA2yEa4zggCxWnvz8ecLClUPfVDPhdLBHc3KmL
CRpHEC6L/wanvDPRdkkzfKyaJuIJlTDaCg63AY5sDkTW2I57iI/nJ3haSeidfQKz
39EfbnM1A/YprIakafjAu3frBIsjBVcxwGihZmL/YriTHjOggJF841kT5zFkkv2L
/530Wk6xAoGBAOqZLZ4DIi/zLndEOz1mRbUfjc7GQUdYplBnBwJ22VdS0P4TOXnd
UbJth2MA92NM7ocTYVFl4TVIZY/Y+Prxk7KQdHWzR7JPpKfx9OEVgtSqV0vF9eGI
rKp79Y1T4Mvc3UcQCXX6TP7nHLihEzpS8odm2LW4txrOiLsn4Fq/IWrLAoGBAOVv
6U4tm3lImotUupKLZPKEBYwruo9qRysoug9FiorP4TjaBVOfltiiHbAQD6aGfVtN
SZpZZtrs17wL7Xl4db5asgMcZd+8Hkfo5siR7AuGW9FZloOjDcXb5wCh9EvjJ74J
Cjw7RqyVymq9t7IP6wnVwj5Ck48YhlOZCz/mzlnNAoGAWq7NYFgLvgc9feLFF23S
IjpJQZWHJEITP98jaYNxbfzYRm49+GphqxwFinKULjFNvq7yHlnIXSVYBOu1CqOZ
GRwXuGuNmlKI7lZr9xmukfAqgGLMMdr4C4qRF4lFyufcLRz42z7exmWlx4ST/yaT
E13hBRWayeTuG5JFei6Jh1MCgYEAqmX4LyC+JFBgvvQZcLboLRkSCa18bADxhENG
FAuAvmFvksqRRC71WETmqZj0Fqgxt7pp3KFjO1rFSprNLvbg85PmO1s+6fCLyLpX
lESTu2d5D71qhK93jigooxalGitFm+SY3mzjq0/AOpBWOn+J/w7rqVPGxXLgaHv0
l+vx+00CgYBOvo9/ImjwYii2jFl+sHEoCzlvpITi2temRlT2j6ulSjCLJgjwEFw9
8e+vvfQumQOsutakUVyURrkMGNDiNlIv8kv5YLCCkrwN22E6Ghyi69MJUvHQXkc/
QZhjn/luyfpB5f/BeHFS2bkkxAXo+cfG45ApY3Qfz6/7o+H+vDa6/A==
-----END RSA PRIVATE KEY-----

View File

@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDAzCCAeugAwIBAgIBATANBgkqhkiG9w0BAQsFADA8MTowOAYDVQQDDDFNeVNR
TF9TZXJ2ZXJfOC4wLjE5X0F1dG9fR2VuZXJhdGVkX0NBX0NlcnRpZmljYXRlMB4X
DTIwMDYxMTAzMzg0NloXDTMwMDYwOTAzMzg0NlowPDE6MDgGA1UEAwwxTXlTUUxf
U2VydmVyXzguMC4xOV9BdXRvX0dlbmVyYXRlZF9DQV9DZXJ0aWZpY2F0ZTCCASIw
DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANJBlAYvTQ6euY4HcSn4syH7kq9s
KcG+OMjPUrj+KFEElCzgNuIhaS0f3ORQGB1PNcvVcfdXUI3WX332gWbr9s1b7Xl1
JKJfDXs+26Cm6NhONTE3sPHnbTSmQEFb52hwAtjQmcY3IQs1AgxKFFHJfnCBEWfE
ePBQaiuYk1XDESMdWpMLrPnYQaj9MpAOUxjlmZCayzPWlF0j0IWvfsF5TqZL7tFK
9p5F/DzyZ4n1mqPVEoUmq5ZdSKj2TQkpWTMHBWHEDQQqXbyE1FGJR7zEUFeuG1KT
sVBg7iZEC93SygZTbgUZSQXIwQCsO6xZ8MB2XDJkPbWp/3Wc6c8I6P09F48CAwEA
AaMQMA4wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEADKz6bIpP5anp
GgLB0jkclRWuMlS4qqIt4itSsMXPJ/ezpHwECixmgW2TIQl6S1woRkUeMxhT2/Ay
Sn/7aKxuzRagyE5NEGOvrOuAP5RO2ZdNJ/X3/Rh533fK1sOTEEbSsWUvW6iSkZef
rsfZBVP32xBhRWkKRdLeLB4W99ADMa0IrTmZPCXHSSE2V4e1o6zWLXcOZeH1Qh8N
SkelBweR+8r1Fbvy1r3s7eH7DCbYoGEDVLQGOLvzHKBisQHmoDnnF5E9g1eeNRdg
o+vhOKfYCOzeNREJIqS42PHcGhdNRk90ycigPmfUJclz1mDHoMjKR2S5oosTpr65
tNPx3CL7GA==
-----END CERTIFICATE-----

View File

@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDBDCCAeygAwIBAgIBAzANBgkqhkiG9w0BAQsFADA8MTowOAYDVQQDDDFNeVNR
TF9TZXJ2ZXJfOC4wLjE5X0F1dG9fR2VuZXJhdGVkX0NBX0NlcnRpZmljYXRlMB4X
DTIwMDYxMTAzMzg0N1oXDTMwMDYwOTAzMzg0N1owQDE+MDwGA1UEAww1TXlTUUxf
U2VydmVyXzguMC4xOV9BdXRvX0dlbmVyYXRlZF9DbGllbnRfQ2VydGlmaWNhdGUw
ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDVYSWpOvCTupz82fc85Opv
EQ7rkB8X2oOMyBCpkyHKBIr1ZQgRDWBp9UVOASq3GnSElm6+T3Kb1QbOffa8GIlw
sjAueKdq5L2eSkmPIEQ7eoO5kEW+4V866hE1LeL/PmHg2lGP0iqZiJYtElhHNQO8
3y9I7cm3xWMAA3SSWikVtpJRn3qIp2QSrH+tK+/HHbE5QwtPxdir4ULSCSOaM5Yh
Wi5Oto88TZqe1v7SXC864JVvO4LuS7TuSreCdWZyPXTJFBFeCEWSAxonKZrqHbBe
CwKML6/0NuzjaQ51c2tzmVI6xpHj3nnu4cSRx6Jf9WBm+35vm0wk4pohX3ptdzeV
AgMBAAGjDTALMAkGA1UdEwQCMAAwDQYJKoZIhvcNAQELBQADggEBAByQ5zSNeFUH
Aw7JlpZHtHaSEeiiyBHke20ziQ07BK1yi/ms2HAWwQkpZv149sjNuIRH8pkTmkZn
g8PDzSefjLbC9AsWpWV0XNV22T/cdobqLqMBDDZ2+5bsV+jTrOigWd9/AHVZ93PP
IJN8HJn6rtvo2l1bh/CdsX14uVSdofXnuWGabNTydqtMvmCerZsdf6qKqLL+PYwm
RDpgWiRUY7KPBSSlKm/9lJzA+bOe4dHeJzxWFVCJcbpoiTFs1je1V8kKQaHtuW39
ifX6LTKUMlwEECCbDKM8Yq2tm8NjkjCcnFDtKg8zKGPUu+jrFMN5otiC3wnKcP7r
O9EkaPcgYH8=
-----END CERTIFICATE-----

View File

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA1WElqTrwk7qc/Nn3POTqbxEO65AfF9qDjMgQqZMhygSK9WUI
EQ1gafVFTgEqtxp0hJZuvk9ym9UGzn32vBiJcLIwLninauS9nkpJjyBEO3qDuZBF
vuFfOuoRNS3i/z5h4NpRj9IqmYiWLRJYRzUDvN8vSO3Jt8VjAAN0klopFbaSUZ96
iKdkEqx/rSvvxx2xOUMLT8XYq+FC0gkjmjOWIVouTraPPE2antb+0lwvOuCVbzuC
7ku07kq3gnVmcj10yRQRXghFkgMaJyma6h2wXgsCjC+v9Dbs42kOdXNrc5lSOsaR
49557uHEkceiX/VgZvt+b5tMJOKaIV96bXc3lQIDAQABAoIBAF7yjXmSOn7h6P0y
WCuGiTLG2mbDiLJqj2LTm2Z5i+2Cu/qZ7E76Ls63TxF4v3MemH5vGfQhEhR5ZD/6
GRJ1sKKvB3WGRqjwA9gtojHH39S/nWGy6vYW/vMOOH37XyjIr3EIdIaUtFQBTSHd
Kd71niYrAbVn6fyWHolhADwnVmTMOl5OOAhCdEF4GN3b5aIhIu8BJ7EUzTtHBJIj
CAEfjZFjDs1y1cIgGFJkuIQxMfCpq5recU2qwip7YO6fk//WEjOPu7kSf5IEswL8
jg1dea9rGBV6KaD2xsgsC6Ll6Sb4BbsrHMfflG3K2Lk3RdVqqTFp1Fn1PTLQE/1S
S/SZPYECgYEA9qYcHKHd0+Q5Ty5wgpxKGa4UCWkpwvfvyv4bh8qlmxueB+l2AIdo
ZvkM8gTPagPQ3WypAyC2b9iQu70uOJo1NizTtKnpjDdN1YpDjISJuS/P0x73gZwy
gmoM5AzMtN4D6IbxXtXnPaYICvwLKU80ouEN5ZPM4/ODLUu6gsp0v2UCgYEA3Xgi
zMC4JF0vEKEaK0H6QstaoXUmw/lToZGH3TEojBIkb/2LrHUclygtONh9kJSFb89/
jbmRRLAOrx3HZKCNGUmF4H9k5OQyAIv6OGBinvLGqcbqnyNlI+Le8zxySYwKMlEj
EMrBCLmSyi0CGFrbZ3mlj/oCET/ql9rNvcK+DHECgYAEx5dH3sMjtgp+RFId1dWB
xePRgt4yTwewkVgLO5wV82UOljGZNQaK6Eyd7AXw8f38LHzh+KJQbIvxd2sL4cEi
OaAoohpKg0/Y0YMZl//rPMf0OWdmdZZs/I0fZjgZUSwWN3c59T8z7KG/RL8an9RP
S7kvN7wCttdV61/D5RR6GQKBgDxCe/WKWpBKaovzydMLWLTj7/0Oi0W3iXHkzzr4
LTgvl4qBSofaNbVLUUKuZTv5rXUG2IYPf99YqCYtzBstNDc1MiAriaBeFtzfOW4t
i6gEFtoLLbuvPc3N5Sv5vn8Ug5G9UfU3td5R4AbyyCcoUZqOFuZd+EIJSiOXfXOs
kVmBAoGBAIU9aPAqhU5LX902oq8KsrpdySONqv5mtoStvl3wo95WIqXNEsFY60wO
q02jKQmJJ2MqhkJm2EoF2Mq8+40EZ5sz8LdgeQ/M0yQ9lAhPi4rftwhpe55Ma9dk
SE9X1c/DMCBEaIjJqVXdy0/EeArwpb8sHkguVVAZUWxzD+phm1gs
-----END RSA PRIVATE KEY-----

View File

@ -1,21 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIDYzCCAksCCQC7J1oPkDz7vTANBgkqhkiG9w0BAQUFADCBhTELMAkGA1UEBhMC
Q0ExGTAXBgNVBAgMEEJyaXRpc2ggQ29sdW1iaWExDjAMBgNVBAcMBUNvbW94MRQw
EgYDVQQKDAtUaGVCcmFpbi5jYTEUMBIGA1UEAwwLdGhlYnJhaW4uY2ExHzAdBgkq
hkiG9w0BCQEWEGluZm9AdGhlYnJhaW4uY2EwHhcNMjEwMTEzMDkwNzM2WhcNMjEw
MjEyMDkwNzM2WjBhMQswCQYDVQQGEwJDQTEZMBcGA1UECAwQQnJpdGlzaCBDb2x1
bWJpYTEOMAwGA1UEBwwFQ29tb3gxFDASBgNVBAoMC1RoZUJyYWluLmNhMREwDwYD
VQQDDAh3d3ctZGF0YTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJv9
yO5JGKBl+7w0HGkRDIPZ5Ku3lIAzB4ThszRHBqll7VjlTz+q16OQOONqeHBuxPjj
11WMXD2KnfYZW2ZWd0U8FKzuIGOCStGbSUi2hC0owp+KkJcDujfIafXQnAa0fUiS
FBB5iG98vm3QI4gv9135LgnO5oHopH6oZ/t0Id1LzFhp2sdhebdtczmImpo+nt7v
fduapptuIJ20ThdAvo3MlYoAhivsvJKntlWPAwPMQdyezww/q7T5Y8DCyJJTydr5
PrMz9S/WQTkj/G0y4dZgQonG5r0d1Nf+rwkn78DdXGktVDMBBP41+VWnEDBCTlgS
FjQEY6Izaof8s8q8K2UCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAdlAQkumOAKbQ
SW5gtkHgKyIQyfwk9maKqKccK04WlNk1t1jsvk7kaOEHr3t7YG28yKqicGHAcfFf
i/RU51v2GJVzWCbzkAAH/zNgDcYnYk6sn54YcuBzrPliVH1xxmZy/52+huTxy8Vd
3nmCjdYR/I764rd8gkRK+aHaUTLyitzX1kW90LtXonKY72CNZVXHEBom3XM/a6ff
ilybDloNVTfHstnfsnHHyNYn0SfapqXxPCO+FL9hQjlztUBZryRdS0nq66hB2GSB
CEst/vtNGo/2aa1Vw4bKl2oGepjKNzxp0ZTTVuIcwGzV6oKIsx1ZnWE3gQLEH/TX
dzMzesBayA==
-----END CERTIFICATE-----

View File

@ -1,17 +0,0 @@
-----BEGIN CERTIFICATE REQUEST-----
MIICpjCCAY4CAQAwYTELMAkGA1UEBhMCQ0ExGTAXBgNVBAgMEEJyaXRpc2ggQ29s
dW1iaWExDjAMBgNVBAcMBUNvbW94MRQwEgYDVQQKDAtUaGVCcmFpbi5jYTERMA8G
A1UEAwwId3d3LWRhdGEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCb
/cjuSRigZfu8NBxpEQyD2eSrt5SAMweE4bM0RwapZe1Y5U8/qtejkDjjanhwbsT4
49dVjFw9ip32GVtmVndFPBSs7iBjgkrRm0lItoQtKMKfipCXA7o3yGn10JwGtH1I
khQQeYhvfL5t0COIL/dd+S4JzuaB6KR+qGf7dCHdS8xYadrHYXm3bXM5iJqaPp7e
733bmqabbiCdtE4XQL6NzJWKAIYr7LySp7ZVjwMDzEHcns8MP6u0+WPAwsiSU8na
+T6zM/Uv1kE5I/xtMuHWYEKJxua9HdTX/q8JJ+/A3VxpLVQzAQT+NflVpxAwQk5Y
EhY0BGOiM2qH/LPKvCtlAgMBAAGgADANBgkqhkiG9w0BAQsFAAOCAQEAN6Q8MEDx
g5xlpYB/fFmagpe15+G2QbqVf2mH1a4aBcBns4jMMqNidi4gyjGfzvNxX77R6KcI
AfcxENRVDYJbhAgEQ96jv4jv5pEMuyvQ8VLhn9AOXCaK/VHxbYlOiM7tfFtEDrrB
wTn8FvoEwjehfsSX2dWiwcUK4SPPeuklE/EGjRgoVCwg8EqWzf1fn+tzME8OpnRQ
I8coyALF6ANehvP7ADV3m5iOOaNhfnqmqGBEwjB3TTvE1gZ4UvAyl75bi+Zh3Osn
qemyxocp/ML4o6d/F+nKIZOe6309V2nyrY6RSd2fBCrhYj2rKTbrGTZrpKXeAhtI
jMivnjCK+WNHpQ==
-----END CERTIFICATE REQUEST-----

View File

@ -1,27 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAm/3I7kkYoGX7vDQcaREMg9nkq7eUgDMHhOGzNEcGqWXtWOVP
P6rXo5A442p4cG7E+OPXVYxcPYqd9hlbZlZ3RTwUrO4gY4JK0ZtJSLaELSjCn4qQ
lwO6N8hp9dCcBrR9SJIUEHmIb3y+bdAjiC/3XfkuCc7mgeikfqhn+3Qh3UvMWGna
x2F5t21zOYiamj6e3u9925qmm24gnbROF0C+jcyVigCGK+y8kqe2VY8DA8xB3J7P
DD+rtPljwMLIklPJ2vk+szP1L9ZBOSP8bTLh1mBCicbmvR3U1/6vCSfvwN1caS1U
MwEE/jX5VacQMEJOWBIWNARjojNqh/yzyrwrZQIDAQABAoIBAAOicycSLu+10Jq/
ABZ2njsIPaq+mUgvaDJxa9KBASe7Rz92AFW0blfSSXELDwlXm2FNNbw5jACnFS0h
xB5rT1Yeo0CwP7Lx2zptCtUV45iFxZsgCGRsYs9f7RAcLzZ8yBqDxNHpcwNd/bXj
TqCitXnMD4WM+5P1TrfgxqN2Pj/Atg8w/4dP7KcFcTzcZzIz5rr3NTyjsrLdiFis
sR+7m7Qu4PyEfrDpR9Np111nQqVJ1bpt9qt/hv318FaBnpNY6MMBaSni99mvMXSd
SwHn3gnfHREWcNSLGA9gjEQmyIPHpV9T6SJ/zyr++6y8QCq4DiSP36A9zeA1XThP
YEIsWxUCgYEAyLppQerpOT2CnbTbKO/9rGwlbf8FT2GWFcPBtUm0lp21/C32BX+H
jNCmQsE1pZ6+sqv2mb1onr6Xl9cSEt6KsI1EJtFFR9Lnvqqu+JKo31U94z2yTqgv
sc+qMl7shy1kja8T5NaRc++UkCVzVNsnFB9torIaqQwY9IRdRwmYjisCgYEAxvHR
MwvWpOg25zz75OfupIOQhj9W6yphpY5/yoYBms/4OeabJhMrOV142s9souCHmuGU
EtzOQC5jbEc+3MUjx1ZlboHY7UuoEu87kykFEs9mnaD+T34PEAJcQjSzqzS5KMJE
Ro275xf+V/e3hS/Z3hQXmDQNQDNRYMcAZfTW9K8CgYBkHITOuYikYcc5PLBplHhi
fHWWjLBrTPJ73GxKLH6C+BmBsrKXP2mtk4q4lIBbH/dgSV/ugYciVVBqDHwZKSDm
uS4aZhk1nzyx3ZLyqsLK0ErTgTvi+wL+neH2yV0SdlNGTuGPKmzU89KWqfcBhWPS
J3KYyFd/pGb13OZgvap2jQKBgBXCXR84LEHdJCQmh2aB95gGy8fjJZ6TBBsXeuKr
xYEpPf0XO+DuN8wObSmBhmBKLorCIW/utqBOcpFlOXrsFP24dV+g1BkgLUHk6J8v
3V4xUQfsk+Qd5YfaujyDhyMyoQ3UMaOF3QdpmGgGsAvhL/MaP3pmNwzOkBgFrAV6
wggBAoGBAMflqy2pfqGhaj9S6qZ3K95h7NdCUikdQzqmgbNtOHaZ2kHByyYtOPLB
1VnuDRQiacmum+fTZa6wNmvp2FWg+uxI/aspfF6SdPfGpyPrG5D+ITtqKF2xieK+
XpzehKTrTuYQRAVhmWbhpuyahYnQyd/MrsCMGzUfAJtM7l5vKa2O
-----END RSA PRIVATE KEY-----

View File

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA1zVmMhPqpSPMmYkKh5wwlRD5XuS8YWJKEM6tjFx61VK8qxHE
YngkC2KnL5EuKAjQZIF3tJskwt0hAat047CCCZxrkNEpbVvSnvnk+A/8bg/Ww1n3
qxzfifhsWfpUKlDnwrtH+ftt+5rZeEkf37XAPy7ZjzecAF9SDV6WSiPeAxUX2+hN
dId42Pf45woo4LFGUlQeagCFkD/R0dpNIMGwcnkKCUikiBqr2ijSIgvRtBfZ9fBG
jFGER2uE/Eay4AgcQsHue8skRwDCng8OnqtPnBtTytmqTy9V/BRgsVKUoksm6wsx
kUYwgHeaq7UCvlCm25SZ7yRyd4k8t0BKDf2h+wIDAQABAoIBAEQcrHmRACTADdNS
IjkFYALt2l8EOfMAbryfDSJtapr1kqz59JPNvmq0EIHnixo0n/APYdmReLML1ZR3
tYkSpjVwgkLVUC1CcIjMQoGYXaZf8PLnGJHZk45RR8m6hsTV0mQ5bfBaeVa2jbma
OzJMjcnxg/3l9cPQZ2G/3AUfEPccMxOXp1KRz3mUQcGnKJGtDbN/kfmntcwYoxaE
Zg4RoeKAoMpK1SSHAiJKe7TnztINJ7uygR9XSzNd6auY8A3vomSIjpYO7XL+lh7L
izm4Ir3Gb/eCYBvWgQyQa2KCJgK/sQyEs3a09ngofSEUhQJQYhgZDwUj+fDDOGqj
hCZOA8ECgYEA+ZWuHdcUQ3ygYhLds2QcogUlIsx7C8n/Gk/FUrqqXJrTkuO0Eqqa
B47lCITvmn2zm0ODfSFIARgKEUEDLS/biZYv7SUTrFqBLcet+aGI7Dpv91CgB75R
tNzcIf8VxoiP0jPqdbh9mLbbxGi5Uc4p9TVXRljC4hkswaouebWee0sCgYEA3L2E
YB3kiHrhPI9LHS5Px9C1w+NOu5wP5snxrDGEgaFCvL6zgY6PflacppgnmTXl8D1x
im0IDKSw5dP3FFonSVXReq3CXDql7UnhfTCiLDahV7bLxTH42FofcBpDN3ERdOal
58RwQh6VrLkzQRVoObo+hbGlFiwwSAfQC509FhECgYBsRSBpVXo25IN2yBRg09cP
+gdoFyhxrsj5kw1YnB13WrrZh+oABv4WtUhp77E5ZbpaamlKCPwBbXpAjeFg4tfr
0bksuN7V79UGFQ9FsWuCfr8/nDwv38H2IbFlFhFONMOfPmJBey0Q6JJhm8R41mSh
OOiJXcv85UrjIH5U0hLUDQKBgQDVLOU5WcUJlPoOXSgiT0ZW5xWSzuOLRUUKEf6l
19BqzAzCcLy0orOrRAPW01xylt2v6/bJw1Ahva7k1ZZo/kOwjANYoZPxM+ZoSZBN
MXl8j2mzZuJVV1RFxItV3NcLJNPB/Lk+IbRz9kt/2f9InF7iWR3mSU/wIM6j0X+2
p6yFsQKBgQCM/ldWb511lA+SNkqXB2P6WXAgAM/7+jwsNHX2ia2Ikufm4SUEKMSv
mti/nZkHDHsrHU4wb/2cOAywMELzv9EHzdcoenjBQP65OAc/1qWJs+LnBcCXfqKk
aHjEZW6+brkHdRGLLY3YAHlt/AUL+RsKPJfN72i/FSpmu+52G36eeQ==
-----END RSA PRIVATE KEY-----

View File

@ -0,0 +1,9 @@
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1zVmMhPqpSPMmYkKh5ww
lRD5XuS8YWJKEM6tjFx61VK8qxHEYngkC2KnL5EuKAjQZIF3tJskwt0hAat047CC
CZxrkNEpbVvSnvnk+A/8bg/Ww1n3qxzfifhsWfpUKlDnwrtH+ftt+5rZeEkf37XA
Py7ZjzecAF9SDV6WSiPeAxUX2+hNdId42Pf45woo4LFGUlQeagCFkD/R0dpNIMGw
cnkKCUikiBqr2ijSIgvRtBfZ9fBGjFGER2uE/Eay4AgcQsHue8skRwDCng8OnqtP
nBtTytmqTy9V/BRgsVKUoksm6wsxkUYwgHeaq7UCvlCm25SZ7yRyd4k8t0BKDf2h
+wIDAQAB
-----END PUBLIC KEY-----

View File

@ -1,21 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIDiDCCAnACCQCCsPcIlZO4TDANBgkqhkiG9w0BAQsFADCBhTELMAkGA1UEBhMC
Q0ExGTAXBgNVBAgMEEJyaXRpc2ggQ29sdW1iaWExDjAMBgNVBAcMBUNvbW94MRQw
EgYDVQQKDAtUaGVCcmFpbi5jYTEUMBIGA1UEAwwLdGhlYnJhaW4uY2ExHzAdBgkq
hkiG9w0BCQEWEGluZm9AdGhlYnJhaW4uY2EwHhcNMjEwMTEzMDkwNDIyWhcNMzEw
MTExMDkwNDIyWjCBhTELMAkGA1UEBhMCQ0ExGTAXBgNVBAgMEEJyaXRpc2ggQ29s
dW1iaWExDjAMBgNVBAcMBUNvbW94MRQwEgYDVQQKDAtUaGVCcmFpbi5jYTEUMBIG
A1UEAwwLdGhlYnJhaW4uY2ExHzAdBgkqhkiG9w0BCQEWEGluZm9AdGhlYnJhaW4u
Y2EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2YWuwplM2Hc5tzBMu
covW9nwZ8iNEFo5pbDc8710pmnkF+wsDztLy4afJe6OeVHyCgQxmE+rTZcoWbvoh
pxW3Zy/8es4My07RKHqI3NYadThUvDsmI10cF3tJbhOZaIrMaExLGookZYKwbNAy
7yJ1+MLyNCuFFsaOiNNxHOjH/InKSzEuGSLV68tdC7Pe+uanBcC7RKhOrjUC6Occ
naHPC+a/YMyRYx29T8CfkCBB7N6WanWylFN/1RBmAgq++kDflSaF9k+Zdl6I4jiF
mCPGS0k+AMre4PuAKOZOZOwhF0sWlXIxH6zPm9w0bSYdTLBupL846RTO72NtNP+X
KX5DAgMBAAEwDQYJKoZIhvcNAQELBQADggEBACXXFws+h+Zo9HsxW3BWpl2JU5u6
KyfbLQt4kSN/gqltd4s84Q8c4z2jNdI0t8Oh5dXTjbLCpFjzuF2tdMtOWeYBCdsQ
4NJ69RrwkFdsSPxDPhSE0WGXPaOBaA92wJjTkVf+UYIek1ozeyWwFm1LPiZVei00
mwDVgbAbIEb8cf6OqJrl2r5PMBCLWBwwg5aca3fe6TopJhyPA//DZDRPA5xzKb9e
PHUgF3apbcWxuxm8Mts4bAq8BcKoEvLHYWJ4fEWQvXPP7q1jYC3TkpSt5n3FQZTe
nLyQ+RNzsEHzmyOtTSa0Q+5KVluO1TE3ifpv8737pTLdY8t2waBamoboCu8=
-----END CERTIFICATE-----

View File

@ -1 +0,0 @@
BB275A0F903CFBBD

View File

@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDBDCCAeygAwIBAgIBAjANBgkqhkiG9w0BAQsFADA8MTowOAYDVQQDDDFNeVNR
TF9TZXJ2ZXJfOC4wLjE5X0F1dG9fR2VuZXJhdGVkX0NBX0NlcnRpZmljYXRlMB4X
DTIwMDYxMTAzMzg0NloXDTMwMDYwOTAzMzg0NlowQDE+MDwGA1UEAww1TXlTUUxf
U2VydmVyXzguMC4xOV9BdXRvX0dlbmVyYXRlZF9TZXJ2ZXJfQ2VydGlmaWNhdGUw
ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCcEnEm5hqP1EbEJycOz8Ua
NWp29QdpFUzTWhkKGhVXk+0msmNTw4NBAFB42moY44OU8wvDideOlJNhPRWveD8z
G2lxzJA91p0UK4et8ia9MmeuCGhdC9jxJ8X69WNlUiPyy0hI/ZsqRq9Z0C2eW0iL
JPXsy4X8Xpw3SFwoXf5pR9RFY5Pb2tuyxqmSestu2VXT/NQjJg4CVDR3mFcHPXZB
4elRzH0WshExEGkgy0bg20MJeRc2Qdb5Xx+EakbmwroDWaCn3NSGqQ7jv6Vw0doy
TGvS6h6RHBxnyqRfRgKGlCoOMG9/5+rFJC00QpCUG2vHXHWGoWlMlJ3foN7rj5v9
AgMBAAGjDTALMAkGA1UdEwQCMAAwDQYJKoZIhvcNAQELBQADggEBAJ5zt2rj4Ag6
zpN59AWC1Fur8g8l41ksHkSpKPp+PtyO/ngvbMqBpfmK1e7JCKZv/68QXfMyWWAI
hwalqZkXXWHKjuz3wE7dE25PXFXtGJtcZAaj10xt98fzdqt8lQSwh2kbfNwZIz1F
sgAStgE7+ZTcqTgvNB76Os1UK0to+/P0VBWktaVFdyub4Nc2SdPVnZNvrRBXBwOD
3V8ViwywDOFoE7DvCvwx/SVsvoC0Z4j3AMMovO6oHicP7uU83qsQgm1Qru3YeoLR
+DoVi7IPHbWvN7MqFYn3YjNlByO2geblY7MR0BlqbFlmFrqLsUfjsh2ys7/U/knC
dN/klu446fI=
-----END CERTIFICATE-----

View File

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAnBJxJuYaj9RGxCcnDs/FGjVqdvUHaRVM01oZChoVV5PtJrJj
U8ODQQBQeNpqGOODlPMLw4nXjpSTYT0Vr3g/MxtpccyQPdadFCuHrfImvTJnrgho
XQvY8SfF+vVjZVIj8stISP2bKkavWdAtnltIiyT17MuF/F6cN0hcKF3+aUfURWOT
29rbssapknrLbtlV0/zUIyYOAlQ0d5hXBz12QeHpUcx9FrIRMRBpIMtG4NtDCXkX
NkHW+V8fhGpG5sK6A1mgp9zUhqkO47+lcNHaMkxr0uoekRwcZ8qkX0YChpQqDjBv
f+fqxSQtNEKQlBtrx1x1hqFpTJSd36De64+b/QIDAQABAoIBAFiah66Dt9SruLkn
WR8piUaFyLlcBib8Nq9OWSTJBhDAJERxxb4KIvvGB+l0ZgNXNp5bFPSfzsZdRwZP
PX5uj8Kd71Dxx3mz211WESMJdEC42u+MSmN4lGLkJ5t/sDwXU91E1vbJM0ve8THV
4/Ag9qA4DX2vVZOeyqT/6YHpSsPNZplqzrbAiwrfHwkctHfgqwOf3QLfhmVQgfCS
VwidBldEUv2whSIiIxh4Rv5St4kA68IBCbJxdpOpyuQBkk6CkxZ7VN9FqOuSd4Pk
Wm7iWyBMZsCmELZh5XAXld4BEt87C5R4CvbPBDZxAv3THk1DNNvpy3PFQfwARRFb
SAToYMECgYEAyL7U8yxpzHDYWd3oCx6vTi9p9N/z0FfAkWrRF6dm4UcSklNiT1Aq
EOnTA+SaW8tV3E64gCWcY23gNP8so/ZseWj6L+peHwtchaP9+KB7yGw2A+05+lOx
VetLTjAOmfpiUXFe5w1q4C1RGhLjZjjzW+GvwdAuchQgUEFaomrV+PUCgYEAxwfH
cmVGFbAktcjU4HSRjKSfawCrut+3YUOLybyku3Q/hP9amG8qkVTFe95CTLjLe2D0
ccaTTpofFEJ32COeck0g0Ujn/qQ+KXRoauOYs4FB1DtqMpqB78wufWEUpDpbd9/h
J+gJdC/IADd4tJW9zA92g8IA7ZtFmqDtiSpQ0ekCgYAQGkaorvJZpN+l7cf0RGTZ
h7IfI2vCVZer0n6tQA9fmLzjoe6r4AlPzAHSOR8sp9XeUy43kUzHKQQoHCPvjw/K
eWJAP7OHF/k2+x2fOPhU7mEy1W+mJdp+wt4Kio5RSaVjVQ3AyPG+w8PSrJszEvRq
dWMMz+851WV2KpfjmWBKlQKBgQC++4j4DZQV5aMkSKV1CIZOBf3vaIJhXKEUFQPD
PmB4fBEjpwCg+zNGp6iktt65zi17o8qMjrb1mtCt2SY04eD932LZUHNFlwcLMmes
Ad+aiDLJ24WJL1f16eDGcOyktlblDZB5gZ/ovJzXEGOkLXglosTfo77OQculmDy2
/UL2WQKBgGeKasmGNfiYAcWio+KXgFkHXWtAXB9B91B1OFnCa40wx+qnl71MIWQH
PQ/CZFNWOfGiNEJIZjrHsfNJoeXkhq48oKcT0AVCDYyLV0VxDO4ejT95mGW6njNd
JpvmhwwAjOvuWVr0tn4iXlSK8irjlJHmwcRjLTJq97vE9fsA2MjI
-----END RSA PRIVATE KEY-----

View File

@ -1,21 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIDiDCCAnACCQCCsPcIlZO4TDANBgkqhkiG9w0BAQsFADCBhTELMAkGA1UEBhMC
Q0ExGTAXBgNVBAgMEEJyaXRpc2ggQ29sdW1iaWExDjAMBgNVBAcMBUNvbW94MRQw
EgYDVQQKDAtUaGVCcmFpbi5jYTEUMBIGA1UEAwwLdGhlYnJhaW4uY2ExHzAdBgkq
hkiG9w0BCQEWEGluZm9AdGhlYnJhaW4uY2EwHhcNMjEwMTEzMDkwNDIyWhcNMzEw
MTExMDkwNDIyWjCBhTELMAkGA1UEBhMCQ0ExGTAXBgNVBAgMEEJyaXRpc2ggQ29s
dW1iaWExDjAMBgNVBAcMBUNvbW94MRQwEgYDVQQKDAtUaGVCcmFpbi5jYTEUMBIG
A1UEAwwLdGhlYnJhaW4uY2ExHzAdBgkqhkiG9w0BCQEWEGluZm9AdGhlYnJhaW4u
Y2EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2YWuwplM2Hc5tzBMu
covW9nwZ8iNEFo5pbDc8710pmnkF+wsDztLy4afJe6OeVHyCgQxmE+rTZcoWbvoh
pxW3Zy/8es4My07RKHqI3NYadThUvDsmI10cF3tJbhOZaIrMaExLGookZYKwbNAy
7yJ1+MLyNCuFFsaOiNNxHOjH/InKSzEuGSLV68tdC7Pe+uanBcC7RKhOrjUC6Occ
naHPC+a/YMyRYx29T8CfkCBB7N6WanWylFN/1RBmAgq++kDflSaF9k+Zdl6I4jiF
mCPGS0k+AMre4PuAKOZOZOwhF0sWlXIxH6zPm9w0bSYdTLBupL846RTO72NtNP+X
KX5DAgMBAAEwDQYJKoZIhvcNAQELBQADggEBACXXFws+h+Zo9HsxW3BWpl2JU5u6
KyfbLQt4kSN/gqltd4s84Q8c4z2jNdI0t8Oh5dXTjbLCpFjzuF2tdMtOWeYBCdsQ
4NJ69RrwkFdsSPxDPhSE0WGXPaOBaA92wJjTkVf+UYIek1ozeyWwFm1LPiZVei00
mwDVgbAbIEb8cf6OqJrl2r5PMBCLWBwwg5aca3fe6TopJhyPA//DZDRPA5xzKb9e
PHUgF3apbcWxuxm8Mts4bAq8BcKoEvLHYWJ4fEWQvXPP7q1jYC3TkpSt5n3FQZTe
nLyQ+RNzsEHzmyOtTSa0Q+5KVluO1TE3ifpv8737pTLdY8t2waBamoboCu8=
-----END CERTIFICATE-----

View File

@ -1,27 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAtmFrsKZTNh3ObcwTLnKL1vZ8GfIjRBaOaWw3PO9dKZp5BfsL
A87S8uGnyXujnlR8goEMZhPq02XKFm76IacVt2cv/HrODMtO0Sh6iNzWGnU4VLw7
JiNdHBd7SW4TmWiKzGhMSxqKJGWCsGzQMu8idfjC8jQrhRbGjojTcRzox/yJyksx
Lhki1evLXQuz3vrmpwXAu0SoTq41AujnHJ2hzwvmv2DMkWMdvU/An5AgQezelmp1
spRTf9UQZgIKvvpA35UmhfZPmXZeiOI4hZgjxktJPgDK3uD7gCjmTmTsIRdLFpVy
MR+sz5vcNG0mHUywbqS/OOkUzu9jbTT/lyl+QwIDAQABAoIBAA6UVR6G/UnrMhBW
6wWghItHov4T/Du6LeJBk1zcqa7kuV4ABo5kXzqpTVdu+dJzYIyyMkKKvw/tKC2I
65f7GmJR7mUZkBU3v3I68Si1tqvgyQMFFRlkZFIVknZ5RTnTQJ08jTTHx1lHgB4I
ZNBdi3ywySzBfOUjv/Wu/HAjZnxuEh2guBpRMZdwQwZLXr2koDa5inL3IwJrA4Ir
QzpZ0y6ql3A0tw7jAw36G1AKyyz74aFwJ0I8U8w+2Uk4iX5hcKGA8mFq4lyO4/3+
7W2Z4V8cQzwMq2SMixI0Omxlc2BJUi9j17Ey//5dAXyPaG8QI1kzeL/3Gbs8YBMq
ekN8AZECgYEA5YxcFIVv3yO+ARNWUHovrsMuf9ElhyRuZd0I2+vjrq1b9zQsSy2d
PsyYWD17lO/GDmpTzZOdVsYtZHi+EiXmQnkzLJ4m2nlc7W4annWlbzlQMEn6vAji
l9bSHJXXiiIB7X/oHpDUdsnJp/uyAJppmnVLbSBboNCrG4Mf5cJqOnsCgYEAy2We
scp19h4UEKAU0Yh+5jh8W4VVtlISkH64vMgz/JZWXMPt1bM5C/5j+3UVUL5VmFqF
J1g0gXYkTGTL0+entb3SUiL42zrp3rZ3GgMU6V+aktq3dmri5bOifzihuLHLgjO5
u/MJPBzvFxIiJxnNBybNLijIZfPm+9roUfpcBNkCgYBGE3Zc0WuYnEm5/FRCVzrN
SEqevJOPUSDeuf6lXLryLXxA2E2ZWcCCVmU/su1SR2yYI/+XZ7QFtJRQ8sdbtPQ5
YNStj05fLeOfnBhGPbYWYVHInB0OYEwEfJFCJsBZLA6YmY6cHiyuYuXMAXuS0ZDh
lWNEWjd+vZUu3fXT52kUlwKBgDgq/eH3GRA4Si41JsqeOPz2iFD1xy+sBnhkpjtr
xf9wvLStXpZvAcfwHkgokxRTG2wRQ0gUMZu2tltqUmdYR5YGr3gDNFnGMSNRnB5Q
z4uK3TLEt3k6FyJ7stoTF4Xbg2mXQylF+jzheJ0UYt4NX/MjofGnTX/qFNVkJFfP
HW4xAoGBAMBb9cXTpzOMiMcSdQRlaLttV1p05pqxTgQNEQD8HB+lkx4AGnnHvtxW
XQJvPumtqdCEpfe4kaqLip8T+67sGfcDVQMogJc/tpvZ0AN4FuViFsf/YDuTPXEp
whMldPHtusbRP2fk/JFq4Ak0Xz2wAI1iMD3qfBeW6eJpvRllUo69
-----END RSA PRIVATE KEY-----

View File

@ -115,3 +115,17 @@ auth.redis.acl_cmd = "HGETALL mqtt_acl:%u"
## Value: File
# auth.redis.ssl.keyfile = path/to/your/keyfile
## In mode verify_none the default behavior is to allow all x509-path
## validation errors.
##
## Value: true | false
#auth.redis.ssl.verify = false
## If not specified, the server's names returned in server's certificate is validated against
## what's provided `auth.redis.server` config's host part.
## Setting to 'disable' will make EMQ X ignore unmatched server names.
## If set with a host name, the server's names returned in server's certificate is validated
## against this value.
##
## Value: String | disable
## auth.redis.ssl.server_name_indication = disable

View File

@ -50,6 +50,30 @@
{datatype, string}
]}.
{mapping, "auth.redis.ssl.verify", "emqx_auth_redis.options", [
{default, false},
{datatype, {enum, [true, false]}}
]}.
{mapping, "auth.redis.ssl.server_name_indication", "emqx_auth_redis.options", [
{datatype, string}
]}.
%% FIXME: compatible with 4.0-4.2 version format, plan to delete in 5.0
{mapping, "auth.redis.cafile", "emqx_auth_redis.options", [
{datatype, string}
]}.
%% FIXME: compatible with 4.0-4.2 version format, plan to delete in 5.0
{mapping, "auth.redis.certfile", "emqx_auth_redis.options", [
{datatype, string}
]}.
%% FIXME: compatible with 4.0-4.2 version format, plan to delete in 5.0
{mapping, "auth.redis.keyfile", "emqx_auth_redis.options", [
{datatype, string}
]}.
{translation, "emqx_auth_redis.options", fun(Conf) ->
Ssl = cuttlefish:conf_get("auth.redis.ssl.enable", Conf, false),
Filter = fun(Opts) -> [{K, V} || {K, V} <- Opts, V =/= undefined] end,
@ -58,7 +82,7 @@
%% FIXME: compatible with 4.0-4.2 version format, plan to delete in 5.0
CA = cuttlefish:conf_get(
"auth.redis.ssl.cacertfile", Conf,
cuttlefish:conf_get("auth.redis.cacertfile", Conf, undefined)
cuttlefish:conf_get("auth.redis.cafile", Conf, undefined)
),
Cert = cuttlefish:conf_get(
"auth.redis.ssl.certfile", Conf,
@ -68,10 +92,21 @@
"auth.redis.ssl.keyfile", Conf,
cuttlefish:conf_get("auth.redis.keyfile", Conf, undefined)
),
Verify = case cuttlefish:conf_get("auth.redis.ssl.verify", Conf, false) of
true -> verify_peer;
flase -> verify_none
end,
SNI = case cuttlefish:conf_get("auth.redis.ssl.server_name_indication", Conf, undefined) of
"disable" -> disable;
SNI0 -> SNI0
end,
[{options, [{ssl_options,
Filter([{cacertfile, CA},
{certfile, Cert},
{keyfile, Key}])
{keyfile, Key},
{verify, Verify},
{server_name_indication, SNI}
])
}]}];
_ -> [{options, []}]
end

View File

@ -49,22 +49,18 @@ all() ->
emqx_ct:all(?MODULE).
init_per_suite(Cfg) ->
emqx_ct_helpers:start_apps([emqx_modules, emqx_auth_redis], fun set_special_configs/1),
emqx_ct_helpers:start_apps([emqx_auth_redis], fun set_special_configs/1),
init_redis_rows(),
Cfg.
end_per_suite(_Cfg) ->
deinit_redis_rows(),
emqx_ct_helpers:stop_apps([emqx_auth_redis, emqx_modules]).
emqx_ct_helpers:stop_apps([emqx_auth_redis]).
set_special_configs(emqx) ->
application:set_env(emqx, allow_anonymous, false),
application:set_env(emqx, acl_nomatch, deny),
application:set_env(emqx, acl_file,
emqx_ct_helpers:deps_path(emqx, "test/emqx_SUITE_data/acl.conf")),
application:set_env(emqx, enable_acl_cache, false),
application:set_env(emqx, plugins_loaded_file,
emqx_ct_helpers:deps_path(emqx, "test/emqx_SUITE_data/loaded_plugins"));
application:set_env(emqx, enable_acl_cache, false);
set_special_configs(_App) ->
ok.
@ -72,7 +68,6 @@ init_redis_rows() ->
%% Users
[q(["HMSET", Key|FiledValue]) || {Key, FiledValue} <- ?INIT_AUTH],
%% ACLs
emqx_modules:load_module(emqx_mod_acl_internal, false),
Result = [q(["HSET", Key, Filed, Value]) || {Key, Filed, Value} <- ?INIT_ACL],
ct:pal("redis init result: ~p~n", [Result]).
@ -136,7 +131,7 @@ t_check_acl(_) ->
allow = emqx_access_control:check_acl(User2, subscribe, <<"topic2">>),
allow = emqx_access_control:check_acl(User3, publish, <<"topic3">>),
allow = emqx_access_control:check_acl(User3, subscribe, <<"topic3">>),
allow = emqx_access_control:check_acl(User4, publish, <<"a/b/c">>).
deny = emqx_access_control:check_acl(User4, publish, <<"a/b/c">>).
t_acl_super(_) ->
reload([{password_hash, plain}]),

View File

@ -567,8 +567,7 @@ options(Options, PoolName, ResId) ->
maybe_ssl(_Options, false, _ResId) ->
[];
maybe_ssl(Options, true, ResId) ->
Dir = filename:join([emqx:get_env(data_dir), "rule", ResId]),
[{ssl, true}, {ssl_opts, emqx_plugin_libs_ssl:save_files_return_opts(Options, Dir)}].
[{ssl, true}, {ssl_opts, emqx_plugin_libs_ssl:save_files_return_opts(Options, "rules", ResId)}].
mqtt_ver(ProtoVer) ->
case ProtoVer of

View File

@ -151,8 +151,9 @@ To subscribe any topic, issue following command:
- if clientid is absent, a "bad_request" will be returned.
- {topicname} in URI should be percent-encoded to prevent special characters, such as + and #.
- {username} and {password} are optional.
- if {username} and {password} are not correct, an uauthorized error will be returned.
- if {username} or {password} is incorrect, the error code `uauthorized` will be returned.
- topic is subscribed with qos1.
- if the subscription failed due to ACL deny, the error code `forbidden` will be returned.
CoAP Client Unobserve Operation (unsubscribe topic)
---------------------------------------------------
@ -168,7 +169,7 @@ To cancel observation, issue following command:
- if clientid is absent, a "bad_request" will be returned.
- {topicname} in URI should be percent-encoded to prevent special characters, such as + and #.
- {username} and {password} are optional.
- if {username} and {password} are not correct, an uauthorized error will be returned.
- if {username} or {password} is incorrect, the error code `uauthorized` will be returned.
CoAP Client Notification Operation (subscribed Message)
-------------------------------------------------------
@ -179,7 +180,7 @@ Server will issue an observe-notification as a subscribed message.
CoAP Client Publish Operation
-----------------------------
Issue a coap put command to do publishment. For example:
Issue a coap put command to publish messages. For example:
```
PUT coap://localhost/mqtt/{topicname}?c={clientid}&u={username}&p={password}
@ -191,10 +192,11 @@ Issue a coap put command to do publishment. For example:
- if clientid is absent, a "bad_request" will be returned.
- {topicname} in URI should be percent-encoded to prevent special characters, such as + and #.
- {username} and {password} are optional.
- if {username} and {password} are not correct, an uauthorized error will be returned.
- if {username} or {password} is incorrect, the error code `uauthorized` will be returned.
- payload could be any binary data.
- payload data type is "application/octet-stream".
- publish message will be sent with qos0.
- if the publishing failed due to ACL deny, the error code `forbidden` will be returned.
CoAP Client Keep Alive
----------------------
@ -209,7 +211,7 @@ Device should issue a get command periodically, serve as a ping to keep mqtt ses
- {any_topicname} is optional, and should be percent-encoded to prevent special characters.
- {clientid} is mandatory. If clientid is absent, a "bad_request" will be returned.
- {username} and {password} are optional.
- if {username} and {password} are not correct, an uauthorized error will be returned.
- if {username} or {password} is incorrect, the error code `uauthorized` will be returned.
- coap client should do keepalive work periodically to keep mqtt session online, especially those devices in a NAT network.

View File

@ -2,7 +2,7 @@
- Enhance all test case
2. Remove the mqtt adaptor
3. Remove the emqx_coap_ps_topics.erl
3. Remove the emqx_coap_pubsub_topics.erl
### Problems

View File

@ -29,12 +29,12 @@
start(_Type, _Args) ->
{ok, Sup} = emqx_coap_sup:start_link(),
coap_server_registry:add_handler([<<"mqtt">>], emqx_coap_resource, undefined),
coap_server_registry:add_handler([<<"ps">>], emqx_coap_ps_resource, undefined),
_ = emqx_coap_ps_topics:start_link(),
coap_server_registry:add_handler([<<"ps">>], emqx_coap_pubsub_resource, undefined),
_ = emqx_coap_pubsub_topics:start_link(),
emqx_coap_server:start(application:get_all_env(?APP)),
{ok,Sup}.
stop(_State) ->
coap_server_registry:remove_handler([<<"mqtt">>], emqx_coap_resource, undefined),
coap_server_registry:remove_handler([<<"ps">>], emqx_coap_ps_resource, undefined),
coap_server_registry:remove_handler([<<"ps">>], emqx_coap_pubsub_resource, undefined),
emqx_coap_server:stop(application:get_all_env(?APP)).

View File

@ -133,8 +133,8 @@ init({ClientId, Username, Password, Channel}) ->
handle_call({subscribe, Topic, CoapPid}, _From, State=#state{sub_topics = TopicList}) ->
NewTopics = proplists:delete(Topic, TopicList),
IsWild = emqx_topic:wildcard(Topic),
chann_subscribe(Topic, State),
{reply, ok, State#state{sub_topics = [{Topic, {IsWild, CoapPid}}|NewTopics]}, hibernate};
{reply, chann_subscribe(Topic, State), State#state{sub_topics =
[{Topic, {IsWild, CoapPid}}|NewTopics]}, hibernate};
handle_call({unsubscribe, Topic, _CoapPid}, _From, State=#state{sub_topics = TopicList}) ->
NewTopics = proplists:delete(Topic, TopicList),
@ -142,8 +142,7 @@ handle_call({unsubscribe, Topic, _CoapPid}, _From, State=#state{sub_topics = Top
{reply, ok, State#state{sub_topics = NewTopics}, hibernate};
handle_call({publish, Topic, Payload}, _From, State) ->
_ = chann_publish(Topic, Payload, State),
{reply, ok, State};
{reply, chann_publish(Topic, Payload, State), State};
handle_call(info, _From, State) ->
{reply, info(State), State};
@ -221,10 +220,12 @@ chann_subscribe(Topic, State = #state{clientid = ClientId}) ->
case emqx_access_control:check_acl(clientinfo(State), subscribe, Topic) of
allow ->
emqx_broker:subscribe(Topic, ClientId, ?SUBOPTS),
emqx_hooks:run('session.subscribed', [clientinfo(State), Topic, ?SUBOPTS]);
emqx_hooks:run('session.subscribed', [clientinfo(State), Topic, ?SUBOPTS]),
ok;
deny ->
?LOG(warning, "subscribe to ~p by clientid ~p failed due to acl check.",
[Topic, ClientId])
[Topic, ClientId]),
{error, forbidden}
end.
chann_unsubscribe(Topic, State) ->
@ -237,12 +238,14 @@ chann_publish(Topic, Payload, State = #state{clientid = ClientId}) ->
?LOG(debug, "publish Topic=~p, Payload=~p", [Topic, Payload]),
case emqx_access_control:check_acl(clientinfo(State), publish, Topic) of
allow ->
emqx_broker:publish(
emqx_message:set_flag(retain, false,
emqx_message:make(ClientId, ?QOS_0, Topic, Payload)));
_ = emqx_broker:publish(
emqx_message:set_flag(retain, false,
emqx_message:make(ClientId, ?QOS_0, Topic, Payload))),
ok;
deny ->
?LOG(warning, "publish to ~p by clientid ~p failed due to acl check.",
[Topic, ClientId])
[Topic, ClientId]),
{error, forbidden}
end.

Some files were not shown because too many files have changed in this diff Show More