added pure javascript version

This commit is contained in:
Eugenio Marzo
2021-02-10 09:22:26 +01:00
parent 6f73775906
commit 70aa217964
11 changed files with 622 additions and 129 deletions
+7 -3
View File
@@ -1,7 +1,6 @@
FROM nginx
# Install kubectl
RUN curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl"
RUN chmod +x ./kubectl
RUN mv ./kubectl /usr/local/bin/kubectl
@@ -12,8 +11,11 @@ RUN apt-get -y install --no-install-recommends wget gnupg ca-certificates jq ope
RUN wget -O - https://openresty.org/package/pubkey.gpg | apt-key add -
RUN codename=`grep -Po 'VERSION="[0-9]+ \(\K[^)]+' /etc/os-release` && echo "deb http://openresty.org/package/debian $codename openresty" | tee /etc/apt/sources.list.d/openresty.list
RUN apt-get update
RUN apt-get -y install openresty
RUN apt-get -y install openresty luarocks
RUN chmod 777 /usr/local/openresty/nginx
RUN apt-get -y install openresty luarocks libssl-dev git vim lua-json lua-socket
RUN luarocks install luasec
RUN luarocks install lunajson
# Install kube-linter
RUN curl -L -O https://github.com/stackrox/kube-linter/releases/download/0.1.5/kube-linter-linux.tar.gz
@@ -41,13 +43,15 @@ RUN sed -i.bak 's/listen\(.*\)80;/listen 8081;/' /etc/nginx/conf.d/default.conf
COPY nginx/nginx.conf /etc/nginx/nginx.conf
COPY nginx/metrics.lua-script /tmp/metrics.lua
COPY nginx/pod.lua /tmp/pod.lua
COPY nginx/node.lua /tmp/node.lua
COPY chaos-node/chaos-node.lua /tmp/chaos-node.lua
COPY nginx/KubeInvaders.templ /etc/nginx/conf.d/KubeInvaders.templ
COPY nginx/KubeInvaders_dev.templ /etc/nginx/conf.d/KubeInvaders_dev.templ
RUN chmod g+rwx /var/cache/nginx /var/run /var/log/nginx /var/www/html /etc/nginx/conf.d/KubeInvaders.templ /etc/nginx/conf.d
EXPOSE 8080
ENV PATH=/usr/local/openresty/nginx/sbin:$PATH
+52
View File
@@ -0,0 +1,52 @@
FROM nginx
# Install kubectl
RUN curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl"
RUN chmod +x ./kubectl
RUN mv ./kubectl /usr/local/bin/kubectl
# Install Openresty
RUN apt-get update
RUN apt-get -y install --no-install-recommends wget gnupg ca-certificates jq openssl task-spooler at
RUN wget -O - https://openresty.org/package/pubkey.gpg | apt-key add -
RUN codename=`grep -Po 'VERSION="[0-9]+ \(\K[^)]+' /etc/os-release` && echo "deb http://openresty.org/package/debian $codename openresty" | tee /etc/apt/sources.list.d/openresty.list
RUN apt-get update
RUN apt-get -y install openresty
RUN chmod 777 /usr/local/openresty/nginx
# Install kube-linter
RUN curl -L -O https://github.com/stackrox/kube-linter/releases/download/0.1.5/kube-linter-linux.tar.gz
RUN tar -xvf kube-linter-linux.tar.gz
RUN rm -f kube-linter-linux.tar.gz
RUN cp kube-linter /usr/local/bin/
RUN chmod 775 /usr/local/bin/kube-linter
COPY kube-linter/kube-linter-parser.sh /opt/kube-linter-parser.sh
RUN chmod +x /opt/kube-linter-parser.sh
# Install Redis
RUN apt-get install redis -y
COPY redis/redis.conf /etc/redis/redis.conf
# Install KubeInvaders
COPY ./js-web/KubeInvaders /var/www/html
# Configure Nginx
#RUN sed -i.bak 's/^user/#user/' /etc/nginx/nginx.conf
RUN sed -i.bak 's/listen\(.*\)80;/listen 8081;/' /etc/nginx/conf.d/default.conf
COPY nginx/nginx.conf /etc/nginx/nginx.conf
COPY nginx/metrics.lua-script /tmp/metrics.lua
COPY chaos-node/chaos-node.lua-script /tmp/chaos-node.lua
COPY nginx/KubeInvaders.templ /etc/nginx/conf.d/KubeInvaders.templ
COPY nginx/KubeInvaders_dev.templ /etc/nginx/conf.d/KubeInvaders_dev.templ
RUN chmod g+rwx /var/cache/nginx /var/run /var/log/nginx /var/www/html /etc/nginx/conf.d/KubeInvaders.templ /etc/nginx/conf.d
EXPOSE 8080
ENV PATH=/usr/local/openresty/nginx/sbin:$PATH
COPY ./temporary_hack.sh /
RUN chmod a+rwx temporary_hack.sh
ENTRYPOINT ["/temporary_hack.sh"]
+32 -61
View File
@@ -1,39 +1,44 @@
![Alt Text](https://github.com/lucky-sideburn/KubeInvaders/blob/master/logo.png)
*Gamified chaos engineering and analysis tool for Kubernetes. It is like Space Invaders but the aliens are PODs.*
*Gamified chaos engineering and analysis tool for Kubernetes. It is like Space Invaders but the aliens are pods or worker nodes.*
![Alt Text](https://github.com/lucky-sideburn/KubeInvaders/blob/master/images/kubeinvaders.png)
# Table of Contents
1. [Description](#Description)
2. [Special Input Keys and features](#Special-Input-Keys-and-features)
3. [Prometheus metrics and Grafana](#Metrics)
4. [Installation](#Installation)
5. [Notes for large clusters](#Notes-for-large-clusters)
6. [Configuration](#Configuration)
2. [New Version (game part in pure JS)](#new-version)
3. [Special Input Keys and features](#Special-Input-Keys-and-features)
4. [Prometheus metrics and Grafana](#Metrics)
5. [Installation](#Installation)
6. [Notes for large clusters](#Notes-for-large-clusters)
7. [Configuration](#Configuration)
## Description
KubeInvaders has been developed using [Defold](https://www.defold.com/).
Through KubeInvaders you can stress a Kubernetes cluster in a fun way and check how it is resilient.
## New Version
I added also new experimental features like a linter for the pods. The current latest image of the game include [kube-linter](https://github.com/stackrox/kube-linter) developed by [stackrox](https://github.com/stackrox).
KubeInvaders is going to be full open-source. Meanwhile it possibile choose 2 different version.
Legacy version: Made with Defold as game engine
New version: It has been written in pure Javascript and it is totaly open-source
The new version of KubeInvaders has fewer features than legacy but is optimized for chaos engineering because pods and nodes are rendered together and there is a shuffle for better random experiments.
## Special Input Keys and features
| Input | Action |
|-----------------|--------------------------------------------------------------------------------------------|
| n | Change namespace (you should define namespaces list. Ex: TARGET_NAMESPACE=foo1,foo2,foo3). |
| a | Switch to automatic mode. |
| m | Switch to manual mode. |
| h | Show special keys. |
| q | Hide help for special keys. |
| i | Show pod's name. Move the ship towards an alien. |
| r | Refresh log of a pod when spaceship is over the alien. |
| k | *(NEW)* Perform [kube-linter](https://github.com/stackrox/kube-linter) analysis for a pod. |
| w | *(NEW)* Chaos engineering against Kubernetes nodes. |
| Input | Action | Version (New or Legacy)|
|-----------------|--------------------------------------------------------------------------------------------|------------------------|
| n | Change namespace (you should define namespaces list. Ex: TARGET_NAMESPACE=foo1,foo2,foo3). | New, Legacy |
| a | Switch to automatic mode. | Legacy |
| m | Switch to manual mode. | Legacy |
| h | Show special keys. | New, Legacy |
| q | Hide help for special keys. | New, Legacy |
| i | Show pod's name. Move the ship towards an alien. | Legacy |
| r | Refresh log of a pod when spaceship is over the alien. | Legacy |
| k | *(NEW)* Perform [kube-linter](https://github.com/stackrox/kube-linter) analysis for a pod. | Legacy |
| w | *(NEW)* Chaos engineering against Kubernetes nodes. | New, Legacy |
### Known problems
@@ -82,44 +87,15 @@ git clone https://github.com/lucky-sideburn/KubeInvaders.git
kubectl create namespace kubeinvaders
# Install new and full open-source version
helm install kubeinvaders --set-string target_namespace="namespace1\,namespace2" \
--namespace kubeinvaders ./helm-charts/kubeinvaders \
--set ingress.hostName=kubeinvaders.io
```
### Install client on your workstation
--set ingress.hostName=kubeinvaders.io --set image.tag=latest
The easiest way to install KubeInvaders is on your workstation but if you choose this method you cannot use kube-linter feature directly from the game. Follow this guide:
1. Start KubeInvaders docker container locally
```bash
docker rm kubeinvaders -f && docker run --env DEVELOPMENT=true --env ENDPOINT=https://<k8s_url> --env NAMESPACE=namespace1,namespace2 --env TOKEN=<Service Account token> -p 8080:8080 --name kubeinvaders docker.io/luckysideburn/kubeinvaders
```
2. Create $HOME/.KubeInv.json like this - The endpoint is localhost:8080 because it is using KubeInvaders container as a proxy
to Kubernetes:
```json
{
"token": "<Service Account Token>",
"endpoint": "http://localhost:8080",
"namespace": "namespace1,namespace2"
}
```
Download the game from these locations:
* [MacOS](https://github.com/lucky-sideburn/KubeInvaders/releases/download/1.0-metrics/x86_64-darwin.zip)
* [Linux](https://github.com/lucky-sideburn/KubeInvaders/releases/download/1.0-metrics/x86_64-linux.zip)
### Run directly from Docker
This method can be used for developing KubeInvaders and testing the HTML5 bundle.
Using this method you can have problem of CORS:
```bash
docker build . -t kubeinvaders_dev
docker rm kubeinvaders -f && docker run --env DEVELOPMENT=true --env ENDPOINT=https://youk8scluster:8443 --env NAMESPACE=kubeinvadersdemo --env TOKEN=xxxx -p 8080:8080 --name kubeinvaders kubeinvaders_dev
# Install legacy version
helm install kubeinvaders --set-string target_namespace="namespace1\,namespace2" \
--namespace kubeinvaders ./helm-charts/kubeinvaders \
--set ingress.hostName=kubeinvaders.io --set image.tag=legacy
```
### Install KubeInvaders on OpenShift
@@ -147,11 +123,6 @@ KUBEINVADERS_SECRET=$(oc get secret -n kubeinvaders --field-selector=type==kuber
oc process -f openshift/KubeInvaders.yaml -p ROUTE_HOST=$ROUTE_HOST -p TARGET_NAMESPACE=$TARGET_NAMESPACE -p KUBEINVADERS_SECRET=$KUBEINVADERS_SECRET | oc create -f -
```
#### How the configuration of KubeInvaders DeploymentConfig should be (remember to use your TARGET_NAMESPACE and ROUTE_HOST)
![Alt Text](https://github.com/lucky-sideburn/KubeInvaders/blob/master/images/dcenv.png)
## Notes for large clusters
For clusters with many workers-nodes, KubeInvaders selects a subset of random items.
@@ -160,7 +131,7 @@ For clusters with many workers-nodes, KubeInvaders selects a subset of random it
|-----------|--------------|
| Nodes | 15 |
## Configuration
### Environment Variables - Make the game more difficult to win!
### (Legacy Version) Environment Variables - Make the game more difficult to win!
Set the following variables in Kubernetes Deployment or OpenShift DeploymentConfig:
+162
View File
@@ -0,0 +1,162 @@
loadfile("/tmp/metrics.lua")
local https = require "ssl.https"
local ltn12 = require "ltn12"
local json = require 'lunajson'
function read_all(file)
local f = assert(io.open(file, "rb"))
local content = f:read("*all")
f:close()
return content
end
local http = require("socket.http")
math.randomseed(os.clock()*100000000000)
local rand = math.random(999, 9999)
local arg = ngx.req.get_uri_args()
local k8s_url = os.getenv("ENDPOINT")
local token = os.getenv("TOKEN")
local namespace = arg['namespace']
local node_name = arg['node_name']
local url = k8s_url .. "/apis/batch/v1/namespaces/" .. namespace .. "/jobs"
local resp = {}
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';
headers = {
["Accept"] = "application/json",
["Content-Type"] = "application/json",
["Authorization"] = "Bearer " .. token,
}
body = [[
{
"apiVersion": "batch/v1",
"kind": "Job",
"metadata": {
"name": "kubeinvaders-chaos-]] .. rand .. [[",
"labels": {
"app": "kubeinvaders",
"approle": "chaosnode"
}
},
"spec": {
"template": {
"metadata": {
"labels": {
"app": "kubeinvaders",
"approle": "chaosnode"
}
},
"spec": {
"containers": [
{
"name": "kubeinvaders-chaos-node",
"image": "docker.io/luckysideburn/kubeinvaders-stress-ng:latest",
"command": [
"stress-ng",
"--cpu",
"4",
"--io",
"2",
"--vm",
"1",
"--vm-bytes",
"1G",
"--timeout",
"10s",
"--metrics-brief"
]
}
],
"restartPolicy": "Never",
"nodeSelector": {
"kubernetes.io/hostname": "wrk5-oc"
}
}
},
"backoffLimit": null
}
}
]]
local headers2 = {
["Accept"] = "application/json",
["Content-Type"] = "application/json",
["Authorization"] = "Bearer " .. token,
["Content-Length"] = string.len(body)
}
url = k8s_url .. "/apis/batch/v1/namespaces/" .. namespace .. "/jobs"
ngx.log(ngx.ERR, "Creating chaos_node job kubeinvaders-chaos-" ..rand)
local ok, statusCode, headers, statusText = https.request{
url = url,
headers = headers2,
method = "POST",
sink = ltn12.sink.table(resp),
source = ltn12.source.string(body)
}
ngx.log(ngx.ERR, ok)
ngx.log(ngx.ERR, statusCode)
ngx.log(ngx.ERR, statusText)
local url = k8s_url.. "/apis/batch/v1/namespaces/" .. namespace .. "/jobs"
ngx.log(ngx.ERR, "Getting JobList" .. rand)
local ok, statusCode, headers, statusText = https.request{
url = url,
headers = headers,
method = "GET",
sink = ltn12.sink.table(resp)
}
ngx.log(ngx.ERR, ok)
ngx.log(ngx.ERR, statusCode)
ngx.log(ngx.ERR, statusText)
for k,v in ipairs(resp) do
decoded = json.decode(v)
if decoded["kind"] == "JobList" then
for k2,v2 in ipairs(decoded["items"]) do
if v2["status"]["succeeded"] == 1 and v2["metadata"]["labels"]["approle"] == "chaosnode" then
delete_job = "kubectl delete job " .. v2["metadata"]["name"] .. " --token=" .. token .. " --server=" .. k8s_url .. " --insecure-skip-tls-verify=true -n " .. namespace
ngx.log(ngx.ERR, delete_pod)
end
end
end
end
local url = k8s_url.. "/api/v1/namespaces/" .. namespace .. "/pods"
ngx.log(ngx.ERR, "Getting PodList" .. rand)
local ok, statusCode, headers, statusText = https.request{
url = url,
headers = headers,
method = "GET",
sink = ltn12.sink.table(resp)
}
ngx.log(ngx.ERR, ok)
ngx.log(ngx.ERR, statusCode)
ngx.log(ngx.ERR, statusText)
for k,v in ipairs(resp) do
decoded = json.decode(v)
if decoded["kind"] == "PodList" then
for k2,v2 in ipairs(decoded["items"]) do
if v2["status"]["phase"] == "Succeeded" and v2["metadata"]["labels"]["approle"] == "chaosnode" then
delete_pod = "kubectl delete pod " .. v2["metadata"]["name"] .. " --token=" .. token .. " --server=" .. k8s_url .. " --insecure-skip-tls-verify=true -n " .. namespace
ngx.log(ngx.ERR, delete_pod)
end
end
end
end
ngx.say("chaos node")
+115 -14
View File
@@ -9,7 +9,11 @@ var spaceshipHeight = 60;
var spaceshipWidth = 60;
var spaceshipX = (canvas.width-spaceshipWidth)/2;
var spaceshipY = (canvas.height-spaceshipHeight)/2;
var namespace = "kubeinvadersdemo";
var cluster = "CLUSTER_PLACEOLDER";
var namespaces = ["kubeinvadersdemo", "foobar"];
var namespaces_index = 0;
var namespace = namespaces[namespaces_index];
var endpoint = "";
// pods list from kubernetes
var pods = [];
@@ -64,14 +68,43 @@ var collisionDetected = false;
var aliensY = [];
var aliensIncrementY = 50;
var shuffle = true;
var help = false;
function getEndpoint(){
var oReq = new XMLHttpRequest();
oReq.onload = function () {
endpoint = this.responseText;
};;
oReq.open("GET", "http://localhost:8080/kube/endpoint");
oReq.send();
}
function startChaosNode(node_name){
var oReq = new XMLHttpRequest();
oReq.onload = function () {
console.log(JSON.parse(this.responseText))
};;
oReq.open("GET", "http://localhost:8080/kube/chaos/nodes?nodename=node_name=" + node_name + "&namespace=" + namespace);
oReq.send();
}
function deletePods(pod_name){
var oReq = new XMLHttpRequest();
oReq.onload = function () {
console.log(JSON.parse(this.responseText))
};;
oReq.open("GET", "http://localhost:8080/kube/pods?action=delete&pod_name=" + pod_name + "&namespace=" + namespace);
oReq.send();
}
function getPods(){
foo = pods;
var oReq = new XMLHttpRequest();
oReq.onload = function () {
json_parsed = JSON.parse(this.responseText)
pods = json_parsed["items"];
pods = json_parsed["items"].concat(nodes);
};;
oReq.open("GET", "http://localhost:8080/kube/pods?namespace=" + namespace);
oReq.open("GET", "http://localhost:8080/kube/pods?action=list&namespace=" + namespace);
oReq.send();
}
@@ -86,7 +119,8 @@ function getNodes(){
}
function getKubeItems() {
getPods()
getNodes();
getPods();
}
function keyDownHandler(e) {
@@ -114,10 +148,43 @@ function keyDownHandler(e) {
console.log("Spaceship Y: " + spaceshipY);
console.log("Spaceship X: " + spaceshipX);
}
else if(e.keyCode == 83) {
if (shuffle) {
shuffle = false;
console.log("Deactivate shuffle");
}
else {
shuffle = true
console.log("Activate shuffle");
}
}
else if(e.keyCode == 32) {
console.log("Shot");
shot = true
}
else if(e.keyCode == 78) {
console.log("Change Namespace");
if (namespaces_index < namespaces.length-1) {
namespaces_index +=1 ;
}
else {
namespaces_index = 0;
}
namespace = namespaces[namespaces_index];
aliens = [];
pods = [];
}
else if(e.keyCode == 72) {
console.log("Help");
if (help) {
help = false;
console.log("Deactivate help");
}
else {
help = true
console.log("Activate help");
}
}
}
function keyUpHandler(e) {
@@ -138,10 +205,17 @@ function keyUpHandler(e) {
document.addEventListener("keydown", keyDownHandler, false);
document.addEventListener("keyup", keyUpHandler, false);
function drawAlien(alienX, alienY) {
function drawAlien(alienX, alienY, name) {
var image = new Image(); // Image constructor
image.src = './sprite_invader.png';
ctx.drawImage(image, alienX, alienY, 40, 40);
if (nodes.includes(name)) {
image.src = './k8s_node.png';
ctx.drawImage(image, alienX, alienY, 30, 40);
}
else {
image.src = './sprite_invader.png';
ctx.drawImage(image, alienX, alienY, 40, 40);
}
ctx.closePath();
}
@@ -152,8 +226,6 @@ function checkRocketAlienCollision(){
for (i=aliens.length - 1; i >= 0; i--) {
if (aliens[i]["active"] && (rocketY - aliens[i]["y"] < 5)) {
var rangeX = []
//console.log(aliens[i]);
//console.log(aliens[i]["x"]);
rangeX.push(aliens[i]["x"]);
for (k=aliens[i]["x"]; k<aliens[i]["x"]+aliensWidth; k++) {
@@ -166,7 +238,14 @@ function checkRocketAlienCollision(){
console.log("collision detected");
collisionDetected = true;
aliens[i]["active"] = false;
aliens[i]["name"] = "killed_pod";
if (nodes.includes(aliens[i]["name"])) {
startChaosNode(aliens[i]["name"]);
aliens[i]["name"] = "killed_pod";
}
else {
deletePods(aliens[i]["name"]);
aliens[i]["name"] = "killed_pod";
}
return true;
}
}
@@ -175,13 +254,15 @@ function checkRocketAlienCollision(){
return false;
}
function shuffleAliens() {
pods = pods.sort(() => Math.random() - 0.5)
}
function drawRocket() {
var image = new Image(); // Image constructor
image.src = './kuberocket.png';
ctx.drawImage(image, rocketX, rocketY, 20, 20);
ctx.closePath();
//console.log("Rocket X: " + rocketX + " Rocket Y: " + rocketY);
if (checkRocketAlienCollision()) {
rocketY = -100;
@@ -215,6 +296,7 @@ function drawSpaceship() {
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawSpaceship();
@@ -258,9 +340,22 @@ function draw() {
for (i=0; i<aliens.length; i++) {
if (aliens[i]["active"]) {
drawAlien(aliens[i]["x"], aliens[i]["y"]);
drawAlien(aliens[i]["x"], aliens[i]["y"], aliens[i]["name"]);
}
}
ctx.fillStyle = 'white';
ctx.font = '15px Verdana';
ctx.fillText('Cluster: ' + endpoint, 10, 400);
ctx.fillText('Current Namespace: ' + namespace, 10, 420);
ctx.fillText('Alien Shuffle: ' + shuffle, 10, 440);
ctx.fillText('press \'h\' for help!', 10, 470);
if (help) {
ctx.fillText('Special Keys:', 10, 300);
ctx.fillText('h => Activate or deactivate Help', 10, 320);
ctx.fillText('s => Activate or deactivate shuffle for aliens', 10, 340);
ctx.fillText('n => Change namespace', 10, 360);
}
}
function podExists(podName) {
@@ -282,6 +377,11 @@ function findReplace() {
}
function setAliens() {
if (shuffle) {
pods = pods.sort(() => Math.random() - 0.5)
}
aliens = [];
console.log("Length of aliensY array: " + aliensY.length);
if (pods.length > 0) {
for (k=10; k>0; k--) {
if (!aliensY.includes(k)) {
@@ -301,7 +401,7 @@ function setAliens() {
aliens.push({"name": pods[i], "x": x, "y": y, "active": true});
cnt =+ 1;
}
if (aliens.length == 12) {
if (aliens.length % 12 == 0) {
console.log("we need another line of aliens for Y="+aliensIncrementY);
x = 10;
y += aliensIncrementY;
@@ -320,6 +420,7 @@ function setAliens() {
}
}
getEndpoint();
setInterval(draw, 10);
setInterval(getKubeItems, 1000);
setInterval(setAliens, 1000);
View File
+57 -26
View File
@@ -2,8 +2,12 @@ server {
listen 8080 default_server;
root /var/www/html/;
index index.html;
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;
add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0';
@@ -12,12 +16,63 @@ server {
etag off;
}
location /kube {
rewrite ^/kube(.*)$ /api$1 break;
proxy_pass ${ENDPOINT};
access_by_lua_file /tmp/metrics.lua;
}
location /kube/api {
rewrite ^/kube/api(.*)$ /api$1 break;
proxy_pass ${ENDPOINT};
access_by_lua_file /tmp/metrics.lua;
}
location /kube/pods {
access_by_lua_file "/tmp/pod.lua";
}
location /kube/delete/pods {
access_by_lua_file "/tmp/pod.lua";
}
location /kube/nodes {
access_by_lua_file "/tmp/node.lua";
}
location /kube/chaos/nodes {
access_by_lua_file "/tmp/chaos-node.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';
ngx.say(os.getenv("ENDPOINT"))
}
}
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';
ngx.say(os.getenv("NAMESPACE"))
}
}
location /metrics {
default_type text/html;
content_by_lua_block {
local redis = require "resty.redis"
local red = redis:new()
-- local okredis, errredis = red:connect(os.getenv("REDIS_HOST"), 6379)
local okredis, errredis = red:connect("unix:/tmp/redis.sock")
for i, res in ipairs(red:keys("*")) do
ngx.log(ngx.ERR, res)
@@ -42,34 +97,10 @@ server {
content_by_lua_block {
local arg = ngx.req.get_uri_args()
ngx.req.read_body()
local request_body = ngx.req.get_body_data()
local request_body = ngx.req.get_body_data()
local handle = io.popen("/opt/kube-linter-parser.sh " .. arg['k8s_url'] .. " " .. arg['namespace'] .. " " .. arg['pod_name'] .. " " .. arg['token'])
local result = handle:read("*a")
ngx.say(result)
}
}
location /kube/chaos-node {
default_type text/html;
access_by_lua_file /tmp/metrics.lua;
content_by_lua_block {
local arg = ngx.req.get_uri_args()
ngx.req.read_body()
local request_body = ngx.req.get_body_data()
os.execute("/opt/chaos-node.sh " .. arg['k8s_url'] .. " " .. arg['token'] .. " " .. arg['node_name'] .. " " .. arg['namespace'] .. " &")
ngx.say('chaos_node started!')
}
}
location /kube {
rewrite ^/kube(.*)$ /api$1 break;
proxy_pass https://${KUBERNETES_SERVICE_HOST}:${KUBERNETES_SERVICE_PORT_HTTPS};
access_by_lua_file /tmp/metrics.lua;
}
location /kube/api {
rewrite ^/kube/api(.*)$ /api$1 break;
proxy_pass https://${KUBERNETES_SERVICE_HOST}:${KUBERNETES_SERVICE_PORT_HTTPS};
access_by_lua_file /tmp/metrics.lua;
}
}
+54 -25
View File
@@ -1,9 +1,15 @@
# lua_package_path '/usr/share/lua/5.1/?.lua;;';
server {
listen 8080 default_server;
root /var/www/html/;
index index.html;
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;
add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0';
@@ -12,6 +18,54 @@ server {
etag off;
}
location /kube {
rewrite ^/kube(.*)$ /api$1 break;
proxy_pass ${ENDPOINT};
access_by_lua_file /tmp/metrics.lua;
}
location /kube/api {
rewrite ^/kube/api(.*)$ /api$1 break;
proxy_pass ${ENDPOINT};
access_by_lua_file /tmp/metrics.lua;
}
location /kube/pods {
access_by_lua_file "/tmp/pod.lua";
}
location /kube/delete/pods {
access_by_lua_file "/tmp/pod.lua";
}
location /kube/nodes {
access_by_lua_file "/tmp/node.lua";
}
location /kube/chaos/nodes {
access_by_lua_file "/tmp/chaos-node.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';
ngx.say(os.getenv("ENDPOINT"))
}
}
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';
ngx.say(os.getenv("NAMESPACE"))
}
}
location /metrics {
default_type text/html;
content_by_lua_block {
@@ -51,29 +105,4 @@ server {
ngx.say(result)
}
}
location /kube/chaos-node {
default_type text/html;
access_by_lua_file /tmp/metrics.lua;
content_by_lua_block {
local arg = ngx.req.get_uri_args()
ngx.req.read_body()
local request_body = ngx.req.get_body_data()
os.execute("/opt/chaos-node.sh " .. arg['k8s_url'] .. " " .. arg['token'] .. " " .. arg['node_name'] .. " " .. arg['namespace'] .. " &")
ngx.say('chaos_node started!')
}
}
location /kube {
rewrite ^/kube(.*)$ /api$1 break;
proxy_pass ${ENDPOINT};
access_by_lua_file /tmp/metrics.lua;
}
location /kube/api {
rewrite ^/kube/api(.*)$ /api$1 break;
proxy_pass ${ENDPOINT};
access_by_lua_file /tmp/metrics.lua;
}
}
+3
View File
@@ -2,6 +2,9 @@ worker_processes 2;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
env REDIS_HOST;
env TOKEN;
env ENDPOINT;
env NAMESPACE;
events {
worker_connections 1024;
+56
View File
@@ -0,0 +1,56 @@
local https = require "ssl.https"
local ltn12 = require "ltn12"
local json = require 'lunajson'
local k8s_url = os.getenv("ENDPOINT")
local token = os.getenv("TOKEN")
local arg = ngx.req.get_uri_args()
local url = k8s_url.. "/api/v1/nodes"
local decoded = nil
local nodes = {}
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.log(ngx.ERR, "token: " .. token)
ngx.log(ngx.ERR, "url: " .. url)
local headers = {
["Accept"] = "application/json",
["Content-Type"] = "application/json",
["Authorization"] = "Bearer " .. token,
}
local resp = {}
local ok, statusCode, headers, statusText = https.request{
url = url,
headers = headers,
method = "GET",
sink = ltn12.sink.table(resp)
}
ngx.log(ngx.ERR, "REQUEST LOGS...")
ngx.log(ngx.ERR, ok)
ngx.log(ngx.ERR, statusCode)
ngx.log(ngx.ERR, statusText)
local i = 0
nodes["items"] = {}
for k,v in ipairs(resp) do
decoded = json.decode(v)
if decoded["kind"] == "NodeList" then
for k2,v2 in ipairs(decoded["items"]) do
if not v2["metadata"]["labels"]["node-role.kubernetes.io/master"] then
ngx.log(ngx.ERR, "found node " .. v2["metadata"]["name"])
nodes["items"][i] = v2["metadata"]["name"]
i = i + 1
end
end
end
end
ngx.say(json.encode(nodes))
+84
View File
@@ -0,0 +1,84 @@
local https = require "ssl.https"
local ltn12 = require "ltn12"
local json = require 'lunajson'
local k8s_url = os.getenv("ENDPOINT")
local token = os.getenv("TOKEN")
local arg = ngx.req.get_uri_args()
local namespace = arg['namespace']
local decoded = nil
local action = arg['action']
local url = ''
local pods = {}
local method = 'GET'
local pods_not_found = true;
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 action == "list" then
url = k8s_url.. "/api/v1/namespaces/" .. namespace .. "/pods"
elseif action == "delete" then
local pod_name = arg['pod_name']
url = k8s_url.. "/api/v1/namespaces/" .. namespace .. "/pods/" .. pod_name
method = "DELETE"
else
ngx.say("Please set the parameter 'action'")
ngx.exit(ngx.OK)
end
ngx.log(ngx.ERR, "token: " .. token)
ngx.log(ngx.ERR, "url: " .. url)
ngx.log(ngx.ERR, "namespace: " .. namespace)
local headers = {
["Accept"] = "application/json",
["Content-Type"] = "application/json",
["Authorization"] = "Bearer " .. token,
}
local resp = {}
local ok, statusCode, headers, statusText = https.request{
url = url,
headers = headers,
method = method,
sink = ltn12.sink.table(resp)
}
ngx.log(ngx.ERR, "REQUEST LOGS...")
ngx.log(ngx.ERR, ok)
ngx.log(ngx.ERR, statusCode)
ngx.log(ngx.ERR, statusText)
if action == "list" then
local i = 1
pods["items"] = {}
for k,v in ipairs(resp) do
decoded = json.decode(v)
if decoded["kind"] == "PodList" then
for k2,v2 in ipairs(decoded["items"]) do
if v2["status"]["phase"] == "Running" and v2["metadata"]["labels"]["approle"] ~= "chaosnode" then
ngx.log(ngx.ERR, "found pod " .. v2["metadata"]["name"])
pods["items"][i] = v2["metadata"]["name"]
i = i + 1
pods_not_found = false;
end
end
end
end
if pods_not_found then
ngx.log(ngx.ERR, "No pods found into the namespace" .. namespace)
ngx.say("{\"items\": []}")
else
ngx.say(json.encode(pods))
end
elseif action == "delete" then
ngx.say(table.concat(resp))
end