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 22be6d08c refactor(admin): 
stream_routes/upstreams/protos/services/global_rules/consumer_groups/plugin_configs
 (#8661)
22be6d08c is described below

commit 22be6d08cef7de16c3f8a303e75c1872378c3dee
Author: dongjunduo <[email protected]>
AuthorDate: Mon Jan 30 19:30:17 2023 -0600

    refactor(admin): 
stream_routes/upstreams/protos/services/global_rules/consumer_groups/plugin_configs
 (#8661)
    
    Fixes https://github.com/apache/apisix/issues/8569
---
 apisix/admin/consumer_group.lua | 155 +++--------------------------------
 apisix/admin/global_rules.lua   | 155 +++--------------------------------
 apisix/admin/init.lua           |  12 ++-
 apisix/admin/plugin_config.lua  | 155 +++--------------------------------
 apisix/admin/proto.lua          | 114 ++++----------------------
 apisix/admin/resource.lua       |  57 ++++++++++++-
 apisix/admin/routes.lua         |   2 +-
 apisix/admin/services.lua       | 177 +++-------------------------------------
 apisix/admin/stream_routes.lua  | 119 +++------------------------
 apisix/admin/upstreams.lua      | 175 +++------------------------------------
 10 files changed, 150 insertions(+), 971 deletions(-)

diff --git a/apisix/admin/consumer_group.lua b/apisix/admin/consumer_group.lua
index 6e1e41df4..9aed58f06 100644
--- a/apisix/admin/consumer_group.lua
+++ b/apisix/admin/consumer_group.lua
@@ -16,40 +16,15 @@
 --
 local core = require("apisix.core")
 local consumers = require("apisix.consumer").consumers
-local utils = require("apisix.admin.utils")
+local resource = require("apisix.admin.resource")
 local schema_plugin = require("apisix.admin.plugins").check_schema
 local type = type
 local tostring = tostring
 local ipairs = ipairs
 
 
-local _M = {
-    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 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 ok, err = core.schema.check(core.schema.consumer_group, conf)
+local function check_conf(id, conf, need_id, schema)
+    local ok, err = core.schema.check(schema, conf)
     if not ok then
         return nil, {error_msg = "invalid configuration: " .. err}
     end
@@ -63,50 +38,7 @@ local function check_conf(id, conf, need_id)
 end
 
 
-function _M.put(id, conf)
-    local ok, err = check_conf(id, conf, true)
-    if not ok then
-        return 400, err
-    end
-
-    local key = "/consumer_groups/" .. id
-
-    local ok, err = utils.inject_conf_with_prev_conf("consumer_group", 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 consumer group[", key, "]: ", err)
-        return 503, {error_msg = err}
-    end
-
-    return res.status, res.body
-end
-
-
-function _M.get(id)
-    local key = "/consumer_groups"
-    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 consumer group[", key, "]: ", err)
-        return 503, {error_msg = err}
-    end
-
-    utils.fix_count(res.body, id)
-    return res.status, res.body
-end
-
-
-function _M.delete(id)
-    if not id then
-        return 400, {error_msg = "missing consumer group id"}
-    end
-
+local function delete_checker(id)
     local consumers, consumers_ver = consumers()
     if consumers_ver and consumers then
         for _, consumer in ipairs(consumers) do
@@ -120,76 +52,15 @@ function _M.delete(id)
         end
     end
 
-    local key = "/consumer_groups/" .. id
-    local res, err = core.etcd.delete(key)
-    if not res then
-        core.log.error("failed to delete consumer group[", 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 consumer group 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 = "/consumer_groups/" .. id
-    local res_old, err = core.etcd.get(key)
-    if not res_old then
-        core.log.error("failed to get consumer group [", 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(id, node_value, true)
-    if not ok 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 consumer group[", key, "]: ", err)
-        return 503, {error_msg = err}
-    end
-
-    return res.status, res.body
+    return nil, nil
 end
 
 
-return _M
+return resource.new({
+    name = "consumer_groups",
+    kind = "consumer group",
+    schema = core.schema.consumer_group,
+    checker = check_conf,
+    unsupported_methods = {"post"},
+    delete_checker = delete_checker
+})
diff --git a/apisix/admin/global_rules.lua b/apisix/admin/global_rules.lua
index 88d3d2af6..81db85052 100644
--- a/apisix/admin/global_rules.lua
+++ b/apisix/admin/global_rules.lua
@@ -15,41 +15,12 @@
 -- limitations under the License.
 --
 local core = require("apisix.core")
-local utils = require("apisix.admin.utils")
+local resource = require("apisix.admin.resource")
 local schema_plugin = require("apisix.admin.plugins").check_schema
-local type = type
-local tostring = tostring
 
 
-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 route id"}
-    end
-
-    if not need_id and id then
-        return nil, {error_msg = "wrong route id, do not need it"}
-    end
-
-    if need_id and conf.id and tostring(conf.id) ~= tostring(id) then
-        return nil, {error_msg = "wrong route id"}
-    end
-
-    conf.id = id
-
-    core.log.info("schema: ", core.json.delay_encode(core.schema.global_rule))
-    core.log.info("conf  : ", core.json.delay_encode(conf))
-    local ok, err = core.schema.check(core.schema.global_rule, conf)
+local function check_conf(id, conf, need_id, schema)
+    local ok, err = core.schema.check(schema, conf)
     if not ok then
         return nil, {error_msg = "invalid configuration: " .. err}
     end
@@ -63,116 +34,10 @@ local function check_conf(id, conf, need_id)
 end
 
 
-function _M.put(id, conf)
-    local ok, err = check_conf(id, conf, true)
-    if not ok then
-        return 400, err
-    end
-
-    local key = "/global_rules/" .. id
-
-    local ok, err = utils.inject_conf_with_prev_conf("global_rule", 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 global rule[", key, "]: ", err)
-        return 503, {error_msg = err}
-    end
-
-    return res.status, res.body
-end
-
-
-function _M.get(id)
-    local key = "/global_rules"
-    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 global rule[", key, "]: ", err)
-        return 503, {error_msg = err}
-    end
-
-    utils.fix_count(res.body, id)
-    return res.status, res.body
-end
-
-
-function _M.delete(id)
-    local key = "/global_rules/" .. id
-    -- core.log.info("key: ", key)
-    local res, err = core.etcd.delete(key)
-    if not res then
-        core.log.error("failed to delete global rule[", 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 global rule 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 = "/global_rules/" .. id
-    local res_old, err = core.etcd.get(key)
-    if not res_old then
-        core.log.error("failed to get global rule [", 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(id, node_value, true)
-    if not ok 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 global rule[", key, "]: ", err)
-        return 503, {error_msg = err}
-    end
-
-    return res.status, res.body
-end
-
-
-return _M
+return resource.new({
+    name = "global_rules",
+    kind = "global rule",
+    schema = core.schema.global_rule,
+    checker = check_conf,
+    unsupported_methods = {"post"}
+})
diff --git a/apisix/admin/init.lua b/apisix/admin/init.lua
index 15c4ee6cb..e96b05c33 100644
--- a/apisix/admin/init.lua
+++ b/apisix/admin/init.lua
@@ -199,7 +199,17 @@ local function run()
     end
 
     local code, data
-    if seg_res == "routes" then
+    local refactored_resources = {
+        "routes",
+        "stream_routes",
+        "upstreams",
+        "protos",
+        "global_rules",
+        "services",
+        "consumer_groups",
+        "plugin_configs",
+    }
+    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
         code, data = resource[method](seg_id, req_body, seg_sub_path, uri_args)
diff --git a/apisix/admin/plugin_config.lua b/apisix/admin/plugin_config.lua
index 708de0164..153a7bd9e 100644
--- a/apisix/admin/plugin_config.lua
+++ b/apisix/admin/plugin_config.lua
@@ -16,40 +16,15 @@
 --
 local core = require("apisix.core")
 local get_routes = require("apisix.router").http_routes
-local utils = require("apisix.admin.utils")
+local resource = require("apisix.admin.resource")
 local schema_plugin = require("apisix.admin.plugins").check_schema
 local type = type
 local tostring = tostring
 local ipairs = ipairs
 
 
-local _M = {
-    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 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 ok, err = core.schema.check(core.schema.plugin_config, conf)
+local function check_conf(id, conf, need_id, schema)
+    local ok, err = core.schema.check(schema, conf)
     if not ok then
         return nil, {error_msg = "invalid configuration: " .. err}
     end
@@ -63,50 +38,7 @@ local function check_conf(id, conf, need_id)
 end
 
 
-function _M.put(id, conf)
-    local ok, err = check_conf(id, conf, true)
-    if not ok then
-        return 400, err
-    end
-
-    local key = "/plugin_configs/" .. id
-
-    local ok, err = utils.inject_conf_with_prev_conf("plugin_config", 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 plugin config[", key, "]: ", err)
-        return 503, {error_msg = err}
-    end
-
-    return res.status, res.body
-end
-
-
-function _M.get(id)
-    local key = "/plugin_configs"
-    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 plugin config[", key, "]: ", err)
-        return 503, {error_msg = err}
-    end
-
-    utils.fix_count(res.body, id)
-    return res.status, res.body
-end
-
-
-function _M.delete(id)
-    if not id then
-        return 400, {error_msg = "missing plugin config id"}
-    end
-
+local function delete_checker(id)
     local routes, routes_ver = get_routes()
     if routes_ver and routes then
         for _, route in ipairs(routes) do
@@ -120,76 +52,15 @@ function _M.delete(id)
         end
     end
 
-    local key = "/plugin_configs/" .. id
-    local res, err = core.etcd.delete(key)
-    if not res then
-        core.log.error("failed to delete plugin config[", 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 plugin config 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 = "/plugin_configs/" .. id
-    local res_old, err = core.etcd.get(key)
-    if not res_old then
-        core.log.error("failed to get plugin config [", 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(id, node_value, true)
-    if not ok 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 plugin config[", key, "]: ", err)
-        return 503, {error_msg = err}
-    end
-
-    return res.status, res.body
+    return nil, nil
 end
 
 
-return _M
+return resource.new({
+    name = "plugin_configs",
+    kind = "plugin config",
+    schema = core.schema.plugin_config,
+    checker = check_conf,
+    unsupported_methods = {"post"},
+    delete_checker = delete_checker
+})
diff --git a/apisix/admin/proto.lua b/apisix/admin/proto.lua
index d00c21653..de4d24e23 100644
--- a/apisix/admin/proto.lua
+++ b/apisix/admin/proto.lua
@@ -17,40 +17,15 @@
 local type = type
 local ipairs = ipairs
 local core = require("apisix.core")
-local utils = require("apisix.admin.utils")
+local resource = require("apisix.admin.resource")
 local get_routes = require("apisix.router").http_routes
 local get_services = require("apisix.http.service").services
 local compile_proto = 
require("apisix.plugins.grpc-transcode.proto").compile_proto
 local tostring = tostring
 
 
-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 proto id"}
-    end
-
-    if not need_id and id then
-        return nil, {error_msg = "wrong proto id, do not need it"}
-    end
-
-    if need_id and conf.id and tostring(conf.id) ~= tostring(id) then
-        return nil, {error_msg = "wrong proto id"}
-    end
-
-    core.log.info("schema: ", core.json.delay_encode(core.schema.proto))
-    core.log.info("conf  : ", core.json.delay_encode(conf))
-    local ok, err = core.schema.check(core.schema.proto, conf)
+local function check_conf(id, conf, need_id, schema)
+    local ok, err = core.schema.check(schema, conf)
     if not ok then
         return nil, {error_msg = "invalid configuration: " .. err}
     end
@@ -60,67 +35,10 @@ local function check_conf(id, conf, need_id)
         return nil, {error_msg = "invalid content: " .. err}
     end
 
-    return need_id and id or true
-end
-
-
-function _M.put(id, conf)
-    local id, err = check_conf(id, conf, true)
-    if not id then
-        return 400, err
-    end
-
-    local key = "/protos/" .. id
-
-    local ok, err = utils.inject_conf_with_prev_conf("proto", 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 proto[", key, "]: ", err)
-        return 503, {error_msg = err}
-    end
-
-    return res.status, res.body
-end
-
-
-function _M.get(id)
-    local key = "/protos"
-    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 proto[", key, "]: ", err)
-        return 503, {error_msg = err}
-    end
-
-    utils.fix_count(res.body, id)
-    return res.status, res.body
+    return true
 end
 
 
-function _M.post(id, conf)
-    local id, err = check_conf(id, conf, false)
-    if not id then
-        return 400, err
-    end
-
-    local key = "/protos"
-    utils.inject_timestamp(conf)
-    local res, err = core.etcd.push(key, conf)
-    if not res then
-        core.log.error("failed to post proto[", key, "]: ", err)
-        return 503, {error_msg = err}
-    end
-
-    return res.status, res.body
-end
-
 local function check_proto_used(plugins, deleting, ptype, pid)
 
     --core.log.info("check_proto_used plugins: ", 
core.json.delay_encode(plugins, true))
@@ -140,10 +58,7 @@ local function check_proto_used(plugins, deleting, ptype, 
pid)
     return true
 end
 
-function _M.delete(id)
-    if not id then
-        return 400, {error_msg = "missing proto id"}
-    end
+local function delete_checker(id)
     core.log.info("proto delete: ", id)
 
     local routes, routes_ver = get_routes()
@@ -182,16 +97,15 @@ function _M.delete(id)
     end
     core.log.info("proto delete service ref check pass: ", id)
 
-    local key = "/protos/" .. id
-    -- core.log.info("key: ", key)
-    local res, err = core.etcd.delete(key)
-    if not res then
-        core.log.error("failed to delete proto[", key, "]: ", err)
-        return 503, {error_msg = err}
-    end
-
-    return res.status, res.body
+    return nil, nil
 end
 
 
-return _M
+return resource.new({
+    name = "protos",
+    kind = "proto",
+    schema = core.schema.proto,
+    checker = check_conf,
+    unsupported_methods = {"patch"},
+    delete_checker = delete_checker
+})
diff --git a/apisix/admin/resource.lua b/apisix/admin/resource.lua
index c4aa21b35..6746c055c 100644
--- a/apisix/admin/resource.lua
+++ b/apisix/admin/resource.lua
@@ -57,11 +57,21 @@ function _M:check_conf(id, conf, need_id)
     core.log.info("conf  : ", core.json.delay_encode(conf))
 
     -- check the resource own rules
-    return self.checker(id, conf, need_id, self.schema)
+    local ok, err = self.checker(id, conf, need_id, self.schema)
+
+    if not ok then
+        return ok, err
+    else
+        return need_id and id or true
+    end
 end
 
 
 function _M:get(id)
+    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
     if id then
         key = key .. "/" .. id
@@ -79,6 +89,10 @@ end
 
 
 function _M:post(id, conf, sub_path, args)
+    if core.table.array_find(self.unsupported_methods, "post") then
+        return 405, {error_msg = "not supported `POST` method for " .. 
self.kind}
+    end
+
     local id, err = self:check_conf(id, conf, false)
     if not id then
         return 400, err
@@ -86,7 +100,13 @@ function _M:post(id, conf, sub_path, args)
 
     local key = "/" .. self.name
     utils.inject_timestamp(conf)
-    local res, err = core.etcd.push(key, conf, args.ttl)
+
+    local ttl = nil
+    if args then
+        ttl = args.ttl
+    end
+
+    local res, err = core.etcd.push(key, conf, ttl)
     if not res then
         core.log.error("failed to post ", self.kind, "[", key, "] to etcd: ", 
err)
         return 503, {error_msg = err}
@@ -97,6 +117,10 @@ end
 
 
 function _M:put(id, conf, sub_path, args)
+    if core.table.array_find(self.unsupported_methods, "put") then
+        return 405, {error_msg = "not supported `PUT` method for " .. 
self.kind}
+    end
+
     local id, err = self:check_conf(id, conf, true)
     if not id then
         return 400, err
@@ -109,7 +133,12 @@ function _M:put(id, conf, sub_path, args)
         return 503, {error_msg = err}
     end
 
-    local res, err = core.etcd.set(key, conf, args.ttl)
+    local ttl = nil
+    if args then
+        ttl = args.ttl
+    end
+
+    local res, err = core.etcd.set(key, conf, ttl)
     if not res then
         core.log.error("failed to put ", self.kind, "[", key, "] to etcd: ", 
err)
         return 503, {error_msg = err}
@@ -120,10 +149,21 @@ end
 
 
 function _M:delete(id)
+    if core.table.array_find(self.unsupported_methods, "delete") then
+        return 405, {error_msg = "not supported `DELETE` method for " .. 
self.kind}
+    end
+
     if not id then
         return 400, {error_msg = "missing " .. self.kind .. " id"}
     end
 
+    if self.delete_checker then
+        local code, err = self.delete_checker(id)
+        if err then
+            return code, err
+        end
+    end
+
     local key = "/" .. self.name .. "/" .. id
     local res, err = core.etcd.delete(key)
     if not res then
@@ -136,6 +176,10 @@ end
 
 
 function _M:patch(id, conf, sub_path, args)
+    if core.table.array_find(self.unsupported_methods, "patch") then
+        return 405, {error_msg = "not supported `PATCH` method for " .. 
self.kind}
+    end
+
     if not id then
         return 400, {error_msg = "missing " .. self.kind .. " id"}
     end
@@ -188,7 +232,12 @@ function _M:patch(id, conf, sub_path, args)
         return 400, err
     end
 
-    local res, err = core.etcd.atomic_set(key, node_value, args.ttl, 
modified_index)
+    local ttl = nil
+    if args then
+        ttl = args.ttl
+    end
+
+    local res, err = core.etcd.atomic_set(key, node_value, ttl, modified_index)
     if not res then
         core.log.error("failed to set new ", self.kind, "[", key, "] to etcd: 
", err)
         return 503, {error_msg = err}
diff --git a/apisix/admin/routes.lua b/apisix/admin/routes.lua
index 06f27fa0c..04f72f22d 100644
--- a/apisix/admin/routes.lua
+++ b/apisix/admin/routes.lua
@@ -135,7 +135,7 @@ local function check_conf(id, conf, need_id, schema)
         end
     end
 
-    return need_id and id or true
+    return true
 end
 
 
diff --git a/apisix/admin/services.lua b/apisix/admin/services.lua
index 505ab2ccd..dc14bda44 100644
--- a/apisix/admin/services.lua
+++ b/apisix/admin/services.lua
@@ -17,43 +17,16 @@
 local core = require("apisix.core")
 local get_routes = require("apisix.router").http_routes
 local apisix_upstream = require("apisix.upstream")
+local resource = require("apisix.admin.resource")
 local schema_plugin = require("apisix.admin.plugins").check_schema
-local utils = require("apisix.admin.utils")
 local tostring = tostring
 local ipairs = ipairs
 local type = type
 local loadstring = loadstring
 
 
-local _M = {
-    version = 0.3,
-    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 service id"}
-    end
-
-    if not need_id and id then
-        return nil, {error_msg = "wrong service id, do not need it"}
-    end
-
-    if need_id and conf.id and tostring(conf.id) ~= tostring(id) then
-        return nil, {error_msg = "wrong service id"}
-    end
-
-    conf.id = id
-
-    core.log.info("schema: ", core.json.delay_encode(core.schema.service))
-    core.log.info("conf  : ", core.json.delay_encode(conf))
-    local ok, err = core.schema.check(core.schema.service, conf)
+local function check_conf(id, conf, need_id, schema)
+    local ok, err = core.schema.check(schema, conf)
     if not ok then
         return nil, {error_msg = "invalid configuration: " .. err}
     end
@@ -106,74 +79,11 @@ local function check_conf(id, conf, need_id)
         end
     end
 
-    return need_id and id or true
-end
-
-
-function _M.put(id, conf)
-    local id, err = check_conf(id, conf, true)
-    if not id then
-        return 400, err
-    end
-
-    local key = "/services/" .. id
-    core.log.info("key: ", key)
-
-    local ok, err = utils.inject_conf_with_prev_conf("service", 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 service[", key, "]: ", err)
-        return 503, {error_msg = err}
-    end
-
-    return res.status, res.body
-end
-
-
-function _M.get(id)
-    local key = "/services"
-    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 service[", key, "]: ", err)
-        return 503, {error_msg = err}
-    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
-
-    local key = "/services"
-    utils.inject_timestamp(conf)
-    local res, err = core.etcd.push(key, conf)
-    if not res then
-        core.log.error("failed to post service[", key, "]: ", err)
-        return 503, {error_msg = err}
-    end
-
-    return res.status, res.body
+    return true
 end
 
 
-function _M.delete(id)
-    if not id then
-        return 400, {error_msg = "missing service id"}
-    end
-
+local function delete_checker(id)
     local routes, routes_ver = get_routes()
     core.log.info("routes: ", core.json.delay_encode(routes, true))
     core.log.info("routes_ver: ", routes_ver)
@@ -189,75 +99,14 @@ function _M.delete(id)
         end
     end
 
-    local key = "/services/" .. id
-    local res, err = core.etcd.delete(key)
-    if not res then
-        core.log.error("failed to delete service[", 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 service 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 = "/services" .. "/" .. id
-    local res_old, err = core.etcd.get(key)
-    if not res_old then
-        core.log.error("failed to get service[", 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 value ", 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 service[", key, "]: ", err)
-        return 503, {error_msg = err}
-    end
-
-    return res.status, res.body
+    return nil, nil
 end
 
 
-return _M
+return resource.new({
+    name = "services",
+    kind = "service",
+    schema = core.schema.service,
+    checker = check_conf,
+    delete_checker = delete_checker
+})
diff --git a/apisix/admin/stream_routes.lua b/apisix/admin/stream_routes.lua
index 51b944eba..c16a9a793 100644
--- a/apisix/admin/stream_routes.lua
+++ b/apisix/admin/stream_routes.lua
@@ -15,40 +15,12 @@
 -- limitations under the License.
 --
 local core = require("apisix.core")
-local utils = require("apisix.admin.utils")
+local resource = require("apisix.admin.resource")
 local stream_route_checker = 
require("apisix.stream.router.ip_port").stream_route_checker
-local tostring = tostring
 
 
-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 stream route id"}
-    end
-
-    if not need_id and id then
-        return nil, {error_msg = "wrong stream route id, do not need it"}
-    end
-
-    if need_id and conf.id and tostring(conf.id) ~= tostring(id) then
-        return nil, {error_msg = "wrong stream route id"}
-    end
-
-    conf.id = id
-
-    core.log.info("schema: ", core.json.delay_encode(core.schema.stream_route))
-    core.log.info("conf  : ", core.json.delay_encode(conf))
-    local ok, err = core.schema.check(core.schema.stream_route, conf)
+local function check_conf(id, conf, need_id, schema)
+    local ok, err = core.schema.check(schema, conf)
     if not ok then
         return nil, {error_msg = "invalid configuration: " .. err}
     end
@@ -75,83 +47,14 @@ local function check_conf(id, conf, need_id)
         return nil, {error_msg = err}
     end
 
-    return need_id and id or true
-end
-
-
-function _M.put(id, conf)
-    local id, err = check_conf(id, conf, true)
-    if not id then
-        return 400, err
-    end
-
-    local key = "/stream_routes/" .. id
-
-    local ok, err = utils.inject_conf_with_prev_conf("stream_routes", 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 stream route[", key, "]: ", err)
-        return 503, {error_msg = err}
-    end
-
-    return res.status, res.body
-end
-
-
-function _M.get(id)
-    local key = "/stream_routes"
-    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 stream route[", key, "]: ", err)
-        return 503, {error_msg = err}
-    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
-
-    local key = "/stream_routes"
-    utils.inject_timestamp(conf)
-    local res, err = core.etcd.push(key, conf)
-    if not res then
-        core.log.error("failed to post stream route[", 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 stream route id"}
-    end
-
-    local key = "/stream_routes/" .. id
-    -- core.log.info("key: ", key)
-    local res, err = core.etcd.delete(key)
-    if not res then
-        core.log.error("failed to delete stream route[", key, "]: ", err)
-        return 503, {error_msg = err}
-    end
-
-    return res.status, res.body
+    return true
 end
 
 
-return _M
+return resource.new({
+    name = "stream_routes",
+    kind = "stream route",
+    schema = core.schema.stream_route,
+    checker = check_conf,
+    unsupported_methods = {"patch"}
+})
diff --git a/apisix/admin/upstreams.lua b/apisix/admin/upstreams.lua
index 45a7199f4..a85d24d8d 100644
--- a/apisix/admin/upstreams.lua
+++ b/apisix/admin/upstreams.lua
@@ -18,115 +18,23 @@ local core = require("apisix.core")
 local get_routes = require("apisix.router").http_routes
 local get_services = require("apisix.http.service").services
 local apisix_upstream = require("apisix.upstream")
-local utils = require("apisix.admin.utils")
+local resource = require("apisix.admin.resource")
 local tostring = tostring
 local ipairs = ipairs
 local type = type
 
 
-local _M = {
-    version = 0.2,
-    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 upstream id"}
-    end
-
-    if not need_id and id then
-        return nil, {error_msg = "wrong upstream id, do not need it"}
-    end
-
-    if need_id and conf.id and tostring(conf.id) ~= tostring(id) then
-        return nil, {error_msg = "wrong upstream id"}
-    end
-
-    -- let schema check id
-    conf.id = id
-
-    core.log.info("schema: ", core.json.delay_encode(core.schema.upstream))
-    core.log.info("conf: ", core.json.delay_encode(conf))
-
     local ok, err = apisix_upstream.check_upstream_conf(conf)
     if not ok then
         return nil, {error_msg = err}
     end
 
-    return need_id and id or true
-end
-
-
-function _M.put(id, conf)
-    local id, err = check_conf(id, conf, true)
-    if not id then
-        return 400, err
-    end
-
-    local key = "/upstreams/" .. id
-    core.log.info("key: ", key)
-
-    local ok, err = utils.inject_conf_with_prev_conf("upstream", 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 upstream[", key, "]: ", err)
-        return 503, {error_msg = err}
-    end
-
-    return res.status, res.body
-end
-
-
-function _M.get(id)
-    local key = "/upstreams"
-    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 upstream[", key, "]: ", err)
-        return 503, {error_msg = err}
-    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
-
-    local key = "/upstreams"
-    utils.inject_timestamp(conf)
-    local res, err = core.etcd.push(key, conf)
-    if not res then
-        core.log.error("failed to post upstream[", key, "]: ", err)
-        return 503, {error_msg = err}
-    end
-
-    return res.status, res.body
+    return true
 end
 
 
-function _M.delete(id)
-    if not id then
-        return 400, {error_msg = "missing upstream id"}
-    end
-
+local function delete_checker(id)
     local routes, routes_ver = get_routes()
     if routes_ver and routes then
         for _, route in ipairs(routes) do
@@ -155,75 +63,14 @@ function _M.delete(id)
         end
     end
 
-    local key = "/upstreams/" .. id
-    local res, err = core.etcd.delete(key)
-    if not res then
-        core.log.error("failed to delete upstream[", 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 upstream 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 = "/upstreams" .. "/" .. id
-    local res_old, err = core.etcd.get(key)
-    if not res_old then
-        core.log.error("failed to get upstream [", 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 new_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(new_value, sub_path, conf)
-        new_value = node_val
-        if code then
-            return code, err
-        end
-        utils.inject_timestamp(new_value, nil, true)
-    else
-        new_value = core.table.merge(new_value, conf)
-        utils.inject_timestamp(new_value, nil, conf)
-    end
-
-    core.log.info("new value ", core.json.delay_encode(new_value, true))
-
-    local id, err = check_conf(id, new_value, true)
-    if not id then
-        return 400, err
-    end
-
-    local res, err = core.etcd.atomic_set(key, new_value, nil, modified_index)
-    if not res then
-        core.log.error("failed to set new upstream[", key, "]: ", err)
-        return 503, {error_msg = err}
-    end
-
-    return res.status, res.body
+    return nil, nil
 end
 
 
-return _M
+return resource.new({
+    name = "upstreams",
+    kind = "upstream",
+    schema = core.schema.upstream,
+    checker = check_conf,
+    delete_checker = delete_checker
+})


Reply via email to