Sindbad~EG File Manager

Current Path : /opt/nginxhttpd_/etc/openresty_config/lua/
Upload File :
Current File : //opt/nginxhttpd_/etc/openresty_config/lua/api_nginx_internal.lua

--[[
    This file is kind of our own API to expose Nginx internal and to do stuff on the Nginx level.

    Pseudo API doc : 
    GET /internal?domain=toto.com&action=burst : will purge all cache (vhost, ssl) related to the toto.com domain
    GET /internal?action=warmup : will warm up the Vhost/SSL cache for all domains stored on Redis
    GET /internal?action=purge : will purge all the Vhost/SSL cache, for all domains
    GET /internal?action=export&type={ip,domain}&threshold=1000 : Export counter from nginx internal
    GET /internal?action=debug : retrieve some debug info about nginx/lua internal TODO
--]]

local cjson = require "cjson"
local o2debug = require "lib/o2switch_debug"
local o2utils = require "lib/o2switch_utils"
local o2redis = require "lib/o2switch_redis"
local o2ssl = require "lib/o2switch_ssl"
local o2counter = require "lib/o2switch_counter"
local ban = require "lib/o2switch_ban"
local cacheWrapper = require 'lib/o2switch_cache_wrapper'
local ngx = ngx
local ipairs = ipairs
local type = type 
local tonumber = tonumber

local argAction = ngx.var.arg_action
local argDomain = ngx.var.arg_domain
local argType = ngx.var.arg_type
local argThreshold = ngx.var.arg_threshold or 1000
local argThreshold = tonumber(argThreshold) ~= nil and tonumber(argThreshold) or 1000

ngx.status = ngx.HTTP_OK
ngx.header.content_type = "application/json; charset=utf-8"

-- --o2debug.debug("Internal API : Request received");

-- ?action={burst, warmup, purge, export, debug}
if not argAction then
    --o2debug.debug("Internal API : Action missing");
    ngx.say(cjson.encode({
        status = false,
        reason = 'action missing'
    }))
    return ngx.exit(ngx.HTTP_OK)
end

-- We only support some action, we check that
if argAction ~= 'burst' and argAction ~= 'warmup' and argAction ~= 'purge' 
    and argAction ~= 'export' and argAction ~= 'debug' then
    --o2debug.debug("Internal API : Action not supported");
    ngx.say(cjson.encode({
        status = false,
        reason = 'action not supported'
    }))
    return ngx.exit(ngx.HTTP_OK)
end

-- 'burst' action needs the 'domain' parameter
if argAction == 'burst' then
    -- ?domain=toto.com
    if not argDomain then
        --o2debug.debug("Internal API : Burst requested but the domain is missing");
        ngx.say(cjson.encode({
            status = false,
            reason = 'domain missing'
        }))
        return ngx.exit(ngx.HTTP_OK)
    end
end

-- 'export' action needs the 'type' parameter
if argAction == 'burst' then
    -- ?domain=toto.com
    if not argDomain then
        --o2debug.debug("Internal API : Burst requested but the domain is missing");
        ngx.say(cjson.encode({
            status = false,
            reason = 'domain missing'
        }))
        return ngx.exit(ngx.HTTP_OK)
    end
end

if argAction == 'export' then
     -- ?type=ip
     local validType = {
        ['ip'] = true,
        ['domain'] = true,
        ['ban'] = true,
    }
    if type(argType) ~= 'string' or not validType[argType] then
        --o2debug.debug("Internal API : type not provided or unsupported");
        ngx.say(cjson.encode({
            status = false,
            reason = 'type missing or invalid type'
        }))
        return ngx.exit(ngx.HTTP_OK)
    end
end

--[[
    Purge all of the internal cache
    GET /internal?action=purge
--]]
if argAction == 'purge' then
    local ok, err = cacheWrapper.purgeCache()
    if not ok then
        --o2debug.debug("Internal API : Purge error" .. (err or "no err msg"));
        ngx.say(cjson.encode({
            status = false,
            reason = "Can't purge. " .. err
        }))
        return ngx.exit(ngx.HTTP_OK)
    end

    --o2debug.debug("Internal API : Purged OK");
    ngx.say(cjson.encode({
        status = true,
        reason = "Ok. Purged"
    }))
    return ngx.exit(ngx.HTTP_OK)
end


--[[
    Warmup cache : Vhost & SSL
    GET /internal?action=warmup
--]]
if argAction == 'warmup' then
    local red = o2redis.getRedisInstance()
    if not red then
        --o2debug.debug("Internal API : Warmup requested but cant connect to redis");
        ngx.say(cjson.encode({
            status = false,
            reason = "Can't connect to redis"
        }))
        return ngx.exit(ngx.HTTP_OK)
    end

    local res, err = red:keys("*.*")
    if err then
        --o2debug.debug("Internal API : Cant retrieve the keys from redis");
        ngx.say(cjson.encode({
            status = false,
            reason = "Cant retrieve the keys from redis"
        }))
        return ngx.exit(ngx.HTTP_OK)
    end

    local ok, err = cacheWrapper.purgeCache()

    for k, name in ipairs(res) do
        if type(name) == 'string' then
            -- Warmup the vhosts cache
            local data, err = cacheWrapper.get(name, o2redis.getFromRedis, name)

            -- Warmup the SSL cache
            if  type(data) == 'table' and (data[5] ~= nil or data[6] ~= nil) then
                cacheWrapper.get(name .. '_crt', o2ssl.getCrt, name)
                cacheWrapper.get(name .. '_key', o2ssl.getKey, name)
            end
        end
    end

    --o2debug.debug("Internal API : cache warmed up");
    ngx.say(cjson.encode({
        status = true,
        reason = "OpenResty internal cache warmed'up!"
    }))

    local ok, err = cacheWrapper.executeInvalidation()
    return ngx.exit(ngx.HTTP_OK)
end

--[[
    Burst the cache for one specific domain
    GET /internal?domain=toto.com&action=burst
--]]
if argAction == 'burst' then
    local domain = o2utils.extractDomain(argDomain)

    if type(domain) ~= 'string' then
        ngx.say(cjson.encode({
            status = false,
            reason = "The name provided is not a string"
        }))
        return ngx.exit(ngx.HTTP_OK)
    end

    -- Vhost (proxy_pass rules etc...)
    local ok, err = cacheWrapper.deleteFromCache(domain)

    if err then
        --o2debug.debug("Internal API : Cant purge for domain " .. domain);
        ngx.say(cjson.encode({
            status = false,
            reason = "Can't purge the vhost cache for " .. domain .. ". Error received " .. err
        }))
        return ngx.exit(ngx.HTTP_OK)
    end

    -- SSL certificates
    local ok, err = cacheWrapper.deleteFromCache(domain .. '_crt')
    local ok, err = cacheWrapper.deleteFromCache(domain .. '_key')
    local ok, err = cacheWrapper.deleteFromCache(domain .. '_ocsp')

    --o2debug.debug("Internal API : Purge OK " .. domain);
    ngx.say(cjson.encode({
        status = true,
        reason = "Nginx internal mlcache purged for " .. domain
    }))

    return ngx.exit(ngx.HTTP_OK)
end

--[[
    Export data from Nginx internal memory, like the IP counter & domain counter
    Careful : It's expensive as it used a get_keys() call that use a global lock for all workers !
    GET /internal?action=export&type={ip,domain}&threshold=1000
--]]
if argAction == 'export' then
    local result, err = nil, nil
    if argType == 'ip' then
        result, err = o2counter.exportDataFromCounter('i', function(v) return v >= argThreshold end)
    elseif argType == 'domain' then
        result, err = o2counter.exportDataFromCounter('d', function(v) return v >= argThreshold end)
    elseif argType == 'ban' then
        result, err = ban.exportBlacklistedIp()
    end

    if err ~= nil or type(result) ~= 'table' then
        ngx.say(cjson.encode({
            status = false,
            reason = "Error " .. (err or 'no err msg')
        }))
        ngx.exit(ngx.HTTP_OK)
    end

    ngx.say(cjson.encode({
        status = true,
        result = result
    }))
    ngx.exit(ngx.HTTP_OK)
end

-- We should't arrive here.
ngx.say(cjson.encode({
    status = false,
    reason = "Unexpected error : we should not get here"
}))
return ngx.exit(ngx.HTTP_OK)

Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists