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 7d676f3bd refactor(admin): secrets and ssls (#8911)
7d676f3bd is described below

commit 7d676f3bdf256c883c74b30bcdebb48bfbd97a28
Author: dongjunduo <[email protected]>
AuthorDate: Wed Mar 1 17:49:08 2023 +0800

    refactor(admin): secrets and ssls (#8911)
---
 apisix/admin/init.lua     |  18 +---
 apisix/admin/resource.lua | 147 +++++++++++++++++++++++++++----
 apisix/admin/secrets.lua  | 183 ++------------------------------------
 apisix/admin/ssl.lua      | 219 ++--------------------------------------------
 4 files changed, 149 insertions(+), 418 deletions(-)

diff --git a/apisix/admin/init.lua b/apisix/admin/init.lua
index 5afbff096..072a58435 100644
--- a/apisix/admin/init.lua
+++ b/apisix/admin/init.lua
@@ -204,22 +204,10 @@ local function run()
     end
 
     local code, data
-    local refactored_resources = {
-        "routes",
-        "stream_routes",
-        "upstreams",
-        "protos",
-        "global_rules",
-        "services",
-        "consumer_groups",
-        "plugin_configs",
-        "consumers",
-        "plugin_metadata",
-    }
-    if core.table.array_find(refactored_resources, seg_res) then
-        code, data = resource[method](resource, seg_id, req_body, 
seg_sub_path, uri_args)
-    else
+    if seg_res == "schema" or seg_res == "plugins" then
         code, data = resource[method](seg_id, req_body, seg_sub_path, uri_args)
+    else
+        code, data = resource[method](resource, seg_id, req_body, 
seg_sub_path, uri_args)
     end
 
     if code then
diff --git a/apisix/admin/resource.lua b/apisix/admin/resource.lua
index 59689a2af..ac204dcf5 100644
--- a/apisix/admin/resource.lua
+++ b/apisix/admin/resource.lua
@@ -16,6 +16,7 @@
 --
 local core = require("apisix.core")
 local utils = require("apisix.admin.utils")
+local apisix_ssl = require("apisix.ssl")
 local setmetatable = setmetatable
 local tostring = tostring
 local type = type
@@ -37,7 +38,21 @@ local no_id_res = {
 }
 
 
-function _M:check_conf(id, conf, need_id)
+local function split_typ_and_id(id, sub_path)
+    local uri_segs = core.utils.split_uri(sub_path)
+    local typ = id
+    local id = nil
+    if #uri_segs > 0 then
+        id = uri_segs[1]
+    end
+    return typ, id
+end
+
+
+function _M:check_conf(id, conf, need_id, typ)
+    if self.name == "secrets" then
+        id = typ .. "/" .. id
+    end
     -- check if missing configurations
     if not conf then
         return nil, {error_msg = "missing configurations"}
@@ -61,11 +76,14 @@ function _M:check_conf(id, conf, need_id)
         conf.id = id
     end
 
-    core.log.info("schema: ", core.json.delay_encode(self.schema))
     core.log.info("conf  : ", core.json.delay_encode(conf))
 
     -- check the resource own rules
-    local ok, err = self.checker(id, conf, need_id, self.schema)
+    if self.name ~= "secrets" then
+        core.log.info("schema: ", core.json.delay_encode(self.schema))
+    end
+
+    local ok, err = self.checker(id, conf, need_id, self.schema, typ)
 
     if not ok then
         return ok, err
@@ -79,13 +97,22 @@ function _M:check_conf(id, conf, need_id)
 end
 
 
-function _M:get(id)
+function _M:get(id, conf, sub_path)
     if core.table.array_find(self.unsupported_methods, "get") then
         return 405, {error_msg = "not supported `GET` method for " .. 
self.kind}
     end
 
     local key = "/" .. self.name
+    local typ = nil
+    if self.name == "secrets" then
+        key = key .. "/"
+        typ, id = split_typ_and_id(id, sub_path)
+    end
+
     if id then
+        if self.name == "secrets" then
+            key = key .. typ
+        end
         key = key .. "/" .. id
     end
 
@@ -95,6 +122,13 @@ function _M:get(id)
         return 503, {error_msg = err}
     end
 
+    if self.name == "ssls" then
+        -- not return private key for security
+        if res.body and res.body.node and res.body.node.value then
+            res.body.node.value.key = nil
+        end
+    end
+
     utils.fix_count(res.body, id)
     return res.status, res.body
 end
@@ -110,6 +144,17 @@ function _M:post(id, conf, sub_path, args)
         return 400, err
     end
 
+    if self.name == "ssls" then
+        -- encrypt private key
+        conf.key = apisix_ssl.aes_encrypt_pkey(conf.key)
+
+        if conf.keys then
+            for i = 1, #conf.keys do
+                conf.keys[i] = apisix_ssl.aes_encrypt_pkey(conf.keys[i])
+            end
+        end
+    end
+
     local key = "/" .. self.name
     utils.inject_timestamp(conf)
 
@@ -133,13 +178,35 @@ function _M:put(id, conf, sub_path, args)
         return 405, {error_msg = "not supported `PUT` method for " .. 
self.kind}
     end
 
+    local key = "/" .. self.name
+    local typ = nil
+    if self.name == "secrets" then
+        typ, id = split_typ_and_id(id, sub_path)
+        key = key .. "/" .. typ
+    end
+
     local need_id = not no_id_res[self.name]
-    local id, err = self:check_conf(id, conf, need_id)
-    if not id then
+    local ok, err = self:check_conf(id, conf, need_id, typ)
+    if not ok then
         return 400, err
     end
 
-    local key = "/" .. self.name .. "/" .. id
+    if self.name ~= "secrets" then
+        id = ok
+    end
+
+    if self.name == "ssls" then
+        -- encrypt private key
+        conf.key = apisix_ssl.aes_encrypt_pkey(conf.key)
+
+        if conf.keys then
+            for i = 1, #conf.keys do
+                conf.keys[i] = apisix_ssl.aes_encrypt_pkey(conf.keys[i])
+            end
+        end
+    end
+
+    key = key .. "/" .. id
 
     if self.name ~= "plugin_metadata" then
         local ok, err = utils.inject_conf_with_prev_conf(self.kind, key, conf)
@@ -162,16 +229,30 @@ function _M:put(id, conf, sub_path, args)
     return res.status, res.body
 end
 
-
-function _M:delete(id)
+-- Keep the unused conf to make the args list consistent with other methods
+function _M:delete(id, conf, sub_path)
     if core.table.array_find(self.unsupported_methods, "delete") then
         return 405, {error_msg = "not supported `DELETE` method for " .. 
self.kind}
     end
 
+    local key = "/" .. self.name
+    local typ = nil
+    if self.name == "secrets" then
+        typ, id = split_typ_and_id(id, sub_path)
+    end
+
     if not id then
         return 400, {error_msg = "missing " .. self.kind .. " id"}
     end
 
+    -- core.log.error("failed to delete ", self.kind, "[", key, "] in etcd: ", 
err)
+
+    if self.name == "secrets" then
+        key = key .. "/" .. typ
+    end
+
+    key = key .. "/" .. id
+
     if self.delete_checker then
         local code, err = self.delete_checker(id)
         if err then
@@ -179,7 +260,6 @@ function _M:delete(id)
         end
     end
 
-    local key = "/" .. self.name .. "/" .. id
     local res, err = core.etcd.delete(key)
     if not res then
         core.log.error("failed to delete ", self.kind, "[", key, "] in etcd: 
", err)
@@ -195,10 +275,28 @@ function _M:patch(id, conf, sub_path, args)
         return 405, {error_msg = "not supported `PATCH` method for " .. 
self.kind}
     end
 
+    local key = "/" .. self.name
+    local typ = nil
+    if self.name == "secrets" then
+        local uri_segs = core.utils.split_uri(sub_path)
+        if #uri_segs < 2 then
+            return 400, {error_msg = "no secret id and/or sub path in uri"}
+        end
+        typ = id
+        id = uri_segs[1]
+        sub_path = core.table.concat(uri_segs, "/", 2)
+    end
+
     if not id then
         return 400, {error_msg = "missing " .. self.kind .. " id"}
     end
 
+    if self.name == "secrets" then
+        key = key .. "/" .. typ
+    end
+
+    key = key .. "/" .. id
+
     if conf == nil then
         return 400, {error_msg = "missing new configuration"}
     end
@@ -209,11 +307,6 @@ function _M:patch(id, conf, sub_path, args)
         end
     end
 
-    local key = "/" .. self.name
-    if id then
-        key = key .. "/" .. id
-    end
-
     local res_old, err = core.etcd.get(key)
     if not res_old then
         core.log.error("failed to get ", self.kind, " [", key, "] in etcd: ", 
err)
@@ -229,6 +322,15 @@ function _M:patch(id, conf, sub_path, args)
     local modified_index = res_old.body.node.modifiedIndex
 
     if sub_path and sub_path ~= "" then
+        if self.name == "ssls" then
+            if sub_path == "key" then
+                conf = apisix_ssl.aes_encrypt_pkey(conf)
+            elseif sub_path == "keys" then
+                for i = 1, #conf do
+                    conf[i] = apisix_ssl.aes_encrypt_pkey(conf[i])
+                end
+            end
+        end
         local code, err, node_val = core.table.patch(node_value, sub_path, 
conf)
         node_value = node_val
         if code then
@@ -236,14 +338,25 @@ function _M:patch(id, conf, sub_path, args)
         end
         utils.inject_timestamp(node_value, nil, true)
     else
+        if self.name == "ssls" then
+            if conf.key then
+                conf.key = apisix_ssl.aes_encrypt_pkey(conf.key)
+            end
+
+            if conf.keys then
+                for i = 1, #conf.keys do
+                    conf.keys[i] = apisix_ssl.aes_encrypt_pkey(conf.keys[i])
+                end
+            end
+        end
         node_value = core.table.merge(node_value, conf)
         utils.inject_timestamp(node_value, nil, conf)
     end
 
     core.log.info("new conf: ", core.json.delay_encode(node_value, true))
 
-    local id, err = self:check_conf(id, node_value, true)
-    if not id then
+    local ok, err = self:check_conf(id, node_value, true, typ)
+    if not ok then
         return 400, err
     end
 
diff --git a/apisix/admin/secrets.lua b/apisix/admin/secrets.lua
index 362c9517b..b149ef0dd 100644
--- a/apisix/admin/secrets.lua
+++ b/apisix/admin/secrets.lua
@@ -17,39 +17,12 @@
 local require = require
 
 local core = require("apisix.core")
-local utils = require("apisix.admin.utils")
+local resource = require("apisix.admin.resource")
 
-local type = type
-local tostring = tostring
 local pcall = pcall
 
 
-local _M = {
-    need_v3_filter = true,
-}
-
-
-local function check_conf(id, conf, need_id, typ)
-    if not conf then
-        return nil, {error_msg = "missing configurations"}
-    end
-
-    id = id or conf.id
-    if need_id and not id then
-        return nil, {error_msg = "missing id"}
-    end
-
-    if not need_id and id then
-        return nil, {error_msg = "wrong id, do not need it"}
-    end
-
-    if need_id and conf.id and tostring(conf.id) ~= tostring(id) then
-        return nil, {error_msg = "wrong id"}
-    end
-
-    conf.id = id
-
-    core.log.info("conf: ", core.json.delay_encode(conf))
+local function check_conf(id, conf, need_id, schema, typ)
     local ok, secret_manager = pcall(require, "apisix.secret." .. typ)
     if not ok then
         return false, {error_msg = "invalid secret manager: " .. typ}
@@ -64,149 +37,9 @@ local function check_conf(id, conf, need_id, typ)
 end
 
 
-local function split_typ_and_id(id, sub_path)
-    local uri_segs = core.utils.split_uri(sub_path)
-    local typ = id
-    local id = nil
-    if #uri_segs > 0 then
-        id = uri_segs[1]
-    end
-    return typ, id
-end
-
-
-function _M.put(id, conf, sub_path)
-    local typ, id = split_typ_and_id(id, sub_path)
-    if not id then
-        return 400, {error_msg = "no secret id in uri"}
-    end
-
-    local ok, err = check_conf(typ .. "/" .. id, conf, true, typ)
-    if not ok then
-        return 400, err
-    end
-
-    local key = "/secrets/" .. typ .. "/" .. id
-
-    local ok, err = utils.inject_conf_with_prev_conf("secrets", key, conf)
-    if not ok then
-        return 503, {error_msg = err}
-    end
-
-    local res, err = core.etcd.set(key, conf)
-    if not res then
-        core.log.error("failed to put secret [", key, "]: ", err)
-        return 503, {error_msg = err}
-    end
-
-    return res.status, res.body
-end
-
-
-function _M.get(id, conf, sub_path)
-    local typ, id = split_typ_and_id(id, sub_path)
-
-    local key = "/secrets/"
-    if id then
-        key = key .. typ
-        key = key .. "/" .. id
-    end
-
-    local res, err = core.etcd.get(key, not id)
-    if not res then
-        core.log.error("failed to get secret [", key, "]: ", err)
-        return 503, {error_msg = err}
-    end
-
-    utils.fix_count(res.body, id)
-    return res.status, res.body
-end
-
-
-function _M.delete(id, conf, sub_path)
-    local typ, id = split_typ_and_id(id, sub_path)
-    if not id then
-        return 400, {error_msg = "no secret id in uri"}
-    end
-
-    local key = "/secrets/" .. typ .. "/" .. id
-
-    local res, err = core.etcd.delete(key)
-    if not res then
-        core.log.error("failed to delete secret [", key, "]: ", err)
-        return 503, {error_msg = err}
-    end
-
-    return res.status, res.body
-end
-
-
-function _M.patch(id, conf, sub_path)
-    local uri_segs = core.utils.split_uri(sub_path)
-    if #uri_segs < 2 then
-        return 400, {error_msg = "no secret id and/or sub path in uri"}
-    end
-    local typ = id
-    id = uri_segs[1]
-    sub_path = core.table.concat(uri_segs, "/", 2)
-
-    if not id then
-        return 400, {error_msg = "missing secret id"}
-    end
-
-    if not conf then
-        return 400, {error_msg = "missing new configuration"}
-    end
-
-    if not sub_path or sub_path == "" then
-        if type(conf) ~= "table"  then
-            return 400, {error_msg = "invalid configuration"}
-        end
-    end
-
-    local key = "/secrets/" .. typ .. "/" .. id
-    local res_old, err = core.etcd.get(key)
-    if not res_old then
-        core.log.error("failed to get secret [", key, "]: ", err)
-        return 503, {error_msg = err}
-    end
-
-    if res_old.status ~= 200 then
-        return res_old.status, res_old.body
-    end
-    core.log.info("key: ", key, " old value: ",
-                  core.json.delay_encode(res_old, true))
-
-    local node_value = res_old.body.node.value
-    local modified_index = res_old.body.node.modifiedIndex
-
-    if sub_path and sub_path ~= "" then
-        local code, err, node_val = core.table.patch(node_value, sub_path, 
conf)
-        node_value = node_val
-        if code then
-            return code, err
-        end
-        utils.inject_timestamp(node_value, nil, true)
-    else
-        node_value = core.table.merge(node_value, conf)
-        utils.inject_timestamp(node_value, nil, conf)
-    end
-
-    core.log.info("new conf: ", core.json.delay_encode(node_value, true))
-
-    local ok, err = check_conf(typ .. "/" .. id, node_value, true, typ)
-    if not ok then
-        return 400, {error_msg = err}
-    end
-
-    local res, err = core.etcd.atomic_set(key, node_value, nil, modified_index)
-    if not res then
-        core.log.error("failed to set new secret[", key, "]: ", err)
-        return 503, {error_msg = err}
-    end
-
-    return res.status, res.body
-end
-
-
-return _M
+return resource.new({
+    name = "secrets",
+    kind = "secret",
+    checker = check_conf,
+    unsupported_methods = {"post"}
+})
diff --git a/apisix/admin/ssl.lua b/apisix/admin/ssl.lua
index 35f80a7ff..d13d08ffa 100644
--- a/apisix/admin/ssl.lua
+++ b/apisix/admin/ssl.lua
@@ -15,40 +15,11 @@
 -- limitations under the License.
 --
 local core              = require("apisix.core")
-local utils             = require("apisix.admin.utils")
+local resource          = require("apisix.admin.resource")
 local apisix_ssl        = require("apisix.ssl")
-local tostring          = tostring
-local type              = type
 
-local _M = {
-    version = 0.1,
-    need_v3_filter = true,
-}
-
-
-local function check_conf(id, conf, need_id)
-    if not conf then
-        return nil, {error_msg = "missing configurations"}
-    end
-
-    id = id or conf.id
-    if need_id and not id then
-        return nil, {error_msg = "missing ssl id"}
-    end
-
-    if not need_id and id then
-        return nil, {error_msg = "wrong ssl id, do not need it"}
-    end
-
-    if need_id and conf.id and tostring(conf.id) ~= tostring(id) then
-        return nil, {error_msg = "wrong ssl id"}
-    end
-
-    conf.id = id
-
-    core.log.info("schema: ", core.json.delay_encode(core.schema.ssl))
-    core.log.info("conf: ", core.json.delay_encode(conf))
 
+local function check_conf(id, conf, need_id, schema)
     local ok, err = apisix_ssl.check_ssl_conf(false, conf)
     if not ok then
         return nil, {error_msg = err}
@@ -58,183 +29,9 @@ local function check_conf(id, conf, need_id)
 end
 
 
-function _M.put(id, conf)
-    local id, err = check_conf(id, conf, true)
-    if not id then
-        return 400, err
-    end
-
-    -- encrypt private key
-    conf.key = apisix_ssl.aes_encrypt_pkey(conf.key)
-
-    if conf.keys then
-        for i = 1, #conf.keys do
-            conf.keys[i] = apisix_ssl.aes_encrypt_pkey(conf.keys[i])
-        end
-    end
-
-    local key = "/ssls/" .. id
-
-    local ok, err = utils.inject_conf_with_prev_conf("ssl", key, conf)
-    if not ok then
-        return 503, {error_msg = err}
-    end
-
-    local res, err = core.etcd.set(key, conf)
-    if not res then
-        core.log.error("failed to put ssl[", key, "]: ", err)
-        return 503, {error_msg = err}
-    end
-
-    return res.status, res.body
-end
-
-
-function _M.get(id)
-    local key = "/ssls"
-    if id then
-        key = key .. "/" .. id
-    end
-
-    local res, err = core.etcd.get(key, not id)
-    if not res then
-        core.log.error("failed to get ssl[", key, "]: ", err)
-        return 503, {error_msg = err}
-    end
-
-    -- not return private key for security
-    if res.body and res.body.node and res.body.node.value then
-        res.body.node.value.key = nil
-    end
-
-    utils.fix_count(res.body, id)
-    return res.status, res.body
-end
-
-
-function _M.post(id, conf)
-    local id, err = check_conf(id, conf, false)
-    if not id then
-        return 400, err
-    end
-
-    -- encrypt private key
-    conf.key = apisix_ssl.aes_encrypt_pkey(conf.key)
-
-    if conf.keys then
-        for i = 1, #conf.keys do
-            conf.keys[i] = apisix_ssl.aes_encrypt_pkey(conf.keys[i])
-        end
-    end
-
-    local key = "/ssls"
-    utils.inject_timestamp(conf)
-    local res, err = core.etcd.push(key, conf)
-    if not res then
-        core.log.error("failed to post ssl[", key, "]: ", err)
-        return 503, {error_msg = err}
-    end
-
-    return res.status, res.body
-end
-
-
-function _M.delete(id)
-    if not id then
-        return 400, {error_msg = "missing ssl id"}
-    end
-
-    local key = "/ssls/" .. id
-    -- core.log.info("key: ", key)
-    local res, err = core.etcd.delete(key)
-    if not res then
-        core.log.error("failed to delete ssl[", key, "]: ", err)
-        return 503, {error_msg = err}
-    end
-
-    return res.status, res.body
-end
-
-
-function _M.patch(id, conf, sub_path)
-    if not id then
-        return 400, {error_msg = "missing route id"}
-    end
-
-    if not conf then
-        return 400, {error_msg = "missing new configuration"}
-    end
-
-    if type(conf) ~= "table"  then
-        return 400, {error_msg = "invalid configuration"}
-    end
-
-    local key = "/ssls"
-    if id then
-        key = key .. "/" .. id
-    end
-
-    local res_old, err = core.etcd.get(key)
-    if not res_old then
-        core.log.error("failed to get ssl [", key, "] in etcd: ", err)
-        return 503, {error_msg = err}
-    end
-
-    if res_old.status ~= 200 then
-        return res_old.status, res_old.body
-    end
-    core.log.info("key: ", key, " old value: ",
-                  core.json.delay_encode(res_old, true))
-
-
-    local node_value = res_old.body.node.value
-    local modified_index = res_old.body.node.modifiedIndex
-
-    if sub_path and sub_path ~= "" then
-        if sub_path == "key" then
-            conf = apisix_ssl.aes_encrypt_pkey(conf)
-        elseif sub_path == "keys" then
-            for i = 1, #conf do
-                conf[i] = apisix_ssl.aes_encrypt_pkey(conf[i])
-            end
-        end
-
-        local code, err, node_val = core.table.patch(node_value, sub_path, 
conf)
-        node_value = node_val
-        if code then
-            return code, err
-        end
-        utils.inject_timestamp(node_value, nil, true)
-    else
-        if conf.key then
-            conf.key = apisix_ssl.aes_encrypt_pkey(conf.key)
-        end
-
-        if conf.keys then
-            for i = 1, #conf.keys do
-                conf.keys[i] = apisix_ssl.aes_encrypt_pkey(conf.keys[i])
-            end
-        end
-
-        node_value = core.table.merge(node_value, conf)
-        utils.inject_timestamp(node_value, nil, conf)
-    end
-
-    core.log.info("new ssl conf: ", core.json.delay_encode(node_value, true))
-
-    local id, err = check_conf(id, node_value, true)
-    if not id then
-        return 400, err
-    end
-
-    local res, err = core.etcd.atomic_set(key, node_value, nil, modified_index)
-    if not res then
-        core.log.error("failed to set new ssl[", key, "] to etcd: ", err)
-        return 503, {error_msg = err}
-    end
-
-    return res.status, res.body
-end
-
-
-return _M
+return resource.new({
+    name = "ssls",
+    kind = "ssl",
+    schema = core.schema.ssl,
+    checker = check_conf
+})

Reply via email to