summaryrefslogtreecommitdiff
path: root/opendc-compute/opendc-compute-simulator
diff options
context:
space:
mode:
authorDante Niewenhuis <d.niewenhuis@hotmail.com>2024-03-05 13:23:57 +0100
committerGitHub <noreply@github.com>2024-03-05 13:23:57 +0100
commit5864cbcbfe2eb8c36ca05c3a39c7e5916aeecaec (patch)
tree5b2773b8dc21c2e1b526fb70f829c376dd80532a /opendc-compute/opendc-compute-simulator
parentd28002a3c151d198298574312f32f1cb43f3a660 (diff)
Updated package versions, updated web server tests. (#207)
* Updated all package versions including kotlin. Updated all web-server tests to run. * Changed the java version of the tests. OpenDC now only supports java 19. * small update * test update * new update * updated docker version to 19 * updated docker version to 19
Diffstat (limited to 'opendc-compute/opendc-compute-simulator')
-rw-r--r--opendc-compute/opendc-compute-simulator/build.gradle.kts2
-rw-r--r--opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/MutableServiceRegistry.kt11
-rw-r--r--opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/ServiceRegistry.kt5
-rw-r--r--opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/ServiceRegistryImpl.kt16
-rw-r--r--opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimHost.kt136
-rw-r--r--opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/failure/FailureModel.kt2
-rw-r--r--opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/failure/FailureModels.kt4
-rw-r--r--opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/failure/HostFault.kt5
-rw-r--r--opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/failure/HostFaultInjector.kt2
-rw-r--r--opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/failure/StartStopHostFault.kt5
-rw-r--r--opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/failure/StochasticVictimSelector.kt3
-rw-r--r--opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/internal/Guest.kt39
-rw-r--r--opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/internal/HostFaultInjectorImpl.kt11
-rw-r--r--opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/provisioner/ComputeMonitorProvisioningStep.kt7
-rw-r--r--opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/provisioner/ComputeServiceProvisioningStep.kt9
-rw-r--r--opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/provisioner/ComputeSteps.kt10
-rw-r--r--opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/provisioner/HostsProvisioningStep.kt26
-rw-r--r--opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/provisioner/Provisioner.kt13
-rw-r--r--opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/provisioner/ProvisioningStep.kt5
-rw-r--r--opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimHostTest.kt451
-rw-r--r--opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/failure/HostFaultInjectorTest.kt70
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))