diff --git a/theodolite/crd/crd-benchmark.yaml b/theodolite/crd/crd-benchmark.yaml index 7ab2e5f3b890a883f68dbbd36805f3791158f256..60c777c7d508e6d89a2678dd101678bbf40627c4 100644 --- a/theodolite/crd/crd-benchmark.yaml +++ b/theodolite/crd/crd-benchmark.yaml @@ -64,6 +64,9 @@ spec: type: array items: type: string + beforeActions: + type: array + properties: sut: description: The appResourceSets specifies all Kubernetes resources required to start the sut. A resourceSet can be either a configMap resourceSet or a fileSystem resourceSet. type: object diff --git a/theodolite/src/main/kotlin/theodolite/benchmark/Action.kt b/theodolite/src/main/kotlin/theodolite/benchmark/Action.kt new file mode 100644 index 0000000000000000000000000000000000000000..55add765e8d0d7d3299d9e8f940a122ead899caf --- /dev/null +++ b/theodolite/src/main/kotlin/theodolite/benchmark/Action.kt @@ -0,0 +1,31 @@ +package theodolite.benchmark + +import io.fabric8.kubernetes.client.NamespacedKubernetesClient + +class Action { + + lateinit var selector: ActionSelector + lateinit var exec: Command + + fun exec(client: NamespacedKubernetesClient) { + ActionCommand(client = client) + .exec( + matchLabels = selector.pod.matchLabels, + container = selector.container, + command = exec.command + ) + } +} + +class ActionSelector { + lateinit var pod: PodSelector + lateinit var container: String +} + +class PodSelector { + lateinit var matchLabels: MutableMap<String, String> +} + +class Command { + lateinit var command: String +} \ No newline at end of file diff --git a/theodolite/src/main/kotlin/theodolite/benchmark/ActionCommand.kt b/theodolite/src/main/kotlin/theodolite/benchmark/ActionCommand.kt new file mode 100644 index 0000000000000000000000000000000000000000..762487c6db7e11ed9e1d13384e3796be81f6074f --- /dev/null +++ b/theodolite/src/main/kotlin/theodolite/benchmark/ActionCommand.kt @@ -0,0 +1,70 @@ +package theodolite.benchmark + +import io.fabric8.kubernetes.client.NamespacedKubernetesClient +import io.fabric8.kubernetes.client.dsl.ExecListener +import io.fabric8.kubernetes.client.dsl.ExecWatch +import mu.KotlinLogging +import okhttp3.Response +import theodolite.util.ActionCommandFailedException +import java.io.ByteArrayOutputStream +import java.util.concurrent.CountDownLatch +import java.util.concurrent.TimeUnit + +private val logger = KotlinLogging.logger {} + +class ActionCommand(val client: NamespacedKubernetesClient) { + var out: ByteArrayOutputStream = ByteArrayOutputStream() + var error: ByteArrayOutputStream = ByteArrayOutputStream() + private val execLatch = CountDownLatch(1); + + fun exec(matchLabels: MutableMap<String, String>, container: String, command: String): Pair<String, String> { + try { + val execWatch: ExecWatch = client.pods() + .withName(getPodName(matchLabels)) + .inContainer(container) + .writingOutput(out) + .writingError(error) + .usingListener(MyPodExecListener(execLatch)) + .exec(*command.split(" ").toTypedArray()) + + val latchTerminationStatus = execLatch.await(5, TimeUnit.SECONDS); + if (!latchTerminationStatus) { + logger.warn("Latch could not terminate within specified time"); + } + execWatch.close(); + } catch (e: InterruptedException) { + Thread.currentThread().interrupt(); + throw ActionCommandFailedException("Interrupted while waiting for the exec", e) + } + return Pair(out.toString(), error.toString()) + } + + private fun getPodName(matchLabels: MutableMap<String, String>): String { + return try { + this.client + .pods() + .withLabels(matchLabels) + .list() + .items + .first() + .metadata + .name + } catch (e: Exception) { + throw ActionCommandFailedException("Couldn't find any pod that matches the specified labels.", e) + } + } + + private class MyPodExecListener(val execLatch: CountDownLatch) : ExecListener { + override fun onOpen(response: Response) { + } + + override fun onFailure(throwable: Throwable, response: Response) { + logger.warn("Some error encountered while executing action") + execLatch.countDown() + } + + override fun onClose(i: Int, s: String) { + execLatch.countDown() + } + } +} diff --git a/theodolite/src/main/kotlin/theodolite/benchmark/Resources.kt b/theodolite/src/main/kotlin/theodolite/benchmark/Resources.kt index 0187735b8fd273419874942cb7ed68797732c84c..738fb60148d9a218454314dd9395fc8a5ea9b5c2 100644 --- a/theodolite/src/main/kotlin/theodolite/benchmark/Resources.kt +++ b/theodolite/src/main/kotlin/theodolite/benchmark/Resources.kt @@ -9,5 +9,7 @@ import io.quarkus.runtime.annotations.RegisterForReflection class Resources { lateinit var resources: List<ResourceSets> + lateinit var beforeActions: List<Action> + lateinit var afterActions: List<Action> } \ No newline at end of file diff --git a/theodolite/src/main/kotlin/theodolite/util/ActionCommandFailedException.kt b/theodolite/src/main/kotlin/theodolite/util/ActionCommandFailedException.kt new file mode 100644 index 0000000000000000000000000000000000000000..c1a8fc401961370d2f07bfffe43f0ae4dc441d25 --- /dev/null +++ b/theodolite/src/main/kotlin/theodolite/util/ActionCommandFailedException.kt @@ -0,0 +1,4 @@ +package theodolite.util + +class ActionCommandFailedException(message: String, e: Exception? = null) : DeploymentFailedException(message,e) { +} \ No newline at end of file diff --git a/theodolite/src/test/kotlin/theodolite/benchmark/ActionCommandTest.kt b/theodolite/src/test/kotlin/theodolite/benchmark/ActionCommandTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..0b9f89aa09dacad9d6cfc96e5999397a7f95a133 --- /dev/null +++ b/theodolite/src/test/kotlin/theodolite/benchmark/ActionCommandTest.kt @@ -0,0 +1,24 @@ +package theodolite.benchmark + +import io.fabric8.kubernetes.client.DefaultKubernetesClient +import io.quarkus.test.junit.QuarkusTest +import org.junit.jupiter.api.Test + + +@QuarkusTest +class ActionCommandTest { + + @Test + fun testAction() { + val action = ActionCommand(DefaultKubernetesClient().inNamespace("default")) + val result = action.exec(mutableMapOf( + Pair("app.kubernetes.io/name","grafana") + ), + container = "grafana", + command = "ls /") + println("out is: " + result.first) + println("error is: " + result.second) + + + } +} \ No newline at end of file