mirror of
https://github.com/lucky-sideburn/kubeinvaders.git
synced 2026-05-17 14:16:43 +00:00
882 lines
30 KiB
Plaintext
882 lines
30 KiB
Plaintext
# lua_package_path '/usr/share/lua/5.1/?.lua;;';
|
|
server {
|
|
listen 8080 default_server;
|
|
root /var/www/html/;
|
|
index index.html;
|
|
access_log off;
|
|
|
|
set_by_lua_block $application_url {
|
|
return os.getenv("APPLICATION_URL")
|
|
}
|
|
|
|
set_by_lua_block $disable_tls {
|
|
local env_var = os.getenv("DISABLE_TLS")
|
|
if env_var then
|
|
return env_var
|
|
else
|
|
return "false"
|
|
end
|
|
}
|
|
|
|
set_by_lua_block $demo_mode {
|
|
local env_var = os.getenv("PLATFORM_ENGINEERING_DEMO_MODE")
|
|
if env_var then
|
|
return env_var
|
|
else
|
|
return "false"
|
|
end
|
|
}
|
|
|
|
set_by_lua_block $selected_env_vars {
|
|
local selected_env_vars = {"KUBERNETES_SERVICE_HOST", "KUBERNETES_SERVICE_PORT_HTTPS", "NAMESPACE", "DISABLE_TLS", "APPLICATION_URL"}
|
|
|
|
local result = {}
|
|
|
|
for _, var_name in ipairs(selected_env_vars) do
|
|
local value = os.getenv(var_name)
|
|
if value then
|
|
table.insert(result, var_name .. " = " .. value)
|
|
else
|
|
table.insert(result, var_name .. " = nil")
|
|
end
|
|
end
|
|
|
|
return table.concat(result, ", ")
|
|
|
|
}
|
|
|
|
location / {
|
|
add_header 'Access-Control-Allow-Origin' '*';
|
|
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
|
|
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
|
|
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
|
|
try_files $uri $uri/ =404;
|
|
add_header Last-Modified $date_gmt;
|
|
if_modified_since off;
|
|
expires off;
|
|
etag off;
|
|
sub_filter_types "*";
|
|
sub_filter demo_mode_placeholder $demo_mode;
|
|
sub_filter application_url_placeholder $application_url;
|
|
sub_filter disable_tls_placeholder $disable_tls;
|
|
sub_filter selected_env_vars_placeholder $selected_env_vars;
|
|
}
|
|
|
|
location /kube/ingresses {
|
|
access_by_lua_file "/usr/local/openresty/nginx/conf/kubeinvaders/ingress.lua";
|
|
}
|
|
|
|
location /kube/vm {
|
|
access_by_lua_file "/usr/local/openresty/nginx/conf/kubeinvaders/vm.lua";
|
|
}
|
|
|
|
location /kube/vm_reboot {
|
|
access_by_lua_file "/usr/local/openresty/nginx/conf/kubeinvaders/vm_reboot.lua";
|
|
}
|
|
|
|
location /kube/healthz {
|
|
content_by_lua_block {
|
|
local https = require "ssl.https"
|
|
local ltn12 = require "ltn12"
|
|
local json = require "lunajson"
|
|
local redis = require "resty.redis"
|
|
|
|
ngx.header['Access-Control-Allow-Origin'] = '*'
|
|
ngx.header['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS'
|
|
ngx.header['Access-Control-Allow-Headers'] = 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'
|
|
ngx.header['Access-Control-Expose-Headers'] = 'Content-Length,Content-Range';
|
|
|
|
if ngx.var.request_method == "OPTIONS" then
|
|
ngx.status = 204
|
|
return
|
|
end
|
|
|
|
local args = ngx.req.get_uri_args()
|
|
local target = args["target"]
|
|
local ca_cert = nil
|
|
|
|
if ngx.var.request_method == "POST" then
|
|
ngx.req.read_body()
|
|
local data = ngx.req.get_body_data()
|
|
|
|
if data and data ~= "" then
|
|
local ok, decoded = pcall(json.decode, data)
|
|
if ok and decoded then
|
|
if decoded["target"] and decoded["target"] ~= "" then
|
|
target = decoded["target"]
|
|
end
|
|
if decoded["ca_cert"] and decoded["ca_cert"] ~= "" then
|
|
ca_cert = decoded["ca_cert"]
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if not target or target == "" then
|
|
if os.getenv("KUBERNETES_SERVICE_HOST") then
|
|
target = "https://" .. os.getenv("KUBERNETES_SERVICE_HOST") .. ":" .. os.getenv("KUBERNETES_SERVICE_PORT_HTTPS")
|
|
else
|
|
target = os.getenv("ENDPOINT")
|
|
end
|
|
end
|
|
|
|
if not target or target == "" then
|
|
ngx.status = 400
|
|
ngx.say("Missing Kubernetes endpoint")
|
|
return
|
|
end
|
|
|
|
if not string.match(target, "^https?://") then
|
|
target = "https://" .. target
|
|
end
|
|
|
|
target = string.gsub(target, "/+$", "")
|
|
|
|
-- Persist the user-configured endpoint so background loops can reuse it.
|
|
local red = redis:new()
|
|
local okredis, errredis = red:connect("unix:/tmp/redis.sock")
|
|
if okredis then
|
|
local okset, errset = red:set("k8s_api_endpoint", target)
|
|
if not okset then
|
|
ngx.log(ngx.WARN, "[kube/healthz] Unable to persist k8s_api_endpoint in Redis: ", tostring(errset))
|
|
end
|
|
else
|
|
ngx.log(ngx.WARN, "[kube/healthz] Redis connection failed while storing k8s_api_endpoint: ", tostring(errredis))
|
|
end
|
|
|
|
local healthz_url = target .. "/healthz"
|
|
|
|
local disable_tls_env = string.lower(tostring(os.getenv("DISABLE_TLS") or "false"))
|
|
local disable_tls = disable_tls_env == "true" or disable_tls_env == "1" or disable_tls_env == "yes"
|
|
|
|
local request_opts = {
|
|
url = healthz_url,
|
|
method = "GET",
|
|
verify = disable_tls and "none" or "peer"
|
|
}
|
|
|
|
if not disable_tls and ca_cert and ca_cert ~= "" then
|
|
local ca_file_path = "/tmp/kubeinv-custom-ca.crt"
|
|
local ca_file = io.open(ca_file_path, "w")
|
|
|
|
if not ca_file then
|
|
ngx.status = 500
|
|
ngx.say("Unable to persist CA certificate")
|
|
return
|
|
end
|
|
|
|
ca_file:write(ca_cert)
|
|
ca_file:close()
|
|
request_opts.cafile = ca_file_path
|
|
end
|
|
|
|
local resp = {}
|
|
request_opts.sink = ltn12.sink.table(resp)
|
|
local ok, statusCode, response_headers, status_line = https.request(request_opts)
|
|
local numeric_status = tonumber(statusCode)
|
|
|
|
if not numeric_status then
|
|
numeric_status = ok and 200 or 502
|
|
end
|
|
|
|
ngx.status = numeric_status
|
|
ngx.header['Content-Type'] = 'application/json'
|
|
|
|
local body = table.concat(resp)
|
|
local response = {
|
|
ok = ok and numeric_status >= 200 and numeric_status < 300,
|
|
status = numeric_status,
|
|
target = healthz_url
|
|
}
|
|
|
|
if body ~= "" then
|
|
response["body"] = body
|
|
end
|
|
|
|
if not ok then
|
|
response["error"] = tostring(statusCode or "unknown")
|
|
end
|
|
|
|
ngx.say(json.encode(response))
|
|
}
|
|
}
|
|
|
|
location /kube/chaos/programming_mode {
|
|
access_by_lua_file "/usr/local/openresty/nginx/conf/kubeinvaders/programming_mode.lua";
|
|
}
|
|
|
|
location /kube/pods {
|
|
access_by_lua_file "/usr/local/openresty/nginx/conf/kubeinvaders/pod.lua";
|
|
}
|
|
|
|
location /kube/delete/pods {
|
|
access_by_lua_file "/usr/local/openresty/nginx/conf/kubeinvaders/pod.lua";
|
|
}
|
|
|
|
location /kube/nodes {
|
|
access_by_lua_file "/usr/local/openresty/nginx/conf/kubeinvaders/node.lua";
|
|
}
|
|
|
|
location /kube/chaos/nodes {
|
|
access_by_lua_file "/usr/local/openresty/nginx/conf/kubeinvaders/chaos-node.lua";
|
|
}
|
|
|
|
location /kube/kube-linter {
|
|
access_by_lua_file "/usr/local/openresty/nginx/conf/kubeinvaders/kube-linter.lua";
|
|
}
|
|
|
|
location /kube/endpoint {
|
|
content_by_lua_block {
|
|
ngx.header['Access-Control-Allow-Origin'] = '*'
|
|
ngx.header['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS'
|
|
ngx.header['Access-Control-Allow-Headers'] = 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'
|
|
ngx.header['Access-Control-Expose-Headers'] = 'Content-Length,Content-Range';
|
|
local endpoint = os.getenv("APPLICATION_URL")
|
|
|
|
if not endpoint or endpoint == "" then
|
|
if os.getenv("KUBERNETES_SERVICE_HOST") and os.getenv("KUBERNETES_SERVICE_PORT_HTTPS") then
|
|
endpoint = "https://" .. os.getenv("KUBERNETES_SERVICE_HOST") .. ":" .. os.getenv("KUBERNETES_SERVICE_PORT_HTTPS")
|
|
else
|
|
endpoint = os.getenv("ENDPOINT")
|
|
end
|
|
end
|
|
|
|
if not endpoint or endpoint == "" then
|
|
ngx.status = 500
|
|
ngx.say("Error! No cluster endpoint configured (APPLICATION_URL, KUBERNETES_SERVICE_HOST, or ENDPOINT).")
|
|
else
|
|
ngx.say(endpoint)
|
|
end
|
|
}
|
|
}
|
|
|
|
location /chaos/redis/get {
|
|
content_by_lua_block {
|
|
local redis = require "resty.redis"
|
|
local red = redis:new()
|
|
local okredis, errredis = red:connect("unix:/tmp/redis.sock")
|
|
ngx.header['Access-Control-Allow-Origin'] = '*'
|
|
ngx.header['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS'
|
|
ngx.header['Access-Control-Allow-Headers'] = 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'
|
|
ngx.header['Access-Control-Expose-Headers'] = 'Content-Length,Content-Range';
|
|
ngx.req.read_body()
|
|
local data = ngx.req.get_body_data()
|
|
local args = ngx.req.get_uri_args()
|
|
local key = args["key"]
|
|
|
|
if red:exists(key) == 0 then
|
|
ngx.say("Key not found")
|
|
else
|
|
ngx.say(tostring(red:get(key)))
|
|
end
|
|
}
|
|
}
|
|
|
|
location /chaos/redis/set {
|
|
content_by_lua_block {
|
|
local redis = require "resty.redis"
|
|
local red = redis:new()
|
|
local okredis, errredis = red:connect("unix:/tmp/redis.sock")
|
|
ngx.header['Access-Control-Allow-Origin'] = '*'
|
|
ngx.header['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS'
|
|
ngx.header['Access-Control-Allow-Headers'] = 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'
|
|
ngx.header['Access-Control-Expose-Headers'] = 'Content-Length,Content-Range';
|
|
ngx.req.read_body()
|
|
local data = ngx.req.get_body_data()
|
|
local args = ngx.req.get_uri_args()
|
|
local key = args["key"]
|
|
ngx.log(ngx.INFO, "[KUBEPING] Setting key " .. key .. " with data |" .. tostring(data) .. "|")
|
|
|
|
ngx.say(tostring(red:set(key, tostring(data))))
|
|
|
|
if key == "kubeping" and data == "1" then
|
|
local http = require("socket.http")
|
|
|
|
local function get_data(url)
|
|
local respbody = {}
|
|
local code, response = http.request(url)
|
|
if code == 200 then
|
|
local json = require("json")
|
|
respbody = json.decode(response)
|
|
else
|
|
print("Errore nella richiesta: " .. code)
|
|
end
|
|
return respbody
|
|
end
|
|
local data = get_data("https://devopstribe.it/kubeping?msg=" .. args["msg"])
|
|
print(data.result)
|
|
end
|
|
ngx.say("OK")
|
|
}
|
|
}
|
|
|
|
location /kube/namespaces {
|
|
content_by_lua_block {
|
|
ngx.header['Access-Control-Allow-Origin'] = '*'
|
|
ngx.header['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS'
|
|
ngx.header['Access-Control-Allow-Headers'] = 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'
|
|
ngx.header['Access-Control-Expose-Headers'] = 'Content-Length,Content-Range';
|
|
-- TO DO
|
|
-- Check when NAMESPACE is nil
|
|
ngx.say(os.getenv("NAMESPACE"))
|
|
}
|
|
}
|
|
|
|
location /codename {
|
|
content_by_lua_block {
|
|
local open = io.open
|
|
|
|
local function read_rand_line_from_file(path)
|
|
local handle = io.popen("shuf -n 1 " .. path)
|
|
local result = handle:read("*a")
|
|
local rc = handle:close()
|
|
return result
|
|
end
|
|
|
|
local random_word = read_rand_line_from_file("/usr/local/openresty/nginx/conf/kubeinvaders/data/codenames.txt")
|
|
local redis = require "resty.redis"
|
|
local red = redis:new()
|
|
local okredis, errredis = red:connect("unix:/tmp/redis.sock")
|
|
|
|
ngx.header['Access-Control-Allow-Origin'] = '*'
|
|
ngx.header['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS'
|
|
ngx.header['Access-Control-Allow-Headers'] = 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'
|
|
ngx.header['Access-Control-Expose-Headers'] = 'Content-Length,Content-Range';
|
|
|
|
while (red:get("latest_codename") == random_word)
|
|
do
|
|
random_word = read_rand_line_from_file("/usr/local/openresty/nginx/conf/kubeinvaders/data/codenames.txt")
|
|
end
|
|
|
|
red:set("latest_codename", random_word)
|
|
|
|
-- ngx.log(ngx.INFO, "[programming_mode_codename] Choosing random word " .. random_word)
|
|
ngx.say(random_word)
|
|
|
|
}
|
|
}
|
|
|
|
location /metrics {
|
|
default_type text/plain;
|
|
content_by_lua_block {
|
|
ngx.header['Access-Control-Allow-Origin'] = '*'
|
|
ngx.header['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS'
|
|
ngx.header['Access-Control-Allow-Headers'] = 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'
|
|
ngx.header['Access-Control-Expose-Headers'] = 'Content-Length,Content-Range'
|
|
|
|
local redis = require "resty.redis"
|
|
local red = redis:new()
|
|
local okredis, errredis = red:connect("unix:/tmp/redis.sock")
|
|
|
|
if not okredis then
|
|
ngx.log(ngx.ERR, "[metrics] Redis connection failed: " .. tostring(errredis))
|
|
ngx.status = 500
|
|
ngx.say("Redis connection failed")
|
|
return
|
|
end
|
|
|
|
local total_keys = red:keys("*total*")
|
|
if total_keys and type(total_keys) == "table" then
|
|
for i, res in ipairs(total_keys) do
|
|
if string.find(res, "chaos_node_jobs_total_on") then
|
|
local node = string.gsub(res, "chaos_node_jobs_total_on_", "")
|
|
local metric = "chaos_jobs_node_count{node=\"".. node .."\"}"
|
|
ngx.say(metric .. " " .. red:get(res))
|
|
|
|
elseif string.find(res, "deleted_pods_total_on") then
|
|
local namespace = string.gsub(res, "deleted_pods_total_on_", "")
|
|
local metric = "deleted_namespace_pods_count{namespace=\"".. namespace .."\"}"
|
|
ngx.say(metric .. " " .. red:get(res))
|
|
end
|
|
end
|
|
end
|
|
|
|
local regex_keys = red:keys("pods_match_regex:*")
|
|
if regex_keys and type(regex_keys) == "table" then
|
|
for i, res in ipairs(regex_keys) do
|
|
ngx.say(res .. " " .. red:get(res))
|
|
end
|
|
end
|
|
|
|
local metrics = {
|
|
'chaos_node_jobs_total',
|
|
'deleted_pods_total',
|
|
'fewer_replicas_seconds',
|
|
'latest_fewer_replicas_seconds',
|
|
'pods_not_running_on_selected_ns',
|
|
'current_chaos_job_pod',
|
|
'pods_match_regex'
|
|
}
|
|
|
|
local metric_name = ""
|
|
local metric_value = ""
|
|
|
|
for key, value in ipairs(metrics) do
|
|
metric_name = value
|
|
|
|
if (red:exists(metric_name) == 1) then
|
|
metric_value = red:get(metric_name)
|
|
ngx.say(metric_name .. " " .. metric_value)
|
|
end
|
|
end
|
|
|
|
local status_keys = red:keys("chaos_jobs_status*")
|
|
if status_keys and type(status_keys) == "table" then
|
|
for i, res in ipairs(status_keys) do
|
|
ngx.say(res .. " " .. red:get(res))
|
|
end
|
|
end
|
|
}
|
|
}
|
|
|
|
location /chaos_jobs_pod_phase {
|
|
default_type text/plain;
|
|
content_by_lua_block {
|
|
ngx.header['Access-Control-Allow-Origin'] = '*'
|
|
ngx.header['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS'
|
|
ngx.header['Access-Control-Allow-Headers'] = 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'
|
|
ngx.header['Access-Control-Expose-Headers'] = 'Content-Length,Content-Range'
|
|
|
|
local redis = require "resty.redis"
|
|
local red = redis:new()
|
|
local okredis, errredis = red:connect("unix:/tmp/redis.sock")
|
|
|
|
if not okredis then
|
|
ngx.log(ngx.ERR, "[chaos_jobs_pod_phase] Redis connection failed: " .. tostring(errredis))
|
|
ngx.status = 500
|
|
ngx.say("Redis connection failed")
|
|
return
|
|
end
|
|
|
|
local phase_keys = red:keys("chaos_jobs_pod_phase*")
|
|
if phase_keys and type(phase_keys) == "table" then
|
|
for i, res in ipairs(phase_keys) do
|
|
ngx.say(res .. " " .. red:get(res))
|
|
end
|
|
end
|
|
}
|
|
}
|
|
|
|
location /kube/chaos/containers {
|
|
lua_need_request_body 'on';
|
|
access_by_lua_file "/usr/local/openresty/nginx/conf/kubeinvaders/chaos-containers.lua";
|
|
}
|
|
|
|
location /chaos/logs/keepalive {
|
|
content_by_lua_block {
|
|
local redis = require "resty.redis"
|
|
local red = redis:new()
|
|
local args = ngx.req.get_uri_args()
|
|
ngx.header['Access-Control-Allow-Origin'] = '*'
|
|
ngx.header['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS'
|
|
ngx.header['Access-Control-Allow-Headers'] = 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'
|
|
ngx.header['Access-Control-Expose-Headers'] = 'Content-Length,Content-Range';
|
|
ngx.req.read_body()
|
|
local data = ngx.req.get_body_data()
|
|
local okredis, errredis = red:connect("unix:/tmp/redis.sock")
|
|
local logid = args["logid"]
|
|
|
|
red:set("do_not_clean_log:" .. logid, "1")
|
|
red:expire("do_not_clean_log:" .. logid, "20")
|
|
|
|
red:set("logs_enabled:" .. logid, "1")
|
|
red:expire("logs_enabled:" .. logid, "10")
|
|
|
|
if red:exists("log_status:".. logid) then
|
|
ngx.say(red:get("log_status:".. logid))
|
|
else
|
|
ngx.say('Waiting for log collector status...')
|
|
end
|
|
|
|
}
|
|
}
|
|
|
|
location /chaos/logs/count {
|
|
default_type text/html;
|
|
content_by_lua_block {
|
|
local redis = require "resty.redis"
|
|
local red = redis:new()
|
|
local args = ngx.req.get_uri_args()
|
|
ngx.header['Access-Control-Allow-Origin'] = '*'
|
|
ngx.header['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS'
|
|
ngx.header['Access-Control-Allow-Headers'] = 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'
|
|
ngx.header['Access-Control-Expose-Headers'] = 'Content-Length,Content-Range';
|
|
ngx.req.read_body()
|
|
local data = ngx.req.get_body_data()
|
|
local okredis, errredis = red:connect("unix:/tmp/redis.sock")
|
|
local logid = args["logid"]
|
|
|
|
local res, err = red:get("logs:chaoslogs-" .. logid .. "-count")
|
|
|
|
if res == ngx.null then
|
|
ngx.say("0")
|
|
else
|
|
ngx.say(res)
|
|
end
|
|
}
|
|
}
|
|
|
|
location /chaos/logs {
|
|
default_type text/html;
|
|
content_by_lua_block {
|
|
local redis = require "resty.redis"
|
|
local red = redis:new()
|
|
local args = ngx.req.get_uri_args()
|
|
ngx.header['Access-Control-Allow-Origin'] = '*'
|
|
ngx.header['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS'
|
|
ngx.header['Access-Control-Allow-Headers'] = 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'
|
|
ngx.header['Access-Control-Expose-Headers'] = 'Content-Length,Content-Range';
|
|
ngx.req.read_body()
|
|
local data = ngx.req.get_body_data()
|
|
local okredis, errredis = red:connect("unix:/tmp/redis.sock")
|
|
local logid = args["logid"]
|
|
local pos = args["pos"]
|
|
local res = red:get("logs:chaoslogs-" .. logid .. "-" .. pos)
|
|
ngx.say(res)
|
|
}
|
|
}
|
|
|
|
location /chaos/loadpreset {
|
|
content_by_lua_block {
|
|
local redis = require "resty.redis"
|
|
local red = redis:new()
|
|
local args = ngx.req.get_uri_args()
|
|
ngx.header['Access-Control-Allow-Origin'] = '*'
|
|
ngx.header['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS'
|
|
ngx.header['Access-Control-Allow-Headers'] = 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'
|
|
ngx.header['Access-Control-Expose-Headers'] = 'Content-Length,Content-Range';
|
|
ngx.req.read_body()
|
|
local okredis, errredis = red:connect("unix:/tmp/redis.sock")
|
|
local key_name = args["lang"] .. "_" .. args["name"]
|
|
|
|
local res, err = red:get(key_name)
|
|
|
|
if res == ngx.null then
|
|
ngx.say(err)
|
|
else
|
|
ngx.say(res)
|
|
end
|
|
}
|
|
}
|
|
|
|
location /chaos/loadpreset/reset {
|
|
content_by_lua_block {
|
|
|
|
local function mysplit (inputstr, sep)
|
|
if sep == nil then
|
|
sep = "%s"
|
|
end
|
|
local t={}
|
|
for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
|
|
table.insert(t, str)
|
|
end
|
|
return t
|
|
end
|
|
|
|
local redis = require "resty.redis"
|
|
local red = redis:new()
|
|
local args = ngx.req.get_uri_args()
|
|
ngx.header['Access-Control-Allow-Origin'] = '*'
|
|
ngx.header['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS'
|
|
ngx.header['Access-Control-Allow-Headers'] = 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'
|
|
ngx.header['Access-Control-Expose-Headers'] = 'Content-Length,Content-Range';
|
|
ngx.req.read_body()
|
|
local okredis, errredis = red:connect("unix:/tmp/redis.sock")
|
|
local key_name = args["lang"] .. "_" .. args["name"]
|
|
-- ngx.log(ngx.INFO, "[PRESETS-RESET] The item " .. key_name .. " should be removed from the key presets_list")
|
|
|
|
local handle = io.popen("redis-cli --scan --pattern " .. key_name .. " | xargs redis-cli del")
|
|
local result = handle:read("*a")
|
|
local rc = handle:close()
|
|
|
|
local res = red:get("presets_list")
|
|
|
|
if res == ngx.null then
|
|
ngx.say("There are no presets saved yet")
|
|
else
|
|
local preset = "";
|
|
local new_preset_list = "";
|
|
local cnt = 0;
|
|
for key, value in ipairs(mysplit(res, ",")) do
|
|
-- ngx.log(ngx.INFO, "[PRESETS-RESET] Split the key presets_list. Current preset is: " .. value)
|
|
if value ~= key_name then
|
|
preset = value
|
|
if cnt > 0 then
|
|
new_preset_list = new_preset_list .. "," .. preset
|
|
else
|
|
new_preset_list = preset
|
|
end
|
|
end
|
|
cnt = cnt + 1
|
|
end
|
|
-- ngx.log(ngx.INFO, "[PRESETS-RESET] New key presets_list is: " .. new_preset_list)
|
|
red:set("presets_list", new_preset_list)
|
|
end
|
|
}
|
|
}
|
|
|
|
location /chaos/loadpreset/savedpresets {
|
|
default_type text/html;
|
|
content_by_lua_block {
|
|
local redis = require "resty.redis"
|
|
local red = redis:new()
|
|
local args = ngx.req.get_uri_args()
|
|
ngx.header['Access-Control-Allow-Origin'] = '*'
|
|
ngx.header['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS'
|
|
ngx.header['Access-Control-Allow-Headers'] = 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'
|
|
ngx.header['Access-Control-Expose-Headers'] = 'Content-Length,Content-Range';
|
|
local okredis, errredis = red:connect("unix:/tmp/redis.sock")
|
|
|
|
local res, err = red:get("presets_list")
|
|
if res == ngx.null then
|
|
ngx.say(err)
|
|
else
|
|
ngx.say(res)
|
|
-- ngx.log(ngx.INFO, "[PRESETS_LIST] " .. res)
|
|
end
|
|
}
|
|
}
|
|
|
|
location /chaos/report/keepalive {
|
|
content_by_lua_block {
|
|
|
|
local function check_if_string_contain_project(project_list, project)
|
|
if string.find(project_list, project) then
|
|
return true
|
|
end
|
|
return false
|
|
end
|
|
|
|
local function add_project(project_list, new_project)
|
|
local new_project_list = project_list .. "," .. new_project
|
|
return new_project_list
|
|
end
|
|
|
|
local function check_if_redis_key_exists(redis, key)
|
|
if redis:exists(key) == 1 then
|
|
return true
|
|
end
|
|
return false
|
|
end
|
|
|
|
local redis = require "resty.redis"
|
|
local red = redis:new()
|
|
local args = ngx.req.get_uri_args()
|
|
ngx.header['Access-Control-Allow-Origin'] = '*'
|
|
ngx.header['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS'
|
|
ngx.header['Access-Control-Allow-Headers'] = 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'
|
|
ngx.header['Access-Control-Expose-Headers'] = 'Content-Length,Content-Range';
|
|
ngx.req.read_body()
|
|
local data = ngx.req.get_body_data()
|
|
local okredis, errredis = red:connect("unix:/tmp/redis.sock")
|
|
if check_if_redis_key_exists(red, "chaos_report_project_list") then
|
|
if not check_if_string_contain_project(red:get("chaos_report_project_list"), args["project"]) then
|
|
red:set("chaos_report_project_list", add_project(red:get("chaos_report_project_list"), args["project"]))
|
|
end
|
|
else
|
|
red:set("chaos_report_project_list", args["project"])
|
|
end
|
|
red:expire("chaos_report_project_list", 120)
|
|
}
|
|
}
|
|
|
|
location /chaos/report/save {
|
|
content_by_lua_block {
|
|
|
|
local function check_if_string_contain_project(project_list, project)
|
|
if string.find(project_list, project) then
|
|
return true
|
|
end
|
|
return false
|
|
end
|
|
|
|
local function add_project(project_list, new_project)
|
|
local new_project_list = project_list .. "," .. new_project
|
|
return new_project_list
|
|
end
|
|
|
|
local function check_if_redis_key_exists(redis, key)
|
|
if redis:exists(key) == 1 then
|
|
return true
|
|
end
|
|
return false
|
|
end
|
|
|
|
local redis = require "resty.redis"
|
|
local red = redis:new()
|
|
local args = ngx.req.get_uri_args()
|
|
ngx.header['Access-Control-Allow-Origin'] = '*'
|
|
ngx.header['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS'
|
|
ngx.header['Access-Control-Allow-Headers'] = 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'
|
|
ngx.header['Access-Control-Expose-Headers'] = 'Content-Length,Content-Range';
|
|
ngx.req.read_body()
|
|
local data = ngx.req.get_body_data()
|
|
local okredis, errredis = red:connect("unix:/tmp/redis.sock")
|
|
red:set("chaos_report_project_" .. args["project"], data)
|
|
|
|
local project = args["project"] or ""
|
|
if project ~= "" then
|
|
local check_url_counter_key = project .. "_check_url_counter"
|
|
local check_url_status_code_key = project .. "_check_url_status_code"
|
|
local check_url_elapsed_time_key = project .. "_check_url_elapsed_time"
|
|
local check_url_start_time_key = project .. "_check_url_start_time"
|
|
|
|
if red:exists(check_url_counter_key) == 0 then
|
|
red:set(check_url_counter_key, 0)
|
|
end
|
|
|
|
if red:exists(check_url_status_code_key) == 0 then
|
|
red:set(check_url_status_code_key, "Other")
|
|
end
|
|
|
|
if red:exists(check_url_elapsed_time_key) == 0 then
|
|
red:set(check_url_elapsed_time_key, 0)
|
|
end
|
|
|
|
if red:exists(check_url_start_time_key) == 0 then
|
|
red:set(check_url_start_time_key, os.date("%Y-%m-%d %H:%M:%S"))
|
|
end
|
|
end
|
|
|
|
if check_if_redis_key_exists(red, "chaos_report_project_list") then
|
|
if not check_if_string_contain_project(red:get("chaos_report_project_list"), args["project"]) then
|
|
red:set("chaos_report_project_list", add_project(red:get("chaos_report_project_list"), args["project"]))
|
|
end
|
|
else
|
|
red:set("chaos_report_project_list", args["project"])
|
|
end
|
|
|
|
red:expire("chaos_report_project_list", 120)
|
|
|
|
-- ngx.log(ngx.INFO, "[CHAOS-REPORT-SAVE] " .. data)
|
|
}
|
|
}
|
|
|
|
location /chaos/loadpreset/save {
|
|
content_by_lua_block {
|
|
local redis = require "resty.redis"
|
|
local red = redis:new()
|
|
local args = ngx.req.get_uri_args()
|
|
ngx.header['Access-Control-Allow-Origin'] = '*'
|
|
ngx.header['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS'
|
|
ngx.header['Access-Control-Allow-Headers'] = 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'
|
|
ngx.header['Access-Control-Expose-Headers'] = 'Content-Length,Content-Range';
|
|
ngx.req.read_body()
|
|
local data = ngx.req.get_body_data()
|
|
local okredis, errredis = red:connect("unix:/tmp/redis.sock")
|
|
local key_name = args["lang"] .. "_" .. args["name"]
|
|
local all_presets_key = ""
|
|
|
|
if data ~= nil then
|
|
-- ngx.log(ngx.INFO, "[SAVE-PRESETS] lang:" .. args["lang"] .. ", name:" .. args["name"] .. ", payload:" .. data .. "\n key_name:" .. key_name .. "\n key_exists: " .. red:exists(key_name))
|
|
-- if (red:exists(key_name) == 0) then
|
|
red:set(key_name, data)
|
|
-- ngx.log(ngx.INFO, "[SAVE-PRESETS] key_name:" .. key_name .. ", data:" .. data)
|
|
local res, err = red:get(key_name)
|
|
|
|
if res == ngx.null then
|
|
ngx.say("error: " .. args["name"] .. " has not been saved.")
|
|
else
|
|
|
|
local file = io.open("/var/www/html/" .. key_name, "w")
|
|
io.output(file)
|
|
io.write(data)
|
|
io.close(file)
|
|
ngx.say(args["name"] .. " has been saved.")
|
|
|
|
local redis_presets_list = red:get("presets_list")
|
|
|
|
if redis_presets_list == ngx.null then
|
|
red:set("presets_list", key_name)
|
|
else
|
|
local presets_list = redis_presets_list .. "," .. key_name
|
|
red:set("presets_list", presets_list)
|
|
end
|
|
|
|
end
|
|
-- end
|
|
else
|
|
ngx.say("Error in payload sent by web interface.")
|
|
end
|
|
}
|
|
}
|
|
|
|
location /chaos/programs/json-flow {
|
|
content_by_lua_block {
|
|
|
|
local function key_exists(data, mykey)
|
|
for key, value in pairs(data) do
|
|
if key == mykey then
|
|
return true
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
local function is_key_empty(data, mykey)
|
|
local cnt = 0
|
|
for key, value in pairs(data[mykey]) do
|
|
cnt = cnt + 1
|
|
end
|
|
if cnt > 0 then
|
|
return false
|
|
end
|
|
return true
|
|
end
|
|
|
|
local lyaml = require "lyaml"
|
|
local json = require 'lunajson'
|
|
|
|
ngx.header['Access-Control-Allow-Origin'] = '*'
|
|
ngx.header['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS'
|
|
ngx.header['Access-Control-Allow-Headers'] = 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'
|
|
ngx.header['Access-Control-Expose-Headers'] = 'Content-Length,Content-Range';
|
|
ngx.req.read_body()
|
|
local data = ngx.req.get_body_data()
|
|
if data then
|
|
ngx.log(ngx.INFO, "[PROGRAMMING_MODE] Chaos program payload sent from client: " .. data)
|
|
end
|
|
|
|
if data == nil then
|
|
error = "[PROGRAMMING_MODE] No chaos program already loaded."
|
|
ngx.status = 400
|
|
ngx.say(error)
|
|
else
|
|
local parse_ok, yaml_data = pcall(lyaml.load, data)
|
|
if not parse_ok or type(yaml_data) ~= "table" then
|
|
ngx.status = 400
|
|
ngx.say("Invalid YAML Chaos Program")
|
|
return
|
|
end
|
|
|
|
if not key_exists(yaml_data, "k8s_jobs") then
|
|
error = "[PROGRAMMING_MODE] Chaos program does not contain 'jobs' key."
|
|
ngx.status = 400
|
|
ngx.say(error)
|
|
|
|
elseif not key_exists(yaml_data, "experiments") then
|
|
error = "[PROGRAMMING_MODE] Chaos program does not contain 'experiments' key."
|
|
ngx.status = 400
|
|
ngx.say(error)
|
|
|
|
elseif is_key_empty(yaml_data, "k8s_jobs") then
|
|
error = "[PROGRAMMING_MODE] Chaos program does not contain valid 'jobs' key."
|
|
ngx.status = 400
|
|
ngx.say(error)
|
|
|
|
elseif is_key_empty(yaml_data, "experiments") then
|
|
error = "[PROGRAMMING_MODE] Chaos program does not contain valid 'experiments' key."
|
|
ngx.status = 400
|
|
ngx.say(error)
|
|
|
|
else
|
|
local response = json.encode(yaml_data)
|
|
ngx.log(ngx.INFO, response)
|
|
ngx.status = 200
|
|
ngx.say(response)
|
|
end
|
|
end
|
|
}
|
|
}
|
|
}
|