This is an automated email from the ASF dual-hosted git repository.

baoyuan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix.git


The following commit(s) were added to refs/heads/master by this push:
     new 31148aa65 fix(docker): support valid YAML variations in standalone 
mode (#12949)
31148aa65 is described below

commit 31148aa6590ea0f047123acb0a6007aa3fc744d0
Author: Mohammad Izzraff Janius 
<[email protected]>
AuthorDate: Wed Feb 4 13:52:02 2026 +0800

    fix(docker): support valid YAML variations in standalone mode (#12949)
---
 .github/workflows/docker-standalone.yml    |  63 +++++++++
 Makefile                                   |   1 -
 apisix/cli/ops.lua                         |  22 +++
 ci/linux_apisix_current_luarocks_runner.sh |   2 +
 docker/debian-dev/Dockerfile               |   4 +-
 docker/debian-dev/docker-entrypoint.sh     |   3 -
 docker/utils/check_standalone_config.sh    |  35 -----
 t/cli/test_standalone_docker.sh            | 214 +++++++++++++++++++++++++++++
 t/cli/test_standalone_yaml_format.sh       | 169 +++++++++++++++++++++++
 9 files changed, 471 insertions(+), 42 deletions(-)

diff --git a/.github/workflows/docker-standalone.yml 
b/.github/workflows/docker-standalone.yml
new file mode 100644
index 000000000..a048ee36e
--- /dev/null
+++ b/.github/workflows/docker-standalone.yml
@@ -0,0 +1,63 @@
+name: Docker Standalone Test
+
+on:
+  push:
+    branches: [master, 'release/**']
+    paths:
+      - 'apisix/cli/ops.lua'
+      - 'docker/debian-dev/**'
+      - 't/cli/test_standalone_docker.sh'
+      - 'Makefile'
+      - '.github/workflows/docker-standalone.yml'
+  pull_request:
+    branches: [master, 'release/**']
+    paths:
+      - 'apisix/cli/ops.lua'
+      - 'docker/debian-dev/**'
+      - 't/cli/test_standalone_docker.sh'
+      - 'Makefile'
+      - '.github/workflows/docker-standalone.yml'
+
+concurrency:
+  group: ${{ github.workflow }}-${{ github.ref == 'refs/heads/master' && 
github.run_number || github.ref }}
+  cancel-in-progress: true
+
+permissions:
+  contents: read
+
+jobs:
+  docker-test:
+    runs-on: ubuntu-latest
+    timeout-minutes: 30
+
+    steps:
+      - name: Check out code
+        uses: actions/checkout@v5
+
+      - name: Build APISIX Dashboard
+        run: |
+          # install node.js and pnpm
+          sudo n lts
+          corepack enable pnpm
+
+          # prepare apisix-dashboard source code
+          source .requirements
+          git clone --revision=${APISIX_DASHBOARD_COMMIT} --depth 1 
https://github.com/apache/apisix-dashboard.git
+          pushd apisix-dashboard
+
+          # compile
+          pnpm install --frozen-lockfile
+          pnpm run build
+          popd
+
+          # copy the dist files to the ui directory
+          mkdir ui
+          cp -r apisix-dashboard/dist/* ui/
+          rm -r apisix-dashboard
+
+          # build Docker image
+          make build-on-debian-dev
+
+      - name: Run Docker standalone test
+        run: |
+          ./t/cli/test_standalone_docker.sh
diff --git a/Makefile b/Makefile
index 423b24056..b54d7eefc 100644
--- a/Makefile
+++ b/Makefile
@@ -501,7 +501,6 @@ build-on-debian-dev:
                --build-arg CODE_PATH=. \
                --build-arg 
ENTRYPOINT_PATH=./docker/debian-dev/docker-entrypoint.sh \
                --build-arg 
INSTALL_BROTLI=./docker/debian-dev/install-brotli.sh \
-               --build-arg 
CHECK_STANDALONE_CONFIG=./docker/utils/check_standalone_config.sh \
                -f ./docker/debian-dev/Dockerfile .
        @$(call func_echo_success_status, "$@ -> [ Done ]")
 
diff --git a/apisix/cli/ops.lua b/apisix/cli/ops.lua
index 0bb64b689..f5e9beb17 100644
--- a/apisix/cli/ops.lua
+++ b/apisix/cli/ops.lua
@@ -181,6 +181,28 @@ local function init(env)
         util.die(err, "\n")
     end
 
+    -- validate standalone mode config
+    local standalone_env = getenv("APISIX_STAND_ALONE")
+    if standalone_env == "true" then
+        local role = yaml_conf.deployment.role
+        local config_provider
+
+        if role == "data_plane" then
+            config_provider = 
yaml_conf.deployment.role_data_plane.config_provider
+        elseif role == "traditional" then
+            config_provider = yaml_conf.deployment.role_traditional and
+                yaml_conf.deployment.role_traditional.config_provider
+        end
+
+        if config_provider ~= "yaml" and config_provider ~= "json" then
+            util.die("APISIX_STAND_ALONE is set to 'true' but config_provider 
is '"
+                .. tostring(config_provider) .. "'\n"
+                .. "For standalone mode, config_provider must be 'yaml' or 
'json'\n"
+                .. "Current role: " .. tostring(role) .. "\n"
+                .. "See: 
https://apisix.apache.org/docs/apisix/deployment-modes/\n";)
+        end
+    end
+
     -- check the Admin API token
     local checked_admin_key = false
     local allow_admin = yaml_conf.deployment.admin and
diff --git a/ci/linux_apisix_current_luarocks_runner.sh 
b/ci/linux_apisix_current_luarocks_runner.sh
index 39b9df8d0..a77f8878b 100755
--- a/ci/linux_apisix_current_luarocks_runner.sh
+++ b/ci/linux_apisix_current_luarocks_runner.sh
@@ -72,6 +72,8 @@ script() {
     ulimit -n -H
 
     for f in ./t/cli/test_*.sh; do
+        # skip docker test - runs in separate container
+        [[ "$f" == "./t/cli/test_standalone_docker.sh" ]] && continue
         PATH="$PATH" "$f"
     done
 }
diff --git a/docker/debian-dev/Dockerfile b/docker/debian-dev/Dockerfile
index ae971dff2..ff906d551 100644
--- a/docker/debian-dev/Dockerfile
+++ b/docker/debian-dev/Dockerfile
@@ -43,7 +43,6 @@ FROM debian:bullseye-slim
 
 ARG ENTRYPOINT_PATH=./docker-entrypoint.sh
 ARG INSTALL_BROTLI=./install-brotli.sh
-ARG CHECK_STANDALONE_CONFIG=./check_standalone_config.sh
 
 # Install the runtime libyaml package
 RUN apt-get -y update --fix-missing \
@@ -72,8 +71,7 @@ RUN ln -sf /dev/stdout /usr/local/apisix/logs/access.log \
 EXPOSE 9080 9443
 
 COPY ${ENTRYPOINT_PATH} /docker-entrypoint.sh
-COPY ${CHECK_STANDALONE_CONFIG} /check_standalone_config.sh
-RUN chmod +x /docker-entrypoint.sh /check_standalone_config.sh
+RUN chmod +x /docker-entrypoint.sh
 
 ENTRYPOINT ["/docker-entrypoint.sh"]
 
diff --git a/docker/debian-dev/docker-entrypoint.sh 
b/docker/debian-dev/docker-entrypoint.sh
index 7ca7b8a91..41fab0905 100644
--- a/docker/debian-dev/docker-entrypoint.sh
+++ b/docker/debian-dev/docker-entrypoint.sh
@@ -30,9 +30,6 @@ deployment:
   role_data_plane:
     config_provider: yaml
 _EOC_
-      else
-          # Check if the deployment role is set to data_plane and config 
provider is set to yaml for standalone mode
-          source /check_standalone_config.sh
       fi
 
         if [ ! -f "${PREFIX}/conf/apisix.yaml" ]; then
diff --git a/docker/utils/check_standalone_config.sh 
b/docker/utils/check_standalone_config.sh
deleted file mode 100644
index 22792c54f..000000000
--- a/docker/utils/check_standalone_config.sh
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/usr/bin/env bash
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License.  You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-if ! grep -q 'role: data_plane' "${PREFIX}/conf/config.yaml"; then
-    echo "Error: ${PREFIX}/conf/config.yaml does not contain 'role: 
data_plane'. Deployment role must be set to 'data_plane' for standalone mode."
-    echo "Please refer to the APISIX documentation for deployment modes: 
https://apisix.apache.org/docs/apisix/deployment-modes/";
-    exit 1
-fi
-
-if ! grep -q 'role_data_plane:' "${PREFIX}/conf/config.yaml"; then
-    echo "Error: ${PREFIX}/conf/config.yaml does not contain 
'role_data_plane:'."
-    echo "Please refer to the APISIX documentation for deployment modes: 
https://apisix.apache.org/docs/apisix/deployment-modes/";
-    exit 1
-fi
-
-if ! grep -q 'config_provider: yaml' "${PREFIX}/conf/config.yaml"; then
-    echo "Error: ${PREFIX}/conf/config.yaml does not contain 'config_provider: 
yaml'. Config provider must be set to 'yaml' for standalone mode."
-    echo "Please refer to the APISIX documentation for deployment modes: 
https://apisix.apache.org/docs/apisix/deployment-modes/";
-    exit 1
-fi
diff --git a/t/cli/test_standalone_docker.sh b/t/cli/test_standalone_docker.sh
new file mode 100755
index 000000000..7fce58364
--- /dev/null
+++ b/t/cli/test_standalone_docker.sh
@@ -0,0 +1,214 @@
+#!/usr/bin/env bash
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+. ./t/cli/common.sh
+
+standalone() {
+    clean_up
+    docker rm -f apisix-test-standalone 2>/dev/null || true
+    git checkout conf/apisix.yaml
+}
+
+DOCKER_IMAGE="${DOCKER_IMAGE:-apache/apisix:master-debian-dev}"
+trap standalone EXIT
+
+echo 'routes: []
+#END' > conf/apisix.yaml
+
+run_docker_test() {
+    local standalone_flag=$1
+    local config_mode=${2:-ro}
+
+    if [ "$standalone_flag" = "true" ]; then
+        docker run -d --name apisix-test-standalone \
+            -e APISIX_STAND_ALONE=true \
+            -v 
$(pwd)/conf/config.yaml:/usr/local/apisix/conf/config.yaml:${config_mode} \
+            -v $(pwd)/conf/apisix.yaml:/usr/local/apisix/conf/apisix.yaml:ro \
+            ${DOCKER_IMAGE} > /dev/null 2>&1
+    else
+        docker run -d --name apisix-test-standalone \
+            -v 
$(pwd)/conf/config.yaml:/usr/local/apisix/conf/config.yaml:${config_mode} \
+            -v $(pwd)/conf/apisix.yaml:/usr/local/apisix/conf/apisix.yaml:ro \
+            ${DOCKER_IMAGE} > /dev/null 2>&1
+    fi
+
+    sleep 5
+
+    if ! docker ps | grep -q apisix-test-standalone; then
+        echo "Container failed to start. Logs:"
+        docker logs apisix-test-standalone
+        docker rm -f apisix-test-standalone > /dev/null 2>&1
+        return 1
+    fi
+
+    docker rm -f apisix-test-standalone > /dev/null 2>&1
+    return 0
+}
+
+# normal YAML format
+echo '
+deployment:
+    role: data_plane
+    role_data_plane:
+        config_provider: yaml
+apisix:
+    node_listen: 9080
+' > conf/config.yaml
+
+if ! run_docker_test "true"; then
+    echo "failed: normal YAML format 'role: data_plane' was rejected"
+    exit 1
+fi
+
+echo "passed: normal YAML format accepted"
+
+# double-quoted format
+echo '
+deployment:
+    role: "data_plane"
+    role_data_plane:
+        config_provider: yaml
+apisix:
+    node_listen: 9080
+' > conf/config.yaml
+
+if ! run_docker_test "true"; then
+    echo "failed: double-quoted 'role: \"data_plane\"' was rejected"
+    exit 1
+fi
+
+echo "passed: double-quoted format accepted"
+
+# single-quoted format
+echo "
+deployment:
+    role: 'data_plane'
+    role_data_plane:
+        config_provider: yaml
+apisix:
+    node_listen: 9080
+" > conf/config.yaml
+
+if ! run_docker_test "true"; then
+    echo "failed: single quoted \"role: 'data_plane'\" was rejected"
+    exit 1
+fi
+
+echo "passed: single-quoted format accepted"
+
+# flow syntax
+echo '
+deployment: {"role": "data_plane", "role_data_plane": {"config_provider": 
"yaml"}}
+apisix:
+    node_listen: 9080
+' > conf/config.yaml
+
+if ! run_docker_test "true"; then
+    echo "failed: flow syntax 'role: {\"data_plane\"}' was rejected"
+    exit 1
+fi
+
+echo "passed: flow syntax format accepted"
+
+# mixed quotes
+echo "
+deployment:
+    role: \"data_plane\"
+    role_data_plane:
+        config_provider: 'yaml'
+apisix:
+    node_listen: 9080
+" > conf/config.yaml
+
+if ! run_docker_test "true"; then
+    echo "failed: mixed quotes format was rejected"
+    exit 1
+fi
+
+echo "passed: mixed quotes format accepted"
+
+# etcd config_provider should fail in standalone mode
+echo '
+deployment:
+    role: data_plane
+    role_data_plane:
+        config_provider: etcd
+    etcd:
+        host:
+            - "http://127.0.0.1:2379";
+apisix:
+    node_listen: 9080
+' > conf/config.yaml
+
+if run_docker_test "true"; then
+    echo "failed: 'config_provider: etcd' should be rejected in standalone 
mode"
+    exit 1
+fi
+
+echo "passed: 'config_provider: etcd' was correctly rejected in standalone 
mode"
+
+# traditional role with yaml config_provider should work
+echo '
+deployment:
+    role: traditional
+    role_traditional:
+        config_provider: yaml
+    admin:
+        admin_key_required: false
+apisix:
+    node_listen: 9080
+    enable_admin: true
+' > conf/config.yaml
+
+if ! run_docker_test "true" "rw"; then
+    echo "failed: traditional role with 'config_provider: yaml' was rejected"
+    exit 1
+fi
+
+echo "passed: traditional role with 'config_provider: yaml' accepted"
+
+# check is APISIX_PROFILE is respected in standalone mode
+echo '
+  deployment:
+    role: data_plane
+    role_data_plane:
+      config_provider: yaml
+  apisix:
+    node_listen: 9080
+  ' > conf/config-prod.yaml
+
+  docker run -d --name apisix-test-standalone \
+      -e APISIX_STAND_ALONE=true \
+      -e APISIX_PROFILE=prod \
+      -v 
$(pwd)/conf/config-prod.yaml:/usr/local/apisix/conf/config-prod.yaml:ro \
+      -v $(pwd)/conf/apisix.yaml:/usr/local/apisix/conf/apisix.yaml:ro \
+      ${DOCKER_IMAGE} > /dev/null 2>&1
+
+  sleep 5
+
+  if ! docker ps | grep -q apisix-test-standalone; then
+      echo "failed: APISIX_PROFILE=prod in standalone mode was rejected"
+      docker logs apisix-test-standalone
+      docker rm -f apisix-test-standalone > /dev/null 2>&1
+      exit 1
+  fi
+
+  docker rm -f apisix-test-standalone > /dev/null 2>&1
+
+  echo "passed: APISIX_PROFILE=prod in standalone mode accepted"
diff --git a/t/cli/test_standalone_yaml_format.sh 
b/t/cli/test_standalone_yaml_format.sh
new file mode 100755
index 000000000..d44eb430a
--- /dev/null
+++ b/t/cli/test_standalone_yaml_format.sh
@@ -0,0 +1,169 @@
+#!/usr/bin/env bash
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+. ./t/cli/common.sh
+
+standalone() {
+    clean_up
+    git checkout conf/apisix.yaml
+    rm -f conf/config-prod.yaml
+    unset APISIX_STAND_ALONE
+    unset APISIX_PROFILE
+}
+
+trap standalone EXIT
+
+# normal YAML format
+echo '
+deployment:
+    role: data_plane
+    role_data_plane:
+        config_provider: yaml
+apisix:
+    node_listen: 9080
+' > conf/config.yaml
+
+export APISIX_STAND_ALONE=true
+
+if ! make init > /dev/null 2>&1; then
+    echo "failed: normal YAML format 'role: data_plane' was rejected"
+    exit 1
+fi
+
+echo "passed: normal YAML format accepted"
+
+# double-quoted format
+echo '
+deployment:
+    role: "data_plane"
+    role_data_plane:
+        config_provider: yaml
+apisix:
+    node_listen: 9080
+' > conf/config.yaml
+
+make clean > /dev/null 2>&1
+
+if ! make init > /dev/null 2>&1; then
+    echo "failed: double-quoted 'role: \"data_plane\"' was rejected"
+    exit 1
+fi
+
+echo "passed: double-quoted format accepted"
+
+# single-quoted format
+echo "
+deployment:
+    role: 'data_plane'
+    role_data_plane:
+        config_provider: yaml
+apisix:
+    node_listen: 9080
+" > conf/config.yaml
+
+make clean > /dev/null 2>&1
+
+if ! make init > /dev/null 2>&1; then
+    echo "failed: single quoted "role: 'data_plane'" was rejected"
+    exit 1
+fi
+
+echo "passed: single-quoted format accepted"
+
+# flow syntax
+echo '
+deployment: {"role": "data_plane", "role_data_plane": {"config_provider": 
"yaml"}}
+apisix:
+    node_listen: 9080
+' > conf/config.yaml
+
+make clean > /dev/null 2>&1
+
+if ! make init > /dev/null 2>&1; then
+    echo "failed: flow syntax was rejected"
+    exit 1
+fi
+
+# should fail - etcd config_provider in standalone mode
+echo '
+deployment:
+    role: data_plane
+    role_data_plane:
+        config_provider: etcd
+    etcd:
+        host:
+          - "http://127.0.0.1:2379";
+apisix:
+    node_listen: 9080
+' > conf/config.yaml
+
+make clean > /dev/null 2>&1
+
+if make init > /dev/null 2>&1; then
+    echo "failed: 'config_provider: etcd' should be rejected in standalone 
mode"
+    exit 1
+fi
+
+echo "passed: 'config_provider: etcd' was correctly rejected in standalone 
mode"
+
+# traditional role with yaml config_provider
+echo '
+deployment:
+    role: traditional
+    role_traditional:
+        config_provider: yaml
+    admin:
+        admin_key_required: false
+apisix:
+    node_listen: 9080
+    enable_admin: true
+' > conf/config.yaml
+
+make clean > /dev/null 2>&1
+
+if ! make init > /dev/null 2>&1; then
+    echo "failed: 'role: traditional' with 'config_provider: yaml' was 
rejected"
+    exit 1
+fi
+
+echo "passed: 'role: traditional' with 'config_provider: yaml' accepted"
+
+# check APISIX_PROFILE is respected
+echo '
+deployment:
+    role: data_plane
+    role_data_plane:
+        config_provider: yaml
+apisix:
+    node_listen: 9080
+' > conf/config-prod.yaml
+
+echo 'routes: []
+#END' > conf/apisix.yaml
+
+export APISIX_PROFILE=prod
+
+make clean > /dev/null 2>&1
+
+if ! make init > /dev/null 2>&1; then
+    echo "failed: APISIX_PROFILE=prod is not respected in standalone mode"
+    exit 1
+fi
+
+echo "passed: APISIX_PROFILE=prod is respected in standalone mode"

Reply via email to