diff options
Diffstat (limited to 'opendc-compute/opendc-compute-simulator')
21 files changed, 459 insertions, 373 deletions
diff --git a/opendc-compute/opendc-compute-simulator/build.gradle.kts b/opendc-compute/opendc-compute-simulator/build.gradle.kts index 625f278b..9692f6ba 100644 --- a/opendc-compute/opendc-compute-simulator/build.gradle.kts +++ b/opendc-compute/opendc-compute-simulator/build.gradle.kts @@ -22,7 +22,7 @@ description = "Simulator for OpenDC Compute" -/* Build configuration */ +// Build configuration plugins { `kotlin-library-conventions` } 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 index 49b3688e..ca72c910 100644 --- 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 @@ -34,7 +34,11 @@ public interface MutableServiceRegistry : ServiceRegistry { * @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) + public fun <T : Any> register( + name: String, + type: Class<T>, + service: T, + ) /** * Remove the service with [name] and [type] from this registry. @@ -42,7 +46,10 @@ public interface MutableServiceRegistry : ServiceRegistry { * @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<*>) + public fun remove( + name: String, + type: Class<*>, + ) /** * Remove all services registered with [name]. 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 index d3af3f01..5a4bced1 100644 --- 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 @@ -36,7 +36,10 @@ public interface ServiceRegistry { * @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? + public fun <T : Any> resolve( + name: String, + type: Class<T>, + ): T? /** * Create a copy of the registry. 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 index a9d05844..bf3ee43f 100644 --- 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 @@ -27,14 +27,21 @@ package org.opendc.compute.simulator */ internal class ServiceRegistryImpl(private val registry: MutableMap<String, MutableMap<Class<*>, Any>> = mutableMapOf()) : MutableServiceRegistry { - override fun <T : Any> resolve(name: String, type: Class<T>): T? { + 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) { + override fun <T : Any> register( + name: String, + type: Class<T>, + service: T, + ) { val services = registry.computeIfAbsent(name) { mutableMapOf() } if (type in services) { @@ -44,7 +51,10 @@ internal class ServiceRegistryImpl(private val registry: MutableMap<String, Muta services[type] = service } - override fun remove(name: String, type: Class<*>) { + override fun remove( + name: String, + type: Class<*>, + ) { val services = registry[name] ?: return services.remove(type) } diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimHost.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimHost.kt index 16ded689..47650f5d 100644 --- a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimHost.kt +++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimHost.kt @@ -73,9 +73,8 @@ public class SimHost( private val hypervisor: SimHypervisor, private val mapper: SimWorkloadMapper = DefaultWorkloadMapper, private val bootModel: Supplier<SimWorkload?> = Supplier { null }, - private val optimize: Boolean = false + private val optimize: Boolean = false, ) : Host, AutoCloseable { - /** * The event listeners registered with this host. */ @@ -85,9 +84,9 @@ public class SimHost( * The virtual machines running on the hypervisor. */ private val guests = HashMap<Server, Guest>() - private val _guests = mutableListOf<Guest>() + private val temporaryGuests = mutableListOf<Guest>() // TODO: Determine a better naming for this - private var _state: HostState = HostState.DOWN + private var localState: HostState = HostState.DOWN set(value) { if (value != field) { listeners.forEach { it.onStateChanged(this, value) } @@ -95,24 +94,26 @@ public class SimHost( field = value } - private val model: HostModel = HostModel( - machine.model.cpus.sumOf { it.frequency }, - machine.model.cpus.size, - machine.model.memory.sumOf { it.size } - ) + private val model: HostModel = + HostModel( + machine.model.cpus.sumOf { it.frequency }, + machine.model.cpus.size, + machine.model.memory.sumOf { it.size }, + ) /** * The [GuestListener] that listens for guest events. */ - private val guestListener = object : GuestListener { - override fun onStart(guest: Guest) { - listeners.forEach { it.onStateChanged(this@SimHost, guest.server, guest.state) } - } + private val guestListener = + object : GuestListener { + override fun onStart(guest: Guest) { + listeners.forEach { it.onStateChanged(this@SimHost, guest.server, guest.state) } + } - override fun onStop(guest: Guest) { - listeners.forEach { it.onStateChanged(this@SimHost, guest.server, guest.state) } + override fun onStop(guest: Guest) { + listeners.forEach { it.onStateChanged(this@SimHost, guest.server, guest.state) } + } } - } init { launch() @@ -135,7 +136,7 @@ public class SimHost( } override fun getState(): HostState { - return _state + return localState } override fun getInstances(): Set<Server> { @@ -155,17 +156,18 @@ public class SimHost( require(canFit(key)) { "Server does not fit" } val machine = hypervisor.newMachine(key.flavor.toMachineModel()) - val newGuest = Guest( - clock, - this, - hypervisor, - mapper, - guestListener, - server, - machine - ) - - _guests.add(newGuest) + val newGuest = + Guest( + clock, + this, + hypervisor, + mapper, + guestListener, + server, + machine, + ) + + temporaryGuests.add(newGuest) newGuest } } @@ -210,7 +212,7 @@ public class SimHost( var error = 0 var invalid = 0 - val guests = _guests.listIterator() + val guests = temporaryGuests.listIterator() for (guest in guests) { when (guest.state) { ServerState.TERMINATED -> terminated++ @@ -226,15 +228,15 @@ public class SimHost( } return HostSystemStats( - Duration.ofMillis(_uptime), - Duration.ofMillis(_downtime), - _bootTime, + Duration.ofMillis(localUptime), + Duration.ofMillis(localDowntime), + localBootTime, machine.psu.powerDraw, machine.psu.energyUsage, terminated, running, error, - invalid + invalid, ) } @@ -255,7 +257,7 @@ public class SimHost( hypervisor.cpuCapacity, hypervisor.cpuDemand, hypervisor.cpuUsage, - hypervisor.cpuUsage / _cpuLimit + hypervisor.cpuUsage / localCpuLimit, ) } @@ -275,7 +277,7 @@ public class SimHost( public fun fail() { reset(HostState.ERROR) - for (guest in _guests) { + for (guest in temporaryGuests) { guest.fail() } } @@ -299,31 +301,33 @@ public class SimHost( val bootWorkload = bootModel.get() val hypervisor = hypervisor - val hypervisorWorkload = object : SimWorkload by hypervisor { - override fun onStart(ctx: SimMachineContext) { - try { - _bootTime = clock.instant() - _state = HostState.UP - hypervisor.onStart(ctx) - - // Recover the guests that were running on the hypervisor. - for (guest in _guests) { - guest.recover() + val hypervisorWorkload = + object : SimWorkload by hypervisor { + override fun onStart(ctx: SimMachineContext) { + try { + localBootTime = clock.instant() + localState = HostState.UP + hypervisor.onStart(ctx) + + // Recover the guests that were running on the hypervisor. + for (guest in temporaryGuests) { + guest.recover() + } + } catch (cause: Throwable) { + localState = HostState.ERROR + throw cause } - } catch (cause: Throwable) { - _state = HostState.ERROR - throw cause } } - } val workload = if (bootWorkload != null) SimWorkloads.chain(bootWorkload, hypervisorWorkload) else hypervisorWorkload // Launch hypervisor onto machine - ctx = machine.startWorkload(workload, emptyMap()) { cause -> - _state = if (cause != null) HostState.ERROR else HostState.DOWN - ctx = null - } + ctx = + machine.startWorkload(workload, emptyMap()) { cause -> + localState = if (cause != null) HostState.ERROR else HostState.DOWN + ctx = null + } } /** @@ -334,7 +338,7 @@ public class SimHost( // Stop the hypervisor ctx?.shutdown() - _state = state + localState = state } /** @@ -352,28 +356,28 @@ public class SimHost( return if (optimize) model.optimize() else model } - private var _lastReport = clock.millis() - private var _uptime = 0L - private var _downtime = 0L - private var _bootTime: Instant? = null - private val _cpuLimit = machine.model.cpus.sumOf { it.frequency } + private var localLastReport = clock.millis() + private var localUptime = 0L + private var localDowntime = 0L + private var localBootTime: Instant? = null + private val localCpuLimit = machine.model.cpus.sumOf { it.frequency } /** * Helper function to track the uptime of a machine. */ private fun updateUptime() { val now = clock.millis() - val duration = now - _lastReport - _lastReport = now + val duration = now - localLastReport + localLastReport = now - if (_state == HostState.UP) { - _uptime += duration - } else if (_state == HostState.ERROR) { + if (localState == HostState.UP) { + localUptime += duration + } else if (localState == HostState.ERROR) { // Only increment downtime if the machine is in a failure state - _downtime += duration + localDowntime += duration } - val guests = _guests + val guests = temporaryGuests for (i in guests.indices) { guests[i].updateUptime() } 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 index 5e94830c..9511017f 100644 --- 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 @@ -38,6 +38,6 @@ public interface FailureModel { context: CoroutineContext, clock: InstantSource, service: ComputeService, - random: RandomGenerator + 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 index 337f3c60..b8887627 100644 --- 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 @@ -46,7 +46,7 @@ public fun grid5000(failureInterval: Duration): FailureModel { context: CoroutineContext, clock: InstantSource, service: ComputeService, - random: RandomGenerator + random: RandomGenerator, ): HostFaultInjector { val rng = Well19937c(random.nextLong()) val hosts = service.hosts.map { it as SimHost }.toSet() @@ -59,7 +59,7 @@ public fun grid5000(failureInterval: Duration): FailureModel { 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)) + fault = StartStopHostFault(LogNormalDistribution(rng, 8.89, 2.71)), ) } diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/failure/HostFault.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/failure/HostFault.kt index d34f70d7..faf536ad 100644 --- a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/failure/HostFault.kt +++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/failure/HostFault.kt @@ -32,5 +32,8 @@ public interface HostFault { /** * Apply the fault to the specified [victims]. */ - public suspend fun apply(clock: InstantSource, victims: List<SimHost>) + public suspend fun apply( + clock: InstantSource, + victims: List<SimHost>, + ) } diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/failure/HostFaultInjector.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/failure/HostFaultInjector.kt index afbb99d2..26084a1b 100644 --- a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/failure/HostFaultInjector.kt +++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/failure/HostFaultInjector.kt @@ -60,7 +60,7 @@ public interface HostFaultInjector : AutoCloseable { hosts: Set<SimHost>, iat: RealDistribution, selector: VictimSelector, - fault: HostFault + fault: HostFault, ): HostFaultInjector = HostFaultInjectorImpl(context, clock, hosts, iat, selector, fault) } } diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/failure/StartStopHostFault.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/failure/StartStopHostFault.kt index 8bd25391..45545f3b 100644 --- a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/failure/StartStopHostFault.kt +++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/failure/StartStopHostFault.kt @@ -32,7 +32,10 @@ import kotlin.math.roundToLong * A type of [HostFault] where the hosts are stopped and recover after some random amount of time. */ public class StartStopHostFault(private val duration: RealDistribution) : HostFault { - override suspend fun apply(clock: InstantSource, victims: List<SimHost>) { + override suspend fun apply( + clock: InstantSource, + victims: List<SimHost>, + ) { for (host in victims) { host.fail() } diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/failure/StochasticVictimSelector.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/failure/StochasticVictimSelector.kt index 4aba0e91..93463cdb 100644 --- a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/failure/StochasticVictimSelector.kt +++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/failure/StochasticVictimSelector.kt @@ -34,9 +34,8 @@ import kotlin.math.roundToInt */ public class StochasticVictimSelector( private val size: RealDistribution, - private val random: RandomGenerator = SplittableRandom(0) + private val random: RandomGenerator = SplittableRandom(0), ) : VictimSelector { - override fun select(hosts: Set<SimHost>): List<SimHost> { val n = size.sample().roundToInt() val result = ArrayList<SimHost>(n) diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/internal/Guest.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/internal/Guest.kt index 354eb3d0..e268c506 100644 --- a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/internal/Guest.kt +++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/internal/Guest.kt @@ -47,7 +47,7 @@ internal class Guest( private val mapper: SimWorkloadMapper, private val listener: GuestListener, val server: Server, - val machine: SimVirtualMachine + val machine: SimVirtualMachine, ) { /** * The state of the [Guest]. @@ -132,9 +132,9 @@ internal class Guest( updateUptime() return GuestSystemStats( - Duration.ofMillis(_uptime), - Duration.ofMillis(_downtime), - _bootTime + Duration.ofMillis(localUptime), + Duration.ofMillis(localDowntime), + localBootTime, ) } @@ -152,7 +152,7 @@ internal class Guest( counters.cpuLostTime / 1000L, machine.cpuCapacity, machine.cpuUsage, - machine.cpuUsage / _cpuLimit + machine.cpuUsage / localCpuLimit, ) } @@ -173,10 +173,11 @@ internal class Guest( val workload: SimWorkload = mapper.createWorkload(server) workload.setOffset(clock.millis()) val meta = mapOf("driver" to host, "server" to server) + server.meta - ctx = machine.startWorkload(workload, meta) { cause -> - onStop(if (cause != null) ServerState.ERROR else ServerState.TERMINATED) - ctx = null - } + ctx = + machine.startWorkload(workload, meta) { cause -> + onStop(if (cause != null) ServerState.ERROR else ServerState.TERMINATED) + ctx = null + } } /** @@ -201,7 +202,7 @@ internal class Guest( * This method is invoked when the guest was started on the host and has booted into a running state. */ private fun onStart() { - _bootTime = clock.instant() + localBootTime = clock.instant() state = ServerState.RUNNING listener.onStart(this) } @@ -216,24 +217,24 @@ internal class Guest( listener.onStop(this) } - private var _uptime = 0L - private var _downtime = 0L - private var _lastReport = clock.millis() - private var _bootTime: Instant? = null - private val _cpuLimit = machine.model.cpus.sumOf { it.frequency } + private var localUptime = 0L + private var localDowntime = 0L + private var localLastReport = clock.millis() + private var localBootTime: Instant? = null + private val localCpuLimit = machine.model.cpus.sumOf { it.frequency } /** * Helper function to track the uptime and downtime of the guest. */ fun updateUptime() { val now = clock.millis() - val duration = now - _lastReport - _lastReport = now + val duration = now - localLastReport + localLastReport = now if (state == ServerState.RUNNING) { - _uptime += duration + localUptime += duration } else if (state == ServerState.ERROR) { - _downtime += duration + localDowntime += duration } } diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/internal/HostFaultInjectorImpl.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/internal/HostFaultInjectorImpl.kt index afc0b0d4..c75ce528 100644 --- a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/internal/HostFaultInjectorImpl.kt +++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/internal/HostFaultInjectorImpl.kt @@ -52,7 +52,7 @@ internal class HostFaultInjectorImpl( private val hosts: Set<SimHost>, private val iat: RealDistribution, private val selector: VictimSelector, - private val fault: HostFault + private val fault: HostFault, ) : HostFaultInjector { /** * The scope in which the injector runs. @@ -72,10 +72,11 @@ internal class HostFaultInjectorImpl( return } - job = scope.launch { - runInjector() - job = null - } + job = + scope.launch { + runInjector() + job = null + } } /** 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 index 50e7bd0d..753cde16 100644 --- 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 @@ -34,10 +34,13 @@ import java.time.Duration public class ComputeMonitorProvisioningStep( private val serviceDomain: String, private val monitor: ComputeMonitor, - private val exportInterval: Duration + 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 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 index fc555016..484ae7ca 100644 --- 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 @@ -36,12 +36,13 @@ import java.time.Duration public class ComputeServiceProvisioningStep internal constructor( private val serviceDomain: String, private val scheduler: (ProvisioningContext) -> ComputeScheduler, - private val schedulingQuantum: Duration + private val schedulingQuantum: Duration, ) : ProvisioningStep { override fun apply(ctx: ProvisioningContext): AutoCloseable { - val service = ComputeService.builder(ctx.dispatcher, scheduler(ctx)) - .withQuantum(schedulingQuantum) - .build() + 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 index 93f8fa4f..53294b1b 100644 --- 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 @@ -40,7 +40,7 @@ import java.time.Duration public fun setupComputeService( serviceDomain: String, scheduler: (ProvisioningContext) -> ComputeScheduler, - schedulingQuantum: Duration = Duration.ofMinutes(5) + schedulingQuantum: Duration = Duration.ofMinutes(5), ): ProvisioningStep { return ComputeServiceProvisioningStep(serviceDomain, scheduler, schedulingQuantum) } @@ -56,7 +56,7 @@ public fun setupComputeService( public fun registerComputeMonitor( serviceDomain: String, monitor: ComputeMonitor, - exportInterval: Duration = Duration.ofMinutes(5) + exportInterval: Duration = Duration.ofMinutes(5), ): ProvisioningStep { return ComputeMonitorProvisioningStep(serviceDomain, monitor, exportInterval) } @@ -69,6 +69,10 @@ public fun registerComputeMonitor( * @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 { +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 index 3104ccbe..d9c5e7a6 100644 --- 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 @@ -40,10 +40,13 @@ import java.util.SplittableRandom public class HostsProvisioningStep internal constructor( private val serviceDomain: String, private val specs: List<HostSpec>, - private val optimize: Boolean + 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 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>() @@ -52,15 +55,16 @@ public class HostsProvisioningStep internal constructor( 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 - ) + 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) 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 index 275378e7..58d3a8c2 100644 --- 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 @@ -43,13 +43,14 @@ 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() + 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" - } + override fun toString(): String = "Provisioner.ProvisioningContext" + } /** * The stack of handles to run during the clean-up process. 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 index 0226a704..c5b2be72 100644 --- 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 @@ -56,6 +56,9 @@ public fun interface ProvisioningStep { * @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 + public abstract fun create( + spec: S, + config: Config, + ): ProvisioningStep } } diff --git a/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimHostTest.kt b/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimHostTest.kt index e9bac8db..3a985486 100644 --- a/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimHostTest.kt +++ b/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimHostTest.kt @@ -62,243 +62,274 @@ internal class SimHostTest { fun setUp() { val cpuNode = ProcessingNode("Intel", "Xeon", "amd64", 2) - machineModel = MachineModel( - /*cpus*/ List(cpuNode.coreCount) { ProcessingUnit(cpuNode, it, 3200.0) }, - /*memory*/ List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) } - ) + machineModel = + MachineModel( + // cpus + List(cpuNode.coreCount) { ProcessingUnit(cpuNode, it, 3200.0) }, + // memory + List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) }, + ) } /** * Test a single virtual machine hosted by the hypervisor. */ @Test - fun testSingle() = runSimulation { - val duration = 5 * 60L - - val engine = FlowEngine.create(dispatcher) - val graph = engine.newGraph() - - val machine = SimBareMetalMachine.create(graph, machineModel) - val hypervisor = SimHypervisor.create(FlowMultiplexerFactory.maxMinMultiplexer(), SplittableRandom(1)) - - val host = SimHost( - uid = UUID.randomUUID(), - name = "test", - meta = emptyMap(), - timeSource, - machine, - hypervisor - ) - val vmImage = MockImage( - UUID.randomUUID(), - "<unnamed>", - emptyMap(), - mapOf( - "workload" to - SimTrace.ofFragments( - SimTraceFragment(0, duration * 1000, 2 * 28.0, 2), - SimTraceFragment(duration * 1000, duration * 1000, 2 * 3500.0, 2), - SimTraceFragment(duration * 2000, duration * 1000, 0.0, 2), - SimTraceFragment(duration * 3000, duration * 1000, 2 * 183.0, 2) - ).createWorkload(1) - ) - ) - - val flavor = MockFlavor(2, 0) + fun testSingle() = + runSimulation { + val duration = 5 * 60L + + val engine = FlowEngine.create(dispatcher) + val graph = engine.newGraph() + + val machine = SimBareMetalMachine.create(graph, machineModel) + val hypervisor = SimHypervisor.create(FlowMultiplexerFactory.maxMinMultiplexer(), SplittableRandom(1)) + + val host = + SimHost( + uid = UUID.randomUUID(), + name = "test", + meta = emptyMap(), + timeSource, + machine, + hypervisor, + ) + val vmImage = + MockImage( + UUID.randomUUID(), + "<unnamed>", + emptyMap(), + mapOf( + "workload" to + SimTrace.ofFragments( + SimTraceFragment(0, duration * 1000, 2 * 28.0, 2), + SimTraceFragment(duration * 1000, duration * 1000, 2 * 3500.0, 2), + SimTraceFragment(duration * 2000, duration * 1000, 0.0, 2), + SimTraceFragment(duration * 3000, duration * 1000, 2 * 183.0, 2), + ).createWorkload(1), + ), + ) + + val flavor = MockFlavor(2, 0) - suspendCancellableCoroutine { cont -> - host.addListener(object : HostListener { - private var finished = 0 - - override fun onStateChanged(host: Host, server: Server, newState: ServerState) { - if (newState == ServerState.TERMINATED && ++finished == 1) { - cont.resume(Unit) - } - } - }) - val server = MockServer(UUID.randomUUID(), "a", flavor, vmImage) - host.spawn(server) - host.start(server) - } + suspendCancellableCoroutine { cont -> + host.addListener( + object : HostListener { + private var finished = 0 + + override fun onStateChanged( + host: Host, + server: Server, + newState: ServerState, + ) { + if (newState == ServerState.TERMINATED && ++finished == 1) { + cont.resume(Unit) + } + } + }, + ) + val server = MockServer(UUID.randomUUID(), "a", flavor, vmImage) + host.spawn(server) + host.start(server) + } - // Ensure last cycle is collected - delay(1000L * duration) - host.close() + // Ensure last cycle is collected + delay(1000L * duration) + host.close() - val cpuStats = host.getCpuStats() + val cpuStats = host.getCpuStats() - assertAll( - { assertEquals(639564, cpuStats.activeTime, "Active time does not match") }, - { assertEquals(2360433, cpuStats.idleTime, "Idle time does not match") }, - { assertEquals(56251, cpuStats.stealTime, "Steal time does not match") }, - { assertEquals(1499999, timeSource.millis()) } - ) - } + assertAll( + { assertEquals(639564, cpuStats.activeTime, "Active time does not match") }, + { assertEquals(2360433, cpuStats.idleTime, "Idle time does not match") }, + { assertEquals(56251, cpuStats.stealTime, "Steal time does not match") }, + { assertEquals(1499999, timeSource.millis()) }, + ) + } /** * Test overcommitting of resources by the hypervisor. */ @Test - fun testOvercommitted() = runSimulation { - val duration = 5 * 60L - - val engine = FlowEngine.create(dispatcher) - val graph = engine.newGraph() - - val machine = SimBareMetalMachine.create(graph, machineModel) - val hypervisor = SimHypervisor.create(FlowMultiplexerFactory.maxMinMultiplexer(), SplittableRandom(1)) - - val host = SimHost( - uid = UUID.randomUUID(), - name = "test", - meta = emptyMap(), - timeSource, - machine, - hypervisor - ) - val vmImageA = MockImage( - UUID.randomUUID(), - "<unnamed>", - emptyMap(), - mapOf( - "workload" to - SimTrace.ofFragments( - SimTraceFragment(0, duration * 1000, 2 * 28.0, 2), - SimTraceFragment(duration * 1000, duration * 1000, 2 * 3500.0, 2), - SimTraceFragment(duration * 2000, duration * 1000, 0.0, 2), - SimTraceFragment(duration * 3000, duration * 1000, 2 * 183.0, 2) - ).createWorkload(1) - ) - ) - val vmImageB = MockImage( - UUID.randomUUID(), - "<unnamed>", - emptyMap(), - mapOf( - "workload" to - SimTrace.ofFragments( - SimTraceFragment(0, duration * 1000, 2 * 28.0, 2), - SimTraceFragment(duration * 1000, duration * 1000, 2 * 3100.0, 2), - SimTraceFragment(duration * 2000, duration * 1000, 0.0, 2), - SimTraceFragment(duration * 3000, duration * 1000, 2 * 73.0, 2) - ).createWorkload(1) - ) - ) - - val flavor = MockFlavor(2, 0) - - coroutineScope { - suspendCancellableCoroutine { cont -> - host.addListener(object : HostListener { - private var finished = 0 - - override fun onStateChanged(host: Host, server: Server, newState: ServerState) { - if (newState == ServerState.TERMINATED && ++finished == 2) { - cont.resume(Unit) - } - } - }) - val serverA = MockServer(UUID.randomUUID(), "a", flavor, vmImageA) - host.spawn(serverA) - val serverB = MockServer(UUID.randomUUID(), "b", flavor, vmImageB) - host.spawn(serverB) - - host.start(serverA) - host.start(serverB) + fun testOvercommitted() = + runSimulation { + val duration = 5 * 60L + + val engine = FlowEngine.create(dispatcher) + val graph = engine.newGraph() + + val machine = SimBareMetalMachine.create(graph, machineModel) + val hypervisor = SimHypervisor.create(FlowMultiplexerFactory.maxMinMultiplexer(), SplittableRandom(1)) + + val host = + SimHost( + uid = UUID.randomUUID(), + name = "test", + meta = emptyMap(), + timeSource, + machine, + hypervisor, + ) + val vmImageA = + MockImage( + UUID.randomUUID(), + "<unnamed>", + emptyMap(), + mapOf( + "workload" to + SimTrace.ofFragments( + SimTraceFragment(0, duration * 1000, 2 * 28.0, 2), + SimTraceFragment(duration * 1000, duration * 1000, 2 * 3500.0, 2), + SimTraceFragment(duration * 2000, duration * 1000, 0.0, 2), + SimTraceFragment(duration * 3000, duration * 1000, 2 * 183.0, 2), + ).createWorkload(1), + ), + ) + val vmImageB = + MockImage( + UUID.randomUUID(), + "<unnamed>", + emptyMap(), + mapOf( + "workload" to + SimTrace.ofFragments( + SimTraceFragment(0, duration * 1000, 2 * 28.0, 2), + SimTraceFragment(duration * 1000, duration * 1000, 2 * 3100.0, 2), + SimTraceFragment(duration * 2000, duration * 1000, 0.0, 2), + SimTraceFragment(duration * 3000, duration * 1000, 2 * 73.0, 2), + ).createWorkload(1), + ), + ) + + val flavor = MockFlavor(2, 0) + + coroutineScope { + suspendCancellableCoroutine { cont -> + host.addListener( + object : HostListener { + private var finished = 0 + + override fun onStateChanged( + host: Host, + server: Server, + newState: ServerState, + ) { + if (newState == ServerState.TERMINATED && ++finished == 2) { + cont.resume(Unit) + } + } + }, + ) + val serverA = MockServer(UUID.randomUUID(), "a", flavor, vmImageA) + host.spawn(serverA) + val serverB = MockServer(UUID.randomUUID(), "b", flavor, vmImageB) + host.spawn(serverB) + + host.start(serverA) + host.start(serverB) + } } - } - // Ensure last cycle is collected - delay(1000L * duration) - host.close() + // Ensure last cycle is collected + delay(1000L * duration) + host.close() - val cpuStats = host.getCpuStats() + val cpuStats = host.getCpuStats() - assertAll( - { assertEquals(658502, cpuStats.activeTime, "Active time does not match") }, - { assertEquals(2341496, cpuStats.idleTime, "Idle time does not match") }, - { assertEquals(637504, cpuStats.stealTime, "Steal time does not match") }, - { assertEquals(1499999, timeSource.millis()) } - ) - } + assertAll( + { assertEquals(658502, cpuStats.activeTime, "Active time does not match") }, + { assertEquals(2341496, cpuStats.idleTime, "Idle time does not match") }, + { assertEquals(637504, cpuStats.stealTime, "Steal time does not match") }, + { assertEquals(1499999, timeSource.millis()) }, + ) + } /** * Test failure of the host. */ @Test - fun testFailure() = runSimulation { - val duration = 5 * 60L - - val engine = FlowEngine.create(dispatcher) - val graph = engine.newGraph() - - val machine = SimBareMetalMachine.create(graph, machineModel) - val hypervisor = SimHypervisor.create(FlowMultiplexerFactory.maxMinMultiplexer(), SplittableRandom(1)) - val host = SimHost( - uid = UUID.randomUUID(), - name = "test", - meta = emptyMap(), - timeSource, - machine, - hypervisor - ) - val image = MockImage( - UUID.randomUUID(), - "<unnamed>", - emptyMap(), - mapOf( - "workload" to - SimTrace.ofFragments( - SimTraceFragment(0, duration * 1000, 2 * 28.0, 2), - SimTraceFragment(duration * 1000L, duration * 1000, 2 * 3500.0, 2), - SimTraceFragment(duration * 2000L, duration * 1000, 0.0, 2), - SimTraceFragment(duration * 3000L, duration * 1000, 2 * 183.0, 2) - ).createWorkload(1) - ) - ) - val flavor = MockFlavor(2, 0) - val server = MockServer(UUID.randomUUID(), "a", flavor, image) - - coroutineScope { - host.spawn(server) - host.start(server) - delay(5000L) - host.fail() - delay(duration * 1000) - host.recover() - - suspendCancellableCoroutine { cont -> - host.addListener(object : HostListener { - override fun onStateChanged(host: Host, server: Server, newState: ServerState) { - if (newState == ServerState.TERMINATED) { - cont.resume(Unit) - } - } - }) + fun testFailure() = + runSimulation { + val duration = 5 * 60L + + val engine = FlowEngine.create(dispatcher) + val graph = engine.newGraph() + + val machine = SimBareMetalMachine.create(graph, machineModel) + val hypervisor = SimHypervisor.create(FlowMultiplexerFactory.maxMinMultiplexer(), SplittableRandom(1)) + val host = + SimHost( + uid = UUID.randomUUID(), + name = "test", + meta = emptyMap(), + timeSource, + machine, + hypervisor, + ) + val image = + MockImage( + UUID.randomUUID(), + "<unnamed>", + emptyMap(), + mapOf( + "workload" to + SimTrace.ofFragments( + SimTraceFragment(0, duration * 1000, 2 * 28.0, 2), + SimTraceFragment(duration * 1000L, duration * 1000, 2 * 3500.0, 2), + SimTraceFragment(duration * 2000L, duration * 1000, 0.0, 2), + SimTraceFragment(duration * 3000L, duration * 1000, 2 * 183.0, 2), + ).createWorkload(1), + ), + ) + val flavor = MockFlavor(2, 0) + val server = MockServer(UUID.randomUUID(), "a", flavor, image) + + coroutineScope { + host.spawn(server) + host.start(server) + delay(5000L) + host.fail() + delay(duration * 1000) + host.recover() + + suspendCancellableCoroutine { cont -> + host.addListener( + object : HostListener { + override fun onStateChanged( + host: Host, + server: Server, + newState: ServerState, + ) { + if (newState == ServerState.TERMINATED) { + cont.resume(Unit) + } + } + }, + ) + } } - } - host.close() - // Ensure last cycle is collected - delay(1000L * duration) - - val cpuStats = host.getCpuStats() - val sysStats = host.getSystemStats() - val guestSysStats = host.getSystemStats(server) - - assertAll( - { assertEquals(1770344, cpuStats.idleTime, "Idle time does not match") }, - { assertEquals(639653, cpuStats.activeTime, "Active time does not match") }, - { assertEquals(1204999, sysStats.uptime.toMillis(), "Uptime does not match") }, - { assertEquals(300000, sysStats.downtime.toMillis(), "Downtime does not match") }, - { assertEquals(1204999, guestSysStats.uptime.toMillis(), "Guest uptime does not match") }, - { assertEquals(300000, guestSysStats.downtime.toMillis(), "Guest downtime does not match") } - ) - } + host.close() + // Ensure last cycle is collected + delay(1000L * duration) + + val cpuStats = host.getCpuStats() + val sysStats = host.getSystemStats() + val guestSysStats = host.getSystemStats(server) + + assertAll( + { assertEquals(1770344, cpuStats.idleTime, "Idle time does not match") }, + { assertEquals(639653, cpuStats.activeTime, "Active time does not match") }, + { assertEquals(1204999, sysStats.uptime.toMillis(), "Uptime does not match") }, + { assertEquals(300000, sysStats.downtime.toMillis(), "Downtime does not match") }, + { assertEquals(1204999, guestSysStats.uptime.toMillis(), "Guest uptime does not match") }, + { assertEquals(300000, guestSysStats.downtime.toMillis(), "Guest downtime does not match") }, + ) + } private class MockFlavor( override val cpuCount: Int, - override val memorySize: Long + override val memorySize: Long, ) : Flavor { override val uid: UUID = UUID.randomUUID() override val name: String = "test" @@ -318,7 +349,7 @@ internal class SimHostTest { override val uid: UUID, override val name: String, override val labels: Map<String, String>, - override val meta: Map<String, Any> + override val meta: Map<String, Any>, ) : Image { override fun delete() { throw NotImplementedError() @@ -333,7 +364,7 @@ internal class SimHostTest { override val uid: UUID, override val name: String, override val flavor: Flavor, - override val image: Image + override val image: Image, ) : Server { override val labels: Map<String, String> = emptyMap() diff --git a/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/failure/HostFaultInjectorTest.kt b/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/failure/HostFaultInjectorTest.kt index 29d0b5e7..690bf472 100644 --- a/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/failure/HostFaultInjectorTest.kt +++ b/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/failure/HostFaultInjectorTest.kt @@ -43,64 +43,72 @@ class HostFaultInjectorTest { * Simple test case to test that nothing happens when the injector is not started. */ @Test - fun testInjectorNotStarted() = runSimulation { - val host = mockk<SimHost>(relaxUnitFun = true) + fun testInjectorNotStarted() = + runSimulation { + val host = mockk<SimHost>(relaxUnitFun = true) - val injector = createSimpleInjector(coroutineContext, timeSource, setOf(host)) + val injector = createSimpleInjector(coroutineContext, timeSource, setOf(host)) - coVerify(exactly = 0) { host.fail() } - coVerify(exactly = 0) { host.recover() } + coVerify(exactly = 0) { host.fail() } + coVerify(exactly = 0) { host.recover() } - injector.close() - } + injector.close() + } /** * Simple test case to test a start stop fault where the machine is stopped and started after some time. */ @Test - fun testInjectorStopsMachine() = runSimulation { - val host = mockk<SimHost>(relaxUnitFun = true) + fun testInjectorStopsMachine() = + runSimulation { + val host = mockk<SimHost>(relaxUnitFun = true) - val injector = createSimpleInjector(coroutineContext, timeSource, setOf(host)) + val injector = createSimpleInjector(coroutineContext, timeSource, setOf(host)) - injector.start() + injector.start() - delay(Duration.ofDays(55).toMillis()) + delay(Duration.ofDays(55).toMillis()) - injector.close() + injector.close() - coVerify(exactly = 1) { host.fail() } - coVerify(exactly = 1) { host.recover() } - } + coVerify(exactly = 1) { host.fail() } + coVerify(exactly = 1) { host.recover() } + } /** * Simple test case to test a start stop fault where multiple machines are stopped. */ @Test - fun testInjectorStopsMultipleMachines() = runSimulation { - val hosts = listOf<SimHost>( - mockk(relaxUnitFun = true), - mockk(relaxUnitFun = true) - ) + fun testInjectorStopsMultipleMachines() = + runSimulation { + val hosts = + listOf<SimHost>( + mockk(relaxUnitFun = true), + mockk(relaxUnitFun = true), + ) - val injector = createSimpleInjector(coroutineContext, timeSource, hosts.toSet()) + val injector = createSimpleInjector(coroutineContext, timeSource, hosts.toSet()) - injector.start() + injector.start() - delay(Duration.ofDays(55).toMillis()) + delay(Duration.ofDays(55).toMillis()) - injector.close() + injector.close() - coVerify(exactly = 1) { hosts[0].fail() } - coVerify(exactly = 1) { hosts[1].fail() } - coVerify(exactly = 1) { hosts[0].recover() } - coVerify(exactly = 1) { hosts[1].recover() } - } + coVerify(exactly = 1) { hosts[0].fail() } + coVerify(exactly = 1) { hosts[1].fail() } + coVerify(exactly = 1) { hosts[0].recover() } + coVerify(exactly = 1) { hosts[1].recover() } + } /** * Create a simple start stop fault injector. */ - private fun createSimpleInjector(context: CoroutineContext, clock: InstantSource, hosts: Set<SimHost>): HostFaultInjector { + private fun createSimpleInjector( + context: CoroutineContext, + clock: InstantSource, + hosts: Set<SimHost>, + ): HostFaultInjector { val rng = Well19937c(0) val iat = LogNormalDistribution(rng, ln(24 * 7.0), 1.03) val selector = StochasticVictimSelector(LogNormalDistribution(rng, 1.88, 1.25)) |
