Selaa lähdekoodia

Merge branch 'master' into release-v515-patch1-20230809

Thales Macedo Garitezi 2 vuotta sitten
vanhempi
commit
cce0d144f9

+ 5 - 8
.github/workflows/_push-entrypoint.yaml

@@ -23,7 +23,6 @@ jobs:
     container: 'ghcr.io/emqx/emqx-builder/5.1-3:1.14.5-25.3.2-1-ubuntu22.04'
     container: 'ghcr.io/emqx/emqx-builder/5.1-3:1.14.5-25.3.2-1-ubuntu22.04'
     outputs:
     outputs:
       profile: ${{ steps.parse-git-ref.outputs.profile }}
       profile: ${{ steps.parse-git-ref.outputs.profile }}
-      edition: ${{ steps.parse-git-ref.outputs.edition }}
       release: ${{ steps.parse-git-ref.outputs.release }}
       release: ${{ steps.parse-git-ref.outputs.release }}
       latest: ${{ steps.parse-git-ref.outputs.latest }}
       latest: ${{ steps.parse-git-ref.outputs.latest }}
       version: ${{ steps.parse-git-ref.outputs.version }}
       version: ${{ steps.parse-git-ref.outputs.version }}
@@ -50,12 +49,10 @@ jobs:
         run: |
         run: |
           JSON="$(./scripts/parse-git-ref.sh $GITHUB_REF)"
           JSON="$(./scripts/parse-git-ref.sh $GITHUB_REF)"
           PROFILE=$(echo "$JSON" | jq -cr '.profile')
           PROFILE=$(echo "$JSON" | jq -cr '.profile')
-          EDITION=$(echo "$JSON" | jq -cr '.edition')
           RELEASE=$(echo "$JSON" | jq -cr '.release')
           RELEASE=$(echo "$JSON" | jq -cr '.release')
           LATEST=$(echo "$JSON"  | jq -cr '.latest')
           LATEST=$(echo "$JSON"  | jq -cr '.latest')
           VERSION="$(./pkg-vsn.sh "$PROFILE")"
           VERSION="$(./pkg-vsn.sh "$PROFILE")"
           echo "profile=$PROFILE" | tee -a $GITHUB_OUTPUT
           echo "profile=$PROFILE" | tee -a $GITHUB_OUTPUT
-          echo "edition=$EDITION" | tee -a $GITHUB_OUTPUT
           echo "release=$RELEASE" | tee -a $GITHUB_OUTPUT
           echo "release=$RELEASE" | tee -a $GITHUB_OUTPUT
           echo "latest=$LATEST"   | tee -a $GITHUB_OUTPUT
           echo "latest=$LATEST"   | tee -a $GITHUB_OUTPUT
           echo "version=$VERSION" | tee -a $GITHUB_OUTPUT
           echo "version=$VERSION" | tee -a $GITHUB_OUTPUT
@@ -107,8 +104,9 @@ jobs:
       publish: ${{ needs.prepare.outputs.release }}
       publish: ${{ needs.prepare.outputs.release }}
       otp_vsn: ${{ needs.prepare.outputs.otp_vsn }}
       otp_vsn: ${{ needs.prepare.outputs.otp_vsn }}
       elixir_vsn: ${{ needs.prepare.outputs.elixir_vsn }}
       elixir_vsn: ${{ needs.prepare.outputs.elixir_vsn }}
-      runner: ${{ needs.prepare.outputs.runner }}
       builder_vsn: ${{ needs.prepare.outputs.builder_vsn }}
       builder_vsn: ${{ needs.prepare.outputs.builder_vsn }}
+      runner: ${{ needs.prepare.outputs.runner }}
+    secrets: inherit
 
 
   build_and_push_docker_images:
   build_and_push_docker_images:
     if: ${{ needs.prepare.outputs.release == 'true' }}
     if: ${{ needs.prepare.outputs.release == 'true' }}
@@ -117,14 +115,14 @@ jobs:
     uses: ./.github/workflows/build_and_push_docker_images.yaml
     uses: ./.github/workflows/build_and_push_docker_images.yaml
     with:
     with:
       profile: ${{ needs.prepare.outputs.profile }}
       profile: ${{ needs.prepare.outputs.profile }}
-      edition: ${{ needs.prepare.outputs.edition }}
       version: ${{ needs.prepare.outputs.version }}
       version: ${{ needs.prepare.outputs.version }}
-      latest: ${{ needs.prepare.outputs.latest }}
       publish: ${{ needs.prepare.outputs.release }}
       publish: ${{ needs.prepare.outputs.release }}
+      latest: ${{ needs.prepare.outputs.latest }}
       otp_vsn: ${{ needs.prepare.outputs.otp_vsn }}
       otp_vsn: ${{ needs.prepare.outputs.otp_vsn }}
       elixir_vsn: ${{ needs.prepare.outputs.elixir_vsn }}
       elixir_vsn: ${{ needs.prepare.outputs.elixir_vsn }}
-      runner: ${{ needs.prepare.outputs.runner }}
       builder_vsn: ${{ needs.prepare.outputs.builder_vsn }}
       builder_vsn: ${{ needs.prepare.outputs.builder_vsn }}
+      runner: ${{ needs.prepare.outputs.runner }}
+    secrets: inherit
 
 
   compile:
   compile:
     runs-on: ${{ needs.prepare.outputs.runner }}
     runs-on: ${{ needs.prepare.outputs.runner }}
@@ -188,4 +186,3 @@ jobs:
       runner: ${{ needs.prepare.outputs.runner }}
       runner: ${{ needs.prepare.outputs.runner }}
       builder: ${{ needs.prepare.outputs.builder }}
       builder: ${{ needs.prepare.outputs.builder }}
       ct-matrix: ${{ needs.prepare.outputs.ct-matrix }}
       ct-matrix: ${{ needs.prepare.outputs.ct-matrix }}
-

+ 34 - 74
.github/workflows/build_and_push_docker_images.yaml

@@ -10,9 +10,6 @@ on:
       profile:
       profile:
         required: true
         required: true
         type: string
         type: string
-      edition:
-        required: true
-        type: string
       version:
       version:
         required: true
         required: true
         type: string
         type: string
@@ -28,27 +25,31 @@ on:
       elixir_vsn:
       elixir_vsn:
         required: true
         required: true
         type: string
         type: string
-      runner:
+      builder_vsn:
         required: true
         required: true
         type: string
         type: string
-      builder_vsn:
+      runner:
         required: true
         required: true
         type: string
         type: string
+    secrets:
+      DOCKER_HUB_USER:
+        required: true
+      DOCKER_HUB_TOKEN:
+        required: true
+      AWS_ACCESS_KEY_ID:
+        required: true
+      AWS_SECRET_ACCESS_KEY:
+        required: true
   workflow_dispatch:
   workflow_dispatch:
     inputs:
     inputs:
       ref:
       ref:
         required: false
         required: false
-      version:
-        required: true
-        type: string
       profile:
       profile:
         required: false
         required: false
         type: string
         type: string
         default: 'emqx'
         default: 'emqx'
-      edition:
-        required: false
-        type: string
-        default: 'Opensource'
+      version:
+        required: true
       latest:
       latest:
         required: false
         required: false
         type: boolean
         type: boolean
@@ -65,14 +66,14 @@ on:
         required: false
         required: false
         type: string
         type: string
         default: '1.14.5'
         default: '1.14.5'
-      runner:
-        required: false
-        type: string
-        default: 'ubuntu-22.04'
       builder_vsn:
       builder_vsn:
         required: false
         required: false
         type: string
         type: string
         default: '5.1-3'
         default: '5.1-3'
+      runner:
+        required: false
+        type: string
+        default: 'ubuntu-22.04'
 
 
 jobs:
 jobs:
   docker:
   docker:
@@ -83,18 +84,10 @@ jobs:
       matrix:
       matrix:
         profile:
         profile:
           - ${{ inputs.profile }}
           - ${{ inputs.profile }}
+          - ${{ inputs.profile }}-elixir
         registry:
         registry:
           - 'docker.io'
           - 'docker.io'
           - 'public.ecr.aws'
           - 'public.ecr.aws'
-        os:
-          - [debian11, "debian:11-slim", "deploy/docker/Dockerfile"]
-        builder:
-          - ${{ inputs.builder_vsn }}
-        otp:
-          - ${{ inputs.otp_vsn }}
-        elixir:
-          - 'no_elixir'
-          - ${{ inputs.elixir_vsn }}
 
 
     steps:
     steps:
     - uses: actions/checkout@v3
     - uses: actions/checkout@v3
@@ -121,53 +114,20 @@ jobs:
         password: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
         password: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
         ecr: true
         ecr: true
 
 
-    - name: prepare for docker/metadata-action
-      id: pre-meta
-      shell: bash
+    - name: Build docker image
+      env:
+        PROFILE: ${{ matrix.profile }}
+        DOCKER_REGISTRY: ${{ matrix.registry }}
+        DOCKER_ORG: ${{ github.repository_owner }}
+        DOCKER_LATEST: ${{ inputs.latest }}
+        DOCKER_PUSH: ${{ inputs.publish == 'true' || inputs.publish || github.repository_owner != 'emqx' }}
+        DOCKER_BUILD_NOCACHE: true
+        DOCKER_PLATFORMS: linux/amd64,linux/arm64
+        EMQX_RUNNER: 'debian:11-slim'
+        EMQX_DOCKERFILE: 'deploy/docker/Dockerfile'
+        PKG_VSN: ${{ inputs.version }}
+        EMQX_BUILDER_VSN: ${{ inputs.builder_vsn }}
+        EMQX_OTP_VSN: ${{ inputs.otp_vsn }}
+        EMQX_ELIXIR_VSN: ${{ inputs.elixir_vsn }}
       run: |
       run: |
-        extra_labels=
-        img_suffix=
-        if [ "${{ matrix.elixir }}" != 'no_elixir' ]; then
-          img_suffix="-elixir"
-          extra_labels="org.opencontainers.image.elixir.version=${{ matrix.elixir }}"
-        fi
-        extra_deps=
-        if [[ "${{ matrix.profile }}" = *enterprise* ]]; then
-          extra_deps='libsasl2-2,libsasl2-modules-gssapi-mit'
-        fi
-
-        echo "img_suffix=$img_suffix" >> $GITHUB_OUTPUT
-        echo "extra_labels=$extra_labels" >> $GITHUB_OUTPUT
-        echo "extra_deps=$extra_deps" >> $GITHUB_OUTPUT
-
-    - uses: docker/metadata-action@v4
-      id: meta
-      with:
-        images: |
-          ${{ matrix.registry }}/${{ github.repository_owner }}/${{ matrix.profile }}
-        flavor: |
-          latest=${{ matrix.elixir == 'no_elixir'  }}
-          suffix=${{ steps.pre-meta.outputs.img_suffix }}
-        tags: |
-          type=semver,pattern={{major}}.{{minor}},value=${{ inputs.version }}
-          type=semver,pattern={{version}},value=${{ inputs.version }}
-          type=raw,value=${{ inputs.version }}
-          type=raw,value=latest,enable=${{ inputs.latest }}
-        labels: |
-          org.opencontainers.image.otp.version=${{ matrix.otp }}
-          org.opencontainers.image.edition=${{ inputs.edition }}
-          ${{ steps.pre-meta.outputs.extra_labels }}
-
-    - uses: docker/build-push-action@v3
-      with:
-        push: ${{ inputs.publish == 'true' || github.repository_owner != 'emqx' }}
-        pull: true
-        no-cache: true
-        platforms: linux/amd64,linux/arm64
-        tags: ${{ steps.meta.outputs.tags }}
-        labels: ${{ steps.meta.outputs.labels }}
-        build-args: |
-          EMQX_NAME=${{ matrix.profile }}${{ steps.pre-meta.outputs.img_suffix }}
-          EXTRA_DEPS=${{ steps.pre-meta.outputs.extra_deps }}
-        file: source/${{ matrix.os[2] }}
-
+        ./build ${PROFILE} docker

+ 21 - 2
.github/workflows/build_packages.yaml

@@ -25,6 +25,25 @@ on:
       builder_vsn:
       builder_vsn:
         required: true
         required: true
         type: string
         type: string
+    secrets:
+      AWS_ACCESS_KEY_ID:
+        required: true
+      AWS_SECRET_ACCESS_KEY:
+        required: true
+      AWS_DEFAULT_REGION:
+        required: true
+      AWS_S3_BUCKET:
+        required: true
+      AWS_CLOUDFRONT_ID:
+        required: true
+      APPLE_ID_PASSWORD:
+        required: true
+      APPLE_DEVELOPER_IDENTITY:
+        required: true
+      APPLE_DEVELOPER_ID_BUNDLE:
+        required: true
+      APPLE_DEVELOPER_ID_BUNDLE_PASSWORD:
+        required: true
   workflow_dispatch:
   workflow_dispatch:
     inputs:
     inputs:
       ref:
       ref:
@@ -249,7 +268,7 @@ jobs:
     needs:
     needs:
       - mac
       - mac
       - linux
       - linux
-    if: ${{ inputs.publish == 'true' }}
+    if: inputs.publish == 'true' || inputs.publish
     strategy:
     strategy:
       fail-fast: false
       fail-fast: false
       matrix:
       matrix:
@@ -261,7 +280,7 @@ jobs:
         name: ${{ matrix.profile }}
         name: ${{ matrix.profile }}
         path: packages/${{ matrix.profile }}
         path: packages/${{ matrix.profile }}
     - name: install dos2unix
     - name: install dos2unix
-      run: sudo apt-get update && sudo apt install -y dos2unix
+      run: apt-get update && apt install -y dos2unix
     - name: get packages
     - name: get packages
       run: |
       run: |
         set -eu
         set -eu

+ 18 - 5
apps/emqx/src/emqx_calendar.erl

@@ -158,9 +158,9 @@ offset_second_(Offset) when is_list(Offset) ->
             _ ->
             _ ->
                 error({bad_time_offset, Offset})
                 error({bad_time_offset, Offset})
         end,
         end,
-    Hour = list_to_int_or_error(HourStr, {bad_time_offset_hour, HourStr}),
-    Minute = list_to_int_or_error(MinuteStr, {bad_time_offset_minute, MinuteStr}),
-    Second = list_to_int_or_error(SecondStr, {bad_time_offset_second, SecondStr}),
+    Hour = str_to_int_or_error(HourStr, {bad_time_offset_hour, HourStr}),
+    Minute = str_to_int_or_error(MinuteStr, {bad_time_offset_minute, MinuteStr}),
+    Second = str_to_int_or_error(SecondStr, {bad_time_offset_second, SecondStr}),
     (Hour =< 23) orelse error({bad_time_offset_hour, Hour}),
     (Hour =< 23) orelse error({bad_time_offset_hour, Hour}),
     (Minute =< 59) orelse error({bad_time_offset_minute, Minute}),
     (Minute =< 59) orelse error({bad_time_offset_minute, Minute}),
     (Second =< 59) orelse error({bad_time_offset_second, Second}),
     (Second =< 59) orelse error({bad_time_offset_second, Second}),
@@ -417,7 +417,11 @@ do_parse_date_str(Date, [Key | Formatter], Result) ->
     <<DatePart:Size/binary-unit:8, Tail/binary>> = Date,
     <<DatePart:Size/binary-unit:8, Tail/binary>> = Date,
     case lists:member(Key, ?DATE_PART) of
     case lists:member(Key, ?DATE_PART) of
         true ->
         true ->
-            do_parse_date_str(Tail, Formatter, Result#{Key => erlang:binary_to_integer(DatePart)});
+            %% Note: Here is a fix to make the error reason more sense
+            %% when the format or date can't be matched,
+            %% but the root reason comment underneath at <ROOT>
+            PartValue = str_to_int_or_error(DatePart, bad_formatter_or_date),
+            do_parse_date_str(Tail, Formatter, Result#{Key => PartValue});
         false ->
         false ->
             case lists:member(Key, ?DATE_ZONE_NAME) of
             case lists:member(Key, ?DATE_ZONE_NAME) of
                 true ->
                 true ->
@@ -425,6 +429,13 @@ do_parse_date_str(Date, [Key | Formatter], Result) ->
                         parsed_offset => offset_second(DatePart)
                         parsed_offset => offset_second(DatePart)
                     });
                     });
                 false ->
                 false ->
+                    %% <ROOT>
+                    %% Here should have compared the date part with the key,
+                    %% but for compatibility, we can't fix it here
+                    %% e.g.
+                    %% date_to_unix_ts('second','%Y-%m-%d %H-%M-%S', '2022-05-26 10:40:12')
+                    %% this is valid in 4.x, but actually '%H-%M-%S' can't match with '10:40:12'
+                    %% We cannot ensure whether there are more exceptions in the user's rule
                     do_parse_date_str(Tail, Formatter, Result)
                     do_parse_date_str(Tail, Formatter, Result)
             end
             end
     end.
     end.
@@ -456,10 +467,12 @@ dm(10) -> 273;
 dm(11) -> 304;
 dm(11) -> 304;
 dm(12) -> 334.
 dm(12) -> 334.
 
 
-list_to_int_or_error(Str, Error) ->
+str_to_int_or_error(Str, Error) ->
     case string:to_integer(Str) of
     case string:to_integer(Str) of
         {Int, []} ->
         {Int, []} ->
             Int;
             Int;
+        {Int, <<>>} ->
+            Int;
         _ ->
         _ ->
             error(Error)
             error(Error)
     end.
     end.

+ 6 - 4
apps/emqx_ldap/src/emqx_ldap.erl

@@ -54,10 +54,11 @@ fields(config) ->
         {pool_size, fun ?ECS:pool_size/1},
         {pool_size, fun ?ECS:pool_size/1},
         {username, fun ensure_username/1},
         {username, fun ensure_username/1},
         {password, fun ?ECS:password/1},
         {password, fun ?ECS:password/1},
-        {base_object,
+        {base_dn,
             ?HOCON(binary(), #{
             ?HOCON(binary(), #{
-                desc => ?DESC(base_object),
+                desc => ?DESC(base_dn),
                 required => true,
                 required => true,
+                example => <<"uid=${username},ou=testdevice,dc=emqx,dc=io">>,
                 validator => fun emqx_schema:non_empty_string/1
                 validator => fun emqx_schema:non_empty_string/1
             })},
             })},
         {filter,
         {filter,
@@ -66,6 +67,7 @@ fields(config) ->
                 #{
                 #{
                     desc => ?DESC(filter),
                     desc => ?DESC(filter),
                     default => <<"(objectClass=mqttUser)">>,
                     default => <<"(objectClass=mqttUser)">>,
+                    example => <<"(& (objectClass=mqttUser) (uid=${username}))">>,
                     validator => fun emqx_schema:non_empty_string/1
                     validator => fun emqx_schema:non_empty_string/1
                 }
                 }
             )}
             )}
@@ -229,9 +231,9 @@ log(Level, Format, Args) ->
     ).
     ).
 
 
 prepare_template(Config, State) ->
 prepare_template(Config, State) ->
-    do_prepare_template(maps:to_list(maps:with([base_object, filter], Config)), State).
+    do_prepare_template(maps:to_list(maps:with([base_dn, filter], Config)), State).
 
 
-do_prepare_template([{base_object, V} | T], State) ->
+do_prepare_template([{base_dn, V} | T], State) ->
     do_prepare_template(T, State#{base_tokens => emqx_placeholder:preproc_tmpl(V)});
     do_prepare_template(T, State#{base_tokens => emqx_placeholder:preproc_tmpl(V)});
 do_prepare_template([{filter, V} | T], State) ->
 do_prepare_template([{filter, V} | T], State) ->
     do_prepare_template(T, State#{filter_tokens => emqx_placeholder:preproc_tmpl(V)});
     do_prepare_template(T, State#{filter_tokens => emqx_placeholder:preproc_tmpl(V)});

+ 1 - 1
apps/emqx_ldap/test/emqx_ldap_SUITE.erl

@@ -154,7 +154,7 @@ ldap_config(Config) ->
             "    password = public\n"
             "    password = public\n"
             "    pool_size = 8\n"
             "    pool_size = 8\n"
             "    server = \"~s:~b\"\n"
             "    server = \"~s:~b\"\n"
-            "    base_object=\"uid=${username},ou=testdevice,dc=emqx,dc=io\"\n"
+            "    base_dn=\"uid=${username},ou=testdevice,dc=emqx,dc=io\"\n"
             "    filter =\"(objectClass=mqttUser)\"\n"
             "    filter =\"(objectClass=mqttUser)\"\n"
             "    ~ts\n"
             "    ~ts\n"
             "",
             "",

+ 2 - 2
apps/emqx_ldap/test/emqx_ldap_authn_SUITE.erl

@@ -167,7 +167,7 @@ t_update(_Config) ->
     CorrectConfig = raw_ldap_auth_config(),
     CorrectConfig = raw_ldap_auth_config(),
     IncorrectConfig =
     IncorrectConfig =
         CorrectConfig#{
         CorrectConfig#{
-            <<"base_object">> => <<"ou=testdevice,dc=emqx,dc=io">>
+            <<"base_dn">> => <<"ou=testdevice,dc=emqx,dc=io">>
         },
         },
 
 
     {ok, _} = emqx:update_config(
     {ok, _} = emqx:update_config(
@@ -208,7 +208,7 @@ raw_ldap_auth_config() ->
         <<"mechanism">> => <<"password_based">>,
         <<"mechanism">> => <<"password_based">>,
         <<"backend">> => <<"ldap">>,
         <<"backend">> => <<"ldap">>,
         <<"server">> => ldap_server(),
         <<"server">> => ldap_server(),
-        <<"base_object">> => <<"uid=${username},ou=testdevice,dc=emqx,dc=io">>,
+        <<"base_dn">> => <<"uid=${username},ou=testdevice,dc=emqx,dc=io">>,
         <<"username">> => <<"cn=root,dc=emqx,dc=io">>,
         <<"username">> => <<"cn=root,dc=emqx,dc=io">>,
         <<"password">> => <<"public">>,
         <<"password">> => <<"public">>,
         <<"pool_size">> => 8
         <<"pool_size">> => 8

+ 1 - 1
apps/emqx_ldap/test/emqx_ldap_authz_SUITE.erl

@@ -138,7 +138,7 @@ raw_ldap_authz_config() ->
         <<"enable">> => <<"true">>,
         <<"enable">> => <<"true">>,
         <<"type">> => <<"ldap">>,
         <<"type">> => <<"ldap">>,
         <<"server">> => ldap_server(),
         <<"server">> => ldap_server(),
-        <<"base_object">> => <<"uid=${username},ou=testdevice,dc=emqx,dc=io">>,
+        <<"base_dn">> => <<"uid=${username},ou=testdevice,dc=emqx,dc=io">>,
         <<"username">> => <<"cn=root,dc=emqx,dc=io">>,
         <<"username">> => <<"cn=root,dc=emqx,dc=io">>,
         <<"password">> => <<"public">>,
         <<"password">> => <<"public">>,
         <<"pool_size">> => 8
         <<"pool_size">> => 8

+ 29 - 0
apps/emqx_rule_engine/test/emqx_rule_funcs_SUITE.erl

@@ -1031,6 +1031,35 @@ timezone_to_offset_seconds_helper(FunctionName) ->
     apply_func(FunctionName, [local]),
     apply_func(FunctionName, [local]),
     ok.
     ok.
 
 
+t_parse_date_errors(_) ->
+    ?assertError(
+        bad_formatter_or_date,
+        emqx_rule_funcs:date_to_unix_ts(
+            second, <<"%Y-%m-%d %H:%M:%S">>, <<"2022-059999-26 10:40:12">>
+        )
+    ),
+    ?assertError(
+        bad_formatter_or_date,
+        emqx_rule_funcs:date_to_unix_ts(second, <<"%y-%m-%d %H:%M:%S">>, <<"2022-05-26 10:40:12">>)
+    ),
+
+    %% Compatibility test
+    UnixTs = 1653561612,
+    ?assertEqual(
+        UnixTs,
+        emqx_rule_funcs:date_to_unix_ts(second, <<"%Y-%m-%d %H:%M:%S">>, <<"2022-05-26 10:40:12">>)
+    ),
+
+    ?assertEqual(
+        UnixTs,
+        emqx_rule_funcs:date_to_unix_ts(second, <<"%Y-%m-%d %H-%M-%S">>, <<"2022-05-26 10:40:12">>)
+    ),
+
+    ?assertEqual(
+        UnixTs,
+        emqx_rule_funcs:date_to_unix_ts(second, <<"%Y-%m-%d %H:%M:%S">>, <<"2022-05-26 10-40-12">>)
+    ).
+
 %%------------------------------------------------------------------------------
 %%------------------------------------------------------------------------------
 %% Utility functions
 %% Utility functions
 %%------------------------------------------------------------------------------
 %%------------------------------------------------------------------------------

+ 77 - 17
build

@@ -368,21 +368,87 @@ docker_cleanup() {
 }
 }
 
 
 ## Build the default docker image based on debian 11.
 ## Build the default docker image based on debian 11.
-## NOTE: docker image build in github action does not call this
-##       function, see build_and_push_docker_images.yaml
 make_docker() {
 make_docker() {
-    EMQX_BUILDER="${EMQX_BUILDER:-${EMQX_DEFAULT_BUILDER}}"
-    EMQX_RUNNER="${EMQX_RUNNER:-${EMQX_DEFAULT_RUNNER}}"
-    EMQX_DOCKERFILE="${EMQX_DOCKERFILE:-deploy/docker/Dockerfile}"
+    local EMQX_BUILDER_VERSION="${EMQX_BUILDER_VERSION:-5.1-3}"
+    local EMQX_BUILDER_PLATFORM="${EMQX_BUILDER_PLATFORM:-debian11}"
+    local EMQX_BUILDER_OTP="${EMQX_BUILDER_OTP:-25.3.2-1}"
+    local EMQX_BUILDER_ELIXIR="${EMQX_BUILDER_ELIXIR:-1.14.5}"
+    local EMQX_BUILDER=${EMQX_BUILDER:-ghcr.io/emqx/emqx-builder/${EMQX_BUILDER_VERSION}:${EMQX_BUILDER_ELIXIR}-${EMQX_BUILDER_OTP}-${EMQX_BUILDER_PLATFORM}}
+    local EMQX_RUNNER="${EMQX_RUNNER:-${EMQX_DEFAULT_RUNNER}}"
+    local EMQX_DOCKERFILE="${EMQX_DOCKERFILE:-deploy/docker/Dockerfile}"
+    local PKG_VSN="${PKG_VSN:-$(./pkg-vsn.sh)}"
+    # shellcheck disable=SC2155
+    local VSN_MAJOR="$(echo "$PKG_VSN" | cut -d . -f 1)"
+    # shellcheck disable=SC2155
+    local VSN_MINOR="$(echo "$PKG_VSN" | cut -d . -f 2)"
+    # shellcheck disable=SC2155
+    local VSN_PATCH="$(echo "$PKG_VSN" | cut -d . -f 3)"
+    local SUFFIX=''
     if [[ "$PROFILE" = *-elixir ]]; then
     if [[ "$PROFILE" = *-elixir ]]; then
-        PKG_VSN="$PKG_VSN-elixir"
+        SUFFIX="-elixir"
     fi
     fi
-    local default_tag="emqx/${PROFILE%%-elixir}:${PKG_VSN}"
-    EMQX_IMAGE_TAG="${EMQX_IMAGE_TAG:-$default_tag}"
+    local DOCKER_REGISTRY="${REGISTRY:-docker.io}"
+    local DOCKER_ORG="${DOCKER_ORG:-emqx}"
+    local EMQX_BASE_DOCKER_TAG="${DOCKER_REGISTRY}/${DOCKER_ORG}/${PROFILE%%-elixir}"
+    local default_tag="${EMQX_BASE_DOCKER_TAG}:${PKG_VSN}${SUFFIX}"
+    local EMQX_IMAGE_TAG="${EMQX_IMAGE_TAG:-$default_tag}"
+    local EDITION=Opensource
+    local LICENSE='Apache-2.0'
+    local PRODUCT_URL='https://www.emqx.io'
+    local PRODUCT_DESCRIPTION='Official docker image for EMQX, the most scalable open-source MQTT broker for IoT, IIoT, and connected vehicles.'
+    local DOCUMENTATION_URL='https://www.emqx.io/docs/en/latest/'
     ## extra_deps is a comma separated list of debian 11 package names
     ## extra_deps is a comma separated list of debian 11 package names
-    local extra_deps=''
+    local EXTRA_DEPS=''
     if [[ "$PROFILE" = *enterprise* ]]; then
     if [[ "$PROFILE" = *enterprise* ]]; then
-        extra_deps='libsasl2-2,libsasl2-modules-gssapi-mit'
+        EXTRA_DEPS='libsasl2-2,libsasl2-modules-gssapi-mit'
+        EDITION=Enterprise
+        LICENSE='(Apache-2.0 AND BSL-1.1)'
+        PRODUCT_URL='https://www.emqx.com/en/products/emqx'
+        PRODUCT_DESCRIPTION='Official docker image for EMQX Enterprise, an enterprise MQTT platform at scale. '
+        DOCUMENTATION_URL='https://docs.emqx.com/en/enterprise/latest/'
+    fi
+    # shellcheck disable=SC2155
+    local ISO_8601_DATE="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
+    # shellcheck disable=SC2155
+    local GIT_REVISION="$(git rev-parse HEAD)"
+    local DOCKER_BUILDX_ARGS=(
+       --build-arg BUILD_FROM="${EMQX_BUILDER}" \
+       --build-arg RUN_FROM="${EMQX_RUNNER}" \
+       --build-arg EMQX_NAME="${PROFILE}" \
+       --build-arg EXTRA_DEPS="${EXTRA_DEPS}" \
+       --build-arg PKG_VSN="${PKG_VSN}" \
+       --file "${EMQX_DOCKERFILE}" \
+       --label org.opencontainers.image.title="${PROFILE}" \
+       --label org.opencontainers.image.edition="${EDITION}" \
+       --label org.opencontainers.image.version="${PKG_VSN}" \
+       --label org.opencontainers.image.revision="${GIT_REVISION}" \
+       --label org.opencontainers.image.created="${ISO_8601_DATE}" \
+       --label org.opencontainers.image.source='https://github.com/emqx/emqx' \
+       --label org.opencontainers.image.url="${PRODUCT_URL}" \
+       --label org.opencontainers.image.description="${PRODUCT_DESCRIPTION}" \
+       --label org.opencontainers.image.documentation="${DOCUMENTATION_URL}" \
+       --label org.opencontainers.image.licenses="${LICENSE}" \
+       --label org.opencontainers.image.otp.version="${EMQX_BUILDER_OTP}" \
+       --tag "${EMQX_IMAGE_TAG}" \
+       --tag "${EMQX_BASE_DOCKER_TAG}:${VSN_MAJOR}.${VSN_MINOR}${SUFFIX}" \
+       --tag "${EMQX_BASE_DOCKER_TAG}:${VSN_MAJOR}.${VSN_MINOR}.${VSN_PATCH}${SUFFIX}" \
+       --provenance false \
+       --pull
+    )
+    if [ "${DOCKER_BUILD_NOCACHE:-false}" = true ]; then
+        DOCKER_BUILDX_ARGS+=(--no-cache)
+    fi
+    if [ "${SUFFIX}" = '-elixir' ]; then
+        DOCKER_BUILDX_ARGS+=(--label org.opencontainers.image.elixir.version="${EMQX_BUILDER_ELIXIR}")
+    fi
+    if [ "${DOCKER_LATEST:-false}" = true ]; then
+        DOCKER_BUILDX_ARGS+=(--tag "${DOCKER_REGISTRY}/${DOCKER_ORG}/${PROFILE}:latest${SUFFIX}")
+    fi
+    if [ "${DOCKER_PLATFORMS:-default}" != 'default' ]; then
+        DOCKER_BUILDX_ARGS+=(--platform "${DOCKER_PLATFORMS}")
+    fi
+    if [ "${DOCKER_PUSH:-false}" = true ]; then
+        DOCKER_BUILDX_ARGS+=(--push)
     fi
     fi
     # shellcheck disable=SC2015
     # shellcheck disable=SC2015
     [ -f ./.dockerignore ] && mv ./.dockerignore ./.dockerignore.bak || true
     [ -f ./.dockerignore ] && mv ./.dockerignore ./.dockerignore.bak || true
@@ -393,13 +459,7 @@ make_docker() {
         echo '/*.lock'
         echo '/*.lock'
     } >> ./.dockerignore
     } >> ./.dockerignore
     set -x
     set -x
-    docker build --no-cache --pull \
-       --build-arg BUILD_FROM="${EMQX_BUILDER}" \
-       --build-arg RUN_FROM="${EMQX_RUNNER}" \
-       --build-arg EMQX_NAME="${PROFILE}" \
-       --build-arg EXTRA_DEPS="${extra_deps}" \
-       --tag "${EMQX_IMAGE_TAG}" \
-       -f "${EMQX_DOCKERFILE}" .
+    docker buildx build "${DOCKER_BUILDX_ARGS[@]}" .
     [[ "${DEBUG:-}" -eq 1 ]] || set +x
     [[ "${DEBUG:-}" -eq 1 ]] || set +x
     echo "${EMQX_IMAGE_TAG}" > ./.docker_image_tag
     echo "${EMQX_IMAGE_TAG}" > ./.docker_image_tag
 }
 }

+ 1 - 0
changes/ce/perf-11405.en.md

@@ -0,0 +1 @@
+Improve the error reason of the `date_to_unix_ts` to make more sense.

+ 1 - 0
deploy/docker/Dockerfile

@@ -5,6 +5,7 @@ FROM ${BUILD_FROM} AS builder
 COPY . /emqx
 COPY . /emqx
 
 
 ARG EMQX_NAME=emqx
 ARG EMQX_NAME=emqx
+ARG PKG_VSN
 ENV EMQX_RELUP=false
 ENV EMQX_RELUP=false
 
 
 RUN export PROFILE=${EMQX_NAME%%-elixir} \
 RUN export PROFILE=${EMQX_NAME%%-elixir} \

+ 5 - 4
rel/i18n/emqx_ldap.hocon

@@ -8,16 +8,17 @@ The LDAP default port 389 is used if `[:Port]` is not specified."""
 server.label:
 server.label:
 """Server Host"""
 """Server Host"""
 
 
-base_object.desc:
+base_dn.desc:
 """The name of the base object entry (or possibly the root) relative to
 """The name of the base object entry (or possibly the root) relative to
 which the Search is to be performed."""
 which the Search is to be performed."""
 
 
-base_object.label:
-"""Base Object"""
+base_dn.label:
+"""Base DN"""
 
 
 filter.desc:
 filter.desc:
 """The filter that defines the conditions that must be fulfilled in order
 """The filter that defines the conditions that must be fulfilled in order
-for the Search to match a given entry."""
+for the Search to match a given entry.<br>
+The syntax of the filter follows RFC 4515 and also supports placeholders."""
 
 
 filter.label:
 filter.label:
 """Filter"""
 """Filter"""

+ 3 - 12
scripts/parse-git-ref.sh

@@ -18,32 +18,26 @@ is_latest() {
 
 
 if [[ $1 =~ ^refs/tags/v[5-9]+\.[0-9]+\.[0-9]+$ ]]; then
 if [[ $1 =~ ^refs/tags/v[5-9]+\.[0-9]+\.[0-9]+$ ]]; then
     PROFILE=emqx
     PROFILE=emqx
-    EDITION=Opensource
     RELEASE=true
     RELEASE=true
     LATEST=$(is_latest "$1")
     LATEST=$(is_latest "$1")
-elif [[ $1 =~ ^refs/tags/v[5-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
+elif [[ $1 =~ ^refs/tags/v[5-9]+\.[0-9]+\.[0-9]+-[0-9]+$ ]]; then
     PROFILE=emqx
     PROFILE=emqx
-    EDITION=Opensource
     RELEASE=true
     RELEASE=true
     LATEST=$(is_latest "$1")
     LATEST=$(is_latest "$1")
 elif [[ $1 =~ ^refs/tags/e[5-9]+\.[0-9]+\.[0-9]+$ ]]; then
 elif [[ $1 =~ ^refs/tags/e[5-9]+\.[0-9]+\.[0-9]+$ ]]; then
     PROFILE=emqx-enterprise
     PROFILE=emqx-enterprise
-    EDITION=Enterprise
     RELEASE=true
     RELEASE=true
     LATEST=$(is_latest "$1")
     LATEST=$(is_latest "$1")
-elif [[ $1 =~ ^refs/tags/e[5-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
+elif [[ $1 =~ ^refs/tags/e[5-9]+\.[0-9]+\.[0-9]+-[0-9]+$ ]]; then
     PROFILE=emqx-enterprise
     PROFILE=emqx-enterprise
-    EDITION=Enterprise
     RELEASE=true
     RELEASE=true
     LATEST=$(is_latest "$1")
     LATEST=$(is_latest "$1")
 elif [[ $1 =~ ^refs/tags/v[5-9]+\.[0-9]+\.[0-9]+-(alpha|beta|rc)\.[0-9]+$ ]]; then
 elif [[ $1 =~ ^refs/tags/v[5-9]+\.[0-9]+\.[0-9]+-(alpha|beta|rc)\.[0-9]+$ ]]; then
     PROFILE=emqx
     PROFILE=emqx
-    EDITION=Opensource
     RELEASE=true
     RELEASE=true
     LATEST=false
     LATEST=false
 elif [[ $1 =~ ^refs/tags/e[5-9]+\.[0-9]+\.[0-9]+-(alpha|beta|rc)\.[0-9]+$ ]]; then
 elif [[ $1 =~ ^refs/tags/e[5-9]+\.[0-9]+\.[0-9]+-(alpha|beta|rc)\.[0-9]+$ ]]; then
     PROFILE=emqx-enterprise
     PROFILE=emqx-enterprise
-    EDITION=Enterprise
     RELEASE=true
     RELEASE=true
     LATEST=false
     LATEST=false
 elif [[ $1 =~ ^refs/tags/.+ ]]; then
 elif [[ $1 =~ ^refs/tags/.+ ]]; then
@@ -51,17 +45,14 @@ elif [[ $1 =~ ^refs/tags/.+ ]]; then
     exit 1
     exit 1
 elif [[ $1 =~ ^refs/heads/master$ ]]; then
 elif [[ $1 =~ ^refs/heads/master$ ]]; then
     PROFILE=emqx
     PROFILE=emqx
-    EDITION=Opensource
     RELEASE=false
     RELEASE=false
     LATEST=false
     LATEST=false
 elif [[ $1 =~ ^refs/heads/release-[5-9][0-9]+$ ]]; then
 elif [[ $1 =~ ^refs/heads/release-[5-9][0-9]+$ ]]; then
     PROFILE=emqx-enterprise
     PROFILE=emqx-enterprise
-    EDITION=Enterprise
     RELEASE=false
     RELEASE=false
     LATEST=false
     LATEST=false
 elif [[ $1 =~ ^refs/heads/ci/.* ]]; then
 elif [[ $1 =~ ^refs/heads/ci/.* ]]; then
     PROFILE=emqx
     PROFILE=emqx
-    EDITION=Opensource
     RELEASE=false
     RELEASE=false
     LATEST=false
     LATEST=false
 else
 else
@@ -70,5 +61,5 @@ else
 fi
 fi
 
 
 cat <<EOF
 cat <<EOF
-{"profile": "$PROFILE", "edition": "$EDITION", "release": $RELEASE, "latest": $LATEST}
+{"profile": "$PROFILE", "release": $RELEASE, "latest": $LATEST}
 EOF
 EOF

+ 17 - 17
scripts/shelltest/parse-git-ref.test

@@ -10,17 +10,17 @@ Unrecognized git ref: v5.2.0
 
 
 ./parse-git-ref.sh refs/tags/v5.1.0
 ./parse-git-ref.sh refs/tags/v5.1.0
 >>>
 >>>
-{"profile": "emqx", "edition": "Opensource", "release": true, "latest": false}
+{"profile": "emqx", "release": true, "latest": false}
 >>>= 0
 >>>= 0
 
 
-./parse-git-ref.sh refs/tags/v5.1.5.1
+./parse-git-ref.sh refs/tags/v5.1.5-1
 >>>
 >>>
-{"profile": "emqx", "edition": "Opensource", "release": true, "latest": false}
+{"profile": "emqx", "release": true, "latest": false}
 >>>= 0
 >>>= 0
 
 
 ./parse-git-ref.sh refs/tags/v5.2.0-alpha.1
 ./parse-git-ref.sh refs/tags/v5.2.0-alpha.1
 >>>
 >>>
-{"profile": "emqx", "edition": "Opensource", "release": true, "latest": false}
+{"profile": "emqx", "release": true, "latest": false}
 >>>= 0
 >>>= 0
 
 
 ./parse-git-ref.sh refs/tags/v5.2.0-alpha-1
 ./parse-git-ref.sh refs/tags/v5.2.0-alpha-1
@@ -30,62 +30,62 @@ Unrecognized tag: refs/tags/v5.2.0-alpha-1
 
 
 ./parse-git-ref.sh refs/tags/v5.2.0-beta.1
 ./parse-git-ref.sh refs/tags/v5.2.0-beta.1
 >>>
 >>>
-{"profile": "emqx", "edition": "Opensource", "release": true, "latest": false}
+{"profile": "emqx", "release": true, "latest": false}
 >>>= 0
 >>>= 0
 
 
 ./parse-git-ref.sh refs/tags/v5.2.0-rc.1
 ./parse-git-ref.sh refs/tags/v5.2.0-rc.1
 >>>
 >>>
-{"profile": "emqx", "edition": "Opensource", "release": true, "latest": false}
+{"profile": "emqx", "release": true, "latest": false}
 >>>= 0
 >>>= 0
 
 
 ./parse-git-ref.sh refs/tags/e5.1.0
 ./parse-git-ref.sh refs/tags/e5.1.0
 >>>
 >>>
-{"profile": "emqx-enterprise", "edition": "Enterprise", "release": true, "latest": false}
+{"profile": "emqx-enterprise", "release": true, "latest": false}
 >>>= 0
 >>>= 0
 
 
-./parse-git-ref.sh refs/tags/e5.1.5.1
+./parse-git-ref.sh refs/tags/e5.1.5-1
 >>>
 >>>
-{"profile": "emqx-enterprise", "edition": "Enterprise", "release": true, "latest": false}
+{"profile": "emqx-enterprise", "release": true, "latest": false}
 >>>= 0
 >>>= 0
 
 
 ./parse-git-ref.sh refs/tags/e5.2.0-alpha.1
 ./parse-git-ref.sh refs/tags/e5.2.0-alpha.1
 >>>
 >>>
-{"profile": "emqx-enterprise", "edition": "Enterprise", "release": true, "latest": false}
+{"profile": "emqx-enterprise", "release": true, "latest": false}
 >>>= 0
 >>>= 0
 
 
 ./parse-git-ref.sh refs/tags/e5.2.0-beta.1
 ./parse-git-ref.sh refs/tags/e5.2.0-beta.1
 >>>
 >>>
-{"profile": "emqx-enterprise", "edition": "Enterprise", "release": true, "latest": false}
+{"profile": "emqx-enterprise", "release": true, "latest": false}
 >>>= 0
 >>>= 0
 
 
 ./parse-git-ref.sh refs/tags/e5.2.0-rc.1
 ./parse-git-ref.sh refs/tags/e5.2.0-rc.1
 >>>
 >>>
-{"profile": "emqx-enterprise", "edition": "Enterprise", "release": true, "latest": false}
+{"profile": "emqx-enterprise", "release": true, "latest": false}
 >>>= 0
 >>>= 0
 
 
 ./parse-git-ref.sh refs/tags/e5.1.99
 ./parse-git-ref.sh refs/tags/e5.1.99
 >>>
 >>>
-{"profile": "emqx-enterprise", "edition": "Enterprise", "release": true, "latest": true}
+{"profile": "emqx-enterprise", "release": true, "latest": true}
 >>>= 0
 >>>= 0
 
 
 ./parse-git-ref.sh refs/tags/v5.1.99
 ./parse-git-ref.sh refs/tags/v5.1.99
 >>>
 >>>
-{"profile": "emqx", "edition": "Opensource", "release": true, "latest": true}
+{"profile": "emqx", "release": true, "latest": true}
 >>>= 0
 >>>= 0
 
 
 ./parse-git-ref.sh refs/heads/master
 ./parse-git-ref.sh refs/heads/master
 >>>
 >>>
-{"profile": "emqx", "edition": "Opensource", "release": false, "latest": false}
+{"profile": "emqx", "release": false, "latest": false}
 >>>= 0
 >>>= 0
 
 
 ./parse-git-ref.sh refs/heads/release-51
 ./parse-git-ref.sh refs/heads/release-51
 >>>
 >>>
-{"profile": "emqx-enterprise", "edition": "Enterprise", "release": false, "latest": false}
+{"profile": "emqx-enterprise", "release": false, "latest": false}
 >>>= 0
 >>>= 0
 
 
 ./parse-git-ref.sh refs/heads/ci/foobar
 ./parse-git-ref.sh refs/heads/ci/foobar
 >>>
 >>>
-{"profile": "emqx", "edition": "Opensource", "release": false, "latest": false}
+{"profile": "emqx", "release": false, "latest": false}
 >>>= 0
 >>>= 0
 
 
 ./parse-git-ref.sh refs/heads/release-44
 ./parse-git-ref.sh refs/heads/release-44