summaryrefslogtreecommitdiff
path: root/opendc-compute/opendc-compute-simulator
diff options
context:
space:
mode:
Diffstat (limited to 'opendc-compute/opendc-compute-simulator')
-rw-r--r--opendc-compute/opendc-compute-simulator/build.gradle.kts4
-rw-r--r--opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/MutableServiceRegistry.kt58
-rw-r--r--opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/ServiceRegistry.kt45
-rw-r--r--opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/ServiceRegistryImpl.kt66
-rw-r--r--opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/failure/FailureModel.kt43
-rw-r--r--opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/failure/FailureModels.kt68
-rw-r--r--opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/provisioner/ComputeMonitorProvisioningStep.kt44
-rw-r--r--opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/provisioner/ComputeServiceProvisioningStep.kt49
-rw-r--r--opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/provisioner/ComputeSteps.kt74
-rw-r--r--opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/provisioner/HostsProvisioningStep.kt75
-rw-r--r--opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/provisioner/Provisioner.kt98
-rw-r--r--opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/provisioner/ProvisioningContext.kt50
-rw-r--r--opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/provisioner/ProvisioningStep.kt61
13 files changed, 735 insertions, 0 deletions
diff --git a/opendc-compute/opendc-compute-simulator/build.gradle.kts b/opendc-compute/opendc-compute-simulator/build.gradle.kts
index 72962147..625f278b 100644
--- a/opendc-compute/opendc-compute-simulator/build.gradle.kts
+++ b/opendc-compute/opendc-compute-simulator/build.gradle.kts
@@ -34,6 +34,10 @@ dependencies {
implementation(projects.opendcCommon)
implementation(libs.kotlin.logging)
+ api(libs.microprofile.config)
+ implementation(project(mapOf("path" to ":opendc-compute:opendc-compute-topology")))
+ implementation(project(mapOf("path" to ":opendc-compute:opendc-compute-telemetry")))
+
testImplementation(projects.opendcSimulator.opendcSimulatorCore)
testRuntimeOnly(libs.slf4j.simple)
}
diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/MutableServiceRegistry.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/MutableServiceRegistry.kt
new file mode 100644
index 00000000..49b3688e
--- /dev/null
+++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/MutableServiceRegistry.kt
@@ -0,0 +1,58 @@
+/*
+ * 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.compute.simulator
+
+/**
+ * A mutable [ServiceRegistry].
+ */
+public interface MutableServiceRegistry : ServiceRegistry {
+ /**
+ * Register [service] for the specified [name] in this registry.
+ *
+ * @param name The name of the service to register, which should follow the rules for domain names as defined by
+ * DNS.
+ * @param type The interface provided by the service.
+ * @param service A reference to the actual implementation of the service.
+ */
+ public fun <T : Any> register(name: String, type: Class<T>, service: T)
+
+ /**
+ * Remove the service with [name] and [type] from this registry.
+ *
+ * @param name The name of the service to remove, which should follow the rules for domain names as defined by DNS.
+ * @param type The type of the service to remove.
+ */
+ public fun remove(name: String, type: Class<*>)
+
+ /**
+ * Remove all services registered with [name].
+ *
+ * @param name The name of the services to remove, which should follow the rules for domain names as defined by DNS.
+ */
+ public fun remove(name: String)
+
+ /**
+ * Create a copy of the registry.
+ */
+ public override fun clone(): MutableServiceRegistry
+}
diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/ServiceRegistry.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/ServiceRegistry.kt
new file mode 100644
index 00000000..d3af3f01
--- /dev/null
+++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/ServiceRegistry.kt
@@ -0,0 +1,45 @@
+/*
+ * 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.compute.simulator
+
+/**
+ * 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.
+ */
+public interface ServiceRegistry {
+ /**
+ * Lookup the service with the specified [name] and [type].
+ *
+ * @param name The name of the service to resolve, which should follow the rules for domain names as defined by DNS.
+ * @param type The type of the service to resolve, identified by the interface that is implemented by the service.
+ * @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-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/ServiceRegistryImpl.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/ServiceRegistryImpl.kt
new file mode 100644
index 00000000..a9d05844
--- /dev/null
+++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/ServiceRegistryImpl.kt
@@ -0,0 +1,66 @@
+/*
+ * 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.compute.simulator
+
+/**
+ * Implementation of the [MutableServiceRegistry] interface.
+ */
+internal class ServiceRegistryImpl(private val registry: MutableMap<String, MutableMap<Class<*>, Any>> = mutableMapOf()) :
+ MutableServiceRegistry {
+ override fun <T : Any> resolve(name: String, type: Class<T>): T? {
+ val servicesForName = registry[name] ?: return null
+
+ @Suppress("UNCHECKED_CAST")
+ return servicesForName[type] as T?
+ }
+
+ override fun <T : Any> register(name: String, type: Class<T>, service: T) {
+ val services = registry.computeIfAbsent(name) { mutableMapOf() }
+
+ if (type in services) {
+ throw IllegalStateException("Duplicate service $type registered for name $name")
+ }
+
+ services[type] = service
+ }
+
+ override fun remove(name: String, type: Class<*>) {
+ val services = registry[name] ?: return
+ services.remove(type)
+ }
+
+ override fun remove(name: String) {
+ registry.remove(name)
+ }
+
+ override fun clone(): MutableServiceRegistry {
+ val res = mutableMapOf<String, MutableMap<Class<*>, Any>>()
+ registry.mapValuesTo(res) { (_, v) -> v.toMutableMap() }
+ return ServiceRegistryImpl(res)
+ }
+
+ override fun toString(): String {
+ val entries = registry.map { "${it.key}=${it.value}" }.joinToString()
+ return "ServiceRegistry{$entries}"
+ }
+}
diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/failure/FailureModel.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/failure/FailureModel.kt
new file mode 100644
index 00000000..5e94830c
--- /dev/null
+++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/failure/FailureModel.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2021 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.compute.simulator.failure
+
+import org.opendc.compute.service.ComputeService
+import java.time.InstantSource
+import java.util.random.RandomGenerator
+import kotlin.coroutines.CoroutineContext
+
+/**
+ * Factory interface for constructing [HostFaultInjector] for modeling failures of compute service hosts.
+ */
+public interface FailureModel {
+ /**
+ * Construct a [HostFaultInjector] for the specified [service].
+ */
+ public fun createInjector(
+ context: CoroutineContext,
+ clock: InstantSource,
+ service: ComputeService,
+ random: RandomGenerator
+ ): HostFaultInjector
+}
diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/failure/FailureModels.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/failure/FailureModels.kt
new file mode 100644
index 00000000..337f3c60
--- /dev/null
+++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/failure/FailureModels.kt
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2021 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.
+ */
+
+@file:JvmName("FailureModels")
+
+package org.opendc.compute.simulator.failure
+
+import org.apache.commons.math3.distribution.LogNormalDistribution
+import org.apache.commons.math3.random.Well19937c
+import org.opendc.compute.service.ComputeService
+import org.opendc.compute.simulator.SimHost
+import java.time.Duration
+import java.time.InstantSource
+import java.util.random.RandomGenerator
+import kotlin.coroutines.CoroutineContext
+import kotlin.math.ln
+
+/**
+ * Obtain a [FailureModel] based on the GRID'5000 failure trace.
+ *
+ * This fault injector uses parameters from the GRID'5000 failure trace as described in
+ * "A Framework for the Study of Grid Inter-Operation Mechanisms", A. Iosup, 2009.
+ */
+public fun grid5000(failureInterval: Duration): FailureModel {
+ return object : FailureModel {
+ override fun createInjector(
+ context: CoroutineContext,
+ clock: InstantSource,
+ service: ComputeService,
+ random: RandomGenerator
+ ): HostFaultInjector {
+ val rng = Well19937c(random.nextLong())
+ val hosts = service.hosts.map { it as SimHost }.toSet()
+
+ // Parameters from A. Iosup, A Framework for the Study of Grid Inter-Operation Mechanisms, 2009
+ // GRID'5000
+ return HostFaultInjector(
+ context,
+ clock,
+ hosts,
+ iat = LogNormalDistribution(rng, ln(failureInterval.toHours().toDouble()), 1.03),
+ selector = StochasticVictimSelector(LogNormalDistribution(rng, 1.88, 1.25), random),
+ fault = StartStopHostFault(LogNormalDistribution(rng, 8.89, 2.71))
+ )
+ }
+
+ override fun toString(): String = "Grid5000FailureModel"
+ }
+}
diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/provisioner/ComputeMonitorProvisioningStep.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/provisioner/ComputeMonitorProvisioningStep.kt
new file mode 100644
index 00000000..50e7bd0d
--- /dev/null
+++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/provisioner/ComputeMonitorProvisioningStep.kt
@@ -0,0 +1,44 @@
+/*
+ * 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.compute.simulator.provisioner
+
+import org.opendc.compute.service.ComputeService
+import org.opendc.compute.telemetry.ComputeMetricReader
+import org.opendc.compute.telemetry.ComputeMonitor
+import java.time.Duration
+
+/**
+ * A [ProvisioningStep] that provisions a [ComputeMetricReader] to periodically collect the metrics of a [ComputeService]
+ * and report them to a [ComputeMonitor].
+ */
+public class ComputeMonitorProvisioningStep(
+ private val serviceDomain: String,
+ private val monitor: ComputeMonitor,
+ private val exportInterval: Duration
+) : ProvisioningStep {
+ override fun apply(ctx: ProvisioningContext): AutoCloseable {
+ val service = requireNotNull(ctx.registry.resolve(serviceDomain, ComputeService::class.java)) { "Compute service $serviceDomain does not exist" }
+ val metricReader = ComputeMetricReader(ctx.dispatcher, service, monitor, exportInterval)
+ return AutoCloseable { metricReader.close() }
+ }
+}
diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/provisioner/ComputeServiceProvisioningStep.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/provisioner/ComputeServiceProvisioningStep.kt
new file mode 100644
index 00000000..fc555016
--- /dev/null
+++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/provisioner/ComputeServiceProvisioningStep.kt
@@ -0,0 +1,49 @@
+/*
+ * 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.compute.simulator.provisioner
+
+import org.opendc.compute.service.ComputeService
+import org.opendc.compute.service.scheduler.ComputeScheduler
+import java.time.Duration
+
+/**
+ * A [ProvisioningStep] that provisions a [ComputeService] without any hosts.
+ *
+ * @param serviceDomain The domain name under which to register the compute service.
+ * @param scheduler A function to construct the compute scheduler.
+ * @param schedulingQuantum The scheduling quantum of the compute scheduler.
+ */
+public class ComputeServiceProvisioningStep internal constructor(
+ private val serviceDomain: String,
+ private val scheduler: (ProvisioningContext) -> ComputeScheduler,
+ private val schedulingQuantum: Duration
+) : ProvisioningStep {
+ override fun apply(ctx: ProvisioningContext): AutoCloseable {
+ val service = ComputeService.builder(ctx.dispatcher, scheduler(ctx))
+ .withQuantum(schedulingQuantum)
+ .build()
+ ctx.registry.register(serviceDomain, ComputeService::class.java, service)
+
+ return AutoCloseable { service.close() }
+ }
+}
diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/provisioner/ComputeSteps.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/provisioner/ComputeSteps.kt
new file mode 100644
index 00000000..93f8fa4f
--- /dev/null
+++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/provisioner/ComputeSteps.kt
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+@file:JvmName("ComputeSteps")
+
+package org.opendc.compute.simulator.provisioner
+
+import org.opendc.compute.service.ComputeService
+import org.opendc.compute.service.scheduler.ComputeScheduler
+import org.opendc.compute.telemetry.ComputeMonitor
+import org.opendc.compute.topology.HostSpec
+import java.time.Duration
+
+/**
+ * Return a [ProvisioningStep] that provisions a [ComputeService] without any hosts.
+ *
+ * @param serviceDomain The domain name under which to register the compute service.
+ * @param scheduler A function to construct the compute scheduler.
+ * @param schedulingQuantum The scheduling quantum of the compute scheduler.
+ */
+public fun setupComputeService(
+ serviceDomain: String,
+ scheduler: (ProvisioningContext) -> ComputeScheduler,
+ schedulingQuantum: Duration = Duration.ofMinutes(5)
+): ProvisioningStep {
+ return ComputeServiceProvisioningStep(serviceDomain, scheduler, schedulingQuantum)
+}
+
+/**
+ * Return a [ProvisioningStep] that installs a [ComputeMetricReader] to periodically collect the metrics of a
+ * [ComputeService] and report them to a [ComputeMonitor].
+ *
+ * @param serviceDomain The service domain at which the [ComputeService] is located.
+ * @param monitor The [ComputeMonitor] to install.
+ * @param exportInterval The interval between which to collect the metrics.
+ */
+public fun registerComputeMonitor(
+ serviceDomain: String,
+ monitor: ComputeMonitor,
+ exportInterval: Duration = Duration.ofMinutes(5)
+): ProvisioningStep {
+ return ComputeMonitorProvisioningStep(serviceDomain, monitor, exportInterval)
+}
+
+/**
+ * Return a [ProvisioningStep] that sets up the specified list of hosts (based on [specs]) for the specified compute
+ * service.
+ *
+ * @param serviceDomain The domain name under which the compute service is registered.
+ * @param specs A list of [HostSpec] objects describing the simulated hosts to provision.
+ * @param optimize A flag to indicate that the CPU resources of the host should be merged into a single CPU resource.
+ */
+public fun setupHosts(serviceDomain: String, specs: List<HostSpec>, optimize: Boolean = false): ProvisioningStep {
+ return HostsProvisioningStep(serviceDomain, specs, optimize)
+}
diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/provisioner/HostsProvisioningStep.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/provisioner/HostsProvisioningStep.kt
new file mode 100644
index 00000000..3104ccbe
--- /dev/null
+++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/provisioner/HostsProvisioningStep.kt
@@ -0,0 +1,75 @@
+/*
+ * 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.compute.simulator.provisioner
+
+import org.opendc.compute.service.ComputeService
+import org.opendc.compute.simulator.SimHost
+import org.opendc.compute.topology.HostSpec
+import org.opendc.simulator.compute.SimBareMetalMachine
+import org.opendc.simulator.compute.kernel.SimHypervisor
+import org.opendc.simulator.flow2.FlowEngine
+import java.util.SplittableRandom
+
+/**
+ * A [ProvisioningStep] that provisions a list of hosts for a [ComputeService].
+ *
+ * @param serviceDomain The domain name under which the compute service is registered.
+ * @param specs A list of [HostSpec] objects describing the simulated hosts to provision.
+ * @param optimize A flag to indicate that the CPU resources of the host should be merged into a single CPU resource.
+ */
+public class HostsProvisioningStep internal constructor(
+ private val serviceDomain: String,
+ private val specs: List<HostSpec>,
+ private val optimize: Boolean
+) : ProvisioningStep {
+ override fun apply(ctx: ProvisioningContext): AutoCloseable {
+ val service = requireNotNull(ctx.registry.resolve(serviceDomain, ComputeService::class.java)) { "Compute service $serviceDomain does not exist" }
+ val engine = FlowEngine.create(ctx.dispatcher)
+ val graph = engine.newGraph()
+ val hosts = mutableSetOf<SimHost>()
+
+ for (spec in specs) {
+ val machine = SimBareMetalMachine.create(graph, spec.model, spec.psuFactory)
+ val hypervisor = SimHypervisor.create(spec.multiplexerFactory, SplittableRandom(ctx.seeder.nextLong()))
+
+ val host = SimHost(
+ spec.uid,
+ spec.name,
+ spec.meta,
+ ctx.dispatcher.timeSource,
+ machine,
+ hypervisor,
+ optimize = optimize
+ )
+
+ require(hosts.add(host)) { "Host with uid ${spec.uid} already exists" }
+ service.addHost(host)
+ }
+
+ return AutoCloseable {
+ for (host in hosts) {
+ host.close()
+ }
+ }
+ }
+}
diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/provisioner/Provisioner.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/provisioner/Provisioner.kt
new file mode 100644
index 00000000..275378e7
--- /dev/null
+++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/provisioner/Provisioner.kt
@@ -0,0 +1,98 @@
+/*
+ * 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.compute.simulator.provisioner
+
+import org.opendc.common.Dispatcher
+import org.opendc.compute.simulator.MutableServiceRegistry
+import org.opendc.compute.simulator.ServiceRegistry
+import org.opendc.compute.simulator.ServiceRegistryImpl
+import java.util.ArrayDeque
+import java.util.SplittableRandom
+
+/**
+ * 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 dispatcher The [Dispatcher] implementation for scheduling future tasks.
+ * @param seed A seed for initializing the randomness of the environment.
+ */
+public class Provisioner(dispatcher: Dispatcher, seed: Long) : AutoCloseable {
+ /**
+ * Implementation of [ProvisioningContext].
+ */
+ private val context = object : ProvisioningContext {
+ override val dispatcher: Dispatcher = dispatcher
+ 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-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/provisioner/ProvisioningContext.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/provisioner/ProvisioningContext.kt
new file mode 100644
index 00000000..1788c8e2
--- /dev/null
+++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/provisioner/ProvisioningContext.kt
@@ -0,0 +1,50 @@
+/*
+ * 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.compute.simulator.provisioner
+
+import org.opendc.common.Dispatcher
+import org.opendc.compute.simulator.MutableServiceRegistry
+import java.util.SplittableRandom
+import java.util.random.RandomGenerator
+
+/**
+ * The [ProvisioningContext] class provides access to shared state between subsequent [ProvisioningStep]s, as well as
+ * access to the simulation dispatcher, the virtual clock, and a randomness seeder to allow
+ * the provisioning steps to initialize the (simulated) resources.
+ */
+public interface ProvisioningContext {
+ /**
+ * The [Dispatcher] provided by the provisioner to schedule future events during the simulation.
+ */
+ public val dispatcher: Dispatcher
+
+ /**
+ * A [SplittableRandom] instance used to seed the provisioners.
+ */
+ public val seeder: RandomGenerator
+
+ /**
+ * A [MutableServiceRegistry] where the provisioned services are registered.
+ */
+ public val registry: MutableServiceRegistry
+}
diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/provisioner/ProvisioningStep.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/provisioner/ProvisioningStep.kt
new file mode 100644
index 00000000..0226a704
--- /dev/null
+++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/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.compute.simulator.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
+ }
+}