Skip to content
Snippets Groups Projects
Commit 7b55c6d1 authored by Lorenz Boguhn's avatar Lorenz Boguhn
Browse files

Applied Code Reviews for TopicManager and WorkloadGeneratorStateCleaner

parent 4ffaa587
No related branches found
No related tags found
4 merge requests!159Re-implementation of Theodolite with Kotlin/Quarkus,!157Update Graal Image in CI pipeline,!83WIP: Re-implementation of Theodolite with Kotlin/Quarkus,!78Resolve "Implement Quarkus/Kotlin protype"
This commit is part of merge request !78. Comments created here will be created in the context of that merge request.
...@@ -25,7 +25,7 @@ abstract class BenchmarkExecutor(val benchmark: Benchmark, val results: Results, ...@@ -25,7 +25,7 @@ abstract class BenchmarkExecutor(val benchmark: Benchmark, val results: Results,
* @param res resources to be tested. * @param res resources to be tested.
* @return True, if the number of resources are suitable for the given load, false otherwise. * @return True, if the number of resources are suitable for the given load, false otherwise.
*/ */
abstract fun runExperiment(load: LoadDimension, res: Resource): Boolean; abstract fun runExperiment(load: LoadDimension, res: Resource): Boolean
/** /**
* Wait while the benchmark is running and log the number of minutes executed every 1 minute. * Wait while the benchmark is running and log the number of minutes executed every 1 minute.
......
...@@ -8,6 +8,10 @@ import org.apache.kafka.clients.admin.NewTopic ...@@ -8,6 +8,10 @@ import org.apache.kafka.clients.admin.NewTopic
private val logger = KotlinLogging.logger {} private val logger = KotlinLogging.logger {}
/**
* Manages the topics related tasks
* @param bootstrapServers Ip of the kafka server
*/
class TopicManager(bootstrapServers: String) { class TopicManager(bootstrapServers: String) {
private val props = hashMapOf<String, Any>(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG to bootstrapServers) private val props = hashMapOf<String, Any>(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG to bootstrapServers)
lateinit var kafkaAdmin: AdminClient lateinit var kafkaAdmin: AdminClient
...@@ -20,6 +24,11 @@ class TopicManager(bootstrapServers: String) { ...@@ -20,6 +24,11 @@ class TopicManager(bootstrapServers: String) {
} }
} }
/**
* Creates topics.
* @param topics Map that holds a numPartition for each topic it should create
* @param replicationFactor
*/
fun createTopics(topics: Map<String, Int>, replicationFactor: Short) { fun createTopics(topics: Map<String, Int>, replicationFactor: Short) {
val newTopics = mutableSetOf<NewTopic>() val newTopics = mutableSetOf<NewTopic>()
...@@ -42,6 +51,10 @@ class TopicManager(bootstrapServers: String) { ...@@ -42,6 +51,10 @@ class TopicManager(bootstrapServers: String) {
logger.info { "Creation of $topics started" } logger.info { "Creation of $topics started" }
} }
/**
* Deletes topics.
* @param topics
*/
fun deleteTopics(topics: List<String>) { fun deleteTopics(topics: List<String>) {
val result = kafkaAdmin.deleteTopics(topics) val result = kafkaAdmin.deleteTopics(topics)
......
...@@ -27,9 +27,9 @@ class UC1Benchmark(config: UC1BenchmarkConfig) : Benchmark(config) { ...@@ -27,9 +27,9 @@ class UC1Benchmark(config: UC1BenchmarkConfig) : Benchmark(config) {
private var wgDeployment: Deployment private var wgDeployment: Deployment
private var configMap: ConfigMap private var configMap: ConfigMap
init { init {
this.workloadGeneratorStateCleaner = WorkloadGeneratorStateCleaner(this.config.zookeeperConnectionString) this.workloadGeneratorStateCleaner =
WorkloadGeneratorStateCleaner(this.config.zookeeperConnectionString, path = "/workload-generation")
this.topicManager = TopicManager(this.config.kafkaIPConnectionString) this.topicManager = TopicManager(this.config.kafkaIPConnectionString)
this.kubernetesClient = DefaultKubernetesClient().inNamespace("default") this.kubernetesClient = DefaultKubernetesClient().inNamespace("default")
this.yamlLoader = YamlLoader(this.kubernetesClient) this.yamlLoader = YamlLoader(this.kubernetesClient)
...@@ -83,7 +83,7 @@ class UC1Benchmark(config: UC1BenchmarkConfig) : Benchmark(config) { ...@@ -83,7 +83,7 @@ class UC1Benchmark(config: UC1BenchmarkConfig) : Benchmark(config) {
// TODO ("calculate number of required instances") // TODO ("calculate number of required instances")
val requiredInstances: Int = 1 val requiredInstances = 1
val environmentVariables: MutableMap<String, String> = mutableMapOf() val environmentVariables: MutableMap<String, String> = mutableMapOf()
//environmentVariables.put("KAFKA_BOOTSTRAP_SERVERS", this.config.kafkaIPConnectionString) //environmentVariables.put("KAFKA_BOOTSTRAP_SERVERS", this.config.kafkaIPConnectionString)
//environmentVariables.put("ZK_HOST", this.config.zookeeperConnectionString.split(":")[0]) //environmentVariables.put("ZK_HOST", this.config.zookeeperConnectionString.split(":")[0])
......
...@@ -5,43 +5,52 @@ import org.apache.zookeeper.KeeperException ...@@ -5,43 +5,52 @@ import org.apache.zookeeper.KeeperException
import org.apache.zookeeper.WatchedEvent import org.apache.zookeeper.WatchedEvent
import org.apache.zookeeper.Watcher import org.apache.zookeeper.Watcher
import org.apache.zookeeper.ZooKeeper import org.apache.zookeeper.ZooKeeper
import java.time.Duration
private val logger = KotlinLogging.logger {} private val logger = KotlinLogging.logger {}
/**
class WorkloadGeneratorStateCleaner(ip: String) { * Resets the workloadgenerator states in zookeper (and potetially watches for Zookeper events)
private val path = "/workload-generation" *
private val sessionTimeout = 60 * @param ip of zookeeper
private val retryTime = 3000L * @param path path of the zookeeper node
*/
class WorkloadGeneratorStateCleaner(ip: String, val path: String) {
private val timeout: Duration = Duration.ofMillis(500)
private val retryAfter: Duration = Duration.ofSeconds(5)
lateinit var zookeeperClient: ZooKeeper lateinit var zookeeperClient: ZooKeeper
init { init {
try { try {
val watcher: Watcher = ZookeeperWatcher() // defined below val watcher: Watcher = ZookeeperWatcher() // defined below
zookeeperClient = ZooKeeper(ip, sessionTimeout, watcher) zookeeperClient = ZooKeeper(ip, timeout.toMillis().toInt(), watcher)
} catch (e: Exception) { } catch (e: Exception) {
logger.error { e.toString() } logger.error { e.toString() }
} }
} }
/**
* Deletes all Zookeeper nodes with the corresponding path.
*/
fun deleteAll() { fun deleteAll() {
var deleted = false var deleted = false
while (!deleted) { while (!deleted) {
//
try { try {
zookeeperClient.delete(path, -1) zookeeperClient.delete(this.path, -1)
} catch (ex: Exception) { } catch (ex: Exception) {
logger.error { ex.toString() } logger.error { ex.toString() }
} }
try { try {
val clients = zookeeperClient.getChildren(path, true) // get list of all nodes of the given path
val clients = zookeeperClient.getChildren(this.path, true)
if (clients.isEmpty()) { if (clients.isEmpty()) {
break; deleted = true
break
} }
} catch (ex: Exception) { } catch (ex: Exception) {
when (ex) { when (ex) {
// indicates that there are no nodes to delete left
is KeeperException -> { is KeeperException -> {
deleted = true deleted = true
} }
...@@ -50,13 +59,15 @@ class WorkloadGeneratorStateCleaner(ip: String) { ...@@ -50,13 +59,15 @@ class WorkloadGeneratorStateCleaner(ip: String) {
} }
} }
} }
Thread.sleep(retryTime) Thread.sleep(retryAfter.toMillis())
logger.info { "ZooKeeper reset was not successful. Retrying in 5s" } logger.info { "ZooKeeper reset was not successful. Retrying in 5s" }
} }
logger.info { "ZooKeeper reset was successful" } logger.info { "ZooKeeper reset was successful" }
} }
/**
* Currently empty, could be used to watch(and react) on certain zookeeper events
*/
private class ZookeeperWatcher : Watcher { private class ZookeeperWatcher : Watcher {
override fun process(event: WatchedEvent) {} override fun process(event: WatchedEvent) {}
......
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>theodolite-quarkus - 1.0.0-SNAPSHOT</title>
<style>
h1, h2, h3, h4, h5, h6 {
margin-bottom: 0.5rem;
font-weight: 400;
line-height: 1.5;
}
h1 {
font-size: 2.5rem;
}
h2 {
font-size: 2rem
}
h3 {
font-size: 1.75rem
}
h4 {
font-size: 1.5rem
}
h5 {
font-size: 1.25rem
}
h6 {
font-size: 1rem
}
.lead {
font-weight: 300;
font-size: 2rem;
}
.banner {
font-size: 2.7rem;
margin: 0;
padding: 2rem 1rem;
background-color: #0d1c2c;
color: white;
}
body {
margin: 0;
font-family: -apple-system, system-ui, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
}
code {
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
font-size: 87.5%;
color: #e83e8c;
word-break: break-word;
}
.left-column {
padding: .75rem;
max-width: 75%;
min-width: 55%;
}
.right-column {
padding: .75rem;
max-width: 25%;
}
.container {
display: flex;
width: 100%;
}
li {
margin: 0.75rem;
}
.right-section {
margin-left: 1rem;
padding-left: 0.5rem;
}
.right-section h3 {
padding-top: 0;
font-weight: 200;
}
.right-section ul {
border-left: 0.3rem solid #71aeef;
list-style-type: none;
padding-left: 0;
}
.examples {
display: flex;
flex-wrap: wrap;
margin: 20px 0 20px -40px;
}
.example {
display: flex;
margin-left: 20px;
margin-bottom: 20px;
flex-direction: column;
width: 350px;
background-color: #205894;
color: white;
}
.example code {
color: lightgrey;
}
.example-header {
padding: 20px;
display: flex;
position: relative;
}
.example-header h4 {
margin: 0;
font-size: 1.4rem;
flex-grow: 1;
line-height: 1.5;
}
.example-description {
padding: 0 20px;
flex-grow: 1;
}
.example-paths {
display: flex;
flex-direction: column;
}
.example-paths a {
display: block;
background-color: transparent;
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
color: white;
padding: 10px;
text-decoration: none;
}
.example-paths a:before {
content: '⇨';
font-weight: bold;
font-size: 1.5rem;
margin: 20px;
}
.example-paths a:hover {
background-color: #0d1c2c;
}
.guide-link {
background-color: #71aeef;
position: absolute;
color: white;
text-decoration: none;
top: 0;
right: 0;
padding: 7px;
font-weight: bold;
}
.guide-link:hover {
background-color: #0d1c2c;
}
</style>
</head>
<body>
<div class="banner lead">
Your new Cloud-Native application is ready!
</div>
<div class="container">
<div class="left-column">
<p class="lead"> Congratulations, you have created a new Quarkus cloud application.</p>
<h2>Why do you see this?</h2>
<p>This page is served by Quarkus. The source is in
<code>src/main/resources/META-INF/resources/index.html</code>.</p>
<h2>What can I do from here?</h2>
<p>If not already done, run the application in <em>dev mode</em> using: <code>./gradlew quarkusDev</code>.
</p>
<ul>
<li>Play with your example code in <code>src/main/kotlin</code>:
<div class="examples">
<div class="example">
<div class="example-header">
<h4>RESTEasy JAX-RS</h4>
<a href="https://quarkus.io/guides/rest-json" target="_blank" class="guide-link">Guide</a>
</div>
<div class="example-description">
<p>A Hello World RESTEasy resource</p>
</div>
<div class="example-paths">
<a href="/hello-resteasy" class="path-link" target="_blank">GET /hello-resteasy</a>
</div>
</div>
</div>
</li>
<li>Your static assets are located in <code>src/main/resources/META-INF/resources</code>.</li>
<li>Configure your application in <code>src/main/resources/application.properties</code>.</li>
</ul>
<h2>Do you like Quarkus?</h2>
<p>Go give it a star on <a href="https://github.com/quarkusio/quarkus">GitHub</a>.</p>
</div>
<div class="right-column">
<div class="right-section">
<h3>Application</h3>
<ul>
<li>GroupId: theodolite</li>
<li>ArtifactId: theodolite-quarkus</li>
<li>Version: 1.0.0-SNAPSHOT</li>
<li>Quarkus Version: 1.10.3.Final</li>
</ul>
</div>
<div class="right-section">
<h3>Next steps</h3>
<ul>
<li><a href="https://quarkus.io/guides/gradle-tooling" target="_blank">Setup your IDE</a></li>
<li><a href="https://quarkus.io/guides/getting-started.html" target="_blank">Getting started</a></li>
<li><a href="https://quarkus.io" target="_blank">Quarkus Web Site</a></li>
</ul>
</div>
</div>
</div>
</body>
</html>
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment