start feature

This commit is contained in:
Eugenio Marzo
2022-12-28 07:54:21 +01:00
parent c94d27fab2
commit eab565a338
38 changed files with 463 additions and 30 deletions

View File

@@ -16,6 +16,7 @@ RUN apt-get update --fix-missing
RUN chmod 777 /usr/local/openresty/nginx
RUN luarocks install luasec
RUN luarocks install lunajson
RUN luarocks install lyaml
# Install kube-linter
RUN curl -L -O https://github.com/stackrox/kube-linter/releases/download/0.2.4/kube-linter-linux.tar.gz
@@ -34,7 +35,7 @@ COPY html5/ /var/www/html
# Install Redis
RUN apt-get install redis -y
COPY redis/redis.conf /etc/redis/redis.conf
COPY confs/redis/redis.conf /etc/redis/redis.conf
# Configure Nginx
RUN sed -i.bak 's/listen\(.*\)80;/listen 8081;/' /etc/nginx/conf.d/default.conf

View File

@@ -158,7 +158,7 @@ Example of metrics
| deleted_pods_total 16 | Total number of deleted pods |
| deleted_namespace_pods_count{namespace=myawesomenamespace} |Total number of deleted pods per namespace |
![Download Grafana dashboard](./grafana/KubeInvadersDashboard.json)
![Download Grafana dashboard](./confs/grafana/KubeInvadersDashboard.json)
![Alt Text](./doc_images/grafana1.png)

View File

@@ -7,9 +7,22 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="./bootstrap-5.0.0-dist/css/bootstrap.min.css">
<style>
.chaos-prog-area {
border: 7px solid #feb515;
border-radius: 5px;
-moz-border-radius: 15px;
-webkit-border-radius: 15px;
/* width: 500px;
height: 100px; */
padding: 5px;
border-image-slice: 5;
}
.btn-light {
border-color: #000000;
}
.btn-light:hover, .btn-light:focus, .btn-light:active, .btn-light.active, .open .dropdown-toggle.btn-default {
background-color: #5a078b;
color:#FFF;
@@ -19,14 +32,18 @@
.btn-light:hover {
transform: scale(1.05);
}
@font-face {
font-family: pixel;
src: url('./fonts/pixel.otf');
}
div {
font-family: pixel;
}
canvas { background: #000; display: block; margin: 0 auto; border:1px solid #ffffff;}
canvas { background: #161616 ; display: block; margin: 0 auto; border:1px solid #ffffff;}
</style>
</head>
<body>
@@ -46,6 +63,19 @@
<li><a class="dropdown-item" href="#" onclick="showSpecialKeys()">Show Special Keys</a></li>
<li><a class="dropdown-item" href="#" onclick="showCurrentChaosContainer()">Show Current Chaos Container for nodes</a></li>
<li><a class="dropdown-item" href="#" onclick="showSetCurrentChaosContainer()">Set Custom Chaos Container for nodes</a></li>
<li><a class="dropdown-item" href="#" onclick="showSetCurrentChaosContainer()">Load Consul</a></li>
<li><a class="dropdown-item" href="#" onclick="showSetCurrentChaosContainer()">Load Elasticsearch</a></li>
<li><a class="dropdown-item" href="#" onclick="showSetCurrentChaosContainer()">Load Etcd3</a></li>
<li><a class="dropdown-item" href="#" onclick="showSetCurrentChaosContainer()">Load Http</a></li>
<li><a class="dropdown-item" href="#" onclick="showSetCurrentChaosContainer()">Load Jira</a></li>
<li><a class="dropdown-item" href="#" onclick="showSetCurrentChaosContainer()">Load Kafka</a></li>
<li><a class="dropdown-item" href="#" onclick="showSetCurrentChaosContainer()">Load Kubernetes</a></li>
<li><a class="dropdown-item" href="#" onclick="showSetCurrentChaosContainer()">Load Mongodb</a></li>
<li><a class="dropdown-item" href="#" onclick="showSetCurrentChaosContainer()">Load Mysql</a></li>
<li><a class="dropdown-item" href="#" onclick="showSetCurrentChaosContainer()">Load Nomad</a></li>
<li><a class="dropdown-item" href="#" onclick="showSetCurrentChaosContainer()">Load Postgresql</a></li>
<li><a class="dropdown-item" href="#" onclick="showSetCurrentChaosContainer()">Load Prometheus</a></li>
<li><a class="dropdown-item" href="#" onclick="showSetCurrentChaosContainer()">Load Vault</a></li>
</li>
</ul>
</div>
@@ -88,7 +118,7 @@
<textarea class="form-control" id="currentChaosContainerJsonTextArea" rows="20"></textarea>
</div>
<div class="form-group">
<p id="alert_placeholder2" style="color: black; font-family: 'Courier New', Courier, monospace; margin-top: 3%;"></p>
<p id="alert_placeholder2" style="color: #161616; font-family: 'Courier New', Courier, monospace; margin-top: 3%;"></p>
</div>
<div class="modal-footer">
<button type="
@@ -190,11 +220,12 @@
<div id="chaos-program-screen" style="display: none;">
<div class="row" style="margin-top: 1%;">
<form>
<div class="col">
<form>
<div id="alert_placeholder" style="margin-top: 1%;"></div>
<div class="form-group">
<label for="chaosProgramTextArea"></label>
<textarea class="form-control" id="chaosProgramTextArea" rows="20" style="font-family: Courier, monospace;">
<textarea class="form-control chaos-prog-area" id="chaosProgramTextArea" rows="50" style="font-family: Courier, monospace;">
jobs:
cpu-attack:
additional-labels:
@@ -222,8 +253,13 @@ experiments:
loop: 5
</textarea>
</div>
</form>
<div id="chaosJobLogsDiv" style="margin-top: 2%; overflow-y: scroll; height:1000px;"></div>
</form>
<div id="chaosJobLogsDiv" style="margin-top: 2%; overflow-y: scroll; height:1000px;"></div>
</div>
<div class="col">
<div id="chaosProgramDiagram">
</div>
</div>
</div>
</div>
@@ -286,25 +322,10 @@ experiments:
<div align="center" style="margin-top: 20%;">
<img src="images/kubeinvaders_spaceship.png">
</div>
<div class="container text-center">
<div class="container text-center" style="margin-top: 2%;">
<p class="text-muted credit" style="color:#fff">kubeinvaders_version: v1.9.5</p>
</div>
</div>
<div class='row' style='margin-top: 2%; color: #1d1919;'>
<div class='row' style="font-size: 12px">-----------------------</div>
<div class='row' style="font-size: 12px">Namespace:{pod.metadata.namespace}</div>
<div class='row' style="font-size: 12px">Pod:{pod.metadata.name}</div>
<div class='row' style="font-size: 12px">Container:{pod.metadata.name}</div>
</div>
<div class='row' style='margin-top: 0.5%; color: #444141; font-size: 12px; font-family: Courier New, Courier, monospace;'>
>>>{api_response_line}
</div>
<div class='row' style="font-size: 12px">-----------------------</div>
<script src="kubeinvaders.js"></script>
<script src="./bootstrap-5.0.0-dist/js/bootstrap.min.js"></script>
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>

View File

@@ -70,9 +70,9 @@ var shuffle = true;
var help = false;
var chaos_nodes = true;
var chaos_pods = true;
var log_tail_alert = '<div id="alert_placeholder3" style="margin-top: 2%; margin-bottom: 1%; background-color:#000000; color: #0cf52b" class="alert" role="alert">';
var alert_div = '<div id="alert_placeholder" style="margin-top: 2%; margin-bottom: 1%; background-color:#000000; color: #0cf52b" class="alert" role="alert">';
var alert_div_webtail = '<div id="alert_placeholder3" style="margin-top: 2%; background-color:#000000; color: #0cf52b" class="alert" role="alert">';
var log_tail_alert = '<div id="alert_placeholder3" style="margin-top: 2%; margin-bottom: 1%; background-color: #161616; color: #ffffff" class="alert" role="alert">';
var alert_div = '<div id="alert_placeholder" style="margin-top: 2%; margin-bottom: 1%; background-color: #161616; color: #ffffff" class="alert" role="alert">';
var alert_div_webtail = '<div id="alert_placeholder3" style="margin-top: 2%; background-color: #161616; color: #ffffff" class="alert" role="alert">';
var kubelinter = '';
var showPodName = true
@@ -80,6 +80,24 @@ var latestPodNameY = '';
var namespacesJumpFlag = false;
var namespacesJumpStaus = 'Disabled';
function drawChaosProgramDiagram() {
var chaosProgram = "";
chaosProgram = $('#chaosProgramTextArea').text();
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);
$('#chaosProgramDiagram').html(this.responseText);
}
};;
oReq.setRequestHeader("Content-Type", "application/json");
oReq.send(chaosProgram);
}
function IsJsonString(str) {
try {
JSON.parse(str);
@@ -160,6 +178,7 @@ function runKubeLinter() {
oReq.open("GET", "https://" + clu_endpoint + "/kube/kube-linter?namespace=" + namespace);
oReq.send();
}
function getNamespaces() {
var oReq = new XMLHttpRequest();
oReq.onload = function () {
@@ -701,6 +720,7 @@ function randNamespaceJump(min, max, jumpRandomFactor) {
switchNamespace();
}
}
window.setInterval(function setAliens() {
if (shuffle) {
@@ -757,7 +777,12 @@ window.setInterval(function setAliens() {
}
}, 1000)
window.setInterval(function chaosProgram() {
drawChaosProgramDiagram();
}, 2000)
window.setInterval(function metrics() {
if (game_mode_switch || programming_mode_switch) {
getMetrics()
}

View File

@@ -0,0 +1,14 @@
FROM python:3.9
WORKDIR /app
COPY requirements.txt requirements.txt
COPY requirements.txt requirements.txt
RUN /usr/local/bin/python -m pip install --upgrade pip
RUN pip3 install -r requirements.txt
COPY . .
CMD [ "bash", "start.sh" ]

View File

@@ -0,0 +1,3 @@
#!/bin/bash
docker build . -t docker.io/kubeinvaders/chaos_exec:latest

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

View File

@@ -0,0 +1,21 @@
import time
import consul
# Connect to the Consul cluster
client = consul.Consul()
# Continuously register and deregister a service
while True:
# Register the service
client.agent.service.register(
"stress-test-service",
port=8080,
tags=["stress-test"],
check=consul.Check().tcp("localhost", 8080, "10s")
)
# Deregister the service
client.agent.service.deregister("stress-test-service")
time.sleep(1)

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@@ -0,0 +1,16 @@
import time
from elasticsearch import Elasticsearch
# Connect to the Elasticsearch cluster
es = Elasticsearch(["localhost"])
# Continuously index and delete documents
while True:
# Index a document
es.index(index="test-index", doc_type="test-type", id=1, body={"test": "test"})
# Delete the document
es.delete(index="test-index", doc_type="test-type", id=1)
time.sleep(1)

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

View File

@@ -0,0 +1,16 @@
import time
import etcd3
# Connect to the etcd3 cluster
client = etcd3.client()
# Continuously set and delete keys
while True:
# Set a key
client.put("/stress-test-key", "stress test value")
# Delete the key
client.delete("/stress-test-key")
time.sleep(1)

Binary file not shown.

After

Width:  |  Height:  |  Size: 299 KiB

View File

@@ -0,0 +1,22 @@
import time
import requests
# Set up the URL to send requests to
url = 'http://localhost:8080/'
# Set up the number of requests to send
num_requests = 10000
# Set up the payload to send
payload = {'key': 'value'}
# Send the requests
start_time = time.time()
for i in range(num_requests):
requests.post(url, json=payload)
end_time = time.time()
# Calculate the throughput
throughput = num_requests / (end_time - start_time)
print(f'Throughput: {throughput} requests/second')

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

View File

@@ -0,0 +1,24 @@
import time
from jira import JIRA
# Connect to the Jira instance
jira = JIRA(
server="https://jira.example.com",
basic_auth=("user", "password")
)
# Continuously create and delete issues
while True:
# Create an issue
issue = jira.create_issue(
project="PROJECT",
summary="Stress test issue",
description="This is a stress test issue.",
issuetype={"name": "Bug"}
)
# Delete the issue
jira.delete_issue(issue)
time.sleep(1)

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

View File

@@ -0,0 +1,30 @@
import time
import random
from kafka import KafkaProducer
# Set up the Kafka producer
producer = KafkaProducer(bootstrap_servers=['localhost:9092'])
# Set up the topic to send messages to
topic = 'test'
# Set up the number of messages to send
num_messages = 10000
# Set up the payload to send
payload = b'a' * 1000000
# Send the messages
start_time = time.time()
for i in range(num_messages):
producer.send(topic, payload)
end_time = time.time()
# Calculate the throughput
throughput = num_messages / (end_time - start_time)
print(f'Throughput: {throughput} messages/second')
# Flush and close the producer
producer.flush()
producer.close()

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

View File

@@ -0,0 +1,25 @@
import time
import kubernetes
# Create a Kubernetes client
client = kubernetes.client.CoreV1Api()
# Continuously create and delete pods
while True:
# Create a pod
pod = kubernetes.client.V1Pod(
metadata=kubernetes.client.V1ObjectMeta(name="stress-test-pod"),
spec=kubernetes.client.V1PodSpec(
containers=[kubernetes.client.V1Container(
name="stress-test-container",
image="nginx:latest"
)]
)
)
client.create_namespaced_pod(namespace="default", body=pod)
# Delete the pod
client.delete_namespaced_pod(name="stress-test-pod", namespace="default")
time.sleep(1)

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

View File

@@ -0,0 +1,30 @@
import time
import random
from pymongo import MongoClient
# Set up the MongoDB client
client = MongoClient('mongodb://localhost:27017/')
# Set up the database and collection to use
db = client['test']
collection = db['test']
# Set up the number of documents to insert
num_documents = 10000
# Set up the payload to insert
payload = {'key': 'a' * 1000000}
# Insert the documents
start_time = time.time()
for i in range(num_documents):
collection.insert_one(payload)
end_time = time.time()
# Calculate the throughput
throughput = num_documents / (end_time - start_time)
print(f'Throughput: {throughput} documents/second')
# Close the client
client.close()

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

View File

@@ -0,0 +1,21 @@
import time
import mysql.connector
# Connect to the MySQL database
cnx = mysql.connector.connect(
host="localhost",
user="root",
password="password",
database="test"
)
cursor = cnx.cursor()
# Continuously insert rows into the "test_table" table
while True:
cursor.execute("INSERT INTO test_table (col1, col2) VALUES (%s, %s)", (1, 2))
cnx.commit()
time.sleep(1)
# Close the database connection
cnx.close()

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -0,0 +1,33 @@
import time
import nomad
# Create a Nomad client
client = nomad.Nomad()
# Create a batch of jobs to submit to Nomad
jobs = [{
"Name": "stress-test-job",
"Type": "batch",
"Datacenters": ["dc1"],
"TaskGroups": [{
"Name": "stress-test-task-group",
"Tasks": [{
"Name": "stress-test-task",
"Driver": "raw_exec",
"Config": {
"command": "sleep 10"
},
"Resources": {
"CPU": 500,
"MemoryMB": 512
}
}]
}]
}]
# Continuously submit the batch of jobs to Nomad
while True:
for job in jobs:
client.jobs.create(job)
time.sleep(1)

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -0,0 +1,41 @@
import time
import random
import psycopg2
# Set up the connection parameters
params = {
'host': 'localhost',
'port': '5432',
'database': 'test',
'user': 'postgres',
'password': 'password'
}
# Connect to the database
conn = psycopg2.connect(**params)
# Set up the cursor
cur = conn.cursor()
# Set up the table and payload to insert
table_name = 'test'
payload = 'a' * 1000000
# Set up the number of rows to insert
num_rows = 10000
# Insert the rows
start_time = time.time()
for i in range(num_rows):
cur.execute(f"INSERT INTO {table_name} (col) VALUES ('{payload}')")
conn.commit()
end_time = time.time()
# Calculate the throughput
throughput = num_rows / (end_time - start_time)
print(f'Throughput: {throughput} rows/second')
# Close the cursor and connection
cur.close()
conn.close()

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

View File

@@ -0,0 +1,30 @@
import time
import random
from prometheus_client import CollectorRegistry, Gauge, push_to_gateway
# Set up the metrics registry
registry = CollectorRegistry()
# Set up the metric to push
gauge = Gauge('test_gauge', 'A test gauge', registry=registry)
# Set up the push gateway URL
push_gateway = 'http://localhost:9091'
# Set up the number of pushes to send
num_pushes = 10000
# Set up the metric value to push
value = random.random()
# Push the metric
start_time = time.time()
for i in range(num_pushes):
gauge.set(value)
push_to_gateway(push_gateway, job='test_job', registry=registry)
end_time = time.time()
# Calculate the throughput
throughput = num_pushes / (end_time - start_time)
print(f'Throughput: {throughput} pushes/second')

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@@ -0,0 +1,17 @@
import time
import hvac
# Connect to the Vault instance
client = hvac.Client()
client.auth_approle(approle_id="approle-id", secret_id="secret-id")
# Continuously read and write secrets
while True:
# Write a secret
client.write("secret/stress-test", value="secret value")
# Read the secret
client.read("secret/stress-test")
time.sleep(1)

View File

@@ -0,0 +1,14 @@
atlassian-api-py
python-consul
elasticsearch
etcd3
hvac
jira
kubernetes
mysql.connector
nomad
prometheus_client
psycopg2
pymongo
requests
kafka

View File

@@ -50,9 +50,11 @@ server {
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 ENDPOINT is nil
ngx.say(os.getenv("ENDPOINT"))
if os.getenv("ENDPOINT") == nil then
ngx.say("Error! ENDPOINT is nil!")
else
ngx.say(os.getenv("ENDPOINT"))
end
}
}
@@ -100,4 +102,29 @@ server {
lua_need_request_body 'on';
access_by_lua_file "/usr/local/openresty/nginx/conf/kubeinvaders/chaos-containers.lua";
}
location /chaos/programs/json-flow {
content_by_lua_block {
local lyaml = require "lyaml"
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 data = yaml.load(ngx.req.get_body_data())
local reponse = ""
for key, value in pairs(data) do
if key == "experiments" then
for exp, expvalue in pairs(key) do
reponse = response .. "<div class='row'>"
reponse = response .. expvalue
reponse = response .. "</div>"
end
end
end
ngx.say(reponse)
}
}
}

View File

@@ -101,11 +101,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}"
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)
else:
pod_template = create_pod_template(exp["name"], {}, container)
logging.info(f"Creating job {job_name}")
job_def = create_job(job_name, pod_template)