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

spacewander 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 089e8a218 feat(deployment): support connecting to etcd via https 
(#7269)
089e8a218 is described below

commit 089e8a2181cb9872e1be239cafdb60b4f930e347
Author: 罗泽轩 <spacewander...@gmail.com>
AuthorDate: Mon Jun 20 14:24:17 2022 +0800

    feat(deployment): support connecting to etcd via https (#7269)
---
 .github/workflows/build.yml          |   2 +-
 .github/workflows/centos7-ci.yml     |   2 +-
 apisix/cli/file.lua                  |   8 ---
 apisix/cli/ngx_tpl.lua               |   2 +-
 apisix/cli/ops.lua                   |   5 +-
 apisix/cli/schema.lua                |   5 +-
 apisix/cli/snippet.lua               |  42 ++++++++++-----
 apisix/core/etcd.lua                 |  42 +++++++++++----
 t/bin/gen_snippet.lua                |  51 ++++++++++++++++++
 t/cli/test_deployment_traditional.sh |  20 +++++++
 t/deployment/conf_server.t           | 100 +++++++++++++++++++++++++++++++++++
 11 files changed, 243 insertions(+), 36 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index bd199672e..6834d8651 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -31,7 +31,7 @@ jobs:
           - linux_openresty_1_17
         test_dir:
           - t/plugin
-          - t/admin t/cli t/config-center-yaml t/control t/core t/debug 
t/discovery t/error_page t/misc
+          - t/admin t/cli t/config-center-yaml t/control t/core t/debug 
t/deployment t/discovery t/error_page t/misc
           - t/node t/pubsub t/router t/script t/stream-node t/utils t/wasm 
t/xds-library t/xrpc
 
     runs-on: ${{ matrix.platform }}
diff --git a/.github/workflows/centos7-ci.yml b/.github/workflows/centos7-ci.yml
index 9b2f8fc81..589e5ed69 100644
--- a/.github/workflows/centos7-ci.yml
+++ b/.github/workflows/centos7-ci.yml
@@ -29,7 +29,7 @@ jobs:
       matrix:
         test_dir:
           - t/plugin
-          - t/admin t/cli t/config-center-yaml t/control t/core t/debug 
t/discovery t/error_page t/misc
+          - t/admin t/cli t/config-center-yaml t/control t/core t/debug 
t/deployment t/discovery t/error_page t/misc
           - t/node t/pubsub t/router t/script t/stream-node t/utils t/wasm 
t/xds-library
 
     steps:
diff --git a/apisix/cli/file.lua b/apisix/cli/file.lua
index 5bd64a682..66600b54b 100644
--- a/apisix/cli/file.lua
+++ b/apisix/cli/file.lua
@@ -237,14 +237,6 @@ function _M.read_yaml_conf(apisix_home)
         end
     end
 
-    if default_conf.deployment
-        and default_conf.deployment.role == "traditional"
-        and default_conf.deployment.etcd
-    then
-        default_conf.etcd = default_conf.deployment.etcd
-        default_conf.etcd.unix_socket_proxy = "unix:./conf/config_listen.sock"
-    end
-
     if default_conf.apisix.config_center == "yaml" then
         local apisix_conf_path = profile:yaml_path("apisix")
         local apisix_conf_yaml, _ = util.read_file(apisix_conf_path)
diff --git a/apisix/cli/ngx_tpl.lua b/apisix/cli/ngx_tpl.lua
index 161c530b8..f22280766 100644
--- a/apisix/cli/ngx_tpl.lua
+++ b/apisix/cli/ngx_tpl.lua
@@ -64,7 +64,7 @@ lua {
     {% end %}
 }
 
-{% if (enabled_stream_plugins["prometheus"] or conf_server) and not 
enable_http then %}
+{% if enabled_stream_plugins["prometheus"] and not enable_http then %}
 http {
     {% if enabled_stream_plugins["prometheus"] then %}
     init_worker_by_lua_block {
diff --git a/apisix/cli/ops.lua b/apisix/cli/ops.lua
index 3e933ddd3..9a275648e 100644
--- a/apisix/cli/ops.lua
+++ b/apisix/cli/ops.lua
@@ -540,7 +540,10 @@ Please modify "admin_key" in conf/config.yaml .
         proxy_mirror_timeouts = yaml_conf.plugin_attr["proxy-mirror"].timeout
     end
 
-    local conf_server = snippet.generate_conf_server(yaml_conf)
+    local conf_server, err = snippet.generate_conf_server(env, yaml_conf)
+    if err then
+        util.die(err, "\n")
+    end
 
     -- Using template.render
     local sys_conf = {
diff --git a/apisix/cli/schema.lua b/apisix/cli/schema.lua
index ab053a0a7..db4f47477 100644
--- a/apisix/cli/schema.lua
+++ b/apisix/cli/schema.lua
@@ -43,7 +43,7 @@ local etcd_schema = {
                 key = {
                     type = "string",
                 },
-            }
+            },
         },
         prefix = {
             type = "string",
@@ -54,7 +54,8 @@ local etcd_schema = {
             items = {
                 type = "string",
                 pattern = [[^https?://]]
-            }
+            },
+            minItems = 1,
         }
     },
     required = {"prefix", "host"}
diff --git a/apisix/cli/snippet.lua b/apisix/cli/snippet.lua
index 014719511..191e3b0ed 100644
--- a/apisix/cli/snippet.lua
+++ b/apisix/cli/snippet.lua
@@ -22,19 +22,31 @@ local ipairs = ipairs
 local _M = {}
 
 
-function _M.generate_conf_server(conf)
+function _M.generate_conf_server(env, conf)
     if not (conf.deployment and conf.deployment.role == "traditional") then
-        return nil
+        return nil, nil
     end
 
     -- we use proxy even the role is traditional so that we can test the proxy 
in daily dev
-    local servers = conf.deployment.etcd.host
+    local etcd = conf.deployment.etcd
+    local servers = etcd.host
+    local enable_https = false
+    local prefix = "https://";
+    if servers[1]:find(prefix, 1, true) then
+        enable_https = true
+    end
+    -- there is not a compatible way to verify upstream TLS like the one we do 
in cosocket
+    -- so here we just ignore it as the verification is already done in the 
init phase
     for i, s in ipairs(servers) do
-        local prefix = "http://";
-        -- TODO: support https
-        if s:find(prefix, 1, true) then
-            servers[i] = s:sub(#prefix + 1)
+        if (s:find(prefix, 1, true) ~= nil) ~= enable_https then
+            return nil, "all nodes in the etcd cluster should enable/disable 
TLS together"
+        end
+
+        local _, to = s:find("://", 1, true)
+        if not to then
+            return nil, "bad etcd endpoint format"
         end
+        servers[i] = s:sub(to + 1)
     end
 
     local conf_render = template.compile([[
@@ -44,12 +56,16 @@ function _M.generate_conf_server(conf)
         {% end %}
     }
     server {
-        listen unix:./conf/config_listen.sock;
+        listen unix:{* home *}/conf/config_listen.sock;
         access_log off;
         location / {
-            set $upstream_scheme             'http';
-
-            proxy_pass $upstream_scheme://apisix_conf_backend;
+            {% if enable_https then %}
+            proxy_pass https://apisix_conf_backend;
+            proxy_ssl_server_name on;
+            proxy_ssl_protocols TLSv1.2 TLSv1.3;
+            {% else %}
+            proxy_pass http://apisix_conf_backend;
+            {% end %}
 
             proxy_http_version 1.1;
             proxy_set_header Connection "";
@@ -57,7 +73,9 @@ function _M.generate_conf_server(conf)
     }
     ]])
     return conf_render({
-        servers = servers
+        servers = servers,
+        enable_https = enable_https,
+        home = env.apisix_home or ".",
     })
 end
 
diff --git a/apisix/core/etcd.lua b/apisix/core/etcd.lua
index 9d289bd5d..274b3a9d8 100644
--- a/apisix/core/etcd.lua
+++ b/apisix/core/etcd.lua
@@ -19,15 +19,19 @@
 --
 -- @module core.etcd
 
-local fetch_local_conf = require("apisix.core.config_local").local_conf
-local array_mt         = require("apisix.core.json").array_mt
-local etcd             = require("resty.etcd")
-local clone_tab        = require("table.clone")
-local health_check     = require("resty.etcd.health_check")
-local ipairs           = ipairs
-local setmetatable     = setmetatable
-local string           = string
-local tonumber         = tonumber
+local fetch_local_conf  = require("apisix.core.config_local").local_conf
+local array_mt          = require("apisix.core.json").array_mt
+local etcd              = require("resty.etcd")
+local clone_tab         = require("table.clone")
+local health_check      = require("resty.etcd.health_check")
+local ipairs            = ipairs
+local setmetatable      = setmetatable
+local string            = string
+local tonumber          = tonumber
+local ngx_config_prefix = ngx.config.prefix()
+
+
+local is_http = ngx.config.subsystem == "http"
 local _M = {}
 
 
@@ -38,7 +42,25 @@ local function new()
         return nil, nil, err
     end
 
-    local etcd_conf = clone_tab(local_conf.etcd)
+    local etcd_conf
+
+    if local_conf.deployment
+        and local_conf.deployment.role == "traditional"
+        -- we proxy the etcd requests in traditional mode so we can test the 
CP's behavior in
+        -- daily development. However, a stream proxy can't be the CP.
+        -- Hence, generate a HTTP conf server to proxy etcd requests in stream 
proxy is
+        -- unnecessary and inefficient.
+        and is_http
+    then
+        local sock_prefix = ngx_config_prefix
+        etcd_conf = clone_tab(local_conf.deployment.etcd)
+        etcd_conf.unix_socket_proxy =
+            "unix:" .. sock_prefix .. "/conf/config_listen.sock"
+        etcd_conf.host = {"http://127.0.0.1:2379"}
+    else
+        etcd_conf = clone_tab(local_conf.etcd)
+    end
+
     local prefix = etcd_conf.prefix
     etcd_conf.http_host = etcd_conf.host
     etcd_conf.host = nil
diff --git a/t/bin/gen_snippet.lua b/t/bin/gen_snippet.lua
new file mode 100755
index 000000000..085409b6b
--- /dev/null
+++ b/t/bin/gen_snippet.lua
@@ -0,0 +1,51 @@
+#!/usr/bin/env luajit
+--
+-- 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.
+--
+-- this script generates Nginx configuration in the test
+-- so we can test some features with test-nginx
+local pkg_cpath_org = package.cpath
+local pkg_path_org = package.path
+local pkg_cpath = "deps/lib64/lua/5.1/?.so;deps/lib/lua/5.1/?.so;"
+local pkg_path = "deps/share/lua/5.1/?.lua;"
+-- modify the load path to load our dependencies
+package.cpath = pkg_cpath .. pkg_cpath_org
+package.path  = pkg_path .. pkg_path_org
+
+
+local file = require("apisix.cli.file")
+local schema = require("apisix.cli.schema")
+local snippet = require("apisix.cli.snippet")
+local yaml_conf, err = file.read_yaml_conf("t/servroot")
+if not yaml_conf then
+    error(err)
+end
+local ok, err = schema.validate(yaml_conf)
+if not ok then
+    error(err)
+end
+
+local res, err
+if arg[1] == "conf_server" then
+    res, err = snippet.generate_conf_server(
+        {apisix_home = "t/servroot/"},
+        yaml_conf)
+end
+
+if not res then
+    error(err or "none")
+end
+print(res)
diff --git a/t/cli/test_deployment_traditional.sh 
b/t/cli/test_deployment_traditional.sh
index f6d7d62c9..895675118 100755
--- a/t/cli/test_deployment_traditional.sh
+++ b/t/cli/test_deployment_traditional.sh
@@ -111,3 +111,23 @@ if grep '\[error\]' logs/error.log; then
 fi
 
 echo "passed: could connect to etcd"
+
+echo '
+deployment:
+    role: traditional
+    role_traditional:
+        config_provider: etcd
+    etcd:
+        prefix: "/apisix"
+        host:
+            - http://127.0.0.1:2379
+            - https://127.0.0.1:2379
+' > conf/config.yaml
+
+out=$(make init 2>&1 || true)
+if ! echo "$out" | grep 'all nodes in the etcd cluster should enable/disable 
TLS together'; then
+    echo "failed: should validate etcd host"
+    exit 1
+fi
+
+echo "passed: validate etcd host"
diff --git a/t/deployment/conf_server.t b/t/deployment/conf_server.t
new file mode 100644
index 000000000..84b045055
--- /dev/null
+++ b/t/deployment/conf_server.t
@@ -0,0 +1,100 @@
+#
+# 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.
+#
+use t::APISIX;
+
+my $nginx_binary = $ENV{'TEST_NGINX_BINARY'} || 'nginx';
+my $version = eval { `$nginx_binary -V 2>&1` };
+
+if ($version =~ m/\/1.17.8/) {
+    plan(skip_all => "require OpenResty 1.19+");
+} else {
+    plan('no_plan');
+}
+
+add_block_preprocessor(sub {
+    my ($block) = @_;
+
+    if (!$block->request) {
+        $block->set_value("request", "GET /t");
+    }
+
+    if ((!defined $block->error_log) && (!defined $block->no_error_log)) {
+        $block->set_value("no_error_log", "[error]");
+    }
+
+});
+
+Test::Nginx::Socket::set_http_config_filter(sub {
+    my $config = shift;
+    my $snippet = `./t/bin/gen_snippet.lua conf_server`;
+    $config .= $snippet;
+    return $config;
+});
+
+run_tests();
+
+__DATA__
+
+=== TEST 1: sync in https
+--- config
+    location /t {
+        content_by_lua_block {
+            local core = require("apisix.core")
+            local t = require("lib.test_admin").test
+
+            local consumers, _ = core.config.new("/consumers", {
+                automatic = true,
+                item_schema = core.schema.consumer,
+            })
+
+            ngx.sleep(0.6)
+            local idx = consumers.prev_index
+
+            local code, body = t('/apisix/admin/consumers',
+                ngx.HTTP_PUT,
+                [[{
+                    "username": "jobs",
+                    "plugins": {
+                        "basic-auth": {
+                            "username": "jobs",
+                            "password": "678901"
+                        }
+                    }
+                }]])
+
+            ngx.sleep(2)
+            local new_idx = consumers.prev_index
+            if new_idx > idx then
+                ngx.say("prev_index updated")
+            else
+                ngx.say("prev_index not update")
+            end
+        }
+    }
+--- response_body
+prev_index updated
+--- extra_yaml_config
+deployment:
+    role: traditional
+    role_traditional:
+        config_provider: etcd
+    etcd:
+        prefix: "/apisix"
+        host:
+            - https://127.0.0.1:12379
+        tls:
+            verify: false

Reply via email to