diff --git a/Dockerfile b/Dockerfile index 93fe7db..24473b3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -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"] \ No newline at end of file +ENTRYPOINT ["/entrypoint.sh"] diff --git a/html5/index.html b/html5/index.html index 803996d..bc38f40 100644 --- a/html5/index.html +++ b/html5/index.html @@ -338,17 +338,21 @@ diff --git a/html5/kubeinvaders.js b/html5/kubeinvaders.js index df4f275..40786e4 100644 --- a/html5/kubeinvaders.js +++ b/html5/kubeinvaders.js @@ -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. '); + 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 + '
' - if (i < flow["experiments"].length - 1 ) { - flow_html = flow_html + '' + if (flow["experiments"][i]["loop"] == 1){ + times = "once"; + } + else if (flow["experiments"][i]["loop"] == 2) { + times = "twice" + } + else { + times = "times" + } + + flow_html = flow_html + '
'; + 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 + '
'; + } } 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 + ' '); @@ -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() } diff --git a/nginx/KubeInvaders.conf b/nginx/KubeInvaders.conf index 3c1a8de..211b11c 100644 --- a/nginx/KubeInvaders.conf +++ b/nginx/KubeInvaders.conf @@ -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() diff --git a/scripts/data/codenames.txt b/scripts/data/codenames.txt new file mode 100644 index 0000000..78b5595 --- /dev/null +++ b/scripts/data/codenames.txt @@ -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 diff --git a/scripts/logs_loop/start.py b/scripts/logs_loop/start.py index 167f1cc..7d3f948 100644 --- a/scripts/logs_loop/start.py +++ b/scripts/logs_loop/start.py @@ -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"): diff --git a/scripts/metrics_loop/start.py b/scripts/metrics_loop/start.py index 735e833..e4260b2 100644 --- a/scripts/metrics_loop/start.py +++ b/scripts/metrics_loop/start.py @@ -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) diff --git a/scripts/programming_mode/start.py b/scripts/programming_mode/start.py index f3717e0..3a3d4ee 100644 --- a/scripts/programming_mode/start.py +++ b/scripts/programming_mode/start.py @@ -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: