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

monkeydluffy 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 d80fc3bc9 feat: support pulling env vars from yaml keys (#9855)
d80fc3bc9 is described below

commit d80fc3bc97158617287a406c269f1bce2d67ab64
Author: Abhishek Choudhary <[email protected]>
AuthorDate: Fri Aug 4 14:40:32 2023 +0545

    feat: support pulling env vars from yaml keys (#9855)
---
 apisix/cli/file.lua         | 81 +++++++++++++++++++++++++++++----------------
 docs/en/latest/admin-api.md | 13 ++++++++
 docs/zh/latest/admin-api.md | 13 ++++++++
 t/cli/test_standalone.sh    | 29 +++++++++++++++-
 4 files changed, 107 insertions(+), 29 deletions(-)

diff --git a/apisix/cli/file.lua b/apisix/cli/file.lua
index af071a840..149c4e913 100644
--- a/apisix/cli/file.lua
+++ b/apisix/cli/file.lua
@@ -54,8 +54,59 @@ local function tab_is_array(t)
 end
 
 
+local function var_sub(val)
+    local err
+    local var_used = false
+    -- we use '${{var}}' because '$var' and '${var}' are taken
+    -- by Nginx
+    local new_val = val:gsub("%$%{%{%s*([%w_]+[%:%=]?.-)%s*%}%}", function(var)
+        local i, j = var:find("%:%=")
+        local default
+        if i and j then
+            default = var:sub(i + 2, #var)
+            default = default:gsub('^%s*(.-)%s*$', '%1')
+            var = var:sub(1, i - 1)
+        end
+
+        local v = getenv(var) or default
+        if v then
+            if not exported_vars then
+                exported_vars = {}
+            end
+
+            exported_vars[var] = v
+            var_used = true
+            return v
+        end
+
+        err = "failed to handle configuration: " ..
+              "can't find environment variable " .. var
+        return ""
+    end)
+    return new_val, var_used, err
+end
+
+
 local function resolve_conf_var(conf)
+    local new_keys = {}
     for key, val in pairs(conf) do
+        -- avoid re-iterating the table for already iterated key
+        if new_keys[key] then
+            goto continue
+        end
+        -- substitute environment variables from conf keys
+        if type(key) == "string" then
+            local new_key, _, err = var_sub(key)
+            if err then
+                return nil, err
+            end
+            if new_key ~= key then
+                new_keys[new_key] = "dummy" -- we only care about checking the 
key
+                conf.key = nil
+                conf[new_key] = val
+                key = new_key
+            end
+        end
         if type(val) == "table" then
             local ok, err = resolve_conf_var(val)
             if not ok then
@@ -63,34 +114,7 @@ local function resolve_conf_var(conf)
             end
 
         elseif type(val) == "string" then
-            local err
-            local var_used = false
-            -- we use '${{var}}' because '$var' and '${var}' are taken
-            -- by Nginx
-            local new_val = val:gsub("%$%{%{%s*([%w_]+[%:%=]?.-)%s*%}%}", 
function(var)
-                local i, j = var:find("%:%=")
-                local default
-                if i and j then
-                    default = var:sub(i + 2, #var)
-                    default = default:gsub('^%s*(.-)%s*$', '%1')
-                    var = var:sub(1, i - 1)
-                end
-
-                local v = getenv(var) or default
-                if v then
-                    if not exported_vars then
-                        exported_vars = {}
-                    end
-
-                    exported_vars[var] = v
-                    var_used = true
-                    return v
-                end
-
-                err = "failed to handle configuration: " ..
-                      "can't find environment variable " .. var
-                return ""
-            end)
+            local new_val, var_used, err = var_sub(val)
 
             if err then
                 return nil, err
@@ -108,6 +132,7 @@ local function resolve_conf_var(conf)
 
             conf[key] = new_val
         end
+        ::continue::
     end
 
     return true
diff --git a/docs/en/latest/admin-api.md b/docs/en/latest/admin-api.md
index 3071a3e00..787a61e98 100644
--- a/docs/en/latest/admin-api.md
+++ b/docs/en/latest/admin-api.md
@@ -103,6 +103,19 @@ deployment:
 
 This will find the environment variable `ADMIN_KEY` first, and if it does not 
exist, it will use `edd1c9f034335f136f87ad84b625c8f1` as the default value.
 
+You can also specify environment variables in yaml keys. This is specifically 
useful in the `standalone` [mode](./deployment-modes.md#standalone) where you 
can specify the upstream nodes as follows:
+
+```yaml title="./conf/apisix.yaml"
+routes:
+  -
+    uri: "/test"
+    upstream:
+      nodes:
+        "${{HOST_IP}}:${{PORT}}": 1
+      type: roundrobin
+#END
+```
+
 ### Force Delete
 
 By default, the Admin API checks for references between resources and will 
refuse to delete resources in use.
diff --git a/docs/zh/latest/admin-api.md b/docs/zh/latest/admin-api.md
index ab2625d94..e1fd063e8 100644
--- a/docs/zh/latest/admin-api.md
+++ b/docs/zh/latest/admin-api.md
@@ -105,6 +105,19 @@ deployment:
 
 首先查找环境变量 `ADMIN_KEY`,如果该环境变量不存在,它将使用 `edd1c9f034335f136f87ad84b625c8f1` 作为默认值。
 
+您还可以在 yaml 键中指定环境变量。这在 `standalone` 模式 中特别有用,您可以在其中指定上游节点,如下所示:
+
+```yaml title="./conf/apisix.yaml"
+routes:
+  -
+    uri: "/test"
+    upstream:
+      nodes:
+        "${{HOST_IP}}:${{PORT}}": 1
+      type: roundrobin
+#END
+```
+
 ### 强制删除 {#force-delete}
 
 默认情况下,Admin API 会检查资源间的引用关系,将会拒绝删除正在使用中的资源。
diff --git a/t/cli/test_standalone.sh b/t/cli/test_standalone.sh
index 2a3add666..a0d91c11c 100755
--- a/t/cli/test_standalone.sh
+++ b/t/cli/test_standalone.sh
@@ -26,7 +26,7 @@ standalone() {
 
 trap standalone EXIT
 
-# support environment variables
+# support environment variables in yaml values
 echo '
 apisix:
   enable_admin: false
@@ -69,6 +69,33 @@ fi
 
 echo "passed: resolve variables in apisix.yaml conf success"
 
+# support environment variables in yaml keys
+echo '
+routes:
+  -
+    uri: "/test"
+    plugins:
+      proxy-rewrite:
+        uri: "/apisix/nginx_status"
+    upstream:
+      nodes:
+        "${{HOST_IP}}:${{PORT}}": 1
+      type: roundrobin
+#END
+' > conf/apisix.yaml
+
+# variable is valid
+HOST_IP="127.0.0.1" PORT="9091" make init
+HOST_IP="127.0.0.1" PORT="9091" make run
+sleep 0.1
+
+code=$(curl -o /dev/null -s -m 5 -w %{http_code} http://127.0.0.1:9080/test)
+if [ ! $code -eq 200 ]; then
+    echo "failed: resolve variables in apisix.yaml conf failed"
+fi
+
+echo "passed: resolve variables in apisix.yaml conf success"
+
 # configure standalone via deployment
 echo '
 deployment:

Reply via email to