Implement Service RESTful API for hub 08/3708/5
authorYao Le <le.yao@intel.com>
Thu, 17 Sep 2020 04:25:47 +0000 (04:25 +0000)
committerYao Le <le.yao@intel.com>
Tue, 13 Oct 2020 01:59:11 +0000 (01:59 +0000)
The API handles service POST, GET and DELETE call

Signed-off-by: Yao Le <le.yao@intel.com>
Change-Id: I2e75f1ae0d7a33b58c620f5637b36994fecc7381

platform/cnf/src/rest_v1/index.lua
platform/cnf/src/rest_v1/svc_rest.lua [new file with mode: 0644]

index 3a11e92..97a5d96 100644 (file)
@@ -8,6 +8,7 @@ function index()
     entry({"sdewan", "mwan3", ver}, call("help")).dependent = false
     entry({"sdewan", "firewall", ver}, call("help")).dependent = false
     entry({"sdewan", "ipsec", ver}, call("help")).dependent = false
+    entry({"sdewan", "service", ver}, call("help")).dependent = false
 end
 
 function help()
diff --git a/platform/cnf/src/rest_v1/svc_rest.lua b/platform/cnf/src/rest_v1/svc_rest.lua
new file mode 100644 (file)
index 0000000..06e9e6e
--- /dev/null
@@ -0,0 +1,185 @@
+-- Licensed to the public under the GNU General Public License v2.
+
+module("luci.controller.rest_v1.svc_rest", package.seeall)
+
+local uci = require "luci.model.uci"
+
+json = require "luci.jsonc"
+io = require "io"
+sys = require "luci.sys"
+utils = require "luci.controller.rest_v1.utils"
+
+uci_conf = "service"
+
+function index()
+    ver = "v1"
+    configuration = "service"
+    entry({"sdewan", configuration, ver, "services"}, call("handle_request")).leaf = true
+end
+
+-- Request Handler
+function handle_request()
+    local method = utils.get_req_method()
+    if method == "GET" then
+        return get_service()
+    elseif method == "POST" then
+        return create_service()
+    elseif method == "DELETE" then
+        return delete_service()
+    else
+        utils.response_error(405, "Method Not Allowed")
+    end
+end
+
+-- Post
+function create_service()
+    local obj = utils.get_request_body_object()
+    if obj == nil then
+        return
+    end
+    if is_invalid(obj.port, obj.dport) then
+        utils.response_error(416, "Invalid Port Range")
+    elseif is_duplicated(obj.name, obj.port) then
+        utils.response_error(409, "Duplicated Service Configuration")
+    else
+        local count = 0
+        local ns = "nslookup "..obj.fullname.." | tail -n2 | awk -F':' '{print $2}' | head -1"
+        local ip
+        local exec
+        while count < 6 do
+            exec = io.popen(ns)
+            ip = string.gsub(exec:read("*a"), "^%s*(.-)%s*$", "%1")
+            if ip ~= "NXDOMAIN"
+             then
+                break
+            end
+            os.execute("sleep " .. tonumber(5))
+            count = count + 1
+        end
+        if ip ~= "NXDOMAIN" then
+            exec:close()
+            local file = io.open("/etc/sdewan_svc.info", "a+")
+            file:write(obj.name, " ", obj.fullname, " ", obj.port, " ", obj.dport, " ", ip, " ", "0\n")
+            local comm = "iptables -t nat -I PREROUTING 2 -p tcp --dport "..obj.port.." -j DNAT --to-destination "..ip..":"..obj.dport
+            os.execute(comm)
+            file:close()
+            sync_info()
+        else
+            utils.response_error(408, "Timeout: waiting for service ready...")
+        end
+    end
+    luci.http.prepare_content("application/json")
+    luci.http.write_json(obj)
+end
+
+-- Delete
+function delete_service()
+    local uri_list = utils.get_URI_list(7)
+    local name = uri_list[#uri_list]
+    local info_file = io.open("/etc/sdewan_svc.info", "w")
+    local up_file = io.open("/etc/sdewan_svc.up", "r")
+    for line in up_file:lines() do
+        local message = split(line)
+        if name ~= message[1] then
+            info_file:write(line, "\n")
+        else
+            local comm = "iptables -t nat -D PREROUTING -p tcp --dport "..message[3].." -j DNAT --to-destination "..message[5]..":"..message[4]
+            os.execute(comm)
+        end
+    end
+    info_file:close()
+    up_file:close()
+    sync_info()
+end
+
+-- Get
+function get_service()
+    local uri_list = utils.get_URI_list()
+    local file = io.open("/etc/sdewan_svc.info", "r")
+    if #uri_list == 6 then
+        local objs = {}
+        objs["services"] = {}
+        for line in file:lines() do
+            local message = split(line)
+            local obj = {}
+            obj["name"] = message[1]
+            obj["fullname"] = message[2]
+            obj["port"] = message[3]
+            obj["dport"] = message[4]
+            table.insert(objs["services"], obj)
+        end
+        luci.http.prepare_content("application/json")
+        luci.http.write_json(objs)
+    elseif #uri_list == 7 then
+        local name = uri_list[#uri_list]
+        local no = true
+        for line in file:lines() do
+            local message = split(line)
+            if name == message[1] then
+                no = false
+                local obj = {}
+                obj["name"] = message[1]
+                obj["fullname"] = message[2]
+                obj["port"] = message[3]
+                obj["dport"] = message[4]
+                luci.http.prepare_content("application/json")
+                luci.http.write_json(obj)
+                break
+            end
+        end
+        if no then
+            utils.response_error(404, "Cannot find " .. "service" .. "[" .. name .. "]" )
+        end
+    else
+        utils.response_error(400, "Bad request URI")
+    end
+    file:close()
+end
+
+-- Sync and validate
+function sync_info()
+    local in_file = io.open("/etc/sdewan_svc.info", "r")
+    local out_file = io.open("/etc/sdewan_svc.up", "w")
+    local content = in_file:read("*a")
+    out_file:write(content)
+    in_file:close()
+    out_file:close()
+end
+
+function split(str)
+    local arr = {}
+    for w in string.gmatch(str, "%S+") do
+        table.insert(arr, w)
+    end
+    return arr
+end
+
+function is_duplicated(name, port)
+    local file = io.open("/etc/sdewan_svc.info", "r")
+    local judge = false
+    for line in file:lines() do
+        local message = split(line)
+        if name == message[1] then
+            judge = true
+            break
+        end
+        if port == message[2] then
+            judge = true
+            break
+        end
+    end
+    file:close()
+    return judge
+end
+
+function is_invalid(port, dport)
+    local judge = false
+    if not utils.is_integer_and_in_range(port, 0, 65535) then
+        judge = true
+    end
+    if not utils.is_integer_and_in_range(dport, 0, 65535) then
+        judge = true
+    end
+    return judge
+end
+