summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gradle/libs.versions.toml2
-rw-r--r--opendc-experiments/opendc-experiments-base/build.gradle.kts3
-rw-r--r--opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/MutableServiceRegistry.kt2
-rw-r--r--opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/ServiceRegistry.kt9
-rw-r--r--opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/provisioner/Provisioner.kt101
-rw-r--r--opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/provisioner/ProvisioningContext.kt55
-rw-r--r--opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/provisioner/ProvisioningStep.kt61
7 files changed, 229 insertions, 4 deletions
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 503d1549..f78ab816 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -17,6 +17,7 @@ kotlinx-coroutines = "1.6.4"
ktlint-gradle = "10.3.0"
log4j = "2.18.0"
microprofile-openapi = "3.0"
+microprofile-config = "3.0.1"
mockk = "1.12.5"
parquet = "1.12.3"
progressbar = "0.9.3"
@@ -97,6 +98,7 @@ hadoop-common = { module = "org.apache.hadoop:hadoop-common", version.ref = "had
hadoop-mapreduce-client-core = { module = "org.apache.hadoop:hadoop-mapreduce-client-core", version.ref = "hadoop" }
commons-math3 = { module = "org.apache.commons:commons-math3", version.ref = "commons-math3" }
microprofile-openapi-api = { module = "org.eclipse.microprofile.openapi:microprofile-openapi-api", version.ref = "microprofile-openapi" }
+microprofile-config = { module = "org.eclipse.microprofile.config:microprofile-config-api", version.ref = "microprofile-config" }
# Other (Build)
dokka-gradle = { module = "org.jetbrains.dokka:dokka-gradle-plugin", version.ref = "dokka" }
diff --git a/opendc-experiments/opendc-experiments-base/build.gradle.kts b/opendc-experiments/opendc-experiments-base/build.gradle.kts
index 181c86e2..2cce8c1c 100644
--- a/opendc-experiments/opendc-experiments-base/build.gradle.kts
+++ b/opendc-experiments/opendc-experiments-base/build.gradle.kts
@@ -30,4 +30,7 @@ plugins {
}
dependencies {
+ api(libs.microprofile.config)
+
+ implementation(projects.opendcSimulator.opendcSimulatorCore)
}
diff --git a/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/MutableServiceRegistry.kt b/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/MutableServiceRegistry.kt
index 94fe56fa..160dd393 100644
--- a/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/MutableServiceRegistry.kt
+++ b/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/MutableServiceRegistry.kt
@@ -54,5 +54,5 @@ public interface MutableServiceRegistry : ServiceRegistry {
/**
* Create a copy of the registry.
*/
- public fun clone(): MutableServiceRegistry
+ public override fun clone(): MutableServiceRegistry
}
diff --git a/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/ServiceRegistry.kt b/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/ServiceRegistry.kt
index a6776e14..e9d5b50e 100644
--- a/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/ServiceRegistry.kt
+++ b/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/ServiceRegistry.kt
@@ -22,10 +22,8 @@
package org.opendc.experiments
-import org.opendc.experiments.broker.Broker
-
/**
- * A read-only registry of services accessible by a [Broker] during an experiment.
+ * A read-only registry of services used during experiments to resolve services.
*
* The service registry is similar conceptually to the Domain Name System (DNS), which is a naming system used to
* identify computers reachable via the Internet. The service registry should be used in a similar fashion.
@@ -39,4 +37,9 @@ public interface ServiceRegistry {
* @return The service with specified [name] and implementing [type] or `null` if it does not exist.
*/
public fun <T : Any> resolve(name: String, type: Class<T>): T?
+
+ /**
+ * Create a copy of the registry.
+ */
+ public fun clone(): ServiceRegistry
}
diff --git a/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/provisioner/Provisioner.kt b/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/provisioner/Provisioner.kt
new file mode 100644
index 00000000..3a1c3144
--- /dev/null
+++ b/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/provisioner/Provisioner.kt
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2022 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package org.opendc.experiments.provisioner
+
+import org.opendc.experiments.MutableServiceRegistry
+import org.opendc.experiments.ServiceRegistry
+import org.opendc.experiments.internal.ServiceRegistryImpl
+import java.time.Clock
+import java.util.*
+import java.util.ArrayDeque
+import kotlin.coroutines.CoroutineContext
+
+/**
+ * A helper class to set up the experimental environment in a reproducible manner.
+ *
+ * With this class, users describe the environment using multiple [ProvisioningStep]s. These re-usable
+ * [ProvisioningStep]s are executed sequentially and ensure that the necessary infrastructure is configured and teared
+ * down after the simulation completes.
+ *
+ * @param coroutineContext The [CoroutineContext] in which the environment is set up.
+ * @param clock The simulation [Clock].
+ * @param seed A seed for initializing the randomness of the environment.
+ */
+public class Provisioner(coroutineContext: CoroutineContext, clock: Clock, seed: Long) : AutoCloseable {
+ /**
+ * Implementation of [ProvisioningContext].
+ */
+ private val context = object : ProvisioningContext {
+ override val clock: Clock = clock
+ override val coroutineContext: CoroutineContext = coroutineContext
+ override val seeder: SplittableRandom = SplittableRandom(seed)
+ override val registry: MutableServiceRegistry = ServiceRegistryImpl()
+
+ override fun toString(): String = "Provisioner.ProvisioningContext"
+ }
+
+ /**
+ * The stack of handles to run during the clean-up process.
+ */
+ private val stack = ArrayDeque<AutoCloseable>()
+
+ /**
+ * The [ServiceRegistry] containing the services registered in this environment.
+ */
+ public val registry: ServiceRegistry
+ get() = context.registry
+
+ /**
+ * Run a single [ProvisioningStep] for this environment.
+ *
+ * @param step The step to apply to the environment.
+ */
+ public fun runStep(step: ProvisioningStep) {
+ val handle = step.apply(context)
+ stack.push(handle)
+ }
+
+ /**
+ * Run multiple [ProvisioningStep]s for this environment.
+ *
+ * @param steps The steps to apply to the environment.
+ */
+ public fun runSteps(vararg steps: ProvisioningStep) {
+ val ctx = context
+ val stack = stack
+ for (step in steps) {
+ val handle = step.apply(ctx)
+ stack.push(handle)
+ }
+ }
+
+ /**
+ * Clean-up the environment.
+ */
+ override fun close() {
+ val stack = stack
+ while (stack.isNotEmpty()) {
+ stack.pop().close()
+ }
+ }
+}
diff --git a/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/provisioner/ProvisioningContext.kt b/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/provisioner/ProvisioningContext.kt
new file mode 100644
index 00000000..58f6844d
--- /dev/null
+++ b/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/provisioner/ProvisioningContext.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2022 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package org.opendc.experiments.provisioner
+
+import org.opendc.experiments.MutableServiceRegistry
+import java.time.Clock
+import java.util.*
+import kotlin.coroutines.CoroutineContext
+
+/**
+ * The [ProvisioningContext] class provides access to shared state between subsequent [ProvisioningStep]s, as well as
+ * access to the simulation dispatcher (via [CoroutineContext]), the virtual clock, and a randomness seeder to allow
+ * the provisioning steps to initialize the (simulated) resources.
+ */
+public interface ProvisioningContext {
+ /**
+ * The [CoroutineContext] in which the provisioner runs.
+ */
+ public val coroutineContext: CoroutineContext
+
+ /**
+ * The [Clock] tracking the virtual simulation time.
+ */
+ public val clock: Clock
+
+ /**
+ * A [SplittableRandom] instance used to seed the provisioners.
+ */
+ public val seeder: SplittableRandom
+
+ /**
+ * A [MutableServiceRegistry] where the provisioned services are registered.
+ */
+ public val registry: MutableServiceRegistry
+}
diff --git a/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/provisioner/ProvisioningStep.kt b/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/provisioner/ProvisioningStep.kt
new file mode 100644
index 00000000..e78f8d4f
--- /dev/null
+++ b/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/provisioner/ProvisioningStep.kt
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2022 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package org.opendc.experiments.provisioner
+
+import org.eclipse.microprofile.config.Config
+
+/**
+ * A provisioning step is responsible for provisioning (acquiring or configuring) infrastructure necessary for a
+ * simulation experiment.
+ */
+public fun interface ProvisioningStep {
+ /**
+ * Apply the step by provisioning the required resources for the experiment using the specified
+ * [ProvisioningContext][ctx].
+ *
+ * @param ctx The environment in which the resources should be provisioned.
+ * @return A handle that is invoked once the simulation completes, so that the resources can be cleaned up.
+ */
+ public fun apply(ctx: ProvisioningContext): AutoCloseable
+
+ /**
+ * A factory interface for [ProvisioningStep] instances.
+ *
+ * @param S The type that describes the input for constructing a [ProvisioningStep].
+ */
+ public abstract class Provider<S>(public val type: Class<S>) {
+ /**
+ * The name that identifies the provisioning step.
+ */
+ public abstract val name: String
+
+ /**
+ * Construct a [ProvisioningStep] with the specified [spec].
+ *
+ * @param spec The specification that describes the provisioner to be created.
+ * @param config The external configuration of the experiment runner.
+ * @return The [ProvisioningStep] constructed according to [spec].
+ */
+ public abstract fun create(spec: S, config: Config): ProvisioningStep
+ }
+}