mirror of
https://github.com/lucky-sideburn/kubeinvaders.git
synced 2026-08-23 21:46:21 +00:00
Merge pull request #53 from lucky-sideburn/feature/programmming_mode
Feature/programmming mode
This commit is contained in:
+4
-1
@@ -11,7 +11,7 @@ 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 luarocks libssl-dev git vim lua-json lua-socket
|
||||
RUN apt-get -y install openresty luarocks libssl-dev git vim lua-json lua-socket python3 python3-pip
|
||||
RUN apt-get update --fix-missing
|
||||
RUN chmod 777 /usr/local/openresty/nginx
|
||||
RUN luarocks install luasec
|
||||
@@ -48,7 +48,10 @@ COPY scripts/node.lua /usr/local/openresty/nginx/conf/kubeinvaders/node.lua
|
||||
COPY scripts/kube-linter.lua /usr/local/openresty/nginx/conf/kubeinvaders/kube-linter.lua
|
||||
COPY scripts/chaos-node.lua /usr/local/openresty/nginx/conf/kubeinvaders/chaos-node.lua
|
||||
COPY scripts/chaos-containers.lua /usr/local/openresty/nginx/conf/kubeinvaders/chaos-containers.lua
|
||||
COPY scripts/programming_mode.lua /usr/local/openresty/nginx/conf/kubeinvaders/programming_mode.lua
|
||||
COPY scripts/config_kubeinv.lua /usr/local/openresty/lualib/config_kubeinv.lua
|
||||
COPY scripts/programming_mode /opt/programming_mode/
|
||||
RUN pip3 install -r /opt/programming_mode/requirements.txt
|
||||
COPY nginx/KubeInvaders.conf /etc/nginx/conf.d/KubeInvaders.conf
|
||||
RUN chmod g+rwx /var/cache/nginx /var/run /var/log/nginx /var/www/html /etc/nginx/conf.d
|
||||
|
||||
|
||||
Binary file not shown.
+137
-23
@@ -115,26 +115,52 @@
|
||||
<div class="starter-template">
|
||||
<div class="container" style="margin-bottom: 2%;">
|
||||
<div class="row" style="margin-top: 2%;">
|
||||
<div class="row">
|
||||
|
||||
<div class="row" style="margin-bottom: 1%;">
|
||||
<div class="col text-center">
|
||||
<button type="button" id="controlAutoPilotButton" class="btn btn-light" onclick="controlAutoPilot()">Start</button>
|
||||
<button type="button" id="gameModeButton" class="btn btn-light" onclick="startGameMode()">Game Mode</button>
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
<input type="range" id="randomFactorInput" name="randomFactorInput" min="0" max="100" value="50" onclick="changeRandomFactor()">
|
||||
<div id="programming-mode-buttons" style="display: none;">
|
||||
<button type="button" id="runProgrammingModeButton" class="btn btn-dark" onclick="runChaosProgram()">RUN</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
<label for="randomFactorInput">Random Factor: <span id="currentRandomFactor">50</span></label>
|
||||
<button type="button" id="programmingModeButton" class="btn btn-light" onclick="startProgrammingMode()">Programming Mode</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" style="margin-top: 1%;">
|
||||
<div class="col text-center">
|
||||
<button type="button" id="buttonShuffle" class="btn btn-light btn-sm" onclick="buttonShuffleHelper()">Disable Shuffle</button>
|
||||
<div id="programming-mode-buttons" style="display: none;">
|
||||
<div class="row">
|
||||
<div class="col text-center">
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
<button type="button" id="namespacesJumpButton" class="btn btn-light btn-sm" onclick="namespacesJumpControl()">Enable Auto NS Switch</button>
|
||||
</div>
|
||||
<div id="game-buttons" style="display: none;">
|
||||
<div class="row">
|
||||
<div class="col text-center">
|
||||
<button type="button" id="controlAutoPilotButton" class="btn btn-light" onclick="controlAutoPilot()">Start</button>
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
<input type="range" id="randomFactorInput" name="randomFactorInput" min="0" max="100" value="50" onclick="changeRandomFactor()">
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
<label for="randomFactorInput">Random Factor: <span id="currentRandomFactor">50</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
<button type="button" id="buttonOnlyPodName" class="btn btn-light btn-sm" onclick="showPodNameControl()">Hide Pods Name</button>
|
||||
<div class="row" style="margin-top: 1%;">
|
||||
<div class="col text-center">
|
||||
<button type="button" id="buttonShuffle" class="btn btn-light btn-sm" onclick="buttonShuffleHelper()">Disable Shuffle</button>
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
<button type="button" id="namespacesJumpButton" class="btn btn-light btn-sm" onclick="namespacesJumpControl()">Enable Auto NS Switch</button>
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
<button type="button" id="buttonOnlyPodName" class="btn btn-light btn-sm" onclick="showPodNameControl()">Hide Pods Name</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -148,23 +174,67 @@
|
||||
<span style="color: #000000">Latest Replicas State Delay: <span id="latest_fewer_replicas_seconds" style="color: #8f00bb">0</span><font color="#4f4f4f"> sec</font> </span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<canvas id="myCanvas" width="720" height="480"></canvas>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col text-center">
|
||||
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
<input type="button" style="margin-top: 2%" class="btn btn-light" id="zoomInGameScreenInput" name="zoomInGameScreenInput" value="+" onclick="zoomIn()">
|
||||
<input type="button" style="margin-top: 2%" class="btn btn-light" id="zoomOutGameScreenInput" name="zoomOutGameScreenInput" value="-" onclick="zoomOut()">
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
<div id="chaos-program-screen" style="display: none;">
|
||||
<div class="row" style="margin-top: 1%;">
|
||||
<form>
|
||||
<div id="alert_placeholder" style="margin-top: 3%;"></div>
|
||||
<div class="form-group">
|
||||
<label for="chaosProgramTextArea"></label>
|
||||
<textarea class="form-control" id="chaosProgramTextArea" rows="20" style="font-family: Courier, monospace;">
|
||||
jobs:
|
||||
cpu-attack:
|
||||
image: docker.io/luckysideburn/kubeinvaders-stress-ng:latest
|
||||
command: "stress-ng"
|
||||
args:
|
||||
- --help
|
||||
|
||||
mem-attack:
|
||||
image: docker.io/luckysideburn/kubeinvaders-stress-ng:latest
|
||||
command: "stress-ng"
|
||||
args:
|
||||
- --help
|
||||
|
||||
experiments:
|
||||
- name: cpu-attack-exp
|
||||
job: cpu-attack
|
||||
loop: 5
|
||||
after:
|
||||
check_url: https://google.it
|
||||
check_payload: ''
|
||||
check_tls_ignore: true
|
||||
- name: mem-attack-exp
|
||||
job: mem-attack
|
||||
loop: 5
|
||||
after:
|
||||
check_url: https://google.it
|
||||
check_payload: ''
|
||||
check_tls_ignore: true
|
||||
</textarea>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="game-screen" style="display: none;">
|
||||
<div class="row">
|
||||
<canvas id="myCanvas" width="720" height="480"></canvas>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col text-center">
|
||||
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
<input type="button" style="margin-top: 2%" class="btn btn-light" id="zoomInGameScreenInput" name="zoomInGameScreenInput" value="+" onclick="zoomIn()">
|
||||
<input type="button" style="margin-top: 2%" class="btn btn-light" id="zoomOutGameScreenInput" name="zoomOutGameScreenInput" value="-" onclick="zoomOut()">
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="alert_placeholder" style="margin-top: 3%;"></div>
|
||||
</div>
|
||||
<div id="alert_placeholder" style="margin-top: 3%;"></div>
|
||||
</div>
|
||||
<div id="footer" style="margin-top: 5%;">
|
||||
<div class="container text-center">
|
||||
@@ -211,6 +281,50 @@
|
||||
}
|
||||
}
|
||||
|
||||
function startGameMode() {
|
||||
|
||||
if (game_mode_switch) {
|
||||
game_mode_switch = false;
|
||||
} else {
|
||||
game_mode_switch = true;
|
||||
}
|
||||
|
||||
if (game_buttons.style.display === "none") {
|
||||
game_buttons.style.display = "block";
|
||||
} else {
|
||||
game_buttons.style.display = "none";
|
||||
}
|
||||
|
||||
if (game_screen.style.display === "none") {
|
||||
game_screen.style.display = "block";
|
||||
} else {
|
||||
game_screen.style.display = "none";
|
||||
}
|
||||
|
||||
chaos_program_screen.style.display = "none";
|
||||
programming_mode_buttons.style.display = "none";
|
||||
|
||||
}
|
||||
|
||||
function startProgrammingMode() {
|
||||
|
||||
if (chaos_program_screen.style.display === "none") {
|
||||
chaos_program_screen.style.display = "block";
|
||||
} else {
|
||||
chaos_program_screen.style.display = "none";
|
||||
}
|
||||
|
||||
if (programming_mode_buttons.style.display === "none") {
|
||||
programming_mode_buttons.style.display = "block";
|
||||
} else {
|
||||
programming_mode_buttons.style.display = "none";
|
||||
}
|
||||
|
||||
game_buttons.style.display = "none";
|
||||
game_screen.style.display = "none";
|
||||
|
||||
}
|
||||
|
||||
function showSpecialKeys() {
|
||||
$('#showSpecialKeysModal').modal('show');
|
||||
modal_opened = true;
|
||||
|
||||
+28
-5
@@ -21,6 +21,12 @@ var spaceshipxOld = 0;
|
||||
var randomFactor = 10;
|
||||
// pods list from kubernetes
|
||||
var pods = [];
|
||||
var game_mode_switch = false;
|
||||
|
||||
var game_buttons = document.getElementById("game-buttons");
|
||||
var game_screen = document.getElementById("game-screen");
|
||||
var chaos_program_screen = document.getElementById("chaos-program-screen");
|
||||
var programming_mode_buttons = document.getElementById("programming-mode-buttons");
|
||||
|
||||
// nodes list from kubernetes
|
||||
var nodes = [];
|
||||
@@ -194,6 +200,19 @@ function setChaosContainer() {
|
||||
}
|
||||
}
|
||||
|
||||
function runChaosProgram() {
|
||||
var oReq = new XMLHttpRequest();
|
||||
oReq.open("POST", "https://" + clu_endpoint + "/kube/chaos/programming_mode", true);
|
||||
oReq.onreadystatechange = function () {
|
||||
if (this.readyState === XMLHttpRequest.DONE && this.status === 200) {
|
||||
//console.log(this.responseText);
|
||||
$('#alert_placeholder2').text('New Chaos Program has been started.');
|
||||
}
|
||||
};;
|
||||
oReq.setRequestHeader("Content-Type", "application/json");
|
||||
oReq.send($('#chaosProgramTextArea').val());
|
||||
}
|
||||
|
||||
function startChaosNode(node_name) {
|
||||
var oReq = new XMLHttpRequest();
|
||||
oReq.onload = function () {
|
||||
@@ -252,13 +271,15 @@ function getNodes() {
|
||||
}
|
||||
}
|
||||
|
||||
window.setInterval(function getKubeItems() {
|
||||
getNodes();
|
||||
getPods();
|
||||
window.setInterval(function getKubeItems() {
|
||||
if (game_mode_switch) {
|
||||
getNodes();
|
||||
getPods();
|
||||
}
|
||||
}, 1000)
|
||||
|
||||
function keyDownHandler(e) {
|
||||
if (!modal_opened) {
|
||||
if (!modal_opened && game_mode_switch) {
|
||||
e.preventDefault();
|
||||
if(e.key == "Right" || e.key == "ArrowRight") {
|
||||
rightPressed = true;
|
||||
@@ -682,7 +703,9 @@ window.setInterval(function setAliens() {
|
||||
}, 1000)
|
||||
|
||||
window.setInterval(function metrics() {
|
||||
getMetrics()
|
||||
if (game_mode_switch) {
|
||||
getMetrics()
|
||||
}
|
||||
}, 2000)
|
||||
|
||||
getEndpoint();
|
||||
|
||||
Binary file not shown.
@@ -20,6 +20,10 @@ server {
|
||||
sub_filter endpoint_placeholder $endpoint;
|
||||
}
|
||||
|
||||
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";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
local https = require "ssl.https"
|
||||
local ltn12 = require "ltn12"
|
||||
local json = require 'lunajson'
|
||||
local redis = require "resty.redis"
|
||||
|
||||
if os.getenv("KUBERNETES_SERVICE_HOST") then
|
||||
k8s_url = "https://" .. os.getenv("KUBERNETES_SERVICE_HOST") .. ":" .. os.getenv("KUBERNETES_SERVICE_PORT_HTTPS")
|
||||
else
|
||||
k8s_url = os.getenv("ENDPOINT")
|
||||
end
|
||||
|
||||
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 token = os.getenv("TOKEN")
|
||||
local arg = ngx.req.get_uri_args()
|
||||
local body_data = ngx.req.get_body_data()
|
||||
|
||||
ngx.log(ngx.ERR, "[programming_mode]" .. body_data)
|
||||
|
||||
file = io.open("/tmp/experiments.yaml", "w")
|
||||
io.output(file)
|
||||
io.write(body_data)
|
||||
io.close(file)
|
||||
|
||||
local handle = io.popen("python3 /opt/programming_mode/start.py")
|
||||
local result = handle:read("*a")
|
||||
|
||||
ngx.say("Chaos program has been started...")
|
||||
@@ -0,0 +1,53 @@
|
||||
jobs:
|
||||
# cpu-attack:
|
||||
# image: docker.io/luckysideburn/kubeinvaders-stress-ng:latest
|
||||
# command: "stress-ng"
|
||||
# args:
|
||||
# - --cpu
|
||||
# - 4
|
||||
# - --io
|
||||
# - 2
|
||||
# - --vm
|
||||
# - 1
|
||||
# - --vm-bytes
|
||||
# - 1G
|
||||
# - --timeout
|
||||
# - 10s
|
||||
# - --metrics-brief
|
||||
|
||||
# mem-attack:
|
||||
# image: docker.io/luckysideburn/kubeinvaders-stress-ng:latest
|
||||
# command: "stress-ng"
|
||||
# args:
|
||||
# - --vm
|
||||
# - 2
|
||||
# - --vm-bytes
|
||||
# - 1G
|
||||
|
||||
cpu-attack:
|
||||
image: docker.io/luckysideburn/kubeinvaders-stress-ng:latest
|
||||
command: "stress-ng"
|
||||
args:
|
||||
- --help
|
||||
|
||||
mem-attack:
|
||||
image: docker.io/luckysideburn/kubeinvaders-stress-ng:latest
|
||||
command: "stress-ng"
|
||||
args:
|
||||
- --help
|
||||
|
||||
experiments:
|
||||
- name: cpu-attack-exp
|
||||
job: cpu-attack
|
||||
loop: 5
|
||||
after:
|
||||
check_url: https://google.it
|
||||
check_payload: ''
|
||||
check_tls_ignore: true
|
||||
- name: mem-attack-exp
|
||||
job: mem-attack
|
||||
loop: 5
|
||||
after:
|
||||
check_url: https://google.it
|
||||
check_payload: ''
|
||||
check_tls_ignore: true
|
||||
@@ -0,0 +1,3 @@
|
||||
yaml
|
||||
requests
|
||||
kubernetes
|
||||
@@ -0,0 +1,100 @@
|
||||
from asyncio.log import logger
|
||||
import yaml
|
||||
import logging
|
||||
import os
|
||||
from kubernetes import client, config
|
||||
from kubernetes.client.rest import ApiException
|
||||
import requests
|
||||
from string import Template
|
||||
import string
|
||||
import random
|
||||
|
||||
def create_container(image, name, command, args):
|
||||
container = client.V1Container(
|
||||
image=image,
|
||||
name=name,
|
||||
image_pull_policy='IfNotPresent',
|
||||
args=args,
|
||||
command=command,
|
||||
)
|
||||
|
||||
logging.info(
|
||||
f"Created container with name: {container.name}, "
|
||||
f"image: {container.image} and args: {container.args}"
|
||||
)
|
||||
|
||||
return container
|
||||
|
||||
def create_pod_template(pod_name, container):
|
||||
pod_template = client.V1PodTemplateSpec(
|
||||
spec=client.V1PodSpec(restart_policy="Never", containers=[container]),
|
||||
metadata=client.V1ObjectMeta(name=pod_name, labels={"pod_name": pod_name, "approle": "chaosnode"}),
|
||||
)
|
||||
|
||||
return pod_template
|
||||
|
||||
def create_job(job_name, pod_template):
|
||||
metadata = client.V1ObjectMeta(name=job_name, labels={"job_name": job_name, "approle": "chaosnode"})
|
||||
|
||||
job = client.V1Job(
|
||||
api_version="batch/v1",
|
||||
kind="Job",
|
||||
metadata=metadata,
|
||||
spec=client.V1JobSpec(backoff_limit=0, template=pod_template),
|
||||
)
|
||||
#logger.info(job)
|
||||
return job
|
||||
|
||||
|
||||
# create logger
|
||||
logging.basicConfig(level=os.environ.get("LOGLEVEL", "INFO"))
|
||||
logging.info('Starting script for KubeInvaders programming mode')
|
||||
|
||||
with open("./experiments.yaml", 'r') as stream:
|
||||
try:
|
||||
parsed_yaml=yaml.safe_load(stream)
|
||||
logging.info(f"Parsed yaml => {parsed_yaml}")
|
||||
except yaml.YAMLError as exc:
|
||||
print(exc)
|
||||
|
||||
configuration = client.Configuration()
|
||||
token = os.environ["TOKEN"]
|
||||
configuration.api_key = {"authorization": f"Bearer {token}"}
|
||||
configuration.host = os.environ["ENDPOINT"]
|
||||
configuration.insecure_skip_tls_verify = True
|
||||
configuration.verify_ssl = False
|
||||
|
||||
client.Configuration.set_default(configuration)
|
||||
client.Configuration.set_default(configuration)
|
||||
|
||||
api_instance = client.CoreV1Api()
|
||||
batch_api = client.BatchV1Api()
|
||||
namespace = "kubeinvaders"
|
||||
|
||||
for job in parsed_yaml["jobs"]:
|
||||
logging.info(f"Found job {job}")
|
||||
|
||||
for exp in parsed_yaml["experiments"]:
|
||||
logging.info(f"Processing the experiment {exp}")
|
||||
job_attrs = parsed_yaml["jobs"][exp["job"]]
|
||||
args = []
|
||||
for arg in job_attrs['args']:
|
||||
args.append(str(arg))
|
||||
|
||||
logging.info(f"args = {args}")
|
||||
logging.info(f"command = {job_attrs['command']}")
|
||||
|
||||
container = create_container(
|
||||
image = job_attrs['image'],
|
||||
name = exp['name'],
|
||||
command = [job_attrs['command']],
|
||||
args = args
|
||||
)
|
||||
|
||||
letters = string.ascii_lowercase
|
||||
rand_suffix = ''.join(random.choice(letters) for i in range(5))
|
||||
job_name = f"{exp['name']}-{rand_suffix}"
|
||||
pod_template = create_pod_template(exp["name"], container)
|
||||
logging.info(f"Creating job {job_name}")
|
||||
job_def = create_job(job_name, pod_template)
|
||||
batch_api.create_namespaced_job('kubeinvaders', job_def)
|
||||
Reference in New Issue
Block a user