This commit is contained in:
Eugenio Marzo
2023-01-03 20:51:09 +01:00
parent dd7f608509
commit fb15ee4ac9
8 changed files with 424 additions and 39 deletions
+3 -2
View File
@@ -43,7 +43,7 @@ COPY confs/redis/redis.conf /etc/redis/redis.conf
# Configure Nginx and KubeInvaders conf
RUN sed -i.bak 's/listen\(.*\)80;/listen 8081;/' /etc/nginx/conf.d/default.conf
RUN mkdir /usr/local/openresty/nginx/conf/kubeinvaders
RUN mkdir -p /usr/local/openresty/nginx/conf/kubeinvaders/data
COPY nginx/nginx.conf /etc/nginx/nginx.conf
COPY nginx/KubeInvaders.conf /etc/nginx/conf.d/KubeInvaders.conf
RUN chmod g+rwx /var/cache/nginx /var/run /var/log/nginx /etc/nginx/conf.d
@@ -58,6 +58,7 @@ COPY scripts/chaos-node.lua /usr/local/openresty/nginx/conf/kubeinvaders/chaos-n
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/data/codenames.txt /usr/local/openresty/nginx/conf/kubeinvaders/data/codenames.txt
# Copy Python helpers
COPY scripts/programming_mode /opt/programming_mode/
@@ -70,4 +71,4 @@ EXPOSE 8080
ENV PATH=/usr/local/openresty/nginx/sbin:$PATH
COPY ./entrypoint.sh /
RUN chmod a+rwx ./entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
ENTRYPOINT ["/entrypoint.sh"]
+10 -6
View File
@@ -338,17 +338,21 @@
<label for="chaosProgramTextArea"></label>
<textarea class="form-control chaos-prog-area" id="chaosProgramTextArea" rows="50" style="min-width: 100%; font-family: Courier, monospace;">
jobs:
cpu-attack:
cpu-attack-job:
additional-labels:
test-label: "test"
chaos-controller: kubeinvaders
chaos-type: stress-ng
chaos-codename: CODENAME_PLACEHOLDER
image: docker.io/luckysideburn/kubeinvaders-stress-ng:latest
command: "stress-ng"
args:
- --help
mem-attack:
mem-attack-job:
additional-labels:
test-label: "test"
chaos-controller: kubeinvaders
chaos-type: stress-ng
chaos-codename: CODENAME_PLACEHOLDER
image: docker.io/luckysideburn/kubeinvaders-stress-ng:latest
command: "stress-ng"
args:
@@ -356,11 +360,11 @@ jobs:
experiments:
- name: cpu-attack-exp
job: cpu-attack
job: cpu-attack-job
loop: 5
- name: mem-attack-exp
job: mem-attack
job: mem-attack-job
loop: 5
</textarea>
</div>
+74 -19
View File
@@ -82,6 +82,11 @@ var namespacesJumpStaus = 'Disabled';
var latest_preset_name = "";
var latest_preset_lang = "";
var codename = getCodeName();
const codename_regex = /chaos-codename:\ [a-zA-Z_]*/g;
const chaos_job_regex = /chaos_jobs_status.*/g;
var codename_configured = false;
var chaos_jobs_status = new Map();
function isJsonString(str) {
try {
@@ -92,11 +97,26 @@ function isJsonString(str) {
return true;
}
function getCodeName() {
var oReq = new XMLHttpRequest();
oReq.onreadystatechange = function () {
if (this.readyState === XMLHttpRequest.DONE && this.status === 200) {
codename = this.responseText.trim();
if (codename == "") {
$('#alert_placeholder').replaceWith(alert_div + 'Error getting codename from backend. </div>');
codename = "error_fix_getcodename_from_backend";
}
}
};;
oReq.open("GET", "https://" + clu_endpoint + "/codename");
oReq.send();
}
function loadSavedPreset(tool, lang, defaultpreset) {
var oReq = new XMLHttpRequest();
oReq.onreadystatechange = function () {
if (this.readyState === XMLHttpRequest.DONE && this.status === 200) {
console.log("response of loadSavedPreset: ||" + this.responseText + "||");
//console.log("response of loadSavedPreset: ||" + this.responseText + "||");
if (this.responseText.trim() != "nil") {
$("#currentLoadTest").val(this.responseText.trim());
} else {
@@ -114,7 +134,7 @@ function savePreset(action) {
presetLang = latest_preset_lang;
presetName = latest_preset_name;
console.log("Saving preset. name:" + presetName + ", lang:" + presetName + ", body: " + presetBody);
//console.log("Saving preset. name:" + presetName + ", lang:" + presetName + ", body: " + presetBody);
var oReq = new XMLHttpRequest();
oReq.open("POST", "https://" + clu_endpoint + "/chaos/loadpreset/save?name=" + presetName + "&lang=" + presetLang, true);
@@ -123,12 +143,13 @@ function savePreset(action) {
if (this.readyState === XMLHttpRequest.DONE && this.status === 200 && action == "apply") {
// console.log(this.responseText);
// $('#alert_placeholder').replaceWith(this.responseText);
presetBody = $('#chaosProgramTextArea').text(`jobs:
${presetName}:
presetBody = $('#chaosProgramTextArea').val(`chaos-codename: ${codename}\njobs:
${presetName}-job:
additional-labels:
created-by: kubeinvaders
lang: ${presetLang}
type: loadtest
chaos-controller: kubeinvaders
chaos-lang: ${presetLang}
chaos-type: loadtest
chaos-codename: ${codename}
image: docker.io/luckysideburn/chaos-exec:v1.0.0
command: bash
args:
@@ -136,8 +157,8 @@ function savePreset(action) {
- ${presetLang}
- http://kubeinvaders:8080/${presetLang}_${presetName}
experiments:
- name: ${presetName}
job: ${presetName}
- name: ${presetName}-exp
job: ${presetName}-job
loop: 5`);
}
};;
@@ -154,30 +175,44 @@ experiments:
function drawChaosProgramFlow() {
var chaosProgram = "";
chaosProgram = $('#chaosProgramTextArea').text();
var oReq = new XMLHttpRequest();
// var chaosProgramWithCodename = chaosProgram.replace('CODENAME_PLACEHOLDER', codename);
// console.log(chaosProgramWithCodename);
// $('#chaosProgramTextArea').val(chaosProgramWithCodename);
var oReq = new XMLHttpRequest();
oReq.open("POST", "https://" + clu_endpoint + "/chaos/programs/json-flow", true);
oReq.onreadystatechange = function () {
if (this.readyState === XMLHttpRequest.DONE && this.status === 200) {
// console.log(this.responseText);
if (isJsonString(this.responseText)){
var flow = JSON.parse(this.responseText);
//console.log(flow)
var flow_html = "";
let i = 0;
var times = "";
$('#chaosProgramFlow').html("");
while (i < flow["experiments"].length) {
flow_html = flow_html + '<div class="row"><div class="alert alert-dark" role="alert">' + flow["experiments"][i]["name"] + '(x' + flow["experiments"][i]["loop"] +')</div></div>'
if (i < flow["experiments"].length - 1 ) {
flow_html = flow_html + '<img src="images/down-arrow.png" width="30" height="30" style="margin-bottom: 2%;">'
if (flow["experiments"][i]["loop"] == 1){
times = "once";
}
else if (flow["experiments"][i]["loop"] == 2) {
times = "twice"
}
else {
times = "times"
}
flow_html = flow_html + '<div class="row"><div class="alert alert-light" role="alert">Do ' + flow["experiments"][i]["name"] + ' ' + flow["experiments"][i]["loop"] + ' ' + times + '</div></div>';
search_job = codename + ":" + flow["experiments"][i]["name"]
//console.log("Search " + search_job);
for (let [key, value] of chaos_jobs_status) {
if (key.search(search_job)) {
flow_html = flow_html + '<div class="row"><div class="alert alert-light" role="alert">[' + key.split(":")[2] + '] Status: ' + value + '</div></div>';
}
}
i++;
}
//console.log("FLOWHTML" + flow_html);
$('#chaosProgramFlow').html(flow_html);
}
else {
@@ -231,6 +266,13 @@ function getMetrics() {
else if (metric[0] == "pods_not_running_on_selected_ns") {
$('#pods_not_running_on').text(metric[1]);
}
else if (metric[0].match(chaos_job_regex)) {
metrics_split = metric[0].split(":");
chaos_jobs_status.set(metrics_split[1] + ":" + metrics_split[2] + ":" + metrics_split[3], metric[1]);
// for (let [key, value] of chaos_jobs_status) {
// console.log(key + " = " + value);
// }
}
else if (metric[0] == "current_chaos_job_pod") {
$('#current_chaos_job_pod').text(metric[1]);
}
@@ -373,6 +415,11 @@ function setChaosContainer() {
function runChaosProgram() {
chaosProgram = $('#chaosProgramTextArea').val();
chaosProgramWithCodename = chaosProgram.replace(codename_regex, "chaos-codename: " + codename);
$('#chaosProgramTextArea').val(chaosProgramWithCodename);
codename_configured = true;
var now = new Date().toLocaleString().replace(',','')
$('#alert_placeholder4').replaceWith(alert_div + 'Chaos Program launched at ' + now + ' </div>');
@@ -882,6 +929,14 @@ window.setInterval(function setAliens() {
}, 1000)
window.setInterval(function backgroundTasks() {
if (!codename_configured) {
chaosProgram = $('#chaosProgramTextArea').val();
chaosProgramWithCodename = chaosProgram.replace(codename_regex, "chaos-codename: " + codename);
$('#chaosProgramTextArea').val(chaosProgramWithCodename);
codename_configured = true;
}
if (game_mode_switch || programming_mode_switch) {
getMetrics()
}
+49 -1
View File
@@ -70,6 +70,54 @@ server {
}
}
location /codename {
content_by_lua_block {
local open = io.open
local function read_rand_line_from_file(path)
local word_array_index = 0
local word_array = {}
local file = open(path, "rb") -- r read mode and b binary mode
if not file then return nil end
local content = file:read "*a" -- *a or *all reads the whole file
file:close()
for word in string.gmatch(content, "%S+") do
word_array[word_array_index] = word
word_array_index = word_array_index + 1
end
while (type(rand) ~= "number")
do
math.randomseed(os.clock()*100000000000)
rand = math.random(0, word_array_index - 1)
end
return word_array[rand]
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("programming_mode_codename:" .. random_word) == nil)
do
random_word = read_rand_line_from_file("/usr/local/openresty/nginx/conf/kubeinvaders/data/codenames.txt")
end
red:set("programming_mode_codename:" .. random_word, "active")
ngx.say(random_word)
}
}
location /metrics {
default_type text/html;
content_by_lua_block {
@@ -222,7 +270,7 @@ server {
ngx.log(ngx.ERR, "[programming_mode_diagram] write temp file " .. filename)
yamlfile = io.open(filename, "w")
local yamlfile = io.open(filename, "w")
yamlfile:write(data)
yamlfile:close()
+266
View File
@@ -0,0 +1,266 @@
actinium
alligator
alpaca
aluminum
americium
ant
antelope
antimony
ape
argon
armadillo
arsenic
astatine
baboon
badger
barium
bat
bear
beaver
bee
beetle
berkelium
beryllium
bigfoot
bismuth
bohrium
boron
bromine
buffalo
burro
butterfly
cadmium
calcium
californium
camel
carabao
carbon
caribou
cat
cattle
cerium
cesium
cheetah
chimpanzee
chinchilla
chlorine
chromium
cicada
clam
cobalt
cockroach
cod
copernicium
copper
coyote
crab
cricket
crocodile
crow
curium
darmstadtium
deer
dinosaur
dog
dolphin
donkey
dragon
dubnium
duck
dysprosium
eagle
eel
einsteinium
elephant
elk
erbium
europium
fermium
ferret
fish
flerovium
fluorine
fly
fox
francium
frog
gadolinium
gallium
gerbil
germanium
giraffe
gnat
gnu
goat
gold
goldfish
goose
gorilla
grasshopper
hafnium
hamster
hare
hassium
hedgehog
helium
herring
hippopotamus
holmium
hornet
horse
hound
hydrogen
hyena
impala
indium
insect
iodine
iridium
iron
jackal
jellyfish
kangaroo
koala
kraken
krypton
lanthanum
lawrencium
lead
leopard
lion
lithium
livermorium
lizard
llama
locust
louse
lutetium
macaw
magnesium
mallard
mammoth
manatee
manganese
marten
meitnerium
mendelevium
mercury
mink
minnow
mole
molybdenum
monkey
moose
moscovium
mosquito
mouse
mule
muskrat
neodymium
neon
neptunium
nessie
nickel
nihonium
ninja
niobium
nitrogen
nobelium
oganesson
osmium
otter
ox
oxygen
oyster
palladium
panda
phosphorus
pig
pirate
platinum
platypus
plutonium
polonium
porcupine
porpoise
potassium
praseodymium
promethium
protactinium
pug
rabbit
raccoon
radium
radon
rat
raven
reindeer
rhenium
rhinoceros
rhodium
robot
roentgenium
rubidium
ruthenium
rutherfordium
salmon
samarium
samurai
sardine
scandium
scorpion
seaborgium
seal
selenium
serval
shark
sheep
silicon
silver
skunk
snail
snake
sodium
spider
squirrel
strontium
sulfur
swan
tantalum
technetium
tellurium
tennessine
terbium
termite
thallium
thorium
thulium
tiger
tin
titanium
toad
trout
tungsten
turtle
unicorn
uranium
vanadium
wallaby
walrus
wasp
weasel
whale
wildebeest
wolf
wombat
woodchuck
worm
xenon
yak
yellowjacket
ytterbium
yttrium
zebra
zinc
zirconium
zombie
+3 -2
View File
@@ -200,8 +200,9 @@ while True:
for pod in final_pod_list:
container_list = []
for container in pod.spec.containers:
if re.search(f"{containers_re}", container.name):
container_list.append(container.name)
if "containers_re" in locals() or "containers_re" in globals():
if re.search(f"{containers_re}", container.name):
container_list.append(container.name)
for container in container_list:
if webtail_switch or (pod.metadata.labels.get('approle') != None and pod.metadata.labels['approle'] == 'chaosnode' and pod.status.phase != "Pending"):
+9 -3
View File
@@ -30,16 +30,16 @@ def create_container(image, name, command, args):
return container
def create_pod_template(pod_name, container):
def create_pod_template(pod_name, container, job_name):
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"}),
metadata=client.V1ObjectMeta(name=pod_name, labels={"pod-name-prefix": pod_name, "approle": "chaosnode", "job-name": job_name}),
)
return pod_template
def create_job(job_name, pod_template):
metadata = client.V1ObjectMeta(name=job_name, labels={"job_name": job_name, "approle": "chaosnode"})
metadata = client.V1ObjectMeta(name=job_name, labels={"job-name": job_name, "approle": "chaosnode"})
job = client.V1Job(
api_version="batch/v1",
@@ -85,4 +85,10 @@ while True:
if pod.metadata.labels.get('approle') != None and pod.metadata.labels['approle'] == 'chaosnode':
if pod.status.phase == "Pending" or pod.status.phase == "Running":
r.incr('current_chaos_job_pod')
if pod.metadata.labels.get('chaos-codename') != None:
codename = pod.metadata.labels.get('chaos-codename')
job_name = pod.metadata.labels.get('job-name')
exp_name = pod.metadata.labels.get('experiment-name')
r.set(f"chaos_jobs_status:{codename}:{exp_name}:{job_name}", pod.status.phase)
time.sleep(1)
+10 -6
View File
@@ -27,8 +27,8 @@ def create_container(image, name, command, args):
return container
def create_pod_template(pod_name, additional_labels, container):
pod_labels = { "app": "kubeinvaders", "pod_name": pod_name, "approle": "chaosnode" }
def create_pod_template(pod_name, additional_labels, container, exp_name):
pod_labels = {"app": "kubeinvaders", "approle": "chaosnode", "experiment-name": exp_name}
pod_labels.update(additional_labels)
pod_template = client.V1PodTemplateSpec(
spec=client.V1PodSpec(restart_policy="Never", containers=[container]),
@@ -38,7 +38,7 @@ def create_pod_template(pod_name, additional_labels, container):
return pod_template
def create_job(job_name, pod_template):
metadata = client.V1ObjectMeta(name=job_name, labels={"job_name": job_name, "approle": "chaosnode"})
metadata = client.V1ObjectMeta(name=job_name, labels={"job-name": job_name, "approle": "chaosnode"})
job = client.V1Job(
api_version="batch/v1",
@@ -100,13 +100,13 @@ for exp in parsed_yaml["experiments"]:
letters = string.ascii_lowercase
rand_suffix = ''.join(random.choice(letters) for i in range(5))
job_name = f"{exp['name']}-{rand_suffix}"
job_name = f"{exp['job']}-{rand_suffix}"
if 'additional-labels' in job_attrs:
logging.info(f"additional-labels = {job_attrs['additional-labels']}")
pod_template = create_pod_template(exp["name"], job_attrs['additional-labels'], container)
pod_template = create_pod_template(f"{exp['name']}-exec", job_attrs['additional-labels'], container, exp["name"])
else:
pod_template = create_pod_template(exp["name"], {}, container)
pod_template = create_pod_template(f"{exp['name']}-exec", {}, container, exp["name"])
logging.info(f"Creating job {job_name}")
job_def = create_job(job_name, pod_template)
@@ -117,6 +117,10 @@ for exp in parsed_yaml["experiments"]:
logging.info(e)
quit()
if 'additional-labels' in job_attrs and 'chaos-codename' in job_attrs['additional-labels']:
codename = job_attrs['additional-labels']['chaos-codename']
r.set(f"chaos_jobs_status:{codename}:{exp['name']}:{exp['job']}", "Created")
if r.exists('chaos_node_jobs_total') == 1:
r.incr('chaos_node_jobs_total')
else: